add more spacing
[personal-kdebase.git] / apps / konsole / src / EditProfileDialog.cpp
blobe07e39c79c65a1548cc8b8374615cfed0f40b3a4
1 /*
2 Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301 USA.
20 // Own
21 #include "EditProfileDialog.h"
23 // Qt
24 #include <QtGui/QKeyEvent>
25 #include <QtGui/QBrush>
26 #include <QtGui/QPainter>
27 #include <QtGui/QStandardItem>
28 #include <QtCore/QTextCodec>
29 #include <QtGui/QLinearGradient>
30 #include <QtGui/QRadialGradient>
32 #include <QtCore/QTimer>
33 #include <QtCore/QTimeLine>
35 // KDE
36 #include <kcodecaction.h>
37 #include <KDebug>
38 #include <KFontDialog>
39 #include <KIcon>
40 #include <KIconDialog>
41 #include <KFileDialog>
42 #include <KUrlCompletion>
43 #include <KWindowSystem>
44 #include <KTextEdit>
46 // Konsole
47 #include "ColorScheme.h"
48 #include "ColorSchemeEditor.h"
49 #include "ui_EditProfileDialog.h"
50 #include "KeyBindingEditor.h"
51 #include "KeyboardTranslator.h"
52 #include "SessionManager.h"
53 #include "ShellCommand.h"
54 #include "TabTitleFormatAction.h"
56 using namespace Konsole;
58 EditProfileDialog::EditProfileDialog(QWidget* parent)
59 : KDialog(parent)
60 , _colorSchemeAnimationTimeLine(0)
61 , _delayedPreviewTimer(new QTimer(this))
63 setCaption(i18n("Edit Profile"));
64 setButtons( KDialog::Ok | KDialog::Cancel | KDialog::Apply );
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());
71 // - Renable in a later KDE 4.x release when this feature works again
72 _ui->enableResizeWindowButton->setVisible(false);
74 #ifdef __GNUC__
75 #warning "Re-enable when flow control is working again - bug in KDE 4.1"
76 #endif
77 _ui->enableFlowControlButton->setEnabled(false);
79 // there are various setupXYZPage() methods to load the items
80 // for each page and update their states to match the profile
81 // being edited.
83 // these are only called when needed ( ie. when the user clicks
84 // the tab to move to that page ).
86 // the _pageNeedsUpdate vector keeps track of the pages that have
87 // not been updated since the last profile change and will need
88 // to be refreshed when the user switches to them
89 _pageNeedsUpdate.resize( _ui->tabWidget->count() );
90 connect( _ui->tabWidget , SIGNAL(currentChanged(int)) , this ,
91 SLOT(preparePage(int)) );
93 _tempProfile = new Profile;
94 _tempProfile->setHidden(true);
96 EditProfileDialog::~EditProfileDialog()
98 delete _ui;
100 void EditProfileDialog::save()
102 if ( _tempProfile->isEmpty() )
103 return;
105 SessionManager::instance()->changeProfile(_profile,_tempProfile->setProperties());
107 // ensure that these settings are not undone by a call
108 // to unpreview()
109 QHashIterator<Profile::Property,QVariant> iter(_tempProfile->setProperties());
110 while ( iter.hasNext() )
112 iter.next();
113 _previewedProperties.remove(iter.key());
116 void EditProfileDialog::reject()
118 unpreviewAll();
119 KDialog::reject();
121 void EditProfileDialog::accept()
123 save();
124 unpreviewAll();
125 KDialog::accept();
127 QString EditProfileDialog::groupProfileNames(const ProfileGroup::Ptr group, int maxLength)
129 QString caption;
130 int count = group->profiles().count();
131 for (int i=0;i < count;i++)
133 caption += group->profiles()[i]->name();
134 if (i < (count-1))
136 caption += ',';
137 // limit caption length to prevent very long window titles
138 if (maxLength > 0 && caption.length() > maxLength)
140 caption += "...";
141 break;
145 return caption;
147 void EditProfileDialog::updateCaption(const Profile::Ptr profile)
149 const int MAX_GROUP_CAPTION_LENGTH = 25;
150 ProfileGroup::Ptr group = profile->asGroup();
151 if (group && group->profiles().count() > 1)
153 QString caption = groupProfileNames(group,MAX_GROUP_CAPTION_LENGTH);
154 setCaption( i18n("Edit Profile \"%1\"",caption) );
155 // STRINGFREEZE - Change caption for groups after KDE 4.1 is released
156 // setCaption( i18n("Editing %1 profiles",group->profiles().count()) )
158 else
159 setCaption( i18n("Edit Profile \"%1\"",profile->name()) );
161 void EditProfileDialog::setProfile(Profile::Ptr profile)
163 _profile = profile;
165 Q_ASSERT( profile );
167 // update caption
168 updateCaption(profile);
170 // mark each page of the dialog as out of date
171 // and force an update of the currently visible page
173 // the other pages will be updated as necessary
174 _pageNeedsUpdate.fill(true);
175 preparePage( _ui->tabWidget->currentIndex() );
177 if ( _tempProfile )
179 _tempProfile = new Profile;
182 const Profile::Ptr EditProfileDialog::lookupProfile() const
184 return _profile;
186 void EditProfileDialog::preparePage(int page)
188 const Profile::Ptr info = lookupProfile();
190 Q_ASSERT( _pageNeedsUpdate.count() > page );
191 Q_ASSERT( info );
193 QWidget* pageWidget = _ui->tabWidget->widget(page);
195 if ( _pageNeedsUpdate[page] )
197 if ( pageWidget == _ui->generalTab )
198 setupGeneralPage(info);
199 else if ( pageWidget == _ui->tabsTab )
200 setupTabsPage(info);
201 else if ( pageWidget == _ui->appearanceTab )
202 setupAppearancePage(info);
203 else if ( pageWidget == _ui->scrollingTab )
204 setupScrollingPage(info);
205 else if ( pageWidget == _ui->keyboardTab )
206 setupKeyboardPage(info);
207 else if ( pageWidget == _ui->advancedTab )
208 setupAdvancedPage(info);
209 else
210 Q_ASSERT(false);
212 _pageNeedsUpdate[page] = false;
215 // start page entry animation for color schemes
216 if ( pageWidget == _ui->appearanceTab )
217 _colorSchemeAnimationTimeLine->start();
219 void EditProfileDialog::selectProfileName()
221 _ui->profileNameEdit->selectAll();
222 _ui->profileNameEdit->setFocus();
224 void EditProfileDialog::setupGeneralPage(const Profile::Ptr info)
226 // basic profile options
228 ProfileGroup::Ptr group = info->asGroup();
229 if (!group || group->profiles().count() < 2)
230 _ui->profileNameEdit->setText( info->name() );
231 else
233 _ui->profileNameEdit->setText( groupProfileNames(group,-1) );
234 _ui->profileNameLabel->setEnabled(false);
235 _ui->profileNameEdit->setEnabled(false);
239 ShellCommand command( info->command() , info->arguments() );
240 _ui->commandEdit->setText( command.fullCommand() );
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() );
248 KUrlCompletion* dirCompletion = new KUrlCompletion(KUrlCompletion::DirCompletion);
249 dirCompletion->setParent(this);
250 _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));
256 // window options
257 _ui->showMenuBarButton->setChecked( info->property<bool>(Profile::ShowMenuBar) );
259 // signals and slots
260 connect( _ui->dirSelectButton , SIGNAL(clicked()) , this , SLOT(selectInitialDir()) );
261 connect( _ui->iconSelectButton , SIGNAL(clicked()) , this , SLOT(selectIcon()) );
262 connect( _ui->startInSameDirButton , SIGNAL(toggled(bool)) , this ,
263 SLOT(startInSameDir(bool)));
264 connect( _ui->profileNameEdit , SIGNAL(textChanged(const QString&)) , this ,
265 SLOT(profileNameChanged(const QString&)) );
266 connect( _ui->initialDirEdit , SIGNAL(textChanged(const QString&)) , this ,
267 SLOT(initialDirChanged(const QString&)) );
268 connect(_ui->commandEdit , SIGNAL(textChanged(const QString&)) , this ,
269 SLOT(commandChanged(const QString&)) );
271 connect(_ui->showMenuBarButton , SIGNAL(toggled(bool)) , this ,
272 SLOT(showMenuBar(bool)) );
274 connect(_ui->environmentEditButton , SIGNAL(clicked()) , this ,
275 SLOT(showEnvironmentEditor()) );
277 void EditProfileDialog::showEnvironmentEditor()
279 const Profile::Ptr info = lookupProfile();
281 KDialog* dialog = new KDialog(this);
282 KTextEdit* edit = new KTextEdit(dialog);
284 QStringList currentEnvironment = info->property<QStringList>(Profile::Environment);
286 edit->setPlainText( currentEnvironment.join("\n") );
287 dialog->setPlainCaption(i18n("Edit Environment"));
288 dialog->setMainWidget(edit);
290 if ( dialog->exec() == QDialog::Accepted )
292 QStringList newEnvironment = edit->toPlainText().split('\n');
293 _tempProfile->setProperty(Profile::Environment,newEnvironment);
296 dialog->deleteLater();
298 void EditProfileDialog::setupTabsPage(const Profile::Ptr info)
300 // tab title format
301 _ui->tabTitleEdit->setClearButtonShown(true);
302 _ui->remoteTabTitleEdit->setClearButtonShown(true);
303 _ui->tabTitleEdit->setText( info->property<QString>(Profile::LocalTabTitleFormat) );
304 _ui->remoteTabTitleEdit->setText(
305 info->property<QString>(Profile::RemoteTabTitleFormat));
307 // tab options
308 int tabMode = info->property<int>(Profile::TabBarMode);
309 int tabPosition = info->property<int>(Profile::TabBarPosition);
311 // note: Items should be in the same order as the
312 // Profile::TabBarModeEnum enum
313 _ui->tabBarVisibilityCombo->addItems( QStringList() << i18n("Always Hide Tab Bar")
314 << i18n("Show Tab Bar When Needed")
315 << i18n("Always Show Tab Bar") );
316 _ui->tabBarVisibilityCombo->setCurrentIndex(tabMode);
318 // note: Items should be in the same order as the
319 // Profile::TabBarPositionEnum enum
320 _ui->tabBarPositionCombo->addItems( QStringList() << i18n("Below Terminal Displays")
321 << i18n("Above Terminal Displays") );
323 _ui->tabBarPositionCombo->setCurrentIndex(tabPosition);
324 _ui->newTabButton->setChecked(info->property<bool>(Profile::ShowNewAndCloseTabButtons));
326 // signals and slots
327 connect( _ui->tabBarVisibilityCombo , SIGNAL(activated(int)) , this ,
328 SLOT(tabBarVisibilityChanged(int)) );
329 connect( _ui->tabBarPositionCombo , SIGNAL(activated(int)) , this ,
330 SLOT(tabBarPositionChanged(int)) );
331 connect( _ui->newTabButton , SIGNAL(toggled(bool)) , this ,
332 SLOT(showNewTabButton(bool)) );
334 connect(_ui->tabTitleEdit , SIGNAL(textChanged(const QString&)) , this ,
335 SLOT(tabTitleFormatChanged(const QString&)) );
336 connect(_ui->remoteTabTitleEdit , SIGNAL(textChanged(const QString&)) , this ,
337 SLOT(remoteTabTitleFormatChanged(const QString&)));
339 // menus for local and remote tab title dynamic elements
340 TabTitleFormatAction* localTabTitleAction = new TabTitleFormatAction(this);
341 localTabTitleAction->setContext(Session::LocalTabTitle);
342 _ui->tabTitleEditButton->setMenu(localTabTitleAction->menu());
343 connect( localTabTitleAction , SIGNAL(dynamicElementSelected(const QString&)) ,
344 this , SLOT(insertTabTitleText(const QString&)) );
346 TabTitleFormatAction* remoteTabTitleAction = new TabTitleFormatAction(this);
347 remoteTabTitleAction->setContext(Session::RemoteTabTitle);
348 _ui->remoteTabTitleEditButton->setMenu(remoteTabTitleAction->menu());
349 connect( remoteTabTitleAction , SIGNAL(dynamicElementSelected(const QString&)) ,
350 this , SLOT(insertRemoteTabTitleText(const QString&)) );
352 void EditProfileDialog::showNewTabButton(bool show)
353 { _tempProfile->setProperty(Profile::ShowNewAndCloseTabButtons,show); }
354 void EditProfileDialog::tabBarVisibilityChanged(int newValue)
356 _tempProfile->setProperty( Profile::TabBarMode , newValue );
358 void EditProfileDialog::tabBarPositionChanged(int newValue)
360 _tempProfile->setProperty( Profile::TabBarPosition , newValue );
362 void EditProfileDialog::insertTabTitleText(const QString& text)
364 _ui->tabTitleEdit->insert(text);
366 void EditProfileDialog::insertRemoteTabTitleText(const QString& text)
368 _ui->remoteTabTitleEdit->insert(text);
370 void EditProfileDialog::showMenuBar(bool show)
372 _tempProfile->setProperty(Profile::ShowMenuBar,show);
374 void EditProfileDialog::tabTitleFormatChanged(const QString& format)
376 _tempProfile->setProperty(Profile::LocalTabTitleFormat,format);
378 void EditProfileDialog::remoteTabTitleFormatChanged(const QString& format)
380 _tempProfile->setProperty(Profile::RemoteTabTitleFormat,format);
383 void EditProfileDialog::selectIcon()
385 const QString& icon = KIconDialog::getIcon(KIconLoader::Desktop, KIconLoader::Application,
386 false, 0, false, this);
387 if (!icon.isEmpty())
389 _ui->iconSelectButton->setIcon( KIcon(icon) );
390 _tempProfile->setProperty(Profile::Icon,icon);
393 void EditProfileDialog::profileNameChanged(const QString& text)
395 _tempProfile->setProperty(Profile::Name,text);
396 updateCaption(_tempProfile);
398 void EditProfileDialog::startInSameDir(bool sameDir)
400 _tempProfile->setProperty(Profile::StartInCurrentSessionDir,sameDir);
402 void EditProfileDialog::initialDirChanged(const QString& dir)
404 _tempProfile->setProperty(Profile::Directory,dir);
406 void EditProfileDialog::commandChanged(const QString& command)
408 ShellCommand shellCommand(command);
410 _tempProfile->setProperty(Profile::Command,shellCommand.command());
411 _tempProfile->setProperty(Profile::Arguments,shellCommand.arguments());
413 void EditProfileDialog::selectInitialDir()
415 const KUrl url = KFileDialog::getExistingDirectoryUrl(_ui->initialDirEdit->text(),
416 this,
417 i18n("Select Initial Directory"));
419 if ( !url.isEmpty() )
420 _ui->initialDirEdit->setText(url.path());
422 void EditProfileDialog::setupAppearancePage(const Profile::Ptr info)
424 ColorSchemeViewDelegate* delegate = new ColorSchemeViewDelegate(this);
425 _ui->colorSchemeList->setItemDelegate(delegate);
427 _colorSchemeAnimationTimeLine = new QTimeLine( 500 , this );
428 delegate->setEntryTimeLine(_colorSchemeAnimationTimeLine);
430 connect( _colorSchemeAnimationTimeLine , SIGNAL(valueChanged(qreal)) , this ,
431 SLOT(colorSchemeAnimationUpdate()) );
433 _ui->transparencyWarningWidget->setVisible(false);
434 _ui->transparencyWarningWidget->setText(i18n("This color scheme uses a transparent background"
435 " which does not appear to be supported on your"
436 " desktop"));
437 _ui->editColorSchemeButton->setEnabled(false);
438 _ui->removeColorSchemeButton->setEnabled(false);
440 // setup color list
441 updateColorSchemeList(true);
443 _ui->colorSchemeList->setMouseTracking(true);
444 _ui->colorSchemeList->installEventFilter(this);
445 _ui->colorSchemeList->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOn );
447 connect( _ui->colorSchemeList->selectionModel() ,
448 SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&))
449 , this , SLOT(colorSchemeSelected()) );
450 connect( _ui->colorSchemeList , SIGNAL(entered(const QModelIndex&)) , this ,
451 SLOT(previewColorScheme(const QModelIndex&)) );
453 updateColorSchemeButtons();
455 connect( _ui->editColorSchemeButton , SIGNAL(clicked()) , this ,
456 SLOT(editColorScheme()) );
457 connect( _ui->removeColorSchemeButton , SIGNAL(clicked()) , this ,
458 SLOT(removeColorScheme()) );
459 connect( _ui->newColorSchemeButton , SIGNAL(clicked()) , this ,
460 SLOT(newColorScheme()) );
462 // setup font preview
463 bool antialias = info->property<bool>(Profile::AntiAliasFonts);
465 QFont font = info->font();
466 if (!antialias)
467 font.setStyleStrategy(QFont::NoAntialias);
469 _ui->fontPreviewLabel->installEventFilter(this);
470 _ui->fontPreviewLabel->setFont(font);
471 _ui->fontSizeSlider->setValue( font.pointSize() );
472 _ui->fontSizeSlider->setMinimum( KGlobalSettings::smallestReadableFont().pointSize() );
474 connect( _ui->fontSizeSlider , SIGNAL(valueChanged(int)) , this ,
475 SLOT(setFontSize(int)) );
476 connect( _ui->editFontButton , SIGNAL(clicked()) , this ,
477 SLOT(showFontDialog()) );
479 // setup font smoothing
480 _ui->antialiasTextButton->setChecked(antialias);
481 connect( _ui->antialiasTextButton , SIGNAL(toggled(bool)) , this ,
482 SLOT(setAntialiasText(bool)) );
484 void EditProfileDialog::setAntialiasText(bool enable)
486 _tempProfile->setProperty(Profile::AntiAliasFonts,enable);
488 // update preview to reflect text smoothing state
489 fontSelected(_ui->fontPreviewLabel->font());
491 void EditProfileDialog::colorSchemeAnimationUpdate()
493 QAbstractItemModel* model = _ui->colorSchemeList->model();
495 for ( int i = model->rowCount() ; i >= 0 ; i-- )
496 _ui->colorSchemeList->update( model->index(i,0) );
498 void EditProfileDialog::updateColorSchemeList(bool selectCurrentScheme)
500 if (!_ui->colorSchemeList->model())
501 _ui->colorSchemeList->setModel(new QStandardItemModel(this));
503 const QString& name = lookupProfile()->colorScheme();
504 const ColorScheme* currentScheme = ColorSchemeManager::instance()->findColorScheme(name);
506 QStandardItemModel* model = qobject_cast<QStandardItemModel*>(_ui->colorSchemeList->model());
508 Q_ASSERT(model);
510 model->clear();
512 QList<const ColorScheme*> schemeList = ColorSchemeManager::instance()->allColorSchemes();
513 QListIterator<const ColorScheme*> schemeIter(schemeList);
515 QStandardItem* selectedItem = 0;
517 while (schemeIter.hasNext())
519 const ColorScheme* colors = schemeIter.next();
520 QStandardItem* item = new QStandardItem(colors->description());
521 item->setData( QVariant::fromValue(colors) , Qt::UserRole + 1);
522 item->setFlags( item->flags() );
524 if ( currentScheme == colors )
525 selectedItem = item;
527 model->appendRow(item);
530 model->sort(0);
532 if ( selectCurrentScheme && selectedItem )
534 _ui->colorSchemeList->updateGeometry();
535 _ui->colorSchemeList->selectionModel()->setCurrentIndex( selectedItem->index() ,
536 QItemSelectionModel::Select );
538 // update transparency warning label
539 updateTransparencyWarning();
542 void EditProfileDialog::updateKeyBindingsList(bool selectCurrentTranslator)
544 if (!_ui->keyBindingList->model())
545 _ui->keyBindingList->setModel(new QStandardItemModel(this));
547 KeyboardTranslatorManager* keyManager = KeyboardTranslatorManager::instance();
549 const QString& name = lookupProfile()
550 ->property<QString>(Profile::KeyBindings);
552 const KeyboardTranslator* currentTranslator = keyManager->findTranslator(name);
554 QStandardItemModel* model = qobject_cast<QStandardItemModel*>(_ui->keyBindingList->model());
556 Q_ASSERT(model);
558 model->clear();
560 QStandardItem* selectedItem = 0;
562 QList<QString> translatorNames = keyManager->allTranslators();
563 QListIterator<QString> iter(translatorNames);
564 while (iter.hasNext())
566 const QString& name = iter.next();
568 const KeyboardTranslator* translator = keyManager->findTranslator(name);
570 QStandardItem* item = new QStandardItem(translator->description());
571 item->setData(QVariant::fromValue(translator),Qt::UserRole+1);
572 item->setIcon( KIcon("preferences-desktop-keyboard") );
574 if ( translator == currentTranslator )
575 selectedItem = item;
577 model->appendRow(item);
580 model->sort(0);
582 if ( selectCurrentTranslator && selectedItem )
584 _ui->keyBindingList->selectionModel()->setCurrentIndex( selectedItem->index() ,
585 QItemSelectionModel::Select );
588 bool EditProfileDialog::eventFilter( QObject* watched , QEvent* event )
590 if ( watched == _ui->colorSchemeList && event->type() == QEvent::Leave )
592 if ( _tempProfile->isPropertySet(Profile::ColorScheme) )
593 preview(Profile::ColorScheme,_tempProfile->colorScheme());
594 else
595 unpreview(Profile::ColorScheme);
597 if ( watched == _ui->fontPreviewLabel && event->type() == QEvent::FontChange )
599 const QFont& labelFont = _ui->fontPreviewLabel->font();
600 _ui->fontPreviewLabel->setText(i18n("%1, size %2",labelFont.family(),labelFont.pointSize()));
603 return KDialog::eventFilter(watched,event);
605 void EditProfileDialog::unpreviewAll()
607 _delayedPreviewTimer->stop();
608 _delayedPreviewProperties.clear();
610 QHash<Profile::Property,QVariant> map;
611 QHashIterator<int,QVariant> iter(_previewedProperties);
612 while ( iter.hasNext() )
614 iter.next();
615 map.insert((Profile::Property)iter.key(),iter.value());
618 // undo any preview changes
619 if ( !map.isEmpty() )
620 SessionManager::instance()->changeProfile(_profile,map,false);
622 void EditProfileDialog::unpreview(int property)
624 _delayedPreviewProperties.remove(property);
626 if (!_previewedProperties.contains(property))
627 return;
629 QHash<Profile::Property,QVariant> map;
630 map.insert((Profile::Property)property,_previewedProperties[property]);
631 SessionManager::instance()->changeProfile(_profile,map,false);
633 _previewedProperties.remove(property);
635 void EditProfileDialog::delayedPreview(int property , const QVariant& value)
637 _delayedPreviewProperties.insert(property,value);
639 _delayedPreviewTimer->stop();
640 _delayedPreviewTimer->start(300);
642 void EditProfileDialog::delayedPreviewActivate()
644 Q_ASSERT( qobject_cast<QTimer*>(sender()) );
646 QMutableHashIterator<int,QVariant> iter(_delayedPreviewProperties);
647 if ( iter.hasNext() )
649 iter.next();
650 preview(iter.key(),iter.value());
653 void EditProfileDialog::preview(int property , const QVariant& value)
655 QHash<Profile::Property,QVariant> map;
656 map.insert((Profile::Property)property,value);
658 _delayedPreviewProperties.remove(property);
660 const Profile::Ptr original = lookupProfile();
662 // skip previews for profile groups if the profiles in the group
663 // have conflicting original values for the property
665 // TODO - Save the original values for each profile and use to unpreview properties
666 ProfileGroup::Ptr group = original->asGroup();
667 if (group && group->profiles().count() > 1 &&
668 original->property<QVariant>((Profile::Property)property).isNull())
669 return;
671 if (!_previewedProperties.contains(property))
673 _previewedProperties.insert(property , original->property<QVariant>((Profile::Property)property) );
676 // temporary change to color scheme
677 SessionManager::instance()->changeProfile( _profile , map , false);
679 void EditProfileDialog::previewColorScheme(const QModelIndex& index)
681 const QString& name = index.data(Qt::UserRole+1).value<const ColorScheme*>()->name();
683 delayedPreview( Profile::ColorScheme , name );
685 void EditProfileDialog::removeColorScheme()
687 QModelIndexList selected = _ui->colorSchemeList->selectionModel()->selectedIndexes();
689 if ( !selected.isEmpty() )
691 const QString& name = selected.first().data(Qt::UserRole+1).value<const ColorScheme*>()->name();
693 if (ColorSchemeManager::instance()->deleteColorScheme(name))
694 _ui->colorSchemeList->model()->removeRow(selected.first().row());
697 void EditProfileDialog::showColorSchemeEditor(bool isNewScheme)
699 QModelIndexList selected = _ui->colorSchemeList->selectionModel()->selectedIndexes();
701 QAbstractItemModel* model = _ui->colorSchemeList->model();
702 const ColorScheme* colors = 0;
703 if ( !selected.isEmpty() )
704 colors = model->data(selected.first(),Qt::UserRole+1).value<const ColorScheme*>();
705 else
706 colors = ColorSchemeManager::instance()->defaultColorScheme();
708 Q_ASSERT(colors);
710 KDialog* dialog = new KDialog(this);
712 if ( isNewScheme )
713 dialog->setCaption(i18n("New Color Scheme"));
714 else
715 dialog->setCaption(i18n("Edit Color Scheme"));
717 ColorSchemeEditor* editor = new ColorSchemeEditor;
718 dialog->setMainWidget(editor);
719 editor->setup(colors);
721 if ( isNewScheme )
722 editor->setDescription(i18n("New Color Scheme"));
724 if ( dialog->exec() == QDialog::Accepted )
726 ColorScheme* newScheme = new ColorScheme(*editor->colorScheme());
728 // if this is a new color scheme, pick a name based on the description
729 if ( isNewScheme )
730 newScheme->setName(newScheme->description());
732 ColorSchemeManager::instance()->addColorScheme( newScheme );
734 updateColorSchemeList(true);
736 preview(Profile::ColorScheme,newScheme->name());
739 void EditProfileDialog::newColorScheme()
741 showColorSchemeEditor(true);
743 void EditProfileDialog::editColorScheme()
745 showColorSchemeEditor(false);
747 void EditProfileDialog::colorSchemeSelected()
749 QModelIndexList selected = _ui->colorSchemeList->selectionModel()->selectedIndexes();
751 if ( !selected.isEmpty() )
753 QAbstractItemModel* model = _ui->colorSchemeList->model();
754 const ColorScheme* colors = model->data(selected.first(),Qt::UserRole+1).value<const ColorScheme*>();
756 kDebug() << "Setting temp profile color to" << colors->name();
758 previewColorScheme(selected.first());
759 _tempProfile->setProperty(Profile::ColorScheme,colors->name());
761 updateTransparencyWarning();
764 updateColorSchemeButtons();
766 void EditProfileDialog::updateColorSchemeButtons()
768 enableIfNonEmptySelection(_ui->editColorSchemeButton,_ui->colorSchemeList->selectionModel());
769 enableIfNonEmptySelection(_ui->removeColorSchemeButton,_ui->colorSchemeList->selectionModel());
771 void EditProfileDialog::updateKeyBindingsButtons()
773 enableIfNonEmptySelection(_ui->editKeyBindingsButton,_ui->keyBindingList->selectionModel());
774 enableIfNonEmptySelection(_ui->removeKeyBindingsButton,_ui->keyBindingList->selectionModel());
776 void EditProfileDialog::enableIfNonEmptySelection(QWidget* widget,QItemSelectionModel* selectionModel)
778 widget->setEnabled(selectionModel->hasSelection());
780 void EditProfileDialog::updateTransparencyWarning()
782 // zero or one indexes can be selected
783 foreach( const QModelIndex& index , _ui->colorSchemeList->selectionModel()->selectedIndexes() )
785 bool hasTransparency = index.data(Qt::UserRole+1).value<const ColorScheme*>()->opacity() < 1.0;
786 _ui->transparencyWarningWidget->setHidden(KWindowSystem::compositingActive() || !hasTransparency);
789 void EditProfileDialog::setupKeyboardPage(const Profile::Ptr /* info */)
791 // setup translator list
792 updateKeyBindingsList(true);
794 connect( _ui->keyBindingList->selectionModel() ,
795 SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)),
796 SLOT(keyBindingSelected()) );
797 connect( _ui->newKeyBindingsButton , SIGNAL(clicked()) , this ,
798 SLOT(newKeyBinding()) );
800 updateKeyBindingsButtons();
802 connect( _ui->editKeyBindingsButton , SIGNAL(clicked()) , this ,
803 SLOT(editKeyBinding()) );
804 connect( _ui->removeKeyBindingsButton , SIGNAL(clicked()) , this ,
805 SLOT(removeKeyBinding()) );
807 void EditProfileDialog::keyBindingSelected()
809 QModelIndexList selected = _ui->keyBindingList->selectionModel()->selectedIndexes();
811 if ( !selected.isEmpty() )
813 QAbstractItemModel* model = _ui->keyBindingList->model();
814 const KeyboardTranslator* translator = model->data(selected.first(),Qt::UserRole+1)
815 .value<const KeyboardTranslator*>();
816 _tempProfile->setProperty(Profile::KeyBindings,translator->name());
819 updateKeyBindingsButtons();
821 void EditProfileDialog::removeKeyBinding()
823 QModelIndexList selected = _ui->keyBindingList->selectionModel()->selectedIndexes();
825 if ( !selected.isEmpty() )
827 const QString& name = selected.first().data(Qt::UserRole+1).value<const KeyboardTranslator*>()->name();
828 if (KeyboardTranslatorManager::instance()->deleteTranslator(name))
829 _ui->keyBindingList->model()->removeRow(selected.first().row());
832 void EditProfileDialog::showKeyBindingEditor(bool isNewTranslator)
834 QModelIndexList selected = _ui->keyBindingList->selectionModel()->selectedIndexes();
835 QAbstractItemModel* model = _ui->keyBindingList->model();
837 const KeyboardTranslator* translator = 0;
838 if ( !selected.isEmpty() )
839 translator = model->data(selected.first(),Qt::UserRole+1).value<const KeyboardTranslator*>();
840 else
841 translator = KeyboardTranslatorManager::instance()->defaultTranslator();
843 Q_ASSERT(translator);
845 KDialog* dialog = new KDialog(this);
847 if ( isNewTranslator )
848 dialog->setCaption(i18n("New Key Binding List"));
849 else
850 dialog->setCaption(i18n("Edit Key Binding List"));
852 KeyBindingEditor* editor = new KeyBindingEditor;
853 dialog->setMainWidget(editor);
855 if ( translator )
856 editor->setup(translator);
858 if ( isNewTranslator )
859 editor->setDescription(i18n("New Key Binding List"));
861 if ( dialog->exec() == QDialog::Accepted )
863 KeyboardTranslator* newTranslator = new KeyboardTranslator(*editor->translator());
865 if ( isNewTranslator )
866 newTranslator->setName(newTranslator->description());
868 KeyboardTranslatorManager::instance()->addTranslator( newTranslator );
870 updateKeyBindingsList();
872 const QString& currentTranslator = lookupProfile()
873 ->property<QString>(Profile::KeyBindings);
875 if ( newTranslator->name() == currentTranslator )
877 _tempProfile->setProperty(Profile::KeyBindings,newTranslator->name());
881 void EditProfileDialog::newKeyBinding()
883 showKeyBindingEditor(true);
885 void EditProfileDialog::editKeyBinding()
887 showKeyBindingEditor(false);
889 void EditProfileDialog::setupCombo( ComboOption* options , const Profile::Ptr profile )
891 while ( options->button != 0 )
893 options->button->setChecked(profile->property<bool>((Profile::Property)options->property));
894 connect( options->button , SIGNAL(toggled(bool)) , this , options->slot );
896 ++options;
899 void EditProfileDialog::setupRadio( RadioOption* possible , int actual )
901 while (possible->button != 0)
903 if ( possible->property == actual )
904 possible->button->setChecked(true);
905 else
906 possible->button->setChecked(false);
908 connect( possible->button , SIGNAL(clicked()) , this , possible->slot );
910 ++possible;
914 void EditProfileDialog::setupScrollingPage(const Profile::Ptr profile)
916 // setup scrollbar radio
917 int scrollBarPosition = profile->property<int>(Profile::ScrollBarPosition);
919 RadioOption positions[] = { {_ui->scrollBarHiddenButton,Profile::ScrollBarHidden,SLOT(hideScrollBar())},
920 {_ui->scrollBarLeftButton,Profile::ScrollBarLeft,SLOT(showScrollBarLeft())},
921 {_ui->scrollBarRightButton,Profile::ScrollBarRight,SLOT(showScrollBarRight())},
922 {0,0,0}
925 setupRadio( positions , scrollBarPosition );
927 // setup scrollback type radio
928 int scrollBackType = profile->property<int>(Profile::HistoryMode);
930 RadioOption types[] = { {_ui->disableScrollbackButton,Profile::DisableHistory,SLOT(noScrollBack())},
931 {_ui->fixedScrollbackButton,Profile::FixedSizeHistory,SLOT(fixedScrollBack())},
932 {_ui->unlimitedScrollbackButton,Profile::UnlimitedHistory,SLOT(unlimitedScrollBack())},
933 {0,0,0} };
934 setupRadio( types , scrollBackType );
936 // setup scrollback line count spinner
937 _ui->scrollBackLinesSpinner->setValue( profile->property<int>(Profile::HistorySize) );
939 // signals and slots
940 connect( _ui->scrollBackLinesSpinner , SIGNAL(valueChanged(int)) , this ,
941 SLOT(scrollBackLinesChanged(int)) );
944 void EditProfileDialog::scrollBackLinesChanged(int lineCount)
946 _tempProfile->setProperty(Profile::HistorySize , lineCount);
948 void EditProfileDialog::noScrollBack()
950 _tempProfile->setProperty(Profile::HistoryMode , Profile::DisableHistory);
952 void EditProfileDialog::fixedScrollBack()
954 _tempProfile->setProperty(Profile::HistoryMode , Profile::FixedSizeHistory);
956 void EditProfileDialog::unlimitedScrollBack()
958 _tempProfile->setProperty(Profile::HistoryMode , Profile::UnlimitedHistory );
960 void EditProfileDialog::hideScrollBar()
962 _tempProfile->setProperty(Profile::ScrollBarPosition , Profile::ScrollBarHidden );
964 void EditProfileDialog::showScrollBarLeft()
966 _tempProfile->setProperty(Profile::ScrollBarPosition , Profile::ScrollBarLeft );
968 void EditProfileDialog::showScrollBarRight()
970 _tempProfile->setProperty(Profile::ScrollBarPosition , Profile::ScrollBarRight );
972 void EditProfileDialog::setupAdvancedPage(const Profile::Ptr profile)
974 ComboOption options[] = { { _ui->enableBlinkingTextButton , Profile::BlinkingTextEnabled ,
975 SLOT(toggleBlinkingText(bool)) },
976 { _ui->enableFlowControlButton , Profile::FlowControlEnabled ,
977 SLOT(toggleFlowControl(bool)) },
978 { _ui->enableResizeWindowButton , Profile::AllowProgramsToResizeWindow ,
979 SLOT(toggleResizeWindow(bool)) },
980 { _ui->enableBlinkingCursorButton , Profile::BlinkingCursorEnabled ,
981 SLOT(toggleBlinkingCursor(bool)) },
982 { _ui->enableBidiRenderingButton , Profile::BidiRenderingEnabled ,
983 SLOT(togglebidiRendering(bool)) },
984 { 0 , 0 , 0 }
986 setupCombo( options , profile );
988 // interaction options
989 _ui->wordCharacterEdit->setText( profile->property<QString>(Profile::WordCharacters) );
991 connect( _ui->wordCharacterEdit , SIGNAL(textChanged(const QString&)) , this ,
992 SLOT(wordCharactersChanged(const QString&)) );
994 // cursor options
995 if ( profile->property<bool>(Profile::UseCustomCursorColor) )
996 _ui->customCursorColorButton->setChecked(true);
997 else
998 _ui->autoCursorColorButton->setChecked(true);
1000 _ui->customColorSelectButton->setColor( profile->property<QColor>(Profile::CustomCursorColor) );
1002 connect( _ui->customCursorColorButton , SIGNAL(clicked()) , this , SLOT(customCursorColor()) );
1003 connect( _ui->autoCursorColorButton , SIGNAL(clicked()) , this , SLOT(autoCursorColor()) );
1004 connect( _ui->customColorSelectButton , SIGNAL(changed(const QColor&)) ,
1005 SLOT(customCursorColorChanged(const QColor&)) );
1007 int shape = profile->property<int>(Profile::CursorShape);
1008 _ui->cursorShapeCombo->setCurrentIndex(shape);
1010 connect( _ui->cursorShapeCombo , SIGNAL(activated(int)) , this , SLOT(setCursorShape(int)) );
1012 // encoding options
1013 QAction* codecAction = new KCodecAction(this);
1014 _ui->selectEncodingButton->setMenu( codecAction->menu() );
1015 connect( codecAction , SIGNAL(triggered(QTextCodec*)) , this , SLOT(setDefaultCodec(QTextCodec*)) );
1017 _ui->characterEncodingLabel->setText( profile->property<QString>(Profile::DefaultEncoding) );
1020 void EditProfileDialog::setDefaultCodec(QTextCodec* codec)
1022 QString name = QString(codec->name());
1024 _tempProfile->setProperty(Profile::DefaultEncoding,name);
1025 _ui->characterEncodingLabel->setText(codec->name());
1027 void EditProfileDialog::customCursorColorChanged(const QColor& color)
1029 _tempProfile->setProperty(Profile::CustomCursorColor,color);
1031 // ensure that custom cursor colors are enabled
1032 _ui->customCursorColorButton->click();
1034 void EditProfileDialog::wordCharactersChanged(const QString& text)
1036 _tempProfile->setProperty(Profile::WordCharacters,text);
1038 void EditProfileDialog::autoCursorColor()
1040 _tempProfile->setProperty(Profile::UseCustomCursorColor,false);
1042 void EditProfileDialog::customCursorColor()
1044 _tempProfile->setProperty(Profile::UseCustomCursorColor,true);
1046 void EditProfileDialog::setCursorShape(int index)
1048 _tempProfile->setProperty(Profile::CursorShape,index);
1050 void EditProfileDialog::togglebidiRendering(bool enable)
1052 _tempProfile->setProperty(Profile::BidiRenderingEnabled,enable);
1054 void EditProfileDialog::toggleBlinkingCursor(bool enable)
1056 _tempProfile->setProperty(Profile::BlinkingCursorEnabled,enable);
1058 void EditProfileDialog::toggleBlinkingText(bool enable)
1060 _tempProfile->setProperty(Profile::BlinkingTextEnabled,enable);
1062 void EditProfileDialog::toggleFlowControl(bool enable)
1064 _tempProfile->setProperty(Profile::FlowControlEnabled,enable);
1066 void EditProfileDialog::toggleResizeWindow(bool enable)
1068 _tempProfile->setProperty(Profile::AllowProgramsToResizeWindow,enable);
1070 void EditProfileDialog::fontSelected(const QFont& font)
1072 QFont previewFont = font;
1074 QSlider* slider = _ui->fontSizeSlider;
1075 _ui->fontSizeSlider->setRange( qMin(slider->minimum(),font.pointSize()) ,
1076 qMax(slider->maximum(),font.pointSize()) );
1077 _ui->fontSizeSlider->setValue(font.pointSize());
1080 QFont::StyleStrategy strategy;
1081 if (_tempProfile->property<bool>(Profile::AntiAliasFonts))
1082 strategy = QFont::PreferAntialias;
1083 else
1084 strategy = QFont::NoAntialias;
1086 previewFont.setStyleStrategy(strategy);
1088 _ui->fontPreviewLabel->setFont(previewFont);
1090 _tempProfile->setProperty(Profile::Font,font);
1092 preview(Profile::Font,font);
1094 void EditProfileDialog::showFontDialog()
1096 QFont currentFont = _ui->fontPreviewLabel->font();
1098 KFontDialog* dialog = new KFontDialog(this, KFontChooser::FixedFontsOnly);
1099 dialog->setFont(currentFont, true);
1101 connect( dialog , SIGNAL(fontSelected(const QFont&)) , this , SLOT(fontSelected(const QFont&)) );
1103 if (dialog->exec() == QDialog::Rejected)
1104 fontSelected(currentFont);
1106 void EditProfileDialog::setFontSize(int pointSize)
1108 QFont newFont = _ui->fontPreviewLabel->font();
1109 newFont.setPointSize(pointSize);
1110 _ui->fontPreviewLabel->setFont(newFont);
1112 _tempProfile->setProperty(Profile::Font,newFont);
1114 preview(Profile::Font,newFont);
1116 ColorSchemeViewDelegate::ColorSchemeViewDelegate(QObject* parent)
1117 : QAbstractItemDelegate(parent)
1122 void ColorSchemeViewDelegate::setEntryTimeLine(QTimeLine* timeLine)
1124 _entryTimeLine = timeLine;
1127 void ColorSchemeViewDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option,
1128 const QModelIndex& index) const
1130 // entry animation
1132 // note that the translation occurs for each item drawn, but the
1133 // painter is not reset between painting items. this means that when
1134 // the items are painted in order ( as occurs when the list is first
1135 // shown ), there is a visually pleasing staggering of items as they
1136 // enter.
1137 if ( _entryTimeLine != 0 )
1139 qreal value = 1.0-_entryTimeLine->currentValue();
1140 painter->translate( value *
1141 option.rect.width() , 0 );
1143 painter->setOpacity( _entryTimeLine->currentValue() );
1146 const ColorScheme* scheme = index.data(Qt::UserRole + 1).value<const ColorScheme*>();
1148 Q_ASSERT(scheme);
1150 bool transparencyAvailable = KWindowSystem::compositingActive();
1152 painter->setRenderHint( QPainter::Antialiasing );
1154 // draw background
1155 painter->setPen( QPen(scheme->foregroundColor() , 1) );
1157 // radial gradient for background
1158 // from a lightened version of the scheme's background color in the center to
1159 // a darker version at the outer edge
1160 QColor color = scheme->backgroundColor();
1161 QRectF backgroundRect = QRectF(option.rect).adjusted(1.5,1.5,-1.5,-1.5);
1163 QRadialGradient backgroundGradient(backgroundRect.center() , backgroundRect.width() / 2);
1164 backgroundGradient.setColorAt( 0 , color.lighter(105) );
1165 backgroundGradient.setColorAt( 1 , color.darker(115) );
1167 const int backgroundRectXRoundness = 4;
1168 const int backgroundRectYRoundness = 30;
1170 QPainterPath backgroundRectPath(backgroundRect.topLeft());
1171 backgroundRectPath.addRoundRect( backgroundRect , backgroundRectXRoundness , backgroundRectYRoundness );
1173 if ( transparencyAvailable )
1175 painter->save();
1176 color.setAlphaF(scheme->opacity());
1177 painter->setCompositionMode( QPainter::CompositionMode_Source );
1178 painter->setBrush(backgroundGradient);
1180 painter->drawPath(backgroundRectPath);
1181 painter->restore();
1183 else
1185 painter->setBrush(backgroundGradient);
1186 painter->drawPath(backgroundRectPath);
1189 // draw stripe at the side using scheme's foreground color
1190 painter->setPen( QPen(Qt::NoPen) );
1191 QPainterPath path( option.rect.topLeft() );
1192 path.lineTo( option.rect.width() / 10.0 , option.rect.top() );
1193 path.lineTo( option.rect.bottomLeft() );
1194 path.lineTo( option.rect.topLeft() );
1195 painter->setBrush( scheme->foregroundColor() );
1196 painter->drawPath(path.intersected(backgroundRectPath));
1198 // draw highlight
1199 // with a linear gradient going from translucent white to transparent
1200 QLinearGradient gradient( option.rect.topLeft() , option.rect.bottomLeft() );
1201 gradient.setColorAt( 0 , QColor(255,255,255,90) );
1202 gradient.setColorAt( 1 , Qt::transparent );
1203 painter->setBrush(gradient);
1204 painter->drawRoundRect( backgroundRect , 4 , 30 );
1206 //const bool isChecked = index.data(Qt::CheckStateRole) == Qt::Checked;
1207 const bool isSelected = option.state & QStyle::State_Selected;
1209 // draw border on selected items
1210 if ( isSelected ) //|| isChecked )
1212 static const int selectedBorderWidth = 6;
1215 painter->setBrush( QBrush(Qt::NoBrush) );
1216 QPen pen;
1218 QColor highlightColor = option.palette.highlight().color();
1220 if ( isSelected )
1221 highlightColor.setAlphaF(1.0);
1222 else
1223 highlightColor.setAlphaF(0.7);
1225 pen.setBrush(highlightColor);
1226 pen.setWidth(selectedBorderWidth);
1227 pen.setJoinStyle(Qt::MiterJoin);
1229 painter->setPen(pen);
1232 painter->drawRect( option.rect.adjusted(selectedBorderWidth/2,
1233 selectedBorderWidth/2,
1234 -selectedBorderWidth/2,
1235 -selectedBorderWidth/2) );
1238 // draw color scheme name using scheme's foreground color
1239 QPen pen(scheme->foregroundColor());
1240 painter->setPen(pen);
1242 painter->drawText( option.rect , Qt::AlignCenter ,
1243 index.data(Qt::DisplayRole).value<QString>() );
1247 QSize ColorSchemeViewDelegate::sizeHint( const QStyleOptionViewItem& option,
1248 const QModelIndex& /*index*/) const
1250 const int width = 200;
1251 qreal colorWidth = (qreal)width / TABLE_COLORS;
1252 int margin = 5;
1253 qreal heightForWidth = ( colorWidth * 2 ) + option.fontMetrics.height() + margin;
1255 // temporary
1256 return QSize(width,(int)heightForWidth);
1259 #include "EditProfileDialog.moc"