EditProfileDialog.cpp 43.8 KB
Newer Older
1
/*
2
    Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301  USA.
*/

20
21
22
// Own
#include "EditProfileDialog.h"

23
// Qt
Dirk Mueller's avatar
Dirk Mueller committed
24
25
26
27
#include <QtGui/QKeyEvent>
#include <QtGui/QBrush>
#include <QtGui/QPainter>
#include <QtGui/QStandardItem>
28
#include <QtCore/QTextCodec>
29
#include <QtGui/QTextEdit>
30
31
32
#include <QtGui/QLinearGradient>
#include <QtGui/QRadialGradient>

33
#include <QtCore/QTimer>
34
35
#include <QtCore/QTimeLine>

36
// KDE
37
#include <kcodecaction.h>
Robert Knight's avatar
   
Robert Knight committed
38
#include <KDebug>
39
40
#include <KFontDialog>
#include <KIcon>
41
#include <KIconDialog>
42
#include <KFileDialog>
43
#include <KUrlCompletion>
44
#include <KWindowSystem>
45
46
47

// Konsole
#include "ColorScheme.h"
48
#include "ColorSchemeEditor.h"
49
#include "ui_EditProfileDialog.h"
50
51
#include "KeyBindingEditor.h"
#include "KeyboardTranslator.h"
52
#include "SessionManager.h"
53
#include "ShellCommand.h"
54
#include "TabTitleFormatAction.h"
55
56
57

using namespace Konsole;

58
EditProfileDialog::EditProfileDialog(QWidget* parent)
59
    : KDialog(parent)
Robert Knight's avatar
   
Robert Knight committed
60
    , _colorSchemeAnimationTimeLine(0)
61
    , _delayedPreviewTimer(new QTimer(this))
62
{
63
    setCaption(i18n("Edit Profile"));
64
    setButtons( KDialog::Ok | KDialog::Cancel | KDialog::Apply );
65

66
    connect( this , SIGNAL(applyClicked()) , this , SLOT(save()) );
67
    connect( _delayedPreviewTimer , SIGNAL(timeout()) , this , SLOT(delayedPreviewActivate()) );
68
    _ui = new Ui::EditProfileDialog();
69
    _ui->setupUi(mainWidget());
70

71
    // - Renable in a later KDE 4.x release when this feature works again
72
    _ui->enableResizeWindowButton->setVisible(false);
73
	
Laurent Montel's avatar
Laurent Montel committed
74
#ifdef __GNUC__
75
#warning "Re-enable when flow control is working again - bug in KDE 4.1"
Laurent Montel's avatar
Laurent Montel committed
76
#endif
77
	_ui->enableFlowControlButton->setEnabled(false);
78

79
80
81
82
83
84
85
86
87
88
89
    // there are various setupXYZPage() methods to load the items
    // for each page and update their states to match the profile
    // being edited.
    //
    // these are only called when needed ( ie. when the user clicks
    // the tab to move to that page ).
    //
    // the _pageNeedsUpdate vector keeps track of the pages that have
    // not been updated since the last profile change and will need
    // to be refreshed when the user switches to them
    _pageNeedsUpdate.resize( _ui->tabWidget->count() );
90
    connect( _ui->tabWidget , SIGNAL(currentChanged(int)) , this , 
Robert Knight's avatar
   
Robert Knight committed
91
            SLOT(preparePage(int)) );
92

93
    _tempProfile = new Profile;
94
	_tempProfile->setHidden(true);
95
}
96
EditProfileDialog::~EditProfileDialog()
97
98
{
    delete _ui;
99
}
100
void EditProfileDialog::save()
101
{
102
103
    if ( _tempProfile->isEmpty() )
        return;
104

105
    SessionManager::instance()->changeProfile(_profile,_tempProfile->setProperties());
106
107
108
109
110
111
112
113
114
115
116
117
118
119

    // ensure that these settings are not undone by a call
    // to unpreview()
    QHashIterator<Profile::Property,QVariant> iter(_tempProfile->setProperties());
    while ( iter.hasNext() )
    {
        iter.next();
        _previewedProperties.remove(iter.key());
    }
}
void EditProfileDialog::reject()
{
    unpreviewAll();
    KDialog::reject();
120
121
122
123
}
void EditProfileDialog::accept()
{
    save();
124
    unpreviewAll();
125
    KDialog::accept(); 
126
}
127
QString EditProfileDialog::groupProfileNames(const ProfileGroup::Ptr group, int maxLength)
Robert Knight's avatar
   
Robert Knight committed
128
{
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
    QString caption;
    int count = group->profiles().count();
    for (int i=0;i < count;i++)
    {
        caption += group->profiles()[i]->name();
        if (i < (count-1)) 
        {
            caption += ',';
            // limit caption length to prevent very long window titles
            if (maxLength > 0 && caption.length() > maxLength)
            {
                caption += "...";
                break;
            }
        }
    }
    return caption;
}
void EditProfileDialog::updateCaption(const Profile::Ptr profile)
{
    const int MAX_GROUP_CAPTION_LENGTH = 25;
    ProfileGroup::Ptr group = profile->asGroup(); 
    if (group && group->profiles().count() > 1)
    {
        QString caption = groupProfileNames(group,MAX_GROUP_CAPTION_LENGTH); 
        setCaption( i18n("Edit Profile \"%1\"",caption) );
        // STRINGFREEZE - Change caption for groups after KDE 4.1 is released
        // setCaption( i18n("Editing %1 profiles",group->profiles().count()) )
    }
    else
        setCaption( i18n("Edit Profile \"%1\"",profile->name()) );
Robert Knight's avatar
   
Robert Knight committed
160
}
161
void EditProfileDialog::setProfile(Profile::Ptr profile)
162
{
163
    _profile = profile;
164

165
    Q_ASSERT( profile );
166

167
    // update caption
168
    updateCaption(profile);
169

170
171
172
173
174
    // mark each page of the dialog as out of date
    // and force an update of the currently visible page
    //
    // the other pages will be updated as necessary
    _pageNeedsUpdate.fill(true);
Robert Knight's avatar
   
Robert Knight committed
175
    preparePage( _ui->tabWidget->currentIndex() );
176

177
178
179
180
    if ( _tempProfile )
    {
        _tempProfile = new Profile;
    }
181
}
182
const Profile::Ptr EditProfileDialog::lookupProfile() const
183
{
184
    return _profile; 
185
}
Robert Knight's avatar
   
Robert Knight committed
186
void EditProfileDialog::preparePage(int page)
187
{
188
    const Profile::Ptr info = lookupProfile();
189

190
    Q_ASSERT( _pageNeedsUpdate.count() > page );
191
192
    Q_ASSERT( info );

Robert Knight's avatar
   
Robert Knight committed
193
194
    QWidget* pageWidget = _ui->tabWidget->widget(page);
    
195
    if ( _pageNeedsUpdate[page] )
196
197
198
    {
       if ( pageWidget == _ui->generalTab )
            setupGeneralPage(info);
199
200
       else if ( pageWidget == _ui->tabsTab )
            setupTabsPage(info);
201
202
203
204
205
206
207
208
209
210
211
       else if ( pageWidget == _ui->appearanceTab )
            setupAppearancePage(info);
       else if ( pageWidget == _ui->scrollingTab )
            setupScrollingPage(info);
       else if ( pageWidget == _ui->keyboardTab )
            setupKeyboardPage(info);
       else if ( pageWidget == _ui->advancedTab )
            setupAdvancedPage(info);
       else
           Q_ASSERT(false);

212
        _pageNeedsUpdate[page] = false;
213
    }
Robert Knight's avatar
   
Robert Knight committed
214
215
216
217
218
219
220
221
222

    // start page entry animation for color schemes
    if ( pageWidget == _ui->appearanceTab )
            _colorSchemeAnimationTimeLine->start();
}
void EditProfileDialog::selectProfileName()
{
    _ui->profileNameEdit->selectAll();
    _ui->profileNameEdit->setFocus();
223
}
224
void EditProfileDialog::setupGeneralPage(const Profile::Ptr info)
225
{
226
    // basic profile options
227
228
229
230
231
232
233
234
235
236
237
    {
        ProfileGroup::Ptr group = info->asGroup(); 
        if (!group || group->profiles().count() < 2)
            _ui->profileNameEdit->setText( info->name() );
        else 
        {
            _ui->profileNameEdit->setText( groupProfileNames(group,-1) );
            _ui->profileNameLabel->setEnabled(false);
            _ui->profileNameEdit->setEnabled(false);
        }
    }
238
239
240

    ShellCommand command( info->command() , info->arguments() );
    _ui->commandEdit->setText( command.fullCommand() );
241
242

    KUrlCompletion* exeCompletion = new KUrlCompletion(KUrlCompletion::ExeCompletion);
243
    exeCompletion->setParent(this);
244
    exeCompletion->setDir(QString());
245
    _ui->commandEdit->setCompletionObject( exeCompletion );
246
    _ui->initialDirEdit->setText( info->defaultWorkingDirectory() );
247
248
249
250

    KUrlCompletion* dirCompletion = new KUrlCompletion(KUrlCompletion::DirCompletion);
    dirCompletion->setParent(this);
    _ui->initialDirEdit->setCompletionObject( dirCompletion );
251
    _ui->initialDirEdit->setClearButtonShown(true);
252
    _ui->dirSelectButton->setIcon( KIcon("folder-open") );
253
    _ui->iconSelectButton->setIcon( KIcon(info->icon()) );
254
	_ui->startInSameDirButton->setChecked(info->property<bool>(Profile::StartInCurrentSessionDir));
255

256
    // window options
257
    _ui->showMenuBarButton->setChecked( info->property<bool>(Profile::ShowMenuBar) );
258
259
260
261

    // signals and slots
    connect( _ui->dirSelectButton , SIGNAL(clicked()) , this , SLOT(selectInitialDir()) );
    connect( _ui->iconSelectButton , SIGNAL(clicked()) , this , SLOT(selectIcon()) );
262
263
	connect( _ui->startInSameDirButton , SIGNAL(toggled(bool)) , this , 
			SLOT(startInSameDir(bool)));
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
    connect( _ui->profileNameEdit , SIGNAL(textChanged(const QString&)) , this ,
            SLOT(profileNameChanged(const QString&)) );
    connect( _ui->initialDirEdit , SIGNAL(textChanged(const QString&)) , this , 
            SLOT(initialDirChanged(const QString&)) );
    connect(_ui->commandEdit , SIGNAL(textChanged(const QString&)) , this ,
            SLOT(commandChanged(const QString&)) ); 
    
    connect(_ui->showMenuBarButton , SIGNAL(toggled(bool)) , this , 
            SLOT(showMenuBar(bool)) );

    connect(_ui->environmentEditButton , SIGNAL(clicked()) , this , 
            SLOT(showEnvironmentEditor()) );
}
void EditProfileDialog::showEnvironmentEditor()
{
279
    const Profile::Ptr info = lookupProfile();
280
281
282
283

    KDialog* dialog = new KDialog(this);
    QTextEdit* edit = new QTextEdit(dialog);

284
    QStringList currentEnvironment = info->property<QStringList>(Profile::Environment);
285
286
287
288
289
290
291
292
293
294
295
296
297

    edit->setPlainText( currentEnvironment.join("\n") );
    dialog->setPlainCaption(i18n("Edit Environment"));
    dialog->setMainWidget(edit);

    if ( dialog->exec() == QDialog::Accepted )
    {
        QStringList newEnvironment = edit->toPlainText().split('\n');
        _tempProfile->setProperty(Profile::Environment,newEnvironment);
    }

    dialog->deleteLater();
}
298
void EditProfileDialog::setupTabsPage(const Profile::Ptr info)
299
{
300
301
302
    // tab title format
    _ui->tabTitleEdit->setClearButtonShown(true);
    _ui->remoteTabTitleEdit->setClearButtonShown(true);
303
    _ui->tabTitleEdit->setText( info->property<QString>(Profile::LocalTabTitleFormat) );
304
    _ui->remoteTabTitleEdit->setText( 
305
            info->property<QString>(Profile::RemoteTabTitleFormat));
306

307
    // tab options
308
309
    int tabMode = info->property<int>(Profile::TabBarMode);
    int tabPosition = info->property<int>(Profile::TabBarPosition);
310

311
312
    // note: Items should be in the same order as the 
    // Profile::TabBarModeEnum enum
313
314
315
    _ui->tabBarVisibilityCombo->addItems( QStringList() << i18n("Always Hide Tab Bar")
                                                        << i18n("Show Tab Bar When Needed") 
                                                        << i18n("Always Show Tab Bar") );
316
317
318
319
    _ui->tabBarVisibilityCombo->setCurrentIndex(tabMode);

    // note: Items should be in the same order as the
    // Profile::TabBarPositionEnum enum
320
321
    _ui->tabBarPositionCombo->addItems( QStringList() << i18n("Below Terminal Displays")
                                                      << i18n("Above Terminal Displays") );
322
323

    _ui->tabBarPositionCombo->setCurrentIndex(tabPosition);
Robert Knight's avatar
   
Robert Knight committed
324
    _ui->newTabButton->setChecked(info->property<bool>(Profile::ShowNewAndCloseTabButtons));
325

326
    // signals and slots
327
328
329
330
    connect( _ui->tabBarVisibilityCombo , SIGNAL(activated(int)) , this , 
             SLOT(tabBarVisibilityChanged(int)) );
    connect( _ui->tabBarPositionCombo , SIGNAL(activated(int)) , this ,
             SLOT(tabBarPositionChanged(int)) );
331
332
    connect( _ui->newTabButton , SIGNAL(toggled(bool)) , this ,
             SLOT(showNewTabButton(bool)) );
333

334
335
336
337
    connect(_ui->tabTitleEdit , SIGNAL(textChanged(const QString&)) , this ,
            SLOT(tabTitleFormatChanged(const QString&)) );
    connect(_ui->remoteTabTitleEdit , SIGNAL(textChanged(const QString&)) , this ,
            SLOT(remoteTabTitleFormatChanged(const QString&)));
338

339
340
341
342
343
344
345
346
347
348
349
350
    // menus for local and remote tab title dynamic elements
    TabTitleFormatAction* localTabTitleAction = new TabTitleFormatAction(this);
    localTabTitleAction->setContext(Session::LocalTabTitle);
    _ui->tabTitleEditButton->setMenu(localTabTitleAction->menu());
    connect( localTabTitleAction , SIGNAL(dynamicElementSelected(const QString&)) , 
            this , SLOT(insertTabTitleText(const QString&)) );

    TabTitleFormatAction* remoteTabTitleAction = new TabTitleFormatAction(this);
    remoteTabTitleAction->setContext(Session::RemoteTabTitle);
    _ui->remoteTabTitleEditButton->setMenu(remoteTabTitleAction->menu());
    connect( remoteTabTitleAction , SIGNAL(dynamicElementSelected(const QString&)) ,
           this , SLOT(insertRemoteTabTitleText(const QString&)) ); 
351
}
352
void EditProfileDialog::showNewTabButton(bool show)
Robert Knight's avatar
   
Robert Knight committed
353
{ _tempProfile->setProperty(Profile::ShowNewAndCloseTabButtons,show); }
354
355
356
357
358
359
360
361
void EditProfileDialog::tabBarVisibilityChanged(int newValue)
{
    _tempProfile->setProperty( Profile::TabBarMode , newValue );
}
void EditProfileDialog::tabBarPositionChanged(int newValue)
{
    _tempProfile->setProperty( Profile::TabBarPosition , newValue );
}
362
363
364
365
366
367
368
369
void EditProfileDialog::insertTabTitleText(const QString& text)
{
    _ui->tabTitleEdit->insert(text);
}
void EditProfileDialog::insertRemoteTabTitleText(const QString& text)
{
    _ui->remoteTabTitleEdit->insert(text);
}
370
371
372
373
void EditProfileDialog::showMenuBar(bool show)
{
    _tempProfile->setProperty(Profile::ShowMenuBar,show);
}
374
375
376
377
378
379
380
381
382
383
384
void EditProfileDialog::tabTitleFormatChanged(const QString& format)
{
    _tempProfile->setProperty(Profile::LocalTabTitleFormat,format);
}
void EditProfileDialog::remoteTabTitleFormatChanged(const QString& format)
{
    _tempProfile->setProperty(Profile::RemoteTabTitleFormat,format);
}

void EditProfileDialog::selectIcon()
{
Craig Drummond's avatar
Craig Drummond committed
385
386
    const QString& icon = KIconDialog::getIcon(KIconLoader::Desktop, KIconLoader::Application,
                                               false, 0, false, this);
387
388
389
390
391
392
393
394
395
    if (!icon.isEmpty())
    {
        _ui->iconSelectButton->setIcon( KIcon(icon) );
        _tempProfile->setProperty(Profile::Icon,icon);
    }
}
void EditProfileDialog::profileNameChanged(const QString& text)
{
    _tempProfile->setProperty(Profile::Name,text);
396
    updateCaption(_tempProfile);
397
}
398
399
400
401
void EditProfileDialog::startInSameDir(bool sameDir)
{
	_tempProfile->setProperty(Profile::StartInCurrentSessionDir,sameDir);
}
402
403
404
405
406
407
void EditProfileDialog::initialDirChanged(const QString& dir)
{
    _tempProfile->setProperty(Profile::Directory,dir);
}
void EditProfileDialog::commandChanged(const QString& command)
{
408
409
410
411
    ShellCommand shellCommand(command);

    _tempProfile->setProperty(Profile::Command,shellCommand.command());
    _tempProfile->setProperty(Profile::Arguments,shellCommand.arguments());
412
413
414
}
void EditProfileDialog::selectInitialDir()
{
415
416
417
    const KUrl url = KFileDialog::getExistingDirectoryUrl(_ui->initialDirEdit->text(),
                                                          this,
                                                          i18n("Select Initial Directory"));
418
419
420

    if ( !url.isEmpty() )
        _ui->initialDirEdit->setText(url.path());
421
}
422
void EditProfileDialog::setupAppearancePage(const Profile::Ptr info)
423
{
424
    ColorSchemeViewDelegate* delegate = new ColorSchemeViewDelegate(this);
425
426
    _ui->colorSchemeList->setItemDelegate(delegate);
    
Robert Knight's avatar
   
Robert Knight committed
427
428
    _colorSchemeAnimationTimeLine = new QTimeLine( 500 , this );
    delegate->setEntryTimeLine(_colorSchemeAnimationTimeLine);
429
    
Robert Knight's avatar
   
Robert Knight committed
430
    connect( _colorSchemeAnimationTimeLine , SIGNAL(valueChanged(qreal)) , this ,
431
             SLOT(colorSchemeAnimationUpdate()) );
Robert Knight's avatar
   
Robert Knight committed
432
433
   
    _ui->transparencyWarningWidget->setVisible(false);
434
435
436
	_ui->transparencyWarningWidget->setText(i18n("This color scheme uses a transparent background"
												 " which does not appear to be supported on your"
												 " desktop"));
Robert Knight's avatar
   
Robert Knight committed
437
438
439
    _ui->editColorSchemeButton->setEnabled(false);
    _ui->removeColorSchemeButton->setEnabled(false);

440
441
    // setup color list
    updateColorSchemeList(true);
Robert Knight's avatar
   
Robert Knight committed
442
    
443
444
    _ui->colorSchemeList->setMouseTracking(true);
    _ui->colorSchemeList->installEventFilter(this);
Robert Knight's avatar
   
Robert Knight committed
445
    _ui->colorSchemeList->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOn );
446

447
448
449
    connect( _ui->colorSchemeList->selectionModel() , 
            SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)) 
            , this , SLOT(colorSchemeSelected()) );
450
451
    connect( _ui->colorSchemeList , SIGNAL(entered(const QModelIndex&)) , this , 
            SLOT(previewColorScheme(const QModelIndex&)) );
Robert Knight's avatar
   
Robert Knight committed
452
453
    
    updateColorSchemeButtons();
454

455
456
457
458
459
460
    connect( _ui->editColorSchemeButton , SIGNAL(clicked()) , this , 
            SLOT(editColorScheme()) );
    connect( _ui->removeColorSchemeButton , SIGNAL(clicked()) , this ,
            SLOT(removeColorScheme()) );
    connect( _ui->newColorSchemeButton , SIGNAL(clicked()) , this , 
            SLOT(newColorScheme()) );
461

462
    // setup font preview
463
464
465
466
467
468
	bool antialias = info->property<bool>(Profile::AntiAliasFonts);

    QFont font = info->font();
	if (!antialias)
		font.setStyleStrategy(QFont::NoAntialias);

469
470
	_ui->fontPreviewLabel->installEventFilter(this);
	_ui->fontPreviewLabel->setFont(font);
471
    _ui->fontSizeSlider->setValue( font.pointSize() );
472
    _ui->fontSizeSlider->setMinimum( KGlobalSettings::smallestReadableFont().pointSize() );
473
474
475
476
477

    connect( _ui->fontSizeSlider , SIGNAL(valueChanged(int)) , this ,
             SLOT(setFontSize(int)) );
    connect( _ui->editFontButton , SIGNAL(clicked()) , this ,
             SLOT(showFontDialog()) );
478
479

	// setup font smoothing 
480
	_ui->antialiasTextButton->setChecked(antialias);
481
482
483
484
485
486
	connect( _ui->antialiasTextButton , SIGNAL(toggled(bool)) , this , 
			 SLOT(setAntialiasText(bool)) );
}
void EditProfileDialog::setAntialiasText(bool enable)
{
	_tempProfile->setProperty(Profile::AntiAliasFonts,enable);
487
488
489

	// update preview to reflect text smoothing state
	fontSelected(_ui->fontPreviewLabel->font());
490
491
492
493
494
495
496
}
void EditProfileDialog::colorSchemeAnimationUpdate()
{
    QAbstractItemModel* model = _ui->colorSchemeList->model();

    for ( int i = model->rowCount() ; i >= 0 ; i-- )
        _ui->colorSchemeList->update( model->index(i,0) );
497
}
498
void EditProfileDialog::updateColorSchemeList(bool selectCurrentScheme)
499
{
Robert Knight's avatar
   
Robert Knight committed
500
501
    if (!_ui->colorSchemeList->model())
        _ui->colorSchemeList->setModel(new QStandardItemModel(this));
502

503
    const QString& name = lookupProfile()->colorScheme();
504
505
    const ColorScheme* currentScheme = ColorSchemeManager::instance()->findColorScheme(name);

Robert Knight's avatar
   
Robert Knight committed
506
507
508
509
510
511
    QStandardItemModel* model = qobject_cast<QStandardItemModel*>(_ui->colorSchemeList->model());

    Q_ASSERT(model);
    
    model->clear();

512
513
514
    QList<const ColorScheme*> schemeList = ColorSchemeManager::instance()->allColorSchemes();
    QListIterator<const ColorScheme*> schemeIter(schemeList);

515
516
    QStandardItem* selectedItem = 0;

517
518
519
520
521
    while (schemeIter.hasNext())
    {
        const ColorScheme* colors = schemeIter.next();
        QStandardItem* item = new QStandardItem(colors->description());
        item->setData( QVariant::fromValue(colors) ,  Qt::UserRole + 1);
522
        item->setFlags( item->flags() );
523
524
       
        if ( currentScheme == colors ) 
Robert Knight's avatar
   
Robert Knight committed
525
526
            selectedItem = item;  

527
528
529
        model->appendRow(item);
    }

530
531
    model->sort(0);

Robert Knight's avatar
   
Robert Knight committed
532
    if ( selectCurrentScheme && selectedItem )
533
534
535
536
    {
        _ui->colorSchemeList->updateGeometry();
        _ui->colorSchemeList->selectionModel()->setCurrentIndex( selectedItem->index() , 
                                                                 QItemSelectionModel::Select );
Robert Knight's avatar
   
Robert Knight committed
537
538
539

        // update transparency warning label
        updateTransparencyWarning();
540
    }
541
}
542
void EditProfileDialog::updateKeyBindingsList(bool selectCurrentTranslator)
543
{
Robert Knight's avatar
   
Robert Knight committed
544
545
    if (!_ui->keyBindingList->model())
        _ui->keyBindingList->setModel(new QStandardItemModel(this));
546

Robert Knight's avatar
   
Robert Knight committed
547
    KeyboardTranslatorManager* keyManager = KeyboardTranslatorManager::instance();
548

549
    const QString& name = lookupProfile()
550
                                    ->property<QString>(Profile::KeyBindings);
551

552
    const KeyboardTranslator* currentTranslator = keyManager->findTranslator(name);
553
    
Robert Knight's avatar
   
Robert Knight committed
554
555
556
557
558
    QStandardItemModel* model = qobject_cast<QStandardItemModel*>(_ui->keyBindingList->model());

    Q_ASSERT(model);

    model->clear();
559

560
561
    QStandardItem* selectedItem = 0;

562
    QList<QString> translatorNames = keyManager->allTranslators();
563
564
565
566
567
    QListIterator<QString> iter(translatorNames);
    while (iter.hasNext())
    {
        const QString& name = iter.next();

568
        const KeyboardTranslator* translator = keyManager->findTranslator(name);
569
570
571

        QStandardItem* item = new QStandardItem(translator->description());
        item->setData(QVariant::fromValue(translator),Qt::UserRole+1);
Laurent Montel's avatar
Laurent Montel committed
572
        item->setIcon( KIcon("preferences-desktop-keyboard") );
573
574

        if ( translator == currentTranslator )
575
            selectedItem = item;
576
577
578
579

        model->appendRow(item);
    }

580
    model->sort(0);
581
    
Robert Knight's avatar
   
Robert Knight committed
582
    if ( selectCurrentTranslator && selectedItem )
583
584
585
586
    {
        _ui->keyBindingList->selectionModel()->setCurrentIndex( selectedItem->index() , 
                                                                  QItemSelectionModel::Select );
    }
587
}
588
589
590
591
bool EditProfileDialog::eventFilter( QObject* watched , QEvent* event )
{
    if ( watched == _ui->colorSchemeList && event->type() == QEvent::Leave )
    {
592
593
594
595
        if ( _tempProfile->isPropertySet(Profile::ColorScheme) )
            preview(Profile::ColorScheme,_tempProfile->colorScheme());
        else
            unpreview(Profile::ColorScheme);
596
    }
597
598
599
600
601
	if ( watched == _ui->fontPreviewLabel && event->type() == QEvent::FontChange )
	{
		const QFont& labelFont = _ui->fontPreviewLabel->font();
		_ui->fontPreviewLabel->setText(i18n("%1, size %2",labelFont.family(),labelFont.pointSize()));
	}
602
603
604

    return KDialog::eventFilter(watched,event);
}
605
void EditProfileDialog::unpreviewAll()
606
{
607
608
609
    _delayedPreviewTimer->stop();
    _delayedPreviewProperties.clear();

610
611
612
613
614
    QHash<Profile::Property,QVariant> map;
    QHashIterator<int,QVariant> iter(_previewedProperties);
    while ( iter.hasNext() )
    {
        iter.next();
615
        map.insert((Profile::Property)iter.key(),iter.value());
616
617
618
    }

    // undo any preview changes
619
    if ( !map.isEmpty() )
620
        SessionManager::instance()->changeProfile(_profile,map,false);
621
622
623
}
void EditProfileDialog::unpreview(int property)
{
624
625
    _delayedPreviewProperties.remove(property);
    
626
627
    if (!_previewedProperties.contains(property))
        return;
628
    
629
630
    QHash<Profile::Property,QVariant> map;
    map.insert((Profile::Property)property,_previewedProperties[property]);
631
    SessionManager::instance()->changeProfile(_profile,map,false); 
632
633
634

    _previewedProperties.remove(property);
}
635
636
637
638
639
void EditProfileDialog::delayedPreview(int property , const QVariant& value)
{
    _delayedPreviewProperties.insert(property,value); 

    _delayedPreviewTimer->stop();
640
    _delayedPreviewTimer->start(300);
641
642
643
644
645
646
647
648
649
650
651
652
}
void EditProfileDialog::delayedPreviewActivate()
{
    Q_ASSERT( qobject_cast<QTimer*>(sender()) );

    QMutableHashIterator<int,QVariant> iter(_delayedPreviewProperties);
    if ( iter.hasNext() ) 
    {
        iter.next();
        preview(iter.key(),iter.value());
    }
}
Robert Knight's avatar
Robert Knight committed
653
void EditProfileDialog::preview(int property , const QVariant& value)
654
655
656
{
    QHash<Profile::Property,QVariant> map;
    map.insert((Profile::Property)property,value);
657

658
    _delayedPreviewProperties.remove(property);
659

660
    const Profile::Ptr original = lookupProfile();
661

662
663
664
665
666
667
668
669
670
671
672
    // skip previews for profile groups if the profiles in the group
    // have conflicting original values for the property
    //
    // TODO - Save the original values for each profile and use to unpreview properties
    ProfileGroup::Ptr group = original->asGroup();
    if (group && group->profiles().count() > 1 &&
        original->property<QVariant>((Profile::Property)property).isNull())
        return;

    if (!_previewedProperties.contains(property))   
    {
673
        _previewedProperties.insert(property , original->property<QVariant>((Profile::Property)property) );
674
    }
675
676

    // temporary change to color scheme
677
    SessionManager::instance()->changeProfile( _profile , map , false);
678
679
680
681
682
}
void EditProfileDialog::previewColorScheme(const QModelIndex& index)
{
    const QString& name = index.data(Qt::UserRole+1).value<const ColorScheme*>()->name();

683
    delayedPreview( Profile::ColorScheme , name );
684
}
685
686
void EditProfileDialog::removeColorScheme()
{
687
688
689
690
691
    QModelIndexList selected = _ui->colorSchemeList->selectionModel()->selectedIndexes();

    if ( !selected.isEmpty() )
    {
        const QString& name = selected.first().data(Qt::UserRole+1).value<const ColorScheme*>()->name();
692
693
694
        
        if (ColorSchemeManager::instance()->deleteColorScheme(name))    
            _ui->colorSchemeList->model()->removeRow(selected.first().row());
695
    }
696
}
697
void EditProfileDialog::showColorSchemeEditor(bool isNewScheme)
698
699
700
{    
    QModelIndexList selected = _ui->colorSchemeList->selectionModel()->selectedIndexes();

701
    QAbstractItemModel* model = _ui->colorSchemeList->model();
Robert Knight's avatar
   
Robert Knight committed
702
    const ColorScheme* colors = 0;
703
    if ( !selected.isEmpty() )
Robert Knight's avatar
   
Robert Knight committed
704
        colors = model->data(selected.first(),Qt::UserRole+1).value<const ColorScheme*>();
705
    else
Robert Knight's avatar
   
Robert Knight committed
706
        colors = ColorSchemeManager::instance()->defaultColorScheme();
707

Robert Knight's avatar
   
Robert Knight committed
708
    Q_ASSERT(colors);
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724

    KDialog* dialog = new KDialog(this);

    if ( isNewScheme )
        dialog->setCaption(i18n("New Color Scheme"));
    else
        dialog->setCaption(i18n("Edit Color Scheme"));

    ColorSchemeEditor* editor = new ColorSchemeEditor;
    dialog->setMainWidget(editor);
    editor->setup(colors);

    if ( isNewScheme )
        editor->setDescription(i18n("New Color Scheme"));
        
    if ( dialog->exec() == QDialog::Accepted )
725
    {
726
        ColorScheme* newScheme = new ColorScheme(*editor->colorScheme());
727

728
729
730
        // if this is a new color scheme, pick a name based on the description
        if ( isNewScheme )
            newScheme->setName(newScheme->description());
731

732
733
        ColorSchemeManager::instance()->addColorScheme( newScheme );
        
Robert Knight's avatar
   
Robert Knight committed
734
        updateColorSchemeList(true);
735

Robert Knight's avatar
   
Robert Knight committed
736
        preview(Profile::ColorScheme,newScheme->name());
737
738
739
740
741
742
743
744
745
746
    }
}
void EditProfileDialog::newColorScheme()
{
    showColorSchemeEditor(true);    
}
void EditProfileDialog::editColorScheme()
{
    showColorSchemeEditor(false);
}
747
748
749
750
751
752
753
void EditProfileDialog::colorSchemeSelected()
{
    QModelIndexList selected = _ui->colorSchemeList->selectionModel()->selectedIndexes();

    if ( !selected.isEmpty() )
    {
        QAbstractItemModel* model = _ui->colorSchemeList->model();
754
        const ColorScheme* colors = model->data(selected.first(),Qt::UserRole+1).value<const ColorScheme*>();
755

Robert Knight's avatar
   
Robert Knight committed
756
        kDebug() << "Setting temp profile color to" << colors->name();
757
758
759
        
		previewColorScheme(selected.first());
		_tempProfile->setProperty(Profile::ColorScheme,colors->name());
Robert Knight's avatar
   
Robert Knight committed
760
761
762

        updateTransparencyWarning();
    }
Robert Knight's avatar
   
Robert Knight committed
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778

    updateColorSchemeButtons();
}
void EditProfileDialog::updateColorSchemeButtons()
{
    enableIfNonEmptySelection(_ui->editColorSchemeButton,_ui->colorSchemeList->selectionModel());
    enableIfNonEmptySelection(_ui->removeColorSchemeButton,_ui->colorSchemeList->selectionModel());
}
void EditProfileDialog::updateKeyBindingsButtons()
{    
    enableIfNonEmptySelection(_ui->editKeyBindingsButton,_ui->keyBindingList->selectionModel());
    enableIfNonEmptySelection(_ui->removeKeyBindingsButton,_ui->keyBindingList->selectionModel());
}
void EditProfileDialog::enableIfNonEmptySelection(QWidget* widget,QItemSelectionModel* selectionModel)
{
    widget->setEnabled(selectionModel->hasSelection());
Robert Knight's avatar
   
Robert Knight committed
779
780
781
782
783
784
785
786
}
void EditProfileDialog::updateTransparencyWarning() 
{
    // zero or one indexes can be selected
    foreach( const QModelIndex& index , _ui->colorSchemeList->selectionModel()->selectedIndexes() ) 
    {
        bool hasTransparency = index.data(Qt::UserRole+1).value<const ColorScheme*>()->opacity() < 1.0;
        _ui->transparencyWarningWidget->setHidden(KWindowSystem::compositingActive() || !hasTransparency);
787
788
    }
}
789
void EditProfileDialog::setupKeyboardPage(const Profile::Ptr /* info */)
790
791
{
    // setup translator list
792
    updateKeyBindingsList(true); 
793

794
795
796
    connect( _ui->keyBindingList->selectionModel() , 
                SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)),
                SLOT(keyBindingSelected()) );
797
798
    connect( _ui->newKeyBindingsButton , SIGNAL(clicked()) , this ,
            SLOT(newKeyBinding()) );
Robert Knight's avatar
   
Robert Knight committed
799
800
801

    updateKeyBindingsButtons();

802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
    connect( _ui->editKeyBindingsButton , SIGNAL(clicked()) , this , 
          SLOT(editKeyBinding()) );  
    connect( _ui->removeKeyBindingsButton , SIGNAL(clicked()) , this ,
            SLOT(removeKeyBinding()) );
}
void EditProfileDialog::keyBindingSelected()
{
    QModelIndexList selected = _ui->keyBindingList->selectionModel()->selectedIndexes();

    if ( !selected.isEmpty() )
    {
        QAbstractItemModel* model = _ui->keyBindingList->model();
        const KeyboardTranslator* translator = model->data(selected.first(),Qt::UserRole+1)
                                                .value<const KeyboardTranslator*>();
        _tempProfile->setProperty(Profile::KeyBindings,translator->name());
    }
Robert Knight's avatar
   
Robert Knight committed
818
819

    updateKeyBindingsButtons();
820
821
822
823
824
825
826
827
}
void EditProfileDialog::removeKeyBinding()
{
    QModelIndexList selected = _ui->keyBindingList->selectionModel()->selectedIndexes();

    if ( !selected.isEmpty() )
    {
        const QString& name = selected.first().data(Qt::UserRole+1).value<const KeyboardTranslator*>()->name();
828
829
        if (KeyboardTranslatorManager::instance()->deleteTranslator(name))
            _ui->keyBindingList->model()->removeRow(selected.first().row());   
830
831
    }
}
832
void EditProfileDialog::showKeyBindingEditor(bool isNewTranslator)
833
834
{
    QModelIndexList selected = _ui->keyBindingList->selectionModel()->selectedIndexes();
835
    QAbstractItemModel* model = _ui->keyBindingList->model();
836

Robert Knight's avatar
   
Robert Knight committed
837
    const KeyboardTranslator* translator = 0;
838
    if ( !selected.isEmpty() )
Robert Knight's avatar
   
Robert Knight committed
839
        translator = model->data(selected.first(),Qt::UserRole+1).value<const KeyboardTranslator*>();
840
    else
Robert Knight's avatar
   
Robert Knight committed
841
        translator = KeyboardTranslatorManager::instance()->defaultTranslator();
842

Robert Knight's avatar
   
Robert Knight committed
843
    Q_ASSERT(translator);
844

845
    KDialog* dialog = new KDialog(this);
846

847
848
849
850
    if ( isNewTranslator )
        dialog->setCaption(i18n("New Key Binding List"));
    else
        dialog->setCaption(i18n("Edit Key Binding List"));
851

852
853
    KeyBindingEditor* editor = new KeyBindingEditor;
    dialog->setMainWidget(editor);
854
855
856
    
    if ( translator )
        editor->setup(translator);
857
858
859
860
861
862
863
864
865
866

    if ( isNewTranslator )
        editor->setDescription(i18n("New Key Binding List"));

    if ( dialog->exec() == QDialog::Accepted )
    {
        KeyboardTranslator* newTranslator = new KeyboardTranslator(*editor->translator());

        if ( isNewTranslator )
            newTranslator->setName(newTranslator->description());
867

868
        KeyboardTranslatorManager::instance()->addTranslator( newTranslator );
869

870
871
        updateKeyBindingsList();
        
872
        const QString& currentTranslator = lookupProfile()
873
                                        ->property<QString>(Profile::KeyBindings);
874

875
876
877
        if ( newTranslator->name() == currentTranslator )
        {
            _tempProfile->setProperty(Profile::KeyBindings,newTranslator->name());
878
        }
879
880
    }
}
881
882
883
884
885
void EditProfileDialog::newKeyBinding()
{
    showKeyBindingEditor(true);
}
void EditProfileDialog::editKeyBinding()
886
{
887
    showKeyBindingEditor(false);
888
}
889
void EditProfileDialog::setupCombo( ComboOption* options , const Profile::Ptr profile )
890
{
Robert Knight's avatar
Robert Knight committed
891
    while ( options->button != 0 )
892
    {
893
        options->button->setChecked(profile->property<bool>((Profile::Property)options->property));
Robert Knight's avatar
Robert Knight committed
894
895
896
897
898
899
900
901
902
903
904
        connect( options->button , SIGNAL(toggled(bool)) , this , options->slot );

        ++options;
    }
}
void EditProfileDialog::setupRadio( RadioOption* possible , int actual )
{
    while (possible->button != 0)
    {
        if ( possible->property == actual )
            possible->button->setChecked(true);
905
        else
Robert Knight's avatar
Robert Knight committed
906
907
908
909
            possible->button->setChecked(false);
   
        connect( possible->button , SIGNAL(clicked()) , this , possible->slot );

910
911
        ++possible;
    }
912
}
913

914
void EditProfileDialog::setupScrollingPage(const Profile::Ptr profile)
915
{
916
    // setup scrollbar radio
917
    int scrollBarPosition = profile->property<int>(Profile::ScrollBarPosition);
918
   
Robert Knight's avatar
Robert Knight committed
919
920
921
922
923
    RadioOption positions[] = { {_ui->scrollBarHiddenButton,Profile::ScrollBarHidden,SLOT(hideScrollBar())},
                                {_ui->scrollBarLeftButton,Profile::ScrollBarLeft,SLOT(showScrollBarLeft())},
                                {_ui->scrollBarRightButton,Profile::ScrollBarRight,SLOT(showScrollBarRight())},
                                {0,0,0} 
                              }; 
924

Robert Knight's avatar
Robert Knight committed
925
    setupRadio( positions , scrollBarPosition );
926
927
   
    // setup scrollback type radio
928
    int scrollBackType = profile->property<int>(Profile::HistoryMode);
929
    
Robert Knight's avatar
Robert Knight committed
930
931
932
933
934
    RadioOption types[] = { {_ui->disableScrollbackButton,Profile::DisableHistory,SLOT(noScrollBack())},
                            {_ui->fixedScrollbackButton,Profile::FixedSizeHistory,SLOT(fixedScrollBack())},
                            {_ui->unlimitedScrollbackButton,Profile::UnlimitedHistory,SLOT(unlimitedScrollBack())},
                            {0,0,0} };
    setupRadio( types , scrollBackType ); 
935
936
    
    // setup scrollback line count spinner
937
    _ui->scrollBackLinesSpinner->setValue( profile->property<int>(Profile::HistorySize) );
938
939
940
941

    // signals and slots
    connect( _ui->scrollBackLinesSpinner , SIGNAL(valueChanged(int)) , this , 
            SLOT(scrollBackLinesChanged(int)) );
942
943
}

944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
void EditProfileDialog::scrollBackLinesChanged(int lineCount)
{
    _tempProfile->setProperty(Profile::HistorySize , lineCount);
}
void EditProfileDialog::noScrollBack()
{
    _tempProfile->setProperty(Profile::HistoryMode , Profile::DisableHistory);
}
void EditProfileDialog::fixedScrollBack()
{
    _tempProfile->setProperty(Profile::HistoryMode , Profile::FixedSizeHistory);
}
void EditProfileDialog::unlimitedScrollBack()
{
    _tempProfile->setProperty(Profile::HistoryMode , Profile::UnlimitedHistory );
}
void EditProfileDialog::hideScrollBar()
{
    _tempProfile->setProperty(Profile::ScrollBarPosition , Profile::ScrollBarHidden );
}
void EditProfileDialog::showScrollBarLeft()
{
    _tempProfile->setProperty(Profile::ScrollBarPosition , Profile::ScrollBarLeft );
}
void EditProfileDialog::showScrollBarRight()
{
    _tempProfile->setProperty(Profile::ScrollBarPosition , Profile::ScrollBarRight );
}
972
void EditProfileDialog::setupAdvancedPage(const Profile::Ptr profile)
973
{
Robert Knight's avatar
Robert Knight committed
974
975
976
977
978
979
980
981
    ComboOption  options[] = { { _ui->enableBlinkingTextButton , Profile::BlinkingTextEnabled , 
                                 SLOT(toggleBlinkingText(bool)) },
                               { _ui->enableFlowControlButton , Profile::FlowControlEnabled ,
                                 SLOT(toggleFlowControl(bool)) },
                               { _ui->enableResizeWindowButton , Profile::AllowProgramsToResizeWindow ,
                                 SLOT(toggleResizeWindow(bool)) },
                               { _ui->enableBlinkingCursorButton , Profile::BlinkingCursorEnabled ,
                                 SLOT(toggleBlinkingCursor(bool)) },
982
983
                               { _ui->enableBidiRenderingButton , Profile::BidiRenderingEnabled ,
                                 SLOT(togglebidiRendering(bool)) },
Robert Knight's avatar
Robert Knight committed
984
985
986
                               { 0 , 0 , 0 }
                             };
    setupCombo( options , profile );
987
988

    // interaction options
989
    _ui->wordCharacterEdit->setText( profile->property<QString>(Profile::WordCharacters) );
990
991
992
993