File indexing completed on 2024-05-05 04:51:37

0001 /*
0002     SPDX-FileCopyrightText: 2003-2008 Sebastian Trueg <trueg@k3b.org>
0003     SPDX-FileCopyrightText: 2010-2011 Michal Malek <michalm@jabster.pl>
0004     SPDX-FileCopyrightText: 1998-2008 Sebastian Trueg <trueg@k3b.org>
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 
0009 #include "k3bdevicewidget.h"
0010 #include "k3bdevicemanager.h"
0011 #include "k3bdevice.h"
0012 #include "k3bdeviceglobals.h"
0013 
0014 #include <KAuth/Action>
0015 #include <KAuth/ExecuteJob>
0016 #include <KConfig>
0017 #include <KLocalizedString>
0018 #include <KIO/Global>
0019 #include <KMessageWidget>
0020 
0021 #include <QFileInfo>
0022 #include <QColor>
0023 #include <QIcon>
0024 #include <QAction>
0025 #include <QGridLayout>
0026 #include <QGroupBox>
0027 #include <QHBoxLayout>
0028 #include <QHeaderView>
0029 #include <QLayout>
0030 #include <QList>
0031 #include <QPushButton>
0032 #include <QString>
0033 #include <QToolTip>
0034 #include <QTreeWidget>
0035 #include <QVariant>
0036 #include <QVBoxLayout>
0037 
0038 #include <grp.h>
0039 #include <unistd.h>
0040 #include <pwd.h>
0041 
0042 
0043 K3b::DeviceWidget::DeviceWidget( K3b::Device::DeviceManager* manager, QWidget *parent )
0044     : QWidget( parent ),
0045       m_deviceManager( manager ),
0046       m_writerParentViewItem( 0 ),
0047       m_readerParentViewItem( 0 )
0048 {
0049     // message widget
0050     m_messageWidget = new KMessageWidget( this );
0051     m_messageWidget->hide();
0052     m_messageWidget->setWordWrap( true );
0053     m_addToGroupAction = new QAction( QIcon::fromTheme("dialog-password"), QString(), this );
0054 
0055     // buttons
0056     // ------------------------------------------------
0057     QPushButton* buttonRefreshDevices = new QPushButton( QIcon::fromTheme( "view-refresh" ), i18n( "Refresh" ), this );
0058     buttonRefreshDevices->setToolTip( i18n( "Rescan the devices" ) );
0059     QHBoxLayout* refreshButtonGrid = new QHBoxLayout;
0060     refreshButtonGrid->setContentsMargins( 0, 0, 0, 0 );
0061     refreshButtonGrid->addStretch();
0062     refreshButtonGrid->addWidget( buttonRefreshDevices );
0063     // ------------------------------------------------
0064 
0065     // Devices view
0066     // ------------------------------------------------
0067     m_viewDevices = new QTreeWidget( this );
0068     m_viewDevices->setAllColumnsShowFocus( true );
0069     m_viewDevices->setHeaderHidden( true );
0070     m_viewDevices->setColumnCount( 2 );
0071     m_viewDevices->setSelectionMode( QAbstractItemView::NoSelection );
0072     m_viewDevices->setItemsExpandable( false );
0073     m_viewDevices->setRootIsDecorated( false );
0074     m_viewDevices->header()->setSectionResizeMode( 0, QHeaderView::ResizeToContents );
0075     m_viewDevices->setFocusPolicy( Qt::NoFocus );
0076     m_viewDevices->setVerticalScrollMode( QAbstractItemView::ScrollPerPixel );
0077     // ------------------------------------------------
0078 
0079     QVBoxLayout* frameLayout = new QVBoxLayout( this );
0080     frameLayout->setContentsMargins( 0, 0, 0, 0 );
0081     frameLayout->addWidget( m_messageWidget, 0 );
0082     frameLayout->addWidget( m_viewDevices, 1 );
0083     frameLayout->addLayout( refreshButtonGrid, 0 );
0084     // ------------------------------------------------
0085 
0086     // connections
0087     // ------------------------------------------------
0088     connect( buttonRefreshDevices, SIGNAL(clicked()), SIGNAL(refreshButtonClicked()) );
0089     connect( m_deviceManager, SIGNAL(changed()), SLOT(init()) );
0090     connect( m_addToGroupAction, SIGNAL(triggered(bool)), SLOT(addUserToGroup()) );
0091     // ------------------------------------------------
0092 }
0093 
0094 
0095 K3b::DeviceWidget::~DeviceWidget()
0096 {
0097 }
0098 
0099 
0100 void K3b::DeviceWidget::init()
0101 {
0102     updateDeviceListViews();
0103 }
0104 
0105 
0106 void K3b::DeviceWidget::updateDeviceListViews()
0107 {
0108     QColor disabledTextColor = palette().color( QPalette::Disabled, QPalette::Text );
0109 
0110     m_viewDevices->clear();
0111 
0112     // create the parent view items
0113     // -----------------------------------------
0114     m_writerParentViewItem = new QTreeWidgetItem( m_viewDevices, QStringList() << i18n("Writer Drives") );
0115     m_writerParentViewItem->setIcon( 0, QIcon::fromTheme( "media-optical-recordable" ) );
0116     // spacer item
0117     QTreeWidgetItem* spacer = new QTreeWidgetItem( m_viewDevices );
0118     spacer->setFlags( Qt::NoItemFlags );
0119     m_readerParentViewItem = new QTreeWidgetItem( m_viewDevices, QStringList() << i18n("Read-only Drives") );
0120     m_readerParentViewItem->setIcon( 0, QIcon::fromTheme( "media-optical" ) );
0121     // -----------------------------------------
0122 
0123     QFont fBold( m_viewDevices->font() );
0124     fBold.setBold(true);
0125     QFont fItalic( m_viewDevices->font() );
0126     fItalic.setItalic(true);
0127 
0128     foreach( Device::Device* dev, m_deviceManager->allDevices() ) {
0129         // create the root device item
0130         QTreeWidgetItem* devRoot = new QTreeWidgetItem( (dev->burner() ? m_writerParentViewItem : m_readerParentViewItem),
0131                                                         QStringList() << ( dev->vendor() + ' ' + dev->description() ) );
0132         devRoot->setFont( 0, fBold );
0133 
0134         // create the read-only info items
0135         QTreeWidgetItem* systemDeviceItem = new QTreeWidgetItem( devRoot, QStringList() << i18n("System device name:") );
0136         systemDeviceItem->setText( 1, dev->blockDeviceName() );
0137         systemDeviceItem->setForeground( 0, disabledTextColor );
0138         systemDeviceItem->setTextAlignment( 0, Qt::AlignRight );
0139 
0140         QTreeWidgetItem* vendorItem = new QTreeWidgetItem( devRoot, systemDeviceItem );
0141         vendorItem->setText( 0, i18n("Vendor:") );
0142         vendorItem->setText( 1, dev->vendor() );
0143         vendorItem->setForeground( 0, disabledTextColor );
0144         vendorItem->setTextAlignment( 0, Qt::AlignRight );
0145 
0146         QTreeWidgetItem* modelItem = new QTreeWidgetItem( devRoot, vendorItem );
0147         modelItem->setText( 0, i18n("Description:") );
0148         modelItem->setText( 1, dev->description() );
0149         modelItem->setForeground( 0, disabledTextColor );
0150         modelItem->setTextAlignment( 0, Qt::AlignRight );
0151 
0152         QTreeWidgetItem* versionItem = new QTreeWidgetItem( devRoot, modelItem );
0153         versionItem->setText( 0, i18n("Firmware:") );
0154         versionItem->setText( 1, dev->version() );
0155         versionItem->setForeground( 0, disabledTextColor );
0156         versionItem->setTextAlignment( 0, Qt::AlignRight );
0157 
0158 
0159         // drive type
0160         // --------------------------------
0161         QTreeWidgetItem* typeItem = new QTreeWidgetItem( devRoot, versionItem );
0162         typeItem->setText( 0, i18n("Write Capabilities:") );
0163         typeItem->setText( 1, K3b::Device::mediaTypeString( dev->writeCapabilities(), true ) );
0164         typeItem->setToolTip( 1, typeItem->text(1) );
0165         typeItem->setForeground( 0, disabledTextColor );
0166         typeItem->setTextAlignment( 0, Qt::AlignRight );
0167 
0168         typeItem = new QTreeWidgetItem( devRoot, typeItem );
0169         typeItem->setText( 0, i18n("Read Capabilities:") );
0170         typeItem->setText( 1, K3b::Device::mediaTypeString( dev->readCapabilities(), true ) );
0171         typeItem->setToolTip( 1, typeItem->text(1) );
0172         typeItem->setForeground( 0, disabledTextColor );
0173         typeItem->setTextAlignment( 0, Qt::AlignRight );
0174         // --------------------------------
0175 
0176 
0177         // now add the reader (both interfaces) items
0178         if( dev->bufferSize() > 0 ) {
0179             typeItem = new QTreeWidgetItem( devRoot, typeItem );
0180             typeItem->setText( 0, i18n("Buffer Size:") );
0181             typeItem->setText( 1, KIO::convertSizeFromKiB(dev->bufferSize()) );
0182             typeItem->setForeground( 0, disabledTextColor );
0183             typeItem->setTextAlignment( 0, Qt::AlignRight );
0184         }
0185 
0186 
0187         // now add the writer specific items
0188         if( dev->burner() ) {
0189             typeItem = new QTreeWidgetItem( devRoot, typeItem );
0190             typeItem->setText( 0, i18n("Supports Burnfree:") );
0191             typeItem->setText( 1, dev->burnfree() ? i18n("yes") : i18n("no") );
0192             typeItem->setForeground( 0, disabledTextColor );
0193             typeItem->setTextAlignment( 0, Qt::AlignRight );
0194 
0195             // and at last the write modes
0196             typeItem = new QTreeWidgetItem( devRoot, typeItem );
0197             typeItem->setText( 0, i18n("Write modes:") );
0198             typeItem->setText( 1, K3b::Device::writingModeString(dev->writingModes()) );
0199             typeItem->setToolTip( 1, typeItem->text(1) );
0200             typeItem->setForeground( 0, disabledTextColor );
0201             typeItem->setTextAlignment( 0, Qt::AlignRight );
0202         }
0203     }
0204 
0205     // create empty items
0206     if( m_writerParentViewItem->childCount() == 0 ) {
0207         QTreeWidgetItem* item = new QTreeWidgetItem( m_writerParentViewItem );
0208         item->setText( 0, i18n("none") );
0209         item->setFont( 0, fItalic );
0210     }
0211     if( m_readerParentViewItem->childCount() == 0 ) {
0212         QTreeWidgetItem* item = new QTreeWidgetItem( m_readerParentViewItem );
0213         item->setText( 0, i18n("none") );
0214         item->setFont( 0, fItalic );
0215     }
0216 
0217     m_viewDevices->expandAll();
0218 
0219     // Show warning message if the current user does not belong to
0220     // the group device belongs to
0221     QList<Device::Device*> devices = m_deviceManager->allDevices();
0222     if( !devices.empty() ) {
0223         QFileInfo fileInfo( devices.front()->blockDeviceName() );
0224         m_deviceGroup = fileInfo.group();
0225 
0226         if( m_deviceGroup != "root" ) {
0227             QVector<gid_t> gids(::getgroups(0, 0));
0228             ::getgroups(gids.size(), gids.data());
0229 
0230             QSet<QString> groupNames;
0231             Q_FOREACH( gid_t gid, gids ) {
0232                 if( ::group* g = ::getgrgid( gid ) ) {
0233                     groupNames.insert( QString::fromLocal8Bit( g->gr_name ) );
0234                 }
0235             }
0236 
0237             if (!groupNames.contains(m_deviceGroup)) {
0238         QString messageText = i18n("In order to give K3b full access to the writer device the current user needs be added to a group <em>%1</em>.", m_deviceGroup);
0239                 m_messageWidget->setMessageType(KMessageWidget::Warning);
0240                 m_messageWidget->setText(messageText);
0241                 m_messageWidget->addAction(m_addToGroupAction);
0242                 m_addToGroupAction->setText(i18n("Add"));
0243                 m_messageWidget->animatedShow();
0244             }
0245         }
0246     }
0247 }
0248 
0249 void K3b::DeviceWidget::addUserToGroup()
0250 {
0251     QVariantMap args;
0252     args["groupName"] = m_deviceGroup;
0253     args["userName"] = QString::fromLocal8Bit(getpwuid(getuid())->pw_name);
0254 
0255     KAuth::Action action("org.kde.k3b.addtogroup");
0256     action.setHelperId("org.kde.k3b");
0257 #if QT_VERSION_MAJOR == 5
0258     action.setParentWidget(this);
0259 #else
0260     action.setParentWindow(window()->windowHandle());
0261 #endif
0262     action.setArguments(args);
0263 
0264     KAuth::ExecuteJob* job = action.execute();
0265     connect( job, &KAuth::ExecuteJob::result, [this, job]()
0266     {
0267         if( job->error() == KJob::NoError ) {
0268             m_messageWidget->removeAction(m_addToGroupAction);
0269             m_messageWidget->setMessageType(KMessageWidget::Information);
0270             m_messageWidget->setText(i18n("Please relogin to apply the changes."));
0271         } else {
0272             m_messageWidget->setMessageType(KMessageWidget::Error);
0273             m_messageWidget->setText(i18n("Unable to execute the action: %1 (Error code: %2)", job->errorString(), job->error()));
0274             m_addToGroupAction->setText(i18n("Retry"));
0275         }
0276     } );
0277     job->start();
0278 }
0279 
0280 #include "moc_k3bdevicewidget.cpp"