tools/designer/src/lib/shared/connectionedit.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 ** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.
00004 **
00005 ** This file is part of the Qt Designer of the Qt Toolkit.
00006 **
00007 ** This file may be used under the terms of the GNU General Public
00008 ** License version 2.0 as published by the Free Software Foundation
00009 ** and appearing in the file LICENSE.GPL included in the packaging of
00010 ** this file.  Please review the following information to ensure GNU
00011 ** General Public Licensing requirements will be met:
00012 ** http://www.trolltech.com/products/qt/opensource.html
00013 **
00014 ** If you are unsure which license is appropriate for your use, please
00015 ** review the following information:
00016 ** http://www.trolltech.com/products/qt/licensing.html or contact the
00017 ** sales department at sales@trolltech.com.
00018 **
00019 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00020 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00021 **
00022 ****************************************************************************/
00023 
00024 #include <QtGui/QPainter>
00025 #include <QtGui/QPaintEvent>
00026 #include <QtGui/QFontMetrics>
00027 #include <QtGui/QPixmap>
00028 #include <QtGui/QMatrix>
00029 #include <QtGui/QApplication>
00030 #include <QtGui/qevent.h>
00031 
00032 #include <QtCore/qdebug.h>
00033 
00034 #include <QtDesigner/abstractformwindow.h>
00035 
00036 #include "connectionedit_p.h"
00037 
00038 #define BG_ALPHA                32
00039 #define LINE_PROXIMITY_RADIUS   3
00040 #define LOOP_MARGIN             20
00041 #define VLABEL_MARGIN            1
00042 #define HLABEL_MARGIN            3
00043 #define GROUND_W                20
00044 #define GROUND_H                25
00045 
00046 namespace qdesigner_internal {
00047 
00048 /*******************************************************************************
00049 ** Tools
00050 */
00051 
00052 static QRect fixRect(const QRect &r)
00053 {
00054     return QRect(r.x(), r.y(), r.width() - 1, r.height() - 1);
00055 }
00056 
00057 static QRect expand(const QRect &r, int i)
00058 {
00059     return QRect(r.x() - i, r.y() - i, r.width() + 2*i, r.height() + 2*i);
00060 }
00061 
00062 static QRect endPointRect(const QPoint &pos)
00063 {
00064     QRect r(pos + QPoint(-LINE_PROXIMITY_RADIUS, -LINE_PROXIMITY_RADIUS),
00065             QSize(2*LINE_PROXIMITY_RADIUS, 2*LINE_PROXIMITY_RADIUS));
00066     return r;
00067 }
00068 
00069 static void paintGround(QPainter *p, QRect r)
00070 {
00071     QPoint mid = r.center();
00072     p->drawLine(mid.x(), r.top(), mid.x(), mid.y());
00073     p->drawLine(r.left(), mid.y(), r.right(), mid.y());
00074     int y = r.top() + 4*r.height()/6;
00075     int x = GROUND_W/6;
00076     p->drawLine(r.left() + x, y, r.right() - x, y);
00077     y = r.top() + 5*r.height()/6;
00078     x = 2*GROUND_W/6;
00079     p->drawLine(r.left() + x, y, r.right() - x, y);
00080     p->drawLine(mid.x(), r.bottom(), mid.x() + 1, r.bottom());
00081 }
00082 
00083 static void paintEndPoint(QPainter *p, const QPoint &pos)
00084 {
00085     QRect r(pos + QPoint(-LINE_PROXIMITY_RADIUS, -LINE_PROXIMITY_RADIUS),
00086             QSize(2*LINE_PROXIMITY_RADIUS, 2*LINE_PROXIMITY_RADIUS));
00087     p->fillRect(fixRect(r), p->pen().color());
00088 }
00089 
00090 static CETypes::LineDir classifyLine(const QPoint &p1, const QPoint &p2)
00091 {
00092     if (p1.x() == p2.x())
00093         return p1.y() < p2.y() ? CETypes::DownDir : CETypes::UpDir;
00094     Q_ASSERT(p1.y() == p2.y());
00095     return p1.x() < p2.x() ? CETypes::RightDir : CETypes::LeftDir;
00096 }
00097 
00098 static QPoint pointInsideRect(const QRect &r, QPoint p)
00099 {
00100     if (p.x() < r.left())
00101         p.setX(r.left());
00102     else if (p.x() > r.right())
00103         p.setX(r.right());
00104 
00105     if (p.y() < r.top())
00106         p.setY(r.top());
00107     else if (p.y() > r.bottom())
00108         p.setY(r.bottom());
00109 
00110     return p;
00111 }
00112 
00113 /*******************************************************************************
00114 ** Commands
00115 */
00116 
00117 AddConnectionCommand::AddConnectionCommand(ConnectionEdit *edit, Connection *con)
00118     : CECommand(edit), m_con(con)
00119 {
00120     setText(QApplication::translate("Command", "Add connection"));
00121 }
00122 
00123 void AddConnectionCommand::redo()
00124 {
00125     edit()->selectNone();
00126     emit edit()->aboutToAddConnection(edit()->m_con_list.size());
00127     edit()->m_con_list.append(m_con);
00128     m_con->inserted();
00129     edit()->setSelected(m_con, true);
00130     emit edit()->connectionAdded(m_con);
00131 }
00132 
00133 void AddConnectionCommand::undo()
00134 {
00135     int idx = edit()->indexOfConnection(m_con);
00136     emit edit()->aboutToRemoveConnection(m_con);
00137     edit()->setSelected(m_con, false);
00138     m_con->update();
00139     m_con->removed();
00140     edit()->m_con_list.removeAll(m_con);
00141     emit edit()->connectionRemoved(idx);
00142 }
00143 
00144 class AdjustConnectionCommand : public CECommand
00145 {
00146 public:
00147     AdjustConnectionCommand(ConnectionEdit *edit, Connection *con,
00148                             const QPoint &old_source_pos,
00149                             const QPoint &old_target_pos,
00150                             const QPoint &new_source_pos,
00151                             const QPoint &new_target_pos);
00152     virtual void redo();
00153     virtual void undo();
00154 private:
00155     Connection *m_con;
00156     QPoint m_old_source_pos, m_old_target_pos,
00157             m_new_source_pos, m_new_target_pos;
00158 };
00159 
00160 AdjustConnectionCommand::AdjustConnectionCommand(ConnectionEdit *edit, Connection *con,
00161                                                     const QPoint &old_source_pos,
00162                                                     const QPoint &old_target_pos,
00163                                                     const QPoint &new_source_pos,
00164                                                     const QPoint &new_target_pos)
00165     : CECommand(edit)
00166 {
00167     setText(QApplication::translate("Command", "Adjust connection"));
00168     m_con = con;
00169     m_old_source_pos = old_source_pos;
00170     m_old_target_pos = old_target_pos;
00171     m_new_source_pos = new_source_pos;
00172     m_new_target_pos = new_target_pos;
00173 }
00174 
00175 void AdjustConnectionCommand::undo()
00176 {
00177     m_con->setEndPoint(EndPoint::Source, m_con->widget(EndPoint::Source), m_old_source_pos);
00178     m_con->setEndPoint(EndPoint::Target, m_con->widget(EndPoint::Target), m_old_target_pos);
00179 }
00180 
00181 void AdjustConnectionCommand::redo()
00182 {
00183     m_con->setEndPoint(EndPoint::Source, m_con->widget(EndPoint::Source), m_new_source_pos);
00184     m_con->setEndPoint(EndPoint::Target, m_con->widget(EndPoint::Target), m_new_target_pos);
00185 }
00186 
00187 DeleteConnectionsCommand::DeleteConnectionsCommand(ConnectionEdit *edit,
00188                                                     const ConnectionList &con_list)
00189     : CECommand(edit), m_con_list(con_list)
00190 {
00191    setText(QApplication::translate("Command", "Delete connections"));
00192 }
00193 
00194 void DeleteConnectionsCommand::redo()
00195 {
00196     foreach (Connection *con, m_con_list) {
00197         int idx = edit()->indexOfConnection(con);
00198         emit edit()->aboutToRemoveConnection(con);
00199         Q_ASSERT(edit()->m_con_list.contains(con));
00200         edit()->setSelected(con, false);
00201         con->update();
00202         con->removed();
00203         edit()->m_con_list.removeAll(con);
00204         emit edit()->connectionRemoved(idx);
00205     }
00206 }
00207 
00208 void DeleteConnectionsCommand::undo()
00209 {
00210     foreach (Connection *con, m_con_list) {
00211         Q_ASSERT(!edit()->m_con_list.contains(con));
00212         emit edit()->aboutToAddConnection(edit()->m_con_list.size());
00213         edit()->m_con_list.append(con);
00214         edit()->setSelected(con, true);
00215         con->update();
00216         con->inserted();
00217         emit edit()->connectionAdded(con);
00218     }
00219 }
00220 
00221 class SetEndPointCommand : public CECommand
00222 {
00223 public:
00224     SetEndPointCommand(ConnectionEdit *edit, Connection *con, EndPoint::Type type, QObject *object);
00225     virtual void redo();
00226     virtual void undo();
00227 private:
00228     Connection *m_con;
00229     EndPoint::Type m_type;
00230     QObject *m_old_widget, *m_new_widget;
00231     QPoint m_old_pos, m_new_pos;
00232 };
00233 
00234 SetEndPointCommand::SetEndPointCommand(ConnectionEdit *edit, Connection *con,
00235                                         EndPoint::Type type, QObject *object)
00236     : CECommand(edit)
00237 {
00238     m_con = con;
00239     m_type = type;
00240     m_old_widget = con->object(type);
00241     m_old_pos = con->endPointPos(type);
00242     m_new_widget = object;
00243 
00244     if (QWidget *widget = qobject_cast<QWidget*>(object)) {
00245         m_new_pos = edit->widgetRect(widget).center();
00246     }
00247 
00248     if (m_type == EndPoint::Source)
00249         setText(QApplication::translate("Command", "Change source"));
00250     else
00251         setText(QApplication::translate("Command", "Change target"));
00252 }
00253 
00254 void SetEndPointCommand::redo()
00255 {
00256     m_con->setEndPoint(m_type, m_new_widget, m_new_pos);
00257     emit edit()->connectionChanged(m_con);
00258 }
00259 
00260 void SetEndPointCommand::undo()
00261 {
00262     m_con->setEndPoint(m_type, m_old_widget, m_old_pos);
00263     emit edit()->connectionChanged(m_con);
00264 }
00265 
00266 /*******************************************************************************
00267 ** Connection
00268 */
00269 
00270 Connection::Connection(ConnectionEdit *edit)
00271 {
00272     m_edit = edit;
00273     m_source = 0;
00274     m_target = 0;
00275     m_visible = true;
00276 
00277     m_source_pos = QPoint(-1, -1);
00278     m_target_pos = QPoint(-1, -1);
00279 }
00280 
00281 Connection::Connection(ConnectionEdit *edit, QObject *source, QObject *target)
00282 {
00283     m_edit = edit;
00284     m_source = source;
00285     m_target = target;
00286     m_visible = true;
00287 
00288     m_source_pos = QPoint(-1, -1);
00289     m_target_pos = QPoint(-1, -1);
00290 }
00291 
00292 void Connection::setVisible(bool b)
00293 {
00294     m_visible = b;
00295 }
00296 
00297 void Connection::updateVisibility()
00298 {
00299     QWidget *source = widget(EndPoint::Source);
00300     QWidget *target = widget(EndPoint::Target);
00301 
00302     if (source == 0 || target == 0) {
00303         setVisible(false);
00304         return;
00305     }
00306 
00307     QWidget *w = source;
00308     while (w && w->parentWidget()) {
00309         if (!w->isVisibleTo(w->parentWidget())) {
00310             setVisible(false);
00311             return;
00312         }
00313         w = w->parentWidget();
00314     }
00315 
00316     w = target;
00317     while (w && w->parentWidget()) {
00318         if (!w->isVisibleTo(w->parentWidget())) {
00319             setVisible(false);
00320             return;
00321         }
00322         w = w->parentWidget();
00323     }
00324 
00325     setVisible(true);
00326 }
00327 
00328 bool Connection::isVisible() const
00329 {
00330     return m_visible;
00331 }
00332 
00333 bool Connection::ground() const
00334 {
00335     return m_target != 0 && m_target == m_edit->m_bg_widget;
00336 }
00337 
00338 QPoint Connection::endPointPos(EndPoint::Type type) const
00339 {
00340     if (type == EndPoint::Source)
00341         return m_source_pos;
00342     else
00343         return m_target_pos;
00344 }
00345 
00346 static QPoint lineEntryPos(const QPoint &p1, const QPoint &p2, const QRect &rect)
00347 {
00348     QPoint result;
00349 
00350     CETypes::LineDir dir = classifyLine(p1, p2);
00351     switch (dir) {
00352         case CETypes::UpDir:
00353             result = QPoint(p1.x(), rect.bottom());
00354             break;
00355         case CETypes::DownDir:
00356             result = QPoint(p1.x(), rect.top());
00357             break;
00358         case CETypes::LeftDir:
00359             result = QPoint(rect.right(), p1.y());
00360             break;
00361         case CETypes::RightDir:
00362             result = QPoint(rect.left(), p1.y());
00363             break;
00364     }
00365 
00366     return result;
00367 }
00368 
00369 static QPolygonF arrowHead(const QPoint &p1, const QPoint &p2)
00370 {
00371     QPolygonF result;
00372 
00373     CETypes::LineDir dir = classifyLine(p1, p2);
00374     switch (dir) {
00375         case CETypes::UpDir:
00376             result.append(p2 + QPoint(0, 1));
00377             result.append(p2 + QPoint(LINE_PROXIMITY_RADIUS, LINE_PROXIMITY_RADIUS*2 + 1));
00378             result.append(p2 + QPoint(-LINE_PROXIMITY_RADIUS, LINE_PROXIMITY_RADIUS*2 + 1));
00379             break;
00380         case CETypes::DownDir:
00381             result.append(p2);
00382             result.append(p2 + QPoint(LINE_PROXIMITY_RADIUS, -LINE_PROXIMITY_RADIUS*2));
00383             result.append(p2 + QPoint(-LINE_PROXIMITY_RADIUS, -LINE_PROXIMITY_RADIUS*2));
00384             break;
00385         case CETypes::LeftDir:
00386             result.append(p2 + QPoint(1, 0));
00387             result.append(p2 + QPoint(2*LINE_PROXIMITY_RADIUS + 1, -LINE_PROXIMITY_RADIUS));
00388             result.append(p2 + QPoint(2*LINE_PROXIMITY_RADIUS + 1, LINE_PROXIMITY_RADIUS));
00389             break;
00390         case CETypes::RightDir:
00391             result.append(p2);
00392             result.append(p2 + QPoint(-2*LINE_PROXIMITY_RADIUS, -LINE_PROXIMITY_RADIUS));
00393             result.append(p2 + QPoint(-2*LINE_PROXIMITY_RADIUS, LINE_PROXIMITY_RADIUS));
00394             break;
00395     }
00396 
00397     return result;
00398 }
00399 
00400 static CETypes::LineDir closestEdge(const QPoint &p, const QRect &r)
00401 {
00402     CETypes::LineDir result = CETypes::UpDir;
00403     int min = p.y() - r.top();
00404 
00405     int d = p.x() - r.left();
00406     if (d < min) {
00407         min = d;
00408         result = CETypes::LeftDir;
00409     }
00410 
00411     d = r.bottom() - p.y();
00412     if (d < min) {
00413         min = d;
00414         result = CETypes::DownDir;
00415     }
00416 
00417     d = r.right() - p.x();
00418     if (d < min) {
00419         min = d;
00420         result = CETypes::RightDir;
00421     }
00422 
00423     return result;
00424 }
00425 
00426 static bool pointAboveLine(const QPoint &l1, const QPoint &l2, const QPoint &p)
00427 {
00428     if (l1.x() == l2.x())
00429         return p.x() >= l1.x();
00430     return p.y() <= l1.y() + (p.x() - l1.x())*(l2.y() - l1.y())/(l2.x() - l1.x());
00431 }
00432 
00433 void Connection::updateKneeList()
00434 {
00435     LineDir old_source_label_dir = labelDir(EndPoint::Source);
00436     LineDir old_target_label_dir = labelDir(EndPoint::Target);
00437 
00438     QPoint s = endPointPos(EndPoint::Source);
00439     QPoint t = endPointPos(EndPoint::Target);
00440     QRect sr = m_source_rect;
00441     QRect tr = m_target_rect;
00442 
00443     m_knee_list.clear();
00444     m_arrow_head.clear();
00445 
00446     if (m_source == 0 || s == QPoint(-1, -1) || t == QPoint(-1, -1))
00447         return;
00448 
00449     QRect r = sr | tr;
00450 
00451     m_knee_list.append(s);
00452     if (m_target == 0) {
00453         m_knee_list.append(QPoint(t.x(), s.y()));
00454     } else if (m_target == m_edit->m_bg_widget) {
00455         m_knee_list.append(QPoint(s.x(), t.y()));
00456     } else if (tr.contains(sr) || sr.contains(tr)) {
00457 /*
00458         +------------------+
00459         | +----------+     |
00460         | |          |     |
00461         | |   o      |     |
00462         | +---|------+     |
00463         |     |     x      |
00464         +-----|-----|------+
00465               +-----+
00466 
00467         We find out which edge of the outer rectangle is closest to the target
00468         point, and make a loop which exits and re-enters through that edge.
00469 */
00470         LineDir dir = closestEdge(t, tr);
00471         switch (dir) {
00472             case UpDir:
00473                 m_knee_list.append(QPoint(s.x(), r.top() - LOOP_MARGIN));
00474                 m_knee_list.append(QPoint(t.x(), r.top() - LOOP_MARGIN));
00475                 break;
00476             case DownDir:
00477                 m_knee_list.append(QPoint(s.x(), r.bottom() + LOOP_MARGIN));
00478                 m_knee_list.append(QPoint(t.x(), r.bottom() + LOOP_MARGIN));
00479                 break;
00480             case LeftDir:
00481                 m_knee_list.append(QPoint(r.left() - LOOP_MARGIN, s.y()));
00482                 m_knee_list.append(QPoint(r.left() - LOOP_MARGIN, t.y()));
00483                 break;
00484             case RightDir:
00485                 m_knee_list.append(QPoint(r.right() + LOOP_MARGIN, s.y()));
00486                 m_knee_list.append(QPoint(r.right() + LOOP_MARGIN, t.y()));
00487                 break;
00488         }
00489     } else {
00490         if (r.height() < sr.height() + tr.height()) {
00491             if (s.y() >= tr.top() && s.y() <= tr.bottom() || t.y() >= sr.bottom() || t.y() <= sr.top()) {
00492 /*
00493                 +--------+
00494                 |        |   +--------+
00495                 |     o--+---+--x     |
00496                 |     o  |   |        |
00497                 +-----|--+   |        |
00498                       +------+--x     |
00499                              +--------+
00500 
00501                 When dragging one end point, move the other end point to the same y position,
00502                 if that does not cause it to exit it's rectangle.
00503 */
00504                 if (m_edit->state() == ConnectionEdit::Dragging) {
00505                     if (m_edit->m_drag_end_point.type == EndPoint::Source) {
00506                         QPoint p(t.x(), s.y());
00507                         m_knee_list.append(p);
00508                         if (tr.contains(p))
00509                             t = m_target_pos = p;
00510                     } else {
00511                         QPoint p(s.x(), t.y());
00512                         m_knee_list.append(p);
00513                         if (sr.contains(p))
00514                             s = m_source_pos = p;
00515                     }
00516                 } else {
00517                     m_knee_list.append(QPoint(s.x(), t.y()));
00518                 }
00519             } else {
00520 /*
00521                 +--------+
00522                 |   o----+-------+
00523                 |        |   +---|----+
00524                 +--------+   |   |    |
00525                              |   x    |
00526                              +--------+
00527 */
00528                 m_knee_list.append(QPoint(t.x(), s.y()));
00529             }
00530         } else if (r.width() < sr.width() + tr.width()) {
00531             if (s.x() >= tr.left() && s.x() <= tr.right() || t.x() >= sr.right() || t.x() <= sr.left()) {
00532 /*
00533                 +--------+
00534                 |        |
00535                 |    o  o+--+
00536                 +----|---+  |
00537                    +-|------|-+
00538                    | x      x |
00539                    |          |
00540                    +----------+
00541 
00542                 When dragging one end point, move the other end point to the same x position,
00543                 if that does not cause it to exit it's rectangle.
00544 */
00545                 if (m_edit->state() == ConnectionEdit::Dragging) {
00546                     if (m_edit->m_drag_end_point.type == EndPoint::Source) {
00547                         QPoint p(s.x(), t.y());
00548                         m_knee_list.append(p);
00549                         if (tr.contains(p))
00550                             t = m_target_pos = p;
00551                     } else {
00552                         QPoint p(t.x(), s.y());
00553                         m_knee_list.append(p);
00554                         if (sr.contains(p))
00555                             s = m_source_pos = p;
00556                     }
00557                 } else {
00558                     m_knee_list.append(QPoint(t.x(), s.y()));
00559                 }
00560             } else {
00561 /*
00562                 +--------+
00563                 |        |
00564                 |  o     |
00565                 +--|-----+
00566                    |   +--------+
00567                    +---+-x      |
00568                        |        |
00569                        +--------+
00570 
00571 */
00572                 m_knee_list.append(QPoint(s.x(), t.y()));
00573             }
00574         } else {
00575 /*
00576             +--------+
00577             |        |
00578             |  o   o-+--------+
00579             +--|-----+        |
00580                |        +-----|--+
00581                |        |     x  |
00582                +--------+-x      |
00583                         +--------+
00584 
00585             The line enters the target rectangle through the closest edge.
00586 */
00587             if (sr.topLeft() == r.topLeft()) {
00588                 if (pointAboveLine(tr.topLeft(), tr.bottomRight(), t))
00589                     m_knee_list.append(QPoint(t.x(), s.y()));
00590                 else
00591                     m_knee_list.append(QPoint(s.x(), t.y()));
00592             } else if (sr.topRight() == r.topRight()) {
00593                 if (pointAboveLine(tr.bottomLeft(), tr.topRight(), t))
00594                     m_knee_list.append(QPoint(t.x(), s.y()));
00595                 else
00596                     m_knee_list.append(QPoint(s.x(), t.y()));
00597             } else if (sr.bottomRight() == r.bottomRight()) {
00598                 if (pointAboveLine(tr.topLeft(), tr.bottomRight(), t))
00599                     m_knee_list.append(QPoint(s.x(), t.y()));
00600                 else
00601                     m_knee_list.append(QPoint(t.x(), s.y()));
00602             } else {
00603                 if (pointAboveLine(tr.bottomLeft(), tr.topRight(), t))
00604                     m_knee_list.append(QPoint(s.x(), t.y()));
00605                 else
00606                     m_knee_list.append(QPoint(t.x(), s.y()));
00607             }
00608         }
00609     }
00610     m_knee_list.append(t);
00611 
00612     if (m_knee_list.size() == 2)
00613         m_knee_list.clear();
00614 
00615     trimLine();
00616 
00617     LineDir new_source_label_dir = labelDir(EndPoint::Source);
00618     LineDir new_target_label_dir = labelDir(EndPoint::Target);
00619     if (new_source_label_dir != old_source_label_dir)
00620         updatePixmap(EndPoint::Source);
00621     if (new_target_label_dir != old_target_label_dir)
00622         updatePixmap(EndPoint::Target);
00623 }
00624 
00625 void Connection::trimLine()
00626 {
00627     if (m_source == 0 || m_source_pos == QPoint(-1, -1) || m_target_pos == QPoint(-1, -1))
00628         return;
00629     int cnt = m_knee_list.size();
00630     if (cnt < 2)
00631         return;
00632 
00633     QRect sr = m_source_rect;
00634     QRect tr = m_target_rect;
00635 
00636     if (sr.contains(m_knee_list.at(1)))
00637         m_knee_list.removeFirst();
00638 
00639     cnt = m_knee_list.size();
00640     if (cnt < 2)
00641         return;
00642 
00643     if (!tr.contains(sr) && tr.contains(m_knee_list.at(cnt - 2)))
00644         m_knee_list.removeLast();
00645 
00646     cnt = m_knee_list.size();
00647     if (cnt < 2)
00648         return;
00649 
00650     if (sr.contains(m_knee_list.at(0)) && !sr.contains(m_knee_list.at(1)))
00651         m_knee_list[0] = lineEntryPos(m_knee_list.at(1), m_knee_list.at(0), sr);
00652 
00653     if (tr.contains(m_knee_list.at(cnt - 1)) && !tr.contains(m_knee_list.at(cnt - 2))) {
00654         m_knee_list[cnt - 1]
00655             = lineEntryPos(m_knee_list.at(cnt - 2), m_knee_list.at(cnt - 1), tr);
00656         m_arrow_head = arrowHead(m_knee_list.at(cnt - 2), m_knee_list.at(cnt - 1));
00657     }
00658 }
00659 
00660 void Connection::setSource(QObject *source, const QPoint &pos)
00661 {
00662     if (source == m_source && m_source_pos == pos)
00663         return;
00664 
00665     update(false);
00666 
00667     m_source = source;
00668     if (QWidget *widget = qobject_cast<QWidget*>(source)) {
00669         m_source_pos = pos;
00670         m_source_rect = m_edit->widgetRect(widget);
00671         updateKneeList();
00672     }
00673 
00674     update(false);
00675 }
00676 
00677 void Connection::setTarget(QObject *target, const QPoint &pos)
00678 {
00679     if (target == m_target && m_target_pos == pos)
00680         return;
00681 
00682     update(false);
00683 
00684     m_target = target;
00685     if (QWidget *widget = qobject_cast<QWidget*>(target)) {
00686         m_target_pos = pos;
00687         m_target_rect = m_edit->widgetRect(widget);
00688         updateKneeList();
00689     }
00690 
00691     update(false);
00692 }
00693 
00694 static QRect lineRect(const QPoint &a, const QPoint &b)
00695 {
00696     QPoint c(qMin(a.x(), b.x()), qMin(a.y(), b.y()));
00697     QPoint d(qMax(a.x(), b.x()), qMax(a.y(), b.y()));
00698 
00699     QRect result(c, d);
00700     return expand(result, LINE_PROXIMITY_RADIUS);
00701 }
00702 
00703 QRect Connection::groundRect() const
00704 {
00705     if (!ground())
00706         return QRect();
00707     if (m_knee_list.isEmpty())
00708         return QRect();
00709 
00710     QPoint p = m_knee_list.last();
00711     return QRect(p.x() - GROUND_W/2, p.y(), GROUND_W, GROUND_H);
00712 }
00713 
00714 QRegion Connection::region() const
00715 {
00716     QRegion result;
00717 
00718     for (int i = 0; i < m_knee_list.size() - 1; ++i)
00719         result = result.unite(lineRect(m_knee_list.at(i), m_knee_list.at(i + 1)));
00720 
00721     if (!m_arrow_head.isEmpty()) {
00722         QRect r = m_arrow_head.boundingRect().toRect();
00723         r = expand(r, 1);
00724         result = result.unite(r);
00725     } else if (ground()) {
00726         result = result.unite(groundRect());
00727     }
00728 
00729     result = result.unite(labelRect(EndPoint::Source));
00730     result = result.unite(labelRect(EndPoint::Target));
00731 
00732     return result;
00733 }
00734 
00735 void Connection::update(bool update_widgets) const
00736 {
00737     m_edit->update(region());
00738     if (update_widgets) {
00739         if (m_source != 0)
00740             m_edit->update(m_source_rect);
00741         if (m_target != 0)
00742             m_edit->update(m_target_rect);
00743     }
00744 
00745     m_edit->update(endPointRect(EndPoint::Source));
00746     m_edit->update(endPointRect(EndPoint::Target));
00747 }
00748 
00749 void Connection::paint(QPainter *p) const
00750 {
00751     for (int i = 0; i < m_knee_list.size() - 1; ++i)
00752         p->drawLine(m_knee_list.at(i), m_knee_list.at(i + 1));
00753 
00754     if (!m_arrow_head.isEmpty()) {
00755         p->save();
00756         p->setBrush(p->pen().color());
00757         p->drawPolygon(m_arrow_head);
00758         p->restore();
00759     } else if (ground()) {
00760         paintGround(p, groundRect());
00761     }
00762 }
00763 
00764 bool Connection::contains(const QPoint &pos) const
00765 {
00766     return region().contains(pos);
00767 }
00768 
00769 QRect Connection::endPointRect(EndPoint::Type type) const
00770 {
00771     if (type == EndPoint::Source) {
00772         if (m_source_pos != QPoint(-1, -1))
00773             return qdesigner_internal::endPointRect(m_source_pos);
00774     } else {
00775         if (m_target_pos != QPoint(-1, -1))
00776             return qdesigner_internal::endPointRect(m_target_pos);
00777     }
00778     return QRect();
00779 }
00780 
00781 CETypes::LineDir Connection::labelDir(EndPoint::Type type) const
00782 {
00783     int cnt = m_knee_list.size();
00784     if (cnt < 2)
00785         return RightDir;
00786 
00787     LineDir dir;
00788     if (type == EndPoint::Source)
00789         dir = classifyLine(m_knee_list.at(0), m_knee_list.at(1));
00790     else
00791         dir = classifyLine(m_knee_list.at(cnt - 2), m_knee_list.at(cnt - 1));
00792 
00793     if (dir == LeftDir)
00794         dir = RightDir;
00795     if (dir == UpDir)
00796         dir = DownDir;
00797 
00798     return dir;
00799 }
00800 
00801 QRect Connection::labelRect(EndPoint::Type type) const
00802 {
00803     int cnt = m_knee_list.size();
00804     if (cnt < 2)
00805         return QRect();
00806     QString text = label(type);
00807     if (text.isEmpty())
00808         return QRect();
00809 
00810     QSize size = labelPixmap(type).size();
00811     QPoint p1, p2;
00812     if (type == EndPoint::Source) {
00813         p1 = m_knee_list.at(0);
00814         p2 = m_knee_list.at(1);
00815     } else {
00816         p1 = m_knee_list.at(cnt - 1);
00817         p2 = m_knee_list.at(cnt - 2);
00818     }
00819     LineDir dir = classifyLine(p1, p2);
00820 
00821     QRect result;
00822     switch (dir) {
00823         case UpDir:
00824             result = QRect(p1 + QPoint(-size.width()/2, 0), size);
00825             break;
00826         case DownDir:
00827             result = QRect(p1 + QPoint(-size.width()/2, -size.height()), size);
00828             break;
00829         case LeftDir:
00830             result = QRect(p1 + QPoint(0, -size.height()/2), size);
00831             break;
00832         case RightDir:
00833             result = QRect(p1 + QPoint(-size.width(), -size.height()/2), size);
00834             break;
00835     }
00836 
00837     return result;
00838 }
00839 
00840 void Connection::setLabel(EndPoint::Type type, const QString &text)
00841 {
00842     if (text == label(type))
00843         return;
00844 
00845     if (type == EndPoint::Source)
00846         m_source_label = text;
00847     else
00848         m_target_label = text;
00849 
00850     updatePixmap(type);
00851 }
00852 
00853 void Connection::updatePixmap(EndPoint::Type type)
00854 {
00855     QPixmap *pm = type == EndPoint::Source ? &m_source_label_pm : &m_target_label_pm;
00856     *pm = QPixmap();
00857 
00858     QString text = label(type);
00859     if (text.isEmpty())
00860         return;
00861 
00862     QFontMetrics fm = m_edit->fontMetrics();
00863     QSize size = fm.size(Qt::TextSingleLine, text) + QSize(HLABEL_MARGIN*2, VLABEL_MARGIN*2);
00864     *pm = QPixmap(size);
00865     pm->fill(m_edit->palette().color(QPalette::Normal, QPalette::Base));
00866 
00867     QPainter p(pm);
00868     p.setPen(m_edit->palette().color(QPalette::Normal, QPalette::Text));
00869     p.drawText(-fm.leftBearing(text.at(0)) + HLABEL_MARGIN, fm.ascent() + VLABEL_MARGIN, text);
00870     p.end();
00871 
00872     LineDir dir = labelDir(type);
00873 
00874     if (dir == DownDir)
00875         *pm = pm->transformed(QMatrix(0.0, -1.0, 1.0, 0.0, 0.0, 0.0));
00876 }
00877 
00878 void Connection::checkWidgets()
00879 {
00880     bool changed = false;
00881 
00882     if (QWidget *sourceWidget = qobject_cast<QWidget*>(m_source)) {
00883         QRect r = m_edit->widgetRect(sourceWidget);
00884         if (r != m_source_rect) {
00885             if (m_source_pos != QPoint(-1, -1) && !r.contains(m_source_pos)) {
00886                 QPoint offset = m_source_pos - m_source_rect.topLeft();
00887                 QPoint old_pos = m_source_pos;
00888                 m_source_pos = pointInsideRect(r, r.topLeft() + offset);
00889             }
00890             m_edit->update(m_source_rect);
00891             m_source_rect = r;
00892             changed = true;
00893         }
00894     }
00895 
00896     if (QWidget *targetWidget = qobject_cast<QWidget*>(m_target)) {
00897         QRect r = m_edit->widgetRect(targetWidget);
00898         if (r != m_target_rect) {
00899             if (m_target_pos != QPoint(-1, -1) && !r.contains(m_target_pos)) {
00900                 QPoint offset = m_target_pos - m_target_rect.topLeft();
00901                 QPoint old_pos = m_target_pos;
00902                 m_target_pos = pointInsideRect(r, r.topLeft() + offset);
00903             }
00904             m_edit->update(m_target_rect);
00905             m_target_rect = r;
00906             changed = true;
00907         }
00908     }
00909 
00910     if (changed) {
00911         update();
00912         updateKneeList();
00913         update();
00914     }
00915 }
00916 
00917 /*******************************************************************************
00918 ** ConnectionEdit
00919 */
00920 
00921 ConnectionEdit::ConnectionEdit(QWidget *parent, QDesignerFormWindowInterface *form)
00922     : QWidget(parent)
00923 {
00924     m_bg_widget = 0;
00925     m_widget_under_mouse = 0;
00926     m_tmp_con = 0;
00927     m_start_connection_on_drag = true;
00928     m_enable_update_background = false;
00929     m_undo_stack = form->commandHistory();
00930     m_active_color = Qt::red;
00931     m_inactive_color = Qt::blue;
00932     setAttribute(Qt::WA_MouseTracking, true);
00933     setFocusPolicy(Qt::ClickFocus);
00934 
00935     connect(form, SIGNAL(widgetRemoved(QWidget*)), this, SLOT(widgetRemoved(QWidget*)));
00936 }
00937 
00938 
00939 void ConnectionEdit::clear()
00940 {
00941     m_con_list.clear();
00942     m_sel_con_set.clear();
00943     m_bg_widget = 0;
00944     m_widget_under_mouse = 0;
00945     m_tmp_con = 0;
00946 }
00947 
00948 void ConnectionEdit::setBackground(QWidget *background)
00949 {
00950     if (background == m_bg_widget) {
00951         // nothing to do
00952         return;
00953     }
00954 
00955     m_bg_widget = background;
00956     updateBackground();
00957 }
00958 
00959 void ConnectionEdit::enableUpdateBackground(bool enable)
00960 {
00961     m_enable_update_background = enable;
00962     if (enable)
00963         updateBackground();
00964 }
00965 
00966 void ConnectionEdit::updateBackground()
00967 {
00968     if (m_bg_widget == 0)
00969         return;
00970 
00971     if (!m_enable_update_background)
00972         return;
00973 
00974     foreach(Connection *c, m_con_list)
00975         c->updateVisibility();
00976 
00977     updateLines();
00978     update();
00979 }
00980 
00981 QWidget *ConnectionEdit::widgetAt(const QPoint &pos) const
00982 {
00983     if (m_bg_widget == 0)
00984         return 0;
00985     QWidget *widget = m_bg_widget->childAt(pos);
00986     if (widget == 0)
00987         widget = m_bg_widget;
00988 
00989     return widget;
00990 }
00991 
00992 
00993 QRect ConnectionEdit::widgetRect(QWidget *w) const
00994 {
00995     if (w == 0)
00996         return QRect();
00997     QRect r = w->geometry();
00998     QPoint pos = w->mapToGlobal(QPoint(0, 0));
00999     pos = mapFromGlobal(pos);
01000     r.moveTopLeft(pos);
01001     return r;
01002 }
01003 
01004 ConnectionEdit::State ConnectionEdit::state() const
01005 {
01006     if (m_tmp_con != 0)
01007         return Connecting;
01008     if (!m_drag_end_point.isNull())
01009         return Dragging;
01010     return Editing;
01011 }
01012 
01013 void ConnectionEdit::paintLabel(QPainter *p, EndPoint::Type type, Connection *con)
01014 {
01015     if (con->label(type).isEmpty())
01016         return;
01017 
01018     bool heavy = selected(con) || con == m_tmp_con;
01019     p->setPen(heavy ? m_active_color : m_inactive_color);
01020     p->setBrush(Qt::NoBrush);
01021     QRect r = con->labelRect(type);
01022     p->drawPixmap(r.topLeft(), con->labelPixmap(type));
01023     p->drawRect(fixRect(r));
01024 }
01025 
01026 void ConnectionEdit::paintConnection(QPainter *p, Connection *con,
01027                                         WidgetSet *heavy_highlight_set,
01028                                         WidgetSet *light_highlight_set) const
01029 {
01030     QWidget *source = con->widget(EndPoint::Source);
01031     QWidget *target = con->widget(EndPoint::Target);
01032 
01033     bool heavy = selected(con) || con == m_tmp_con;
01034     WidgetSet *set = heavy ? heavy_highlight_set : light_highlight_set;
01035     p->setPen(heavy ? m_active_color : m_inactive_color);
01036     con->paint(p);
01037 
01038     if (source != 0)
01039         set->insert(source, source);
01040 
01041     if (target != 0 && target != m_bg_widget)
01042         set->insert(target, target);
01043 }
01044 
01045 void ConnectionEdit::paintEvent(QPaintEvent *e)
01046 {
01047     QPainter p(this);
01048     p.setClipRegion(e->region());
01049 
01050     WidgetSet heavy_highlight_set, light_highlight_set;
01051 
01052     foreach (Connection *con, m_con_list) {
01053         if (!con->isVisible())
01054             continue;
01055 
01056         paintConnection(&p, con, &heavy_highlight_set, &light_highlight_set);
01057     }
01058 
01059     if (m_tmp_con != 0)
01060         paintConnection(&p, m_tmp_con, &heavy_highlight_set, &light_highlight_set);
01061 
01062     if (!m_widget_under_mouse.isNull() && m_widget_under_mouse != m_bg_widget)
01063         heavy_highlight_set.insert(m_widget_under_mouse, m_widget_under_mouse);
01064 
01065     QColor c = m_active_color;
01066     p.setPen(c);
01067     c.setAlpha(BG_ALPHA);
01068     p.setBrush(c);
01069 
01070     foreach (QWidget *w, heavy_highlight_set) {
01071         p.drawRect(fixRect(widgetRect(w)));
01072         light_highlight_set.remove(w);
01073     }
01074 
01075     c = m_inactive_color;
01076     p.setPen(c);
01077     c.setAlpha(BG_ALPHA);
01078     p.setBrush(c);
01079 
01080     foreach (QWidget *w, light_highlight_set)
01081         p.drawRect(fixRect(widgetRect(w)));
01082 
01083     p.setBrush(palette().color(QPalette::Base));
01084     p.setPen(palette().color(QPalette::Text));
01085     foreach (Connection *con, m_con_list) {
01086         if (!con->isVisible())
01087             continue;
01088 
01089         paintLabel(&p, EndPoint::Source, con);
01090         paintLabel(&p, EndPoint::Target, con);
01091     }
01092 
01093     p.setPen(m_active_color);
01094     p.setBrush(m_active_color);
01095 
01096     foreach (Connection *con, m_con_list) {
01097         if (!selected(con) || !con->isVisible())
01098             continue;
01099 
01100         paintEndPoint(&p, con->endPointPos(EndPoint::Source));
01101 
01102         if (con->widget(EndPoint::Target) != 0)
01103             paintEndPoint(&p, con->endPointPos(EndPoint::Target));
01104     }
01105 }
01106 
01107 void ConnectionEdit::abortConnection()
01108 {
01109     m_tmp_con->update();
01110     delete m_tmp_con;
01111     m_tmp_con = 0;
01112     setCursor(QCursor());
01113     if (m_widget_under_mouse == m_bg_widget)
01114         m_widget_under_mouse = 0;
01115 }
01116 
01117 void ConnectionEdit::mousePressEvent(QMouseEvent *e)
01118 {
01119     e->accept();
01120 
01121     Connection *con_under_mouse = connectionAt(e->pos());
01122     m_start_connection_on_drag = false;
01123 
01124     switch (state()) {
01125         case Connecting:
01126             if (e->button() == Qt::RightButton)
01127                 abortConnection();
01128             break;
01129         case Dragging:
01130             break;
01131         case Editing:
01132             if (!m_end_point_under_mouse.isNull()) {
01133                 if (!(e->modifiers() & Qt::ShiftModifier)) {
01134                     startDrag(m_end_point_under_mouse, e->pos());
01135                 }
01136             } else if (con_under_mouse != 0) {
01137                 if (!(e->modifiers() & Qt::ShiftModifier)) {
01138                     selectNone();
01139                     setSelected(con_under_mouse, true);
01140                 } else {
01141                     setSelected(con_under_mouse, !selected(con_under_mouse));
01142                 }
01143             } else {
01144                 if (!(e->modifiers() & Qt::ShiftModifier)) {
01145                     selectNone();
01146                     if (!m_widget_under_mouse.isNull())
01147                         m_start_connection_on_drag = true;
01148                 }
01149             }
01150             break;
01151     }
01152 }
01153 
01154 void ConnectionEdit::mouseDoubleClickEvent(QMouseEvent *e)
01155 {
01156     e->accept();
01157     switch (state()) {
01158         case Connecting:
01159             abortConnection();
01160             break;
01161         case Dragging:
01162             break;
01163         case Editing:
01164             if (!m_widget_under_mouse.isNull()) {
01165                 emit widgetActivated(m_widget_under_mouse);
01166             } else if (m_sel_con_set.size() == 1) {
01167                 Connection *con = m_sel_con_set.keys().first();
01168                 modifyConnection(con);
01169             }
01170             break;
01171     }
01172 
01173 }
01174 
01175 void ConnectionEdit::mouseReleaseEvent(QMouseEvent *e)
01176 {
01177     e->accept();
01178 
01179     switch (state()) {
01180         case Connecting:
01181             if (m_widget_under_mouse.isNull())
01182                 abortConnection();
01183             else
01184                 endConnection(m_widget_under_mouse, e->pos());
01185             setCursor(QCursor());
01186             break;
01187         case Editing:
01188             break;
01189         case Dragging:
01190             endDrag(e->pos());
01191             break;
01192     }
01193 }
01194 
01195 
01196 void ConnectionEdit::findObjectsUnderMouse(const QPoint &pos)
01197 {
01198     Connection *con_under_mouse = connectionAt(pos);
01199     QWidget *w = con_under_mouse != 0 ? 0 : widgetAt(pos);
01200 
01201     if (state() != Connecting && w == m_bg_widget)
01202         w = 0;
01203 
01204     if (w != m_widget_under_mouse) {
01205         if (!m_widget_under_mouse.isNull())
01206             update(widgetRect(m_widget_under_mouse));
01207         m_widget_under_mouse = w;
01208         if (!m_widget_under_mouse.isNull())
01209             update(widgetRect(m_widget_under_mouse));
01210     }
01211 
01212     EndPoint hs = endPointAt(pos);
01213     if (hs != m_end_point_under_mouse) {
01214         if (m_end_point_under_mouse.isNull())
01215             setCursor(Qt::PointingHandCursor);
01216         else
01217             setCursor(QCursor());
01218         m_end_point_under_mouse = hs;
01219     }
01220 }
01221 
01222 void ConnectionEdit::mouseMoveEvent(QMouseEvent *e)
01223 {
01224     findObjectsUnderMouse(e->pos());
01225 
01226     switch (state()) {
01227         case Connecting:
01228             continueConnection(m_widget_under_mouse, e->pos());
01229             break;
01230         case Editing:
01231             if ((e->buttons() & Qt::LeftButton)
01232                     && m_start_connection_on_drag
01233                     && !m_widget_under_mouse.isNull()) {
01234                 m_start_connection_on_drag = false;
01235                 startConnection(m_widget_under_mouse, e->pos());
01236                 setCursor(Qt::CrossCursor);
01237             }
01238             break;
01239         case Dragging:
01240             continueDrag(e->pos());
01241             break;
01242     }
01243 
01244     e->accept();
01245 }
01246 
01247 void ConnectionEdit::keyPressEvent(QKeyEvent *e)
01248 {
01249     switch (e->key()) {
01250         case Qt::Key_Delete:
01251             if (state() == Editing)
01252                 deleteSelected();
01253             break;
01254         case Qt::Key_Escape:
01255             if (state() == Connecting)
01256                 abortConnection();
01257             break;
01258     }
01259 
01260     e->accept();
01261 }
01262 
01263 void ConnectionEdit::startConnection(QWidget *source, const QPoint &pos)
01264 {
01265     Q_ASSERT(m_tmp_con == 0);
01266 
01267     m_tmp_con = new Connection(this);
01268     m_tmp_con->setEndPoint(EndPoint::Source, source, pos);
01269 }
01270 
01271 void ConnectionEdit::endConnection(QWidget *target, const QPoint &pos)
01272 {
01273     Q_ASSERT(m_tmp_con != 0);
01274 
01275     m_tmp_con->setEndPoint(EndPoint::Target, target, pos);
01276 
01277     QWidget *source = m_tmp_con->widget(EndPoint::Source);
01278     Q_ASSERT(source != 0);
01279     Q_ASSERT(target != 0);
01280     setEnabled(false);
01281     Connection *new_con = createConnection(source, target);
01282     setEnabled(true);
01283     if (new_con != 0) {
01284         new_con->setEndPoint(EndPoint::Source, source, m_tmp_con->endPointPos(EndPoint::Source));
01285         new_con->setEndPoint(EndPoint::Target, target, m_tmp_con->endPointPos(EndPoint::Target));
01286         m_undo_stack->push(new AddConnectionCommand(this, new_con));
01287     }
01288 
01289     delete m_tmp_con;
01290     m_tmp_con = 0;
01291 
01292     findObjectsUnderMouse(mapFromGlobal(QCursor::pos()));
01293 }
01294 
01295 void ConnectionEdit::continueConnection(QWidget *target, const QPoint &pos)
01296 {
01297     Q_ASSERT(m_tmp_con != 0);
01298 
01299     m_tmp_con->setEndPoint(EndPoint::Target, target, pos);
01300 }
01301 
01302 void ConnectionEdit::modifyConnection(Connection *)
01303 {
01304 }
01305 
01306 Connection *ConnectionEdit::createConnection(QWidget *source, QWidget *target)
01307 {
01308     Connection *con = new Connection(this, source, target);
01309     return con;
01310 }
01311 
01312 void ConnectionEdit::widgetRemoved(QWidget *widget)
01313 {
01314     QList<QWidget*> child_list = qFindChildren<QWidget*>(widget);
01315     child_list.prepend(widget);
01316 
01317     ConnectionSet remove_set;
01318     foreach (QWidget *w, child_list) {
01319         foreach (Connection *con, m_con_list) {
01320             if (con->widget(EndPoint::Source) == w || con->widget(EndPoint::Target) == w)
01321                 remove_set.insert(con, con);
01322         }
01323     }
01324 
01325     if (!remove_set.isEmpty())
01326         m_undo_stack->push(new DeleteConnectionsCommand(this, remove_set.keys()));
01327 
01328     updateBackground();
01329 }
01330 
01331 void ConnectionEdit::setSelected(Connection *con, bool sel)
01332 {
01333     if (!con || sel == m_sel_con_set.contains(con))
01334         return;
01335 
01336     if (sel) {
01337         m_sel_con_set.insert(con, con);
01338         emit connectionSelected(con);
01339     } else {
01340         m_sel_con_set.remove(con);
01341     }
01342 
01343     con->update();
01344 }
01345 
01346 bool ConnectionEdit::selected(const Connection *con) const
01347 {
01348     return m_sel_con_set.contains(const_cast<Connection*>(con));
01349 }
01350 
01351 void ConnectionEdit::selectNone()
01352 {
01353     foreach (Connection *con, m_sel_con_set)
01354         con->update();
01355 
01356     m_sel_con_set.clear();
01357 }
01358 
01359 Connection *ConnectionEdit::connectionAt(const QPoint &pos) const
01360 {
01361     foreach (Connection *con, m_con_list) {
01362         if (con->contains(pos))
01363             return con;
01364     }
01365     return 0;
01366 }
01367 
01368 CETypes::EndPoint ConnectionEdit::endPointAt(const QPoint &pos) const
01369 {
01370     foreach (Connection *con, m_con_list) {
01371         if (!selected(con))
01372             continue;
01373         QRect sr = con->endPointRect(EndPoint::Source);
01374         QRect tr = con->endPointRect(EndPoint::Target);
01375 
01376         if (sr.contains(pos))
01377             return EndPoint(con, EndPoint::Source);
01378         if (tr.contains(pos))
01379             return EndPoint(con, EndPoint::Target);
01380     }
01381     return EndPoint();
01382 }
01383 
01384 void ConnectionEdit::startDrag(const EndPoint &end_point, const QPoint &pos)
01385 {
01386     Q_ASSERT(m_drag_end_point.isNull());
01387     m_drag_end_point = end_point;
01388     m_old_source_pos = m_drag_end_point.con->endPointPos(EndPoint::Source);
01389     m_old_target_pos = m_drag_end_point.con->endPointPos(EndPoint::Target);
01390     adjustHotSopt(m_drag_end_point, pos);
01391 }
01392 
01393 void ConnectionEdit::continueDrag(const QPoint &pos)
01394 {
01395     Q_ASSERT(!m_drag_end_point.isNull());
01396     adjustHotSopt(m_drag_end_point, pos);
01397 }
01398 
01399 void ConnectionEdit::endDrag(const QPoint &pos)
01400 {
01401     Q_ASSERT(!m_drag_end_point.isNull());
01402     adjustHotSopt(m_drag_end_point, pos);
01403 
01404     Connection *con = m_drag_end_point.con;
01405     QPoint new_source_pos = con->endPointPos(EndPoint::Source);
01406     QPoint new_target_pos = con->endPointPos(EndPoint::Target);
01407     m_undo_stack->push(new AdjustConnectionCommand(this, con, m_old_source_pos, m_old_target_pos,
01408                                                     new_source_pos, new_target_pos));
01409 
01410     m_drag_end_point = EndPoint();
01411 }
01412 
01413 void ConnectionEdit::adjustHotSopt(const EndPoint &end_point, const QPoint &pos)
01414 {
01415     QWidget *w = end_point.con->widget(end_point.type);
01416     end_point.con->setEndPoint(end_point.type, w, pointInsideRect(widgetRect(w), pos));
01417 }
01418 
01419 void ConnectionEdit::deleteSelected()
01420 {
01421     if (m_sel_con_set.isEmpty())
01422         return;
01423     m_undo_stack->push(new DeleteConnectionsCommand(this, m_sel_con_set.keys()));
01424 }
01425 
01426 void ConnectionEdit::addConnection(Connection *con)
01427 {
01428     m_con_list.append(con);
01429 }
01430 
01431 void ConnectionEdit::updateLines()
01432 {
01433     foreach (Connection *con, m_con_list)
01434         con->checkWidgets();
01435 }
01436 
01437 void ConnectionEdit::resizeEvent(QResizeEvent *e)
01438 {
01439     updateBackground();
01440     QWidget::resizeEvent(e);
01441 }
01442 
01443 void ConnectionEdit::setSource(Connection *con, const QString &obj_name)
01444 {
01445     QObject *object = qFindChild<QObject*>(m_bg_widget, obj_name);
01446     if (object == 0 && m_bg_widget->objectName() == obj_name)
01447         object = m_bg_widget;
01448 
01449     if (object == con->object(EndPoint::Source))
01450         return;
01451 
01452     m_undo_stack->push(new SetEndPointCommand(this, con, EndPoint::Source, object));
01453 }
01454 
01455 void ConnectionEdit::setTarget(Connection *con, const QString &obj_name)
01456 {
01457     QObject *object = qFindChild<QObject*>(m_bg_widget, obj_name);
01458     if (object == 0 && m_bg_widget->objectName() == obj_name)
01459         object = m_bg_widget;
01460 
01461     if (object == con->object(EndPoint::Target))
01462         return;
01463 
01464     m_undo_stack->push(new SetEndPointCommand(this, con, EndPoint::Target, object));
01465 }
01466 
01467 } // namespace qdesigner_internal

Generated on Thu Mar 15 12:01:24 2007 for Qt 4.2 User's Guide by  doxygen 1.5.1