connectionedit.cpp

来自「奇趣公司比较新的qt/emd版本」· C++ 代码 · 共 1,500 行 · 第 1/3 页

CPP
1,500
字号
/******************************************************************************** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.**** This file is part of the Qt Designer of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file.  Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://trolltech.com/products/qt/licenses/licensing/opensource/**** If you are unsure which license is appropriate for your use, please** review the following information:** http://trolltech.com/products/qt/licenses/licensing/licensingoverview** or contact the sales department at sales@trolltech.com.**** In addition, as a special exception, Trolltech gives you certain** additional rights. These rights are described in the Trolltech GPL** Exception version 1.0, which can be found at** http://www.trolltech.com/products/qt/gplexception/ and in the file** GPL_EXCEPTION.txt in this package.**** In addition, as a special exception, Trolltech, as the sole copyright** holder for Qt Designer, grants users of the Qt/Eclipse Integration** plug-in the right for the Qt/Eclipse Integration to link to** functionality provided by Qt Designer and its related libraries.**** Trolltech reserves all rights not expressly granted herein.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include "connectionedit_p.h"#include <QtDesigner/abstractformwindow.h>#include <QtGui/QPainter>#include <QtGui/QPaintEvent>#include <QtGui/QFontMetrics>#include <QtGui/QPixmap>#include <QtGui/QMatrix>#include <QtGui/QApplication>#include <QtCore/QMultiMap>static const int BG_ALPHA =              32;static const int LINE_PROXIMITY_RADIUS =  3;static const int LOOP_MARGIN  =          20;static const int VLABEL_MARGIN =          1;static const int HLABEL_MARGIN =          3;static const int GROUND_W =              20;static const int GROUND_H =              25;/********************************************************************************* Tools*/static QRect fixRect(const QRect &r){    return QRect(r.x(), r.y(), r.width() - 1, r.height() - 1);}static QRect expand(const QRect &r, int i){    return QRect(r.x() - i, r.y() - i, r.width() + 2*i, r.height() + 2*i);}static QRect endPointRect(const QPoint &pos){    const QRect r(pos + QPoint(-LINE_PROXIMITY_RADIUS, -LINE_PROXIMITY_RADIUS),                  QSize(2*LINE_PROXIMITY_RADIUS, 2*LINE_PROXIMITY_RADIUS));    return r;}static void paintGround(QPainter *p, QRect r){    const QPoint mid = r.center();    p->drawLine(mid.x(), r.top(), mid.x(), mid.y());    p->drawLine(r.left(), mid.y(), r.right(), mid.y());    int y = r.top() + 4*r.height()/6;    int x = GROUND_W/6;    p->drawLine(r.left() + x, y, r.right() - x, y);    y = r.top() + 5*r.height()/6;    x = 2*GROUND_W/6;    p->drawLine(r.left() + x, y, r.right() - x, y);    p->drawLine(mid.x(), r.bottom(), mid.x() + 1, r.bottom());}static void paintEndPoint(QPainter *p, const QPoint &pos){    const QRect r(pos + QPoint(-LINE_PROXIMITY_RADIUS, -LINE_PROXIMITY_RADIUS),                  QSize(2*LINE_PROXIMITY_RADIUS, 2*LINE_PROXIMITY_RADIUS));    p->fillRect(fixRect(r), p->pen().color());}static qdesigner_internal::CETypes::LineDir classifyLine(const QPoint &p1, const QPoint &p2){    if (p1.x() == p2.x())        return p1.y() < p2.y() ? qdesigner_internal::CETypes::DownDir : qdesigner_internal::CETypes::UpDir;    Q_ASSERT(p1.y() == p2.y());    return p1.x() < p2.x() ? qdesigner_internal::CETypes::RightDir : qdesigner_internal::CETypes::LeftDir;}static QPoint pointInsideRect(const QRect &r, QPoint p){    if (p.x() < r.left())        p.setX(r.left());    else if (p.x() > r.right())        p.setX(r.right());    if (p.y() < r.top())        p.setY(r.top());    else if (p.y() > r.bottom())        p.setY(r.bottom());    return p;}namespace qdesigner_internal {/********************************************************************************* Commands*/AddConnectionCommand::AddConnectionCommand(ConnectionEdit *edit, Connection *con)    : CECommand(edit), m_con(con){    setText(QApplication::translate("Command", "Add connection"));}void AddConnectionCommand::redo(){    edit()->selectNone();    emit edit()->aboutToAddConnection(edit()->m_con_list.size());    edit()->m_con_list.append(m_con);    m_con->inserted();    edit()->setSelected(m_con, true);    emit edit()->connectionAdded(m_con);}void AddConnectionCommand::undo(){    const int idx = edit()->indexOfConnection(m_con);    emit edit()->aboutToRemoveConnection(m_con);    edit()->setSelected(m_con, false);    m_con->update();    m_con->removed();    edit()->m_con_list.removeAll(m_con);    emit edit()->connectionRemoved(idx);}class AdjustConnectionCommand : public CECommand{public:    AdjustConnectionCommand(ConnectionEdit *edit, Connection *con,                            const QPoint &old_source_pos,                            const QPoint &old_target_pos,                            const QPoint &new_source_pos,                            const QPoint &new_target_pos);    virtual void redo();    virtual void undo();private:    Connection *m_con;    const QPoint m_old_source_pos;    const QPoint m_old_target_pos;    const QPoint m_new_source_pos;    const QPoint m_new_target_pos;};AdjustConnectionCommand::AdjustConnectionCommand(ConnectionEdit *edit, Connection *con,                                                    const QPoint &old_source_pos,                                                    const QPoint &old_target_pos,                                                    const QPoint &new_source_pos,                                                    const QPoint &new_target_pos) :    CECommand(edit),    m_con(con),    m_old_source_pos(old_source_pos),    m_old_target_pos(old_target_pos),    m_new_source_pos(new_source_pos),    m_new_target_pos(new_target_pos){    setText(QApplication::translate("Command", "Adjust connection"));}void AdjustConnectionCommand::undo(){    m_con->setEndPoint(EndPoint::Source, m_con->widget(EndPoint::Source), m_old_source_pos);    m_con->setEndPoint(EndPoint::Target, m_con->widget(EndPoint::Target), m_old_target_pos);}void AdjustConnectionCommand::redo(){    m_con->setEndPoint(EndPoint::Source, m_con->widget(EndPoint::Source), m_new_source_pos);    m_con->setEndPoint(EndPoint::Target, m_con->widget(EndPoint::Target), m_new_target_pos);}DeleteConnectionsCommand::DeleteConnectionsCommand(ConnectionEdit *edit,                                                    const ConnectionList &con_list)    : CECommand(edit), m_con_list(con_list){   setText(QApplication::translate("Command", "Delete connections"));}void DeleteConnectionsCommand::redo(){    foreach (Connection *con, m_con_list) {        const int idx = edit()->indexOfConnection(con);        emit edit()->aboutToRemoveConnection(con);        Q_ASSERT(edit()->m_con_list.contains(con));        edit()->setSelected(con, false);        con->update();        con->removed();        edit()->m_con_list.removeAll(con);        emit edit()->connectionRemoved(idx);    }}void DeleteConnectionsCommand::undo(){    foreach (Connection *con, m_con_list) {        Q_ASSERT(!edit()->m_con_list.contains(con));        emit edit()->aboutToAddConnection(edit()->m_con_list.size());        edit()->m_con_list.append(con);        edit()->setSelected(con, true);        con->update();        con->inserted();        emit edit()->connectionAdded(con);    }}class SetEndPointCommand : public CECommand{public:    SetEndPointCommand(ConnectionEdit *edit, Connection *con, EndPoint::Type type, QObject *object);    virtual void redo();    virtual void undo();private:    Connection *m_con;    const EndPoint::Type m_type;    QObject *m_old_widget, *m_new_widget;    const QPoint m_old_pos;    QPoint m_new_pos;};SetEndPointCommand::SetEndPointCommand(ConnectionEdit *edit, Connection *con,                                        EndPoint::Type type, QObject *object) :    CECommand(edit),    m_con(con),    m_type(type),    m_old_widget(con->object(type)),    m_new_widget(object),    m_old_pos(con->endPointPos(type)){    if (QWidget *widget = qobject_cast<QWidget*>(object)) {        m_new_pos = edit->widgetRect(widget).center();    }    if (m_type == EndPoint::Source)        setText(QApplication::translate("Command", "Change source"));    else        setText(QApplication::translate("Command", "Change target"));}void SetEndPointCommand::redo(){    m_con->setEndPoint(m_type, m_new_widget, m_new_pos);    emit edit()->connectionChanged(m_con);}void SetEndPointCommand::undo(){    m_con->setEndPoint(m_type, m_old_widget, m_old_pos);    emit edit()->connectionChanged(m_con);}/********************************************************************************* Connection*/Connection::Connection(ConnectionEdit *edit) :    m_source_pos(QPoint(-1, -1)),    m_target_pos(QPoint(-1, -1)),    m_source(0),    m_target(0),    m_edit(edit),    m_visible(true){}Connection::Connection(ConnectionEdit *edit, QObject *source, QObject *target) :    m_source_pos(QPoint(-1, -1)),    m_target_pos(QPoint(-1, -1)),    m_source(source),    m_target(target),    m_edit(edit),    m_visible(true){}void Connection::setVisible(bool b){    m_visible = b;}void Connection::updateVisibility(){    QWidget *source = widget(EndPoint::Source);    QWidget *target = widget(EndPoint::Target);    if (source == 0 || target == 0) {        setVisible(false);        return;    }    QWidget *w = source;    while (w && w->parentWidget()) {        if (!w->isVisibleTo(w->parentWidget())) {            setVisible(false);            return;        }        w = w->parentWidget();    }    w = target;    while (w && w->parentWidget()) {        if (!w->isVisibleTo(w->parentWidget())) {            setVisible(false);            return;        }        w = w->parentWidget();    }    setVisible(true);}bool Connection::isVisible() const{    return m_visible;}bool Connection::ground() const{    return m_target != 0 && m_target == m_edit->m_bg_widget;}QPoint Connection::endPointPos(EndPoint::Type type) const{    if (type == EndPoint::Source)        return m_source_pos;    else        return m_target_pos;}static QPoint lineEntryPos(const QPoint &p1, const QPoint &p2, const QRect &rect){    QPoint result;    switch (classifyLine(p1, p2)) {        case CETypes::UpDir:            result = QPoint(p1.x(), rect.bottom());            break;        case CETypes::DownDir:            result = QPoint(p1.x(), rect.top());            break;        case CETypes::LeftDir:            result = QPoint(rect.right(), p1.y());            break;        case CETypes::RightDir:            result = QPoint(rect.left(), p1.y());            break;    }    return result;}static QPolygonF arrowHead(const QPoint &p1, const QPoint &p2){    QPolygonF result;    switch (classifyLine(p1, p2)) {        case CETypes::UpDir:            result.append(p2 + QPoint(0, 1));            result.append(p2 + QPoint(LINE_PROXIMITY_RADIUS, LINE_PROXIMITY_RADIUS*2 + 1));            result.append(p2 + QPoint(-LINE_PROXIMITY_RADIUS, LINE_PROXIMITY_RADIUS*2 + 1));            break;        case CETypes::DownDir:            result.append(p2);            result.append(p2 + QPoint(LINE_PROXIMITY_RADIUS, -LINE_PROXIMITY_RADIUS*2));            result.append(p2 + QPoint(-LINE_PROXIMITY_RADIUS, -LINE_PROXIMITY_RADIUS*2));            break;        case CETypes::LeftDir:            result.append(p2 + QPoint(1, 0));            result.append(p2 + QPoint(2*LINE_PROXIMITY_RADIUS + 1, -LINE_PROXIMITY_RADIUS));            result.append(p2 + QPoint(2*LINE_PROXIMITY_RADIUS + 1, LINE_PROXIMITY_RADIUS));            break;        case CETypes::RightDir:            result.append(p2);            result.append(p2 + QPoint(-2*LINE_PROXIMITY_RADIUS, -LINE_PROXIMITY_RADIUS));            result.append(p2 + QPoint(-2*LINE_PROXIMITY_RADIUS, LINE_PROXIMITY_RADIUS));            break;    }    return result;}static CETypes::LineDir closestEdge(const QPoint &p, const QRect &r){    CETypes::LineDir result = CETypes::UpDir;    int min = p.y() - r.top();    int d = p.x() - r.left();    if (d < min) {        min = d;        result = CETypes::LeftDir;    }    d = r.bottom() - p.y();    if (d < min) {        min = d;        result = CETypes::DownDir;    }    d = r.right() - p.x();    if (d < min) {        min = d;        result = CETypes::RightDir;    }    return result;}static bool pointAboveLine(const QPoint &l1, const QPoint &l2, const QPoint &p){    if (l1.x() == l2.x())        return p.x() >= l1.x();    return p.y() <= l1.y() + (p.x() - l1.x())*(l2.y() - l1.y())/(l2.x() - l1.x());}void Connection::updateKneeList(){    const LineDir old_source_label_dir = labelDir(EndPoint::Source);    const LineDir old_target_label_dir = labelDir(EndPoint::Target);    QPoint s = endPointPos(EndPoint::Source);    QPoint t = endPointPos(EndPoint::Target);    const QRect sr = m_source_rect;    const QRect tr = m_target_rect;    m_knee_list.clear();    m_arrow_head.clear();    if (m_source == 0 || s == QPoint(-1, -1) || t == QPoint(-1, -1))        return;    const QRect r = sr | tr;    m_knee_list.append(s);    if (m_target == 0) {        m_knee_list.append(QPoint(t.x(), s.y()));    } else if (m_target == m_edit->m_bg_widget) {        m_knee_list.append(QPoint(s.x(), t.y()));    } else if (tr.contains(sr) || sr.contains(tr)) {/*        +------------------+        | +----------+     |        | |          |     |        | |   o      |     |        | +---|------+     |        |     |     x      |        +-----|-----|------+              +-----+        We find out which edge of the outer rectangle is closest to the target        point, and make a loop which exits and re-enters through that edge.*/        const LineDir dir = closestEdge(t, tr);        switch (dir) {            case UpDir:                m_knee_list.append(QPoint(s.x(), r.top() - LOOP_MARGIN));                m_knee_list.append(QPoint(t.x(), r.top() - LOOP_MARGIN));                break;            case DownDir:                m_knee_list.append(QPoint(s.x(), r.bottom() + LOOP_MARGIN));                m_knee_list.append(QPoint(t.x(), r.bottom() + LOOP_MARGIN));                break;            case LeftDir:                m_knee_list.append(QPoint(r.left() - LOOP_MARGIN, s.y()));                m_knee_list.append(QPoint(r.left() - LOOP_MARGIN, t.y()));                break;            case RightDir:                m_knee_list.append(QPoint(r.right() + LOOP_MARGIN, s.y()));                m_knee_list.append(QPoint(r.right() + LOOP_MARGIN, t.y()));                break;        }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?