1 /*
2     SPDX-FileCopyrightText: 2010 Michal Malek <michalm@jabster.pl>
3     SPDX-FileCopyrightText: 1998-2008 Sebastian Trueg <trueg@k3b.org>
4 
5     SPDX-License-Identifier: GPL-2.0-or-later
6 */
7 
8 #include "k3bexternalbinwidget.h"
9 #include "k3bexternalbinmanager.h"
10 #include "k3bexternalbinmodel.h"
11 #include "k3bexternalbinparamsmodel.h"
12 #include "k3bexternalbinpermissionmodel.h"
13 #include "config-k3b.h"
14 
15 #include <KAuth>
16 #include <KLocalizedString>
17 #include <KMessageBox>
18 #include <KEditListWidget>
19 
20 #include <QDebug>
21 #include <QItemSelectionModel>
22 #include <QMap>
23 #include <QStringList>
24 #include <QCursor>
25 #include <QPixmap>
26 #include <QApplication>
27 #include <QHeaderView>
28 #include <QLabel>
29 #include <QLayout>
30 #include <QPushButton>
31 #include <QTabWidget>
32 #include <QToolTip>
33 #include <QTreeView>
34 #include <QVBoxLayout>
35 
36 #include <grp.h>
37 
38 
39 
40 // ///////////////////////////////////////////////////////////
41 //
42 // K3BEXTERNALBINWIDGET
43 //
44 // //////////////////////////////////////////////////////////
45 
46 
ExternalBinWidget(K3b::ExternalBinManager * manager,QWidget * parent)47 K3b::ExternalBinWidget::ExternalBinWidget( K3b::ExternalBinManager* manager, QWidget* parent )
48     : QWidget( parent ),
49       m_manager( manager ),
50       m_programModel( new ExternalBinModel( manager, this ) ),
51       m_parameterModel( new ExternalBinParamsModel( manager, this ) )
52 {
53     QGridLayout* mainGrid = new QGridLayout( this );
54     mainGrid->setContentsMargins( 0, 0, 0, 0 );
55 
56     m_mainTabWidget = new QTabWidget( this );
57     m_rescanButton = new QPushButton( QIcon::fromTheme( "view-refresh" ), i18n( "Refresh" ), this );
58     mainGrid->addWidget( m_mainTabWidget, 0, 0, 1, 3 );
59     mainGrid->addWidget( m_rescanButton, 1, 2 );
60     mainGrid->setColumnStretch( 0, 1 );
61     mainGrid->setRowStretch( 0, 1 );
62 
63     // setup program tab
64     // ------------------------------------------------------------
65     QWidget* programTab = new QWidget( m_mainTabWidget );
66     m_programView = new QTreeView( programTab );
67     m_programView->setModel( m_programModel );
68     m_programView->setAllColumnsShowFocus( true );
69     m_programView->setRootIsDecorated( false );
70     m_programView->setItemsExpandable( false );
71     m_programView->header()->setSectionResizeMode( ExternalBinModel::PathColumn, QHeaderView::ResizeToContents );
72     m_programView->header()->setSectionResizeMode( ExternalBinModel::VersionColumn, QHeaderView::ResizeToContents );
73     m_programView->setWhatsThis( i18n("<p>If K3b finds more than one installed version of a program "
74                                       "it will choose one as the <em>default</em>, which will be used "
75                                       "to do the work. If you want to change the default, check "
76                                       "desired version on the list.") );
77 
78     QVBoxLayout* programTabLayout = new QVBoxLayout( programTab );
79     programTabLayout->addWidget( m_programView );
80 
81     m_mainTabWidget->addTab( programTab, i18n("Programs") );
82 
83 
84     // setup parameters tab
85     // ------------------------------------------------------------
86     QWidget* parametersTab = new QWidget( m_mainTabWidget );
87     QLabel* parametersLabel = new QLabel( i18n("User parameters have to be separated by space."), parametersTab );
88     parametersLabel->setWordWrap( true );
89     m_parameterView = new QTreeView( parametersTab );
90     m_parameterView->setModel( m_parameterModel );
91     m_parameterView->setAllColumnsShowFocus( true );
92     m_parameterView->setRootIsDecorated( false );
93     m_parameterView->setEditTriggers( QAbstractItemView::AllEditTriggers );
94     m_parameterView->header()->setSectionResizeMode( QHeaderView::ResizeToContents );
95 
96     QVBoxLayout* parametersTabLayout = new QVBoxLayout( parametersTab );
97     parametersTabLayout->addWidget( parametersLabel );
98     parametersTabLayout->addWidget( m_parameterView, 1 );
99 
100     m_mainTabWidget->addTab( parametersTab, i18n("User Parameters") );
101 
102 
103     // setup permissions tab
104     // ------------------------------------------------------------
105     QWidget* permissionsTab = new QWidget( m_mainTabWidget );
106     QLabel* permissionsLabel = new QLabel( i18n("Check the programs whose permissions you want to be changed:"), permissionsTab );
107     permissionsLabel->setWordWrap( true );
108     m_permissionModel = new ExternalBinPermissionModel( *manager, permissionsTab );
109     m_permissionView = new QTreeView( permissionsTab );
110     m_permissionView->setModel( m_permissionModel );
111     m_permissionView->setAllColumnsShowFocus( true );
112     m_permissionView->setRootIsDecorated( false );
113     m_permissionView->header()->setSectionResizeMode( ExternalBinPermissionModel::ProgramColumn, QHeaderView::ResizeToContents );
114     m_changePermissionsButton = new QPushButton( QIcon::fromTheme("dialog-password"), i18n( "Change Permissions..." ), this );
115     QVBoxLayout* permissionsTabLayout = new QVBoxLayout( permissionsTab );
116     permissionsTabLayout->addWidget( permissionsLabel );
117     permissionsTabLayout->addWidget( m_permissionView );
118     permissionsTabLayout->addWidget( m_changePermissionsButton );
119     m_mainTabWidget->addTab( permissionsTab, i18n("Permissions") );
120 
121 
122     // setup search path tab
123     // ------------------------------------------------------------
124     QWidget* searchPathTab = new QWidget( m_mainTabWidget );
125     m_searchPathBox = new KEditListWidget( searchPathTab );
126     m_searchPathBox->setCheckAtEntering( true );
127     QLabel* hintLabel = new QLabel( i18n("<qt><b>Hint:</b> to force K3b to use another than the "
128                                          "default name for the executable specify it in the search path.</qt>"),
129                                     searchPathTab );
130     hintLabel->setWordWrap( true );
131     QVBoxLayout* searchPathTabLayout = new QVBoxLayout( searchPathTab );
132     searchPathTabLayout->addWidget( m_searchPathBox, 1 );
133     searchPathTabLayout->addWidget( hintLabel );
134 
135     m_mainTabWidget->addTab( searchPathTab, i18n("Search Path") );
136 
137     connect( m_changePermissionsButton, SIGNAL(clicked()), SLOT(slotChangePermissions()) );
138     connect( m_permissionModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), SLOT(slotPermissionModelChanged()) );
139     connect( m_permissionModel, SIGNAL(modelReset()), SLOT(slotPermissionModelChanged()) );
140     connect( m_rescanButton, SIGNAL(clicked(bool)), this, SLOT(rescan()) );
141 
142     qRegisterMetaType<HelperProgramItem>();
143     qRegisterMetaTypeStreamOperators<HelperProgramItem>("K3b::HelperProgramItem");
144 
145     while (::group *g = ::getgrent()) {
146         const QString groupName = QString::fromLocal8Bit(g->gr_name);
147         if (groupName == "cdrom" ||
148             groupName == "optical" ||
149             groupName == "operator" ) {
150             m_permissionModel->setBurningGroup(groupName);
151         }
152     }
153     ::endgrent();
154 }
155 
156 
~ExternalBinWidget()157 K3b::ExternalBinWidget::~ExternalBinWidget()
158 {
159 }
160 
rescan()161 void K3b::ExternalBinWidget::rescan()
162 {
163     QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) );
164     saveSearchPath();
165     m_manager->search();
166     load();
167     QApplication::restoreOverrideCursor();
168 }
169 
170 
load()171 void K3b::ExternalBinWidget::load()
172 {
173     m_programModel->reload();
174     m_programView->expandAll();
175     m_parameterModel->reload();
176 
177     // load search path
178     m_searchPathBox->clear();
179     m_searchPathBox->insertStringList( m_manager->searchPath() );
180 }
181 
182 
save()183 void K3b::ExternalBinWidget::save()
184 {
185     saveSearchPath();
186 
187     m_programModel->save();
188     m_parameterModel->save();
189 }
190 
191 
saveSearchPath()192 void K3b::ExternalBinWidget::saveSearchPath()
193 {
194     m_manager->setSearchPath( m_searchPathBox->items() );
195 }
196 
197 
slotPermissionModelChanged()198 void K3b::ExternalBinWidget::slotPermissionModelChanged()
199 {
200     m_changePermissionsButton->setEnabled(m_permissionModel->changesNeeded());
201 }
202 
203 
slotChangePermissions()204 void K3b::ExternalBinWidget::slotChangePermissions()
205 {
206     KAuth::Action action("org.kde.k3b.updatepermissions");
207     action.setHelperId("org.kde.k3b");
208     action.setParentWidget(this);
209 
210     QVariantMap args;
211 
212     // Set burning group name as first argument
213     args["burningGroup"] = m_permissionModel->burningGroup();
214 
215     // Set devices list as second argument
216     args["devices"] = QStringList();
217 
218     // Set programs list as third argument
219     QVariantList programs;
220     Q_FOREACH(const HelperProgramItem& item, m_permissionModel->selectedPrograms()) {
221         programs << QVariant::fromValue(item);
222     }
223     args["programs"] = programs;
224 
225     action.setArguments(args);
226 
227     KAuth::ExecuteJob* job = action.execute();
228     connect( job, &KAuth::ExecuteJob::result, [this, job]()
229     {
230         if( job->error() == KJob::NoError ) {
231             // Success!!
232             QStringList updated = job->data()["updated"].toStringList();
233             QStringList failedToUpdate = job->data()["failedToUpdate"].toStringList();
234             qDebug() << "Objects updated: " << updated;
235             qDebug() << "Objects failed to update: " << failedToUpdate;
236 
237             if (!failedToUpdate.isEmpty()) {
238                 KMessageBox::errorList(this, i18n("Following programs could not be updated:"), failedToUpdate);
239             }
240 
241             m_permissionModel->update();
242         } else {
243             KMessageBox::error(this, i18n("Unable to execute the action: %1", job->errorString()));
244         }
245     } );
246     job->start();
247 }
248 
249 
250