diff --git a/kdevplatform/shell/sessionchooserdialog.cpp b/kdevplatform/shell/sessionchooserdialog.cpp index 006f4b373e..8a0ffe5f82 100644 --- a/kdevplatform/shell/sessionchooserdialog.cpp +++ b/kdevplatform/shell/sessionchooserdialog.cpp @@ -1,228 +1,230 @@ /* This file is part of KDevelop Copyright 2008 Andreas Pakulat Copyright 2010 David Nolden This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "sessionchooserdialog.h" #include "sessioncontroller.h" #include "core.h" #include #include #include #include #include #include #include #include using namespace KDevelop; SessionChooserDialog::SessionChooserDialog(QListView* view, QAbstractItemModel* model, QLineEdit* filter) : m_view(view), m_model(model), m_filter(filter), m_deleteCandidateRow(-1) { m_updateStateTimer.setInterval(5000); m_updateStateTimer.setSingleShot(false); m_updateStateTimer.start(); connect(&m_updateStateTimer, &QTimer::timeout, this, &SessionChooserDialog::updateState); connect(view, &QListView::doubleClicked, this, &SessionChooserDialog::doubleClicked); connect(view, &QListView::entered, this, &SessionChooserDialog::itemEntered); m_deleteButton = new QPushButton(view->viewport()); m_deleteButton->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete"))); m_deleteButton->setToolTip(i18nc("@info", "Delete session")); m_deleteButton->hide(); connect(m_deleteButton, &QPushButton::clicked, this, &SessionChooserDialog::deleteButtonPressed); m_deleteButtonTimer.setInterval(500); m_deleteButtonTimer.setSingleShot(true); connect(&m_deleteButtonTimer, &QTimer::timeout, this, &SessionChooserDialog::showDeleteButton); view->setMouseTracking(true); view->installEventFilter(this); filter->installEventFilter(this); connect(filter, &QLineEdit::textChanged, this, &SessionChooserDialog::filterTextChanged); setWindowTitle(i18n("Pick a Session")); m_buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Close); auto mainLayout = new QVBoxLayout(this); m_mainWidget = new QWidget(this); mainLayout->addWidget(m_mainWidget); QPushButton *okButton = m_buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::Key_Return); connect(m_buttonBox, &QDialogButtonBox::accepted, this, &SessionChooserDialog::accept); connect(m_buttonBox, &QDialogButtonBox::rejected, this, &SessionChooserDialog::reject); mainLayout->addWidget(m_buttonBox); okButton->setText(i18n("Run")); okButton->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start"))); } void SessionChooserDialog::filterTextChanged() { m_view->selectionModel()->setCurrentIndex(m_model->index(0, 0), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); bool enabled = m_view->model()->rowCount(QModelIndex())>0; m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(enabled); m_deleteButton->setVisible(false); } void SessionChooserDialog::doubleClicked(const QModelIndex& index) { if(m_model->flags(index) & Qt::ItemIsEnabled) accept(); } void SessionChooserDialog::updateState() { // Sometimes locking may take some time, so we stop the timer, to prevent an 'avalanche' of events m_updateStateTimer.stop(); for(int row = 0; row < m_model->rowCount(); ++row) { QString session = m_model->index(row, 0).data().toString(); if(session.isEmpty()) //create new session continue; QString state, tooltip; SessionRunInfo info = SessionController::sessionRunInfo(session); if(info.isRunning) { tooltip = i18n("Active session.\npid %1, app %2, host %3", info.holderPid, info.holderApp, info.holderHostname); state = i18n("Running"); } m_model->setData(m_model->index(row, 1), !info.isRunning ? QIcon() : QIcon::fromTheme(QStringLiteral("media-playback-start")), Qt::DecorationRole); m_model->setData(m_model->index(row, 1), tooltip, Qt::ToolTipRole); m_model->setData(m_model->index(row, 2), state, Qt::DisplayRole); } m_updateStateTimer.start(); } void SessionChooserDialog::itemEntered(const QModelIndex& index) { // The last row says "Create new session", we don't want to delete that if(index.row() == m_model->rowCount()-1) { m_deleteButton->hide(); m_deleteButtonTimer.stop(); return; } // align the delete-button to stay on the right border of the item // we need the right most column's index QModelIndex in = m_model->index( index.row(), 1 ); const QRect rect = m_view->visualRect(in); m_deleteButton->resize(rect.height(), rect.height()); QPoint p(rect.right() - m_deleteButton->size().width(), rect.top()+rect.height()/2-m_deleteButton->height()/2); m_deleteButton->move(p); m_deleteCandidateRow = index.row(); m_deleteButtonTimer.start(); } void SessionChooserDialog::showDeleteButton() { m_deleteButton->show(); } bool SessionChooserDialog::eventFilter(QObject* object, QEvent* event) { if(object == m_view && event->type() == QEvent::Leave ) { m_deleteButtonTimer.stop(); m_deleteButton->hide(); // don't eat the event, pass on } else if (object == m_filter && event->type() == QEvent::KeyPress) { auto *keyEvent = static_cast(event); if (keyEvent->key() == Qt::Key_Return) { accept(); // don't eat the event, pass on } else if (keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down) { QModelIndex currentIndex = m_view->selectionModel()->currentIndex(); int selectRow = -1; if (keyEvent->key() == Qt::Key_Up) { if(!currentIndex.isValid()) { selectRow = m_model->rowCount()-1; } else if(currentIndex.row()-1 >= 0) { selectRow = currentIndex.row()-1; } } else { if(!currentIndex.isValid()) { selectRow = 0; } else if(currentIndex.row()+1 < m_model->rowCount()) { selectRow = currentIndex.row()+1; } } if (selectRow != -1) { m_view->selectionModel()->setCurrentIndex(m_model->index(selectRow, 0), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); } return true; // eat event } } return QDialog::eventFilter(object, event); } QWidget* SessionChooserDialog::mainWidget() const { return m_mainWidget; } void SessionChooserDialog::deleteButtonPressed() { if(m_deleteCandidateRow == -1) return; - QModelIndex index = m_model->index(m_deleteCandidateRow, 0); - const QString uuid = m_model->data(index, Qt::DisplayRole).toString(); + QModelIndex uuidIndex = m_model->index(m_deleteCandidateRow, 0); + QModelIndex sessionNameIndex = m_model->index(m_deleteCandidateRow, 3); + const QString uuid = m_model->data(uuidIndex, Qt::DisplayRole).toString(); + const QString sessionName = m_model->data(sessionNameIndex, Qt::DisplayRole).toString(); TryLockSessionResult result = SessionController::tryLockSession( uuid ); if( !result.lock ) { const QString errCaption = i18nc("@title", "Cannot Delete Session"); QString errText = i18nc("@info", "

Cannot delete a locked session."); if( result.runInfo.holderPid != -1 ) { - errText += i18nc("@info", "

The session is locked by %1 on %2 (PID %3).", - result.runInfo.holderApp, result.runInfo.holderHostname, result.runInfo.holderPid); + errText += i18nc("@info", "

The session %1 is locked by %2 on %3 (PID %4).", + sessionName, result.runInfo.holderApp, result.runInfo.holderHostname, result.runInfo.holderPid); } KMessageBox::error( this, errText, errCaption ); return; } - const QString text = i18nc("@info", "The session and all contained settings will be deleted. The projects will stay unaffected. Do you really want to continue?"); + const QString text = i18nc("@info", "The session %1 and all contained settings will be deleted. The projects will stay unaffected. Do you really want to continue?", sessionName); const QString caption = i18nc("@title", "Delete Session"); const KGuiItem deleteItem = KStandardGuiItem::del(); const KGuiItem cancelItem = KStandardGuiItem::cancel(); if(KMessageBox::warningYesNo(this, text, caption, deleteItem, cancelItem) == KMessageBox::Yes) { SessionController::deleteSessionFromDisk(result.lock); m_model->removeRows( m_deleteCandidateRow, 1 ); m_deleteCandidateRow = -1; } } diff --git a/kdevplatform/shell/sessioncontroller.cpp b/kdevplatform/shell/sessioncontroller.cpp index 84bd07df6f..d3e7ef5f98 100644 --- a/kdevplatform/shell/sessioncontroller.cpp +++ b/kdevplatform/shell/sessioncontroller.cpp @@ -1,697 +1,699 @@ /* This file is part of KDevelop Copyright 2008 Andreas Pakulat Copyright 2010 David Nolden This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "sessioncontroller.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "session.h" #include "core.h" #include "uicontroller.h" #include "shellextension.h" #include "sessionlock.h" #include "sessionchooserdialog.h" #include "debug.h" #include #include #include namespace KDevelop { namespace { int argc = 0; char** argv = nullptr; } void SessionController::setArguments(int _argc, char** _argv) { argc = _argc; argv = _argv; } static QStringList standardArguments() { QStringList ret; for(int a = 0; a < argc; ++a) { QString arg = QString::fromLocal8Bit(argv[a]); if(arg.startsWith(QLatin1String("-graphicssystem")) || arg.startsWith(QLatin1String("-style"))) { ret << QLatin1Char('-') + arg; if(a+1 < argc) ret << QString::fromLocal8Bit(argv[a+1]); } } return ret; } class SessionControllerPrivate : public QObject { Q_OBJECT public: explicit SessionControllerPrivate( SessionController* s ) : q(s) , activeSession(nullptr) , grp(nullptr) { } ~SessionControllerPrivate() override { } Session* findSessionForName( const QString& name ) const { for (auto it = sessionActions.begin(), end = sessionActions.end(); it != end; ++it) { Session* s = it.key(); if( s->name() == name ) return s; } return nullptr; } Session* findSessionForId(const QString& idString) const { QUuid id(idString); for (auto it = sessionActions.begin(), end = sessionActions.end(); it != end; ++it) { Session* s = it.key(); if( s->id() == id) return s; } return nullptr; } void newSession() { qsrand(QDateTime::currentDateTimeUtc().toTime_t()); Session* session = new Session( QUuid::createUuid().toString() ); KProcess::startDetached(ShellExtension::getInstance()->executableFilePath(), QStringList() << QStringLiteral("-s") << session->id().toString() << standardArguments()); delete session; #if 0 //Terminate this instance of kdevelop if the user agrees const auto windows = Core::self()->uiController()->controller()->mainWindows(); for (Sublime::MainWindow* window : windows) { window->close(); } #endif } void deleteCurrentSession() { int choice = KMessageBox::warningContinueCancel(Core::self()->uiController()->activeMainWindow(), i18n("The current session and all contained settings will be deleted. The projects will stay unaffected. Do you really want to continue?")); if(choice == KMessageBox::Continue) { q->deleteSessionFromDisk(sessionLock); q->emitQuitSession(); } } void renameSession() { bool ok; auto newSessionName = QInputDialog::getText(Core::self()->uiController()->activeMainWindow(), i18n("Rename Session"), i18n("New Session Name:"), QLineEdit::Normal, q->activeSession()->name(), &ok); if (ok) { static_cast(q->activeSession())->setName(newSessionName); } q->updateXmlGuiActionList(); // resort } bool loadSessionExternally( Session* s ) { Q_ASSERT( s ); KProcess::startDetached(ShellExtension::getInstance()->executableFilePath(), QStringList() << QStringLiteral("-s") << s->id().toString() << standardArguments()); return true; } TryLockSessionResult activateSession( Session* s ) { Q_ASSERT( s ); activeSession = s; TryLockSessionResult result = SessionController::tryLockSession( s->id().toString()); if( !result.lock ) { activeSession = nullptr; return result; } Q_ASSERT(s->id().toString() == result.lock->id()); sessionLock = result.lock; KConfigGroup grp = KSharedConfig::openConfig()->group( SessionController::cfgSessionGroup() ); grp.writeEntry( SessionController::cfgActiveSessionEntry(), s->id().toString() ); grp.sync(); if (Core::self()->setupFlags() & Core::NoUi) return result; QHash::iterator it = sessionActions.find(s); Q_ASSERT( it != sessionActions.end() ); (*it)->setCheckable(true); (*it)->setChecked(true); for(it = sessionActions.begin(); it != sessionActions.end(); ++it) { if(it.key() != s) (*it)->setCheckable(false); } return result; } void loadSessionFromAction(QAction* action) { auto session = action->data().value(); loadSessionExternally(session); } void addSession( Session* s ) { if (Core::self()->setupFlags() & Core::NoUi) { sessionActions[s] = nullptr; return; } auto* a = new QAction( grp ); a->setText( s->description() ); a->setCheckable( false ); a->setData(QVariant::fromValue(s)); sessionActions[s] = a; q->actionCollection()->addAction(QLatin1String("session_") + s->id().toString(), a); connect( s, &Session::sessionUpdated, this, &SessionControllerPrivate::sessionUpdated ); sessionUpdated( s ); } SessionController* const q; QHash sessionActions; ISession* activeSession; QActionGroup* grp; ISessionLock::Ptr sessionLock; static QString sessionBaseDirectory() { return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + qApp->applicationName() + QLatin1String("/sessions/"); } QString ownSessionDirectory() const { Q_ASSERT(activeSession); return q->sessionDirectory( activeSession->id().toString() ); } private Q_SLOTS: void sessionUpdated( KDevelop::ISession* s ) { sessionActions[static_cast( s )]->setText( KStringHandler::rsqueeze(s->description()) ); } }; SessionController::SessionController( QObject *parent ) : QObject(parent) , d_ptr(new SessionControllerPrivate(this)) { Q_D(SessionController); setObjectName(QStringLiteral("SessionController")); setComponentName(QStringLiteral("kdevsession"), i18n("Session Manager")); setXMLFile(QStringLiteral("kdevsessionui.rc")); QDBusConnection::sessionBus().registerObject( QStringLiteral("/org/kdevelop/SessionController"), this, QDBusConnection::ExportScriptableSlots ); if (Core::self()->setupFlags() & Core::NoUi) return; QAction* action = actionCollection()->addAction(QStringLiteral("new_session")); connect(action, &QAction::triggered, this, [this] { Q_D(SessionController); d->newSession(); }); action->setText( i18nc("@action:inmenu", "Start New Session") ); action->setToolTip( i18nc("@info:tooltip", "Start a new KDevelop instance with an empty session") ); action->setIcon(QIcon::fromTheme(QStringLiteral("window-new"))); action = actionCollection()->addAction(QStringLiteral("rename_session")); connect(action, &QAction::triggered, this, [this] { Q_D(SessionController); d->renameSession(); }); action->setText( i18n("Rename Current Session...") ); action->setIcon(QIcon::fromTheme(QStringLiteral("edit-rename"))); action = actionCollection()->addAction(QStringLiteral("delete_session")); connect(action, &QAction::triggered, this, [this] { Q_D(SessionController); d->deleteCurrentSession(); }); action->setText( i18n("Delete Current Session...") ); action->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete"))); action = actionCollection()->addAction( QStringLiteral("quit"), this, SIGNAL(quitSession()) ); action->setText( i18n("Quit") ); action->setMenuRole( QAction::NoRole ); // OSX: prevent QT from hiding this due to conflict with 'Quit KDevelop...' actionCollection()->setDefaultShortcut( action, Qt::CTRL | Qt::Key_Q ); action->setIcon(QIcon::fromTheme(QStringLiteral("application-exit"))); d->grp = new QActionGroup( this ); connect(d->grp, &QActionGroup::triggered, this, [this] (QAction* a) { Q_D(SessionController); d->loadSessionFromAction(a); } ); } SessionController::~SessionController() = default; void SessionController::startNewSession() { Q_D(SessionController); d->newSession(); } void SessionController::cleanup() { Q_D(SessionController); if (d->activeSession) { Q_ASSERT(d->activeSession->id().toString() == d->sessionLock->id()); if (d->activeSession->isTemporary()) { deleteSessionFromDisk(d->sessionLock); } d->activeSession = nullptr; } d->sessionLock.clear(); qDeleteAll(d->sessionActions); d->sessionActions.clear(); } void SessionController::initialize( const QString& session ) { Q_D(SessionController); QDir sessiondir( SessionControllerPrivate::sessionBaseDirectory() ); const auto sessionDirs = sessiondir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot); for (const QString& s : sessionDirs) { QUuid id( s ); if( id.isNull() ) continue; // Only create sessions for directories that represent proper uuid's Session* ses = new Session( id.toString(), this ); //Delete sessions that have no name and are empty if( ses->containedProjects().isEmpty() && ses->name().isEmpty() && (session.isEmpty() || (ses->id().toString() != session && ses->name() != session)) ) { TryLockSessionResult result = tryLockSession(s); if (result.lock) { deleteSessionFromDisk(result.lock); } delete ses; } else { d->addSession( ses ); } } loadDefaultSession( session ); updateXmlGuiActionList(); } ISession* SessionController::activeSession() const { Q_D(const SessionController); return d->activeSession; } ISessionLock::Ptr SessionController::activeSessionLock() const { Q_D(const SessionController); return d->sessionLock; } void SessionController::loadSession( const QString& nameOrId ) { Q_D(SessionController); d->loadSessionExternally( session( nameOrId ) ); } QList SessionController::sessionNames() const { Q_D(const SessionController); QList l; const auto sessions = d->sessionActions.keys(); l.reserve(sessions.size()); for(const auto* s : sessions) { l << s->name(); } return l; } QList< const KDevelop::Session* > SessionController::sessions() const { Q_D(const SessionController); QList< const KDevelop::Session* > ret; const auto sessions = d->sessionActions.keys(); ret.reserve(sessions.size()); // turn to const pointers for (const auto* s : sessions) { ret << s; } return ret; } Session* SessionController::createSession( const QString& name ) { Q_D(SessionController); Session* s; if(name.startsWith(QLatin1Char('{'))) { s = new Session( QUuid(name).toString(), this ); }else{ qsrand(QDateTime::currentDateTimeUtc().toTime_t()); s = new Session( QUuid::createUuid().toString(), this ); s->setName( name ); } d->addSession( s ); updateXmlGuiActionList(); return s; } void SessionController::deleteSession( const ISessionLock::Ptr& lock ) { Q_D(SessionController); Session* s = session(lock->id()); QHash::iterator it = d->sessionActions.find(s); Q_ASSERT( it != d->sessionActions.end() ); unplugActionList( QStringLiteral("available_sessions") ); actionCollection()->removeAction(*it); if (d->grp) { // happens in unit tests d->grp->removeAction(*it); plugActionList( QStringLiteral("available_sessions"), d->grp->actions() ); } if (s == d->activeSession) { d->activeSession = nullptr; } deleteSessionFromDisk(lock); emit sessionDeleted( s->id().toString() ); d->sessionActions.remove(s); delete s; } void SessionController::deleteSessionFromDisk( const ISessionLock::Ptr& lock ) { qCDebug(SHELL) << "Deleting session:" << lock->id(); static_cast(lock.data())->removeFromDisk(); ItemRepositoryRegistry::deleteRepositoryFromDisk(DUChain::repositoryPathForSession(lock)); } void SessionController::loadDefaultSession( const QString& session ) { Q_D(SessionController); QString load = session; if (load.isEmpty()) { KConfigGroup grp = KSharedConfig::openConfig()->group( cfgSessionGroup() ); load = grp.readEntry( cfgActiveSessionEntry(), "default" ); } // Iteratively try to load the session, asking user what to do in case of failure // If showForceOpenDialog() returns empty string, stop trying do { Session* s = this->session(load); if( !s ) { s = createSession( load ); } TryLockSessionResult result = d->activateSession( s ); if( result.lock ) { Q_ASSERT(d->activeSession == s); Q_ASSERT(d->sessionLock = result.lock); break; } load = handleLockedSession( s->name(), s->id().toString(), result.runInfo ); } while( !load.isEmpty() ); } Session* SessionController::session( const QString& nameOrId ) const { Q_D(const SessionController); Session* ret = d->findSessionForName( nameOrId ); if(ret) return ret; return d->findSessionForId( nameOrId ); } QString SessionController::cloneSession( const QString& nameOrid ) { Q_D(SessionController); Session* origSession = session( nameOrid ); qsrand(QDateTime::currentDateTimeUtc().toTime_t()); QUuid id = QUuid::createUuid(); auto copyJob = KIO::copy(QUrl::fromLocalFile(sessionDirectory(origSession->id().toString())), QUrl::fromLocalFile(sessionDirectory( id.toString()))); KJobWidgets::setWindow(copyJob, Core::self()->uiController()->activeMainWindow()); copyJob->exec(); Session* newSession = new Session( id.toString() ); newSession->setName( i18n( "Copy of %1", origSession->name() ) ); d->addSession(newSession); updateXmlGuiActionList(); return newSession->name(); } void SessionController::updateXmlGuiActionList() { Q_D(SessionController); unplugActionList( QStringLiteral("available_sessions") ); if (d->grp) { auto actions = d->grp->actions(); std::sort(actions.begin(), actions.end(), [](const QAction* lhs, const QAction* rhs) { auto s1 = lhs->data().value(); auto s2 = rhs->data().value(); return QString::localeAwareCompare(s1->description(), s2->description()) < 0; }); plugActionList(QStringLiteral("available_sessions"), actions); } } QString SessionController::cfgSessionGroup() { return QStringLiteral("Sessions"); } QString SessionController::cfgActiveSessionEntry() { return QStringLiteral("Active Session ID"); } SessionInfos SessionController::availableSessionInfos() { SessionInfos sessionInfos; const auto sessionDirs = QDir(SessionControllerPrivate::sessionBaseDirectory()).entryList(QDir::AllDirs); sessionInfos.reserve(sessionDirs.size()); for (const QString& sessionId : sessionDirs) { if( !QUuid( sessionId ).isNull() ) { sessionInfos << Session::parse( sessionId ); } } sessionInfos.squeeze(); return sessionInfos; } QString SessionController::sessionDirectory(const QString& sessionId) { return SessionControllerPrivate::sessionBaseDirectory() + sessionId; } TryLockSessionResult SessionController::tryLockSession(const QString& id, bool doLocking) { return SessionLock::tryLockSession(id, doLocking); } bool SessionController::isSessionRunning(const QString& id) { return sessionRunInfo(id).isRunning; } SessionRunInfo SessionController::sessionRunInfo(const QString& id) { return SessionLock::tryLockSession(id, false).runInfo; } QString SessionController::showSessionChooserDialog(const QString& headerText, bool onlyRunning) { ///FIXME: move this code into sessiondialog.cpp auto* view = new QListView; auto* filter = new QLineEdit; filter->setClearButtonEnabled( true ); filter->setPlaceholderText(i18n("Search")); auto* model = new QStandardItemModel(view); auto *proxy = new QSortFilterProxyModel(model); proxy->setSourceModel(model); proxy->setFilterKeyColumn( 1 ); proxy->setFilterCaseSensitivity( Qt::CaseInsensitive ); connect(filter, &QLineEdit::textChanged, proxy, &QSortFilterProxyModel::setFilterFixedString); SessionChooserDialog dialog(view, proxy, filter); view->setEditTriggers(QAbstractItemView::NoEditTriggers); QVBoxLayout layout(dialog.mainWidget()); if(!headerText.isEmpty()) { QLabel* heading = new QLabel(headerText); QFont font = heading->font(); font.setBold(true); heading->setFont(font); layout.addWidget(heading); } - model->setColumnCount(3); + model->setColumnCount(4); model->setHeaderData(0, Qt::Horizontal,i18n("Identity")); - model->setHeaderData(1, Qt::Horizontal, i18n("Contents")); + model->setHeaderData(1, Qt::Horizontal,i18n("Contents")); model->setHeaderData(2, Qt::Horizontal,i18n("State")); + model->setHeaderData(3, Qt::Horizontal,i18n("Name")); view->setModel(proxy); view->setModelColumn(1); auto* filterLayout = new QHBoxLayout(); filterLayout->addWidget(new QLabel(i18n("Filter:"))); filterLayout->addWidget(filter); layout.addLayout(filterLayout); layout.addWidget(view); filter->setFocus(); int row = 0; QString defaultSession = KSharedConfig::openConfig()->group( cfgSessionGroup() ).readEntry( cfgActiveSessionEntry(), "default" ); const auto availableSessionInfos = KDevelop::SessionController::availableSessionInfos(); for (const KDevelop::SessionInfo& si : availableSessionInfos) { if ( si.name.isEmpty() && si.projects.isEmpty() ) { continue; } bool running = KDevelop::SessionController::isSessionRunning(si.uuid.toString()); if(onlyRunning && !running) continue; - + model->setItem(row, 0, new QStandardItem(si.uuid.toString())); model->setItem(row, 1, new QStandardItem(si.description)); model->setItem(row, 2, new QStandardItem); + model->setItem(row, 3, new QStandardItem(si.name)); ++row; } model->sort(1); if(!onlyRunning) { model->setItem(row, 0, new QStandardItem); model->setItem(row, 1, new QStandardItem(QIcon::fromTheme(QStringLiteral("window-new")), i18n("Create New Session"))); } dialog.updateState(); dialog.mainWidget()->layout()->setContentsMargins(0,0,0,0); const QModelIndex defaultSessionIndex = model->match(model->index(0, 0), Qt::DisplayRole, defaultSession, 1, Qt::MatchExactly).value(0); view->selectionModel()->setCurrentIndex(proxy->mapFromSource(defaultSessionIndex), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); view->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); ///@todo We need a way to get a proper size-hint from the view, but unfortunately, that only seems possible after the view was shown. dialog.resize(QSize(900, 600)); if(dialog.exec() != QDialog::Accepted) // krazy:exclude=crashy { return QString(); } QModelIndex selected = view->selectionModel()->currentIndex(); if (!selected.isValid()) return QString(); const QString selectedSessionId = selected.sibling(selected.row(), 0).data().toString(); if (selectedSessionId.isEmpty()) { // "Create New Session" item selected, return a fresh UUID qsrand(QDateTime::currentDateTimeUtc().toTime_t()); return QUuid::createUuid().toString(); } return selectedSessionId; } QString SessionController::handleLockedSession( const QString& sessionName, const QString& sessionId, const SessionRunInfo& runInfo ) { return SessionLock::handleLockedSession(sessionName, sessionId, runInfo); } QString SessionController::sessionDir() { Q_D(SessionController); if( !activeSession() ) return QString(); return d->ownSessionDirectory(); } QString SessionController::sessionName() { if(!activeSession()) return QString(); return activeSession()->description(); } } #include "sessioncontroller.moc" #include "moc_sessioncontroller.cpp"