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