1 // Copyright (c) 2012 Dennco Project
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, either version 3 of the License, or
6 // (at your option) any later version.
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
13 // You should have received a copy of the GNU General Public License
14 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 // Created by tkawata on Sep-30, 2012.
19 #include "dctreeviewwidget.h"
21 #include "dccreator.h"
25 #include "dccontainer.h"
26 #include "command/dccommand.h"
28 #include "dialog/dcinputnewpagenamedialog.h"
29 #include "dialog/dcaddcellcodeclassdialog.h"
30 #include "dialog/dcaddcelldialog.h"
32 #include "uieditor/dcuieditor.h"
33 #include "propertyeditor/dcpropertyeditor.h"
36 #include <QItemSelectionModel>
37 #include <QModelIndexList>
39 static DCTreeViewWidget *s_treeViewWidget = NULL;
41 static bool IsIndexUnderContainer(const QFileSystemModel *model, QModelIndex index, bool includesContainerDir = false)
45 if (!includesContainerDir)
48 index = index.parent();
51 while (index.isValid())
53 if (model->fileName(index) == "Container"
54 && index.parent().isValid()
55 && index.parent() == model->index(model->rootPath()))
59 index = index.parent();
64 class FileIconProvider : public QFileIconProvider
70 pageIcon(":/pageIcon.png"),
71 folderIcon(":/folderIcon.png")
75 virtual ~FileIconProvider()
79 virtual QIcon icon(const QFileInfo &info) const
81 if (info.completeSuffix() == "xhtml")
85 else if (info.isDir())
90 return QFileIconProvider::icon(info);
96 DCTreeViewModel::DCTreeViewModel(DCCreator *creator)
99 setIconProvider(new FileIconProvider);
102 DCTreeViewModel::~DCTreeViewModel()
107 bool DCTreeViewModel::setData(const QModelIndex &index, const QVariant &value, int role)
110 if (role == Qt::EditRole)
112 QString oldFilePath = filePath(index);
113 QString oldFileName = fileName(index);
114 QString baseDirPath = oldFilePath.left(oldFilePath.length()-oldFileName.length());
116 if (QFileInfo(oldFilePath).isDir() && IsIndexUnderContainer(this, index))
118 QString newFilePath = baseDirPath + value.toString();
119 d_creator->doCommandRenameDirectory(this, oldFilePath, newFilePath);
125 r = QFileSystemModel::setData(index, value, role);
130 DCTreeViewWidget::DCTreeViewWidget(QWidget *parent, DCCreator *creator) :
131 QTreeView(parent), d_creator(creator), d_fileSystemModel(creator), d_scene(NULL), d_inSelectionChange(false), d_pendingSelectionPath("")
133 setModel(&d_fileSystemModel);
134 d_fileSystemModel.setReadOnly(false);
135 connect(d_creator, SIGNAL(contentRootPathChanged(const void*, QString)), this, SLOT(contentRootPathChanged(const void*, QString)));
136 connect(d_creator, SIGNAL(sceneChanged(const void*, DCScene*)), this, SLOT(sceneChanged(const void*, DCScene*)));
137 connect(d_creator, SIGNAL(sceneSelectedPageChanged(const void*, const DCScene*)), this, SLOT(selectedPageChanged(const void*, const DCScene*)));
138 connect(d_creator, SIGNAL(destroyed(QObject*)), this, SLOT(creatorDestroyed()));
140 connect(&d_fileSystemModel, SIGNAL(directoryLoaded(QString)), this, SLOT(directoryLoaded(QString)));
141 connect(&d_fileSystemModel, SIGNAL(rowsRemoved(const QModelIndex, int, int)), this, SLOT(rowsRemoved()));
142 setContextMenuPolicy(Qt::CustomContextMenu);
143 connect(this, SIGNAL(customContextMenuRequested(const QPoint&)),this, SLOT(doContextMenu(const QPoint&)));
144 connect(d_creator, SIGNAL(commandExecuted(const QUndoCommand*)), this, SLOT(commandExecuted(const QUndoCommand*)));
145 s_treeViewWidget = this;
148 DCTreeViewWidget::~DCTreeViewWidget()
152 d_creator->disconnect(this);
157 bool DCTreeViewWidget::addDirectory(const QString &path)
161 if (s_treeViewWidget)
163 QModelIndex index = s_treeViewWidget->d_fileSystemModel.index(path);
166 QString newDirName = "NewFolder";
168 while(QDir(path + "/" + newDirName).exists())
172 QTextStream(&newDirName) << "NewFolder(" << i << ")";
174 QModelIndex newDirIndex = s_treeViewWidget->d_fileSystemModel.mkdir(index, newDirName);
175 if (newDirIndex.isValid())
178 s_treeViewWidget->setCurrentIndex(newDirIndex);
190 bool DCTreeViewWidget::removeDirectory(const QString &path)
194 if (s_treeViewWidget)
198 QFileInfoList list = dir.entryInfoList(QDir::NoDot | QDir::NoDotDot | QDir::AllEntries);
200 for (int i = 0; i < list.length(); i++)
202 QFileInfo info = list.at(i);
205 removeDirectory(info.absoluteFilePath());
209 QModelIndex index = s_treeViewWidget->d_fileSystemModel.index(info.absoluteFilePath());
212 //hack for prevening auto selection happing by removing row.
213 s_treeViewWidget->d_inSelectionChange = true;
214 s_treeViewWidget->d_fileSystemModel.remove(index);
219 QModelIndex index = s_treeViewWidget->d_fileSystemModel.index(path);
222 //hack for prevening auto selection happing by removing row.
223 s_treeViewWidget->d_inSelectionChange = true;
224 r = s_treeViewWidget->d_fileSystemModel.rmdir(index);
235 bool DCTreeViewWidget::removeFile(const QString &path)
239 if (s_treeViewWidget)
241 QModelIndex index = s_treeViewWidget->d_fileSystemModel.index(path);
242 if (index.isValid() && s_treeViewWidget->d_fileSystemModel.fileInfo(index).isFile())
244 //hack for prevening auto selection happing by removing row.
245 s_treeViewWidget->d_inSelectionChange = true;
246 r = s_treeViewWidget->d_fileSystemModel.remove(index);
257 void DCTreeViewWidget::selectWhenFilePathAdded(const QString &path)
259 if (s_treeViewWidget)
261 s_treeViewWidget->d_pendingSelectionPath = path;
266 void DCTreeViewWidget::doContextMenu(const QPoint &pos)
268 QPoint globalPos = mapToGlobal(pos);
270 QFileSystemModel *fileModel = dynamic_cast<QFileSystemModel*>(model());
273 bool showMenu = false;
275 QAction *addDictionaryAction = NULL;
276 QAction *addPageAction = NULL;
277 QAction *addCellAction = NULL;
278 QAction *addCellCodeClassAction = NULL;
279 QAction *renamePageAction = NULL;
280 QAction *removeDirectoryAction = NULL;
281 QAction *removePageAction = NULL;
288 QModelIndexList indexes = selectedIndexes();
289 if (indexes.length() == 0)
291 addDictionaryAction = menu.addAction(tr("Add folder"));
292 index = fileModel->index(fileModel->rootPath() + "/Container");
295 else if (indexes.length() > 0)
297 index = indexes.at(0);
298 isDir = d_fileSystemModel.isDir(index);
299 isPage = !isDir && d_fileSystemModel.fileInfo(index).completeSuffix() == "xhtml";
303 addDictionaryAction = menu.addAction(tr("Add folder"));
304 if (IsIndexUnderContainer(&d_fileSystemModel, index, true))
306 addPageAction = menu.addAction(tr("Add page..."));
308 if (fileModel->flags(index) & Qt::ItemIsEditable && !index.child(0,0).isValid())
310 removeDirectoryAction = menu.addAction(tr("Remove"));
318 addCellAction = menu.addAction(tr("Add cell ..."));
319 addCellCodeClassAction = menu.addAction(tr("Add cell code class ..."));
321 renamePageAction = menu.addAction(tr("Rename"));
322 removePageAction = menu.addAction(tr("Remove..."));
325 addDictionaryAction = menu.addAction(tr("Add folder"));
332 DCContainer *container = d_creator->getCurrentContainer();
336 QString containerBasedPath;
340 containerBasedPath = container->sysFilePathToContainerBasedPath(fileModel->filePath(index));
343 QAction* selectedItem = menu.exec(globalPos);
346 if (selectedItem == addDictionaryAction)
349 d_creator->doCommandAddDirectory(this, fileModel->filePath(index));
351 else if (selectedItem == removeDirectoryAction)
354 d_creator->doCommandRemoveDirectory(this, fileModel->filePath(index));
356 else if (selectedItem == addPageAction)
360 if (containerBasedPath.length() >= 1)
362 DCInputNewPageNameDialog dialog(fileModel->filePath(index), tr("Add new page"));
365 QString pageName = dialog.getName();
366 if (pageName.length() > 0)
368 QString pathName = containerBasedPath;
369 if (containerBasedPath.length()>1)
370 pathName.append("/");
371 pathName.append(pageName);
372 d_creator->doCommandAddPage(this, pathName);
378 else if (selectedItem == renamePageAction)
382 if (containerBasedPath.length() >= 1)
384 QFileInfo fileInfo = fileModel->filePath(index);
385 QString oldName = fileInfo.fileName().left(fileInfo.fileName().length() - fileInfo.completeSuffix().length() - 1);
386 DCInputNewPageNameDialog dialog(fileInfo.absolutePath(), tr("Rename"), oldName);
389 QString pageName = dialog.getName();
390 if (pageName.length() > 0)
392 QString pathName = container->sysFilePathToContainerBasedPath(fileInfo.absolutePath() + "/" + pageName);
393 d_creator->doCommandMovePage(this, containerBasedPath, pathName);
399 else if (selectedItem == removePageAction)
403 bool doExecute = true;
404 DCVCPage *page = d_scene->getPage(containerBasedPath.toStdString());
405 if (page->getCells()->length() > 0 || page->getCellCodeClasses()->length() > 0)
407 QMessageBox::StandardButton button = QMessageBox::warning(this,
409 tr("This Page has cells / cellcodes. Those cells / cell codes will be removed"),
410 QMessageBox::Cancel | QMessageBox::Ok, QMessageBox::Cancel);
412 doExecute = (button == QMessageBox::Ok);
416 d_creator->doCommandRemovePage(this, page);
420 else if (selectedItem == addCellAction )
424 DCAddCellDialog dialog(container, d_creator, containerBasedPath,0,0);
428 else if (selectedItem == addCellCodeClassAction)
432 DCAddCellCodeClassDialog dialog(container, d_creator, containerBasedPath);
443 void DCTreeViewWidget::showEvent(QShowEvent *event)
445 setColumnHidden(1,true);
446 setColumnHidden(2,true);
447 setColumnHidden(3,true);
449 QTreeView::showEvent(event);
452 void DCTreeViewWidget::mouseDoubleClickEvent(QMouseEvent *event)
454 QModelIndex index = currentIndex();
457 bool isDir = d_fileSystemModel.isDir(index);
460 bool isProprty = false;
464 if (d_fileSystemModel.fileInfo(index).completeSuffix() == "xhtml")
469 else if (d_fileSystemModel.fileInfo(index).completeSuffix() == "htm")
473 else if (d_fileSystemModel.fileInfo(index).completeSuffix() == "html")
477 else if (d_fileSystemModel.fileName(index) == "property.xml"
478 && index.parent() == d_fileSystemModel.index(d_fileSystemModel.rootPath()))
484 if (!IsIndexUnderContainer(&d_fileSystemModel, index))
488 DCUIEditor *editor = DCUIEditor::getEditor();
489 editor->startEditing(d_fileSystemModel.filePath(index));
493 DCPropertyEditor *editor = DCPropertyEditor::getEditor();
494 editor->startEditing(d_fileSystemModel.filePath(index));
502 QTreeView::mouseDoubleClickEvent(event);
506 d_creator->changePersMode(this, DCCreator::DC_PERSMODE_PAGEEDIT);
512 QTreeView::mouseDoubleClickEvent(event);
516 void DCTreeViewWidget::rowsInserted(const QModelIndex &parent, int start, int end)
518 if (d_pendingSelectionPath.length() > 0)
520 QModelIndex index = d_fileSystemModel.index(d_pendingSelectionPath);
524 d_pendingSelectionPath = "";
525 QItemSelectionModel *selection = selectionModel();
526 selection->select(index, QItemSelectionModel::Select);
531 void DCTreeViewWidget::rowsRemoved()
533 //hack for prevening auto selection happing by removing row.
534 d_inSelectionChange = false;
537 void DCTreeViewWidget::creatorDestroyed()
542 void DCTreeViewWidget::contentRootPathChanged(const void *requester, QString rootPath)
544 QModelIndex idx = d_fileSystemModel.setRootPath(rootPath);
545 QStringList nameFilters;
546 nameFilters << "*.xhtml";
547 nameFilters << "property.xml";
548 nameFilters << "data.db";
549 nameFilters << "*.html";
550 nameFilters << "*.htm";
551 d_fileSystemModel.setNameFilters(nameFilters);
552 d_fileSystemModel.setNameFilterDisables(false);
555 sortByColumn(0, Qt::DescendingOrder);
558 void DCTreeViewWidget::sceneChanged(const void *requester, DCScene*scene)
563 void DCTreeViewWidget::selectedPageChanged(const void *requester, const DCScene*scene)
565 if (d_scene != scene)
568 if (requester == this)
575 d_inSelectionChange = true;
577 QList<DCVCPage*> list = d_scene->getSelectedPages();
578 QItemSelectionModel *selection = selectionModel();
579 QString rootPath = d_fileSystemModel.rootPath();
580 for (int i = 0; i < list.length(); i++)
582 DCVCPage *page = list.at(i);
583 QString path = rootPath + QString("/Container") + page->getLocationPath();
584 QModelIndex idx = d_fileSystemModel.index(path);
585 selection->select(idx, QItemSelectionModel::Select);
587 d_inSelectionChange = false;
591 void DCTreeViewWidget::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
593 QTreeView::selectionChanged(selected, deselected);
595 if (d_inSelectionChange)
602 QModelIndexList selectedList = selected.indexes();
603 QModelIndexList deselectedList = deselected.indexes();
604 int stripLen = d_fileSystemModel.rootPath().length();
606 for (int i = 0; i < selectedList.length(); i++)
608 QString fpath = d_fileSystemModel.filePath(selectedList.at(i));
609 if (fpath.length() > stripLen)
611 fpath = fpath.mid(stripLen);
612 if (fpath.indexOf("/Container") == 0)
614 fpath = fpath.mid(10);
615 d_creator->selectPage(this, fpath, true);
620 for (int i = 0; i < deselectedList.length(); i++)
622 QString fpath = d_fileSystemModel.filePath(deselectedList.at(i));
623 if (fpath.length() > stripLen)
625 fpath = fpath.mid(stripLen);
626 if (fpath.indexOf("/Container") == 0)
628 fpath = fpath.mid(10);
629 d_creator->unselectPage(this, fpath);
634 if (d_creator->getPersMode() == DCCreator::DC_PERSMODE_PAGEEDIT)
636 d_creator->changePersMode(this, DCCreator::DC_PERSMODE_NAVIGATION);
641 void DCTreeViewWidget::commandExecuted(const QUndoCommand *command)
643 const DCCommand *dccommand = dynamic_cast<const DCCommand*>(command);
644 if (dccommand && dccommand->getRequester() == this)
646 sortByColumn(0, Qt::DescendingOrder);
650 void DCTreeViewWidget::directoryLoaded(const QString &directory)