diff --git a/desktop/sessionui.rc b/desktop/sessionui.rc index f948044e5..39bf9cc26 100644 --- a/desktop/sessionui.rc +++ b/desktop/sessionui.rc @@ -11,7 +11,7 @@ - + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cc174118f..49e28ed94 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -29,6 +29,7 @@ set(konsole_KDEINIT_SRCS BookmarkHandler.cpp ColorScheme.cpp ColorSchemeEditor.cpp + CopyInputDialog.cpp EditProfileDialog.cpp Emulation.cpp Filter.cpp @@ -69,6 +70,7 @@ set(konsole_KDEINIT_SRCS kde4_add_ui_files(konsole_KDEINIT_SRCS ColorSchemeEditor.ui + CopyInputDialog.ui EditProfileDialog.ui KeyBindingEditor.ui ManageProfilesDialog.ui @@ -110,6 +112,7 @@ set(konsolepart_PART_SRCS BookmarkHandler.cpp ColorScheme.cpp ColorSchemeEditor.cpp + CopyInputDialog.cpp EditProfileDialog.cpp Emulation.cpp Filter.cpp diff --git a/src/CopyInputDialog.cpp b/src/CopyInputDialog.cpp new file mode 100644 index 000000000..04c7396c4 --- /dev/null +++ b/src/CopyInputDialog.cpp @@ -0,0 +1,194 @@ +/* + Copyright 2008 by Robert Knight + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. +*/ + +// Own +#include "CopyInputDialog.h" + +// Qt +#include +#include + +// Konsole +#include "ui_CopyInputDialog.h" + +using namespace Konsole; + +CopyInputDialog::CopyInputDialog(QWidget* parent) +: KDialog(parent) +{ + setCaption(i18n("Copy Input")); + setButtons( KDialog::Ok | KDialog::Cancel ); + + _ui = new Ui::CopyInputDialog(); + _ui->setupUi(mainWidget()); + + connect(_ui->selectAllButton,SIGNAL(clicked()),this,SLOT(selectAll())); + connect(_ui->deselectAllButton,SIGNAL(clicked()),this,SLOT(deselectAll())); + + _ui->filterEdit->setClearButtonShown(true); + _ui->filterEdit->setFocus(); + + _model = new CheckableSessionModel(parent); + _model->setCheckColumn(1); + _model->setSessions(SessionManager::instance()->sessions()); + + QSortFilterProxyModel* filterProxyModel = new QSortFilterProxyModel(this); + filterProxyModel->setDynamicSortFilter(true); + filterProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); + filterProxyModel->setSourceModel(_model); + filterProxyModel->setFilterKeyColumn(-1); + + connect(_ui->filterEdit,SIGNAL(textChanged(QString)),filterProxyModel, + SLOT(setFilterFixedString(QString))); + + _ui->sessionList->setModel(filterProxyModel); + _ui->sessionList->setColumnHidden(0,true); // Hide number column + _ui->sessionList->header()->hide(); +} +void CopyInputDialog::setChosenSessions(const QSet& sessions) +{ + QSet checked = sessions; + if (_masterSession) + checked.insert(_masterSession); + + _model->setCheckedSessions(checked); +} +QSet CopyInputDialog::chosenSessions() const +{ + return _model->checkedSessions(); +} +void CopyInputDialog::setMasterSession(Session* session) +{ + if (_masterSession) + _model->setCheckable(_masterSession,true); + + _model->setCheckable(session,false); + QSet checked = _model->checkedSessions(); + checked.insert(session); + _model->setCheckedSessions(checked); + + _masterSession = session; +} +void CopyInputDialog::setSelectionChecked(bool checked) +{ + QAbstractItemModel* model = _ui->sessionList->model(); + int rows = model->rowCount(); + + QModelIndexList selected = _ui->sessionList->selectionModel()->selectedIndexes(); + + if (selected.count() > 1) + { + foreach(QModelIndex index,selected) + setRowChecked(index.row(),checked); + } + else + { + for (int i=0;isessionList->model(); + QModelIndex index = model->index(row,0); + if (checked) + model->setData(index,(int)Qt::Checked,Qt::CheckStateRole); + else + model->setData(index,(int)Qt::Unchecked,Qt::CheckStateRole); +} +CheckableSessionModel::CheckableSessionModel(QObject* parent) +: SessionListModel(parent) +, _checkColumn(0) +{ +} +void CheckableSessionModel::setCheckColumn(int column) +{ + _checkColumn = column; + reset(); +} +Qt::ItemFlags CheckableSessionModel::flags(const QModelIndex& index) const +{ + Session* session = (Session*)index.internalPointer(); + + if (_fixedSessions.contains(session)) + return SessionListModel::flags(index) & ~Qt::ItemIsEnabled; + else + return SessionListModel::flags(index) | Qt::ItemIsUserCheckable; +} +QVariant CheckableSessionModel::data(const QModelIndex& index, int role) const +{ + if (role == Qt::CheckStateRole && index.column() == _checkColumn) + { + Session* session = (Session*)index.internalPointer(); + + if (_checkedSessions.contains(session)) + return QVariant::fromValue((int)Qt::Checked); + else + return QVariant::fromValue((int)Qt::Unchecked); + } + else + return SessionListModel::data(index,role); +} +bool CheckableSessionModel::setData(const QModelIndex& index, const QVariant& value, int role) +{ + if (role == Qt::CheckStateRole && index.column() == _checkColumn) + { + Session* session = (Session*)index.internalPointer(); + + if (_fixedSessions.contains(session)) + return false; + + if (value.value() == Qt::Checked) + _checkedSessions.insert(session); + else + _checkedSessions.remove(session); + + emit dataChanged(index,index); + return true; + } + else + return SessionListModel::setData(index,value,role); +} +void CheckableSessionModel::setCheckedSessions(const QSet sessions) +{ + _checkedSessions = sessions; + reset(); +} +QSet CheckableSessionModel::checkedSessions() const +{ + return _checkedSessions; +} +void CheckableSessionModel::setCheckable(Session* session, bool checkable) +{ + if (!checkable) + _fixedSessions.insert(session); + else + _fixedSessions.remove(session); + + reset(); +} +void CheckableSessionModel::sessionRemoved(Session* session) +{ + _checkedSessions.remove(session); + _fixedSessions.remove(session); +} + + + + diff --git a/src/CopyInputDialog.h b/src/CopyInputDialog.h new file mode 100644 index 000000000..512d64e3d --- /dev/null +++ b/src/CopyInputDialog.h @@ -0,0 +1,98 @@ +/* + Copyright 2008 by Robert Knight + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. +*/ + +#ifndef COPYINPUTDIALOG +#define COPYINPUTDIALOG + +// Qt +#include + +// KDE +#include + +// Konsole +#include "SessionManager.h" +#include "Session.h" + +namespace Ui +{ + class CopyInputDialog; +} + +namespace Konsole +{ +class CheckableSessionModel; + +class CopyInputDialog : public KDialog +{ +Q_OBJECT + +public: + CopyInputDialog(QWidget* parent = 0); + + void setMasterSession(Session* master); + Session* masterSession() const; + + void setChosenSessions(const QSet& sessions); + QSet chosenSessions() const; + +private slots: + void selectAll() { setSelectionChecked(true); }; + void deselectAll() { setSelectionChecked(false); }; + +private: + void setSelectionChecked(bool checked); + void setRowChecked(int row, bool checked); + + Ui::CopyInputDialog* _ui; + CheckableSessionModel* _model; + QPointer _masterSession; +}; + +class CheckableSessionModel : public SessionListModel +{ +Q_OBJECT + +public: + CheckableSessionModel(QObject* parent); + + void setCheckColumn(int column); + + void setCheckable(Session* session, bool checkable); + + void setCheckedSessions(const QSet sessions); + QSet checkedSessions() const; + + virtual Qt::ItemFlags flags(const QModelIndex& index) const; + virtual QVariant data(const QModelIndex& index, int role) const; + virtual bool setData(const QModelIndex& index, const QVariant& value, int role); + +protected: + virtual void sessionRemoved(Session*); + +private: + QSet _checkedSessions; + QSet _fixedSessions; + int _checkColumn; +}; + +} + +#endif // COPYINPUTDIALOG + diff --git a/src/CopyInputDialog.ui b/src/CopyInputDialog.ui new file mode 100644 index 000000000..1d87c5f9c --- /dev/null +++ b/src/CopyInputDialog.ui @@ -0,0 +1,85 @@ + + CopyInputDialog + + + + 0 + 0 + 363 + 223 + + + + Form + + + + + + + + Filter: + + + + + + + + + + + + QAbstractItemView::ExtendedSelection + + + false + + + true + + + + + + + + + Select All + + + + + + + Deselect All + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + KLineEdit + QLineEdit +
klineedit.h
+
+
+ + +
diff --git a/src/Session.cpp b/src/Session.cpp index 394d20326..ce916c101 100644 --- a/src/Session.cpp +++ b/src/Session.cpp @@ -952,8 +952,8 @@ int Session::processId() const return _shellProcess->pid(); } -SessionGroup::SessionGroup() - : _masterMode(0) +SessionGroup::SessionGroup(QObject* parent) + : QObject(parent), _masterMode(0) { } SessionGroup::~SessionGroup() @@ -967,6 +967,8 @@ bool SessionGroup::masterStatus(Session* session) const { return _sessions[sessi void SessionGroup::addSession(Session* session) { + connect(session,SIGNAL(finished()),this,SLOT(sessionFinished())); + _sessions.insert(session,false); QListIterator masterIter(masters()); @@ -976,6 +978,8 @@ void SessionGroup::addSession(Session* session) } void SessionGroup::removeSession(Session* session) { + disconnect(session,SIGNAL(finished()),this,SLOT(sessionFinished())); + setMasterStatus(session,false); QListIterator masterIter(masters()); @@ -985,6 +989,12 @@ void SessionGroup::removeSession(Session* session) _sessions.remove(session); } +void SessionGroup::sessionFinished() +{ + Session* session = qobject_cast(sender()); + Q_ASSERT(session); + removeSession(session); +} void SessionGroup::setMasterMode(int mode) { _masterMode = mode; @@ -1044,11 +1054,9 @@ void SessionGroup::setMasterStatus(Session* session , bool master) } void SessionGroup::connectPair(Session* master , Session* other) { - kDebug() << k_funcinfo; - if ( _masterMode & CopyInputToAll ) { - kDebug() << "Connection session " << master->nameTitle() << "to" << other->nameTitle(); +// kDebug() << "Connection session " << master->nameTitle() << "to" << other->nameTitle(); connect( master->emulation() , SIGNAL(sendData(const char*,int)) , other->emulation() , SLOT(sendString(const char*,int)) ); @@ -1056,11 +1064,9 @@ void SessionGroup::connectPair(Session* master , Session* other) } void SessionGroup::disconnectPair(Session* master , Session* other) { - kDebug() << k_funcinfo; - if ( _masterMode & CopyInputToAll ) { - kDebug() << "Disconnecting session " << master->nameTitle() << "from" << other->nameTitle(); +// kDebug() << "Disconnecting session " << master->nameTitle() << "from" << other->nameTitle(); disconnect( master->emulation() , SIGNAL(sendData(const char*,int)) , other->emulation() , SLOT(sendString(const char*,int)) ); diff --git a/src/Session.h b/src/Session.h index 9bf1a21d1..d4a1ca568 100644 --- a/src/Session.h +++ b/src/Session.h @@ -567,7 +567,7 @@ Q_OBJECT public: /** Constructs an empty session group. */ - SessionGroup(); + SessionGroup(QObject* parent); /** Destroys the session group and removes all connections between master and slave sessions. */ ~SessionGroup(); @@ -617,6 +617,9 @@ public: */ int masterMode() const; +private slots: + void sessionFinished(); + private: void connectPair(Session* master , Session* other); void disconnectPair(Session* master , Session* other); diff --git a/src/SessionController.cpp b/src/SessionController.cpp index b16aceece..18c0ac509 100644 --- a/src/SessionController.cpp +++ b/src/SessionController.cpp @@ -43,6 +43,7 @@ // Konsole #include "EditProfileDialog.h" +#include "CopyInputDialog.h" #include "Emulation.h" #include "Filter.h" #include "History.h" @@ -73,6 +74,7 @@ SessionController::SessionController(Session* session , TerminalDisplay* view, Q , KXMLGUIClient() , _session(session) , _view(view) + , _copyToGroup(0) , _profileList(0) , _previousState(-1) , _viewUrlFilter(0) @@ -479,14 +481,10 @@ void SessionController::setupActions() action->setShortcut( QKeySequence(Qt::CTRL+Qt::ALT+Qt::Key_S) ); connect( action , SIGNAL(triggered()) , this , SLOT(renameSession()) ); - // Send to All - - //TODO - Complete the implementation of 'Send Input to All' for - // a future KDE 4 release - // - //toggleAction = new KToggleAction(i18n("Send Input to All"),this); - //action = collection->addAction("send-input-to-all",toggleAction); - //connect( action , SIGNAL(toggled(bool)) , this , SIGNAL(sendInputToAll(bool)) ); + // Copy Input To + action = collection->addAction("copy-input-to"); + action->setText(i18n("Copy Input To...")); + connect( action , SIGNAL(triggered()) , this , SLOT(copyInputTo()) ); // Clear and Clear+Reset action = collection->addAction("clear"); @@ -657,12 +655,16 @@ void SessionController::editCurrentProfile() } void SessionController::renameSession() { + QPointer guard(_session); bool ok = false; const QString& text = KInputDialog::getText( i18n("Rename Tab") , i18n("Enter new tab text:") , _session->tabTitleFormat(Session::LocalTabTitle) , &ok, QApplication::activeWindow() ); - if ( ok ) + if (!guard) + return; + + if ( ok ) { // renaming changes both the local and remote tab title formats, to save confusion over // the tab title not changing if renaming the tab whilst the remote tab title format is @@ -711,6 +713,46 @@ void SessionController::pasteSelection() { _view->pasteSelection(); } +void SessionController::copyInputTo() +{ + if (!_copyToGroup) + { + _copyToGroup = new SessionGroup(this); + _copyToGroup->addSession(_session); + _copyToGroup->setMasterStatus(_session,true); + _copyToGroup->setMasterMode(SessionGroup::CopyInputToAll); + } + + CopyInputDialog* dialog = new CopyInputDialog(_view); + dialog->setMasterSession(_session); + + QSet currentGroup = QSet::fromList(_copyToGroup->sessions()); + currentGroup.remove(_session); + + dialog->setChosenSessions(currentGroup); + + QPointer guard(_session); + int result = dialog->exec(); + if (!guard) + return; + + if (result) + { + QSet newGroup = dialog->chosenSessions(); + newGroup.remove(_session); + + QSet completeGroup = newGroup | currentGroup; + foreach(Session* session, completeGroup) + { + if (newGroup.contains(session) && !currentGroup.contains(session)) + _copyToGroup->addSession(session); + else if (!newGroup.contains(session) && currentGroup.contains(session)) + _copyToGroup->removeSession(session); + } + } + + delete dialog; +} void SessionController::clear() { Emulation* emulation = _session->emulation(); diff --git a/src/SessionController.h b/src/SessionController.h index 48263ea48..4eaf35389 100644 --- a/src/SessionController.h +++ b/src/SessionController.h @@ -54,6 +54,7 @@ namespace Konsole { class Session; +class SessionGroup; class ScreenWindow; class TerminalDisplay; class IncrementalSearchBar; @@ -140,12 +141,6 @@ signals: */ void focused( SessionController* controller ); - /** - * Emitted when the user enables the "Send Input to All" menu - * item associated with this session. - */ - void sendInputToAll(bool sendToAll); - public slots: /** * Issues a command to the session to navigate to the specified URL. @@ -166,6 +161,7 @@ private slots: void pasteSelection(); // shortcut only void clear(); void clearAndReset(); + void copyInputTo(); void editCurrentProfile(); void changeCodec(QTextCodec* codec); //void searchHistory(); @@ -233,6 +229,7 @@ private: QPointer _session; QPointer _view; + SessionGroup* _copyToGroup; ProfileList* _profileList; diff --git a/src/SessionManager.cpp b/src/SessionManager.cpp index 71e20c9a9..561f0658c 100644 --- a/src/SessionManager.cpp +++ b/src/SessionManager.cpp @@ -32,6 +32,7 @@ // KDE #include +#include #include #include #include @@ -693,12 +694,106 @@ QKeySequence SessionManager::shortcut(Profile::Ptr info) const return QKeySequence(); } - K_GLOBAL_STATIC( SessionManager , theSessionManager ) SessionManager* SessionManager::instance() { return theSessionManager; } +SessionListModel::SessionListModel(QObject* parent) +: QAbstractListModel(parent) +{ +} + +void SessionListModel::setSessions(const QList& sessions) +{ + _sessions = sessions; + + foreach(Session* session, sessions) + connect(session,SIGNAL(finished()),this,SLOT(sessionFinished())); + + reset(); +} +QVariant SessionListModel::data(const QModelIndex& index, int role) const +{ + Q_ASSERT(index.isValid()); + + int row = index.row(); + int column = index.column(); + + Q_ASSERT( row >= 0 && row < _sessions.count() ); + Q_ASSERT( column >= 0 && column < 2 ); + + switch (role) + { + case Qt::DisplayRole: + if (column == 1) + return _sessions[row]->title(Session::DisplayedTitleRole); + else if (column == 0) + return _sessions[row]->sessionId(); + break; + case Qt::DecorationRole: + if (column == 1) + return KIcon(_sessions[row]->iconName()); + else + return QVariant(); + } + + return QVariant(); +} +QVariant SessionListModel::headerData(int section, Qt::Orientation orientation, + int role) const +{ + if (role != Qt::DisplayRole) + return QVariant(); + + if (orientation == Qt::Vertical) + return QVariant(); + else + { + switch (section) + { + case 0: + return i18n("Number"); + case 1: + return i18n("Title"); + default: + return QVariant(); + } + } +} + +int SessionListModel::columnCount(const QModelIndex& parent) const +{ + return 2; +} +int SessionListModel::rowCount(const QModelIndex& parent) const +{ + return _sessions.count(); +} +QModelIndex SessionListModel::parent(const QModelIndex& index) const +{ + return QModelIndex(); +} +void SessionListModel::sessionFinished() +{ + Session* session = qobject_cast(sender()); + int row = _sessions.indexOf(session); + + if (row != -1) + { + beginRemoveRows(QModelIndex(),row,row); + sessionRemoved(session); + _sessions.removeAt(row); + endRemoveRows(); + } +} +QModelIndex SessionListModel::index(int row, int column, const QModelIndex& parent) const +{ + if (hasIndex(row,column,parent)) + return createIndex(row,column,_sessions[row]); + else + return QModelIndex(); +} #include "SessionManager.moc" diff --git a/src/SessionManager.h b/src/SessionManager.h index b7bbde564..5ede14eab 100644 --- a/src/SessionManager.h +++ b/src/SessionManager.h @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -367,5 +368,33 @@ private: int _count; }; +class SessionListModel : public QAbstractListModel +{ +Q_OBJECT + +public: + SessionListModel(QObject* parent = 0); + + void setSessions(const QList& sessions); + + virtual QModelIndex index(int row, int column, const QModelIndex& parent) const; + virtual QVariant data(const QModelIndex& index, int role) const; + virtual QVariant headerData(int section, Qt::Orientation orientation, + int role) const; + virtual int columnCount(const QModelIndex& parent) const; + virtual int rowCount(const QModelIndex& parent) const; + virtual QModelIndex parent(const QModelIndex& index) const; + +protected: + virtual void sessionRemoved(Session*) {} + +private slots: + void sessionFinished(); + +private: + QList _sessions; +}; + } #endif //SESSIONMANAGER_H + diff --git a/src/ViewManager.cpp b/src/ViewManager.cpp index 463892d04..9753cb63e 100644 --- a/src/ViewManager.cpp +++ b/src/ViewManager.cpp @@ -466,7 +466,6 @@ SessionController* ViewManager::createController(Session* session , TerminalDisp connect( controller , SIGNAL(focused(SessionController*)) , this , SLOT(controllerChanged(SessionController*)) ); connect( session , SIGNAL(destroyed()) , controller , SLOT(deleteLater()) ); connect( view , SIGNAL(destroyed()) , controller , SLOT(deleteLater()) ); - connect( controller , SIGNAL(sendInputToAll(bool)) , this , SLOT(sendInputToAll()) ); // if this is the first controller created then set it as the active controller if (!_pluggedController) @@ -789,22 +788,6 @@ QList ViewManager::viewProperties() const return list; } -void ViewManager::sendInputToAll() -{ - SessionGroup* group = new SessionGroup(); - group->setMasterMode( SessionGroup::CopyInputToAll ); - - Session* activeSession = _sessionMap[qobject_cast(activeView())]; - if ( activeSession != 0 ) - { - QListIterator iter( SessionManager::instance()->sessions() ); - while ( iter.hasNext() ) - group->addSession(iter.next()); - - group->setMasterStatus(activeSession,true); - } -} - uint qHash(QPointer display) { return qHash((TerminalDisplay*)display); diff --git a/src/ViewManager.h b/src/ViewManager.h index 12c87caea..bd7259dc0 100644 --- a/src/ViewManager.h +++ b/src/ViewManager.h @@ -233,9 +233,6 @@ private slots: void updateViewsForSession(Session* session); - // sends input from active view to all sessions - void sendInputToAll(); - // moves active view to the left void moveActiveViewLeft(); // moves active view to the right