// return pixmap for zoom 100% QPixmap * get_pixmap(const char * path) { QPixmap * px = DiagramPixmap.find(path); if (px == 0) { QString abspath; if (!QDir::isRelativePath(path)) abspath = path; else if ((UmlWindow::images_root_dir().isEmpty() || !QFile::exists(abspath = QDir::cleanDirPath(UmlWindow::images_root_dir() + '/' + path))) && !QFile::exists(abspath = path)) abspath = BrowserView::get_dir().absFilePath(path); px = new QPixmap(abspath); DiagramPixmap.insert(path, px); if (px->isNull()) { msg_critical(TR("Error"), QString(path) + TR("\ndoesn't exist or is not a know image format")); return 0; } DiagramScaledPixmap.insert(path, new QPtrDict<QPixmap>()); } return (px->isNull()) ? 0 : px; }
void BasicDialog::accept() { if (!check_edits(edits) || !kvtable->check_unique()) return; BrowserNode * bn = data->get_browser_node(); if (edname != 0) { QString s = edname->text().stripWhiteSpace(); if ((s != bn->get_name()) && ((BrowserNode *) bn->parent())->wrong_child_name(s, bn->get_type(), bn->allow_spaces(), bn->allow_empty())) { msg_critical(TR("Error"), edname->text() + TR("\n\nillegal name or already used")); return; } else bn->set_name(s); } bool newst = data->set_stereotype(fromUnicode(edstereotype->currentText().stripWhiteSpace())); bn->set_comment(comment->text()); UmlWindow::update_comment_if_needed(bn); kvtable->update(bn); ProfiledStereotypes::modified(bn, newst); bn->package_modified(); data->modified(); Q3TabDialog::accept(); }
bool KeyValuesTable::check_unique() { forceUpdateCells(); unsigned n = numRows(); if (n != 0) { unsigned index; if (text(n - 1, 0).isEmpty()) n -= 1; QStringList l; for (index = 0; index != n; index += 1) { const QString & s = text(index, 0); if (l.findIndex(s) != -1) { msg_critical(TR("Error"), TR("key '%1' used several times", s)); return FALSE; } else l.append(s); } } return TRUE; }
// return pixmap for zoom 100% QPixmap * get_pixmap(QString path) { QPixmap * px = DiagramPixmap.value(path); if (px == 0) { QString abspath; if (!QDir::isRelativePath(path)) abspath = path; else if ((UmlWindow::images_root_dir().isEmpty() || !QFile::exists(abspath = QDir::cleanPath(UmlWindow::images_root_dir() + '/' + path))) && !QFile::exists(abspath = path)) abspath = BrowserView::get_dir().absoluteFilePath(path); px = new QPixmap(abspath); DiagramPixmap.insert(path, px); if (px->isNull()) { msg_critical(QObject::tr("Error"), QString(path) + QObject::tr("\ndoesn't exist or is not a know image format")); return 0; } DiagramScaledPixmap.insert(path, new QMap<void*,QPixmap*>()); } return (px->isNull()) ? 0 : px; }
bool KeyValuesTable::check_unique() { forceUpdateCells(); unsigned n = rowCount(); if (n != 0) { unsigned index; if (text(n - 1, 0).isEmpty()) n -= 1; QStringList l; for (index = 0; index != n; index += 1) { const QString & s = text(index, 0); if (l.indexOf(s) != -1) { msg_critical(tr("Error"), QObject::tr("key '%1' used several times").arg(s)); return FALSE; } else l.append(s); } } return TRUE; }
bool check_edits(Q3PtrList<BodyDialog> & edits) { if (edits.isEmpty()) return TRUE; return (msg_critical("Douml", TR("Sub dialog(s) still opened\n" "If you choose 'Ok' the dialog will be closed\n" "without taking into account it content"), QMessageBox::Ok, QMessageBox::Abort) == QMessageBox::Ok); }
void PseudoStateDialog::accept() { if (!check_edits(edits) || !kvtable->check_unique()) return; QString s = edname->text().stripWhiteSpace(); BrowserPseudoState * bn = (BrowserPseudoState *) pst->browser_node; if ((s != bn->get_name()) && ((BrowserNode *) bn->parent())->wrong_child_name(s, UmlPseudoState, bn->allow_spaces(), bn->allow_empty())) { msg_critical(TR("Error"), edname->text() + TR("\n\nillegal name or already used")); return; } else bn->set_name(s); bool newst = pst->set_stereotype(fromUnicode(edstereotype->currentText().stripWhiteSpace())); bn->set_comment(comment->text()); UmlWindow::update_comment_if_needed(bn); kvtable->updateNodeFromThis(bn); if (edreference != 0) { int index = reflist.findIndex(edreference->currentText()); BrowserPseudoState * ps; if (index != -1) { ps = (BrowserPseudoState *) pseudostates.at(index); if (! bn->can_reference(ps)) ps = 0; } else ps = 0; pst->set_reference(ps); } ProfiledStereotypes::modified(bn, newst); bn->modified(); bn->package_modified(); pst->modified(); Q3TabDialog::accept(); }
void ActivityDialog::accept() { if (!check_edits(edits) || !kvtable->check_unique()) return; BrowserNode * bn = activity->browser_node; QString s; s = edname->text().trimmed(); if ((s != bn->get_name()) && ((BrowserNode *) bn->parent())->wrong_child_name(s, UmlActivity, bn->allow_spaces(), bn->allow_empty())) msg_critical(tr("Error"), s + tr("\n\nillegal name or already used")); else { bn->set_name(s); bool newst = activity->set_stereotype(fromUnicode(edstereotype->currentText().trimmed())); int index = list.indexOf(edspecification->currentText().trimmed()); activity->set_specification((index != -1) ? (BrowserOperation *) opers.at(index) : 0); activity->read_only = readonly_cb->isChecked(); activity->single_execution = singlexec_cb->isChecked(); activity->is_active = active_cb->isChecked(); uml.accept(activity->uml_condition); cpp.accept(activity->cpp_condition); java.accept(activity->java_condition); bn->set_comment(comment->text()); UmlWindow::update_comment_if_needed(bn); activity->constraint = constraint->trimmedText(); kvtable->updateNodeFromThis(bn); ProfiledStereotypes::modified(bn, newst); bn->modified(); bn->package_modified(); activity->modified(); TabDialog::accept(); } }
bool BrowserNode::enter_child_name(QString & r, const QString & msg, UmlCode type, bool allow_spaces, bool allow_empty) { for (;;) { BooL ok = FALSE; r = MyInputDialog::getText("Uml", msg, QString::null, ok); if (ok) { if (wrong_child_name(r, type, allow_spaces, allow_empty)) msg_critical(TR("Error"), r + "\n\n" + TR("illegal name or already used")); else return TRUE; } else return FALSE; } }
void TransitionDialog::accept() { if (!check_edits(edits) || !kvtable->check_unique()) return; BrowserNode * bn = rel->browser_node; QString s; s = edname->text().trimmed(); if (s.isEmpty()) s = "<transition>"; if ((s != bn->get_name()) && ((BrowserNode *) bn->parent())->wrong_child_name(s, UmlTransition, bn->allow_spaces(), bn->allow_empty())) msg_critical(tr("Error"), s + tr("\n\nillegal name or already used")); else { bn->set_name(s); bool newst = rel->set_stereotype(fromUnicode(edstereotype->currentText().trimmed())); if (internal_cb != 0) rel->set_internal(internal_cb->isChecked()); uml.accept(rel->uml); cpp.accept(rel->cpp); java.accept(rel->java); bn->set_comment(comment->text()); UmlWindow::update_comment_if_needed(bn); kvtable->updateNodeFromThis(bn); ProfiledStereotypes::modified(bn, newst); bn->modified(); bn->package_modified(); rel->modified(); TabDialog::accept(); } }
void ParameterSetDialog::accept() { if (!check_edits(edits) || !kvtable->check_unique()) return; QString s = edname->text().stripWhiteSpace(); BrowserParameterSet * bn = (BrowserParameterSet *) data->get_browser_node(); if ((s != bn->get_name()) && ((BrowserNode *) bn->parent())->wrong_child_name(s, bn->get_type(), bn->allow_spaces(), bn->allow_empty())) msg_critical(TR("Error"), edname->text() + TR("\n\nillegal name or already used")); else { bn->set_name(s); bn->set_comment(comment->text()); UmlWindow::update_comment_if_needed(bn); QString stereotype = fromUnicode(edstereotype->currentText().stripWhiteSpace()); bool newst = data->set_stereotype(stereotype); Q3ValueList<BrowserPin *> l; unsigned n = lb_member->count(); for (unsigned i = 0; i != n; i += 1) l.append((BrowserPin *) (((ListBoxBrowserNode *) lb_member->item(i)) ->browser_node)); data->set_pins(l); kvtable->updateNodeFromThis(bn); ProfiledStereotypes::modified(bn, newst); bn->modified(); bn->package_modified(); data->modified(); Q3TabDialog::accept(); } }
bool BrowserNode::enter_child_name(QString & r, const QString & msg, UmlCode type, BrowserNodeList & nodes, BrowserNode ** old, bool allow_spaces, bool allow_empty, bool existing) { if (existing && nodes.isEmpty()) { msg_warning(TR("Error"), TR("nothing available")); return FALSE; } QStringList list; nodes.full_names(list); list.prepend(QString::null); *old = 0; for (;;) { BooL ok = FALSE; r = (list.count() == 1) ? MyInputDialog::getText("Uml", msg, QString::null, ok) : MyInputDialog::getText("Uml", msg, list, QString::null, existing, ok); if (! ok) return FALSE; if (!r.isEmpty()) { int index = list.findIndex(r); if (index != -1) { *old = nodes.at(index - 1); return TRUE; } } if (wrong_child_name(r, type, allow_spaces, allow_empty)) msg_critical(TR("Error"), r + "\n\n" + TR("illegal name or already used")); else return TRUE; } }
void ExpansionRegionDialog::accept() { if (!check_edits(edits) || !kvtable->check_unique()) return; BrowserNode * bn = data->get_browser_node(); if (edname != 0) { QString s = edname->text().trimmed(); if ((s != bn->get_name()) && ((BrowserNode *) bn->parent())->wrong_child_name(s, bn->get_type(), bn->allow_spaces(), bn->allow_empty())) { msg_critical(TR("Error"), edname->text() + TR("\n\nillegal name or already used")); return; } else bn->set_name(s); } data->must_isolate = must_isolate_cb->isChecked(); data->mode = expansion_mode_kind(edmode->currentText().toLatin1().constData()); bool newst = data->set_stereotype(fromUnicode(edstereotype->currentText().trimmed())); bn->set_comment(comment->text()); UmlWindow::update_comment_if_needed(bn); kvtable->updateNodeFromThis(bn); ProfiledStereotypes::modified(bn, newst); bn->package_modified(); data->modified(); TabDialog::accept(); }
void FlowDialog::accept() { if (!check_edits(edits) || !kvtable->check_unique()) return; BrowserNode * bn = flow->browser_node; QString s; s = edname->text().stripWhiteSpace(); if ((s != bn->get_name()) && ((BrowserNode *) bn->parent())->wrong_child_name(s, UmlFlow, bn->allow_spaces(), bn->allow_empty())) msg_critical(TR("Error"), s + TR("\n\nillegal name or already used")); else { bn->set_name(s); bool newst = flow->set_stereotype(fromUnicode(edstereotype->currentText().stripWhiteSpace())); uml.accept(flow->uml); cpp.accept(flow->cpp); java.accept(flow->java); bn->set_comment(comment->text()); UmlWindow::update_comment_if_needed(bn); kvtable->updateNodeFromThis(bn); ProfiledStereotypes::modified(bn, newst); bn->modified(); bn->package_modified(); flow->modified(); Q3TabDialog::accept(); } }
void edit(const QString & s, QString name, void * id, EditType k, Q3TabDialog * d, post_edit pf, Q3PtrList<BodyDialog> & edits) { QString ed = DoumlEditor; if (!ed.isEmpty() && (pf != 0)) { // try to use it QString f; QString firstProto = "%s_%lx_%d.%s"; QString secondProto = "%s_%lx_%d.txt"; firstProto = firstProto.arg(name) .arg(QString::number((unsigned long) id)) .arg(QString::number((unsigned long) user_id())); secondProto=secondProto.arg(name) .arg(QString::number((unsigned long) id)) .arg(QString::number((unsigned long) user_id())); switch (k) { case CppEdit: firstProto=firstProto.arg(GenerationSettings::get_cpp_src_extension()); f=firstProto; break; case JavaEdit: firstProto=firstProto.arg(GenerationSettings::get_java_extension()); f=firstProto; break; case PhpEdit: firstProto=firstProto.arg(GenerationSettings::get_php_extension()); f=firstProto; break; case PythonEdit: firstProto=firstProto.arg(GenerationSettings::get_python_extension()); f=firstProto; break; default: // TxTEdit f = secondProto; } for (int index = 0; index != (int) name.length(); index += 1) if (!f[index].isLetterOrNumber()) f.replace(index, 1, "_"); QString path = BrowserView::get_dir().absFilePath(f); FILE * fp = fopen((const char *) path, "wb"); if (fp != 0) { if (!s.isEmpty()) fputs((const char *) s, fp); fclose(fp); ed += " \"" + path + "\"&"; (void) system(ed); if (d->hasOkButton() && (pf != 0)) (new DialogTimer(s, path, d, pf))->start(1000); return; } else msg_critical("Error", TR("Cannot open '%1'", path)); } else if (d->isModal()) { BodyDialog * bd = new BodyDialog(s, d, pf, k, name, edits); bd->exec(); // will be deleted elsewhere } else (new BodyDialog(s, d, pf, k, name, edits))->show(); }
void ParameterDialog::accept() { if (!check_edits(edits) || !kvtable->check_unique()) return; BrowserNode * bn = param->browser_node; QString s; s = edname->text().trimmed(); if ((s != param->name()) && ((BrowserNode *) bn->parent())->wrong_child_name(s, UmlParameter, bn->allow_spaces(), bn->allow_empty())) msg_critical(tr("Error"), s + tr("\n\nillegal name or already used")); else { // check consistency UmlParamDirection dir = direction(eddir->currentText()); bool exception = exception_rb->isChecked(); UmlParamEffect effect = ::effect(edeffect->currentText()); QString err; if ((dir == UmlIn) && exception) err = tr("An input parameter cannot be an exception.\n"); switch (effect) { case UmlDelete: if ((dir != UmlIn) && (dir != UmlInOut)) err += tr("Only in and inout parameter may have a delete effect."); break; case UmlCreate: if ((dir != UmlOut) && (dir != UmlInOut) && (dir != UmlReturn)) err += tr("Only out, inout and return parameter may have a create effect."); break; default: break; } if (!err.isEmpty()) msg_critical(tr("Error"), err); else { bn->set_name(s); bool newst = param->set_stereotype(fromUnicode(edstereotype->currentText().trimmed())); AType t; s = edtype->currentText().trimmed(); if (!s.isEmpty()) { int index = list.indexOf(s); if (index >= 0) t.type = (BrowserClass *) nodes.at(index); else t.explicit_type = s; } param->set_type(t); param->dir = dir; param->multiplicity = edmultiplicity->currentText().trimmed(); param->ordering = ordering(edordering->currentText().toLatin1()); param->effect = effect; param->is_control = is_control_cb->isChecked(); param->unique = unique_cb->isChecked(); param->exception = exception; param->stream = stream_rb->isChecked(); param->in_state = edin_state->text().trimmed(); param->default_value = edinit->text(); param->uml_selection = eduml_selection->text().trimmed(); param->cpp_selection = edcpp_selection->text().trimmed(); param->java_selection = edjava_selection->text().trimmed(); bn->set_comment(comment->text()); UmlWindow::update_comment_if_needed(bn); kvtable->updateNodeFromThis(bn); ProfiledStereotypes::modified(bn, newst); bn->modified(); bn->package_modified(); param->modified(); TabDialog::accept(); } } }
void BrowserNode::DropAfterEvent(QDropEvent * e, BrowserNode *) { e->ignore(); msg_critical(TR("Error"), TR("Forbidden")); }
void ColDiagramView::contentsMousePressEvent(QMouseEvent * e) { if (!window()->frozen()) { if (e->button() == ::Qt::RightButton) DiagramView::contentsMousePressEvent(e); else { UmlCode c = window()->buttonOn(); switch (c) { case UmlClass: { history_protected = FALSE; unselect_all(); window()->selectOn(); history_save(); BrowserNode * parent = ((BrowserNode *) window()->browser_diagram()->parent()); BrowserClass * b = BrowserClass::get_class(parent); if (b != 0) { CodClassInstCanvas * cl = new CodClassInstCanvas(b, the_canvas(), e->x(), e->y(), 0); cl->show(); cl->upper(); window()->package_modified(); } } canvas()->update(); break; case UmlClassInstance: { history_protected = TRUE; unselect_all(); window()->selectOn(); history_save(); BrowserNode * parent = ((BrowserNode *) window()->browser_diagram()->parent()); BrowserClassInstance * b = BrowserClassInstance::get_classinstance(parent); if (b != 0) { CodClassInstCanvas * cl = new CodClassInstCanvas(b, the_canvas(), e->x(), e->y(), 0); cl->show(); cl->upper(); window()->package_modified(); } } canvas()->update(); history_protected = FALSE; break; case UmlSelfLink: { history_protected = TRUE; window()->selectOn(); history_save(); Q3CanvasItem * ci = the_canvas()->collision(e->pos()); if (ci != 0) { DiagramItem * i = QCanvasItemToDiagramItem(ci); if (i != 0) { QString err = i->may_start(c); if (!err.isEmpty()) msg_critical("Douml", err); else { i->connexion(c, i, e->pos(), e->pos()); window()->package_modified(); } } } } canvas()->update(); history_protected = FALSE; break; default: DiagramView::contentsMousePressEvent(e); break; } } } else DiagramView::contentsMousePressEvent(e); }
int main(int argc, char ** argv) { ExitOnError = FALSE; QApplication a(argc, argv); QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8")); //#ifdef DEBUG QsLogging::Logger & logger = QsLogging::Logger::instance(); logger.setLoggingLevel(QsLogging::TraceLevel); QDir dir; dir.setPath(qApp->applicationDirPath()); dir.remove(QString("douml") + QString(".log")); const QString sLogPath(QDir(qApp->applicationDirPath()).filePath(QString("douml") + QString(".log"))); QsLogging::DestinationPtr fileDestination(QsLogging::DestinationFactory::MakeFileDestination(sLogPath)); QsLogging::DestinationPtr debugDestination(QsLogging::DestinationFactory::MakeDebugOutputDestination()); logger.addDestination(debugDestination.get()); logger.addDestination(fileDestination.get()); QLOG_INFO() << "Starting the log"; //#endif An<EdgeMenuFactory> factory; factory->AddFactory(TypeIdentifier<ClassDialog>::id(), CreateClassDialogMenu); factory->AddConnectionFunctor(TypeIdentifier<ClassDialog>::id(), ConnectToClassDialog<EdgeMenuDialog>); factory->AddFactory(TypeIdentifier<OperationDialog>::id(), CreateClassDialogMenu); factory->AddConnectionFunctor(TypeIdentifier<OperationDialog>::id(), ConnectToClassDialog<EdgeMenuDialog>); factory->AddFactory(TypeIdentifier<ArtifactDialog>::id(), CreateLimitedDialogMenu); factory->AddConnectionFunctor(TypeIdentifier<ArtifactDialog>::id(), ConnectToLimitedDialog<EdgeMenuDialog>); factory->AddFactory(TypeIdentifier<ConstructorInitializerDialog>::id(), CreateLimitedDialogMenu); factory->AddConnectionFunctorQt4(TypeIdentifier<ConstructorInitializerDialog>::id(), ConnectToLimitedDialog<EdgeMenuDialogQt4>); UmlDesktop::init(); QSettings settings("settings.ini", QSettings::IniFormat); settings.setIniCodec(QTextCodec::codecForName("UTF-8")); bool overridePresent = QFileInfo("override_transition.txt").exists(); if(settings.value("Main/compatibility_save") .toInt() == 1 && !overridePresent) { QMessageBox::warning(0, QObject::tr("Warning"), QObject::tr("Douml is working in transitional mode.\n All UI improvements are yours to use, " "but saving is done in the format of Bouml 4.22 " "which loses all new c++11 and hierarchy specifiers\n\n" "To suppress this warning place empty file override_transition.txt into the application folder\n" "To disable the mode - change compatibility_save parameter to 0 in settings.ini\n")); } // note : bool conv_env = !QDir::home().exists(".doumlrc") doesn't work // if the path contains non latin1 characters, for instance cyrillic ! QString s = QDir::home().absFilePath(".doumlrc"); FILE * fp = fopen((const char *) s, "r"); bool conv_env = (fp == 0); if (conv_env) EnvDialog::edit(TRUE); else fclose(fp); read_doumlrc(); // for virtual desktop init_pixmaps(); init_font(); Shortcut::init(conv_env); bool exec = FALSE; bool no_gui = FALSE; if (argc > 3) { if (!strcmp(argv[2], "-execnogui")) exec = no_gui = TRUE; else exec = !strcmp(argv[2], "-exec"); } UmlWindow * uw = new UmlWindow(exec); if (no_gui) UmlDesktop::set_nogui(); else { uw->showMaximized(); } if (argc > 1) { try { if ((argc == 3) && !strcmp(argv[2], "-root") && (msg_critical(TR("DO NOT CONFIRM"), TR("Root mode protection\n\n" "This mode allows me to develop BOUML\n\n" "do NOT confirm to avoid a disaster !!!\n\n" "confirm ?"), QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)) { set_user_id(0); set_editor(getenv("BOUML_EDITOR")); // no environment file argc = 1; } uw->load_it(argv[1]); } catch (...) { // cannot read a file return -1; } } QObject::connect(&a, SIGNAL(lastWindowClosed()), &a, SLOT(quit())); try { if (argc > 2) { if (exec) { bool with_exit = FALSE; if (!strcmp(argv[argc - 1], "-exit")) { with_exit = TRUE; argc -= 1; } WrapperStr cmd = argv[3]; WrapperStr space = " "; int index; for (index = 4; index != argc; index += 1) cmd += space + WrapperStr(argv[index]); ToolCom::run((const char *) cmd, BrowserView::get_project(), with_exit); } else msg_warning(TR("Error"), TR("Bouml was called with wrong parameters, ignore them")); } ExitOnError = TRUE; a.exec(); } catch (...) { ; } return exit_value(); }
void SeqDiagramView::mousePressEvent(QMouseEvent * e) { if (!window()->frozen()) { if (e->button() == ::Qt::RightButton) DiagramView::mousePressEvent(e); else { QPoint diagramPoint(e->x(), e->y()); QPointF scenePoint = mapToScene(diagramPoint); UmlCode c = window()->buttonOn(); switch (c) { case UmlClass: { history_protected = FALSE; unselect_all(); window()->selectOn(); history_save(); BrowserNode * parent = ((BrowserNode *) window()->browser_diagram()->parent()); BrowserClass * b = BrowserClass::get_class(parent); if (b != 0) { SdClassInstCanvas * cli = new SdClassInstCanvas(b, the_canvas(), scenePoint.x(), 0); cli->show(); cli->moveBy(scenePoint.x() - cli->center().x(), 0); cli->upper(); window()->package_modified(); } } break; case UmlClassInstance: { history_protected = TRUE; unselect_all(); window()->selectOn(); history_save(); BrowserNode * parent = ((BrowserNode *) window()->browser_diagram()->parent()); BrowserClassInstance * b = BrowserClassInstance::get_classinstance(parent); if (b != 0) { SdClassInstCanvas * cli = new SdClassInstCanvas(b, the_canvas(), scenePoint.x(), 0); cli->show(); cli->moveBy(scenePoint.x() - cli->center().x(), 0); cli->upper(); window()->package_modified(); } } break; case UmlSyncSelfMsg: case UmlAsyncSelfMsg: case UmlSelfReturnMsg: { history_protected = TRUE; unselect_all(); window()->selectOn(); history_save(); QGraphicsItem * ci = the_canvas()->collision(scenePoint.toPoint()); if (ci != 0) { DiagramItem * i = QCanvasItemToDiagramItem(ci); if (i != 0) { QString err = i->may_start(c); if (!err.isEmpty()) msg_critical("Douml" , err); else { i->connexion(c, i, scenePoint.toPoint(), scenePoint.toPoint()); window()->package_modified(); } } } } break; case UmlContinuation: { history_protected = TRUE; unselect_all(); window()->selectOn(); history_save(); SdContinuationCanvas * cont = new SdContinuationCanvas(the_canvas(), scenePoint.x(), scenePoint.y(), 0); cont->show(); cont->upper(); window()->package_modified(); } break; default: DiagramView::mousePressEvent(e); return; } canvas()->update(); history_protected = FALSE; } } else DiagramView::mousePressEvent(e); }