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
21 #include "EditProfileDialog.h"
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>
36 #include <kcodecaction.h>
38 #include <KFontDialog>
40 #include <KIconDialog>
41 #include <KFileDialog>
42 #include <KUrlCompletion>
43 #include <KWindowSystem>
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
)
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);
75 #warning "Re-enable when flow control is working again - bug in KDE 4.1"
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
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()
100 void EditProfileDialog::save()
102 if ( _tempProfile
->isEmpty() )
105 SessionManager::instance()->changeProfile(_profile
,_tempProfile
->setProperties());
107 // ensure that these settings are not undone by a call
109 QHashIterator
<Profile::Property
,QVariant
> iter(_tempProfile
->setProperties());
110 while ( iter
.hasNext() )
113 _previewedProperties
.remove(iter
.key());
116 void EditProfileDialog::reject()
121 void EditProfileDialog::accept()
127 QString
EditProfileDialog::groupProfileNames(const ProfileGroup::Ptr group
, int maxLength
)
130 int count
= group
->profiles().count();
131 for (int i
=0;i
< count
;i
++)
133 caption
+= group
->profiles()[i
]->name();
137 // limit caption length to prevent very long window titles
138 if (maxLength
> 0 && caption
.length() > maxLength
)
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()) )
159 setCaption( i18n("Edit Profile \"%1\"",profile
->name()) );
161 void EditProfileDialog::setProfile(Profile::Ptr profile
)
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() );
179 _tempProfile
= new Profile
;
182 const Profile::Ptr
EditProfileDialog::lookupProfile() const
186 void EditProfileDialog::preparePage(int page
)
188 const Profile::Ptr info
= lookupProfile();
190 Q_ASSERT( _pageNeedsUpdate
.count() > page
);
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
)
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
);
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() );
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
));
257 _ui
->showMenuBarButton
->setChecked( info
->property
<bool>(Profile::ShowMenuBar
) );
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
)
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
));
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
));
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);
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(),
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"
437 _ui
->editColorSchemeButton
->setEnabled(false);
438 _ui
->removeColorSchemeButton
->setEnabled(false);
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();
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());
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
)
527 model
->appendRow(item
);
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());
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
)
577 model
->appendRow(item
);
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());
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() )
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
))
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() )
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())
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
*>();
706 colors
= ColorSchemeManager::instance()->defaultColorScheme();
710 KDialog
* dialog
= new KDialog(this);
713 dialog
->setCaption(i18n("New Color Scheme"));
715 dialog
->setCaption(i18n("Edit Color Scheme"));
717 ColorSchemeEditor
* editor
= new ColorSchemeEditor
;
718 dialog
->setMainWidget(editor
);
719 editor
->setup(colors
);
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
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
*>();
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"));
850 dialog
->setCaption(i18n("Edit Key Binding List"));
852 KeyBindingEditor
* editor
= new KeyBindingEditor
;
853 dialog
->setMainWidget(editor
);
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
);
899 void EditProfileDialog::setupRadio( RadioOption
* possible
, int actual
)
901 while (possible
->button
!= 0)
903 if ( possible
->property
== actual
)
904 possible
->button
->setChecked(true);
906 possible
->button
->setChecked(false);
908 connect( possible
->button
, SIGNAL(clicked()) , this , possible
->slot
);
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())},
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())},
934 setupRadio( types
, scrollBackType
);
936 // setup scrollback line count spinner
937 _ui
->scrollBackLinesSpinner
->setValue( profile
->property
<int>(Profile::HistorySize
) );
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)) },
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
&)) );
995 if ( profile
->property
<bool>(Profile::UseCustomCursorColor
) )
996 _ui
->customCursorColorButton
->setChecked(true);
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)) );
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
;
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
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
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
*>();
1150 bool transparencyAvailable
= KWindowSystem::compositingActive();
1152 painter
->setRenderHint( QPainter::Antialiasing
);
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
)
1176 color
.setAlphaF(scheme
->opacity());
1177 painter
->setCompositionMode( QPainter::CompositionMode_Source
);
1178 painter
->setBrush(backgroundGradient
);
1180 painter
->drawPath(backgroundRectPath
);
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
));
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
) );
1218 QColor highlightColor
= option
.palette
.highlight().color();
1221 highlightColor
.setAlphaF(1.0);
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
;
1253 qreal heightForWidth
= ( colorWidth
* 2 ) + option
.fontMetrics
.height() + margin
;
1256 return QSize(width
,(int)heightForWidth
);
1259 #include "EditProfileDialog.moc"