PARP Research Group University of Murcia, Spain


src/qvgui/qvdesigner/slate/slatewindow.cpp

00001 /*
00002  *      Copyright (C) 2008, 2009. PARP Research Group.
00003  *      <http://perception.inf.um.es>
00004  *      University of Murcia, Spain.
00005  *
00006  *      This file is part of the QVision library.
00007  *
00008  *      QVision is free software: you can redistribute it and/or modify
00009  *      it under the terms of the GNU Lesser General Public License as
00010  *      published by the Free Software Foundation, version 3 of the License.
00011  *
00012  *      QVision is distributed in the hope that it will be useful,
00013  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *      GNU Lesser General Public License for more details.
00016  *
00017  *      You should have received a copy of the GNU Lesser General Public
00018  *      License along with QVision. If not, see <http://www.gnu.org/licenses/>.
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 "sequenlink.h"
00030 #include "node.h"
00031 #include "groupnode.h"
00032 #include "inputnode.h"
00033 #include "middlenode.h"
00034 #include "outputnode.h"
00035 #include "slateview.h"
00036 #include "insertaction.h"
00037 
00038 #include <QVDesignerGUI>
00039 //#include "../designergui.h"
00040 #include "../facade/itemproperties.h"
00041 
00042 
00043 SlateWindow::SlateWindow(QVDesignerGUI *desig, QWidget * parent): QMainWindow(parent), designer(desig)
00044 {
00045     scene = new QGraphicsScene(-1180, -900, 3200, 2400);
00046 
00047     view = new SlateView;
00048     view->setScene(scene);
00049     view->setDragMode(QGraphicsView::RubberBandDrag);
00050     view->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
00051     view->setContextMenuPolicy(Qt::ActionsContextMenu);
00052     setCentralWidget(view);
00053 
00054     minZ = 0;
00055     maxZ = 0;
00056     seqNumber = 0;
00057 
00058     createMenus();
00059     createToolBars();
00060 
00061         statusbar = new QStatusBar();
00062         setStatusBar(statusbar);
00063 
00064     connect(scene, SIGNAL(selectionChanged()), this, SLOT(updateActions()));
00065 
00066         scene->setBackgroundBrush(QPixmap(":/images/background1.png"));
00067 
00068     setWindowTitle(tr("Slate"));
00069 
00070         showMessage("Pulsa \"Stop\" para poder editar el ejemplo.");
00071 
00072     updateActions();
00073 }
00074 
00075 void SlateWindow::closeEvent(QCloseEvent *)
00076         {
00077         emit closed();
00078         }
00079 
00081 bool SlateWindow::createLink(Node *fromNode, int fromPoint, Node *toNode, int toPoint)
00082 {
00083         // si está en ejecución no se permite lincar
00084         if (stopAction->isEnabled()) return false;
00085 
00086         uint fromId = 0, toId = 0;
00087         fromId = fromNode->getId();
00088         toId = toNode->getId();
00089 
00090         bool sinc = addSLinkAction->isChecked();
00091         bool sequ = (!addSLinkAction->isChecked() && !addALinkAction->isChecked());
00092 
00093         designer->addLink(fromId, fromNode->propName(fromPoint), toId, toNode->propName(toPoint), sinc, sequ);
00094 
00095 return true;
00096 }
00097 
00098 void SlateWindow::addLinkLine(uint fromId, QString fromProp, uint toId, QString toProp, bool sinc, bool sequential)
00099 {
00100         Link *link;
00101         QString linkName = QString("%1").arg(fromId) + "[" + fromProp + "] => " + QString("%1").arg(toId) + "[" + toProp + "]";
00102 
00103         if ( insertNodes.contains(fromId) && insertNodes.contains(toId) ) {
00104                 Node *from = insertNodes.value(fromId);
00105                 Node *to = insertNodes.value(toId);
00106 
00107                 if (sequential) {
00108                         link = new SequenLink(from, fromProp, to, toProp, 0, scene);
00109                         insertLinks.insert(linkName, link);
00110                         link->trackNodes();
00111                 }
00112                 else if (sinc) {
00113                         link = new SincLink(from, fromProp, to, toProp, 0, scene);
00114                         insertLinks.insert(linkName, link);
00115                         link->trackNodes();
00116                 }
00117                 else {
00118                         link = new AsincLink(from, fromProp, to, toProp, 0, scene);
00119                         insertLinks.insert(linkName, link);
00120                         link->trackNodes();
00121                 }
00122         }
00123 }
00124 
00125 void SlateWindow::delLinkLine(uint fromId, QString fromProp, uint toId, QString toProp)
00126 {
00127         QString linkName = QString("%1").arg(fromId) + "[" + fromProp + "] => " + QString("%1").arg(toId) + "[" + toProp + "]";
00128         if (insertLinks.contains(linkName)) {
00129                 delete insertLinks.value(linkName);
00130                 insertLinks.remove(linkName);
00131         }
00132 }
00133 
00134 void SlateWindow::insertItem(QString type)
00135 {
00136         QString name = type.toLower();
00137         name.replace('<', '_');
00138         name.replace(',', '_');
00139         name.replace('>', '_');
00140         name.replace(' ', "");
00141 
00142         designer->addItem(type, name);
00143 }
00144 
00145 void SlateWindow::setName(Node *item, QString name)
00146 {
00147         designer->setName(insertNodes.key(item), name); // si no esta el item devuelve 0, que es id nulo
00148 }
00149 
00150 void SlateWindow::setItemName(uint id, QString name)
00151 {
00152         if (insertNodes.contains(id))
00153                 insertNodes.value(id)->setName(name);
00154 }
00155 
00156 void SlateWindow::addItemNode(QString type, QString name, uint id, ItemProperties *item, uint lastId)
00157 {
00159         bool inputItemsContainsType = false;
00160         foreach(QList<QString> groupItems, designer->getInputItemTypes().values())
00161                 if (groupItems.contains(type)) {
00162                         inputItemsContainsType = true;
00163                         break;
00164                 }
00165         if (inputItemsContainsType) {
00166                 InputNode *node = new InputNode(*item, name, id, this, 0, scene);
00167                 insertNodes.insert(id, node);
00168                 setupNode(node);
00169                 if (insertNodesPos.contains(lastId)) {
00170                         node->setPos(insertNodesPos.value(lastId));
00171                         insertNodesPos.remove(lastId);
00172                         insertNodesPos.insert(id, node->pos());
00173                 }
00174                 else
00175                         insertNodesPos.insert(id, node->pos());
00176         }
00177         else {
00178                 bool middleItemsContainsType = false;
00179                 foreach(QList<QString> groupItems, designer->getMiddleItemTypes().values())
00180                         if (groupItems.contains(type)) {
00181                                 middleItemsContainsType = true;
00182                                 break;
00183                         }
00184                 if (middleItemsContainsType) {
00185                         MiddleNode *node = new MiddleNode(*item, name, id, this, 0, scene);
00186                         insertNodes.insert(id, node);
00187                         setupNode(node);
00188                         if (insertNodesPos.contains(lastId)) {
00189                                 node->setPos(insertNodesPos.value(lastId));
00190                                 insertNodesPos.remove(lastId);
00191                                 insertNodesPos.insert(id, node->pos());
00192                         }
00193                         else
00194                                 insertNodesPos.insert(id, node->pos());
00195                 }
00196                 else {
00197                         bool outputItemsContainsType = false;
00198                         foreach(QList<QString> groupItems, designer->getOutputItemTypes().values())
00199                                 if (groupItems.contains(type)) {
00200                                         outputItemsContainsType = true;
00201                                         break;
00202                                 }
00203                         if (outputItemsContainsType) {
00204                                 OutputNode *node = new OutputNode(*item, name, id, this, 0, scene);
00205                                 insertNodes.insert(id, node);
00206                                 setupNode(node);
00207                                 if (insertNodesPos.contains(lastId)) {
00208                                         node->setPos(insertNodesPos.value(lastId));
00209                                         insertNodesPos.remove(lastId);
00210                                         insertNodesPos.insert(id, node->pos());
00211                                 }
00212                                 else
00213                                         insertNodesPos.insert(id, node->pos());
00214                         }
00215                 }
00216         }
00217 }
00218 
00219 void SlateWindow::delItemNode(uint id)
00220 {
00221         if (insertNodes.contains(id)) {
00222                 insertNodesPos.remove(id);                                                              // guarda la posición del nodo, por si se vuelve a insertar uno con el mismo nombre
00223                 insertNodesPos.insert(id, insertNodes.value(id)->pos());
00224                 delete insertNodes.value(id);
00225                 insertNodes.remove(id);
00226         }
00227 }
00228 
00229 void SlateWindow::addProperty(uint id, QString propName, int type, bool in, bool out)
00230 {
00231         if (insertNodes.contains(id)) {
00232                 insertNodes.value(id)->insertProperty(propName, type, in, out);
00233         }
00234 }
00235 
00236 void SlateWindow::delProperty(uint id, QString propName)
00237 {
00238         if (insertNodes.contains(id)) {
00239                 insertNodes.value(id)->removeProperty(propName);
00240         }
00241 }
00242 
00243 void SlateWindow::del()
00244 {
00245         // primero borro solo los links, ya que al borrar un nodo pueden desaparecer links seleccionados, que se intentarian borrar y daría un core
00246         foreach(QGraphicsItem *item, scene->selectedItems()) {
00247         Link *link = dynamic_cast<Link *>(item);
00248 
00249         if (link && (link->fromNode() != NULL) && (link->toNode() != NULL)) {
00250                         uint fromId = 0, toId = 0;
00251                         fromId = link->fromNode()->getId();
00252                         toId = link->toNode()->getId();
00253 
00254                         designer->delLink(fromId, link->fromProp(), toId, link->toProp());
00255         }
00256     }
00257 
00258         // luego borro los grupos seleccionados
00259         foreach(QGraphicsItem *item, scene->selectedItems()) {
00260                 GroupNode *node = dynamic_cast<GroupNode *>(item);
00261 
00262                 if (node) {
00263                         createdGroupInfos.remove(node);
00264                         createdGroups.remove(node->getId());
00265                         delete node;
00266                 }
00267     }
00268 
00269         // y por último los nodos reatantes
00270         foreach(QGraphicsItem *item, scene->selectedItems()) {
00271                 Node *node = dynamic_cast<InputNode *>(item);
00272                 if (!node) node = dynamic_cast<MiddleNode *>(item);
00273                 if (!node) node = dynamic_cast<OutputNode *>(item);
00274 
00275                 if (node) {
00276                         uint itemnode = 0;
00277                         itemnode = node->getId();
00278                         designer->delItem(itemnode);
00279                 }
00280     }
00281 }
00282 
00283 void SlateWindow::join()
00284 {
00285         QList<QGraphicsItem *> group = selectedNodeGroup();
00286 
00287         // obtengo la posición media de los items a agrupar, para situar el grupo lo más centrado posible
00288         QPointF middlePos;
00289         int count = 0;
00290         foreach (QGraphicsItem *item, group) {
00291                 Node *itemNode = dynamic_cast<Node *>(item);
00292                 if (itemNode) {
00293                         middlePos += itemNode->pos();
00294                         count++;
00295                 }
00296         }
00297         middlePos /= count;
00298 
00299         // creo el nuevo grupo
00300     GroupNode *node = new GroupNode("Group", this, 0, scene);
00301         node->setPos(middlePos);
00302 
00303         // si los items seleccionados estaban ya dentro de otro grupo, este se añade a el (sino a la escena)
00304         if ( !group.isEmpty() && group.first() && group.first()->parentItem() ) {
00305                 GroupNode *parentNode = dynamic_cast<GroupNode *>(group.first()->parentItem());
00306                 if (parentNode) parentNode->addNode(node);
00307         }
00308 
00309         // para cada item si es un nodo lo añado al nuevo grupo
00310         foreach (QGraphicsItem *item, group) {
00311                 Node *itemNode = dynamic_cast<Node *>(item);
00312                 if (itemNode) {
00313                         node->addNode(itemNode);
00314 
00315                         //se actualiza el tamaño de sus links
00316                         //y si la otra punta no se va a meter al grupo pasa a formar parte de este
00317                         foreach (Link *link, itemNode->getInLinks()) {
00318                                 Node *other = link->fromNode();
00319                                 if (group.contains(other)) {
00320                                         QPen pen = link->pen();
00321                                         pen.setWidthF(pen.width()*0.5);
00322                                         link->setPen(pen);
00323                                         link->update();
00324                                 }
00325                         }
00326                         foreach (Link *link, itemNode->getOutLinks()) {
00327                                 Node *other = link->toNode();
00328                                 if (group.contains(other)) {
00329                                         QPen pen = link->pen();
00330                                         pen.setWidthF(pen.width()*0.5);
00331                                         link->setPen(pen);
00332                                         link->update();
00333                                 }
00334                         }
00335                         itemNode->updateLinksPos(); // para que se actualiza la posición y tamaño de los links del nodo
00336                 }
00337         }
00338 
00339         createdGroupInfos.insert(node, node->getInfo());
00340         createdGroups.insert(node->getId(), node);
00341 }
00342 
00343 void SlateWindow::bringToFront()
00344 {
00345     maxZ += 2; // dos, uno para el y otro para sus link que serán: el + 1
00346     setZValue(maxZ);
00347 }
00348 
00349 void SlateWindow::sendToBack()
00350 {
00351     minZ += 2; // dos, uno para el y otro para sus link que serán: el + 1
00352     setZValue(minZ);
00353 }
00354 
00355 void SlateWindow::run()
00356 {
00357         foreach (QAction *action, insertMenu->actions()) {
00358                 action->setEnabled(false);
00359         }
00360         foreach (QMenu *submenu, insertSubmenus) {
00361                 submenu->setEnabled(false);
00362                 foreach (QAction *action, submenu->actions()) {
00363                         action->setEnabled(false);
00364                 }
00365         }
00366 
00367         deleteAction->setEnabled(false);
00368         openAction->setEnabled(false);
00369 
00370         runAction->setEnabled(false);
00371         stopAction->setEnabled(true);
00372         designer->run();
00373 }
00374 
00375 void SlateWindow::stop()
00376 {
00377         designer->stop();
00378         stopAction->setEnabled(false);
00379         runAction->setChecked(false);
00380         runAction->setEnabled(true);
00381 
00382     bool hasSelection = !scene->selectedItems().isEmpty();
00383         deleteAction->setEnabled(hasSelection);
00384         openAction->setEnabled(true);
00385 
00386         foreach (QAction *action, insertMenu->actions()) {
00387                 action->setEnabled(true);
00388         }
00389         foreach (QMenu *submenu, insertSubmenus) {
00390                 foreach (QAction *action, submenu->actions()) {
00391                         action->setEnabled(true);
00392                 }
00393                 submenu->setEnabled(true);
00394         }
00395 }
00396 
00397 void SlateWindow::setZValue(int z)
00398 {
00399     Node *node = selectedNode();
00400     if (node) {
00401         node->setZValue(z);
00402                 node->updateLinksPos();
00403         }
00404 }
00405 
00406 void SlateWindow::showProperties()
00407 {
00408     Node *node = selectedNode();
00409 
00410     if (node) showProperties(node);
00411 }
00412 
00413 void SlateWindow::showProperties(Node *node)
00414 {
00415         uint itemnode = 0;
00416         itemnode = node->getId();
00417 
00418         designer->showProperties(itemnode);
00419 }
00420 
00421 void SlateWindow::updateActions()
00422 {
00423     bool hasSelection = !scene->selectedItems().isEmpty();
00424     bool isNode = (selectedNode() != 0);
00425 //      bool isNodePair = (selectedNodePair() != NodePair());
00426         bool isNodeGroup = false;
00427         int count = 0;
00428         foreach (QGraphicsItem *item, selectedNodeGroup())
00429                 if (dynamic_cast<Node *>(item)) count++;
00430         if (count > 0) isNodeGroup = true;
00431 
00432         joinAction->setEnabled(isNodeGroup);
00433         // si está en ejecución no se permite borrar
00434     if (runAction->isEnabled()) {
00435                 deleteAction->setEnabled(hasSelection);
00436                 openAction->setEnabled(true);
00437         }
00438     bringToFrontAction->setEnabled(isNode);
00439     sendToBackAction->setEnabled(isNode);
00440     propertiesAction->setEnabled(isNode);
00441 
00442     foreach (QAction *action, view->actions())
00443         view->removeAction(action);
00444 
00445     foreach (QAction *action, editMenu->actions()) {
00446         if (action->isEnabled())
00447             view->addAction(action);
00448     }
00449 
00450         if (!hasSelection) {
00451                 // añado las acciones del menu insertar al desplegable del botón derecho (de dos formas distintas)
00452                 QAction *insertTitle = new QAction(tr("Insert"), this);
00453                 insertTitle->setEnabled(false);
00454                 QFont font(insertTitle->font());
00455                 font.setWeight(QFont::Black);
00456                 font.setStyle(QFont::StyleItalic);
00457                 insertTitle->setFont(font);
00458                 view->addAction(insertTitle);
00459                 view->addActions(insertMenu->actions());
00460         }
00461 }
00462 
00463 void SlateWindow::clearSelection()
00464 {
00465         scene->clearSelection();
00466 }
00467 
00468 bool SlateWindow::isSelected(QGraphicsItem *item)
00469 {
00470         return scene->selectedItems().contains(item);
00471 }
00472 
00473 void SlateWindow::setupNode(Node *node)
00474 {
00475     node->setPos( QPoint(10 + (seqNumber % 10) * 6, 20 + (seqNumber % 10) * 6) );
00476     ++seqNumber;
00477 
00478     clearSelection();
00479     node->setSelected(true);
00480     bringToFront();
00481 }
00482 
00483 void SlateWindow::createMenus()
00484 {
00486     exitAction = new QAction(tr("E&xit"), this);
00487     exitAction->setShortcut(tr("Ctrl+Q"));
00488     connect(exitAction, SIGNAL(triggered()), this, SLOT(close()));
00489 
00490     addALinkAction = new QAction(tr("&Asynchronous Link Mode"), this);
00491     addALinkAction->setIcon(QIcon(":/images/alink.png"));
00492     addALinkAction->setShortcut(tr("Ctrl+A"));
00493         addALinkAction->setCheckable(true); // para que se mantenga pulsada
00494         addALinkAction->setChecked(true); // por defecto está seleccionado asincrono
00495 
00496     addSLinkAction = new QAction(tr("&Synchronous Link Mode"), this);
00497     addSLinkAction->setIcon(QIcon(":/images/slink.png"));
00498     addSLinkAction->setShortcut(tr("Ctrl+S"));
00499         addSLinkAction->setCheckable(true); // para que se mantenga pulsada
00500 
00501     addQLinkAction = new QAction(tr("Se&quential Link Mode"), this);
00502     addQLinkAction->setIcon(QIcon(":/images/qlink.png"));
00503     addQLinkAction->setShortcut(tr("Ctrl+Q"));
00504         addQLinkAction->setCheckable(true); // para que se mantenga pulsada
00505 
00506         // con esto conseguimos meterlas en un grupo exclusivo, o una o la otra
00507         linkGroup = new QActionGroup(this);
00508         linkGroup->setExclusive(true);
00509         linkGroup->addAction(addALinkAction);
00510         linkGroup->addAction(addSLinkAction);
00511         linkGroup->addAction(addQLinkAction);
00512 
00513 
00514     joinAction = new QAction(tr("&Join"), this);
00515     joinAction->setIcon(QIcon(":/images/join.png"));
00516     joinAction->setShortcut(tr("Ctrl+J"));
00517     connect(joinAction, SIGNAL(triggered()), this, SLOT(join()));
00518 
00519     deleteAction = new QAction(tr("&Delete"), this);
00520     deleteAction->setIcon(QIcon(":/images/delete.png"));
00521     deleteAction->setShortcut(tr("Del"));
00522         deleteAction->setEnabled(false);
00523     connect(deleteAction, SIGNAL(triggered()), this, SLOT(del()));
00524 
00525     bringToFrontAction = new QAction(tr("Bring to &Front"), this);
00526     bringToFrontAction->setIcon(QIcon(":/images/bringtofront.png"));
00527     connect(bringToFrontAction, SIGNAL(triggered()),this, SLOT(bringToFront()));
00528 
00529     sendToBackAction = new QAction(tr("&Send to Back"), this);
00530     sendToBackAction->setIcon(QIcon(":/images/sendtoback.png"));
00531     connect(sendToBackAction, SIGNAL(triggered()), this, SLOT(sendToBack()));
00532 
00533     propertiesAction = new QAction(tr("P&roperties..."), this);
00534     connect(propertiesAction, SIGNAL(triggered()), this, SLOT(showProperties()));
00535 
00536     runAction = new QAction(tr("&Run"), this);
00537     runAction->setIcon(QIcon(":/images/run.png"));
00538         runAction->setCheckable(true); // para que se mantenga pulsada
00539         runAction->setChecked(true); // porque comienza en ejecución
00540         runAction->setEnabled(false); // porque comienza en ejecución
00541     connect(runAction, SIGNAL(triggered()), this, SLOT(run()));
00542 
00543     stopAction = new QAction(tr("&Stop"), this);
00544     stopAction->setIcon(QIcon(":/images/stop.png"));
00545         stopAction->setEnabled(true); // porque comienza en ejecución
00546     connect(stopAction, SIGNAL(triggered()), this, SLOT(stop()));
00547 
00548     exportAction = new QAction(tr("&Export"), this);
00549     exportAction->setShortcut(tr("Ctrl+E"));
00550     connect(exportAction, SIGNAL(triggered()), this, SLOT(exportAs()));
00551 
00552     saveAsAction = new QAction(tr("&Save As"), this);
00553     saveAsAction->setShortcut(tr("Ctrl+S"));
00554     connect(saveAsAction, SIGNAL(triggered()), this, SLOT(saveAs()));
00555 
00556     openAction = new QAction(tr("&Load"), this);
00557     openAction->setShortcut(tr("Ctrl+L"));
00558         openAction->setEnabled(false);
00559     connect(openAction, SIGNAL(triggered()), this, SLOT(open()));
00560 
00561     fileMenu = menuBar()->addMenu(tr("&File"));
00562         fileMenu->addAction(exportAction);
00563         fileMenu->addAction(saveAsAction);
00564         fileMenu->addAction(openAction);
00565     fileMenu->addAction(exitAction);
00566 
00567     editMenu = menuBar()->addMenu(tr("&Edit"));
00568     editMenu->addAction(addALinkAction);
00569     editMenu->addAction(addSLinkAction);
00570     editMenu->addAction(addQLinkAction);
00571 
00572     editMenu->addSeparator();
00573     editMenu->addAction(joinAction);
00574     editMenu->addAction(deleteAction);
00575     editMenu->addSeparator();
00576     editMenu->addAction(bringToFrontAction);
00577     editMenu->addAction(sendToBackAction);
00578     editMenu->addSeparator();
00579     editMenu->addAction(propertiesAction);
00580 
00581 
00582         // generamos el insert menu a partir de la lista que nos devuelve el controlador
00583         insertMenu = menuBar()->addMenu(tr("&Insert"));
00584 
00585         QMap<QString, QList<QString> > itemTypes = designer->getItemTypes();
00586         foreach (QString group, itemTypes.keys()) {
00587                 QMenu *submenu = insertMenu->addMenu(group);
00588                 submenu->setEnabled(false);
00589                 insertSubmenus.append(submenu);
00590 
00591                 foreach (QString item, itemTypes.value(group))
00592                 {
00593                         InsertAction *action = new InsertAction(item, this);
00594                         action->setEnabled(false);
00595                         connect(action, SIGNAL(triggered(QString)), this, SLOT(insertItem(QString)));
00596                         submenu->addAction(action);
00597                 }
00598         }
00599         insertUserSubmenu = insertMenu->addMenu("User node");
00600         insertUserSubmenu->setEnabled(false);
00601         insertSubmenus.append(insertUserSubmenu);
00602 }
00603 
00604 void SlateWindow::includeItemType(QString itemType)
00605 {
00606         InsertAction *action = new InsertAction(itemType, this);
00607         action->setEnabled(false);
00608         connect(action, SIGNAL(triggered(QString)), this, SLOT(insertItem(QString)));
00609         insertUserSubmenu->addAction(action);
00610 
00611         updateActions();
00612 }
00613 
00614 void SlateWindow::createToolBars()
00615 {
00616     editToolBar = addToolBar(tr("Edit"));
00617     editToolBar->addAction(addALinkAction);
00618     editToolBar->addAction(addSLinkAction);
00619     editToolBar->addAction(addQLinkAction);
00620     editToolBar->addAction(joinAction);
00621     editToolBar->addAction(deleteAction);
00622     editToolBar->addSeparator();
00623     editToolBar->addSeparator();
00624     editToolBar->addAction(bringToFrontAction);
00625     editToolBar->addAction(sendToBackAction);
00626 
00627         editToolBar->addSeparator();
00628         editToolBar->addAction(runAction);
00629         editToolBar->addAction(stopAction);
00630 }
00631 
00632 Node *SlateWindow::selectedNode() const
00633 {
00634     QList<QGraphicsItem *> items = scene->selectedItems();
00635     if (items.count() == 1) {
00636         return dynamic_cast<Node *>(items.first());
00637     } else {
00638         return 0;
00639     }
00640 }
00641 
00642 Link *SlateWindow::selectedLink() const
00643 {
00644     QList<QGraphicsItem *> items = scene->selectedItems();
00645     if (items.count() == 1) {
00646         return dynamic_cast<Link *>(items.first());
00647     } else {
00648         return 0;
00649     }
00650 }
00651 
00652 SlateWindow::NodePair SlateWindow::selectedNodePair() const
00653 {
00654     QList<QGraphicsItem *> items = scene->selectedItems();
00655     if (items.count() == 2) {
00656         Node *first = dynamic_cast<Node *>(items.first());
00657         Node *second = dynamic_cast<Node *>(items.last());
00658         if (first && second)
00659             return NodePair(first, second);
00660     }
00661     return NodePair();
00662 }
00663 
00664 // devuelve la lista de onlyParents seleccionados, si todos ellos comparten padre (ya sea 0 o un grupo), tambien devuelve los link de dicha lista
00665 QList<QGraphicsItem *> SlateWindow::selectedNodeGroup() const
00666 {
00667     QList<QGraphicsItem *> items = onlyParents(scene->selectedItems());
00668 
00669         //si quedan almemos dos
00670     if (items.count() > 1) {
00671                 // y si comparten padre
00672                 QGraphicsItem * parent = 0;
00673                 QMutableListIterator<QGraphicsItem *> i(items);
00674                 if (i.hasNext()) parent = i.next()->parentItem();
00675 
00676                 while (i.hasNext())
00677                         if ( i.next()->parentItem() != parent) return QList<QGraphicsItem *>();
00678 
00679                 return items;
00680     }
00681     return items;
00682 }
00683 
00684 // obtiene los QGraphicsItem de la lista cuyo padre no pertenece a la lista
00685 QList<QGraphicsItem *> SlateWindow::onlyParents(QList<QGraphicsItem *> items) const
00686 {
00687     QList<QGraphicsItem *> parentItems;
00688 
00689     QMutableListIterator<QGraphicsItem *> i(items);
00690     while (i.hasNext()) {
00691                 i.next();
00692                 bool parent = true;
00693                 QMutableListIterator<QGraphicsItem *> j(items);
00694                 while (j.hasNext()) {
00695                         j.next();
00696                         if ( (i.value()) && (i.value()->parentItem() == j.value()) ) {
00697                                 parent = false;
00698                                 break;
00699                         }
00700                 }
00701                 if (parent) parentItems.append(i.value());
00702     }
00703 
00704         return parentItems;
00705 }
00706 
00707 bool SlateWindow::exportAs()
00708 {
00709     QString fileName = QFileDialog::getSaveFileName(this,
00710                                tr("Save C++"), ".",
00711                                tr("C++ files (*.cpp)"));
00712     if (fileName.isEmpty())
00713         return false;
00714         return saveFile(fileName, false);
00715 }
00716 
00717 bool SlateWindow::saveAs()
00718 {
00719     QString fileName = QFileDialog::getSaveFileName(this,
00720                                tr("Save XML"), ".",
00721                                tr("XML files (*.xml)"));
00722     if (fileName.isEmpty())
00723         return false;
00724         return saveFile(fileName, true);
00725 }
00726 
00727 bool SlateWindow::open()
00728 {
00729     QString fileName = QFileDialog::getOpenFileName(this,
00730                                tr("Open File"), ".",
00731                                tr("XML files (*.xml)"));
00732     if (fileName.isEmpty()) return false;
00733 
00734 
00735     QFile file(fileName);
00736     if (!file.open(QIODevice::ReadOnly)) {
00737         QMessageBox::warning(this, tr("QVDesignerGUI"),
00738                              tr("Cannot open file %1:\n%2.")
00739                              .arg(file.fileName())
00740                              .arg(file.errorString()));
00741         return false;
00742     }
00743         QTextStream in(&file);
00744     return (designer->loadXML(in.readAll()));
00745 }
00746 
00747 bool SlateWindow::saveFile(const QString &fileName, bool xmlFile)
00748 {
00749     QFile file(fileName);
00750     if (!file.open(QIODevice::WriteOnly)) {
00751         QMessageBox::warning(this, tr("QVDesignerGUI"),
00752                              tr("Cannot write file %1:\n%2.")
00753                              .arg(file.fileName())
00754                              .arg(file.errorString()));
00755         return false;
00756     }
00757 
00758     QTextStream out(&file);
00759         if (xmlFile)
00760                 out << designer->getXMLText();
00761         else
00762             out << designer->getCppText();
00763 
00764     return true;
00765 }
00766 
00767 void SlateWindow::showMessage(QString message)
00768 {
00769         if (statusbar)
00770                 statusbar->showMessage(message, 10000); // lo muestra 10 segundos
00771 }
00772 
00773 
00774 void SlateWindow::arrangeItems()
00775 {
00776         QList<QList<Node *> *> levels;
00777         int left = 10;
00778         int bottom = 20;
00779         const int MARGIN = 20;
00780 
00781         // obtengo los niveles en que se encuentran los items, organizandolos por columnas en "levels"
00782         foreach(Node *node, insertNodes) {
00783                 int level = node->precursors();
00784                 while(levels.size() <= level)
00785                         levels.append(new QList<Node *>);
00786                 levels[level]->append(node);
00787         }
00788 
00789         //muevo los items en la pizarra en función de los tamaños y niveles de estos
00790         foreach(QList<Node *> *levelNodes, levels) {
00791                 int maxWidth = 0;
00792                 if (levelNodes) {
00793                         foreach(Node *node, *levelNodes) {
00794                                 node->setPos(QPoint(left, bottom));
00795                                 insertNodesPos.insert(insertNodes.key(node), node->pos());
00796                                 bottom += (int)node->boundingRect().height() + MARGIN; //le sumo a bottom el alto mas un margen
00797                                 int width = (int)node->boundingRect().width();
00798                                 if (maxWidth < width) maxWidth = width; //actualiza maxWidth
00799                         }
00800                 }
00801                 left += maxWidth + MARGIN; //le sumo a left maxWide mas un margen
00802                 bottom = 20;//reseteo bottom
00803         }
00804 
00805         // vacio la estructura usada
00806         foreach(QList<Node *> *levelNodes, levels) {
00807                 levelNodes->clear();
00808                 delete levelNodes;
00809         }
00810 }
00811 
00812 QPointF SlateWindow::getNodePos(uint id) const
00813 {
00814         return insertNodesPos.value(id);
00815 }
00816 
00817 bool SlateWindow::moveNode(uint id, QPointF pos)
00818 {
00819         if (insertNodes.contains(id)) {
00820                 Node *node = insertNodes.value(id);
00821                 node->setPos(pos);
00822                 insertNodesPos.remove(id);
00823                 insertNodesPos.insert(id, node->pos());
00824                 return true;
00825         }
00826 
00827         return false;
00828 }
00829 
00830 QList<GroupInfo> SlateWindow::getGroups()
00831 {
00832         // actualizo las posiciones de los grupos antes de pasarlos
00833         foreach(Node *group, createdGroupInfos.keys()) {
00834                 createdGroupInfos[group].setPos(group->pos());
00835         }
00836 
00837         return createdGroupInfos.values();
00838 }
00839 
00840 void SlateWindow::eraseGroups()
00841 {
00842         foreach(Node *group, createdGroupInfos.keys()) {
00843                 delete group;
00844         }
00845 
00846         createdGroupInfos.clear();
00847         createdGroups.clear();
00848 }
00849 
00850 uint SlateWindow::createGroup(GroupInfo info)
00851 {
00852         QList<QGraphicsItem *> group;
00853         foreach (uint nodeId, info.getNodes()) {
00854                 if (insertNodes.contains(nodeId)) {
00855                         group.append(insertNodes.value(nodeId));
00856                 }
00857                 else {
00858 //                      std::cout << QString("ERROR: Devuelvo 0 porque no existe el nodo %1\n").arg(nodeId).toStdString();
00859                         return 0;
00860                 }
00861         }
00862         foreach (uint subgroupId, info.getSubgroups()) {
00863                 if (createdGroups.contains(subgroupId)) {
00864                         group.append(createdGroups.value(subgroupId));
00865                 }
00866                 else {
00867 //                      std::cout << QString("ERROR: Devuelvo 0 porque no existe el grupo %1\n").arg(subgroupId).toStdString();
00868                         return 0;
00869                 }
00870         }
00871 
00872         // creo el nuevo grupo
00873     GroupNode *node = new GroupNode(info.getName(), this, 0, scene);
00874         node->setPos(info.getPos());
00875 
00876         // si los items seleccionados estaban ya dentro de otro grupo, este se añade a el (sino a la escena)
00877         if ( !group.isEmpty() && group.first() && group.first()->parentItem() ) {
00878                 GroupNode *parentNode = dynamic_cast<GroupNode *>(group.first()->parentItem());
00879                 if (parentNode) parentNode->addNode(node);
00880         }
00881 
00882         // para cada item si es un nodo lo añado al nuevo grupo
00883         foreach (QGraphicsItem *item, group) {
00884                 Node *itemNode = dynamic_cast<Node *>(item);
00885                 if (itemNode) {
00886                         node->addNode(itemNode);
00887 
00888                         //se actualiza el tamaño de sus links
00889                         //y si la otra punta no se va a meter al grupo pasa a formar parte de este
00890                         foreach (Link *link, itemNode->getInLinks()) {
00891                                 Node *other = link->fromNode();
00892                                 if (group.contains(other)) {
00893                                         QPen pen = link->pen();
00894                                         pen.setWidthF(pen.width()*0.5);
00895                                         link->setPen(pen);
00896                                         link->update();
00897                                 }
00898                         }
00899                         foreach (Link *link, itemNode->getOutLinks()) {
00900                                 Node *other = link->toNode();
00901                                 if (group.contains(other)) {
00902                                         QPen pen = link->pen();
00903                                         pen.setWidthF(pen.width()*0.5);
00904                                         link->setPen(pen);
00905                                         link->update();
00906                                 }
00907                         }
00908                         itemNode->updateLinksPos(); // para que se actualiza la posición y tamaño de los links del nodo
00909                 }
00910         }
00911 
00912         createdGroupInfos.insert(node, node->getInfo());
00913         createdGroups.insert(node->getId(), node);
00914         node->abstractView(true);
00915 
00916         return node->getId();
00917 }
00918 
00919 
00920 



QVision framework. PARP research group, copyright 2007, 2008.