File indexing completed on 2024-04-14 05:43:05

0001 /*
0002     SPDX-FileCopyrightText: 1999 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-12-03 Espen Sand
0010 // Cleanups, improvements and fixes for KDE-2
0011 //
0012 // 2004-07-15 Stanislav Karchebny
0013 // Rewrite for KDE 3
0014 //
0015 
0016 #include "kwikdisk.h"
0017 
0018 #include "kdf_version.h"
0019 #include "kwikdisk_debug.h"
0020 
0021 #include <KAboutData>
0022 #include <KDialogJobUiDelegate>
0023 #include <KHelpClient>
0024 #include <KMessageBox>
0025 #include <KIO/CommandLauncherJob>
0026 #include <KShell>
0027 #include <KLocalizedString>
0028 
0029 #include <QApplication>
0030 #include <QCommandLineParser>
0031 #include <QAbstractEventDispatcher>
0032 #include <QPainter>
0033 #include <QPixmap>
0034 #include <QActionGroup>
0035 #include <QMenu>
0036 #include <QProcess>
0037 
0038 #include <unistd.h>
0039 
0040 /*****************************************************************************/
0041 
0042 KwikDisk::KwikDisk()
0043         : KStatusNotifierItem()
0044         , m_readingDF(false)
0045         , m_dirty(true)
0046         , m_inside(false)
0047         , m_optionDialog(nullptr)
0048 {
0049     qCDebug(KDF);
0050 
0051     setIconByName(QStringLiteral("kdf"));
0052 
0053     connect( &m_diskList, &DiskList::readDFDone, this, &KwikDisk::updateDFDone );
0054     connect( &m_diskList, &DiskList::criticallyFull,
0055              this, &KwikDisk::criticallyFull );
0056 
0057     m_actionGroup = new QActionGroup( this );
0058     connect( m_actionGroup, &QActionGroup::triggered , this, &KwikDisk::toggleMount );
0059 
0060     QMenu *contextMenu = new QMenu(i18n("KwikDisk"));
0061 
0062     m_actionSeparator = contextMenu->addSeparator();
0063 
0064     contextMenu->addAction(
0065         QIcon::fromTheme(QStringLiteral( "kdf" )),
0066         i18n("&Start KDiskFree"), this, &KwikDisk::startKDF);
0067 
0068     contextMenu->addAction(
0069         QIcon::fromTheme(QStringLiteral( "configure" )),
0070         i18n("&Configure KwikDisk..."), this, &KwikDisk::changeSettings);
0071 
0072     contextMenu->addAction(
0073         QIcon::fromTheme(QStringLiteral( "help-contents" )),
0074         KStandardGuiItem::help().text(), this, &KwikDisk::invokeHelp);
0075 
0076     setContextMenu(contextMenu);
0077 
0078     setStatus(KStatusNotifierItem::Active);
0079 
0080     loadSettings();
0081     updateDF();
0082 }
0083 
0084 void KwikDisk::enterEvent(QEvent *)
0085 {
0086     qCDebug(KDF);
0087     m_inside = true;
0088 }
0089 
0090 void KwikDisk::leaveEvent(QEvent *)
0091 {
0092     qCDebug(KDF);
0093     m_inside = false;
0094 }
0095 
0096 void KwikDisk::activate(const QPoint &pos)
0097 {
0098     Q_UNUSED(pos);
0099     qCDebug(KDF);
0100 
0101     if( m_dirty )
0102         updateDF();
0103 }
0104 
0105 void KwikDisk::loadSettings()
0106 {
0107     qCDebug(KDF);
0108 
0109     m_options.updateConfiguration();
0110     setUpdateFrequency( m_options.updateFrequency() );
0111 }
0112 
0113 void KwikDisk::setUpdateFrequency(int frequency)
0114 {
0115     qCDebug(KDF);
0116 
0117     //
0118     // Kill current timer and restart it if the frequency is
0119     // larger than zero.
0120     //
0121     QAbstractEventDispatcher::instance()->unregisterTimers(this);
0122     if( frequency > 0 )
0123     {
0124         startTimer(frequency * 1000);
0125     }
0126 }
0127 
0128 /**
0129  * Mark the list as dirty thus forcing a reload the next time the
0130  * popup menu is about to become visible. Note: A current visible popup
0131  * will not be updated now.
0132  */
0133 void KwikDisk::timerEvent(QTimerEvent *)
0134 {
0135     qCDebug(KDF);
0136     m_dirty = true;
0137 }
0138 
0139 void KwikDisk::updateDF()
0140 {
0141     qCDebug(KDF);
0142 
0143     m_readingDF = true;
0144     m_diskList.readFSTAB();
0145     m_diskList.readDF();
0146 }
0147 
0148 void KwikDisk::clearDeviceActions()
0149 {
0150     QList<QAction*> listActions = m_actionGroup->actions();
0151     QMutableListIterator<QAction*> it(listActions);
0152     while( it.hasNext() )
0153     {
0154         QAction * action = it.next();
0155         m_actionGroup->removeAction( action );
0156         contextMenu()->removeAction( action );
0157         delete action;
0158     }
0159 }
0160 void KwikDisk::updateDFDone()
0161 {
0162     qCDebug(KDF);
0163 
0164     m_readingDF = false;
0165     m_dirty     = false;
0166 
0167     clearDeviceActions();
0168 
0169     int itemNo = 0;
0170 
0171     DisksConstIterator itr = m_diskList.disksConstIteratorBegin();
0172     DisksConstIterator end = m_diskList.disksConstIteratorEnd();
0173     for (; itr != end; ++itr)
0174     {
0175         DiskEntry * disk = *itr;
0176 
0177         QString toolTipText = QStringLiteral("%1 (%2) %3 on %4")
0178           .arg( disk->mounted() ? i18nc("Unmount the storage device", "Unmount") : i18nc("Mount the storage device", "Mount") )
0179           .arg( disk->fsType().trimmed() ).arg( disk->deviceName().trimmed() ).arg( disk->mountPoint().trimmed() );
0180 
0181         QString entryName = disk->mountPoint().trimmed();
0182         if( disk->mounted() )
0183         {
0184             entryName += QStringLiteral("\t[%1]").arg(disk->prettyKBAvail());
0185         }
0186 
0187         QAction * action = new QAction(entryName, m_actionGroup);
0188         action->setToolTip( toolTipText );
0189         action->setData( itemNo );
0190         itemNo++;
0191 
0192         QPixmap pix = QIcon::fromTheme(disk->iconName()).pixmap(QSize(32,32));
0193 
0194         if( getuid() !=0 && !disk->mountOptions().contains(QLatin1String( "user" ),Qt::CaseInsensitive) )
0195         {
0196             QPainter painter( &pix );
0197             QPixmap lockedPixmap = QIcon::fromTheme(QStringLiteral( "object-locked" )).pixmap(QSize(16,16));
0198             painter.drawPixmap( QRect(0,0,16,16) , lockedPixmap, QRect(0,0,16,16));
0199             painter.end();
0200 
0201             toolTipText = i18n("You must login as root to mount this disk");
0202             action->setToolTip( toolTipText );
0203         }
0204 
0205         if( disk->mounted() )
0206         {
0207             QPainter painter ( &pix );
0208             QPixmap mountedPixmap = QIcon::fromTheme(QStringLiteral( "emblem-mounted" )).pixmap(QSize(16,16));
0209             painter.drawPixmap( QRect(8,8,16,16) , mountedPixmap, QRect(0,0,16,16) );
0210             painter.end();
0211         }
0212 
0213         action->setIcon( pix );
0214 
0215     }
0216 
0217     contextMenu()->insertActions( m_actionSeparator, m_actionGroup->actions() );
0218 
0219 }
0220 
0221 void KwikDisk::toggleMount(QAction * action)
0222 {
0223     qCDebug(KDF);
0224     if ( !action )
0225         return;
0226 
0227     DiskEntry *disk = m_diskList.at( action->data().toInt() );
0228     if( disk == nullptr )
0229     {
0230         return;
0231     }
0232 
0233     int val = disk->toggleMount();
0234     if( val != 0 )
0235     {
0236         KMessageBox::error(nullptr, disk->lastSysError());
0237     }
0238     else if( m_options.openFileManager() && ( disk->mounted() ) )
0239     {
0240         qCDebug(KDF) << "opening filemanager";
0241         if( !m_options.fileManager().isEmpty() )
0242         {
0243             QString cmd = m_options.fileManager();
0244             int pos = cmd.indexOf(QLatin1String( "%m" ));
0245             if( pos > 0 )
0246             {
0247                 cmd.replace( pos, 2, KShell::quoteArg(disk->mountPoint()) );
0248             }
0249             else
0250             {
0251                 cmd += QLatin1Char( ' ' ) + KShell::quoteArg(disk->mountPoint());
0252             }
0253             QStringList argList = cmd.split(QLatin1Char( ' ' ), Qt::SkipEmptyParts);
0254             cmd = argList.takeFirst();
0255             QProcess::startDetached(cmd, argList);
0256         }
0257     }
0258     m_dirty = true;
0259 }
0260 
0261 void KwikDisk::criticallyFull(DiskEntry *disk)
0262 {
0263     qCDebug(KDF);
0264 
0265     if( m_options.popupIfFull())
0266     {
0267         QString msg = i18n("Device [%1] on [%2] is critically full.",
0268                            disk->deviceName(), disk->mountPoint());
0269         KMessageBox::error( nullptr, msg, i18nc("Device is getting critically full", "Warning"));
0270     }
0271 }
0272 
0273 void KwikDisk::changeSettings()
0274 {
0275     if( m_optionDialog == nullptr )
0276     {
0277         m_optionDialog = new COptionDialog(nullptr);
0278         if( !m_optionDialog )
0279             return;
0280         connect(m_optionDialog, &COptionDialog::valueChanged,
0281                 this, &KwikDisk::loadSettings);
0282     }
0283     m_optionDialog->show();
0284 }
0285 
0286 void KwikDisk::startKDF()
0287 {
0288     qCDebug(KDF);
0289 
0290     auto *job = new KIO::CommandLauncherJob(QStringLiteral("kdf"));
0291     job->setUiDelegate(new KDialogJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, nullptr));
0292     job->start();
0293 }
0294 
0295 void KwikDisk::invokeHelp()
0296 {
0297     KHelpClient::invokeHelp(QLatin1String(""), QStringLiteral("kdf"));
0298 }
0299 
0300 /*****************************************************************************/
0301 
0302 int main(int argc, char **argv)
0303 {
0304     QApplication app(argc, argv);
0305 
0306     KLocalizedString::setApplicationDomain(QByteArrayLiteral("kdf"));
0307 
0308     KAboutData aboutData(QStringLiteral("kwikdisk"),
0309                      i18n("KwikDisk"),
0310                      QStringLiteral(KDF_VERSION_STRING),
0311                      i18n("KDE Free disk space utility"),
0312                      KAboutLicense::GPL,
0313                      i18n("(C) 2004 Stanislav Karchebny"),
0314                      QString(),
0315                      QStringLiteral("https://apps.kde.org/kdf"),
0316                      QStringLiteral("Stanislav.Karchebny@kdemail.net"));
0317 
0318     aboutData.addAuthor(i18n("Michael Kropfberger"),
0319                     i18n("Original author"),
0320                     QStringLiteral("michael.kropfberger@gmx.net"));
0321     aboutData.addAuthor(i18n("Espen Sand"),
0322                     i18n("KDE 2 changes"));
0323     aboutData.addAuthor(i18n("Stanislav Karchebny"),
0324                     i18n("KDE 3 changes"),
0325                     QStringLiteral("Stanislav.Karchebny@kdemail.net"));
0326 
0327     QCommandLineParser parser;
0328     parser.setApplicationDescription(aboutData.shortDescription());
0329 
0330     aboutData.setupCommandLine(&parser);
0331 
0332     KAboutData::setApplicationData(aboutData);
0333 
0334     // do the command line parsing
0335     parser.process(app);
0336 
0337     // handle standard options
0338     aboutData.processCommandLine(&parser);
0339 
0340     KwikDisk mainWin;
0341 
0342     //Avoid quit when closing the KwikDisk Settings dialog
0343     app.setQuitOnLastWindowClosed( false );
0344 
0345     // mainWin has WDestructiveClose flag by default, so it will delete itself.
0346     return app.exec();
0347 }
0348 
0349 /*****************************************************************************/
0350 
0351 
0352 
0353 #include "moc_kwikdisk.cpp"