File indexing completed on 2024-04-28 04:37:25

0001 /*
0002     SPDX-FileCopyrightText: 2008 Andreas Pakulat <apaku@gmx.de>
0003     SPDX-FileCopyrightText: 2010 David Nolden <david.nolden.kdevelop@art-master.de>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "sessioncontroller.h"
0009 
0010 #include <QDir>
0011 #include <QHash>
0012 #include <QStringList>
0013 #include <QAction>
0014 #include <QActionGroup>
0015 #include <QCoreApplication>
0016 #include <QDBusConnection>
0017 #include <QInputDialog>
0018 #include <QLabel>
0019 #include <QLineEdit>
0020 #include <QListView>
0021 #include <QSortFilterProxyModel>
0022 #include <QStandardItemModel>
0023 #include <QVBoxLayout>
0024 
0025 #include <KActionCollection>
0026 #include <KConfigGroup>
0027 #include <KIO/CopyJob>
0028 #include <KJobWidgets>
0029 #include <KLocalizedString>
0030 #include <KMessageBox>
0031 #include <KProcess>
0032 #include <KStringHandler>
0033 
0034 #include "session.h"
0035 #include "core.h"
0036 #include "uicontroller.h"
0037 #include "shellextension.h"
0038 #include "sessionlock.h"
0039 #include "sessionchooserdialog.h"
0040 #include "debug.h"
0041 
0042 #include <sublime/mainwindow.h>
0043 #include <serialization/itemrepositoryregistry.h>
0044 #include <duchain/duchain.h>
0045 
0046 namespace KDevelop
0047 {
0048 
0049 namespace {
0050     int argc = 0;
0051     char** argv = nullptr;
0052 }
0053 
0054 void SessionController::setArguments(int _argc, char** _argv)
0055 {
0056     argc = _argc;
0057     argv = _argv;
0058 }
0059 
0060 static QStringList standardArguments()
0061 {
0062     QStringList ret;
0063     for(int a = 0; a < argc; ++a)
0064     {
0065         QString arg = QString::fromLocal8Bit(argv[a]);
0066         if(arg.startsWith(QLatin1String("-graphicssystem")) || arg.startsWith(QLatin1String("-style")))
0067         {
0068             ret << QLatin1Char('-') + arg;
0069             if(a+1 < argc)
0070                 ret << QString::fromLocal8Bit(argv[a+1]);
0071         }
0072     }
0073     return ret;
0074 }
0075 
0076 class SessionControllerPrivate : public QObject
0077 {
0078     Q_OBJECT
0079 public:
0080     explicit SessionControllerPrivate( SessionController* s )
0081         : q(s)
0082         , activeSession(nullptr)
0083         , grp(nullptr)
0084     {
0085     }
0086 
0087     ~SessionControllerPrivate() override {
0088     }
0089 
0090     Session* findSessionForName( const QString& name ) const
0091     {
0092         for (auto it = sessionActions.begin(), end = sessionActions.end(); it != end; ++it) {
0093             Session* s = it.key();
0094             if( s->name() == name )
0095                 return s;
0096         }
0097         return nullptr;
0098     }
0099 
0100     Session* findSessionForId(const QString& idString) const
0101     {
0102         QUuid id(idString);
0103 
0104         for (auto it = sessionActions.begin(), end = sessionActions.end(); it != end; ++it) {
0105             Session* s = it.key();
0106             if( s->id() == id)
0107                 return s;
0108         }
0109         return nullptr;
0110     }
0111 
0112     void newSession(const QString& name = {})
0113     {
0114         auto* session = new Session(QUuid::createUuid().toString());
0115         if (!name.isEmpty()) {
0116             session->setName(name);
0117         }
0118 
0119         KProcess::startDetached(ShellExtension::getInstance()->executableFilePath(), QStringList() << QStringLiteral("-s") << session->id().toString() << standardArguments());
0120         delete session;
0121 #if 0
0122         //Terminate this instance of kdevelop if the user agrees
0123         const auto windows = Core::self()->uiController()->controller()->mainWindows();
0124         for (Sublime::MainWindow* window : windows) {
0125             window->close();
0126         }
0127 #endif
0128     }
0129 
0130     void newNamedSession()
0131     {
0132         bool ok = false;
0133         const QString& newSessionName = QInputDialog::getText(
0134             Core::self()->uiController()->activeMainWindow(), i18nc("@title:window", "Start New Session"),
0135             i18nc("@label:textbox", "New session name:"), QLineEdit::Normal, {}, &ok);
0136 
0137         if (ok) {
0138             newSession(newSessionName);
0139         }
0140     }
0141 
0142     void deleteCurrentSession()
0143     {
0144         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?"));
0145 
0146         if(choice == KMessageBox::Continue)
0147         {
0148             q->deleteSessionFromDisk(sessionLock);
0149             q->emitQuitSession();
0150         }
0151     }
0152 
0153     void renameSession()
0154     {
0155         bool ok;
0156         auto newSessionName = QInputDialog::getText(Core::self()->uiController()->activeMainWindow(),
0157                                                     i18nc("@title:window", "Rename Session"), i18nc("@label:textbox", "New session name:"),
0158                                                     QLineEdit::Normal, q->activeSession()->name(), &ok);
0159         if (ok) {
0160             static_cast<Session*>(q->activeSession())->setName(newSessionName);
0161         }
0162 
0163         q->updateXmlGuiActionList(); // resort
0164     }
0165 
0166     bool loadSessionExternally( Session* s )
0167     {
0168         Q_ASSERT( s );
0169         KProcess::startDetached(ShellExtension::getInstance()->executableFilePath(), QStringList() << QStringLiteral("-s") << s->id().toString() << standardArguments());
0170         return true;
0171     }
0172 
0173     TryLockSessionResult activateSession( Session* s )
0174     {
0175         Q_ASSERT( s );
0176 
0177         activeSession = s;
0178         TryLockSessionResult result = SessionController::tryLockSession( s->id().toString());
0179         if( !result.lock ) {
0180             activeSession = nullptr;
0181             return result;
0182         }
0183         Q_ASSERT(s->id().toString() == result.lock->id());
0184         sessionLock = result.lock;
0185 
0186         KConfigGroup grp = KSharedConfig::openConfig()->group( SessionController::cfgSessionGroup() );
0187         grp.writeEntry( SessionController::cfgActiveSessionEntry(), s->id().toString() );
0188         grp.sync();
0189         if (Core::self()->setupFlags() & Core::NoUi) return result;
0190 
0191         QHash<Session*,QAction*>::iterator it = sessionActions.find(s);
0192         Q_ASSERT( it != sessionActions.end() );
0193         (*it)->setCheckable(true);
0194         (*it)->setChecked(true);
0195 
0196         for(it = sessionActions.begin(); it != sessionActions.end(); ++it)
0197         {
0198             if(it.key() != s)
0199                 (*it)->setCheckable(false);
0200         }
0201 
0202         return result;
0203     }
0204 
0205     void loadSessionFromAction(QAction* action)
0206     {
0207         auto session = action->data().value<Session*>();
0208         loadSessionExternally(session);
0209     }
0210 
0211     void addSession( Session* s )
0212     {
0213         if (Core::self()->setupFlags() & Core::NoUi) {
0214             sessionActions[s] = nullptr;
0215             return;
0216         }
0217 
0218         auto* a = new QAction( grp );
0219         a->setText( s->description() );
0220         a->setToolTip(s->description());
0221         a->setCheckable( false );
0222         a->setData(QVariant::fromValue<Session*>(s));
0223 
0224         sessionActions[s] = a;
0225         q->actionCollection()->addAction(QLatin1String("session_") + s->id().toString(), a);
0226         connect( s, &Session::sessionUpdated, this, &SessionControllerPrivate::sessionUpdated );
0227         sessionUpdated( s );
0228     }
0229 
0230     SessionController* const q;
0231 
0232     QHash<Session*, QAction*> sessionActions;
0233     ISession* activeSession;
0234     QActionGroup* grp;
0235 
0236     ISessionLock::Ptr sessionLock;
0237 
0238     static QString sessionBaseDirectory()
0239     {
0240         return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)
0241             + QLatin1Char('/') + QCoreApplication::applicationName() + QLatin1String("/sessions/");
0242     }
0243 
0244     QString ownSessionDirectory() const
0245     {
0246         Q_ASSERT(activeSession);
0247         return q->sessionDirectory( activeSession->id().toString() );
0248     }
0249 
0250 private Q_SLOTS:
0251     void sessionUpdated( KDevelop::ISession* s )
0252     {
0253         sessionActions[static_cast<Session*>( s )]->setText( KStringHandler::rsqueeze(s->description()) );
0254     }
0255 };
0256 
0257 
0258 SessionController::SessionController( QObject *parent )
0259     : QObject(parent)
0260     , d_ptr(new SessionControllerPrivate(this))
0261 {
0262     Q_D(SessionController);
0263 
0264     setObjectName(QStringLiteral("SessionController"));
0265     setComponentName(QStringLiteral("kdevsession"), i18n("Session Manager"));
0266 
0267     setXMLFile(QStringLiteral("kdevsessionui.rc"));
0268 
0269     QDBusConnection::sessionBus().registerObject( QStringLiteral("/org/kdevelop/SessionController"),
0270         this, QDBusConnection::ExportScriptableSlots );
0271 
0272     if (Core::self()->setupFlags() & Core::NoUi) return;
0273 
0274     QAction* action = actionCollection()->addAction(QStringLiteral("new_session"));
0275     connect(action, &QAction::triggered,
0276             this, [this] { Q_D(SessionController); d->newSession(); });
0277     action->setText( i18nc("@action:inmenu", "Start New Session") );
0278     action->setToolTip( i18nc("@info:tooltip", "Start a new KDevelop instance with an empty session") );
0279     action->setIcon(QIcon::fromTheme(QStringLiteral("window-new")));
0280 
0281     action = actionCollection()->addAction(QStringLiteral("new_named_session"));
0282     connect(action, &QAction::triggered, this, [this] {
0283         Q_D(SessionController);
0284         d->newNamedSession();
0285     });
0286     action->setText(i18nc("@action:inmenu", "Start New Named Session..."));
0287     action->setToolTip(i18nc("@info:tooltip", "Start a new KDevelop instance with an empty named session"));
0288     action->setIcon(QIcon::fromTheme(QStringLiteral("window-new")));
0289 
0290     action = actionCollection()->addAction(QStringLiteral("rename_session"));
0291     connect(action, &QAction::triggered,
0292             this, [this] { Q_D(SessionController); d->renameSession(); });
0293     action->setText( i18nc("@action", "Rename Current Session...") );
0294     action->setIcon(QIcon::fromTheme(QStringLiteral("edit-rename")));
0295 
0296     action = actionCollection()->addAction(QStringLiteral("delete_session"));
0297     connect(action, &QAction::triggered,
0298             this, [this] { Q_D(SessionController); d->deleteCurrentSession(); });
0299     action->setText( i18nc("@action", "Delete Current Session...") );
0300     action->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete")));
0301 
0302     action = actionCollection()->addAction( QStringLiteral("quit"), this, SIGNAL(quitSession()) );
0303     action->setText( i18nc("@action", "Quit") );
0304     action->setMenuRole( QAction::NoRole ); // OSX: prevent QT from hiding this due to conflict with 'Quit KDevelop...'
0305     actionCollection()->setDefaultShortcut( action, Qt::CTRL | Qt::Key_Q );
0306     action->setIcon(QIcon::fromTheme(QStringLiteral("application-exit")));
0307 
0308     d->grp = new QActionGroup( this );
0309     connect(d->grp, &QActionGroup::triggered,
0310             this, [this] (QAction* a) { Q_D(SessionController); d->loadSessionFromAction(a); } );
0311 }
0312 
0313 SessionController::~SessionController() = default;
0314 
0315 void SessionController::startNewSession()
0316 {
0317     Q_D(SessionController);
0318 
0319     d->newSession();
0320 }
0321 
0322 void SessionController::cleanup()
0323 {
0324     Q_D(SessionController);
0325 
0326     if (d->activeSession) {
0327         Q_ASSERT(d->activeSession->id().toString() == d->sessionLock->id());
0328 
0329         if (d->activeSession->isTemporary()) {
0330             deleteSessionFromDisk(d->sessionLock);
0331         }
0332         d->activeSession = nullptr;
0333     }
0334 
0335     d->sessionLock.clear();
0336     qDeleteAll(d->sessionActions);
0337     d->sessionActions.clear();
0338 }
0339 
0340 void SessionController::initialize( const QString& session )
0341 {
0342     Q_D(SessionController);
0343 
0344     QDir sessiondir( SessionControllerPrivate::sessionBaseDirectory() );
0345 
0346     const auto sessionDirs = sessiondir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
0347     for (const QString& s : sessionDirs) {
0348         QUuid id( s );
0349         if( id.isNull() )
0350             continue;
0351         // Only create sessions for directories that represent proper uuid's
0352         auto* ses = new Session(id.toString(), this);
0353 
0354         //Delete sessions that have no name and are empty
0355         if( ses->containedProjects().isEmpty() && ses->name().isEmpty()
0356             && (session.isEmpty() || (ses->id().toString() != session && ses->name() != session)) )
0357         {
0358             TryLockSessionResult result = tryLockSession(s);
0359             if (result.lock) {
0360                 deleteSessionFromDisk(result.lock);
0361             }
0362             delete ses;
0363         } else {
0364             d->addSession( ses );
0365         }
0366     }
0367 
0368     loadDefaultSession( session );
0369 
0370     updateXmlGuiActionList();
0371 }
0372 
0373 
0374 ISession* SessionController::activeSession() const
0375 {
0376     Q_D(const SessionController);
0377 
0378     return d->activeSession;
0379 }
0380 
0381 ISessionLock::Ptr SessionController::activeSessionLock() const
0382 {
0383     Q_D(const SessionController);
0384 
0385     return d->sessionLock;
0386 }
0387 
0388 void SessionController::loadSession( const QString& nameOrId )
0389 {
0390     Q_D(SessionController);
0391 
0392     d->loadSessionExternally( session( nameOrId ) );
0393 }
0394 
0395 QList<QString> SessionController::sessionNames() const
0396 {
0397     Q_D(const SessionController);
0398 
0399     QList<QString> l;
0400     const auto sessions = d->sessionActions.keys();
0401     l.reserve(sessions.size());
0402     for(const auto* s : sessions) {
0403         l << s->name();
0404     }
0405     return l;
0406 }
0407 
0408 QList< const KDevelop::Session* > SessionController::sessions() const
0409 {
0410     Q_D(const SessionController);
0411 
0412     QList< const KDevelop::Session* > ret;
0413     const auto sessions = d->sessionActions.keys();
0414     ret.reserve(sessions.size());
0415     // turn to const pointers
0416     for (const auto* s : sessions) {
0417         ret << s;
0418     }
0419     return ret;
0420 }
0421 
0422 Session* SessionController::createSession( const QString& name )
0423 {
0424     Q_D(SessionController);
0425 
0426     Session* s;
0427     if(name.startsWith(QLatin1Char('{'))) {
0428         s = new Session( QUuid(name).toString(), this );
0429     } else {
0430         s = new Session( QUuid::createUuid().toString(), this );
0431         s->setName( name );
0432     }
0433     d->addSession( s );
0434     updateXmlGuiActionList();
0435     return s;
0436 }
0437 
0438 void SessionController::deleteSession( const ISessionLock::Ptr& lock )
0439 {
0440     Q_D(SessionController);
0441 
0442     Session* s  = session(lock->id());
0443 
0444     QHash<Session*,QAction*>::iterator it = d->sessionActions.find(s);
0445     Q_ASSERT( it != d->sessionActions.end() );
0446 
0447     unplugActionList( QStringLiteral("available_sessions") );
0448     actionCollection()->removeAction(*it);
0449     if (d->grp) { // happens in unit tests
0450         d->grp->removeAction(*it);
0451         plugActionList( QStringLiteral("available_sessions"), d->grp->actions() );
0452     }
0453 
0454     if (s == d->activeSession) {
0455         d->activeSession = nullptr;
0456     }
0457     deleteSessionFromDisk(lock);
0458 
0459     emit sessionDeleted( s->id().toString() );
0460     d->sessionActions.remove(s);
0461     delete s;
0462 }
0463 
0464 void SessionController::deleteSessionFromDisk( const ISessionLock::Ptr& lock )
0465 {
0466     qCDebug(SHELL) << "Deleting session:" << lock->id();
0467 
0468     static_cast<SessionLock*>(lock.data())->removeFromDisk();
0469     ItemRepositoryRegistry::deleteRepositoryFromDisk(DUChain::repositoryPathForSession(lock));
0470 }
0471 
0472 void SessionController::loadDefaultSession( const QString& session )
0473 {
0474     Q_D(SessionController);
0475 
0476     QString load = session;
0477     if (load.isEmpty()) {
0478         KConfigGroup grp = KSharedConfig::openConfig()->group( cfgSessionGroup() );
0479         load = grp.readEntry( cfgActiveSessionEntry(), "default" );
0480     }
0481 
0482     // Iteratively try to load the session, asking user what to do in case of failure
0483     // If showForceOpenDialog() returns empty string, stop trying
0484     do
0485     {
0486         Session* s = this->session(load);
0487         if( !s ) {
0488             s = createSession( load );
0489         }
0490         TryLockSessionResult result = d->activateSession( s );
0491         if( result.lock ) {
0492             Q_ASSERT(d->activeSession == s);
0493             Q_ASSERT(d->sessionLock = result.lock);
0494             break;
0495         }
0496         load = handleLockedSession( s->name(), s->id().toString(), result.runInfo );
0497     } while( !load.isEmpty() );
0498 }
0499 
0500 Session* SessionController::session( const QString& nameOrId ) const
0501 {
0502     Q_D(const SessionController);
0503 
0504     Session* ret = d->findSessionForName( nameOrId );
0505     if(ret)
0506         return ret;
0507 
0508     return d->findSessionForId( nameOrId );
0509 }
0510 
0511 QString SessionController::cloneSession( const QString& nameOrid )
0512 {
0513     Q_D(SessionController);
0514 
0515     Session* origSession = session(nameOrid);
0516     QUuid id = QUuid::createUuid();
0517     auto copyJob = KIO::copy(QUrl::fromLocalFile(sessionDirectory(origSession->id().toString())),
0518                              QUrl::fromLocalFile(sessionDirectory( id.toString())));
0519     KJobWidgets::setWindow(copyJob, Core::self()->uiController()->activeMainWindow());
0520     copyJob->exec();
0521 
0522     auto* newSession = new Session(id.toString(), this);
0523     newSession->setName( i18n( "Copy of %1", origSession->name() ) );
0524     d->addSession(newSession);
0525     updateXmlGuiActionList();
0526     return newSession->name();
0527 }
0528 
0529 void SessionController::updateXmlGuiActionList()
0530 {
0531     Q_D(SessionController);
0532 
0533     unplugActionList( QStringLiteral("available_sessions") );
0534 
0535     if (d->grp) {
0536         auto actions = d->grp->actions();
0537         std::sort(actions.begin(), actions.end(), [](const QAction* lhs, const QAction* rhs) {
0538             auto s1 = lhs->data().value<Session*>();
0539             auto s2 = rhs->data().value<Session*>();
0540             return QString::localeAwareCompare(s1->description(), s2->description()) < 0;
0541         });
0542         plugActionList(QStringLiteral("available_sessions"), actions);
0543     }
0544 }
0545 
0546 
0547 QString SessionController::cfgSessionGroup() { return QStringLiteral("Sessions"); }
0548 QString SessionController::cfgActiveSessionEntry() { return QStringLiteral("Active Session ID"); }
0549 
0550 SessionInfos SessionController::availableSessionInfos()
0551 {
0552     SessionInfos sessionInfos;
0553     const auto sessionDirs = QDir(SessionControllerPrivate::sessionBaseDirectory()).entryList(QDir::AllDirs);
0554     sessionInfos.reserve(sessionDirs.size());
0555     for (const QString& sessionId : sessionDirs) {
0556         if( !QUuid( sessionId ).isNull() ) {
0557             sessionInfos << Session::parse( sessionId );
0558         }
0559     }
0560     sessionInfos.squeeze();
0561     return sessionInfos;
0562 }
0563 
0564 QString SessionController::sessionDirectory(const QString& sessionId)
0565 {
0566     return SessionControllerPrivate::sessionBaseDirectory() + sessionId;
0567 }
0568 
0569 TryLockSessionResult SessionController::tryLockSession(const QString& id, bool doLocking)
0570 {
0571     return SessionLock::tryLockSession(id, doLocking);
0572 }
0573 
0574 bool SessionController::isSessionRunning(const QString& id)
0575 {
0576     return sessionRunInfo(id).isRunning;
0577 }
0578 
0579 SessionRunInfo SessionController::sessionRunInfo(const QString& id)
0580 {
0581     return SessionLock::tryLockSession(id, false).runInfo;
0582 }
0583 
0584 QString SessionController::showSessionChooserDialog(const QString& headerText, bool onlyRunning)
0585 {
0586     ///FIXME: move this code into sessiondialog.cpp
0587     auto* view = new QListView;
0588     auto* filter = new QLineEdit;
0589     filter->setClearButtonEnabled( true );
0590     filter->setPlaceholderText(i18nc("@info:placeholder", "Search..."));
0591 
0592     auto* model = new QStandardItemModel(view);
0593 
0594     auto *proxy = new QSortFilterProxyModel(model);
0595     proxy->setSourceModel(model);
0596     proxy->setFilterKeyColumn( 1 );
0597     proxy->setFilterCaseSensitivity( Qt::CaseInsensitive );
0598     connect(filter, &QLineEdit::textChanged, proxy, &QSortFilterProxyModel::setFilterFixedString);
0599 
0600     SessionChooserDialog dialog(view, proxy, filter);
0601     view->setEditTriggers(QAbstractItemView::NoEditTriggers);
0602 
0603     QVBoxLayout layout(dialog.mainWidget());
0604     if(!headerText.isEmpty()) {
0605         auto* heading = new QLabel(headerText);
0606         QFont font = heading->font();
0607         font.setBold(true);
0608         heading->setFont(font);
0609         layout.addWidget(heading);
0610     }
0611 
0612     model->setColumnCount(4);
0613     model->setHeaderData(0, Qt::Horizontal,i18nc("@title:column", "Identity"));
0614     model->setHeaderData(1, Qt::Horizontal,i18nc("@title:column", "Contents"));
0615     model->setHeaderData(2, Qt::Horizontal,i18nc("@title:column", "State"));
0616     model->setHeaderData(3, Qt::Horizontal,i18nc("@title:column", "Name"));
0617 
0618     view->setModel(proxy);
0619     view->setModelColumn(1);
0620 
0621     auto* filterLayout = new QHBoxLayout();
0622     filterLayout->addWidget(new QLabel(i18nc("@label:textbox", "Filter:")));
0623     filterLayout->addWidget(filter);
0624     layout.addLayout(filterLayout);
0625     layout.addWidget(view);
0626     filter->setFocus();
0627 
0628     int row = 0;
0629 
0630     QString defaultSession = KSharedConfig::openConfig()->group( cfgSessionGroup() ).readEntry( cfgActiveSessionEntry(), "default" );
0631 
0632     const auto availableSessionInfos = KDevelop::SessionController::availableSessionInfos();
0633     for (const KDevelop::SessionInfo& si : availableSessionInfos) {
0634         if ( si.name.isEmpty() && si.projects.isEmpty() ) {
0635             continue;
0636         }
0637 
0638         bool running = KDevelop::SessionController::isSessionRunning(si.uuid.toString());
0639 
0640         if(onlyRunning && !running)
0641             continue;
0642             
0643         model->setItem(row, 0, new QStandardItem(si.uuid.toString()));
0644         model->setItem(row, 1, new QStandardItem(si.description));
0645         model->setItem(row, 2, new QStandardItem);
0646         model->setItem(row, 3, new QStandardItem(si.name));
0647 
0648         ++row;
0649     }
0650     model->sort(1);
0651 
0652     if(!onlyRunning) {
0653         model->setItem(row, 0, new QStandardItem);
0654         model->setItem(row, 1, new QStandardItem(QIcon::fromTheme(QStringLiteral("window-new")), i18n("Create New Session")));
0655     }
0656 
0657     dialog.updateState();
0658     dialog.mainWidget()->layout()->setContentsMargins(0,0,0,0);
0659 
0660     const QModelIndex defaultSessionIndex = model->match(model->index(0, 0), Qt::DisplayRole, defaultSession, 1, Qt::MatchExactly).value(0);
0661     view->selectionModel()->setCurrentIndex(proxy->mapFromSource(defaultSessionIndex), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
0662     view->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
0663     ///@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.
0664     dialog.resize(QSize(900, 600));
0665 
0666     if(dialog.exec() != QDialog::Accepted) // krazy:exclude=crashy
0667     {
0668         return QString();
0669     }
0670 
0671     QModelIndex selected = view->selectionModel()->currentIndex();
0672     if (!selected.isValid())
0673         return QString();
0674 
0675     const QString selectedSessionId = selected.sibling(selected.row(), 0).data().toString();
0676     if (selectedSessionId.isEmpty()) {
0677         // "Create New Session" item selected, return a fresh UUID
0678         return QUuid::createUuid().toString();
0679     }
0680     return selectedSessionId;
0681 }
0682 
0683 QString SessionController::handleLockedSession( const QString& sessionName, const QString& sessionId,
0684                                                 const SessionRunInfo& runInfo )
0685 {
0686     return SessionLock::handleLockedSession(sessionName, sessionId, runInfo);
0687 }
0688 
0689 QString SessionController::sessionDir()
0690 {
0691     Q_D(SessionController);
0692 
0693     if( !activeSession() )
0694         return QString();
0695     return d->ownSessionDirectory();
0696 }
0697 
0698 QString SessionController::sessionName()
0699 {
0700     if(!activeSession())
0701         return QString();
0702     return activeSession()->description();
0703 }
0704 
0705 
0706 }
0707 #include "sessioncontroller.moc"
0708 #include "moc_sessioncontroller.cpp"