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 "resourceview.h"
35 #include "undocommands_p.h"
37 #include <QtCore/QDebug>
39 #include <QtGui/QAction>
40 #include <QtGui/QApplication>
41 #include <QtGui/QFileDialog>
42 #include <QtGui/QHeaderView>
43 #include <QtGui/QInputDialog>
44 #include <QtGui/QMenu>
45 #include <QtGui/QMouseEvent>
46 #include <QtGui/QUndoStack>
48 namespace SharedTools {
51 \class FileEntryBackup
55 class FileEntryBackup : public EntryBackup
62 FileEntryBackup(ResourceModel &model, int prefixIndex, int fileIndex,
63 const QString &fileName, const QString &alias)
64 : EntryBackup(model, prefixIndex, fileName), m_fileIndex(fileIndex),
69 void FileEntryBackup::restore() const
71 m_model->insertFile(m_prefixIndex, m_fileIndex, m_name, m_alias);
75 \class PrefixEntryBackup
77 Backups a prefix node including children.
79 class PrefixEntryBackup : public EntryBackup
83 QList<FileEntryBackup> m_files;
86 PrefixEntryBackup(ResourceModel &model, int prefixIndex, const QString &prefix,
87 const QString &language, const QList<FileEntryBackup> &files)
88 : EntryBackup(model, prefixIndex, prefix), m_language(language), m_files(files) { }
92 void PrefixEntryBackup::restore() const
94 m_model->insertPrefix(m_prefixIndex, m_name, m_language);
95 foreach (const FileEntryBackup &entry, m_files) {
102 class RelativeResourceModel : public ResourceModel
105 RelativeResourceModel(const ResourceFile &resource_file, QObject *parent = 0);
107 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
109 if (!index.isValid())
112 void const * const internalPointer = index.internalPointer();
114 if ((role == Qt::DisplayRole) && (internalPointer != NULL))
115 return ResourceModel::data(index, Qt::ToolTipRole);
117 return ResourceModel::data(index, role);
120 void setResourceDragEnabled(bool e) { m_resourceDragEnabled = e; }
121 bool resourceDragEnabled() const { return m_resourceDragEnabled; }
123 virtual Qt::ItemFlags flags(const QModelIndex &index) const;
125 EntryBackup * removeEntry(const QModelIndex &index);
128 bool m_resourceDragEnabled;
131 RelativeResourceModel::RelativeResourceModel(const ResourceFile &resource_file, QObject *parent) :
132 ResourceModel(resource_file, parent),
133 m_resourceDragEnabled(false)
137 Qt::ItemFlags RelativeResourceModel::flags(const QModelIndex &index) const
139 Qt::ItemFlags rc = ResourceModel::flags(index);
140 if ((rc & Qt::ItemIsEnabled) && m_resourceDragEnabled)
141 rc |= Qt::ItemIsDragEnabled;
145 EntryBackup * RelativeResourceModel::removeEntry(const QModelIndex &index)
147 const QModelIndex prefixIndex = this->prefixIndex(index);
148 const bool isPrefixNode = (prefixIndex == index);
150 // Create backup, remove, return backup
153 QString prefixBackup;
154 getItem(index, prefixBackup, dummy);
155 const QString languageBackup = lang(index);
156 const int childCount = rowCount(index);
157 QList<FileEntryBackup> filesBackup;
158 for (int i = 0; i < childCount; i++) {
159 const QModelIndex childIndex = this->index(i, 0, index);
160 const QString fileNameBackup = file(childIndex);
161 const QString aliasBackup = alias(childIndex);
162 FileEntryBackup entry(*this, index.row(), i, fileNameBackup, aliasBackup);
163 filesBackup << entry;
166 return new PrefixEntryBackup(*this, index.row(), prefixBackup, languageBackup, filesBackup);
168 const QString fileNameBackup = file(index);
169 const QString aliasBackup = alias(index);
171 return new FileEntryBackup(*this, prefixIndex.row(), index.row(), fileNameBackup, aliasBackup);
175 } // namespace Internal
177 ResourceView::ResourceView(QUndoStack *history, QWidget *parent) :
179 m_qrcModel(new Internal::RelativeResourceModel(m_qrcFile, this)),
187 m_defaultAddFile(false),
192 setModel(m_qrcModel);
196 connect(m_qrcModel, SIGNAL(dirtyChanged(bool)),
197 this, SIGNAL(dirtyChanged(bool)));
201 setDefaultAddFileEnabled(true);
202 enableContextMenu(true);
205 ResourceView::~ResourceView()
209 bool ResourceView::isDirty() const
211 return m_qrcModel->dirty();
214 void ResourceView::setDirty(bool dirty)
216 m_qrcModel->setDirty(dirty);
219 void ResourceView::setDefaultAddFileEnabled(bool enable)
221 m_defaultAddFile = enable;
224 bool ResourceView::defaultAddFileEnabled() const
226 return m_defaultAddFile;
229 void ResourceView::findSamePlacePostDeletionModelIndex(int &row, QModelIndex &parent) const
232 // - Make selection stay on same Y level
233 // - Enable user to hit delete several times in row
234 const bool hasLowerBrother = m_qrcModel->hasIndex(row + 1,
236 if (hasLowerBrother) {
237 // First or mid child -> lower brother
243 // --> return unmodified
245 if (parent == QModelIndex()) {
248 // Last and only prefix node
253 parent = QModelIndex();
255 const QModelIndex upperBrother = m_qrcModel->index(row - 1,
257 if (m_qrcModel->hasChildren(upperBrother)) {
261 row = m_qrcModel->rowCount(upperBrother) - 1;
262 parent = upperBrother;
272 const bool hasPrefixBelow = m_qrcModel->hasIndex(parent.row() + 1,
273 parent.column(), QModelIndex());
274 if (hasPrefixBelow) {
275 // Last child or parent with lower brother -> lower brother of parent
280 row = parent.row() + 1;
281 parent = QModelIndex();
283 const bool onlyChild = row == 0;
285 // Last and only child of last parent -> parent
289 parent = m_qrcModel->parent(parent);
291 // Last child of last parent -> upper brother
302 EntryBackup * ResourceView::removeEntry(const QModelIndex &index)
304 Q_ASSERT(m_qrcModel);
305 return m_qrcModel->removeEntry(index);
308 void ResourceView::addFiles(int prefixIndex, const QStringList &fileNames, int cursorFile,
309 int &firstFile, int &lastFile)
311 Q_ASSERT(m_qrcModel);
312 m_qrcModel->addFiles(prefixIndex, fileNames, cursorFile, firstFile, lastFile);
314 // Expand prefix node
315 const QModelIndex prefixModelIndex = m_qrcModel->index(prefixIndex, 0, QModelIndex());
316 if (prefixModelIndex.isValid()) {
317 this->setExpanded(prefixModelIndex, true);
321 void ResourceView::removeFiles(int prefixIndex, int firstFileIndex, int lastFileIndex)
323 Q_ASSERT(prefixIndex >= 0 && prefixIndex < m_qrcModel->rowCount(QModelIndex()));
324 const QModelIndex prefixModelIndex = m_qrcModel->index(prefixIndex, 0, QModelIndex());
325 Q_ASSERT(prefixModelIndex != QModelIndex());
326 Q_ASSERT(firstFileIndex >= 0 && firstFileIndex < m_qrcModel->rowCount(prefixModelIndex));
327 Q_ASSERT(lastFileIndex >= 0 && lastFileIndex < m_qrcModel->rowCount(prefixModelIndex));
329 for (int i = lastFileIndex; i >= firstFileIndex; i--) {
330 const QModelIndex index = m_qrcModel->index(i, 0, prefixModelIndex);
331 delete removeEntry(index);
335 void ResourceView::enableContextMenu(bool enable)
338 connect(this, SIGNAL(clicked(const QModelIndex &)),
339 this, SLOT(popupMenu(const QModelIndex &)));
341 disconnect(this, SIGNAL(clicked(const QModelIndex &)),
342 this, SLOT(popupMenu(const QModelIndex &)));
346 void ResourceView::setupMenu()
348 m_viewMenu = new QMenu(this);
350 m_addFile = m_viewMenu->addAction(tr("Add Files..."), this, SIGNAL(addFiles()));
351 m_editAlias = m_viewMenu->addAction(tr("Change Alias..."), this, SLOT(onEditAlias()));
352 m_addPrefix = m_viewMenu->addAction(tr("Add Prefix..."), this, SLOT(addPrefix()));
353 m_editPrefix = m_viewMenu->addAction(tr("Change Prefix..."), this, SLOT(onEditPrefix()));
354 m_editLang = m_viewMenu->addAction(tr("Change Language..."), this, SLOT(onEditLang()));
355 m_viewMenu->addSeparator();
356 m_removeItem = m_viewMenu->addAction(tr("Remove Item"), this, SLOT(removeItem()));
358 m_addFile = m_viewMenu->addAction(tr("Add Files..."), this, SLOT(onAddFiles()));
359 m_editAlias = m_viewMenu->addAction(tr("Change Alias..."), this, SLOT(onEditAlias()));
360 m_addPrefix = m_viewMenu->addAction(tr("Add Prefix..."), this, SIGNAL(addPrefixTriggered()));
361 m_editPrefix = m_viewMenu->addAction(tr("Change Prefix..."), this, SLOT(onEditPrefix()));
362 m_editLang = m_viewMenu->addAction(tr("Change Language..."), this, SLOT(onEditLang()));
363 m_viewMenu->addSeparator();
364 m_removeItem = m_viewMenu->addAction(tr("Remove Item"), this, SIGNAL(removeItem()));
367 void ResourceView::mouseReleaseEvent(QMouseEvent *e)
369 m_releasePos = e->globalPos();
370 if (e->button() != Qt::RightButton)
371 m_releasePos = QPoint();
373 QTreeView::mouseReleaseEvent(e);
376 void ResourceView::keyPressEvent(QKeyEvent *e)
378 if (e->key() == Qt::Key_Delete)
381 QTreeView::keyPressEvent(e);
384 void ResourceView::popupMenu(const QModelIndex &index)
386 if (!m_releasePos.isNull()) {
387 m_addFile->setEnabled(index.isValid());
388 m_editPrefix->setEnabled(index.isValid());
389 m_editLang->setEnabled(index.isValid());
390 m_removeItem->setEnabled(index.isValid());
392 m_viewMenu->popup(m_releasePos);
396 QModelIndex ResourceView::addPrefix()
398 const QModelIndex idx = m_qrcModel->addNewPrefix();
399 selectionModel()->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect);
403 QStringList ResourceView::fileNamesToAdd()
405 return QFileDialog::getOpenFileNames(this, tr("Open File"),
406 m_qrcModel->absolutePath(QString()),
407 tr("All files (*)"));
410 void ResourceView::onAddFiles()
412 emit addFilesTriggered(currentPrefix());
415 void ResourceView::addFiles(QStringList fileList, const QModelIndex &index)
417 if (fileList.isEmpty())
419 QModelIndex idx = index;
420 if (!m_qrcModel->hasChildren(QModelIndex())) {
425 idx = m_qrcModel->addFiles(idx, fileList);
428 const QModelIndex preindex = m_qrcModel->prefixIndex(index);
429 setExpanded(preindex, true);
430 selectionModel()->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect);
431 QString prefix, file;
432 m_qrcModel->getItem(preindex, prefix, file);
433 // XXX emit filesAdded(prefix, fileList);
437 void ResourceView::addFile(const QString &prefix, const QString &file)
439 const QModelIndex preindex = m_qrcModel->getIndex(prefix, QString());
440 addFiles(QStringList(file), preindex);
444 void ResourceView::removeItem()
446 const QModelIndex index = currentIndex();
447 m_qrcModel->deleteItem(index);
450 void ResourceView::removeFile(const QString &prefix, const QString &file)
452 const QModelIndex index = m_qrcModel->getIndex(prefix, file);
454 m_qrcModel->deleteItem(index);
457 void ResourceView::onEditPrefix()
459 QModelIndex index = currentIndex();
463 void ResourceView::onEditLang()
465 const QModelIndex index = currentIndex();
469 void ResourceView::onEditAlias()
471 const QModelIndex index = currentIndex();
475 bool ResourceView::load(const QString &fileName)
477 const QFileInfo fi(fileName);
478 m_qrcModel->setFileName(fi.absoluteFilePath());
483 return m_qrcModel->reload();
486 bool ResourceView::save()
488 return m_qrcModel->save();
491 void ResourceView::changePrefix(const QModelIndex &index)
494 const QModelIndex preindex = m_qrcModel->prefixIndex(index);
496 QString prefixBefore;
498 m_qrcModel->getItem(preindex, prefixBefore, dummy);
500 QString const prefixAfter = QInputDialog::getText(this, tr("Change Prefix"), tr("Input prefix:"),
501 QLineEdit::Normal, prefixBefore, &ok);
504 addUndoCommand(preindex, PrefixProperty, prefixBefore, prefixAfter);
507 void ResourceView::changeLang(const QModelIndex &index)
510 const QModelIndex preindex = m_qrcModel->prefixIndex(index);
512 QString const langBefore = m_qrcModel->lang(preindex);
513 QString const langAfter = QInputDialog::getText(this, tr("Change Language"), tr("Language:"),
514 QLineEdit::Normal, langBefore, &ok);
517 addUndoCommand(preindex, LanguageProperty, langBefore, langAfter);
521 void ResourceView::changeAlias(const QModelIndex &index)
523 if (!index.parent().isValid())
528 QString const aliasBefore = m_qrcModel->alias(index);
529 QString const aliasAfter = QInputDialog::getText(this, tr("Change File Alias"), tr("Alias:"),
530 QLineEdit::Normal, aliasBefore, &ok);
533 addUndoCommand(index, AliasProperty, aliasBefore, aliasAfter);
536 QString ResourceView::currentAlias() const
538 const QModelIndex current = currentIndex();
539 if (!current.isValid())
541 return m_qrcModel->alias(current);
544 QString ResourceView::currentPrefix() const
546 const QModelIndex current = currentIndex();
547 if (!current.isValid())
549 const QModelIndex preindex = m_qrcModel->prefixIndex(current);
550 QString prefix, file;
551 m_qrcModel->getItem(preindex, prefix, file);
555 QString ResourceView::currentLanguage() const
557 const QModelIndex current = currentIndex();
558 if (!current.isValid())
560 const QModelIndex preindex = m_qrcModel->prefixIndex(current);
561 return m_qrcModel->lang(preindex);
564 QString ResourceView::getCurrentValue(NodeProperty property) const
567 case AliasProperty: return currentAlias();
568 case PrefixProperty: return currentPrefix();
569 case LanguageProperty: return currentLanguage();
570 default: Q_ASSERT(false); return QString(); // Kill warning
574 void ResourceView::changeValue(const QModelIndex &nodeIndex, NodeProperty property,
575 const QString &value)
578 case AliasProperty: m_qrcModel->changeAlias(nodeIndex, value); return;
579 case PrefixProperty: m_qrcModel->changePrefix(nodeIndex, value); return;
580 case LanguageProperty: m_qrcModel->changeLang(nodeIndex, value); return;
581 default: Q_ASSERT(false);
585 void ResourceView::advanceMergeId()
592 void ResourceView::addUndoCommand(const QModelIndex &nodeIndex, NodeProperty property,
593 const QString &before, const QString &after)
595 QUndoCommand * const command = new ModifyPropertyCommand(this, nodeIndex, property,
596 m_mergeId, before, after);
597 m_history->push(command);
600 void ResourceView::setCurrentAlias(const QString &before, const QString &after)
602 const QModelIndex current = currentIndex();
603 if (!current.isValid())
606 addUndoCommand(current, AliasProperty, before, after);
609 void ResourceView::setCurrentPrefix(const QString &before, const QString &after)
611 const QModelIndex current = currentIndex();
612 if (!current.isValid())
614 const QModelIndex preindex = m_qrcModel->prefixIndex(current);
616 addUndoCommand(preindex, PrefixProperty, before, after);
619 void ResourceView::setCurrentLanguage(const QString &before, const QString &after)
621 const QModelIndex current = currentIndex();
622 if (!current.isValid())
624 const QModelIndex preindex = m_qrcModel->prefixIndex(current);
626 addUndoCommand(preindex, LanguageProperty, before, after);
629 bool ResourceView::isPrefix(const QModelIndex &index) const
631 if (!index.isValid())
633 const QModelIndex preindex = m_qrcModel->prefixIndex(index);
634 if (preindex == index)
639 QString ResourceView::fileName() const
641 return m_qrcModel->fileName();
644 void ResourceView::setFileName(const QString &fileName)
646 m_qrcModel->setFileName(fileName);
649 void ResourceView::setResourceDragEnabled(bool e)
652 m_qrcModel->setResourceDragEnabled(e);
655 bool ResourceView::resourceDragEnabled() const
657 return m_qrcModel->resourceDragEnabled();
660 } // namespace SharedTools