00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <QtGui>
00023 #include <QDebug>
00024 #include <iostream>
00025
00026 #include "slatewindow.h"
00027 #include "sinclink.h"
00028 #include "asinclink.h"
00029 #include "node.h"
00030 #include "groupnode.h"
00031 #include "inputnode.h"
00032 #include "middlenode.h"
00033 #include "outputnode.h"
00034 #include "slateview.h"
00035 #include "insertaction.h"
00036
00037 #include <QVDesignerGUI>
00038
00039 #include "../facade/itemproperties.h"
00040
00041
00042 SlateWindow::SlateWindow(QVDesignerGUI *desig, QWidget * parent): QMainWindow(parent), designer(desig)
00043 {
00044 scene = new QGraphicsScene(-1180, -900, 3200, 2400);
00045
00046 view = new SlateView;
00047 view->setScene(scene);
00048 view->setDragMode(QGraphicsView::RubberBandDrag);
00049 view->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
00050 view->setContextMenuPolicy(Qt::ActionsContextMenu);
00051 setCentralWidget(view);
00052
00053 minZ = 0;
00054 maxZ = 0;
00055 seqNumber = 0;
00056
00057 createMenus();
00058 createToolBars();
00059
00060 statusbar = new QStatusBar();
00061 setStatusBar(statusbar);
00062
00063 connect(scene, SIGNAL(selectionChanged()), this, SLOT(updateActions()));
00064
00065 scene->setBackgroundBrush(QPixmap(":/images/background1.png"));
00066
00067 setWindowTitle(tr("Slate"));
00068 updateActions();
00069 }
00070
00071 void SlateWindow::closeEvent(QCloseEvent *)
00072 {
00073 emit closed();
00074 }
00075
00077 bool SlateWindow::createLink(Node *fromNode, int fromPoint, Node *toNode, int toPoint)
00078 {
00079
00080 if (stopAction->isEnabled()) return false;
00081
00082 if (addSLinkAction->isChecked())
00083 designer->addLink(fromNode->getName(), fromNode->propName(fromPoint), toNode->getName(), toNode->propName(toPoint), true);
00084 else
00085 designer->addLink(fromNode->getName(), fromNode->propName(fromPoint), toNode->getName(), toNode->propName(toPoint), false);
00086 return true;
00087 }
00088
00089 void SlateWindow::addLinkLine(QString fromNode, QString fromProp, QString toNode, QString toProp, bool sinc)
00090 {
00091 Link *link;
00092 QString linkName = fromNode + "[" + fromProp + "] => " + toNode + "[" + toProp + "]";
00093
00094 if ( insertNodes.contains(fromNode) && insertNodes.contains(toNode) ) {
00095 ItemNode *from = insertNodes.value(fromNode);
00096 ItemNode *to = insertNodes.value(toNode);
00097
00098 if (sinc) {
00099 link = new SincLink(from, fromProp, to, toProp, 0, scene);
00100 insertLinks.insert(linkName, link);
00101 link->trackNodes();
00102 }
00103 else {
00104 link = new AsincLink(from, fromProp, to, toProp, 0, scene);
00105 insertLinks.insert(linkName, link);
00106 link->trackNodes();
00107 }
00108 }
00109 }
00110
00111 void SlateWindow::delLinkLine(QString fromNode, QString fromProp, QString toNode, QString toProp)
00112 {
00113 QString linkName = fromNode + "[" + fromProp + "] => " + toNode + "[" + toProp + "]";
00114 if (insertLinks.contains(linkName)) {
00115 delete insertLinks.value(linkName);
00116 insertLinks.remove(linkName);
00117 }
00118 }
00119
00120 void SlateWindow::insertItem(QString type)
00121 {
00122 QString name = type.toLower();
00123 name.replace('<', '_');
00124 name.replace(',', '_');
00125 name.replace('>', '_');
00126 name.replace(' ', "");
00127 name += QString("_%1").arg(seqNumber);
00128
00129 designer->addItem(type, name);
00130 }
00131
00132 void SlateWindow::addItemNode(QString type, QString name, ItemProperties *item)
00133 {
00135 if (designer->getInputItemTypes().contains(type)) {
00136 InputNode *node = new InputNode(*item, name, this, 0, scene);
00137 insertNodes.insert(node->getName(), node);
00138 setupNode(node);
00139 if (insertNodesPos.contains(name))
00140 node->setPos(insertNodesPos.value(name));
00141 else
00142 insertNodesPos.insert(name, node->pos());
00143 }
00144 else if (designer->getMiddleItemTypes().contains(type)) {
00145 MiddleNode *node = new MiddleNode(*item, name, this, 0, scene);
00146 insertNodes.insert(node->getName(), node);
00147 setupNode(node);
00148 if (insertNodesPos.contains(name))
00149 node->setPos(insertNodesPos.value(name));
00150 else
00151 insertNodesPos.insert(name, node->pos());
00152 }
00153 else if (designer->getOutputItemTypes().contains(type)) {
00154 OutputNode *node = new OutputNode(*item, name, this, 0, scene);
00155 insertNodes.insert(node->getName(), node);
00156 setupNode(node);
00157 if (insertNodesPos.contains(name))
00158 node->setPos(insertNodesPos.value(name));
00159 else
00160 insertNodesPos.insert(name, node->pos());
00161 }
00162 }
00163
00164 void SlateWindow::delItemNode(QString name)
00165 {
00166 if (insertNodes.contains(name)) {
00167 insertNodesPos.remove(name);
00168 insertNodesPos.insert(name, insertNodes.value(name)->pos());
00169 delete insertNodes.value(name);
00170 insertNodes.remove(name);
00171 }
00172 }
00173
00174 void SlateWindow::addProperty(QString srcName, QString propName, int type, bool in, bool out)
00175 {
00176 if (insertNodes.contains(srcName)) {
00177 insertNodes.value(srcName)->insertProperty(propName, type, in, out);
00178 }
00179 }
00180
00181 void SlateWindow::delProperty(QString srcName, QString propName)
00182 {
00183 if (insertNodes.contains(srcName)) {
00184 insertNodes.value(srcName)->removeProperty(propName);
00185 }
00186 }
00187
00188 void SlateWindow::del()
00189 {
00190
00191 foreach(QGraphicsItem *item, scene->selectedItems()) {
00192 Link *link = dynamic_cast<Link *>(item);
00193
00194 if (link && (link->fromNode() != NULL) && (link->toNode() != NULL)) {
00195 designer->delLink(link->fromNode()->getName(), link->fromProp(), link->toNode()->getName(), link->toProp());
00196 }
00197 }
00198
00199 foreach(QGraphicsItem *item, scene->selectedItems()) {
00200 Node *node = dynamic_cast<Node *>(item);
00201
00202 if (node) {
00203 designer->delItem(node->getName());
00204 }
00205 }
00206 }
00207
00208 void SlateWindow::join()
00209 {
00210 QList<QGraphicsItem *> group = selectedNodeGroup();
00211
00212
00213 GroupNode *node = new GroupNode(0, scene);
00214 node->setText("Group");
00215
00216
00217 if ( group.first() && group.first()->parentItem() ) {
00218 GroupNode *parentNode = dynamic_cast<GroupNode *>(group.first()->parentItem());
00219 if (parentNode) parentNode->addNode(node);
00220 }
00221
00222
00223 foreach (QGraphicsItem *item, group) {
00224 Node *itemNode = dynamic_cast<Node *>(item);
00225 if (itemNode) {
00226 node->addNode(itemNode);
00227
00228
00229
00230 foreach (Link *link, itemNode->getInLinks()) {
00231 Node *other = link->fromNode();
00232 if (group.contains(other)) {
00233 QPen pen = link->pen();
00234 pen.setWidthF(pen.width()*0.5);
00235 link->setPen(pen);
00236 link->update();
00237 }
00238
00239
00240
00241 }
00242 foreach (Link *link, itemNode->getOutLinks()) {
00243 Node *other = link->toNode();
00244 if (group.contains(other)) {
00245 QPen pen = link->pen();
00246 pen.setWidthF(pen.width()*0.5);
00247 link->setPen(pen);
00248 link->update();
00249 }
00250
00251
00252
00253 }
00254 itemNode->updateLinksPos();
00255 }
00256 }
00257 }
00258
00259 void SlateWindow::bringToFront()
00260 {
00261 maxZ += 2;
00262 setZValue(maxZ);
00263 }
00264
00265 void SlateWindow::sendToBack()
00266 {
00267 minZ += 2;
00268 setZValue(minZ);
00269 }
00270
00271 void SlateWindow::run()
00272 {
00273 foreach (QAction *action, insertMenu->actions()) {
00274 action->setEnabled(false);
00275 }
00276
00277 deleteAction->setEnabled(false);
00278
00279 runAction->setEnabled(false);
00280 stopAction->setEnabled(true);
00281 designer->run();
00282 }
00283
00284 void SlateWindow::stop()
00285 {
00286 designer->stop();
00287 stopAction->setEnabled(false);
00288 runAction->setChecked(false);
00289 runAction->setEnabled(true);
00290
00291 bool hasSelection = !scene->selectedItems().isEmpty();
00292 deleteAction->setEnabled(hasSelection);
00293
00294 foreach (QAction *action, insertMenu->actions()) {
00295 action->setEnabled(true);
00296 }
00297 }
00298
00299 void SlateWindow::setZValue(int z)
00300 {
00301 Node *node = selectedNode();
00302 if (node) {
00303 node->setZValue(z);
00304 node->updateLinksPos();
00305 }
00306 }
00307
00308 void SlateWindow::showProperties()
00309 {
00310 Node *node = selectedNode();
00311
00312 if (node) showProperties(node);
00313 }
00314
00315 void SlateWindow::showProperties(Node *node)
00316 {
00317 designer->showProperties(node->getName());
00318 }
00319
00320 void SlateWindow::updateActions()
00321 {
00322 bool hasSelection = !scene->selectedItems().isEmpty();
00323 bool isNode = (selectedNode() != 0);
00324
00325
00326
00327 joinAction->setEnabled(false);
00328
00329 if (runAction->isEnabled()) deleteAction->setEnabled(hasSelection);
00330 bringToFrontAction->setEnabled(isNode);
00331 sendToBackAction->setEnabled(isNode);
00332 propertiesAction->setEnabled(isNode);
00333
00334 foreach (QAction *action, view->actions())
00335 view->removeAction(action);
00336
00337 foreach (QAction *action, editMenu->actions()) {
00338 if (action->isEnabled())
00339 view->addAction(action);
00340 }
00341
00342
00343 QAction *ma = new QAction(tr("..."), this);
00344 ma->setMenu(new QMenu("insert_menu", this));
00345 ma->menu()->addMenu(insertMenu);
00346 view->addAction(ma);
00347
00348 foreach (QAction *action, insertMenu->actions()) {
00349 view->addAction(action);
00350 }
00351 }
00352
00353 void SlateWindow::setupNode(Node *node)
00354 {
00355 node->setPos( QPoint(10 + (seqNumber % 10) * 6, 20 + (seqNumber % 10) * 6) );
00356 ++seqNumber;
00357
00358 scene->clearSelection();
00359 node->setSelected(true);
00360 bringToFront();
00361 }
00362
00363 void SlateWindow::createMenus()
00364 {
00366 exitAction = new QAction(tr("E&xit"), this);
00367 exitAction->setShortcut(tr("Ctrl+Q"));
00368 connect(exitAction, SIGNAL(triggered()), this, SLOT(close()));
00369
00370 addSLinkAction = new QAction(tr("Add &Synchronous Link"), this);
00371 addSLinkAction->setIcon(QIcon(":/images/slink.png"));
00372 addSLinkAction->setShortcut(tr("Ctrl+S"));
00373 addSLinkAction->setCheckable(true);
00374
00375 addALinkAction = new QAction(tr("Add &Asynchronous Link"), this);
00376 addALinkAction->setIcon(QIcon(":/images/alink.png"));
00377 addALinkAction->setShortcut(tr("Ctrl+A"));
00378 addALinkAction->setCheckable(true);
00379 addALinkAction->setChecked(true);
00380
00381
00382 linkGroup = new QActionGroup(this);
00383 linkGroup->setExclusive(true);
00384 linkGroup->addAction(addSLinkAction);
00385 linkGroup->addAction(addALinkAction);
00386
00387
00388 joinAction = new QAction(tr("&Join"), this);
00389 joinAction->setIcon(QIcon(":/images/join.png"));
00390 joinAction->setShortcut(tr("Ctrl+J"));
00391 connect(joinAction, SIGNAL(triggered()), this, SLOT(join()));
00392
00393 deleteAction = new QAction(tr("&Delete"), this);
00394 deleteAction->setIcon(QIcon(":/images/delete.png"));
00395 deleteAction->setShortcut(tr("Del"));
00396 deleteAction->setEnabled(false);
00397 connect(deleteAction, SIGNAL(triggered()), this, SLOT(del()));
00398
00399 bringToFrontAction = new QAction(tr("Bring to &Front"), this);
00400 bringToFrontAction->setIcon(QIcon(":/images/bringtofront.png"));
00401 connect(bringToFrontAction, SIGNAL(triggered()),this, SLOT(bringToFront()));
00402
00403 sendToBackAction = new QAction(tr("&Send to Back"), this);
00404 sendToBackAction->setIcon(QIcon(":/images/sendtoback.png"));
00405 connect(sendToBackAction, SIGNAL(triggered()), this, SLOT(sendToBack()));
00406
00407 propertiesAction = new QAction(tr("P&roperties..."), this);
00408 connect(propertiesAction, SIGNAL(triggered()), this, SLOT(showProperties()));
00409
00410 runAction = new QAction(tr("&Run"), this);
00411 runAction->setIcon(QIcon(":/images/run.png"));
00412 runAction->setCheckable(true);
00413 runAction->setChecked(true);
00414 runAction->setEnabled(false);
00415 connect(runAction, SIGNAL(triggered()), this, SLOT(run()));
00416
00417 stopAction = new QAction(tr("&Run"), this);
00418 stopAction->setIcon(QIcon(":/images/stop.png"));
00419 stopAction->setEnabled(true);
00420 connect(stopAction, SIGNAL(triggered()), this, SLOT(stop()));
00421
00422 saveAsAction = new QAction(tr("&Export"), this);
00423 saveAsAction->setShortcut(tr("Ctrl+E"));
00424 connect(saveAsAction, SIGNAL(triggered()), this, SLOT(saveAs()));
00425
00426
00427 fileMenu = menuBar()->addMenu(tr("&File"));
00428 fileMenu->addAction(saveAsAction);
00429 fileMenu->addAction(exitAction);
00430
00431 editMenu = menuBar()->addMenu(tr("&Edit"));
00432 editMenu->addAction(addSLinkAction);
00433 editMenu->addAction(addALinkAction);
00434
00435 editMenu->addSeparator();
00436 editMenu->addAction(joinAction);
00437 editMenu->addAction(deleteAction);
00438 editMenu->addSeparator();
00439 editMenu->addAction(bringToFrontAction);
00440 editMenu->addAction(sendToBackAction);
00441 editMenu->addSeparator();
00442 editMenu->addAction(propertiesAction);
00443
00444
00445
00446 insertMenu = menuBar()->addMenu(tr("&Insert"));
00447
00448 foreach (QString item, designer->getItemTypes())
00449 {
00450 InsertAction *action = new InsertAction(item, this);
00451 action->setEnabled(false);
00452 connect(action, SIGNAL(triggered(QString)), this, SLOT(insertItem(QString)));
00453 insertMenu->addAction(action);
00454 }
00455 }
00456
00457 void SlateWindow::includeItemType(QString itemType)
00458 {
00459 InsertAction *action = new InsertAction(itemType, this);
00460 action->setEnabled(false);
00461 connect(action, SIGNAL(triggered(QString)), this, SLOT(insertItem(QString)));
00462 insertMenu->addAction(action);
00463
00464 updateActions();
00465 }
00466
00467 void SlateWindow::createToolBars()
00468 {
00469 editToolBar = addToolBar(tr("Edit"));
00470 editToolBar->addAction(addSLinkAction);
00471 editToolBar->addAction(addALinkAction);
00472 editToolBar->addAction(joinAction);
00473 editToolBar->addAction(deleteAction);
00474 editToolBar->addSeparator();
00475 editToolBar->addSeparator();
00476 editToolBar->addAction(bringToFrontAction);
00477 editToolBar->addAction(sendToBackAction);
00478
00479 editToolBar->addSeparator();
00480 editToolBar->addAction(runAction);
00481 editToolBar->addAction(stopAction);
00482 }
00483
00484 Node *SlateWindow::selectedNode() const
00485 {
00486 QList<QGraphicsItem *> items = scene->selectedItems();
00487 if (items.count() == 1) {
00488 return dynamic_cast<Node *>(items.first());
00489 } else {
00490 return 0;
00491 }
00492 }
00493
00494 Link *SlateWindow::selectedLink() const
00495 {
00496 QList<QGraphicsItem *> items = scene->selectedItems();
00497 if (items.count() == 1) {
00498 return dynamic_cast<Link *>(items.first());
00499 } else {
00500 return 0;
00501 }
00502 }
00503
00504 SlateWindow::NodePair SlateWindow::selectedNodePair() const
00505 {
00506 QList<QGraphicsItem *> items = scene->selectedItems();
00507 if (items.count() == 2) {
00508 Node *first = dynamic_cast<Node *>(items.first());
00509 Node *second = dynamic_cast<Node *>(items.last());
00510 if (first && second)
00511 return NodePair(first, second);
00512 }
00513 return NodePair();
00514 }
00515
00516
00517 QList<QGraphicsItem *> SlateWindow::selectedNodeGroup() const
00518 {
00519 QList<QGraphicsItem *> items = onlyParents(scene->selectedItems());
00520
00521
00522 if (items.count() > 1) {
00523
00524 QGraphicsItem * parent = 0;
00525 QMutableListIterator<QGraphicsItem *> i(items);
00526 if (i.hasNext()) parent = i.next()->parentItem();
00527
00528 while (i.hasNext())
00529 if ( i.next()->parentItem() != parent) return QList<QGraphicsItem *>();
00530
00531 return items;
00532 }
00533 return QList<QGraphicsItem *>();
00534 }
00535
00536
00537 QList<QGraphicsItem *> SlateWindow::onlyParents(QList<QGraphicsItem *> items) const
00538 {
00539 QList<QGraphicsItem *> parentItems;
00540
00541 QMutableListIterator<QGraphicsItem *> i(items);
00542 while (i.hasNext()) {
00543 i.next();
00544 bool parent = true;
00545 QMutableListIterator<QGraphicsItem *> j(items);
00546 while (j.hasNext()) {
00547 j.next();
00548 if ( (i.value()) && (i.value()->parentItem() == j.value()) ) {
00549 parent = false;
00550 break;
00551 }
00552 }
00553 if (parent) parentItems.append(i.value());
00554 }
00555
00556 return parentItems;
00557 }
00558
00559 bool SlateWindow::saveAs()
00560 {
00561 QString fileName = QFileDialog::getSaveFileName(this,
00562 tr("Save C++"), ".",
00563 tr("C++ files (*.cpp)"));
00564 if (fileName.isEmpty())
00565 return false;
00566 return saveFile(fileName);
00567 }
00568
00569 bool SlateWindow::saveFile(const QString &fileName)
00570 {
00571 if (!writeCppFile(fileName)) {
00572
00573 return false;
00574 }
00575
00576
00577 return true;
00578 }
00579
00580 bool SlateWindow::writeCppFile(const QString &fileName)
00581 {
00582 QFile file(fileName);
00583 if (!file.open(QIODevice::WriteOnly)) {
00584 QMessageBox::warning(this, tr("QVDesignerGUI"),
00585 tr("Cannot write file %1:\n%2.")
00586 .arg(file.fileName())
00587 .arg(file.errorString()));
00588 return false;
00589 }
00590
00591 QTextStream out(&file);
00592 out << designer->getCppText();
00593
00594 return true;
00595 }
00596
00597
00598 void SlateWindow::showMessage(QString message)
00599 {
00600 if (statusbar)
00601 statusbar->showMessage(message, 10000);
00602 }
00603
00604
00605 void SlateWindow::arrangeItems()
00606 {
00607 QList<QList<ItemNode *> *> levels;
00608 int left = 10;
00609 int bottom = 20;
00610 const int MARGIN = 20;
00611
00612
00613 foreach(ItemNode *node, insertNodes) {
00614 int level = node->precursors();
00615 while(levels.size() <= level)
00616 levels.append(new QList<ItemNode *>);
00617 levels[level]->append(node);
00618 }
00619
00620
00621 foreach(QList<ItemNode *> *levelNodes, levels) {
00622 int maxWidth = 0;
00623 if (levelNodes) {
00624 foreach(ItemNode *node, *levelNodes) {
00625 node->setPos(QPoint(left, bottom));
00626 bottom += (int)node->boundingRect().height() + MARGIN;
00627 int width = (int)node->boundingRect().width();
00628 if (maxWidth < width) maxWidth = width;
00629 }
00630 }
00631 left += maxWidth + MARGIN;
00632 bottom = 20;
00633 }
00634
00635
00636 foreach(QList<ItemNode *> *levelNodes, levels) {
00637 levelNodes->clear();
00638 delete levelNodes;
00639 }
00640 }
00641
00642