1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25 
26 #include "sessionmodel.h"
27 #include "session.h"
28 
29 #include "sessiondialog.h"
30 
31 #include <coreplugin/actionmanager/actionmanager.h>
32 
33 #include <utils/algorithm.h>
34 #include <utils/fileutils.h>
35 #include <utils/stringutils.h>
36 
37 #include <QFileInfo>
38 #include <QDir>
39 
40 using namespace Core;
41 using namespace Utils;
42 
43 namespace ProjectExplorer {
44 namespace Internal {
45 
SessionModel(QObject * parent)46 SessionModel::SessionModel(QObject *parent)
47     : QAbstractTableModel(parent)
48 {
49     m_sortedSessions = SessionManager::sessions();
50     connect(SessionManager::instance(), &SessionManager::sessionLoaded,
51             this, &SessionModel::resetSessions);
52 }
53 
indexOfSession(const QString & session)54 int SessionModel::indexOfSession(const QString &session)
55 {
56     return m_sortedSessions.indexOf(session);
57 }
58 
sessionAt(int row) const59 QString SessionModel::sessionAt(int row) const
60 {
61     return m_sortedSessions.value(row, QString());
62 }
63 
headerData(int section,Qt::Orientation orientation,int role) const64 QVariant SessionModel::headerData(int section, Qt::Orientation orientation, int role) const
65 {
66     QVariant result;
67     if (orientation == Qt::Horizontal) {
68         switch (role) {
69         case Qt::DisplayRole:
70             switch (section) {
71             case 0: result = tr("Session");
72                 break;
73             case 1: result = tr("Last Modified");
74                 break;
75             } // switch (section)
76             break;
77         } // switch (role) {
78     }
79     return result;
80 }
81 
columnCount(const QModelIndex &) const82 int SessionModel::columnCount(const QModelIndex &) const
83 {
84     static int sectionCount = 0;
85     if (sectionCount == 0) {
86         // headers sections defining possible columns
87         while (!headerData(sectionCount, Qt::Horizontal, Qt::DisplayRole).isNull())
88             sectionCount++;
89     }
90 
91     return sectionCount;
92 }
93 
rowCount(const QModelIndex &) const94 int SessionModel::rowCount(const QModelIndex &) const
95 {
96     return m_sortedSessions.count();
97 }
98 
pathsToBaseNames(const QStringList & paths)99 QStringList pathsToBaseNames(const QStringList &paths)
100 {
101     return Utils::transform(paths, [](const QString &path) {
102         return QFileInfo(path).completeBaseName();
103     });
104 }
105 
pathsWithTildeHomePath(const QStringList & paths)106 QStringList pathsWithTildeHomePath(const QStringList &paths)
107 {
108     return Utils::transform(paths, [](const QString &path) {
109         return Utils::withTildeHomePath(QDir::toNativeSeparators(path));
110     });
111 }
112 
data(const QModelIndex & index,int role) const113 QVariant SessionModel::data(const QModelIndex &index, int role) const
114 {
115     QVariant result;
116     if (index.isValid()) {
117         QString sessionName = m_sortedSessions.at(index.row());
118 
119         switch (role) {
120         case Qt::DisplayRole:
121             switch (index.column()) {
122             case 0: result = sessionName;
123                 break;
124             case 1: result = SessionManager::sessionDateTime(sessionName);
125                 break;
126             } // switch (section)
127             break;
128         case Qt::FontRole: {
129             QFont font;
130             if (SessionManager::isDefaultSession(sessionName))
131                 font.setItalic(true);
132             else
133                 font.setItalic(false);
134             if (SessionManager::activeSession() == sessionName && !SessionManager::isDefaultVirgin())
135                 font.setBold(true);
136             else
137                 font.setBold(false);
138             result = font;
139         } break;
140         case DefaultSessionRole:
141             result = SessionManager::isDefaultSession(sessionName);
142             break;
143         case LastSessionRole:
144             result = SessionManager::lastSession() == sessionName;
145             break;
146         case ActiveSessionRole:
147             result = SessionManager::activeSession() == sessionName;
148             break;
149         case ProjectsPathRole:
150             result = pathsWithTildeHomePath(SessionManager::projectsForSessionName(sessionName));
151             break;
152         case ProjectsDisplayRole:
153             result = pathsToBaseNames(SessionManager::projectsForSessionName(sessionName));
154             break;
155         case ShortcutRole: {
156             const Id sessionBase = SESSION_BASE_ID;
157             if (Command *cmd = ActionManager::command(sessionBase.withSuffix(index.row() + 1)))
158                 result = cmd->keySequence().toString(QKeySequence::NativeText);
159         } break;
160         } // switch (role)
161     }
162 
163     return result;
164 }
165 
roleNames() const166 QHash<int, QByteArray> SessionModel::roleNames() const
167 {
168     static const QHash<int, QByteArray> extraRoles{
169         {Qt::DisplayRole, "sessionName"},
170         {DefaultSessionRole, "defaultSession"},
171         {ActiveSessionRole, "activeSession"},
172         {LastSessionRole, "lastSession"},
173         {ProjectsPathRole, "projectsPath"},
174         {ProjectsDisplayRole, "projectsName"}
175     };
176     QHash<int, QByteArray> roles = QAbstractTableModel::roleNames();
177     Utils::addToHash(&roles, extraRoles);
178     return roles;
179 }
180 
sort(int column,Qt::SortOrder order)181 void SessionModel::sort(int column, Qt::SortOrder order)
182 {
183     beginResetModel();
184     const auto cmp = [column, order](const QString &s1, const QString &s2) {
185         bool isLess;
186         if (column == 0) {
187             if (s1 == s2)
188                 return false;
189             isLess = s1 < s2;
190         }
191         else {
192             const auto s1time = SessionManager::sessionDateTime(s1);
193             const auto s2time = SessionManager::sessionDateTime(s2);
194             if (s1time == s2time)
195                 return false;
196             isLess = s1time < s2time;
197         }
198         if (order == Qt::DescendingOrder)
199             isLess = !isLess;
200         return isLess;
201     };
202     Utils::sort(m_sortedSessions, cmp);
203     m_currentSortColumn = column;
204     m_currentSortOrder = order;
205     endResetModel();
206 }
207 
isDefaultVirgin() const208 bool SessionModel::isDefaultVirgin() const
209 {
210     return SessionManager::isDefaultVirgin();
211 }
212 
resetSessions()213 void SessionModel::resetSessions()
214 {
215     beginResetModel();
216     m_sortedSessions = SessionManager::sessions();
217     endResetModel();
218 }
219 
newSession(QWidget * parent)220 void SessionModel::newSession(QWidget *parent)
221 {
222     SessionNameInputDialog sessionInputDialog(parent);
223     sessionInputDialog.setWindowTitle(tr("New Session Name"));
224     sessionInputDialog.setActionText(tr("&Create"), tr("Create and &Open"));
225 
226     runSessionNameInputDialog(&sessionInputDialog, [](const QString &newName) {
227         SessionManager::createSession(newName);
228     });
229 }
230 
cloneSession(QWidget * parent,const QString & session)231 void SessionModel::cloneSession(QWidget *parent, const QString &session)
232 {
233     SessionNameInputDialog sessionInputDialog(parent);
234     sessionInputDialog.setWindowTitle(tr("New Session Name"));
235     sessionInputDialog.setActionText(tr("&Clone"), tr("Clone and &Open"));
236     sessionInputDialog.setValue(session + " (2)");
237 
238     runSessionNameInputDialog(&sessionInputDialog, [session](const QString &newName) {
239         SessionManager::cloneSession(session, newName);
240     });
241 }
242 
deleteSessions(const QStringList & sessions)243 void SessionModel::deleteSessions(const QStringList &sessions)
244 {
245     if (!SessionManager::confirmSessionDelete(sessions))
246         return;
247     beginResetModel();
248     SessionManager::deleteSessions(sessions);
249     m_sortedSessions = SessionManager::sessions();
250     sort(m_currentSortColumn, m_currentSortOrder);
251     endResetModel();
252 }
253 
renameSession(QWidget * parent,const QString & session)254 void SessionModel::renameSession(QWidget *parent, const QString &session)
255 {
256     SessionNameInputDialog sessionInputDialog(parent);
257     sessionInputDialog.setWindowTitle(tr("Rename Session"));
258     sessionInputDialog.setActionText(tr("&Rename"), tr("Rename and &Open"));
259     sessionInputDialog.setValue(session);
260 
261     runSessionNameInputDialog(&sessionInputDialog, [session](const QString &newName) {
262         SessionManager::renameSession(session, newName);
263     });
264 }
265 
switchToSession(const QString & session)266 void SessionModel::switchToSession(const QString &session)
267 {
268     SessionManager::loadSession(session);
269     emit sessionSwitched();
270 }
271 
runSessionNameInputDialog(SessionNameInputDialog * sessionInputDialog,std::function<void (const QString &)> createSession)272 void SessionModel::runSessionNameInputDialog(SessionNameInputDialog *sessionInputDialog, std::function<void(const QString &)> createSession)
273 {
274     if (sessionInputDialog->exec() == QDialog::Accepted) {
275         QString newSession = sessionInputDialog->value();
276         if (newSession.isEmpty() || SessionManager::sessions().contains(newSession))
277             return;
278         beginResetModel();
279         createSession(newSession);
280         m_sortedSessions = SessionManager::sessions();
281         endResetModel();
282         sort(m_currentSortColumn, m_currentSortOrder);
283 
284         if (sessionInputDialog->isSwitchToRequested())
285             switchToSession(newSession);
286         emit sessionCreated(newSession);
287     }
288 }
289 
290 } // namespace Internal
291 } // namespace ProjectExplorer
292