OSDN Git Service

[denncoCreator] cell code scripts editor modification. Set editor readonly when a...
[dennco/denncoCreator.git] / Source / treeview / dctreeviewwidget.cpp
1 //  Copyright (c) 2012 Dennco Project
2 //
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.
7 //
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.
12 //
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/>.
15
16 //
17 //  Created by tkawata on Sep-30, 2012.
18 //
19 #include "dctreeviewwidget.h"
20
21 #include "dccreator.h"
22 #include "dcscene.h"
23 #include "dcvcpage.h"
24 #include "dcvccell.h"
25 #include "dccontainer.h"
26 #include "command/dccommand.h"
27
28 #include "dialog/dcinputnewpagenamedialog.h"
29 #include "dialog/dcaddcellcodeclassdialog.h"
30 #include "dialog/dcaddcelldialog.h"
31
32 #include "uieditor/dcuieditor.h"
33 #include "propertyeditor/dcpropertyeditor.h"
34
35 #include <QList>
36 #include <QItemSelectionModel>
37 #include <QModelIndexList>
38
39 static DCTreeViewWidget *s_treeViewWidget = NULL;
40
41 static bool IsIndexUnderContainer(const QFileSystemModel *model, QModelIndex index, bool includesContainerDir = false)
42 {
43     bool r = false;
44
45     if (!includesContainerDir)
46     {
47         if (index.isValid())
48             index = index.parent();
49     }
50
51     while (index.isValid())
52     {
53         if (model->fileName(index) == "Container"
54                 && index.parent().isValid()
55                 && index.parent() == model->index(model->rootPath()))
56         {
57             r = true;
58         }
59         index = index.parent();
60     }
61     return r;
62 }
63
64 class FileIconProvider : public QFileIconProvider
65 {
66     QIcon pageIcon;
67     QIcon folderIcon;
68 public:
69     FileIconProvider() :
70         pageIcon(":/pageIcon.png"),
71         folderIcon(":/folderIcon.png")
72     {
73     }
74
75     virtual ~FileIconProvider()
76     {
77     }
78
79     virtual QIcon icon(const QFileInfo &info) const
80     {
81         if (info.completeSuffix() == "xhtml")
82         {
83             return pageIcon;
84         }
85         else if (info.isDir())
86         {
87 //            return folderIcon;
88         }
89
90         return QFileIconProvider::icon(info);
91
92     }
93
94 };
95
96 DCTreeViewModel::DCTreeViewModel(DCCreator *creator)
97     : d_creator(creator)
98 {
99     setIconProvider(new FileIconProvider);
100 }
101
102 DCTreeViewModel::~DCTreeViewModel()
103 {
104
105 }
106
107 bool DCTreeViewModel::setData(const QModelIndex &index, const QVariant &value, int role)
108 {
109     bool r = false;
110     if (role == Qt::EditRole)
111     {
112         QString oldFilePath = filePath(index);
113         QString oldFileName = fileName(index);
114         QString baseDirPath = oldFilePath.left(oldFilePath.length()-oldFileName.length());
115
116         if (QFileInfo(oldFilePath).isDir() && IsIndexUnderContainer(this, index))
117         {
118             QString newFilePath = baseDirPath + value.toString();
119             d_creator->doCommandRenameDirectory(this, oldFilePath, newFilePath);
120             r = true;
121         }
122     }
123     else
124     {
125         r = QFileSystemModel::setData(index, value, role);
126     }
127     return r;
128 }
129
130 DCTreeViewWidget::DCTreeViewWidget(QWidget *parent, DCCreator *creator) :
131     QTreeView(parent), d_creator(creator), d_fileSystemModel(creator), d_scene(NULL), d_inSelectionChange(false), d_pendingSelectionPath("")
132 {
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()));
139
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;
146 }
147
148 DCTreeViewWidget::~DCTreeViewWidget()
149 {
150     if (d_creator)
151     {
152         d_creator->disconnect(this);
153     }
154 }
155
156 //static
157 bool  DCTreeViewWidget::addDirectory(const QString &path)
158 {
159     bool r = false;
160
161     if (s_treeViewWidget)
162     {
163         QModelIndex index = s_treeViewWidget->d_fileSystemModel.index(path);
164         if (index.isValid())
165         {
166             QString newDirName = "NewFolder";
167             int i = 0;
168             while(QDir(path + "/" + newDirName).exists())
169             {
170                 i++;
171                 newDirName = "";
172                 QTextStream(&newDirName) << "NewFolder(" << i << ")";
173             }
174             QModelIndex newDirIndex = s_treeViewWidget->d_fileSystemModel.mkdir(index, newDirName);
175             if (newDirIndex.isValid())
176             {
177                 r = true;
178                 s_treeViewWidget->setCurrentIndex(newDirIndex);
179             }
180         }
181     }
182     else
183     {
184         Q_ASSERT(0);
185     }
186     return r;
187 }
188
189 //static
190 bool DCTreeViewWidget::removeDirectory(const QString &path)
191 {
192     bool r = false;
193
194     if (s_treeViewWidget)
195     {
196         QDir  dir(path);
197
198         QFileInfoList list = dir.entryInfoList(QDir::NoDot | QDir::NoDotDot | QDir::AllEntries);
199
200         for (int i = 0; i < list.length(); i++)
201         {
202             QFileInfo info = list.at(i);
203             if (info.isDir())
204             {
205                 removeDirectory(info.absoluteFilePath());
206             }
207             else
208             {
209                 QModelIndex index = s_treeViewWidget->d_fileSystemModel.index(info.absoluteFilePath());
210                 if (index.isValid())
211                 {
212                     //hack for prevening auto selection happing by removing row.
213                     s_treeViewWidget->d_inSelectionChange = true;
214                     s_treeViewWidget->d_fileSystemModel.remove(index);
215                 }
216             }
217         }
218
219         QModelIndex index = s_treeViewWidget->d_fileSystemModel.index(path);
220         if (index.isValid())
221         {
222             //hack for prevening auto selection happing by removing row.
223             s_treeViewWidget->d_inSelectionChange = true;
224             r = s_treeViewWidget->d_fileSystemModel.rmdir(index);
225         }
226     }
227     else
228     {
229         Q_ASSERT(0);
230     }
231     return r;
232 }
233
234 //static
235 bool DCTreeViewWidget::removeFile(const QString &path)
236 {
237     bool r = false;
238
239     if (s_treeViewWidget)
240     {
241         QModelIndex index = s_treeViewWidget->d_fileSystemModel.index(path);
242         if (index.isValid() && s_treeViewWidget->d_fileSystemModel.fileInfo(index).isFile())
243         {
244             //hack for prevening auto selection happing by removing row.
245             s_treeViewWidget->d_inSelectionChange = true;
246             r = s_treeViewWidget->d_fileSystemModel.remove(index);
247         }
248     }
249     else
250     {
251         Q_ASSERT(0);
252     }
253     return r;
254 }
255
256 //static
257 void DCTreeViewWidget::selectWhenFilePathAdded(const QString &path)
258 {
259     if (s_treeViewWidget)
260     {
261         s_treeViewWidget->d_pendingSelectionPath = path;
262     }
263 }
264
265
266 void DCTreeViewWidget::doContextMenu(const QPoint &pos)
267 {
268     QPoint globalPos = mapToGlobal(pos);
269
270     QFileSystemModel *fileModel = dynamic_cast<QFileSystemModel*>(model());
271
272     QMenu menu;
273     bool showMenu = false;
274
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;
282
283     bool isDir = true;
284     bool isPage = false;
285
286     QModelIndex index;
287
288     QModelIndexList indexes = selectedIndexes();
289     if (indexes.length() == 0)
290     {
291         addDictionaryAction = menu.addAction(tr("Add folder"));
292         index = fileModel->index(fileModel->rootPath() + "/Container");
293         showMenu = true;
294     }
295     else if (indexes.length() > 0)
296     {        
297         index = indexes.at(0);
298         isDir = d_fileSystemModel.isDir(index);
299         isPage = !isDir && d_fileSystemModel.fileInfo(index).completeSuffix() == "xhtml";
300
301         if (isDir)
302         {
303             addDictionaryAction = menu.addAction(tr("Add folder"));
304             if (IsIndexUnderContainer(&d_fileSystemModel, index, true))
305             {
306                 addPageAction = menu.addAction(tr("Add page..."));
307             }
308             if (fileModel->flags(index) & Qt::ItemIsEditable && !index.child(0,0).isValid())
309             {
310                 removeDirectoryAction = menu.addAction(tr("Remove"));
311             }
312             showMenu = true;
313         }
314         else
315         {
316             if (isPage)
317             {
318                 addCellAction = menu.addAction(tr("Add cell ..."));
319                 addCellCodeClassAction = menu.addAction(tr("Add cell code class ..."));
320                 menu.addSeparator();
321                 renamePageAction = menu.addAction(tr("Rename"));
322                 removePageAction = menu.addAction(tr("Remove..."));
323                 menu.addSeparator();
324             }
325             addDictionaryAction = menu.addAction(tr("Add folder"));
326             showMenu = true;
327         }
328     }
329
330     if (showMenu)
331     {
332         DCContainer *container = d_creator->getCurrentContainer();
333
334         if (container)
335         {
336             QString containerBasedPath;
337
338             if (index.isValid())
339             {
340                 containerBasedPath = container->sysFilePathToContainerBasedPath(fileModel->filePath(index));
341             }
342
343             QAction* selectedItem = menu.exec(globalPos);
344             if (selectedItem)
345             {
346                 if (selectedItem == addDictionaryAction)
347                 {
348                     if (index.isValid())
349                         d_creator->doCommandAddDirectory(this, fileModel->filePath(index));
350                 }
351                 else if (selectedItem == removeDirectoryAction)
352                 {
353                     if (index.isValid())
354                         d_creator->doCommandRemoveDirectory(this, fileModel->filePath(index));
355                 }
356                 else if (selectedItem == addPageAction)
357                 {
358                     if (index.isValid())
359                     {
360                         if (containerBasedPath.length() >= 1)
361                         {
362                             DCInputNewPageNameDialog dialog(fileModel->filePath(index), tr("Add new page"));
363                             if (dialog.exec())
364                             {
365                                 QString pageName = dialog.getName();
366                                 if (pageName.length() > 0)
367                                 {
368                                     QString pathName = containerBasedPath;
369                                     if (containerBasedPath.length()>1)
370                                         pathName.append("/");
371                                     pathName.append(pageName);
372                                     d_creator->doCommandAddPage(this, pathName);
373                                 }
374                             }
375                         }
376                     }
377                 }
378                 else if (selectedItem == renamePageAction)
379                 {
380                     if (index.isValid())
381                     {
382                         if (containerBasedPath.length() >= 1)
383                         {
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);
387                             if (dialog.exec())
388                             {
389                                 QString pageName = dialog.getName();
390                                 if (pageName.length() > 0)
391                                 {
392                                     QString pathName = container->sysFilePathToContainerBasedPath(fileInfo.absolutePath() + "/" + pageName);
393                                     d_creator->doCommandMovePage(this, containerBasedPath, pathName);
394                                 }
395                             }
396                         }
397                     }
398                 }
399                 else if (selectedItem == removePageAction)
400                 {
401                     if (index.isValid())
402                     {
403                         bool doExecute = true;
404                         DCVCPage *page = d_scene->getPage(containerBasedPath.toStdString());
405                         if (page->getCells()->length() > 0 || page->getCellCodeClasses()->length() > 0)
406                         {
407                             QMessageBox::StandardButton button = QMessageBox::warning(this,
408                                                  tr("Remove file"),
409                                                  tr("This Page has cells / cellcodes. Those cells / cell codes will be removed"),
410                                                  QMessageBox::Cancel | QMessageBox::Ok, QMessageBox::Cancel);
411
412                             doExecute = (button == QMessageBox::Ok);
413                         }
414                         if (doExecute)
415                         {
416                             d_creator->doCommandRemovePage(this, page);
417                         }
418                     }
419                 }
420                 else if (selectedItem == addCellAction )
421                 {
422                     if (index.isValid())
423                     {
424                         DCAddCellDialog dialog(container, d_creator, containerBasedPath,0,0);
425                         dialog.exec();
426                     }
427                 }
428                 else  if (selectedItem == addCellCodeClassAction)
429                 {
430                     if (index.isValid())
431                     {
432                         DCAddCellCodeClassDialog dialog(container, d_creator, containerBasedPath);
433                         dialog.exec();
434                     }
435                 }
436
437             }
438         }
439     }
440 }
441
442
443 void DCTreeViewWidget::showEvent(QShowEvent *event)
444 {
445     setColumnHidden(1,true);
446     setColumnHidden(2,true);
447     setColumnHidden(3,true);
448
449     QTreeView::showEvent(event);
450 }
451
452 void DCTreeViewWidget::mouseDoubleClickEvent(QMouseEvent *event)
453 {
454     QModelIndex index = currentIndex();
455     if (index.isValid())
456     {
457         bool isDir = d_fileSystemModel.isDir(index);
458         bool isPage = false;
459         bool isHtml = false;
460         bool isProprty = false;
461
462         if (!isDir)
463         {
464             if (d_fileSystemModel.fileInfo(index).completeSuffix() == "xhtml")
465             {
466                 isPage = true;
467                 isHtml = true;
468             }
469             else if (d_fileSystemModel.fileInfo(index).completeSuffix() == "htm")
470             {
471                 isHtml = true;
472             }
473             else if (d_fileSystemModel.fileInfo(index).completeSuffix() == "html")
474             {
475                 isHtml = true;
476             }
477             else if (d_fileSystemModel.fileName(index) == "property.xml"
478                      && index.parent() == d_fileSystemModel.index(d_fileSystemModel.rootPath()))
479             {
480                 isProprty = true;
481             }
482         }
483
484         if (!IsIndexUnderContainer(&d_fileSystemModel, index))
485         {
486             if (isHtml)
487             {
488                 DCUIEditor *editor = DCUIEditor::getEditor();
489                 editor->startEditing(d_fileSystemModel.filePath(index));
490             }
491             else if (isProprty)
492             {
493                 DCPropertyEditor *editor = DCPropertyEditor::getEditor();
494                 editor->startEditing(d_fileSystemModel.filePath(index));
495             }
496             event->accept();
497             return;
498         }
499
500         if (isDir)
501         {
502             QTreeView::mouseDoubleClickEvent(event);
503         }
504         else if (isPage)
505         {
506             d_creator->changePersMode(this, DCCreator::DC_PERSMODE_PAGEEDIT);
507             event->accept();
508         }
509     }
510     else
511     {
512         QTreeView::mouseDoubleClickEvent(event);
513     }
514 }
515
516 void DCTreeViewWidget::rowsInserted(const QModelIndex &parent, int start, int end)
517 {
518     if (d_pendingSelectionPath.length() > 0)
519     {
520         QModelIndex index = d_fileSystemModel.index(d_pendingSelectionPath);
521         if (index.isValid())
522         {
523             clearSelection();
524             d_pendingSelectionPath = "";
525             QItemSelectionModel *selection = selectionModel();
526             selection->select(index, QItemSelectionModel::Select);
527         }
528     }
529 }
530
531 void DCTreeViewWidget::rowsRemoved()
532 {
533     //hack for prevening auto selection happing by removing row.
534     d_inSelectionChange = false;
535 }
536
537 void DCTreeViewWidget::creatorDestroyed()
538 {
539     d_creator = NULL;
540 }
541
542 void DCTreeViewWidget::contentRootPathChanged(const void *requester, QString rootPath)
543 {
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);
553     setRootIndex(idx);
554
555     sortByColumn(0, Qt::DescendingOrder);
556 }
557
558 void DCTreeViewWidget::sceneChanged(const void *requester, DCScene*scene)
559 {
560     d_scene = scene;
561 }
562
563 void DCTreeViewWidget::selectedPageChanged(const void *requester, const DCScene*scene)
564 {
565     if (d_scene != scene)
566         return;
567
568     if (requester == this)
569     {
570         return;
571     }
572
573     if (d_scene)
574     {
575         d_inSelectionChange = true;
576         clearSelection();
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++)
581         {
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);
586         }
587         d_inSelectionChange = false;
588     }
589 }
590
591 void DCTreeViewWidget::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
592 {
593     QTreeView::selectionChanged(selected, deselected);
594
595     if (d_inSelectionChange)
596     {
597         return;
598     }
599
600     if (d_creator)
601     {
602         QModelIndexList selectedList = selected.indexes();
603         QModelIndexList deselectedList = deselected.indexes();
604         int stripLen = d_fileSystemModel.rootPath().length();
605
606         for (int i = 0; i < selectedList.length(); i++)
607         {
608             QString fpath = d_fileSystemModel.filePath(selectedList.at(i));
609             if (fpath.length() > stripLen)
610             {
611                  fpath = fpath.mid(stripLen);
612                  if (fpath.indexOf("/Container") == 0)
613                  {
614                      fpath = fpath.mid(10);
615                      d_creator->selectPage(this, fpath, true);
616                  }
617             }
618         }
619
620         for (int i = 0; i < deselectedList.length(); i++)
621         {
622             QString fpath = d_fileSystemModel.filePath(deselectedList.at(i));
623             if (fpath.length() > stripLen)
624             {
625                  fpath = fpath.mid(stripLen);
626                  if (fpath.indexOf("/Container") == 0)
627                  {
628                      fpath = fpath.mid(10);
629                      d_creator->unselectPage(this, fpath);
630                  }
631             }
632         }
633
634         if (d_creator->getPersMode() == DCCreator::DC_PERSMODE_PAGEEDIT)
635         {
636             d_creator->changePersMode(this, DCCreator::DC_PERSMODE_NAVIGATION);
637         }
638     }
639 }
640
641 void DCTreeViewWidget::commandExecuted(const QUndoCommand *command)
642 {
643     const DCCommand *dccommand = dynamic_cast<const DCCommand*>(command);
644     if (dccommand && dccommand->getRequester() == this)
645     {
646         sortByColumn(0, Qt::DescendingOrder);
647     }
648 }
649
650 void DCTreeViewWidget::directoryLoaded(const QString &directory)
651 {
652     expandAll();
653 }