File indexing completed on 2024-11-10 05:13:55
0001 /* 0002 SPDX-FileCopyrightText: 1998-2001 Michael Kropfberger <michael.kropfberger@gmx.net> 0003 SPDX-FileCopyrightText: 2009 Dario Andres Rodriguez <andresbajotierra@gmail.com> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 // 0009 // 1999-11-29 Espen Sand 0010 // Converted to QLayout and QListView + cleanups 0011 // 1999-12-05 Espen Sand 0012 // Usage bars should work again. 0013 // 0014 0015 #include "kdfwidget.h" 0016 0017 #include "kdfprivate_debug.h" 0018 #include "optiondialog.h" 0019 0020 #include <KMessageBox> 0021 #include <KShell> 0022 #include <KHelpClient> 0023 #include <KConfigGroup> 0024 0025 #include <QAbstractEventDispatcher> 0026 #include <QTimer> 0027 #include <QLayout> 0028 #include <QTreeView> 0029 #include <QStandardItemModel> 0030 #include <QStandardItem> 0031 #include <QPainter> 0032 #include <QMenu> 0033 #include <QProcess> 0034 #include <QDesktopServices> 0035 #include <QUrl> 0036 0037 //This aren't used here... 0038 //#define BAR_COLUMN 7 0039 //#define FULL_PERCENT 95.0 0040 0041 #ifndef GUI_DEFINED 0042 static bool GUI; 0043 #define GUI_DEFINED 0044 #endif 0045 0046 KDFWidget::KDFWidget( QWidget *parent, bool init ) 0047 : QWidget(parent) 0048 { 0049 connect(&mDiskList , &DiskList::readDFDone, 0050 this, &KDFWidget::updateDFDone ); 0051 connect(&mDiskList , &DiskList::criticallyFull, 0052 this, &KDFWidget::criticallyFull ); 0053 0054 m_columnList.append( Column( QStringLiteral( "Icon" ), QLatin1String( "" ), 20, IconCol )); 0055 m_columnList.append( Column( QStringLiteral( "Device" ), i18nc("Device of the storage", "Device"), 100, DeviceCol )); 0056 m_columnList.append( Column( QStringLiteral( "Type" ), i18nc("Filesystem on storage", "Type"), 80, TypeCol )); 0057 m_columnList.append( Column( QStringLiteral( "Size" ), i18nc("Total size of the storage", "Size"), 80, SizeCol )); 0058 m_columnList.append( Column( QStringLiteral( "MountPoint" ), i18nc("Mount point of storage", "Mount Point"), 120, MountPointCol )); 0059 m_columnList.append( Column( QStringLiteral( "Free" ), i18nc("Free space in storage", "Free"), 80, FreeCol )); 0060 m_columnList.append( Column( QStringLiteral( "Full%" ), i18nc("Used storage space in %", "Full %"), 50, FullCol )); 0061 m_columnList.append( Column( QStringLiteral( "UsageBar" ), i18nc("Usage graphical bar", "Usage"), 200, UsageBarCol )); 0062 0063 GUI = !init; 0064 if( GUI ) 0065 { 0066 QVBoxLayout *topLayout = new QVBoxLayout( this ); 0067 topLayout->setSpacing( 0 ); 0068 topLayout->setContentsMargins(0, 0, 0, 0); 0069 0070 m_listModel = new QStandardItemModel( this ); 0071 m_sortModel = new KDFSortFilterProxyModel( this ); 0072 m_sortModel->setSourceModel( m_listModel ); 0073 0074 m_listWidget = new QTreeView( this ); 0075 m_listWidget->setModel( m_sortModel ); 0076 0077 m_itemDelegate = new KDFItemDelegate( m_listWidget ); 0078 0079 m_listWidget->setItemDelegate( m_itemDelegate ); 0080 m_listWidget->setRootIsDecorated( false ); 0081 m_listWidget->setSortingEnabled( true ); 0082 m_listWidget->setContextMenuPolicy( Qt::CustomContextMenu ); 0083 m_listWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); 0084 0085 topLayout->addWidget( m_listWidget ); 0086 0087 connect( m_listWidget, &QWidget::customContextMenuRequested, 0088 this, &KDFWidget::contextMenuRequested); 0089 0090 makeColumns(); 0091 0092 mIsTopLevel = QLatin1String(parent->metaObject()->className()) == QLatin1String( "KDFTopLevel" ) ? true : false; 0093 } 0094 0095 loadSettings(); 0096 if( init ) 0097 applySettings(); 0098 } 0099 0100 KDFWidget::~KDFWidget() 0101 { 0102 delete m_listModel; 0103 delete m_sortModel; 0104 delete m_itemDelegate; 0105 delete m_listWidget; 0106 } 0107 0108 void KDFWidget::makeColumns( void ) 0109 { 0110 0111 QStringList columns; 0112 for (const Column &c : std::as_const(m_columnList)){ 0113 columns << c.columnName; 0114 } 0115 m_listModel->setHorizontalHeaderLabels( columns ); 0116 0117 } 0118 0119 /******************************************************************/ 0120 void KDFWidget::closeEvent(QCloseEvent *) 0121 { 0122 applySettings(); 0123 qApp->quit(); 0124 } 0125 0126 0127 void KDFWidget::settingsChanged( void ) 0128 { 0129 applySettings(); 0130 loadSettings(); 0131 } 0132 0133 0134 /*************************************************************************** 0135 * writes the KConfig 0136 **/ 0137 void KDFWidget::applySettings( void ) 0138 { 0139 KConfig m_config; 0140 KConfigGroup config( &m_config, QLatin1String("KDiskFree" )); 0141 0142 if( GUI ) 0143 { 0144 for (const Column &c : std::as_const(m_columnList)){ 0145 if( !m_listWidget->isColumnHidden( c.number ) ) 0146 config.writeEntry( c.name, m_listWidget->columnWidth(c.number) ); 0147 } 0148 0149 config.writeEntry("SortColumn", m_sortModel->sortColumn()); 0150 config.writeEntry("SortOrder", (int)m_sortModel->sortOrder()); 0151 0152 //Save the sort order of the QTreeView Header 0153 QHeaderView * header = m_listWidget->header(); 0154 QList<int> sectionIndices; 0155 for (int i = 0; i < header->count(); i++) { 0156 sectionIndices.append(header->visualIndex(i)); 0157 } 0158 config.writeEntry("HeaderSectionIndices", sectionIndices); 0159 } 0160 config.sync(); 0161 updateDF(); 0162 } 0163 0164 0165 /*************************************************************************** 0166 * reads the KConfig 0167 **/ 0168 void KDFWidget::loadSettings( void ) 0169 { 0170 mStd.updateConfiguration(); 0171 0172 if(GUI) 0173 { 0174 KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("KDiskFree")); 0175 for (const Column &c : std::as_const(m_columnList)){ 0176 int width = config.readEntry( c.name, c.defaultWidth ); 0177 m_listWidget->setColumnWidth( c.number, width ); 0178 } 0179 0180 KConfigGroup config_visible(KSharedConfig::openConfig(), QStringLiteral("KDFConfig")); 0181 for (const Column &c : std::as_const(m_columnList)){ 0182 bool visible = config_visible.readEntry( c.name , true ); 0183 m_listWidget->setColumnHidden( c.number, !visible ); 0184 } 0185 0186 int sortColumn = config.readEntry("SortColumn",0); 0187 int sortOrder = config.readEntry("SortOrder",(int)Qt::AscendingOrder); 0188 m_listWidget->sortByColumn(sortColumn,Qt::SortOrder(sortOrder)); 0189 0190 //Load the sort order of the QTreeView Header 0191 //This can also be achieved by header->saveState() and header->restoreState(...), 0192 //but this would not be "human-readable" any more... 0193 QHeaderView * header = m_listWidget->header(); 0194 QList<int> sectionIndices; 0195 sectionIndices = config.readEntry("HeaderSectionIndices",sectionIndices); 0196 if (sectionIndices.count() == header->count()) { 0197 for (int i = 0; i < header->count(); i++) { 0198 int sectionIndex = sectionIndices.at(i); 0199 int oldVisualIndex = header->visualIndex(sectionIndex); 0200 header->moveSection(oldVisualIndex,i); 0201 } 0202 } 0203 0204 setUpdateFrequency( mStd.updateFrequency() ); 0205 updateDF(); 0206 } 0207 } 0208 0209 0210 /*************************************************************************** 0211 * pops up the SettingsBox if the settingsBtn is clicked 0212 **/ 0213 void KDFWidget::settingsBtnClicked( void ) 0214 { 0215 if( mIsTopLevel ) 0216 { 0217 if( mOptionDialog == nullptr ) 0218 { 0219 mOptionDialog = new COptionDialog( this ); 0220 if( mOptionDialog == nullptr ) 0221 { 0222 return; 0223 } 0224 connect( mOptionDialog, &COptionDialog::valueChanged, 0225 this, &KDFWidget::settingsChanged ); 0226 } 0227 mOptionDialog->show(); 0228 } 0229 } 0230 0231 0232 /*************************************************************************** 0233 * resets the timer for automatic df-refreshes 0234 **/ 0235 void KDFWidget::setUpdateFrequency( int frequency ) 0236 { 0237 // 0238 // Kill current timer and restart it if the frequency is 0239 // larger than zero. 0240 // 0241 QAbstractEventDispatcher::instance()->unregisterTimers(this); 0242 if( frequency > 0 ) 0243 { 0244 startTimer( frequency * 1000 ); 0245 } 0246 } 0247 0248 /*************************************************************************** 0249 * Update (reread) all disk-dependencies 0250 **/ 0251 void KDFWidget::timerEvent(QTimerEvent *) 0252 { 0253 updateDF(); 0254 } 0255 0256 0257 /*************************************************************************** 0258 * checks fstab & df 0259 **/ 0260 void KDFWidget::updateDF( void ) 0261 { 0262 // 0263 // We can only do this if the popupmenu is not present 0264 // 0265 if( mPopup == nullptr ) 0266 { 0267 readingDF = true; 0268 mDiskList.readFSTAB(); 0269 mDiskList.readDF(); 0270 } 0271 } 0272 0273 /*************************************************************************** 0274 * gets the signal when the diskList is complete and up to date 0275 **/ 0276 void KDFWidget::updateDFDone( void ){ 0277 if (mPopup) //The popup menu is ont he screen... Don't touch the list view... 0278 return; 0279 0280 //Clear the list items 0281 m_listModel->removeRows(0,m_listModel->rowCount()); 0282 0283 DisksConstIterator itr = mDiskList.disksConstIteratorBegin(); 0284 DisksConstIterator end = mDiskList.disksConstIteratorEnd(); 0285 for (; itr != end; ++itr) 0286 { 0287 DiskEntry * disk = *itr; 0288 0289 QString size,percent; 0290 if( disk->kBSize() > 0 ) 0291 { 0292 percent = i18nc("Disk percentage", "%1%", QString::number(disk->percentFull())); 0293 size = disk->prettyKBSize(); 0294 } 0295 else 0296 { 0297 percent = i18n("N/A"); 0298 size = i18n("N/A"); 0299 } 0300 0301 bool root = !disk->mountOptions().contains(QLatin1String( "user" ), Qt::CaseInsensitive); 0302 0303 QStandardItem * IconItem = new QStandardItem( generateIcon(disk->iconName(), root, disk->mounted() ), QLatin1String( "" ) ); 0304 0305 QStandardItem * DeviceItem = new QStandardItem( disk->deviceName() ); 0306 0307 QStandardItem * TypeItem = new QStandardItem( disk->fsType() ); 0308 0309 QStandardItem * SizeItem = new QStandardItem( size ); 0310 SizeItem->setData( disk->kBSize(), Qt::UserRole ); 0311 0312 QStandardItem * MountPointItem = new QStandardItem( disk->mountPoint() ); 0313 0314 QStandardItem * FreeItem = new QStandardItem( disk->prettyKBAvail() ); 0315 FreeItem->setData( disk->kBAvail(), Qt::UserRole ); 0316 0317 QStandardItem * FullItem = new QStandardItem( percent ); 0318 FullItem->setData( disk->percentFull() , Qt::UserRole ); 0319 0320 QStandardItem * UsageBarItem = new QStandardItem( QLatin1String( "" ) ); 0321 UsageBarItem->setData( disk->percentFull(), Qt::UserRole ); 0322 0323 m_listModel->appendRow( QList<QStandardItem*>() << IconItem << DeviceItem << TypeItem << SizeItem << MountPointItem << 0324 FreeItem << FullItem << UsageBarItem); 0325 } 0326 0327 readingDF = false; 0328 0329 m_listModel->sort( DeviceCol ); 0330 0331 } 0332 0333 QIcon KDFWidget::generateIcon( const QString &iconName, bool mode, bool mounted) 0334 { 0335 const int smallIcon = qApp->style()->pixelMetric(QStyle::PM_SmallIconSize); 0336 QPixmap pix = QIcon::fromTheme( iconName ).pixmap(smallIcon); 0337 0338 QPainter painter(&pix); 0339 0340 if( mode ) 0341 painter.drawPixmap( QRect(0,6,10,10), QIcon::fromTheme(QStringLiteral( "object-locked" )).pixmap(smallIcon) ); 0342 0343 if( mounted ) 0344 painter.drawPixmap( QRect(6,6,12,12) , QIcon::fromTheme(QStringLiteral( "emblem-mounted" )).pixmap(smallIcon) ); 0345 0346 painter.end(); 0347 return QIcon(pix); 0348 0349 } 0350 0351 void KDFWidget::criticallyFull( DiskEntry *disk ) 0352 { 0353 if( mStd.popupIfFull() ) 0354 { 0355 QString msg = i18n("Device [%1] on [%2] is critically full.", 0356 disk->deviceName(), disk->mountPoint()); 0357 KMessageBox::error( this, msg, i18nc("Warning device getting critically full", "Warning")); 0358 } 0359 } 0360 0361 DiskEntry * KDFWidget::selectedDisk( const QModelIndex &index ) 0362 { 0363 if( !index.isValid() ) 0364 return nullptr; 0365 0366 QStandardItem * itemDevice = m_listModel->item( index.row() , DeviceCol ); 0367 QStandardItem * itemMountPoint = m_listModel->item( index.row() , MountPointCol ); 0368 0369 DiskEntry * disk = new DiskEntry( itemDevice->text() ); 0370 disk->setMountPoint( itemMountPoint->text() ); 0371 0372 int pos = mDiskList.find( disk ); 0373 0374 delete disk; 0375 return mDiskList.at(pos); 0376 0377 } 0378 0379 void KDFWidget::contextMenuRequested( const QPoint &p ) 0380 { 0381 if (mPopup) //The user may even be able to popup another menu while this open is active... 0382 return; 0383 0384 QModelIndex index = m_listWidget->indexAt( p ); 0385 0386 if( !index.isValid() ) 0387 { 0388 QList<QModelIndex> selected = m_listWidget->selectionModel()->selectedIndexes(); 0389 if ( selected.size() > 0 ) 0390 index = selected.at(0); 0391 else 0392 return; 0393 } 0394 0395 index = m_sortModel->mapToSource( index ); 0396 0397 mDiskList.setUpdatesDisabled(true); 0398 DiskEntry * disk = selectedDisk( index ); 0399 0400 if( disk == nullptr ) 0401 return; 0402 0403 mPopup = new QMenu( nullptr ); 0404 mPopup->setTitle( disk->mountPoint() ); 0405 QAction *mountPointAction = mPopup->addAction( i18n("Mount Device") ); 0406 QAction *umountPointAction = mPopup->addAction( i18n("Unmount Device") ); 0407 mPopup->addSeparator(); 0408 QAction *openFileManagerAction = mPopup->addAction( i18n("Open in File Manager") ); 0409 mountPointAction->setEnabled( !disk->mounted() ); 0410 umountPointAction->setEnabled( disk->mounted() ); 0411 openFileManagerAction->setEnabled( disk->mounted() ); 0412 QAction *position = mPopup->exec( m_listWidget->mapToGlobal(p) ); 0413 0414 bool openFileManager = false; 0415 if( !position ) 0416 { 0417 mDiskList.setUpdatesDisabled(false); 0418 delete mPopup; 0419 mPopup = nullptr; 0420 return; 0421 } 0422 else if( position == mountPointAction || position == umountPointAction ) 0423 { 0424 QStandardItem * SizeItem = m_listModel->item( index.row() , SizeCol ); 0425 SizeItem->setText( i18n("MOUNTING") ); 0426 0427 QStandardItem * FreeItem = m_listModel->item( index.row() , FreeCol ); 0428 FreeItem->setText( i18n("MOUNTING") ); 0429 0430 QStandardItem * IconItem = m_listModel->item( index.row() , IconCol ); 0431 IconItem->setIcon( QIcon::fromTheme(QStringLiteral( "user-away" )) ); 0432 0433 int val = disk->toggleMount(); 0434 if( val != 0 /*== false*/ ) 0435 { 0436 KMessageBox::error( this, disk->lastSysError() ); 0437 } 0438 else if ( mStd.openFileManager() 0439 && (position == mountPointAction) ) //only on mount 0440 { 0441 openFileManager = true; 0442 } 0443 0444 //delete item; 0445 mDiskList.deleteAllMountedAt(disk->mountPoint()); 0446 } 0447 else if( position == openFileManagerAction ) 0448 { 0449 openFileManager = true; 0450 } 0451 0452 if( openFileManager ) 0453 { 0454 qCDebug(KDF) << "opening filemanager"; 0455 if( mStd.useSystemFileManager() ) 0456 { 0457 QDesktopServices::openUrl( QUrl::fromLocalFile( disk->mountPoint() ) ); 0458 } 0459 else if( !mStd.fileManager().isEmpty() ) 0460 { 0461 QString cmd = mStd.fileManager(); 0462 int pos = cmd.indexOf(QLatin1String( "%m" )); 0463 if( pos > 0 ) 0464 { 0465 cmd.replace(pos, 2, KShell::quoteArg(disk->mountPoint())); 0466 } 0467 else 0468 { 0469 cmd += QLatin1Char( ' ' ) + KShell::quoteArg(disk->mountPoint()); 0470 } 0471 QStringList argList = cmd.split(QLatin1Char( ' ' ), Qt::SkipEmptyParts); 0472 cmd = argList.takeFirst(); 0473 QProcess::startDetached(cmd, argList); 0474 } 0475 } 0476 0477 //Update only here as showing of error message triggers event loop. 0478 mDiskList.setUpdatesDisabled(false); 0479 delete mPopup; 0480 mPopup = nullptr; 0481 0482 if( position != openFileManagerAction ) // No need to update when just opening the fm. 0483 { 0484 updateDF(); 0485 } 0486 0487 } 0488 0489 void KDFWidget::invokeHelp() 0490 { 0491 KHelpClient::invokeHelp(QLatin1String( "" ), QStringLiteral( "kcontrol/kdf" )); 0492 } 0493 0494 0495 #include "moc_kdfwidget.cpp"