// ************************************************************************* // // Copyleft 2004-2007 Bruno PAGES . // // This file is part of the BOUML Uml Toolkit. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // e-mail : bouml@free.fr // home : http://bouml.free.fr // // ************************************************************************* #ifdef WIN32 #pragma warning (disable: 4150) #endif #include #include #include #include "SdDurationCanvas.h" #include "SdLifeLineCanvas.h" #include "SdClassInstCanvas.h" #include "SdSelfMsgCanvas.h" #include "SdMsgCanvas.h" #include "UmlCanvas.h" #include "BrowserSeqDiagram.h" #include "UmlGlobal.h" #include "Settings.h" #include "SettingsDialog.h" #include "myio.h" #include "MenuTitle.h" #include "ToolCom.h" #define DURATION_MIN_HEIGHT 25 #define DURATION_START_HEIGHT 40 #define DURATION_TOP 70 SdDurationCanvas::SdDurationCanvas(UmlCanvas * canvas, SdDurationSupport * sp, int v, bool isdest) : DiagramCanvas(0, canvas, 0, v, DURATION_WIDTH, (isdest) ? DURATION_MIN_HEIGHT : DURATION_START_HEIGHT, 0), support(sp), itscolor(UmlDefaultColor), coregion(FALSE) { browser_node = canvas->browser_diagram(); update_hpos(); setZ(sp->getZ() + 10); show(); support->add(this); connect(DrawingSettings::instance(), SIGNAL(changed()), this, SLOT(modified())); } // called by load SdDurationCanvas::SdDurationCanvas(UmlCanvas * canvas, SdDurationSupport * sp, int x, int y, int wi, int he, int id, bool coreg) : DiagramCanvas(0, canvas, x, y, wi, he, id), support(sp), itscolor(UmlDefaultColor), coregion(coreg) { browser_node = canvas->browser_diagram(); support->add(this); } SdDurationCanvas::~SdDurationCanvas() { } void SdDurationCanvas::delete_it() { while (!durations.isEmpty()) durations.first()->delete_it(); while (!msgs.isEmpty()) msgs.first()->delete_it(); // will update msgs disconnect(DrawingSettings::instance(), SIGNAL(changed()), this, SLOT(modified())); support->remove(this); DiagramCanvas::delete_it(); } void SdDurationCanvas::delete_available(bool &, bool & out_model) const { out_model |= TRUE; } void SdDurationCanvas::change_scale() { DiagramCanvas::change_scale(); hide(); update_hpos(); show(); } void SdDurationCanvas::update_hpos() { move(support->sub_x(width()), 100000); QListIterator itd(durations); for (; itd.current(); ++itd) itd.current()->update_hpos(); } void SdDurationCanvas::draw(QPainter & p) { const QRect r = rect(); UmlColor used_color = (itscolor != UmlDefaultColor) ? itscolor : browser_node->get_color(UmlActivityDuration); QColor co = color(used_color); int w = width() - 1; int x = r.left(); int y = r.top(); p.setBackgroundMode((used_color == UmlTransparent) ? ::Qt::TransparentMode : ::Qt::OpaqueMode); p.fillRect(r, co); if (coregion) { p.drawLine(x, y + w, x, y); #ifdef WIN32 p.moveTo(x, y); #endif p.lineTo(x + w, y); p.lineTo(x + w, y + w); int b = r.bottom(); p.drawLine(x, b - w, x, b); #ifdef WIN32 p.moveTo(x, b); #endif p.lineTo(x + w, b); p.lineTo(x + w, b - w); } else p.drawRect(r); FILE * fp = svg(); if (fp != 0) { if (coregion) { fprintf(fp, "\n" "\t\n" "\t\n" "\n", svg_color(used_color), x, y, w, r.height() - 1, x, y + w, -w, w, w, x, r.bottom() - w, w, w, -w); } else fprintf(fp, "\n" "\t\n" "\n", svg_color(used_color), x, y, w, r.height() - 1); } if (selected()) show_mark(p, r); } void SdDurationCanvas::moveBy(double dx, double dy) { if (dy > 80000) { // from update_hpos DiagramCanvas::moveBy(dx, 0); // update messages position (even selected, this case is managed by the messages) QListIterator it(msgs); for ( ; it.current(); ++it ) it.current()->update_hpos(); } else { double my = min_y(); if ((y() + dy) < my) dy = my - y(); // accept only vertical move DiagramCanvas::moveBy(0, dy); // move messages (even selected, this case is managed by the messages) QListIterator it(msgs); for ( ; it.current(); ++it ) it.current()->moveBy(100000, dy); } support->update_v_to_contain(this, FALSE); support->update_instance_dead(); } void SdDurationCanvas::prepare_for_move(bool on_resize) { DiagramCanvas::prepare_for_move(on_resize); if (! on_resize) { QListIterator itd(durations); for (; itd.current(); ++itd) { if (! itd.current()->selected()) { the_canvas()->select(itd.current()); itd.current()->prepare_for_move(on_resize); } } } } double SdDurationCanvas::min_y() const { return support->min_y(); } UmlCode SdDurationCanvas::type() const { return UmlActivityDuration; } DiagramItem::LineDirection SdDurationCanvas::allowed_direction(UmlCode c) { return (c == UmlAnchor) ? DiagramItem::All : DiagramItem::Vertical; } // called by the duration's messages to increase if // needed the duration to contain its messages void SdDurationCanvas::update_v_to_contain(const QRect re) { const QRect r = rect(); if (re.top() < r.top()) { int dy = re.top() - r.top(); QCanvasItem::moveBy(0, dy); DiagramCanvas::resize(r.width(), r.height() - dy); update_self(); } else if (re.bottom() > r.bottom()) { DiagramCanvas::resize(r.width(), re.bottom() - r.top() + 1); update_self(); } // done in all cases support->update_v_to_contain(this, TRUE); } void SdDurationCanvas::update_v_to_contain(SdDurationCanvas * d, bool force) { if (force || !selected()) { int min_b = (int) d->y() + d->height() + width()/2; int b = (int) y() + height(); if (d->y() < y()){ QCanvasItem::moveBy(0, d->y() - y()); DiagramCanvas::resize(width(), ((min_b > b) ? min_b : b) - (int) y()); update_self(); } else if (min_b > b) { DiagramCanvas::resize(width(), min_b - (int) y() + 1); update_self(); } // done in all cases support->update_v_to_contain(this, force); } } void SdDurationCanvas::update_self() { QListIterator it(msgs); QRect r = rect(); for ( ; it.current(); ++it ) it.current()->check_vpos(r); } const char * SdDurationCanvas::may_start(UmlCode &) const { return 0; } const char * SdDurationCanvas::may_connect(UmlCode & l, const DiagramItem * dest) const { if (l == UmlAnchor) return dest->may_start(l); else { switch (dest->type()) { case UmlActivityDuration: case UmlLifeLine: return 0; default: return "illegal"; } } } void SdDurationCanvas::connexion(UmlCode l, DiagramItem * dest, const QPoint & s, const QPoint & e) { switch (l) { case UmlSyncSelfMsg: if (dest->type() == UmlLifeLine) dest = this; else if (((BrowserSeqDiagram * ) browser_node)->is_overlapping_bars()) { SdDurationCanvas * d = (SdDurationCanvas *) dest; dest = new SdDurationCanvas(the_canvas(), d, s.y(), TRUE); d->update_v_to_contain((SdDurationCanvas *) dest, FALSE); } (new SdSelfMsgCanvas(the_canvas(), ((SdDurationCanvas *) dest), l, s.y(), 0))->upper(); break; case UmlAsyncSelfMsg: case UmlSelfReturnMsg: if (dest->type() == UmlLifeLine) dest = this; (new SdSelfMsgCanvas(the_canvas(), ((SdDurationCanvas *) dest), l, s.y(), 0))->upper(); break; case UmlAnchor: DiagramCanvas::connexion(l, dest, s, e); break; default: if (dest != this) { if (dest->type() == UmlLifeLine) // insert an activity duration canvas dest = new SdDurationCanvas(the_canvas(), ((SdLifeLineCanvas *) dest), s.y(), TRUE); else if (((BrowserSeqDiagram * ) browser_node)->is_overlapping_bars() && (l == UmlSyncMsg)) { SdDurationCanvas * d = (SdDurationCanvas *) dest; dest = new SdDurationCanvas(the_canvas(), d, s.y(), TRUE); d->update_v_to_contain((SdDurationCanvas *) dest, FALSE); } (new SdMsgCanvas(the_canvas(), this, ((SdDurationCanvas *) dest), l, s.y(), 0)) ->upper(); } } } void SdDurationCanvas::add(SdMsgBaseCanvas * m) { msgs.append(m); } void SdDurationCanvas::remove(SdMsgBaseCanvas * m) { msgs.removeRef(m); if (msgs.isEmpty() && durations.isEmpty()) // now useless, remove it delete_it(); } void SdDurationCanvas::add(SdDurationCanvas * d) { durations.append(d); } void SdDurationCanvas::remove(SdDurationCanvas * d) { durations.remove(d); if (msgs.isEmpty() && durations.isEmpty()) // now useless, remove it delete_it(); } void SdDurationCanvas::cut_internal(int py) { QListIterator itd(durations); for (; itd.current(); ++itd) itd.current()->cut_internal(py); QRect r = rect(); DiagramCanvas::resize(width(), py - r.top()); SdDurationCanvas * newone = 0; QList ms(msgs); QListIterator it(ms); for ( ; it.current(); ++it ) { if (it.current()->rect().center().y() > py) { // on the new duration if (newone == 0) { // width and height to 0 on creation to not have // a round error because of the zoom newone = new SdDurationCanvas(the_canvas(), support, r.x(), py, 0, 0, 0, coregion); newone->DiagramCanvas::resize(width(), r.bottom() - py); newone->itscolor = itscolor; newone->setZ(z()); newone->show(); } remove(it.current()); newone->add(it.current()); it.current()->change_duration(this, newone); } } QList durs(durations); QListIterator itdur(durs); for (itdur.toFirst() ; itdur.current(); ++itdur) { if (itdur.current()->rect().center().y() > py) { // on the new duration if (newone == 0) { // width and height to 0 on creation to not have // a round error because of the zoom newone = new SdDurationCanvas(the_canvas(), support, r.x(), py, 0, 0, 0, coregion); newone->DiagramCanvas::resize(width(), r.bottom() - py); newone->itscolor = itscolor; newone->setZ(z()); newone->show(); } remove(itdur.current()); newone->add(itdur.current()); itdur.current()->support = newone; } itdur.current()->update_v_to_contain(itdur.current(), TRUE); } } void SdDurationCanvas::cut(const QPoint & p) { cut_internal(p.y()); package_modified(); } void SdDurationCanvas::merge(QList & l) { l.removeRef(this); QRect r = rect(); int vmin = r.top(); int vmax = r.bottom(); SdDurationCanvas * d; for (d = l.first(); d != 0; d = l.next()) { QRect dr = d->rect(); if (dr.top() < vmin) vmin = dr.top(); if (dr.bottom() > vmax) vmax = dr.bottom(); collapse(d); } if (vmin < r.top()) QCanvasItem::moveBy(0, vmin - r.top()); DiagramCanvas::resize(r.width(), vmax - vmin + 1); update_self(); } void SdDurationCanvas::collapse(SdDurationCanvas * d) { QList & ms = d->msgs; while (! ms.isEmpty()) { SdMsgBaseCanvas * m = ms.take(0); msgs.append(m); m->change_duration(d, this); } QList & durs = d->durations; while (! durs.isEmpty()) { SdDurationCanvas * dur = durs.take(0); durations.append(dur); dur->support = this; } d->delete_it(); } void SdDurationCanvas::go_up(SdMsgBaseCanvas * m, bool isdest) { // create a new overlapping bar and move m in it int v = (m->type() != UmlSelfReturnMsg) ? (int) m->y() : (int) (m->y() - DURATION_MIN_HEIGHT * the_canvas()->zoom() + m->rect().height() / 2); SdDurationCanvas * d = new SdDurationCanvas(the_canvas(), this, v, isdest); update_v_to_contain(d, FALSE); d->msgs.append(m); m->change_duration(this, d); d->update_hpos(); // update sub duration and msg hpos d->update_self(); msgs.removeRef(m); m->upper(); } void SdDurationCanvas::go_down(SdMsgBaseCanvas * m) { // move m in parent bar SdDurationCanvas * d = (SdDurationCanvas *) support; d->msgs.append(m); m->change_duration(this, d); d->update_hpos(); // update sub duration and msg hpos d->update_self(); remove(m); } void SdDurationCanvas::toFlat() { while (! durations.isEmpty()) { SdDurationCanvas * d = durations.getFirst(); d->toFlat(); collapse(d); } if (! isOverlappingDuration()) update_hpos(); // update msg hpos } void SdDurationCanvas::toOverlapping() { // reorder messages, few messages => use bubble sort unsigned sz = msgs.count(); SdMsgBaseCanvas ** v = new SdMsgBaseCanvas *[sz]; unsigned index = 0; while (! msgs.isEmpty()) v[index++] = msgs.take(0); bool modified; do { modified = FALSE; for (index = 1; index < sz; index += 1) { if (v[index - 1]->y() > v[index]->y()) { modified = TRUE; SdMsgBaseCanvas * m = v[index - 1]; v[index - 1] = v[index]; v[index] = m; } } } while (modified); index = 0; toOverlapping(v, this, index, sz); delete [] v; postToOverlapping(); } void SdDurationCanvas::toOverlapping(SdMsgBaseCanvas ** v, SdDurationCanvas * orig, unsigned & index, unsigned sz) { bool first = TRUE; while (index != sz) { SdMsgBaseCanvas * m = v[index++]; switch (m->overlap_dir(orig)) { case -1: msgs.append(m); if (this != orig) { m->change_duration(orig, this); return; } // redondant return break; default: // 1 if (! first) { index -= 1; (new SdDurationCanvas(the_canvas(), this, (int) m->y(), TRUE)) ->toOverlapping(v, orig, index, sz); break; } // no break; case 0: msgs.append(m); if (this != orig) m->change_duration(orig, this); break; } first = FALSE; } } void SdDurationCanvas::postToOverlapping() { QListIterator itd(durations); for (; itd.current(); ++itd) itd.current()->postToOverlapping(); QListIterator it(msgs); for ( ; it.current(); ++it ) { it.current()->upper(); it.current()->update_hpos(); ((DiagramItem *) it.current())->update(); // not QCanvasItem::update } } void SdDurationCanvas::open() { // package_modified(); } void SdDurationCanvas::modified() { // force son reaffichage hide(); show(); canvas()->update(); package_modified(); } void SdDurationCanvas::menu(const QPoint & p) { QPopupMenu m(0); QCanvasItemList items = collisions(TRUE); QList l; QCanvasItemList::ConstIterator it; QCanvasItemList::ConstIterator end = items.end(); for (it = items.begin(); it != end; ++it) { if ((*it)->visible()) { DiagramItem * di = QCanvasItemToDiagramItem(*it); if ((di != 0) && (di->type() == UmlActivityDuration) && (((SdDurationCanvas *) di)->support == support)) l.append((SdDurationCanvas *) di); } } m.insertItem(new MenuTitle("Activity bar", m.font()), -1); m.insertSeparator(); m.insertItem("Upper", 0); m.insertItem("Lower", 1); m.insertSeparator(); m.insertItem((coregion) ? "Draw as activity bar" : "Draw as a coregion", 7); m.insertItem("Edit drawing settings", 2); m.insertSeparator(); m.insertItem("Select linked items", 3); m.insertSeparator(); m.insertItem("Remove from view", 4); m.insertSeparator(); m.insertItem("Cut here", 5); if (!l.isEmpty()) m.insertItem("Merge juxtaposed activity bars", 6); if (support->isaDuration()) m.insertItem("Collapse in parent bar", 8); switch (m.exec(QCursor::pos())) { case 0: upper(); modified(); return; case 1: lower(); modified(); return; case 2: edit_drawing_settings(); return; case 3: select_associated(); break; case 4: delete_it(); package_modified(); break; case 5: cut(p); package_modified(); break; case 6: merge(l); package_modified(); break; case 7: coregion = !coregion; modified(); return; case 8: { SdDurationCanvas * d = (SdDurationCanvas *) support; d->collapse(this); d->update_hpos(); // update sub duration and msg hpos d->update_self(); } package_modified(); break; default: return; } canvas()->update(); } void SdDurationCanvas::apply_shortcut(QString s) { if (s == "Upper") upper(); else if (s == "Lower") lower(); else if (s == "Edit drawing settings") { edit_drawing_settings(); return; } else return; modified(); } void SdDurationCanvas::edit_drawing_settings() { QArray co(1); co[0].set("duration color", &itscolor); SettingsDialog dialog(0, &co, FALSE, TRUE); dialog.raise(); if (dialog.exec() == QDialog::Accepted) modified(); } bool SdDurationCanvas::has_drawing_settings() const { return TRUE; } void SdDurationCanvas::edit_drawing_settings(QList & l) { QArray co(1); UmlColor itscolor; co[0].set("duration color", &itscolor); SettingsDialog dialog(0, &co, FALSE, TRUE, TRUE); dialog.raise(); if ((dialog.exec() == QDialog::Accepted) && (co[0].name != 0)) { QListIterator it(l); for (; it.current(); ++it) { ((SdDurationCanvas *) it.current())->itscolor = itscolor; ((SdDurationCanvas *) it.current())->modified(); // call package_modified() } } } aCorner SdDurationCanvas::on_resize_point(const QPoint & p) { return ::on_resize_point(p, rect()); } // note : don't consider the messages // size will be rectified if needed by the messages calling // update_v_to_contain() void SdDurationCanvas::resize(aCorner c, int, int dy) { if ((dy < 0) && ((c == UmlTopLeft) || (c == UmlTopRight))) { double my = min_y(); if ((y() + dy) < my) dy = (int) (my - y()); } double zoom = the_canvas()->zoom(); DiagramCanvas::resize(c, 0, dy, (int) (DURATION_WIDTH * zoom), (int) (DURATION_MIN_HEIGHT * zoom)); support->update_v_to_contain(this, FALSE); support->update_instance_dead(); } void SdDurationCanvas::select_associated() { if (! selected()) the_canvas()->select(this); QListIterator it(msgs); for ( ; it.current(); ++it ) if (! it.current()->selected()) it.current()->select_associated(); } bool SdDurationCanvas::copyable() const { if (! selected()) return FALSE; QListIterator it(msgs); for ( ; it.current(); ++it ) if (it.current()->copyable()) return TRUE; return FALSE; } void SdDurationCanvas::update_instance_dead() { // do nothing } int SdDurationCanvas::sub_x(int sub_w) const { QRect r = rect(); return r.right() - sub_w/2 + 1; } SdLifeLineCanvas * SdDurationCanvas::get_line() const { return support->get_line(); } bool SdDurationCanvas::isaDuration() const { return true; } bool SdDurationCanvas::isOverlappingDuration() const { return support->isaDuration(); } double SdDurationCanvas::getZ() const { return z(); } void SdDurationCanvas::save_sub(QTextStream & st) const { nl_indent(st); st << "overlappingdurationcanvas " << get_ident(); save_internal(st); } void SdDurationCanvas::save_internal(QTextStream & st) const { indent(+1); if (coregion) { nl_indent(st); st << "coregion"; } if (itscolor != UmlDefaultColor) { nl_indent(st); st << "color " << stringify(itscolor); } nl_indent(st); save_xyzwh(st, this, "xyzwh"); QListIterator itd(durations); for (; itd.current(); ++itd) itd.current()->save_sub(st); indent(-1); nl_indent(st); st << "end"; } void SdDurationCanvas::save(QTextStream & st, bool ref, QString & warning) const { if (ref) st << "durationcanvas_ref " << get_ident(); else if (!support->isaDuration()) { nl_indent(st); st << "durationcanvas " << get_ident() << ' '; ((DiagramCanvas *) ((SdLifeLineCanvas *) support)->get_obj())->save(st, TRUE, warning); save_internal(st); } } SdDurationCanvas * SdDurationCanvas::read(char * & st, UmlCanvas * canvas, bool ref) { return read(st, canvas, read_keyword(st, (ref) ? "durationcanvas_ref" : "durationcanvas")); } SdDurationCanvas * SdDurationCanvas::read_internal(char * & st, UmlCanvas * canvas, int id, SdDurationSupport * sp) { UmlColor color = UmlDefaultColor; bool coreg = FALSE; char * k = read_keyword(st); if (!strcmp(k, "coregion")) { coreg = TRUE; k = read_keyword(st); } read_color(st, "color", color, k); if (strcmp(k, "xyzwh")) wrong_keyword(k, "xyzwh"); int x = (int) read_double(st); int y = (int) read_double(st); double z = read_double(st); int w = (int) read_double(st); SdDurationCanvas * result = new SdDurationCanvas(canvas, sp, x, y, w, (int) read_double(st), id, coreg); result->itscolor = color; result->setZ(z); result->update_hpos(); // in case the current font is not the original one result->set_center100(); result->show(); if (read_file_format() >= 48) { k = read_keyword(st); while (!strcmp(k, "overlappingdurationcanvas")) { (void) read_internal(st, canvas, read_id(st), result); k = read_keyword(st); } if (strcmp(k, "end")) wrong_keyword(k, "end"); } return result; } SdDurationCanvas * SdDurationCanvas::read(char * & st, UmlCanvas * canvas, char * k) { if (!strcmp(k, "durationcanvas_ref")) return ((SdDurationCanvas *) dict_get(read_id(st), "durationcanvas", canvas)); else if (!strcmp(k, "durationcanvas")) { int id = read_id(st); SdObjCanvas * o; k = read_keyword(st); if ((o = SdClassInstCanvas::read(st, canvas, k)) == 0) wrong_keyword(st, k); return read_internal(st, canvas, id, o->get_life_line()); } else return 0; } void SdDurationCanvas::history_hide() { QCanvasItem::setVisible(FALSE); disconnect(DrawingSettings::instance(), SIGNAL(changed()), this, SLOT(modified())); } void SdDurationCanvas::history_save(QBuffer & b) const { DiagramCanvas::history_save(b); ::save(width_scale100, b); ::save(height_scale100, b); ::save(width(), b); ::save(height(), b); ::save_ptr(support, b); QListIterator it(msgs); ::save((int) msgs.count(), b); for (; it.current(); ++it) ::save(it.current(), b); QListIterator itd(durations); ::save((int) durations.count(), b); for (; itd.current(); ++itd) ::save(itd.current(), b); } void SdDurationCanvas::history_load(QBuffer & b) { DiagramCanvas::history_load(b); ::load(width_scale100, b); ::load(height_scale100, b); int w, h; ::load(w, b); ::load(h, b); QCanvasRectangle::setSize(w, h); support = (SdDurationSupport *) ::load_ptr(b); int n; ::load(n, b); msgs.clear(); while (n--) msgs.append((SdMsgBaseCanvas *) ::load_item(b)); ::load(n, b); durations.clear(); while (n--) durations.append((SdDurationCanvas *) ::load_item(b)); connect(DrawingSettings::instance(), SIGNAL(changed()), this, SLOT(modified())); } // for plug out unsigned SdDurationCanvas::count_msg() const { unsigned count = 0; QListIterator itm(msgs); double maxy = 0; bool isreturn = FALSE; for (; itm.current(); ++itm) { switch (itm.current()->type()) { case UmlSyncMsg: case UmlAsyncMsg: case UmlReturnMsg: if (itm.current()->get_dest() == this) break; // no break default: // msg start from duration count += 1; } if (itm.current()->y() > maxy) { maxy = itm.current()->y(); switch (itm.current()->type()) { case UmlReturnMsg: case UmlSelfReturnMsg: isreturn = TRUE; break; default: isreturn = FALSE; } } } if (!isreturn) count += 1; QListIterator itd(durations); for (; itd.current(); ++itd) count += itd.current()->count_msg(); return count; } void SdDurationCanvas::send(ToolCom * com, int id) const { QListIterator itm(msgs); double maxy = 0; bool isreturn = FALSE; for (; itm.current(); ++itm) { switch (itm.current()->type()) { case UmlSyncMsg: case UmlAsyncMsg: case UmlReturnMsg: if (itm.current()->get_dest() == this) break; // no break default: // msg start from duration itm.current()->send(com, id); } if (itm.current()->y() > maxy) { maxy = itm.current()->y(); switch (itm.current()->type()) { case UmlReturnMsg: case UmlSelfReturnMsg: isreturn = TRUE; break; default: isreturn = FALSE; } } } if (!isreturn) SdMsgBaseCanvas::send_implicit_return(com, id, (unsigned) x() + width(), (unsigned) y() + height()); QListIterator itd(durations); for (; itd.current(); ++itd) itd.current()->send(com, id); }