1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
10 ** GNU Lesser General Public License Usage
12 ** This file may be used under the terms of the GNU Lesser General Public
13 ** License version 2.1 as published by the Free Software Foundation and
14 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
15 ** Please review the following information to ensure the GNU Lesser General
16 ** Public License version 2.1 requirements will be met:
17 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
19 ** In addition, as a special exception, Nokia gives you certain additional
20 ** rights. These rights are described in the Nokia Qt LGPL Exception
21 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
25 ** Alternatively, this file may be used in accordance with the terms and
26 ** conditions contained in a signed written agreement between you and Nokia.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
31 **************************************************************************/
33 #include "environmentmodel.h"
35 #include <utils/environment.h>
37 #include <QtGui/QFont>
43 class EnvironmentModelPrivate
46 void updateResultEnvironment()
48 m_resultEnvironment = m_baseEnvironment;
49 m_resultEnvironment.modify(m_items);
50 // Add removed variables again and mark them as "<UNSET>" so
51 // that the user can actually see those removals:
52 foreach (const Utils::EnvironmentItem &item, m_items) {
54 m_resultEnvironment.set(item.name, EnvironmentModel::tr("<UNSET>"));
59 int findInChanges(const QString &name) const
61 for (int i=0; i<m_items.size(); ++i)
62 if (m_items.at(i).name == name)
67 int findInResultInsertPosition(const QString &name) const
69 Utils::Environment::const_iterator it;
71 for (it = m_resultEnvironment.constBegin(); it != m_resultEnvironment.constEnd(); ++it, ++i)
72 if (m_resultEnvironment.key(it) > name)
74 return m_resultEnvironment.size();
77 int findInResult(const QString &name) const
79 Utils::Environment::const_iterator it;
81 for (it = m_resultEnvironment.constBegin(); it != m_resultEnvironment.constEnd(); ++it, ++i)
82 if (m_resultEnvironment.key(it) == name)
87 Utils::Environment m_baseEnvironment;
88 Utils::Environment m_resultEnvironment;
89 QList<Utils::EnvironmentItem> m_items;
92 } // namespace Internal
94 EnvironmentModel::EnvironmentModel(QObject *parent) :
95 QAbstractTableModel(parent),
96 m_d(new Internal::EnvironmentModelPrivate)
99 EnvironmentModel::~EnvironmentModel()
104 QString EnvironmentModel::indexToVariable(const QModelIndex &index) const
106 return m_d->m_resultEnvironment.key(m_d->m_resultEnvironment.constBegin() + index.row());
109 void EnvironmentModel::setBaseEnvironment(const Utils::Environment &env)
111 if (m_d->m_baseEnvironment == env)
114 m_d->m_baseEnvironment = env;
115 m_d->updateResultEnvironment();
119 int EnvironmentModel::rowCount(const QModelIndex &parent) const
121 if (parent.isValid())
124 return m_d->m_resultEnvironment.size();
126 int EnvironmentModel::columnCount(const QModelIndex &parent) const
128 if (parent.isValid())
134 bool EnvironmentModel::changes(const QString &name) const
136 return m_d->findInChanges(name) >= 0;
139 QVariant EnvironmentModel::data(const QModelIndex &index, int role) const
141 if (!index.isValid())
144 if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::ToolTipRole) {
145 if (index.column() == 0) {
146 return m_d->m_resultEnvironment.key(m_d->m_resultEnvironment.constBegin() + index.row());
147 } else if (index.column() == 1) {
148 // Do not return "<UNSET>" when editing a previously unset variable:
149 if (role == Qt::EditRole) {
150 int pos = m_d->findInChanges(indexToVariable(index));
152 return m_d->m_items.at(pos).value;
154 return m_d->m_resultEnvironment.value(m_d->m_resultEnvironment.constBegin() + index.row());
157 if (role == Qt::FontRole) {
158 // check whether this environment variable exists in m_d->m_items
159 if (changes(m_d->m_resultEnvironment.key(m_d->m_resultEnvironment.constBegin() + index.row()))) {
169 Qt::ItemFlags EnvironmentModel::flags(const QModelIndex &index) const
172 return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled;
175 QVariant EnvironmentModel::headerData(int section, Qt::Orientation orientation, int role) const
177 if (orientation == Qt::Vertical || role != Qt::DisplayRole)
179 return section == 0 ? tr("Variable") : tr("Value");
182 /// *****************
183 /// Utility functions
184 /// *****************
185 QModelIndex EnvironmentModel::variableToIndex(const QString &name) const
187 int row = m_d->findInResult(name);
189 return QModelIndex();
190 return index(row, 0);
193 bool EnvironmentModel::setData(const QModelIndex &index, const QVariant &value, int role)
195 if (!index.isValid() || role != Qt::EditRole)
198 // ignore changes to already set values:
199 if (data(index, role) == value)
202 const QString oldName = data(this->index(index.row(), 0, QModelIndex())).toString();
203 const QString oldValue = data(this->index(index.row(), 1, QModelIndex())).toString();
204 int changesPos = m_d->findInChanges(oldName);
206 if (index.column() == 0) {
207 //fail if a variable with the same name already exists
208 #if defined(Q_OS_WIN)
209 const QString &newName = value.toString().toUpper();
211 const QString &newName = value.toString();
213 // Does the new name exist already?
214 if (m_d->m_resultEnvironment.hasKey(newName))
217 Utils::EnvironmentItem newVariable(newName, oldValue);
219 if (changesPos != -1)
220 resetVariable(oldName); // restore the original base variable again
222 QModelIndex newIndex = addVariable(newVariable); // add the new variable
223 emit focusIndex(newIndex.sibling(newIndex.row(), 1)); // hint to focus on the value
225 } else if (index.column() == 1) {
226 // We are changing an existing value:
227 const QString stringValue = value.toString();
228 if (changesPos != -1) {
229 // We have already changed this value
230 if (stringValue == m_d->m_baseEnvironment.value(oldName)) {
231 // ... and now went back to the base value
232 m_d->m_items.removeAt(changesPos);
234 // ... and changed it again
235 m_d->m_items[changesPos].value = stringValue;
236 m_d->m_items[changesPos].unset = false;
239 // Add a new change item:
240 m_d->m_items.append(Utils::EnvironmentItem(oldName, stringValue));
242 m_d->updateResultEnvironment();
243 emit dataChanged(index, index);
244 emit userChangesChanged();
250 QModelIndex EnvironmentModel::addVariable()
252 //: Name when inserting a new variable
253 return addVariable(Utils::EnvironmentItem(tr("<VARIABLE>"),
254 //: Value when inserting a new variable
258 QModelIndex EnvironmentModel::addVariable(const Utils::EnvironmentItem &item)
261 // Return existing index if the name is already in the result set:
262 int pos = m_d->findInResult(item.name);
263 if (pos >= 0 && pos < m_d->m_resultEnvironment.size())
264 return index(pos, 0, QModelIndex());
266 int insertPos = m_d->findInResultInsertPosition(item.name);
267 int changePos = m_d->findInChanges(item.name);
268 if (m_d->m_baseEnvironment.hasKey(item.name)) {
269 // We previously unset this!
270 Q_ASSERT(changePos >= 0);
271 // Do not insert a line here as we listed the variable as <UNSET> before!
272 Q_ASSERT(m_d->m_items.at(changePos).name == item.name);
273 Q_ASSERT(m_d->m_items.at(changePos).unset);
274 Q_ASSERT(m_d->m_items.at(changePos).value.isEmpty());
275 m_d->m_items[changePos] = item;
276 emit dataChanged(index(insertPos, 0, QModelIndex()), index(insertPos, 1, QModelIndex()));
278 // We add something that is not in the base environment
279 // Insert a new line!
280 beginInsertRows(QModelIndex(), insertPos, insertPos);
281 Q_ASSERT(changePos < 0);
282 m_d->m_items.append(item);
283 m_d->updateResultEnvironment();
286 emit userChangesChanged();
287 return index(insertPos, 0, QModelIndex());
290 void EnvironmentModel::resetVariable(const QString &name)
292 int rowInChanges = m_d->findInChanges(name);
293 if (rowInChanges < 0)
296 int rowInResult = m_d->findInResult(name);
300 if (m_d->m_baseEnvironment.hasKey(name)) {
301 m_d->m_items.removeAt(rowInChanges);
302 m_d->updateResultEnvironment();
303 emit dataChanged(index(rowInResult, 0, QModelIndex()), index(rowInResult, 1, QModelIndex()));
304 emit userChangesChanged();
306 // Remove the line completely!
307 beginRemoveRows(QModelIndex(), rowInResult, rowInResult);
308 m_d->m_items.removeAt(rowInChanges);
309 m_d->updateResultEnvironment();
311 emit userChangesChanged();
315 void EnvironmentModel::unsetVariable(const QString &name)
317 // This does not change the number of rows as we will display a <UNSET>
318 // in place of the original variable!
319 int row = m_d->findInResult(name);
323 // look in m_d->m_items for the variable
324 int pos = m_d->findInChanges(name);
326 m_d->m_items[pos].unset = true;
327 m_d->m_items[pos].value.clear();
328 m_d->updateResultEnvironment();
329 emit dataChanged(index(row, 0, QModelIndex()), index(row, 1, QModelIndex()));
330 emit userChangesChanged();
333 Utils::EnvironmentItem item(name, QString());
335 m_d->m_items.append(item);
336 m_d->updateResultEnvironment();
337 emit dataChanged(index(row, 0, QModelIndex()), index(row, 1, QModelIndex()));
338 emit userChangesChanged();
341 bool EnvironmentModel::canUnset(const QString &name)
343 int pos = m_d->findInChanges(name);
345 return m_d->m_items.at(pos).unset;
350 bool EnvironmentModel::canReset(const QString &name)
352 return m_d->m_baseEnvironment.hasKey(name);
355 QList<Utils::EnvironmentItem> EnvironmentModel::userChanges() const
360 void EnvironmentModel::setUserChanges(QList<Utils::EnvironmentItem> list)
362 // We assume nobody is reordering the items here.
363 if (list == m_d->m_items)
367 m_d->updateResultEnvironment();