1 | /* |
2 | * kdfwidget.cpp |
3 | * |
4 | * Copyright (c) 1998-2001 Michael Kropfberger <michael.kropfberger@gmx.net> |
5 | * 2009 Dario Andres Rodriguez <andresbajotierra@gmail.com> |
6 | * |
7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by |
9 | * the Free Software Foundation; either version 2 of the License, or |
10 | * (at your option) any later version. |
11 | * |
12 | * This program is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | * GNU General Public License for more details. |
16 | * |
17 | * You should have received a copy of the GNU General Public License |
18 | * along with this program; if not, write to the Free Software |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
20 | */ |
21 | |
22 | // |
23 | // 1999-11-29 Espen Sand |
24 | // Converted to QLayout and QListView + cleanups |
25 | // 1999-12-05 Espen Sand |
26 | // Usage bars should work again. |
27 | // |
28 | |
29 | #include "kdfwidget.h" |
30 | |
31 | #include <stdlib.h> |
32 | |
33 | #include <QtCore/QAbstractEventDispatcher> |
34 | #include <QtCore/QTimer> |
35 | #include <QtCore/QFile> |
36 | |
37 | #include <QtGui/QLayout> |
38 | #include <QtGui/QTreeView> |
39 | #include <QtGui/QStandardItemModel> |
40 | #include <QtGui/QStandardItem> |
41 | #include <QtGui/QPainter> |
42 | |
43 | #include <kapplication.h> |
44 | #include <kmessagebox.h> |
45 | #include <kmenu.h> |
46 | #include <ktoolinvocation.h> |
47 | #include <kglobal.h> |
48 | #include <kshell.h> |
49 | #include <klocale.h> |
50 | #include <kdebug.h> |
51 | |
52 | #include "optiondialog.h" |
53 | |
54 | //This aren't used here... |
55 | //#define BAR_COLUMN 7 |
56 | //#define FULL_PERCENT 95.0 |
57 | |
58 | #ifndef GUI_DEFINED |
59 | static bool GUI; |
60 | #define GUI_DEFINED |
61 | #endif |
62 | |
63 | KDFWidget::KDFWidget( QWidget *parent, bool init ) |
64 | : QWidget(parent), mOptionDialog(0), mPopup(0), mTimer(0) |
65 | { |
66 | connect(&mDiskList , SIGNAL(readDFDone()), |
67 | this, SLOT (updateDFDone()) ); |
68 | connect(&mDiskList , SIGNAL(criticallyFull(DiskEntry*)), |
69 | this, SLOT (criticallyFull(DiskEntry*)) ); |
70 | |
71 | m_columnList.append( Column( QLatin1String( "Icon" ), QLatin1String( "" ), 20, IconCol )); |
72 | m_columnList.append( Column( QLatin1String( "Device" ), i18nc("Device of the storage" , "Device" ), 100, DeviceCol )); |
73 | m_columnList.append( Column( QLatin1String( "Type" ), i18nc("Filesystem on storage" , "Type" ), 80, TypeCol )); |
74 | m_columnList.append( Column( QLatin1String( "Size" ), i18nc("Total size of the storage" , "Size" ), 80, SizeCol )); |
75 | m_columnList.append( Column( QLatin1String( "MountPoint" ), i18nc("Mount point of storage" , "Mount Point" ), 120, MountPointCol )); |
76 | m_columnList.append( Column( QLatin1String( "Free" ), i18nc("Free space in storage" , "Free" ), 80, FreeCol )); |
77 | m_columnList.append( Column( QLatin1String( "Full%" ), i18nc("Used storage space in %" , "Full %" ), 50, FullCol )); |
78 | m_columnList.append( Column( QLatin1String( "UsageBar" ), i18nc("Usage graphical bar" , "Usage" ), 200, UsageBarCol )); |
79 | |
80 | GUI = !init; |
81 | if( GUI ) |
82 | { |
83 | QVBoxLayout *topLayout = new QVBoxLayout( this ); |
84 | topLayout->setSpacing( 0 ); |
85 | topLayout->setMargin( 0 ); |
86 | |
87 | m_listModel = new QStandardItemModel( this ); |
88 | m_sortModel = new KDFSortFilterProxyModel( this ); |
89 | m_sortModel->setSourceModel( m_listModel ); |
90 | |
91 | m_listWidget = new QTreeView( this ); |
92 | m_listWidget->setModel( m_sortModel ); |
93 | |
94 | m_itemDelegate = new KDFItemDelegate( m_listWidget ); |
95 | |
96 | m_listWidget->setItemDelegate( m_itemDelegate ); |
97 | m_listWidget->setRootIsDecorated( false ); |
98 | m_listWidget->setSortingEnabled( true ); |
99 | m_listWidget->setContextMenuPolicy( Qt::CustomContextMenu ); |
100 | m_listWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); |
101 | |
102 | topLayout->addWidget( m_listWidget ); |
103 | |
104 | connect( m_listWidget, SIGNAL(customContextMenuRequested(QPoint)), |
105 | this, SLOT(contextMenuRequested(QPoint))); |
106 | |
107 | makeColumns(); |
108 | |
109 | mIsTopLevel = QLatin1String(parent->metaObject()->className()) == QLatin1String( "KDFTopLevel" ) ? true : false; |
110 | } |
111 | |
112 | loadSettings(); |
113 | if( init ) |
114 | applySettings(); |
115 | } |
116 | |
117 | KDFWidget::~KDFWidget() |
118 | { |
119 | delete m_listModel; |
120 | delete m_sortModel; |
121 | delete m_itemDelegate; |
122 | delete m_listWidget; |
123 | } |
124 | |
125 | void KDFWidget::makeColumns( void ) |
126 | { |
127 | |
128 | QStringList columns; |
129 | Q_FOREACH(const Column &c, m_columnList){ |
130 | columns << c.columnName; |
131 | } |
132 | m_listModel->setHorizontalHeaderLabels( columns ); |
133 | |
134 | } |
135 | |
136 | /******************************************************************/ |
137 | void KDFWidget::closeEvent(QCloseEvent *) |
138 | { |
139 | applySettings(); |
140 | kapp->quit(); |
141 | } |
142 | |
143 | |
144 | void KDFWidget::settingsChanged( void ) |
145 | { |
146 | applySettings(); |
147 | loadSettings(); |
148 | } |
149 | |
150 | |
151 | /*************************************************************************** |
152 | * writes the KConfig |
153 | **/ |
154 | void KDFWidget::applySettings( void ) |
155 | { |
156 | KConfig m_config; |
157 | KConfigGroup config( &m_config, "KDiskFree" ); |
158 | |
159 | if( GUI ) |
160 | { |
161 | Q_FOREACH(const Column &c, m_columnList){ |
162 | if( !m_listWidget->isColumnHidden( c.number ) ) |
163 | config.writeEntry( c.name, m_listWidget->columnWidth(c.number) ); |
164 | } |
165 | |
166 | config.writeEntry("SortColumn" , m_sortModel->sortColumn()); |
167 | config.writeEntry("SortOrder" , (int)m_sortModel->sortOrder()); |
168 | |
169 | //Save the sort order of the QTreeView Header |
170 | QHeaderView * = m_listWidget->header(); |
171 | QList<int> sectionIndices; |
172 | for (int i = 0; i < header->count(); i++) { |
173 | sectionIndices.append(header->visualIndex(i)); |
174 | } |
175 | config.writeEntry("HeaderSectionIndices" , sectionIndices); |
176 | } |
177 | config.sync(); |
178 | updateDF(); |
179 | } |
180 | |
181 | |
182 | /*************************************************************************** |
183 | * reads the KConfig |
184 | **/ |
185 | void KDFWidget::loadSettings( void ) |
186 | { |
187 | mStd.updateConfiguration(); |
188 | |
189 | if(GUI) |
190 | { |
191 | KConfigGroup config(KGlobal::config(), "KDiskFree" ); |
192 | Q_FOREACH(const Column &c, m_columnList){ |
193 | int width = config.readEntry( c.name, c.defaultWidth ); |
194 | m_listWidget->setColumnWidth( c.number, width ); |
195 | } |
196 | |
197 | KConfigGroup config_visible(KGlobal::config(), "KDFConfig" ); |
198 | Q_FOREACH(const Column &c, m_columnList){ |
199 | bool visible = config_visible.readEntry( c.name , true ); |
200 | m_listWidget->setColumnHidden( c.number, !visible ); |
201 | } |
202 | |
203 | int sortColumn = config.readEntry("SortColumn" ,0); |
204 | int sortOrder = config.readEntry("SortOrder" ,(int)Qt::AscendingOrder); |
205 | m_listWidget->sortByColumn(sortColumn,Qt::SortOrder(sortOrder)); |
206 | |
207 | //Load the sort order of the QTreeView Header |
208 | //This can also be achieved by header->saveState() and header->restoreState(...), |
209 | //but this would not be "human-readable" any more... |
210 | QHeaderView * = m_listWidget->header(); |
211 | QList<int> sectionIndices; |
212 | sectionIndices = config.readEntry("HeaderSectionIndices" ,sectionIndices); |
213 | if (sectionIndices.count() == header->count()) { |
214 | for (int i = 0; i < header->count(); i++) { |
215 | int sectionIndex = sectionIndices.at(i); |
216 | int oldVisualIndex = header->visualIndex(sectionIndex); |
217 | header->moveSection(oldVisualIndex,i); |
218 | } |
219 | } |
220 | |
221 | setUpdateFrequency( mStd.updateFrequency() ); |
222 | updateDF(); |
223 | } |
224 | } |
225 | |
226 | |
227 | /*************************************************************************** |
228 | * pops up the SettingsBox if the settingsBtn is clicked |
229 | **/ |
230 | void KDFWidget::settingsBtnClicked( void ) |
231 | { |
232 | if( mIsTopLevel == true ) |
233 | { |
234 | if( mOptionDialog == 0 ) |
235 | { |
236 | mOptionDialog = new COptionDialog( this ); |
237 | if( mOptionDialog == 0 ) |
238 | { |
239 | return; |
240 | } |
241 | connect( mOptionDialog, SIGNAL(valueChanged()), |
242 | this, SLOT(settingsChanged()) ); |
243 | } |
244 | mOptionDialog->show(); |
245 | } |
246 | } |
247 | |
248 | |
249 | /*************************************************************************** |
250 | * resets the timer for automatic df-refreshes |
251 | **/ |
252 | void KDFWidget::setUpdateFrequency( int frequency ) |
253 | { |
254 | // |
255 | // Kill current timer and restart it if the frequency is |
256 | // larger than zero. |
257 | // |
258 | QAbstractEventDispatcher::instance()->unregisterTimers(this); |
259 | if( frequency > 0 ) |
260 | { |
261 | startTimer( frequency * 1000 ); |
262 | } |
263 | } |
264 | |
265 | /*************************************************************************** |
266 | * Update (reread) all disk-dependencies |
267 | **/ |
268 | void KDFWidget::timerEvent(QTimerEvent *) |
269 | { |
270 | updateDF(); |
271 | } |
272 | |
273 | |
274 | /*************************************************************************** |
275 | * checks fstab & df |
276 | **/ |
277 | void KDFWidget::updateDF( void ) |
278 | { |
279 | // |
280 | // We can only do this if the popupmenu is not present |
281 | // |
282 | if( mPopup == 0 ) |
283 | { |
284 | readingDF = true; |
285 | mDiskList.readFSTAB(); |
286 | mDiskList.readDF(); |
287 | } |
288 | } |
289 | |
290 | /*************************************************************************** |
291 | * gets the signal when the diskList is complete and up to date |
292 | **/ |
293 | void KDFWidget::updateDFDone( void ){ |
294 | if (mPopup) //The popup menu is ont he screen... Don't touch the list view... |
295 | return; |
296 | |
297 | //Clear the list items |
298 | m_listModel->removeRows(0,m_listModel->rowCount()); |
299 | |
300 | DisksConstIterator itr = mDiskList.disksConstIteratorBegin(); |
301 | DisksConstIterator end = mDiskList.disksConstIteratorEnd(); |
302 | for (; itr != end; ++itr) |
303 | { |
304 | DiskEntry * disk = *itr; |
305 | |
306 | QString size,percent; |
307 | if( disk->kBSize() > 0 ) |
308 | { |
309 | percent = KGlobal::locale()->formatNumber(disk->percentFull(), 1) + QLatin1Char( '%' ); |
310 | size = disk->prettyKBSize(); |
311 | } |
312 | else |
313 | { |
314 | percent = i18n("N/A" ); |
315 | size = i18n("N/A" ); |
316 | } |
317 | |
318 | bool root = !disk->mountOptions().contains(QLatin1String( "user" ), Qt::CaseInsensitive); |
319 | |
320 | QStandardItem * IconItem = new QStandardItem( generateIcon(disk->iconName(), root, disk->mounted() ), QLatin1String( "" ) ); |
321 | |
322 | QStandardItem * DeviceItem = new QStandardItem( disk->deviceName() ); |
323 | |
324 | QStandardItem * TypeItem = new QStandardItem( disk->fsType() ); |
325 | |
326 | QStandardItem * SizeItem = new QStandardItem( size ); |
327 | SizeItem->setData( disk->kBSize(), Qt::UserRole ); |
328 | |
329 | QStandardItem * MountPointItem = new QStandardItem( disk->mountPoint() ); |
330 | |
331 | QStandardItem * FreeItem = new QStandardItem( disk->prettyKBAvail() ); |
332 | FreeItem->setData( disk->kBAvail(), Qt::UserRole ); |
333 | |
334 | QStandardItem * FullItem = new QStandardItem( percent ); |
335 | FullItem->setData( disk->percentFull() , Qt::UserRole ); |
336 | |
337 | QStandardItem * UsageBarItem = new QStandardItem( QLatin1String( "" ) ); |
338 | UsageBarItem->setData( disk->percentFull(), Qt::UserRole ); |
339 | |
340 | m_listModel->appendRow( QList<QStandardItem*>() << IconItem << DeviceItem << TypeItem << SizeItem << MountPointItem << |
341 | FreeItem << FullItem << UsageBarItem); |
342 | } |
343 | |
344 | readingDF = false; |
345 | |
346 | m_listModel->sort( DeviceCol ); |
347 | |
348 | } |
349 | |
350 | QIcon KDFWidget::generateIcon( QString iconName, bool mode, bool mounted) |
351 | { |
352 | QPixmap pix = SmallIcon(iconName); |
353 | |
354 | QPainter painter(&pix); |
355 | |
356 | if( mode ) |
357 | painter.drawPixmap( QRect(0,6,10,10), SmallIcon(QLatin1String( "object-locked" )) ); |
358 | |
359 | if( mounted ) |
360 | painter.drawPixmap( QRect(6,6,12,12) , SmallIcon(QLatin1String( "emblem-mounted" )) ); |
361 | |
362 | painter.end(); |
363 | return QIcon(pix); |
364 | |
365 | } |
366 | |
367 | void KDFWidget::criticallyFull( DiskEntry *disk ) |
368 | { |
369 | if( mStd.popupIfFull() == true ) |
370 | { |
371 | QString msg = i18n("Device [%1] on [%2] is critically full." , |
372 | disk->deviceName(), disk->mountPoint()); |
373 | KMessageBox::sorry( this, msg, i18nc("Warning device getting critically full" , "Warning" )); |
374 | } |
375 | } |
376 | |
377 | DiskEntry * KDFWidget::selectedDisk( QModelIndex index ) |
378 | { |
379 | if( !index.isValid() ) |
380 | return 0; |
381 | |
382 | QStandardItem * itemDevice = m_listModel->item( index.row() , DeviceCol ); |
383 | QStandardItem * itemMountPoint = m_listModel->item( index.row() , MountPointCol ); |
384 | |
385 | DiskEntry * disk = new DiskEntry( itemDevice->text() ); |
386 | disk->setMountPoint( itemMountPoint->text() ); |
387 | |
388 | int pos = mDiskList.find( disk ); |
389 | |
390 | delete disk; |
391 | return mDiskList.at(pos); |
392 | |
393 | } |
394 | |
395 | void KDFWidget::( const QPoint &p ) |
396 | { |
397 | if (mPopup) //The user may even be able to popup another menu while this open is active... |
398 | return; |
399 | |
400 | QModelIndex index = m_listWidget->indexAt( p ); |
401 | |
402 | if( !index.isValid() ) |
403 | { |
404 | QList<QModelIndex> selected = m_listWidget->selectionModel()->selectedIndexes(); |
405 | if ( selected.size() > 0 ) |
406 | index = selected.at(0); |
407 | else |
408 | return; |
409 | } |
410 | |
411 | index = m_sortModel->mapToSource( index ); |
412 | |
413 | mDiskList.setUpdatesDisabled(true); |
414 | DiskEntry * disk = selectedDisk( index ); |
415 | |
416 | if( disk == 0 ) |
417 | return; |
418 | |
419 | mPopup = new KMenu( 0 ); |
420 | mPopup->addTitle( disk->mountPoint() ); |
421 | QAction *mountPointAction = mPopup->addAction( i18n("Mount Device" ) ); |
422 | QAction *umountPointAction = mPopup->addAction( i18n("Unmount Device" ) ); |
423 | mPopup->addSeparator(); |
424 | QAction *openFileManagerAction = mPopup->addAction( i18n("Open in File Manager" ) ); |
425 | mountPointAction->setEnabled( !disk->mounted() ); |
426 | umountPointAction->setEnabled( disk->mounted() ); |
427 | openFileManagerAction->setEnabled( disk->mounted() ); |
428 | QAction *position = mPopup->exec( m_listWidget->mapToGlobal(p) ); |
429 | |
430 | bool openFileManager = false; |
431 | if( !position ) |
432 | { |
433 | mDiskList.setUpdatesDisabled(false); |
434 | delete mPopup; |
435 | mPopup = 0; |
436 | return; |
437 | } |
438 | else if( position == mountPointAction || position == umountPointAction ) |
439 | { |
440 | QStandardItem * SizeItem = m_listModel->item( index.row() , SizeCol ); |
441 | SizeItem->setText( i18n("MOUNTING" ) ); |
442 | |
443 | QStandardItem * FreeItem = m_listModel->item( index.row() , FreeCol ); |
444 | FreeItem->setText( i18n("MOUNTING" ) ); |
445 | |
446 | QStandardItem * IconItem = m_listModel->item( index.row() , IconCol ); |
447 | IconItem->setIcon( SmallIcon(QLatin1String( "user-away" )) ); |
448 | |
449 | int val = disk->toggleMount(); |
450 | if( val != 0 /*== false*/ ) |
451 | { |
452 | KMessageBox::error( this, disk->lastSysError() ); |
453 | } |
454 | else if ( ( mStd.openFileManager() == true) |
455 | && (position == mountPointAction) ) //only on mount |
456 | { |
457 | openFileManager = true; |
458 | } |
459 | |
460 | //delete item; |
461 | mDiskList.deleteAllMountedAt(disk->mountPoint()); |
462 | } |
463 | else if( position == openFileManagerAction ) |
464 | { |
465 | openFileManager = true; |
466 | } |
467 | |
468 | if( openFileManager == true ) |
469 | { |
470 | kDebug() << "opening filemanager" ; |
471 | if( mStd.fileManager().isEmpty() == false ) |
472 | { |
473 | QString cmd = mStd.fileManager(); |
474 | int pos = cmd.indexOf(QLatin1String( "%m" )); |
475 | if( pos > 0 ) |
476 | { |
477 | cmd = cmd.replace( pos, 2, KShell::quoteArg(disk->mountPoint()) ) + QLatin1String( " &" ); |
478 | } |
479 | else |
480 | { |
481 | cmd += QLatin1Char( ' ' ) + KShell::quoteArg(disk->mountPoint()) + QLatin1String( " &" ); |
482 | } |
483 | system( QFile::encodeName(cmd) ); |
484 | } |
485 | } |
486 | |
487 | //Update only here as showing of error message triggers event loop. |
488 | mDiskList.setUpdatesDisabled(false); |
489 | delete mPopup; |
490 | mPopup = 0; |
491 | |
492 | if( position != openFileManagerAction ) // No need to update when just opening the fm. |
493 | { |
494 | updateDF(); |
495 | } |
496 | |
497 | } |
498 | |
499 | void KDFWidget::invokeHelp() |
500 | { |
501 | KToolInvocation::invokeHelp(QLatin1String( "" ), QLatin1String( "kcontrol/kdf" )); |
502 | } |
503 | |
504 | #include "kdfwidget.moc" |
505 | |