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