OSDN Git Service

bb04275534b4489aae582f046b64bb9724e95136
[dennco/denncoCreator.git] / Source / visualizer / toolwindow / dctoolwindowcelleditor.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 "dctoolwindowcelleditor.h"
20
21 #include "dceditablelabel.h"
22 #include "dceditabletreeview.h"
23 #include "dccelltypecombobox.h"
24 #include "dccell.h"
25 #include "dccreator.h"
26 #include "dcreceptor.h"
27 #include "dcaxon.h"
28 #include "dccellcode.h"
29 #include "dcaxonterminal.h"
30 #include "dccontainer.h"
31 #include "utils/dcresources.h"
32 #include "utils/dcqtitemmodel.h"
33 #include "utils/dcutil.h"
34 #include "codeeditor/dccellscriptseditorwindow.h"
35
36 #include <QGridLayout>
37 #include <QLineEdit>
38 #include <QTreeView>
39 #include <QSizePolicy>
40 #include <QIcon>
41
42 class ReceptorModel : public DCQtItemModel
43 {
44     DCToolWindowCellEditor *d_owner;
45 public:
46     ReceptorModel(DCToolWindowCellEditor *owner) : DCQtItemModel(QStringList("name")), d_owner(owner)
47     {
48
49     }
50
51     virtual ~ReceptorModel()
52     {
53     }
54
55     virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole)
56     {
57         if (role != Qt::EditRole)
58             return false;
59
60         DCCell *cell = d_owner->getCell();
61         if (!cell)
62             return false;
63
64         if (index.column() != 0)
65         {
66             return DCQtItemModel::setData(index, value, role);
67         }
68
69         DCQtItemModelItem *item = getItem(index);
70         QString oldReceptorName = item->data(index.column()).toString();
71         QString newReceptorName = value.toString().trimmed();
72         if (newReceptorName.length() == 0)
73         {
74             return false;
75         }
76
77         if (oldReceptorName == newReceptorName)
78         {
79             //nothing actually changes
80             return false;
81         }
82
83         if (!d_owner->getIsViewUpdating())
84         {
85             if (cell->getReceptor(newReceptorName))
86             {
87                 //already exist
88                 QMessageBox::warning(NULL, tr("Rename receptor failed"), tr("The receptor name already exist"));
89                 return false;
90             }
91
92             bool result = item->setData(index.column(), newReceptorName);
93
94             if (result)
95             {
96                 DCCreator *creator = d_owner->getController();
97                 if (creator->doCommandRenameReceptorName(d_owner, cell, oldReceptorName, newReceptorName, true))
98                 {
99                     emit dataChanged(index, index);
100                 }
101                 else
102                 {
103                     item->setData(index.column(), oldReceptorName);
104                 }
105             }
106             return result;
107         }
108         else
109         {
110             return item->setData(index.column(), newReceptorName);
111         }
112     }
113
114     virtual Qt::ItemFlags flags(const QModelIndex &index) const
115     {
116         if (!index.isValid())
117             return 0;
118
119         Qt::ItemFlags flags = Qt::ItemIsEnabled;
120
121         if (index.column() == 0 && index.isValid() && index.parent().isValid() && !index.parent().parent().isValid())
122         {
123             flags |= Qt::ItemIsEditable | Qt::ItemIsSelectable;
124         }
125
126         return flags;
127     }
128 };
129
130 class AxonTerminalModel : public DCQtItemModel
131 {
132     DCToolWindowCellEditor *d_owner;
133 public:
134     AxonTerminalModel(DCToolWindowCellEditor *owner) : DCQtItemModel(QStringList("name")), d_owner(owner)
135     {
136
137     }
138
139     virtual ~AxonTerminalModel()
140     {
141     }
142
143     virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole)
144     {
145         if (role != Qt::EditRole)
146             return false;
147
148         DCCell *cell = d_owner->getCell();
149         if (!cell)
150             return false;
151
152         if (index.column() != 0)
153         {
154             return DCQtItemModel::setData(index, value, role);
155         }
156
157         DCQtItemModelItem *item = getItem(index);
158         QString oldReceptorName = item->data(index.column()).toString();
159         QString newReceptorName = value.toString().trimmed();
160         if (newReceptorName.length() == 0)
161         {
162             return false;
163         }
164
165         if (oldReceptorName == newReceptorName)
166         {
167             //nothing actually changes
168             return false;
169         }
170
171         DCCell *axonTargetCell = NULL;
172         if (!d_owner->getIsViewUpdating())
173         {
174             bool alreadyExist = false;
175             DCAxon *axon = cell->getAxon();
176             int num = axon->getNumberOfTerminals();
177             for (int i = 0; i < num; i++)
178             {
179                 DCReceptor *receptor = axon->getTerminalAt(i)->getTarget();
180                 if (receptor)
181                 {
182                     DCCell *targetCell = receptor->getOwnerCell();
183                     if (targetCell)
184                     {
185                         QString targetReceptorName = QString::fromStdString(targetCell->getReceptorName(receptor));
186                         if (targetReceptorName == newReceptorName)
187                         {
188                             alreadyExist = true;
189                             break;
190                         }
191                         else if (targetReceptorName == oldReceptorName)
192                         {
193                             axonTargetCell = targetCell;
194                         }
195                     }
196                 }
197             }
198
199             if (alreadyExist)
200             {
201                 QMessageBox::warning(NULL, tr("Rename receptor failed"), tr("The receptor name already exist"));
202                 return false;
203             }
204
205             bool result = false;
206
207             if (axonTargetCell)
208             {
209                 result = item->setData(index.column(), newReceptorName);
210
211                 if (result)
212                 {
213                     DCCreator *creator = d_owner->getController();
214                     if (creator->doCommandRenameReceptorName(d_owner, axonTargetCell, oldReceptorName, newReceptorName, true))
215                     {
216                         emit dataChanged(index, index);
217                     }
218                     else
219                     {
220                         item->setData(index.column(), oldReceptorName);
221                     }
222                 }
223             }
224             return result;
225         }
226         else
227         {
228             return item->setData(index.column(), newReceptorName);
229         }
230     }
231
232     virtual Qt::ItemFlags flags(const QModelIndex &index) const
233     {
234         if (!index.isValid())
235             return 0;
236
237         Qt::ItemFlags flags = Qt::ItemIsEnabled;
238
239         if (index.column() == 0 && index.isValid() && index.parent().isValid() && index.parent().parent().isValid() && !index.parent().parent().parent().isValid())
240         {
241             flags |= Qt::ItemIsEditable | Qt::ItemIsSelectable;
242         }
243
244         return flags;
245     }
246
247 };
248
249 DCToolWindowCellEditor::DCToolWindowCellEditor(DCCreator *creator) :
250     DCToolWindowBase("CELL:", creator), d_cell(NULL), d_isViewUpdating(false)
251 {
252     d_layout = new QGridLayout;
253 #ifdef Q_WS_MAC
254     d_layout->setSpacing(10);
255 #else
256     d_layout->setSpacing(6);
257 #endif
258     d_layout->setContentsMargins(0,0,0,0);
259     d_layout->addWidget(new QLabel(tr("page")),0,0);
260     d_layout->addWidget(new QLabel(tr("type")),1,0);
261     d_layout->addWidget(new QLabel(tr("cell code")),2,0);
262     d_layout->addWidget(new QLabel(tr("custom script")),3,0);
263
264     d_detailButton = new QPushButton(tr("detail..."));
265     d_detailButton->setStyleSheet("background-color: rgba(255,255,255,60);");
266
267     d_layout->addWidget(d_detailButton,6,0,1,2);
268
269     d_textPage = new DCEditableLabel(this, "");
270     d_comboType = new DCCellTypeComboBox(creator, this);
271     d_layout->addWidget(d_textPage, 0,1);
272     d_layout->addWidget(d_comboType, 1,1);
273
274     d_classButton = new QPushButton("...");
275     d_customScriptButton = new QPushButton(tr("edit..."));
276
277     d_layout->addWidget(d_classButton, 2,1);
278     d_layout->addWidget(d_customScriptButton, 3,1);
279
280     d_receptors = new DCEditableTreeView(this);
281     d_receptors->setHeaderHidden(true);
282     d_receptors->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
283
284     d_axonTerminals = new DCEditableTreeView(this);
285     d_axonTerminals->setHeaderHidden(true);
286     d_axonTerminals->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
287
288
289     d_receptorItemModel = new ReceptorModel(this);
290     d_axonTerminalItemModel = new AxonTerminalModel(this);
291
292     d_receptors->setModel(d_receptorItemModel);
293     d_axonTerminals->setModel(d_axonTerminalItemModel);
294
295     d_layout->addWidget(d_receptors, 4,0,1,2);
296     d_layout->addWidget(d_axonTerminals, 5, 0, 1, 2);
297
298     contentLayout()->addLayout(d_layout);
299
300     connect(d_receptors, SIGNAL(collapsed(QModelIndex)), this, SLOT(slotReceptorTreeCollapsed(QModelIndex)));
301     connect(d_receptors, SIGNAL(expanded(QModelIndex)), this, SLOT(slotReceptorTreeExpanded(QModelIndex)));
302     connect(d_receptors, SIGNAL(clicked(QModelIndex)), this, SLOT(slotReceptorItemClicked(QModelIndex)));
303     connect(d_receptors, SIGNAL(vscrollbarShown()), this, SLOT(adjustTreeColumnWidth()));
304     connect(d_receptors, SIGNAL(vscrollbarHidden()), this, SLOT(adjustTreeColumnWidth()));
305     connect(d_axonTerminals, SIGNAL(collapsed(QModelIndex)), this, SLOT(slotAxonTerminalTreeCollapsed(QModelIndex)));
306     connect(d_axonTerminals, SIGNAL(expanded(QModelIndex)), this, SLOT(slotAxonTerminalTreeExpanded(QModelIndex)));
307     connect(d_axonTerminals, SIGNAL(clicked(QModelIndex)), this, SLOT(slotAxonTerminalItemClicked(QModelIndex)));
308     connect(d_axonTerminals, SIGNAL(vscrollbarShown()), this, SLOT(adjustTreeColumnWidth()));
309     connect(d_axonTerminals, SIGNAL(vscrollbarHidden()), this, SLOT(adjustTreeColumnWidth()));
310
311     connect(d_classButton, SIGNAL(clicked()), this, SLOT(slotCellCodeEditButtonPressed()));
312     connect(d_customScriptButton, SIGNAL(clicked()), this, SLOT(slotCustomScriptEditButtonPressed()));
313 }
314
315 DCToolWindowCellEditor::~DCToolWindowCellEditor()
316 {
317     d_receptors->disconnect(this);
318     d_axonTerminals->disconnect(this);
319
320     if (d_receptorItemModel)
321         d_receptorItemModel->deleteLater();
322
323     if (d_axonTerminalItemModel)
324         d_axonTerminalItemModel->deleteLater();
325 }
326
327 void DCToolWindowCellEditor::setCell(DCCell *cell)
328 {
329     if (d_cell)
330         d_cell->disconnect(this);
331
332     d_cell = cell;
333     QString title = "CELL:";
334     if (cell)
335     {
336         title.append(QString::fromStdString(cell->getName()));
337         connect(cell, SIGNAL(destroyed(QObject*)), this, SLOT(slotCellDestroyed()));
338         d_comboType->setEditingCell(cell);
339     }
340
341     setButtonedWindowTitle(title);
342
343     updateView();
344 }
345
346 void DCToolWindowCellEditor::updateView()
347 {
348     d_isViewUpdating = true;
349     d_receptorItemModel->removeAllItems();
350     d_axonTerminalItemModel->removeAllItems();
351
352     DCContainer *container = getController()->getCurrentContainer();
353
354     if (d_cell && container)
355     {
356         if (container->getIsScriptable(d_cell->getType()))
357         {
358             if (d_cell->getIsCellCodeAssgined())
359             {
360                 d_classButton->setText(QString::fromStdString(d_cell->getCellCode()->getFQNName()));
361             }
362             else
363             {
364                 d_classButton->setText("...");
365             }
366             d_classButton->setEnabled(true);
367
368             d_customScriptButton->setText("Edit...");
369             d_customScriptButton->setEnabled(true);
370         }
371         else
372         {
373             d_classButton->setText("N/A");
374             d_classButton->setEnabled(false);
375             d_customScriptButton->setText("N/A");
376             d_customScriptButton->setEnabled(false);
377         }
378
379         d_comboType->updateSelection();
380         if (container->getIsPluginType(d_cell->getType()))
381         {
382             d_comboType->setEnabled(false);
383         }
384         else
385         {
386             d_comboType->setEnabled(!d_cell->getIsCellCodeAssgined());
387         }
388
389         d_textPage->setText(QString::fromStdString(d_cell->getLocation()));
390
391         d_receptorItemModel->insertString("receptors");
392         d_receptorItemModel->insertColumns(1,2);
393         d_receptorItemModel->setData(d_receptorItemModel->index(0,1), QVariant::fromValue(DCResources::addItemIcon()));
394
395         d_axonTerminalItemModel->insertString("axonTerminals");
396         d_axonTerminalItemModel->insertColumns(1,2);
397         d_axonTerminalItemModel->setData(d_axonTerminalItemModel->index(0,1), QVariant::fromValue(DCResources::addItemIcon()));
398
399         const TKReceptorMap *receptors = d_cell->getReceptors();
400         TKReceptorMap::const_iterator it = receptors->begin();
401         QModelIndex rroot = d_receptorItemModel->index(0,0);
402         int i = 0;
403         while( it != receptors->end())
404         {
405
406             QString receptorName = QString::fromStdString((*it).first);            
407             d_receptorItemModel->insertString(receptorName,rroot);
408             d_receptorItemModel->setData(rroot.child(i,2), QVariant::fromValue(DCResources::deleteItemIcon()));
409
410             DCReceptor *receptor = dynamic_cast<DCReceptor*>((*it).second);
411             DCAxonTerminal *terminal = receptor->getTarget();
412             if (terminal)
413             {
414                 DCCell *targetCell = dynamic_cast<DCCell*>(terminal->getOwner()->getOwner());
415                 if (targetCell)
416                 {
417                     QString targetPath = DCUtil::getFQNPath(targetCell->getLocation(), targetCell->getName());
418                     d_receptorItemModel->insertString(targetPath,rroot.child(i,0));
419                 }
420             }
421
422             ++it;
423             ++i;
424         }
425
426         d_receptors->expand(rroot);
427         for (int i = 0; i < d_receptorItemModel->rowCount(rroot); i++)
428         {
429             QModelIndex index = rroot.child(i,0);
430             d_receptors->collapse(index);
431             if (d_receptorItemModel->rowCount(index) > 0)
432             {
433                 d_receptors->collapse(index.child(0,0));
434             }
435         }
436
437         QModelIndex aroot = d_axonTerminalItemModel->index(0,0);
438         DCAxon *axon = d_cell->getAxon();
439         int acnt = axon->getNumberOfTerminals();
440         for (int i = 0; i < acnt; i++)
441         {
442             DCReceptor *targetReceptor = NULL;
443             DCCell *targetCell = NULL;
444             DCAxonTerminal *tarminal = axon->getTerminalAt(i);
445             if (tarminal)
446             {
447                 targetReceptor = tarminal->getTarget();
448                 if (targetReceptor)
449                 {
450                     targetCell = targetReceptor->getOwnerCell();
451                 }
452             }
453
454             if (targetCell)
455             {
456                 QString targetPath = DCUtil::getFQNPath(targetCell->getLocation(), targetCell->getName());
457                 QString targetReceptorName = QString::fromStdString(targetCell->getReceptorName(targetReceptor));
458                 d_axonTerminalItemModel->insertString(targetPath,aroot);
459                 d_receptorItemModel->setData(aroot.child(i,2), QVariant::fromValue(DCResources::deleteItemIcon()));
460                 d_axonTerminalItemModel->insertString(targetReceptorName,aroot.child(i,0));
461             }
462             else
463             {
464                 //TODO
465             }
466         }
467
468         d_axonTerminals->expand(aroot);
469         for (int i = 0; i < d_axonTerminalItemModel->rowCount(aroot); i++)
470         {
471             QModelIndex index = aroot.child(i,0);
472             d_axonTerminals->collapse(index);
473             if (d_axonTerminalItemModel->rowCount(index) > 0)
474             {
475                 d_axonTerminals->collapse(index.child(0,0));
476             }
477         }
478
479         resizeView();
480     }
481     d_isViewUpdating = false;
482 }
483
484 void DCToolWindowCellEditor::slotReceptorTreeCollapsed(const QModelIndex &index)
485 {
486     (void)index;
487     resizeView();
488 }
489
490 void DCToolWindowCellEditor::slotReceptorTreeExpanded(const QModelIndex &index)
491 {
492     (void)index;
493     resizeView();
494 }
495
496 void DCToolWindowCellEditor::slotReceptorItemClicked(const QModelIndex &index)
497 {
498     switch (index.column())
499     {
500     case 1:
501         qDebug() << "add item clicked..";
502         if (!index.parent().isValid())
503         {
504             getController()->doCommandStartAddAxonTerminalFromReceptor(this, d_cell);
505         }
506         break;
507
508     case 2:
509         qDebug() << "delete item clicked..";
510         if (index.parent().row() == 0)
511         {
512             int itemRowIndex = index.row();
513             if (itemRowIndex >= 0)
514             {
515                 QModelIndex itemIndex = d_receptorItemModel->index(itemRowIndex,0,index.parent());
516                 QString receptorName = d_receptorItemModel->data(itemIndex,Qt::DisplayRole).toString();
517                 if (receptorName.length()>0)
518                 {
519                     d_receptors->setCurrentIndex(itemIndex);
520                     getController()->doCommandRemoveAxonTerminal(this, d_cell, receptorName);
521                 }
522             }
523         }
524         break;
525
526     default:
527         qDebug() << "other clicked..";
528         break;
529
530     }
531
532 }
533
534 void DCToolWindowCellEditor::slotAxonTerminalTreeCollapsed(const QModelIndex &index)
535 {
536     (void)index;
537     resizeView();
538 }
539
540 void DCToolWindowCellEditor::slotAxonTerminalTreeExpanded(const QModelIndex &index)
541 {
542     (void)index;
543     resizeView();
544 }
545
546 void DCToolWindowCellEditor::slotAxonTerminalItemClicked(const QModelIndex &index)
547 {
548     switch (index.column())
549     {
550     case 1:
551         qDebug() << "add item clicked..";
552         if (!index.parent().isValid())
553         {
554             getController()->doCommandStartAddAxonTerminalFromAxon(this, d_cell);
555         }
556         break;
557
558     case 2:
559         qDebug() << "delete item clicked..";
560         if (index.parent().row() == 0)
561         {
562             int itemIndex = index.row();
563             if (itemIndex >= 0)
564             {
565                 d_axonTerminals->setCurrentIndex(d_axonTerminalItemModel->index(itemIndex,0,index.parent()));
566                 getController()->doCommandRemoveAxonTerminal(this, d_cell, d_cell->getAxon()->getTerminalAt(itemIndex));
567             }
568         }
569         break;
570
571     default:
572         qDebug() << "other clicked..";
573         break;
574
575     }
576 }
577
578 void DCToolWindowCellEditor::slotCellCodeEditButtonPressed()
579 {
580     if (d_cell && d_cell->getCellCode())
581     {
582         DCCellScriptsEditorWindow::startEditing(d_cell, true);
583     }
584 }
585
586 void DCToolWindowCellEditor::slotCustomScriptEditButtonPressed()
587 {
588     if (d_cell)
589     {
590         DCCellScriptsEditorWindow::startEditing(d_cell, false);
591     }
592 }
593
594 // TODO
595 // There may be better / proper way to do this.
596 // The goal is to adjust the window height to fit all inside components
597 // with its desigered size.
598 void DCToolWindowCellEditor::resizeView()
599 {
600     int totalHeight = 0;
601     int spacing = d_layout->verticalSpacing();
602     for (int i = 0 ; i < d_layout->rowCount(); i++ )
603     {
604         int maxHeightInRow = 0;
605         for (int j = 0; j < d_layout->columnCount(); j++)
606         {
607             QLayoutItem *item = d_layout->itemAtPosition(i,j);
608             if (item)
609             {
610                 QWidget *pWidget = item->widget();
611                 if (pWidget)
612                 {
613                     QSize sh = pWidget->sizeHint();
614                     pWidget->setFixedHeight(sh.height());
615                     if (sh.height() > maxHeightInRow)
616                     {
617                         maxHeightInRow = sh.height();
618                     }
619                 }
620             }
621         }
622         totalHeight += maxHeightInRow  + spacing;
623     }
624
625     QSize s = size();
626     int left,top,right,bottom;
627     contentLayout()->getContentsMargins(&left,&top,&right,&bottom);
628     s.setHeight(totalHeight + getTitleButtonHeight() + top + bottom);
629     resize(s);
630
631     adjustTreeColumnWidth();
632 }
633
634 void DCToolWindowCellEditor::adjustTreeColumnWidth()
635 {
636     d_receptors->setColumnWidth(1, 18);
637     d_receptors->setColumnWidth(2, 18);
638     QScrollBar *sb = d_receptors->verticalScrollBar();
639     if (sb && sb->isVisible())
640         d_receptors->setColumnWidth(0, d_receptors->width()-44 - sb->width());
641     else
642         d_receptors->setColumnWidth(0, d_receptors->width()-42);
643
644     d_axonTerminals->setColumnWidth(1, 18);
645     d_axonTerminals->setColumnWidth(2, 18);
646     d_axonTerminals->setColumnWidth(0, d_axonTerminals->width()-42);
647     sb = d_axonTerminals->verticalScrollBar();
648     if (sb && sb->isVisible())
649         d_axonTerminals->setColumnWidth(0, d_axonTerminals->width()-44 - sb->width());
650     else
651         d_axonTerminals->setColumnWidth(0, d_axonTerminals->width()-42);
652 }
653
654 void DCToolWindowCellEditor::slotCellDestroyed()
655 {
656     setCell(NULL);
657 }
658