OSDN Git Service

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