diff --git a/src/EditProfileDialog.cpp b/src/EditProfileDialog.cpp index 3795ed302..79be903cb 100644 --- a/src/EditProfileDialog.cpp +++ b/src/EditProfileDialog.cpp @@ -57,6 +57,7 @@ using namespace Konsole; EditProfileDialog::EditProfileDialog(QWidget* parent) : KDialog(parent) + , _colorSchemeAnimationTimeLine(0) { setCaption(i18n("Edit Profile")); setButtons( KDialog::Ok | KDialog::Cancel | KDialog::Apply | KDialog::Default ); @@ -78,7 +79,7 @@ EditProfileDialog::EditProfileDialog(QWidget* parent) // to be refreshed when the user switches to them _pageNeedsUpdate.resize( _ui->tabWidget->count() ); connect( _ui->tabWidget , SIGNAL(currentChanged(int)) , this , - SLOT(ensurePageLoaded(int)) ); + SLOT(preparePage(int)) ); _tempProfile = new Profile; @@ -116,6 +117,10 @@ void EditProfileDialog::accept() unpreviewAll(); KDialog::accept(); } +void EditProfileDialog::updateCaption(const QString& profileName) +{ + setCaption( i18n("Edit Profile \"%1\"",profileName) ); +} void EditProfileDialog::setProfile(const QString& key) { _profileKey = key; @@ -125,14 +130,14 @@ void EditProfileDialog::setProfile(const QString& key) Q_ASSERT( info ); // update caption - setCaption( i18n("Edit Profile \"%1\"",info->name()) ); + updateCaption(info->name()); // 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); - ensurePageLoaded( _ui->tabWidget->currentIndex() ); + preparePage( _ui->tabWidget->currentIndex() ); if ( _tempProfile ) { @@ -144,17 +149,17 @@ const Profile* EditProfileDialog::lookupProfile() const { return SessionManager::instance()->profile(_profileKey); } -void EditProfileDialog::ensurePageLoaded(int page) +void EditProfileDialog::preparePage(int page) { const Profile* info = lookupProfile(); Q_ASSERT( _pageNeedsUpdate.count() > page ); Q_ASSERT( info ); + QWidget* pageWidget = _ui->tabWidget->widget(page); + if ( _pageNeedsUpdate[page] ) { - QWidget* pageWidget = _ui->tabWidget->widget(page); - if ( pageWidget == _ui->generalTab ) setupGeneralPage(info); else if ( pageWidget == _ui->tabsTab ) @@ -172,6 +177,15 @@ void EditProfileDialog::ensurePageLoaded(int page) _pageNeedsUpdate[page] = false; } + + // start page entry animation for color schemes + if ( pageWidget == _ui->appearanceTab ) + _colorSchemeAnimationTimeLine->start(); +} +void EditProfileDialog::selectProfileName() +{ + _ui->profileNameEdit->selectAll(); + _ui->profileNameEdit->setFocus(); } void EditProfileDialog::setupGeneralPage(const Profile* info) { @@ -324,6 +338,7 @@ void EditProfileDialog::selectIcon() void EditProfileDialog::profileNameChanged(const QString& text) { _tempProfile->setProperty(Profile::Name,text); + updateCaption(_tempProfile->name()); } void EditProfileDialog::initialDirChanged(const QString& dir) { @@ -354,10 +369,10 @@ void EditProfileDialog::setupAppearancePage(const Profile* info) ColorSchemeViewDelegate* delegate = new ColorSchemeViewDelegate(this); - QTimeLine* timeLine = new QTimeLine( 500 , this ); - delegate->setEntryTimeLine(timeLine); + _colorSchemeAnimationTimeLine = new QTimeLine( 500 , this ); + delegate->setEntryTimeLine(_colorSchemeAnimationTimeLine); - connect( timeLine , SIGNAL(valueChanged(qreal)) , this , + connect( _colorSchemeAnimationTimeLine , SIGNAL(valueChanged(qreal)) , this , SLOT(colorSchemeAnimationUpdate()) ); _ui->colorSchemeList->setItemDelegate(delegate); @@ -387,9 +402,6 @@ void EditProfileDialog::setupAppearancePage(const Profile* info) SLOT(setFontSize(int)) ); connect( _ui->editFontButton , SIGNAL(clicked()) , this , SLOT(showFontDialog()) ); - - // start entry animation - timeLine->start(); } void EditProfileDialog::colorSchemeAnimationUpdate() { diff --git a/src/EditProfileDialog.h b/src/EditProfileDialog.h index 4874b86fb..409f58830 100644 --- a/src/EditProfileDialog.h +++ b/src/EditProfileDialog.h @@ -79,6 +79,14 @@ public: */ void setProfile(const QString& key); + /** + * Selects the text in the profile name edit area. + * When the dialog is being used to create a new profile, + * this can be used to draw the user's attention to the profile name + * and make it easy for them to change it. + */ + void selectProfileName(); + public slots: // reimplemented virtual void accept(); @@ -90,7 +98,7 @@ protected: private slots: // sets up the specified tab page if necessary - void ensurePageLoaded(int); + void preparePage(int); // saves changes to profile void save(); @@ -178,6 +186,8 @@ private: void unpreview(int property); void unpreviewAll(); + void updateCaption(const QString& profileName); + struct RadioOption { QAbstractButton* button; @@ -205,6 +215,8 @@ private: // after an update by a call to ensurePageLoaded() QVector _pageNeedsUpdate; QHash _previewedProperties; + + QTimeLine* _colorSchemeAnimationTimeLine; }; /** diff --git a/src/Filter.cpp b/src/Filter.cpp index 15f5d5634..39bbea0f5 100644 --- a/src/Filter.cpp +++ b/src/Filter.cpp @@ -488,7 +488,7 @@ void UrlFilter::HotSpot::activate(QObject* object) //regexp matches: // full url: // protocolname:// or www. followed by numbers, letters dots and dashes or the '@' character. -const QRegExp UrlFilter::FullUrlRegExp("([a-z]+://|www\\.)[a-zA-Z0-9@\\-\\./]+"); +const QRegExp UrlFilter::FullUrlRegExp("([a-z]+://|www\\.)[^\\s]+"); // email address: // [word chars, dots or dashes]@[word chars, dots or dashes].[word chars] const QRegExp UrlFilter::EmailAddressRegExp("(\\w|\\.|-)+@(\\w|\\.|-)+\\.\\w+"); diff --git a/src/ManageProfilesDialog.cpp b/src/ManageProfilesDialog.cpp index a812017ae..ebc011c71 100644 --- a/src/ManageProfilesDialog.cpp +++ b/src/ManageProfilesDialog.cpp @@ -47,7 +47,7 @@ ManageProfilesDialog::ManageProfilesDialog(QWidget* parent) // hide vertical header _ui->sessionTable->verticalHeader()->hide(); - _ui->sessionTable->setItemDelegateForColumn(1,new ProfileItemDelegate(this)); + _ui->sessionTable->setItemDelegateForColumn(FavoriteStatusColumn,new ProfileItemDelegate(this)); // update table and listen for changes to the session types updateTableModel(); @@ -57,6 +57,9 @@ ManageProfilesDialog::ManageProfilesDialog(QWidget* parent) SLOT(updateTableModel()) ); connect( SessionManager::instance() , SIGNAL(profileChanged(const QString&)) , this, SLOT(updateTableModel()) ); + connect( SessionManager::instance() , + SIGNAL(favoriteStatusChanged(const QString&,bool)) , this , + SLOT(updateFavoriteStatus(const QString&,bool)) ); // resize the session table to the full width of the table _ui->sessionTable->horizontalHeader()->setHighlightSections(false); @@ -106,7 +109,7 @@ void ManageProfilesDialog::itemDataChanged(QStandardItem* item) qDebug() << "New key sequence: " << item->text(); - SessionManager::instance()->setShortcut(item->data(Qt::UserRole+1).value(), + SessionManager::instance()->setShortcut(item->data(ShortcutRole).value(), sequence); } } @@ -137,7 +140,7 @@ void ManageProfilesDialog::updateTableModel() if ( !info->icon().isEmpty() ) item->setIcon( KIcon(info->icon()) ); - item->setData(key); + item->setData(key,ProfileKeyRole); const bool isFavorite = SessionManager::instance()->findFavorites().contains(key); @@ -148,14 +151,14 @@ void ManageProfilesDialog::updateTableModel() else favoriteItem->setData(KIcon(),Qt::DecorationRole); - favoriteItem->setData(key,Qt::UserRole+1); + favoriteItem->setData(key,ProfileKeyRole); // shortcut column QStandardItem* shortcutItem = new QStandardItem(); QString shortcut = SessionManager::instance()->shortcut(key). toString(); shortcutItem->setText(shortcut); - shortcutItem->setData(key,Qt::UserRole+1); + shortcutItem->setData(key,ShortcutRole); itemList << item << favoriteItem << shortcutItem; @@ -246,11 +249,16 @@ void ManageProfilesDialog::newType() newProfile->setProperty(Profile::Name,i18n("New Profile")); const QString& key = SessionManager::instance()->addProfile(newProfile); dialog.setProfile(key); - + dialog.selectProfileName(); + // if the user doesn't accept the dialog, remove the temporary profile // if they do accept the dialog, it will become a permanent profile if ( dialog.exec() != QDialog::Accepted ) SessionManager::instance()->deleteProfile(key); + else + { + SessionManager::instance()->setFavorite(key,true); + } } void ManageProfilesDialog::editSelected() { @@ -268,6 +276,21 @@ QString ManageProfilesDialog::selectedKey() const selectionModel()-> selectedIndexes().first().data( Qt::UserRole + 1 ).value(); } +void ManageProfilesDialog::updateFavoriteStatus(const QString& key , bool favorite) +{ + Q_ASSERT( _sessionModel ); + + const QModelIndex topIndex = _sessionModel->index(0,FavoriteStatusColumn); + + QModelIndexList list = _sessionModel->match( topIndex , ProfileKeyRole, + key ); + + foreach( QModelIndex index , list ) + { + const KIcon icon = favorite ? KIcon("favorites") : KIcon(); + _sessionModel->setData(index,icon,Qt::DecorationRole); + } +} ProfileItemDelegate::ProfileItemDelegate(QObject* parent) : QItemDelegate(parent) @@ -278,16 +301,11 @@ bool ProfileItemDelegate::editorEvent(QEvent* event,QAbstractItemModel* model, { if ( event->type() == QEvent::MouseButtonPress || event->type() == QEvent::KeyPress ) { - const QString& key = index.data(Qt::UserRole + 1).value(); + const QString& key = index.data(ManageProfilesDialog::ProfileKeyRole).value(); const bool isFavorite = !SessionManager::instance()->findFavorites().contains(key); SessionManager::instance()->setFavorite(key, isFavorite); - - if ( isFavorite ) - model->setData(index,KIcon("favorites"),Qt::DecorationRole); - else - model->setData(index,KIcon(),Qt::DecorationRole); } return true; diff --git a/src/ManageProfilesDialog.h b/src/ManageProfilesDialog.h index c34737a5a..5e26769df 100644 --- a/src/ManageProfilesDialog.h +++ b/src/ManageProfilesDialog.h @@ -48,11 +48,14 @@ class ManageProfilesDialog : public KDialog { Q_OBJECT +friend class ProfileItemDelegate; + public: /** Constructs a new profile type with the specified parent. */ ManageProfilesDialog(QWidget* parent = 0); virtual ~ManageProfilesDialog(); + protected: virtual void showEvent(QShowEvent* event); @@ -72,6 +75,8 @@ private slots: // session manager void updateTableModel(); + void updateFavoriteStatus(const QString& key , bool favorite); + private: QString selectedKey() const; // return the key associated with the currently selected // item in the profile table @@ -80,6 +85,10 @@ private: // their default / non-default profile status Ui::ManageProfilesDialog* _ui; QStandardItemModel* _sessionModel; + + static const int FavoriteStatusColumn = 1; + static const int ProfileKeyRole = Qt::UserRole + 1; + static const int ShortcutRole = Qt::UserRole + 1; }; class ProfileItemDelegate : public QItemDelegate diff --git a/src/ProcessInfo.cpp b/src/ProcessInfo.cpp index a854573d4..f93f1488b 100644 --- a/src/ProcessInfo.cpp +++ b/src/ProcessInfo.cpp @@ -65,6 +65,8 @@ QString ProcessInfo::format(const QString& input) const // search for and replace known markers output.replace("%u","NOT IMPLEMENTED YET"); output.replace("%n",name(&ok)); + output.replace("%c",formatCommand(name(&ok),arguments(&ok),ShortCommandFormat)); + output.replace("%C",formatCommand(name(&ok),arguments(&ok),LongCommandFormat)); output.replace("%D",currentDir(&ok)); output.replace("%d",formatShortDir(currentDir(&ok))); @@ -80,6 +82,13 @@ const char* ProcessInfo::DefaultCommonDirNames[] = "share" , "examples" , "icons" , "pics" , "plugins" , 0 }; +QString ProcessInfo::formatCommand(const QString& name, + const QVector& arguments, + CommandFormat format) const +{ + // TODO Implement me + return QStringList(QList::fromVector(arguments)).join(" "); +} QString ProcessInfo::formatShortDir(const QString& input) const { QString result; diff --git a/src/ProcessInfo.h b/src/ProcessInfo.h index a81b5dc8b..d7146ff3a 100644 --- a/src/ProcessInfo.h +++ b/src/ProcessInfo.h @@ -237,6 +237,15 @@ private: // space-constrained UI elements (eg. tabs) QString formatShortDir(const QString& dirPath) const; + enum CommandFormat + { + ShortCommandFormat, + LongCommandFormat + }; + // takes a process name and its arguments and produces formatted output + QString formatCommand(const QString& name , const QVector& arguments , + CommandFormat format) const; + // valid bits for _fields variable, ensure that // _fields is changed to an int if more than 8 fields are added enum FIELD_BITS diff --git a/src/ProfileList.cpp b/src/ProfileList.cpp index 5749f1011..e0cd1447e 100644 --- a/src/ProfileList.cpp +++ b/src/ProfileList.cpp @@ -27,6 +27,7 @@ // KDE #include +#include // Konsole #include "SessionManager.h" @@ -36,11 +37,17 @@ using namespace Konsole; ProfileList::ProfileList(bool addShortcuts , QObject* parent) : QObject(parent) , _addShortcuts(addShortcuts) + , _emptyListAction(0) { SessionManager* manager = SessionManager::instance(); // construct the list of favorite session types _group = new QActionGroup(this); + + // disabled action to be shown only when the list is empty + _emptyListAction = new QAction(i18n("No profiles available"),_group); + _emptyListAction->setEnabled(false); + QList list = manager->findFavorites().toList(); qSort(list); @@ -54,13 +61,25 @@ ProfileList::ProfileList(bool addShortcuts , QObject* parent) connect( _group , SIGNAL(triggered(QAction*)) , this , SLOT(triggered(QAction*)) ); + // listen for future changes to the session list connect( manager , SIGNAL(favoriteStatusChanged(const QString&,bool)) , this , SLOT(favoriteChanged(const QString&,bool)) ); connect( manager , SIGNAL(profileChanged(const QString&)) , this , SLOT(profileChanged(const QString&)) ); } +void ProfileList::updateEmptyAction() +{ + Q_ASSERT( _group ); + Q_ASSERT( _emptyListAction ); + // show empty list action when it is the only action + // in the group + const bool showEmptyAction = _group->actions().count() == 1; + + if ( showEmptyAction != _emptyListAction->isVisible() ) + _emptyListAction->setVisible(showEmptyAction); +} QAction* ProfileList::actionForKey(const QString& key) const { QListIterator iter(_group->actions()); @@ -119,6 +138,8 @@ void ProfileList::favoriteChanged(const QString& key,bool isFavorite) emit actionsChanged(_group->actions()); } } + + updateEmptyAction(); } void ProfileList::triggered(QAction* action) diff --git a/src/ProfileList.h b/src/ProfileList.h index 9ba15d224..f1cd80594 100644 --- a/src/ProfileList.h +++ b/src/ProfileList.h @@ -84,9 +84,13 @@ private slots: private: QAction* actionForKey(const QString& key) const; void updateAction(QAction* action , Profile* profile); + void updateEmptyAction(); QActionGroup* _group; bool _addShortcuts; + + // action to show when the list is empty + QAction* _emptyListAction; }; } diff --git a/src/TerminalDisplay.cpp b/src/TerminalDisplay.cpp index f5613e206..f9d213d0f 100644 --- a/src/TerminalDisplay.cpp +++ b/src/TerminalDisplay.cpp @@ -1470,8 +1470,8 @@ void TerminalDisplay::setScroll(int cursor, int slines) // // setting the range or value of a _scrollBar will always trigger // a repaint, so it should be avoided if it is not necessary - if ( _scrollBar->minimum() == 0 && - _scrollBar->maximum() == slines && + if ( _scrollBar->minimum() == 0 && + _scrollBar->maximum() == (slines - _lines) && _scrollBar->value() == cursor ) { //qDebug() << "no change in _scrollBar - skipping update";