1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights. These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
32 **************************************************************************/
34 #include "resourceview.h"
36 #include "undocommands_p.h"
38 #include <QtCore/QDebug>
40 #include <QtGui/QAction>
41 #include <QtGui/QApplication>
42 #include <QtGui/QFileDialog>
43 #include <QtGui/QHeaderView>
44 #include <QtGui/QInputDialog>
45 #include <QtGui/QMenu>
46 #include <QtGui/QMouseEvent>
47 #include <QtGui/QUndoStack>
49 namespace SharedTools {
52 \class FileEntryBackup
56 class FileEntryBackup : public EntryBackup
63 FileEntryBackup(ResourceModel &model, int prefixIndex, int fileIndex,
64 const QString &fileName, const QString &alias)
65 : EntryBackup(model, prefixIndex, fileName), m_fileIndex(fileIndex),
70 void FileEntryBackup::restore() const
72 m_model->insertFile(m_prefixIndex, m_fileIndex, m_name, m_alias);
76 \class PrefixEntryBackup
78 Backups a prefix node including children.
80 class PrefixEntryBackup : public EntryBackup
84 QList<FileEntryBackup> m_files;
87 PrefixEntryBackup(ResourceModel &model, int prefixIndex, const QString &prefix,
88 const QString &language, const QList<FileEntryBackup> &files)
89 : EntryBackup(model, prefixIndex, prefix), m_language(language), m_files(files) { }
93 void PrefixEntryBackup::restore() const
95 m_model->insertPrefix(m_prefixIndex, m_name, m_language);
96 foreach (const FileEntryBackup &entry, m_files) {
103 class RelativeResourceModel : public ResourceModel
106 RelativeResourceModel(const ResourceFile &resource_file, QObject *parent = 0);
108 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
110 if (!index.isValid())
113 void const * const internalPointer = index.internalPointer();
115 if ((role == Qt::DisplayRole) && (internalPointer != NULL))
116 return ResourceModel::data(index, Qt::ToolTipRole);
118 return ResourceModel::data(index, role);
121 void setResourceDragEnabled(bool e) { m_resourceDragEnabled = e; }
122 bool resourceDragEnabled() const { return m_resourceDragEnabled; }
124 virtual Qt::ItemFlags flags(const QModelIndex &index) const;
126 EntryBackup * removeEntry(const QModelIndex &index);
129 bool m_resourceDragEnabled;
132 RelativeResourceModel::RelativeResourceModel(const ResourceFile &resource_file, QObject *parent) :
133 ResourceModel(resource_file, parent),
134 m_resourceDragEnabled(false)
138 Qt::ItemFlags RelativeResourceModel::flags(const QModelIndex &index) const
140 Qt::ItemFlags rc = ResourceModel::flags(index);
141 if ((rc & Qt::ItemIsEnabled) && m_resourceDragEnabled)
142 rc |= Qt::ItemIsDragEnabled;
146 EntryBackup * RelativeResourceModel::removeEntry(const QModelIndex &index)
148 const QModelIndex prefixIndex = this->prefixIndex(index);
149 const bool isPrefixNode = (prefixIndex == index);
151 // Create backup, remove, return backup
154 QString prefixBackup;
155 getItem(index, prefixBackup, dummy);
156 const QString languageBackup = lang(index);
157 const int childCount = rowCount(index);
158 QList<FileEntryBackup> filesBackup;
159 for (int i = 0; i < childCount; i++) {
160 const QModelIndex childIndex = this->index(i, 0, index);
161 const QString fileNameBackup = file(childIndex);
162 const QString aliasBackup = alias(childIndex);
163 FileEntryBackup entry(*this, index.row(), i, fileNameBackup, aliasBackup);
164 filesBackup << entry;
167 return new PrefixEntryBackup(*this, index.row(), prefixBackup, languageBackup, filesBackup);
169 const QString fileNameBackup = file(index);
170 const QString aliasBackup = alias(index);
172 return new FileEntryBackup(*this, prefixIndex.row(), index.row(), fileNameBackup, aliasBackup);
176 } // namespace Internal
178 ResourceView::ResourceView(QUndoStack *history, QWidget *parent) :
180 m_qrcModel(new Internal::RelativeResourceModel(m_qrcFile, this)),
188 m_defaultAddFile(false),
193 setModel(m_qrcModel);
197 connect(m_qrcModel, SIGNAL(dirtyChanged(bool)),
198 this, SIGNAL(dirtyChanged(bool)));
202 setDefaultAddFileEnabled(true);
203 enableContextMenu(true);
206 ResourceView::~ResourceView()
210 bool ResourceView::isDirty() const
212 return m_qrcModel->dirty();
215 void ResourceView::setDirty(bool dirty)
217 m_qrcModel->setDirty(dirty);
220 void ResourceView::setDefaultAddFileEnabled(bool enable)
222 m_defaultAddFile = enable;
225 bool ResourceView::defaultAddFileEnabled() const
227 return m_defaultAddFile;
230 void ResourceView::findSamePlacePostDeletionModelIndex(int &row, QModelIndex &parent) const
233 // - Make selection stay on same Y level
234 // - Enable user to hit delete several times in row
235 const bool hasLowerBrother = m_qrcModel->hasIndex(row + 1,
237 if (hasLowerBrother) {
238 // First or mid child -> lower brother
244 // --> return unmodified
246 if (parent == QModelIndex()) {
249 // Last and only prefix node
254 parent = QModelIndex();
256 const QModelIndex upperBrother = m_qrcModel->index(row - 1,
258 if (m_qrcModel->hasChildren(upperBrother)) {
262 row = m_qrcModel->rowCount(upperBrother) - 1;
263 parent = upperBrother;
273 const bool hasPrefixBelow = m_qrcModel->hasIndex(parent.row() + 1,
274 parent.column(), QModelIndex());
275 if (hasPrefixBelow) {
276 // Last child or parent with lower brother -> lower brother of parent
281 row = parent.row() + 1;
282 parent = QModelIndex();
284 const bool onlyChild = row == 0;
286 // Last and only child of last parent -> parent
290 parent = m_qrcModel->parent(parent);
292 // Last child of last parent -> upper brother
303 EntryBackup * ResourceView::removeEntry(const QModelIndex &index)
305 Q_ASSERT(m_qrcModel);
306 return m_qrcModel->removeEntry(index);
309 void ResourceView::addFiles(int prefixIndex, const QStringList &fileNames, int cursorFile,
310 int &firstFile, int &lastFile)
312 Q_ASSERT(m_qrcModel);
313 m_qrcModel->addFiles(prefixIndex, fileNames, cursorFile, firstFile, lastFile);
315 // Expand prefix node
316 const QModelIndex prefixModelIndex = m_qrcModel->index(prefixIndex, 0, QModelIndex());
317 if (prefixModelIndex.isValid()) {
318 this->setExpanded(prefixModelIndex, true);
322 void ResourceView::removeFiles(int prefixIndex, int firstFileIndex, int lastFileIndex)
324 Q_ASSERT(prefixIndex >= 0 && prefixIndex < m_qrcModel->rowCount(QModelIndex()));
325 const QModelIndex prefixModelIndex = m_qrcModel->index(prefixIndex, 0, QModelIndex());
326 Q_ASSERT(prefixModelIndex != QModelIndex());
327 Q_ASSERT(firstFileIndex >= 0 && firstFileIndex < m_qrcModel->rowCount(prefixModelIndex));
328 Q_ASSERT(lastFileIndex >= 0 && lastFileIndex < m_qrcModel->rowCount(prefixModelIndex));
330 for (int i = lastFileIndex; i >= firstFileIndex; i--) {
331 const QModelIndex index = m_qrcModel->index(i, 0, prefixModelIndex);
332 delete removeEntry(index);
336 void ResourceView::enableContextMenu(bool enable)
339 connect(this, SIGNAL(clicked(const QModelIndex &)),
340 this, SLOT(popupMenu(const QModelIndex &)));
342 disconnect(this, SIGNAL(clicked(const QModelIndex &)),
343 this, SLOT(popupMenu(const QModelIndex &)));
347 void ResourceView::setupMenu()
349 m_viewMenu = new QMenu(this);
351 m_addFile = m_viewMenu->addAction(tr("Add Files..."), this, SIGNAL(addFiles()));
352 m_editAlias = m_viewMenu->addAction(tr("Change Alias..."), this, SLOT(onEditAlias()));
353 m_addPrefix = m_viewMenu->addAction(tr("Add Prefix..."), this, SLOT(addPrefix()));
354 m_editPrefix = m_viewMenu->addAction(tr("Change Prefix..."), this, SLOT(onEditPrefix()));
355 m_editLang = m_viewMenu->addAction(tr("Change Language..."), this, SLOT(onEditLang()));
356 m_viewMenu->addSeparator();
357 m_removeItem = m_viewMenu->addAction(tr("Remove Item"), this, SLOT(removeItem()));
359 m_addFile = m_viewMenu->addAction(tr("Add Files..."), this, SLOT(onAddFiles()));
360 m_editAlias = m_viewMenu->addAction(tr("Change Alias..."), this, SLOT(onEditAlias()));
361 m_addPrefix = m_viewMenu->addAction(tr("Add Prefix..."), this, SIGNAL(addPrefixTriggered()));
362 m_editPrefix = m_viewMenu->addAction(tr("Change Prefix..."), this, SLOT(onEditPrefix()));
363 m_editLang = m_viewMenu->addAction(tr("Change Language..."), this, SLOT(onEditLang()));
364 m_viewMenu->addSeparator();
365 m_removeItem = m_viewMenu->addAction(tr("Remove Item"), this, SIGNAL(removeItem()));
368 void ResourceView::mouseReleaseEvent(QMouseEvent *e)
370 m_releasePos = e->globalPos();
371 if (e->button() != Qt::RightButton)
372 m_releasePos = QPoint();
374 QTreeView::mouseReleaseEvent(e);
377 void ResourceView::keyPressEvent(QKeyEvent *e)
379 if (e->key() == Qt::Key_Delete)
382 QTreeView::keyPressEvent(e);
385 void ResourceView::popupMenu(const QModelIndex &index)
387 if (!m_releasePos.isNull()) {
388 m_addFile->setEnabled(index.isValid());
389 m_editPrefix->setEnabled(index.isValid());
390 m_editLang->setEnabled(index.isValid());
391 m_removeItem->setEnabled(index.isValid());
393 m_viewMenu->popup(m_releasePos);
397 QModelIndex ResourceView::addPrefix()
399 const QModelIndex idx = m_qrcModel->addNewPrefix();
400 selectionModel()->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect);
404 QStringList ResourceView::fileNamesToAdd()
406 return QFileDialog::getOpenFileNames(this, tr("Open File"),
407 m_qrcModel->absolutePath(QString()),
408 tr("All files (*)"));
411 void ResourceView::onAddFiles()
413 emit addFilesTriggered(currentPrefix());
416 void ResourceView::addFiles(QStringList fileList, const QModelIndex &index)
418 if (fileList.isEmpty())
420 QModelIndex idx = index;
421 if (!m_qrcModel->hasChildren(QModelIndex())) {
426 idx = m_qrcModel->addFiles(idx, fileList);
429 const QModelIndex preindex = m_qrcModel->prefixIndex(index);
430 setExpanded(preindex, true);
431 selectionModel()->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect);
432 QString prefix, file;
433 m_qrcModel->getItem(preindex, prefix, file);
434 // XXX emit filesAdded(prefix, fileList);
438 void ResourceView::addFile(const QString &prefix, const QString &file)
440 const QModelIndex preindex = m_qrcModel->getIndex(prefix, QString());
441 addFiles(QStringList(file), preindex);
445 void ResourceView::removeItem()
447 const QModelIndex index = currentIndex();
448 m_qrcModel->deleteItem(index);
451 void ResourceView::removeFile(const QString &prefix, const QString &file)
453 const QModelIndex index = m_qrcModel->getIndex(prefix, file);
455 m_qrcModel->deleteItem(index);
458 void ResourceView::onEditPrefix()
460 QModelIndex index = currentIndex();
464 void ResourceView::onEditLang()
466 const QModelIndex index = currentIndex();
470 void ResourceView::onEditAlias()
472 const QModelIndex index = currentIndex();
476 bool ResourceView::load(const QString &fileName)
478 const QFileInfo fi(fileName);
479 m_qrcModel->setFileName(fi.absoluteFilePath());
484 return m_qrcModel->reload();
487 bool ResourceView::save()
489 return m_qrcModel->save();
492 void ResourceView::changePrefix(const QModelIndex &index)
495 const QModelIndex preindex = m_qrcModel->prefixIndex(index);
497 QString prefixBefore;
499 m_qrcModel->getItem(preindex, prefixBefore, dummy);
501 QString const prefixAfter = QInputDialog::getText(this, tr("Change Prefix"), tr("Input prefix:"),
502 QLineEdit::Normal, prefixBefore, &ok);
505 addUndoCommand(preindex, PrefixProperty, prefixBefore, prefixAfter);
508 void ResourceView::changeLang(const QModelIndex &index)
511 const QModelIndex preindex = m_qrcModel->prefixIndex(index);
513 QString const langBefore = m_qrcModel->lang(preindex);
514 QString const langAfter = QInputDialog::getText(this, tr("Change Language"), tr("Language:"),
515 QLineEdit::Normal, langBefore, &ok);
518 addUndoCommand(preindex, LanguageProperty, langBefore, langAfter);
522 void ResourceView::changeAlias(const QModelIndex &index)
524 if (!index.parent().isValid())
529 QString const aliasBefore = m_qrcModel->alias(index);
530 QString const aliasAfter = QInputDialog::getText(this, tr("Change File Alias"), tr("Alias:"),
531 QLineEdit::Normal, aliasBefore, &ok);
534 addUndoCommand(index, AliasProperty, aliasBefore, aliasAfter);
537 QString ResourceView::currentAlias() const
539 const QModelIndex current = currentIndex();
540 if (!current.isValid())
542 return m_qrcModel->alias(current);
545 QString ResourceView::currentPrefix() const
547 const QModelIndex current = currentIndex();
548 if (!current.isValid())
550 const QModelIndex preindex = m_qrcModel->prefixIndex(current);
551 QString prefix, file;
552 m_qrcModel->getItem(preindex, prefix, file);
556 QString ResourceView::currentLanguage() const
558 const QModelIndex current = currentIndex();
559 if (!current.isValid())
561 const QModelIndex preindex = m_qrcModel->prefixIndex(current);
562 return m_qrcModel->lang(preindex);
565 QString ResourceView::getCurrentValue(NodeProperty property) const
568 case AliasProperty: return currentAlias();
569 case PrefixProperty: return currentPrefix();
570 case LanguageProperty: return currentLanguage();
571 default: Q_ASSERT(false); return QString(); // Kill warning
575 void ResourceView::changeValue(const QModelIndex &nodeIndex, NodeProperty property,
576 const QString &value)
579 case AliasProperty: m_qrcModel->changeAlias(nodeIndex, value); return;
580 case PrefixProperty: m_qrcModel->changePrefix(nodeIndex, value); return;
581 case LanguageProperty: m_qrcModel->changeLang(nodeIndex, value); return;
582 default: Q_ASSERT(false);
586 void ResourceView::advanceMergeId()
593 void ResourceView::addUndoCommand(const QModelIndex &nodeIndex, NodeProperty property,
594 const QString &before, const QString &after)
596 QUndoCommand * const command = new ModifyPropertyCommand(this, nodeIndex, property,
597 m_mergeId, before, after);
598 m_history->push(command);
601 void ResourceView::setCurrentAlias(const QString &before, const QString &after)
603 const QModelIndex current = currentIndex();
604 if (!current.isValid())
607 addUndoCommand(current, AliasProperty, before, after);
610 void ResourceView::setCurrentPrefix(const QString &before, const QString &after)
612 const QModelIndex current = currentIndex();
613 if (!current.isValid())
615 const QModelIndex preindex = m_qrcModel->prefixIndex(current);
617 addUndoCommand(preindex, PrefixProperty, before, after);
620 void ResourceView::setCurrentLanguage(const QString &before, const QString &after)
622 const QModelIndex current = currentIndex();
623 if (!current.isValid())
625 const QModelIndex preindex = m_qrcModel->prefixIndex(current);
627 addUndoCommand(preindex, LanguageProperty, before, after);
630 bool ResourceView::isPrefix(const QModelIndex &index) const
632 if (!index.isValid())
634 const QModelIndex preindex = m_qrcModel->prefixIndex(index);
635 if (preindex == index)
640 QString ResourceView::fileName() const
642 return m_qrcModel->fileName();
645 void ResourceView::setFileName(const QString &fileName)
647 m_qrcModel->setFileName(fileName);
650 void ResourceView::setResourceDragEnabled(bool e)
653 m_qrcModel->setResourceDragEnabled(e);
656 bool ResourceView::resourceDragEnabled() const
658 return m_qrcModel->resourceDragEnabled();
661 } // namespace SharedTools