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

    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>
Robert Knight's avatar
   
Robert Knight committed
28
#include <KDebug>
29
#include <QtCore/QTextCodec>
30
#include <QtGui/QTextEdit>
31
32
33
#include <QtGui/QLinearGradient>
#include <QtGui/QRadialGradient>

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

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

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

using namespace Konsole;

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

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

73
    // - Renable in a later KDE 4.x release when this feature works again
74
    _ui->enableResizeWindowButton->setVisible(false);
75
76
77
	
#warning "Re-enable when flow control is working again - bug in KDE 4.1"
	_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
}
95
EditProfileDialog::~EditProfileDialog()
96
97
{
    delete _ui;
98
99
    delete _tempProfile;
}
100
void EditProfileDialog::save()
101
{
102
103
    if ( _tempProfile->isEmpty() )
        return;
104
105

    SessionManager::instance()->changeProfile(_profileKey,_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
}
Robert Knight's avatar
   
Robert Knight committed
127
128
129
130
void EditProfileDialog::updateCaption(const QString& profileName)
{
    setCaption( i18n("Edit Profile \"%1\"",profileName) );
}
131
void EditProfileDialog::setProfile(const QString& key)
132
{
133
    _profileKey = key;
134

135
    const Profile* info = SessionManager::instance()->profile(key);
136
137
138

    Q_ASSERT( info );

139
    // update caption
Robert Knight's avatar
   
Robert Knight committed
140
    updateCaption(info->name());
141

142
143
144
145
146
    // 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
147
    preparePage( _ui->tabWidget->currentIndex() );
148

149
150
151
152
153
    if ( _tempProfile )
    {
        delete _tempProfile;
        _tempProfile = new Profile;
    }
154
}
155
156
157
158
const Profile* EditProfileDialog::lookupProfile() const
{
    return SessionManager::instance()->profile(_profileKey);
}
Robert Knight's avatar
   
Robert Knight committed
159
void EditProfileDialog::preparePage(int page)
160
{
161
    const Profile* info = lookupProfile();
162

163
    Q_ASSERT( _pageNeedsUpdate.count() > page );
164
165
    Q_ASSERT( info );

Robert Knight's avatar
   
Robert Knight committed
166
167
    QWidget* pageWidget = _ui->tabWidget->widget(page);
    
168
    if ( _pageNeedsUpdate[page] )
169
170
171
    {
       if ( pageWidget == _ui->generalTab )
            setupGeneralPage(info);
172
173
       else if ( pageWidget == _ui->tabsTab )
            setupTabsPage(info);
174
175
176
177
178
179
180
181
182
183
184
       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);

185
        _pageNeedsUpdate[page] = false;
186
    }
Robert Knight's avatar
   
Robert Knight committed
187
188
189
190
191
192
193
194
195

    // start page entry animation for color schemes
    if ( pageWidget == _ui->appearanceTab )
            _colorSchemeAnimationTimeLine->start();
}
void EditProfileDialog::selectProfileName()
{
    _ui->profileNameEdit->selectAll();
    _ui->profileNameEdit->setFocus();
196
}
197
void EditProfileDialog::setupGeneralPage(const Profile* info)
198
{
199
200

    // basic profile options
201
    _ui->profileNameEdit->setText( info->name() );
202
203
204

    ShellCommand command( info->command() , info->arguments() );
    _ui->commandEdit->setText( command.fullCommand() );
205
206

    KUrlCompletion* exeCompletion = new KUrlCompletion(KUrlCompletion::ExeCompletion);
207
    exeCompletion->setParent(this);
208
    exeCompletion->setDir(QString());
209
    _ui->commandEdit->setCompletionObject( exeCompletion );
210
    _ui->initialDirEdit->setText( info->defaultWorkingDirectory() );
211
212
213
214

    KUrlCompletion* dirCompletion = new KUrlCompletion(KUrlCompletion::DirCompletion);
    dirCompletion->setParent(this);
    _ui->initialDirEdit->setCompletionObject( dirCompletion );
215
    _ui->initialDirEdit->setClearButtonShown(true);
216
    _ui->dirSelectButton->setIcon( KIcon("folder-open") );
217
    _ui->iconSelectButton->setIcon( KIcon(info->icon()) );
218

219
    // window options
220
    _ui->showMenuBarButton->setChecked( info->property<bool>(Profile::ShowMenuBar) );
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245

    // signals and slots
    connect( _ui->dirSelectButton , SIGNAL(clicked()) , this , SLOT(selectInitialDir()) );
    connect( _ui->iconSelectButton , SIGNAL(clicked()) , this , SLOT(selectIcon()) );

    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()
{
    const Profile* info = lookupProfile();

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

246
    QStringList currentEnvironment = info->property<QStringList>(Profile::Environment);
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261

    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();
}
void EditProfileDialog::setupTabsPage(const Profile* info)
{
262
263
264
    // tab title format
    _ui->tabTitleEdit->setClearButtonShown(true);
    _ui->remoteTabTitleEdit->setClearButtonShown(true);
265
    _ui->tabTitleEdit->setText( info->property<QString>(Profile::LocalTabTitleFormat) );
266
    _ui->remoteTabTitleEdit->setText( 
267
            info->property<QString>(Profile::RemoteTabTitleFormat));
268

269
    // tab options
270
271
    int tabMode = info->property<int>(Profile::TabBarMode);
    int tabPosition = info->property<int>(Profile::TabBarPosition);
272

273
274
    // note: Items should be in the same order as the 
    // Profile::TabBarModeEnum enum
275
276
277
    _ui->tabBarVisibilityCombo->addItems( QStringList() << i18n("Always Hide Tab Bar")
                                                        << i18n("Show Tab Bar When Needed") 
                                                        << i18n("Always Show Tab Bar") );
278
279
280
281
    _ui->tabBarVisibilityCombo->setCurrentIndex(tabMode);

    // note: Items should be in the same order as the
    // Profile::TabBarPositionEnum enum
282
283
    _ui->tabBarPositionCombo->addItems( QStringList() << i18n("Below Terminal Displays")
                                                      << i18n("Above Terminal Displays") );
284
285
286

    _ui->tabBarPositionCombo->setCurrentIndex(tabPosition);

287
    // signals and slots
288
289
290
291
    connect( _ui->tabBarVisibilityCombo , SIGNAL(activated(int)) , this , 
             SLOT(tabBarVisibilityChanged(int)) );
    connect( _ui->tabBarPositionCombo , SIGNAL(activated(int)) , this ,
             SLOT(tabBarPositionChanged(int)) );
292

293
294
295
296
    connect(_ui->tabTitleEdit , SIGNAL(textChanged(const QString&)) , this ,
            SLOT(tabTitleFormatChanged(const QString&)) );
    connect(_ui->remoteTabTitleEdit , SIGNAL(textChanged(const QString&)) , this ,
            SLOT(remoteTabTitleFormatChanged(const QString&)));
297

298
299
300
301
302
303
304
305
306
307
308
309
    // 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&)) ); 
310
}
311
312
313
314
315
316
317
318
void EditProfileDialog::tabBarVisibilityChanged(int newValue)
{
    _tempProfile->setProperty( Profile::TabBarMode , newValue );
}
void EditProfileDialog::tabBarPositionChanged(int newValue)
{
    _tempProfile->setProperty( Profile::TabBarPosition , newValue );
}
319
320
321
322
323
324
325
326
void EditProfileDialog::insertTabTitleText(const QString& text)
{
    _ui->tabTitleEdit->insert(text);
}
void EditProfileDialog::insertRemoteTabTitleText(const QString& text)
{
    _ui->remoteTabTitleEdit->insert(text);
}
327
328
329
330
void EditProfileDialog::showMenuBar(bool show)
{
    _tempProfile->setProperty(Profile::ShowMenuBar,show);
}
331
332
333
334
335
336
337
338
339
340
341
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
342
343
    const QString& icon = KIconDialog::getIcon(KIconLoader::Desktop, KIconLoader::Application,
                                               false, 0, false, this);
344
345
346
347
348
349
350
351
352
    if (!icon.isEmpty())
    {
        _ui->iconSelectButton->setIcon( KIcon(icon) );
        _tempProfile->setProperty(Profile::Icon,icon);
    }
}
void EditProfileDialog::profileNameChanged(const QString& text)
{
    _tempProfile->setProperty(Profile::Name,text);
Robert Knight's avatar
   
Robert Knight committed
353
    updateCaption(_tempProfile->name());
354
355
356
357
358
359
360
}
void EditProfileDialog::initialDirChanged(const QString& dir)
{
    _tempProfile->setProperty(Profile::Directory,dir);
}
void EditProfileDialog::commandChanged(const QString& command)
{
361
362
363
364
    ShellCommand shellCommand(command);

    _tempProfile->setProperty(Profile::Command,shellCommand.command());
    _tempProfile->setProperty(Profile::Arguments,shellCommand.arguments());
365
366
367
}
void EditProfileDialog::selectInitialDir()
{
368
369
370
    const KUrl url = KFileDialog::getExistingDirectoryUrl(_ui->initialDirEdit->text(),
                                                          this,
                                                          i18n("Select Initial Directory"));
371
372
373

    if ( !url.isEmpty() )
        _ui->initialDirEdit->setText(url.path());
374
}
375
void EditProfileDialog::setupAppearancePage(const Profile* info)
376
{
377
    ColorSchemeViewDelegate* delegate = new ColorSchemeViewDelegate(this);
378
379
    _ui->colorSchemeList->setItemDelegate(delegate);
    
Robert Knight's avatar
   
Robert Knight committed
380
381
    _colorSchemeAnimationTimeLine = new QTimeLine( 500 , this );
    delegate->setEntryTimeLine(_colorSchemeAnimationTimeLine);
382
    
Robert Knight's avatar
   
Robert Knight committed
383
    connect( _colorSchemeAnimationTimeLine , SIGNAL(valueChanged(qreal)) , this ,
384
             SLOT(colorSchemeAnimationUpdate()) );
Robert Knight's avatar
   
Robert Knight committed
385
386
   
    _ui->transparencyWarningWidget->setVisible(false);
Robert Knight's avatar
   
Robert Knight committed
387
388
389
    _ui->editColorSchemeButton->setEnabled(false);
    _ui->removeColorSchemeButton->setEnabled(false);

390
391
    // setup color list
    updateColorSchemeList(true);
Robert Knight's avatar
   
Robert Knight committed
392
    
393
394
    _ui->colorSchemeList->setMouseTracking(true);
    _ui->colorSchemeList->installEventFilter(this);
Robert Knight's avatar
   
Robert Knight committed
395
    _ui->colorSchemeList->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOn );
396

397
398
399
    connect( _ui->colorSchemeList->selectionModel() , 
            SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)) 
            , this , SLOT(colorSchemeSelected()) );
400
401
    connect( _ui->colorSchemeList , SIGNAL(entered(const QModelIndex&)) , this , 
            SLOT(previewColorScheme(const QModelIndex&)) );
Robert Knight's avatar
   
Robert Knight committed
402
403
    
    updateColorSchemeButtons();
404

405
406
407
408
409
410
    connect( _ui->editColorSchemeButton , SIGNAL(clicked()) , this , 
            SLOT(editColorScheme()) );
    connect( _ui->removeColorSchemeButton , SIGNAL(clicked()) , this ,
            SLOT(removeColorScheme()) );
    connect( _ui->newColorSchemeButton , SIGNAL(clicked()) , this , 
            SLOT(newColorScheme()) );
411

412
    // setup font preview
413
    const QFont& font = info->font();
414
415
	_ui->fontPreviewLabel->installEventFilter(this);
	_ui->fontPreviewLabel->setFont(font);
416
    _ui->fontSizeSlider->setValue( font.pointSize() );
417
    _ui->fontSizeSlider->setMinimum( KGlobalSettings::smallestReadableFont().pointSize() );
418
419
420
421
422

    connect( _ui->fontSizeSlider , SIGNAL(valueChanged(int)) , this ,
             SLOT(setFontSize(int)) );
    connect( _ui->editFontButton , SIGNAL(clicked()) , this ,
             SLOT(showFontDialog()) );
423
424
425
426
427
428
429
}
void EditProfileDialog::colorSchemeAnimationUpdate()
{
    QAbstractItemModel* model = _ui->colorSchemeList->model();

    for ( int i = model->rowCount() ; i >= 0 ; i-- )
        _ui->colorSchemeList->update( model->index(i,0) );
430
}
431
void EditProfileDialog::updateColorSchemeList(bool selectCurrentScheme)
432
{
Robert Knight's avatar
   
Robert Knight committed
433
434
    if (!_ui->colorSchemeList->model())
        _ui->colorSchemeList->setModel(new QStandardItemModel(this));
435

436
    const QString& name = lookupProfile()->colorScheme();
437
438
    const ColorScheme* currentScheme = ColorSchemeManager::instance()->findColorScheme(name);

Robert Knight's avatar
   
Robert Knight committed
439
440
441
442
443
444
    QStandardItemModel* model = qobject_cast<QStandardItemModel*>(_ui->colorSchemeList->model());

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

445
446
447
    QList<const ColorScheme*> schemeList = ColorSchemeManager::instance()->allColorSchemes();
    QListIterator<const ColorScheme*> schemeIter(schemeList);

448
449
    QStandardItem* selectedItem = 0;

450
451
452
453
454
    while (schemeIter.hasNext())
    {
        const ColorScheme* colors = schemeIter.next();
        QStandardItem* item = new QStandardItem(colors->description());
        item->setData( QVariant::fromValue(colors) ,  Qt::UserRole + 1);
455
        item->setFlags( item->flags() );
456
457
       
        if ( currentScheme == colors ) 
Robert Knight's avatar
   
Robert Knight committed
458
459
            selectedItem = item;  

460
461
462
        model->appendRow(item);
    }

463
464
    model->sort(0);

Robert Knight's avatar
   
Robert Knight committed
465
    if ( selectCurrentScheme && selectedItem )
466
467
468
469
    {
        _ui->colorSchemeList->updateGeometry();
        _ui->colorSchemeList->selectionModel()->setCurrentIndex( selectedItem->index() , 
                                                                 QItemSelectionModel::Select );
Robert Knight's avatar
   
Robert Knight committed
470
471
472

        // update transparency warning label
        updateTransparencyWarning();
473
    }
474
}
475
void EditProfileDialog::updateKeyBindingsList(bool selectCurrentTranslator)
476
{
Robert Knight's avatar
   
Robert Knight committed
477
478
    if (!_ui->keyBindingList->model())
        _ui->keyBindingList->setModel(new QStandardItemModel(this));
479

Robert Knight's avatar
   
Robert Knight committed
480
    KeyboardTranslatorManager* keyManager = KeyboardTranslatorManager::instance();
481

482
    const QString& name = lookupProfile()
483
                                    ->property<QString>(Profile::KeyBindings);
484

485
    const KeyboardTranslator* currentTranslator = keyManager->findTranslator(name);
486
    
Robert Knight's avatar
   
Robert Knight committed
487
488
489
490
491
    QStandardItemModel* model = qobject_cast<QStandardItemModel*>(_ui->keyBindingList->model());

    Q_ASSERT(model);

    model->clear();
492

493
494
    QStandardItem* selectedItem = 0;

495
    QList<QString> translatorNames = keyManager->allTranslators();
496
497
498
499
500
    QListIterator<QString> iter(translatorNames);
    while (iter.hasNext())
    {
        const QString& name = iter.next();

501
        const KeyboardTranslator* translator = keyManager->findTranslator(name);
502
503
504

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

        if ( translator == currentTranslator )
508
            selectedItem = item;
509
510
511
512

        model->appendRow(item);
    }

513
    model->sort(0);
514
    
Robert Knight's avatar
   
Robert Knight committed
515
    if ( selectCurrentTranslator && selectedItem )
516
517
518
519
    {
        _ui->keyBindingList->selectionModel()->setCurrentIndex( selectedItem->index() , 
                                                                  QItemSelectionModel::Select );
    }
520
}
521
522
523
524
bool EditProfileDialog::eventFilter( QObject* watched , QEvent* event )
{
    if ( watched == _ui->colorSchemeList && event->type() == QEvent::Leave )
    {
525
526
527
528
        if ( _tempProfile->isPropertySet(Profile::ColorScheme) )
            preview(Profile::ColorScheme,_tempProfile->colorScheme());
        else
            unpreview(Profile::ColorScheme);
529
    }
530
531
532
533
534
	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()));
	}
535
536
537

    return KDialog::eventFilter(watched,event);
}
538
void EditProfileDialog::unpreviewAll()
539
{
540
541
542
    _delayedPreviewTimer->stop();
    _delayedPreviewProperties.clear();

543
544
545
546
547
    QHash<Profile::Property,QVariant> map;
    QHashIterator<int,QVariant> iter(_previewedProperties);
    while ( iter.hasNext() )
    {
        iter.next();
548
        map.insert((Profile::Property)iter.key(),iter.value());
549
550
551
    }

    // undo any preview changes
552
    if ( !map.isEmpty() )
553
554
555
556
        SessionManager::instance()->changeProfile(_profileKey,map,false);
}
void EditProfileDialog::unpreview(int property)
{
557
558
    _delayedPreviewProperties.remove(property);
    
559
560
    if (!_previewedProperties.contains(property))
        return;
561
    
562
563
564
565
566
567
    QHash<Profile::Property,QVariant> map;
    map.insert((Profile::Property)property,_previewedProperties[property]);
    SessionManager::instance()->changeProfile(_profileKey,map,false); 

    _previewedProperties.remove(property);
}
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
void EditProfileDialog::delayedPreview(int property , const QVariant& value)
{
    _delayedPreviewProperties.insert(property,value); 
    QTimer* timer = new QTimer(this);
    timer->setSingleShot(true);

    _delayedPreviewTimer->stop();
    _delayedPreviewTimer->start(300);    
}
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
588
void EditProfileDialog::preview(int property , const QVariant& value)
589
590
591
{
    QHash<Profile::Property,QVariant> map;
    map.insert((Profile::Property)property,value);
592
593
    
    _delayedPreviewProperties.remove(property);
594

595
    const Profile* original = lookupProfile();
596
597

    if (!_previewedProperties.contains(property))    
598
        _previewedProperties.insert(property , original->property<QVariant>((Profile::Property)property) );
599
600
601
602
603
604
605
606

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

607
    delayedPreview( Profile::ColorScheme , name );
608
}
609
610
void EditProfileDialog::removeColorScheme()
{
611
612
613
614
615
    QModelIndexList selected = _ui->colorSchemeList->selectionModel()->selectedIndexes();

    if ( !selected.isEmpty() )
    {
        const QString& name = selected.first().data(Qt::UserRole+1).value<const ColorScheme*>()->name();
616
617
618
        
        if (ColorSchemeManager::instance()->deleteColorScheme(name))    
            _ui->colorSchemeList->model()->removeRow(selected.first().row());
619
    }
620
}
621
void EditProfileDialog::showColorSchemeEditor(bool isNewScheme)
622
623
624
{    
    QModelIndexList selected = _ui->colorSchemeList->selectionModel()->selectedIndexes();

625
    QAbstractItemModel* model = _ui->colorSchemeList->model();
Robert Knight's avatar
   
Robert Knight committed
626
    const ColorScheme* colors = 0;
627
    if ( !selected.isEmpty() )
Robert Knight's avatar
   
Robert Knight committed
628
        colors = model->data(selected.first(),Qt::UserRole+1).value<const ColorScheme*>();
629
    else
Robert Knight's avatar
   
Robert Knight committed
630
        colors = ColorSchemeManager::instance()->defaultColorScheme();
631

Robert Knight's avatar
   
Robert Knight committed
632
    Q_ASSERT(colors);
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648

    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 )
649
    {
650
        ColorScheme* newScheme = new ColorScheme(*editor->colorScheme());
651

652
653
654
        // if this is a new color scheme, pick a name based on the description
        if ( isNewScheme )
            newScheme->setName(newScheme->description());
655

656
657
        ColorSchemeManager::instance()->addColorScheme( newScheme );
        
Robert Knight's avatar
   
Robert Knight committed
658
        updateColorSchemeList(true);
659

Robert Knight's avatar
   
Robert Knight committed
660
        preview(Profile::ColorScheme,newScheme->name());
661
662
663
664
665
666
667
668
669
670
    }
}
void EditProfileDialog::newColorScheme()
{
    showColorSchemeEditor(true);    
}
void EditProfileDialog::editColorScheme()
{
    showColorSchemeEditor(false);
}
671
672
673
674
675
676
677
void EditProfileDialog::colorSchemeSelected()
{
    QModelIndexList selected = _ui->colorSchemeList->selectionModel()->selectedIndexes();

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

Robert Knight's avatar
   
Robert Knight committed
680
        kDebug() << "Setting temp profile color to" << colors->name();
681
682
683
        
		previewColorScheme(selected.first());
		_tempProfile->setProperty(Profile::ColorScheme,colors->name());
Robert Knight's avatar
   
Robert Knight committed
684
685
686

        updateTransparencyWarning();
    }
Robert Knight's avatar
   
Robert Knight committed
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702

    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
703
704
705
706
707
708
709
710
711
712
}
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);
        _ui->transparencyWarningIcon->setPixmap( KIcon("dialog-warning").pixmap(QSize(48,48)) );
713
714
    }
}
Robert Knight's avatar
   
Robert Knight committed
715
void EditProfileDialog::setupKeyboardPage(const Profile* /* info */)
716
717
{
    // setup translator list
718
    updateKeyBindingsList(true); 
719

720
721
722
    connect( _ui->keyBindingList->selectionModel() , 
                SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)),
                SLOT(keyBindingSelected()) );
723
724
    connect( _ui->newKeyBindingsButton , SIGNAL(clicked()) , this ,
            SLOT(newKeyBinding()) );
Robert Knight's avatar
   
Robert Knight committed
725
726
727

    updateKeyBindingsButtons();

728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
    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
744
745

    updateKeyBindingsButtons();
746
747
748
749
750
751
752
753
}
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();
754
755
        if (KeyboardTranslatorManager::instance()->deleteTranslator(name))
            _ui->keyBindingList->model()->removeRow(selected.first().row());   
756
757
    }
}
758
void EditProfileDialog::showKeyBindingEditor(bool isNewTranslator)
759
760
{
    QModelIndexList selected = _ui->keyBindingList->selectionModel()->selectedIndexes();
761
    QAbstractItemModel* model = _ui->keyBindingList->model();
762

Robert Knight's avatar
   
Robert Knight committed
763
    const KeyboardTranslator* translator = 0;
764
    if ( !selected.isEmpty() )
Robert Knight's avatar
   
Robert Knight committed
765
        translator = model->data(selected.first(),Qt::UserRole+1).value<const KeyboardTranslator*>();
766
    else
Robert Knight's avatar
   
Robert Knight committed
767
        translator = KeyboardTranslatorManager::instance()->defaultTranslator();
768

Robert Knight's avatar
   
Robert Knight committed
769
    Q_ASSERT(translator);
770

771
    KDialog* dialog = new KDialog(this);
772

773
774
775
776
    if ( isNewTranslator )
        dialog->setCaption(i18n("New Key Binding List"));
    else
        dialog->setCaption(i18n("Edit Key Binding List"));
777

778
779
    KeyBindingEditor* editor = new KeyBindingEditor;
    dialog->setMainWidget(editor);
780
781
782
    
    if ( translator )
        editor->setup(translator);
783
784
785
786
787
788
789
790
791
792

    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());
793

794
        KeyboardTranslatorManager::instance()->addTranslator( newTranslator );
795

796
797
        updateKeyBindingsList();
        
798
        const QString& currentTranslator = lookupProfile()
799
                                        ->property<QString>(Profile::KeyBindings);
800

801
802
803
        if ( newTranslator->name() == currentTranslator )
        {
            _tempProfile->setProperty(Profile::KeyBindings,newTranslator->name());
804
        }
805
806
    }
}
807
808
809
810
811
void EditProfileDialog::newKeyBinding()
{
    showKeyBindingEditor(true);
}
void EditProfileDialog::editKeyBinding()
812
{
813
    showKeyBindingEditor(false);
814
}
Robert Knight's avatar
Robert Knight committed
815
void EditProfileDialog::setupCombo( ComboOption* options , const Profile* profile )
816
{
Robert Knight's avatar
Robert Knight committed
817
    while ( options->button != 0 )
818
    {
819
        options->button->setChecked(profile->property<bool>((Profile::Property)options->property));
Robert Knight's avatar
Robert Knight committed
820
821
822
823
824
825
826
827
828
829
830
        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);
831
        else
Robert Knight's avatar
Robert Knight committed
832
833
834
835
            possible->button->setChecked(false);
   
        connect( possible->button , SIGNAL(clicked()) , this , possible->slot );

836
837
        ++possible;
    }
838
}
839
840

void EditProfileDialog::setupScrollingPage(const Profile* profile)
841
{
842
    // setup scrollbar radio
843
    int scrollBarPosition = profile->property<int>(Profile::ScrollBarPosition);
844
   
Robert Knight's avatar
Robert Knight committed
845
846
847
848
849
    RadioOption positions[] = { {_ui->scrollBarHiddenButton,Profile::ScrollBarHidden,SLOT(hideScrollBar())},
                                {_ui->scrollBarLeftButton,Profile::ScrollBarLeft,SLOT(showScrollBarLeft())},
                                {_ui->scrollBarRightButton,Profile::ScrollBarRight,SLOT(showScrollBarRight())},
                                {0,0,0} 
                              }; 
850

Robert Knight's avatar
Robert Knight committed
851
    setupRadio( positions , scrollBarPosition );
852
853
   
    // setup scrollback type radio
854
    int scrollBackType = profile->property<int>(Profile::HistoryMode);
855
    
Robert Knight's avatar
Robert Knight committed
856
857
858
859
860
    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 ); 
861
862
    
    // setup scrollback line count spinner
863
    _ui->scrollBackLinesSpinner->setValue( profile->property<int>(Profile::HistorySize) );
864
865
866
867

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

870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
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 );
}
void EditProfileDialog::setupAdvancedPage(const Profile* profile)
{
Robert Knight's avatar
Robert Knight committed
900
901
902
903
904
905
906
907
908
909
910
    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)) },
                               { 0 , 0 , 0 }
                             };
    setupCombo( options , profile );
911
912

    // interaction options
913
    _ui->wordCharacterEdit->setText( profile->property<QString>(Profile::WordCharacters) );
914
915
916
917
918

    connect( _ui->wordCharacterEdit , SIGNAL(textChanged(const QString&)) , this , 
            SLOT(wordCharactersChanged(const QString&)) );

    // cursor options
919
    if ( profile->property<bool>(Profile::UseCustomCursorColor) )
920
921
922
923
        _ui->customCursorColorButton->setChecked(true);
    else
        _ui->autoCursorColorButton->setChecked(true);

924
    _ui->customColorSelectButton->setColor( profile->property<QColor>(Profile::CustomCursorColor) );
925
926
927
928
929
930

    connect( _ui->customCursorColorButton , SIGNAL(clicked()) , this , SLOT(customCursorColor()) );
    connect( _ui->autoCursorColorButton , SIGNAL(clicked()) , this , SLOT(autoCursorColor()) );
    connect( _ui->customColorSelectButton , SIGNAL(changed(const QColor&)) , 
            SLOT(customCursorColorChanged(const QColor&)) );

931
    int shape = profile->property<int>(Profile::CursorShape);
932
933
934
    _ui->cursorShapeCombo->setCurrentIndex(shape);

    connect( _ui->cursorShapeCombo , SIGNAL(activated(int)) , this , SLOT(setCursorShape(int)) ); 
935
936
937
938
939
940

    // encoding options
    QAction* codecAction = new KCodecAction(this);
    _ui->selectEncodingButton->setMenu( codecAction->menu() );
    connect( codecAction , SIGNAL(triggered(QTextCodec*)) , this , SLOT(setDefaultCodec(QTextCodec*)) );

941
    _ui->characterEncodingLabel->setText( profile->property<QString>(Profile::DefaultEncoding) );
942
943
944
945
946
947
948
949

}
void EditProfileDialog::setDefaultCodec(QTextCodec* codec)
{
    QString name = QString(codec->name());

    _tempProfile->setProperty(Profile::DefaultEncoding,name);
    _ui->characterEncodingLabel->setText(codec->name());
950
951
952
953
}
void EditProfileDialog::customCursorColorChanged(const QColor& color)
{
    _tempProfile->setProperty(Profile::CustomCursorColor,color);
954
955
956

    // ensure that custom cursor colors are enabled
    _ui->customCursorColorButton->click();
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
}
void EditProfileDialog::wordCharactersChanged(const QString& text)
{
    _tempProfile->setProperty(Profile::WordCharacters,text);
}
void EditProfileDialog::autoCursorColor()
{
    _tempProfile->setProperty(Profile::UseCustomCursorColor,false);
}
void EditProfileDialog::customCursorColor()
{
    _tempProfile->setProperty(Profile::UseCustomCursorColor,true);
}
void EditProfileDialog::setCursorShape(int index)
{
    _tempProfile->setProperty(Profile::CursorShape,index);
973
974
975
976
}
void EditProfileDialog::toggleBlinkingCursor(bool enable)
{
    _tempProfile->setProperty(Profile::BlinkingCursorEnabled,enable);
977
978
979
980
981
982
983
984
985
986
987
988
989
}
void EditProfileDialog::toggleBlinkingText(bool enable)
{
    _tempProfile->setProperty(Profile::BlinkingTextEnabled,enable);
}
void EditProfileDialog::toggleFlowControl(bool enable)
{
    _tempProfile->setProperty(Profile::FlowControlEnabled,enable);
}
void EditProfileDialog::toggleResizeWindow(bool enable)
{
    _tempProfile->setProperty(Profile::AllowProgramsToResizeWindow,enable);
}
990
void EditProfileDialog::fontSelected(const QFont& font)
991
{
992
993
994
995
996
997
   QSlider* slider = _ui->fontSizeSlider;
   
   _ui->fontSizeSlider->setRange( qMin(slider->minimum(),font.pointSize()) ,
                                  qMax(slider->maximum(),font.pointSize()) );
   _ui->fontSizeSlider->setValue(font.pointSize());
   _ui->fontPreviewLabel->setFont(font);
998
   
999
   _tempProfile->setProperty(Profile::Font,font);
1000

1001
   preview(Profile::Font,font);
1002
}
1003
void EditProfileDialog::showFontDialog()
1004
1005
{
    QFont currentFont = _ui->fontPreviewLabel->font();
1006
   
1007
1008
    KFontDialog* dialog = new KFontDialog(this, KFontChooser::FixedFontsOnly);
    dialog->setFont(currentFont, true);
1009

1010
    connect( dialog , SIGNAL(fontSelected(const QFont&)) , this , SLOT(fontSelected(const QFont&)) );
1011
1012
1013

    if (dialog->exec() == QDialog::Rejected)
		fontSelected(currentFont);
1014
}
1015
void EditProfileDialog::setFontSize(int pointSize)
1016
1017
1018
{
    QFont newFont = _ui->fontPreviewLabel->font();
    newFont.setPointSize(pointSize);
1019
	_ui->fontPreviewLabel->setFont(newFont);
1020
1021

    _tempProfile->setProperty(Profile::Font,newFont);
1022
1023

    preview(Profile::Font,newFont);
1024
1025
1026
1027
1028
1029
}
ColorSchemeViewDelegate::ColorSchemeViewDelegate(QObject* parent)
 : QAbstractItemDelegate(parent)
{

}