~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to systemsettings/core/ModuleView.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************************
 
2
 *   Copyright (C) 2009 Ben Cooksley <bcooksley@kde.org>                     *
 
3
 *   Copyright (C) 2009 by Mathias Soeken <msoeken@informatik.uni-bremen.de> *
 
4
 *                                                                           *
 
5
 *   This program is free software; you can redistribute it and/or modify    *
 
6
 *   it under the terms of the GNU General Public License as published by    *
 
7
 *   the Free Software Foundation; either version 2 of the License, or       *
 
8
 *   (at your option) any later version.                                     *
 
9
 *                                                                           *
 
10
 *   This program is distributed in the hope that it will be useful,         *
 
11
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
 
12
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
 
13
 *   GNU General Public License for more details.                            *
 
14
 *                                                                           *
 
15
 *   You should have received a copy of the GNU General Public License       *
 
16
 *   along with this program; if not, write to the                           *
 
17
 *   Free Software Foundation, Inc.,                                         *
 
18
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA            *
 
19
 *****************************************************************************/
 
20
 
 
21
#include "ModuleView.h"
 
22
#include "ExternalAppModule.h"
 
23
 
 
24
#include <QMap>
 
25
#include <QList>
 
26
#include <QProcess>
 
27
#include <QKeyEvent>
 
28
#include <QWhatsThis>
 
29
#include <QScrollArea>
 
30
#include <QVBoxLayout>
 
31
#include <QAbstractItemModel>
 
32
 
 
33
#include <KDebug>
 
34
#include <KDialog>
 
35
#include <KAboutData>
 
36
#include <KPageWidget>
 
37
#include <KPushButton>
 
38
#include <KAuthorized>
 
39
#include <KMessageBox>
 
40
#include <KCModuleInfo>
 
41
#include <KCModuleProxy>
 
42
#include <KStandardGuiItem>
 
43
#include <KDialogButtonBox>
 
44
#include <kauthaction.h>
 
45
 
 
46
#include "MenuItem.h"
 
47
 
 
48
class ModuleView::Private {
 
49
public:
 
50
    Private() { }
 
51
    QMap<KPageWidgetItem*, KCModuleProxy*> mPages;
 
52
    QMap<KPageWidgetItem*, KCModuleInfo*> mModules;
 
53
    KPageWidget* mPageWidget;
 
54
    QVBoxLayout* mLayout;
 
55
    KDialogButtonBox* mButtons;
 
56
    KPushButton* mApply;
 
57
    KPushButton* mReset;
 
58
    KPushButton* mDefault;
 
59
    KPushButton* mHelp;
 
60
    bool pageChangeSupressed;
 
61
};
 
62
 
 
63
ModuleView::ModuleView( QWidget * parent )
 
64
    : QWidget( parent )
 
65
    , d( new Private() )
 
66
{
 
67
    // Configure a layout first
 
68
    d->mLayout = new QVBoxLayout(this);
 
69
    // Create the Page Widget
 
70
    d->mPageWidget = new KPageWidget(this);
 
71
    d->mPageWidget->layout()->setMargin(0);
 
72
    d->mLayout->addWidget(d->mPageWidget);
 
73
    // Create the dialog
 
74
    d->mButtons = new KDialogButtonBox( this, Qt::Horizontal );
 
75
    d->mLayout->addWidget(d->mButtons);
 
76
 
 
77
    // Create the buttons in it
 
78
    d->mApply = d->mButtons->addButton( KStandardGuiItem::apply(), QDialogButtonBox::ApplyRole );
 
79
    d->mDefault = d->mButtons->addButton( KStandardGuiItem::defaults(), QDialogButtonBox::ResetRole );
 
80
    d->mReset = d->mButtons->addButton( KStandardGuiItem::reset(), QDialogButtonBox::ResetRole );
 
81
    d->mHelp = d->mButtons->addButton( KStandardGuiItem::help(), QDialogButtonBox::HelpRole );
 
82
    // Set some more sensible tooltips
 
83
    d->mReset->setToolTip( i18n("Reset all current changes to previous values") );
 
84
    // Set Auto-Default mode ( KDE Bug #211187 )
 
85
    d->mApply->setAutoDefault(true);
 
86
    d->mDefault->setAutoDefault(true);
 
87
    d->mReset->setAutoDefault(true);
 
88
    d->mHelp->setAutoDefault(true);
 
89
    // Prevent the buttons from being used
 
90
    d->mApply->setEnabled(false);
 
91
    d->mDefault->setEnabled(false);
 
92
    d->mReset->setEnabled(false);
 
93
    d->mHelp->setEnabled(false);
 
94
    // Connect up the buttons
 
95
    connect( d->mApply, SIGNAL(clicked()), this, SLOT(moduleSave()) );
 
96
    connect( d->mReset, SIGNAL(clicked()), this, SLOT(moduleLoad()) );
 
97
    connect( d->mHelp, SIGNAL(clicked()), this, SLOT(moduleHelp()) );
 
98
    connect( d->mDefault, SIGNAL(clicked()), this, SLOT(moduleDefaults()) );
 
99
    connect( d->mPageWidget, SIGNAL(currentPageChanged(KPageWidgetItem*, KPageWidgetItem*)),
 
100
             this, SLOT(activeModuleChanged(KPageWidgetItem*, KPageWidgetItem*)) );
 
101
    connect( this, SIGNAL(moduleChanged(bool)), this, SLOT(updateButtons()) );
 
102
}
 
103
 
 
104
ModuleView::~ModuleView()
 
105
{
 
106
    delete d;
 
107
}
 
108
 
 
109
KCModuleInfo * ModuleView::activeModule() const
 
110
{
 
111
    return d->mModules.value( d->mPageWidget->currentPage() );
 
112
}
 
113
 
 
114
const KAboutData * ModuleView::aboutData() const
 
115
{
 
116
    KCModuleProxy * activeModule = d->mPages.value( d->mPageWidget->currentPage() );
 
117
    KAboutData * aboutData = 0;
 
118
    if( activeModule ) {
 
119
        aboutData = const_cast<KAboutData*>( activeModule->aboutData() );
 
120
    }
 
121
    if ( aboutData ) {
 
122
        aboutData->setProgramIconName( activeModule->moduleInfo().service()->icon() );
 
123
        return aboutData;
 
124
    }
 
125
    return 0;
 
126
}
 
127
 
 
128
void ModuleView::loadModule( QModelIndex menuItem )
 
129
{
 
130
    if ( !menuItem.isValid() ) {
 
131
        return;
 
132
    }
 
133
 
 
134
    QList<QModelIndex> indexes;
 
135
    for ( int done = 0; menuItem.model()->rowCount( menuItem ) > done; done = 1 + done ) {
 
136
        indexes << menuItem.model()->index( done, 0, menuItem );
 
137
    }
 
138
    if ( indexes.empty() ) {
 
139
        indexes << menuItem;
 
140
    }
 
141
 
 
142
    foreach ( QModelIndex module, indexes ) {
 
143
        MenuItem *menuItem = module.data( Qt::UserRole ).value<MenuItem*>();
 
144
        addModule( &menuItem->item() );
 
145
    }
 
146
    // changing state is not needed here as the adding / changing of pages does it
 
147
}
 
148
 
 
149
void ModuleView::addModule( KCModuleInfo *module )
 
150
{
 
151
    if( !module ) {
 
152
        return;
 
153
    }
 
154
    if( !module->service() ) {
 
155
        kWarning() << "ModuleInfo has no associated KService" ;
 
156
        return;
 
157
    }
 
158
    if ( !KAuthorized::authorizeControlModule( module->service()->menuId() ) ) {
 
159
        kWarning() << "Not authorised to load module" ;
 
160
        return;
 
161
    }
 
162
    if( module->service()->noDisplay() ) {
 
163
        return;
 
164
    }
 
165
 
 
166
    // Create the scroller
 
167
    QScrollArea * moduleScroll = new QScrollArea( this );
 
168
    // Prepare the scroll area
 
169
    moduleScroll->setWidgetResizable( true );
 
170
    moduleScroll->setFrameStyle( QFrame::NoFrame );
 
171
    moduleScroll->viewport()->setAutoFillBackground( false );
 
172
    // Create the page
 
173
    KPageWidgetItem *page = new KPageWidgetItem( moduleScroll, module->moduleName() );
 
174
    // Provide information to the users
 
175
 
 
176
    if( module->service()->hasServiceType("SystemSettingsExternalApp") ) { // Is it an external app?
 
177
        QWidget * externalWidget = new ExternalAppModule( this, module );
 
178
        moduleScroll->setWidget( externalWidget );
 
179
    } else { // It must be a normal module then
 
180
        KCModuleProxy * moduleProxy = new KCModuleProxy( *module, moduleScroll );
 
181
        moduleScroll->setWidget( moduleProxy );
 
182
        moduleProxy->setAutoFillBackground( false );
 
183
        connect( moduleProxy, SIGNAL(changed(bool)), this, SLOT(stateChanged()));
 
184
        d->mPages.insert( page, moduleProxy );
 
185
    }
 
186
 
 
187
    d->mModules.insert( page, module );
 
188
    updatePageIconHeader( page, true );
 
189
    // Add the new page
 
190
    d->mPageWidget->addPage( page );
 
191
}
 
192
 
 
193
void ModuleView::updatePageIconHeader( KPageWidgetItem * page, bool light )
 
194
{
 
195
    if( !page ) {
 
196
        // Page is invalid. Probably means we have a race condition during closure of everyone so do nothing
 
197
        return;
 
198
    }
 
199
 
 
200
    KCModuleProxy * moduleProxy = d->mPages.value( page );
 
201
    KCModuleInfo * moduleInfo = d->mModules.value( page );
 
202
 
 
203
    if( !moduleInfo ) {
 
204
        // Seems like we have some form of a race condition going on here...
 
205
        return; 
 
206
    }
 
207
 
 
208
    page->setHeader( moduleInfo->comment() );
 
209
    page->setIcon( KIcon( moduleInfo->icon() ) );
 
210
    if( light ) {
 
211
        return;
 
212
    }
 
213
 
 
214
    if( moduleProxy && moduleProxy->realModule()->useRootOnlyMessage() ) {
 
215
        page->setHeader( "<b>" + moduleInfo->comment() + "</b><br><i>" + moduleProxy->rootOnlyMessage() + "</i>" );
 
216
        page->setIcon( KIcon( moduleInfo->icon(), 0, QStringList() << "dialog-warning" ) );
 
217
    }
 
218
}
 
219
 
 
220
bool ModuleView::resolveChanges()
 
221
{
 
222
    KCModuleProxy * currentProxy = d->mPages.value( d->mPageWidget->currentPage() );
 
223
    return resolveChanges(currentProxy);
 
224
}
 
225
 
 
226
bool ModuleView::resolveChanges(KCModuleProxy * currentProxy)
 
227
{
 
228
    if( !currentProxy || !currentProxy->changed() ) {
 
229
        return true;
 
230
    }
 
231
 
 
232
    // Let the user decide
 
233
    KGuiItem applyItem = KStandardGuiItem::apply();
 
234
    applyItem.setIcon( KIcon(d->mApply->icon()) );
 
235
    const int queryUser = KMessageBox::warningYesNoCancel(
 
236
        this,
 
237
        i18n("The settings of the current module have changed.\n"
 
238
             "Do you want to apply the changes or discard them?"),
 
239
        i18n("Apply Settings"),
 
240
        applyItem,
 
241
        KStandardGuiItem::discard(),
 
242
        KStandardGuiItem::cancel() );
 
243
 
 
244
    switch (queryUser) {
 
245
        case KMessageBox::Yes:
 
246
            return moduleSave(currentProxy);
 
247
 
 
248
        case KMessageBox::No:
 
249
            currentProxy->load();
 
250
            return true;
 
251
 
 
252
        case KMessageBox::Cancel:
 
253
            return false;
 
254
 
 
255
        default:
 
256
            Q_ASSERT(false);
 
257
            return false;
 
258
    }
 
259
}
 
260
 
 
261
void ModuleView::closeModules()
 
262
{
 
263
    d->pageChangeSupressed = true;
 
264
    d->mApply->setAuthAction( 0 ); // Ensure KAuth knows that authentication is now pointless...
 
265
    QMap<KPageWidgetItem*, KCModuleInfo*>::iterator page = d->mModules.begin();
 
266
    QMap<KPageWidgetItem*, KCModuleInfo*>::iterator pageEnd = d->mModules.end();
 
267
    for ( ; page != pageEnd; ++page ) {
 
268
        d->mPageWidget->removePage( page.key() );
 
269
    }
 
270
 
 
271
    d->mPages.clear();
 
272
    d->mModules.clear();
 
273
    d->pageChangeSupressed = false;
 
274
}
 
275
 
 
276
bool ModuleView::moduleSave()
 
277
{
 
278
    KCModuleProxy * moduleProxy = d->mPages.value( d->mPageWidget->currentPage() );
 
279
    return moduleSave( moduleProxy );
 
280
}
 
281
 
 
282
bool ModuleView::moduleSave(KCModuleProxy *module)
 
283
{
 
284
    if( !module ) {
 
285
        return false;
 
286
    }
 
287
 
 
288
    module->save();
 
289
    return true;
 
290
}
 
291
 
 
292
void ModuleView::moduleLoad()
 
293
{
 
294
    KCModuleProxy * activeModule = d->mPages.value( d->mPageWidget->currentPage() );
 
295
    if( activeModule ) {
 
296
        activeModule->load();
 
297
    }
 
298
}
 
299
 
 
300
void ModuleView::moduleDefaults()
 
301
{
 
302
    KCModuleProxy * activeModule = d->mPages.value( d->mPageWidget->currentPage() );
 
303
    if( activeModule ) {
 
304
        activeModule->defaults();
 
305
    }
 
306
}
 
307
 
 
308
void ModuleView::moduleHelp()
 
309
{
 
310
    KCModuleInfo * activeModule = d->mModules.value( d->mPageWidget->currentPage() );
 
311
    if( !activeModule ) {
 
312
        return;
 
313
    }
 
314
 
 
315
    QString docPath = activeModule->docPath();
 
316
    if( docPath.isEmpty() ) {
 
317
        return;
 
318
    }
 
319
    KUrl url( KUrl("help:/"), docPath );
 
320
    QProcess::startDetached("khelpcenter", QStringList() << url.url());
 
321
}
 
322
 
 
323
void ModuleView::activeModuleChanged(KPageWidgetItem * current, KPageWidgetItem * previous)
 
324
{
 
325
    d->mPageWidget->blockSignals(true);
 
326
    d->mPageWidget->setCurrentPage(previous);
 
327
    KCModuleProxy * previousModule = d->mPages.value(previous);
 
328
    if( resolveChanges(previousModule) ) {
 
329
        d->mPageWidget->setCurrentPage(current);
 
330
    }
 
331
    d->mPageWidget->blockSignals(false);
 
332
    if( d->pageChangeSupressed ) {
 
333
        return;
 
334
    }
 
335
    // We need to get the state of the now active module
 
336
    stateChanged();
 
337
}
 
338
 
 
339
void ModuleView::stateChanged()
 
340
{
 
341
    KCModuleProxy * activeModule = d->mPages.value( d->mPageWidget->currentPage() );
 
342
    KAuth::Action * moduleAction = 0;
 
343
    bool change = false;
 
344
    if( activeModule ) {
 
345
        change = activeModule->changed();
 
346
 
 
347
        disconnect( d->mApply, SIGNAL(authorized(KAuth::Action*)), this, SLOT(moduleSave()) );
 
348
        disconnect( d->mApply, SIGNAL(clicked()), this, SLOT(moduleSave()) );
 
349
        if( activeModule->realModule()->authAction() ) {
 
350
            connect( d->mApply, SIGNAL(authorized(KAuth::Action*)), this, SLOT(moduleSave()) );
 
351
            moduleAction = activeModule->realModule()->authAction();
 
352
        } else {
 
353
            connect( d->mApply, SIGNAL(clicked()), this, SLOT(moduleSave()) );
 
354
        }
 
355
    }
 
356
 
 
357
    updatePageIconHeader( d->mPageWidget->currentPage() );
 
358
    d->mApply->setAuthAction( moduleAction );
 
359
    d->mApply->setEnabled( change );
 
360
    d->mReset->setEnabled( change );
 
361
    emit moduleChanged( change );
 
362
}
 
363
 
 
364
void ModuleView::keyPressEvent ( QKeyEvent * event )
 
365
{
 
366
    if ( event->key() == Qt::Key_F1 && d->mHelp->isVisible() && d->mHelp->isEnabled()) {
 
367
        d->mHelp->animateClick();
 
368
        event->accept();
 
369
        return;
 
370
    } else if ( event->key() == Qt::Key_Escape ) {
 
371
        event->accept();
 
372
        emit closeRequest();
 
373
        return;
 
374
    } else if ( event->key() == Qt::Key_F1 && event->modifiers() == Qt::ShiftModifier ) {
 
375
        QWhatsThis::enterWhatsThisMode();
 
376
        event->accept();
 
377
        return;
 
378
    }
 
379
 
 
380
    QWidget::keyPressEvent( event );
 
381
}
 
382
 
 
383
void ModuleView::updateButtons()
 
384
{
 
385
    KCModuleProxy * activeModule = d->mPages.value( d->mPageWidget->currentPage() );
 
386
    if( !activeModule ) {
 
387
        return;
 
388
    }
 
389
 
 
390
    const int buttons = activeModule->buttons();
 
391
 
 
392
    d->mApply->setShown(buttons & KCModule::Apply );
 
393
    d->mReset->setShown(buttons & KCModule::Apply );
 
394
 
 
395
    d->mHelp->setEnabled(buttons & KCModule::Help );
 
396
    d->mDefault->setEnabled(buttons & KCModule::Default );
 
397
}
 
398
 
 
399
#include "ModuleView.moc"