/* Copyright 2006-2020 The QElectroTech Team This file is part of QElectroTech. QElectroTech 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. QElectroTech 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 QElectroTech. If not, see . */ #ifndef CONDUCTOR_H #define CONDUCTOR_H #include "conductorproperties.h" #include "propertiesinterface.h" #include #include "assignvariables.h" class ConductorProfile; class ConductorSegmentProfile; class Diagram; class Terminal; class ConductorSegment; class ConductorTextItem; class Element; class QETDiagramEditor; class NumerotationContext; class QetGraphicsHandlerItem; typedef QPair ConductorBend; typedef QHash ConductorProfilesGroup; /** This class represents a conductor, i.e. a wire between two element terminals. */ class Conductor : public QGraphicsObject, public PropertiesInterface { Q_OBJECT Q_PROPERTY(QPointF pos READ pos WRITE setPos) Q_PROPERTY(int animPath READ fakePath WRITE updatePathAnimate) Q_PROPERTY(ConductorProperties properties READ properties WRITE setProperties) Q_PROPERTY(autonum::sequentialNumbers sequenceNum READ sequenceNum WRITE setSequenceNum) signals: void propertiesChange(); public: Conductor(Terminal *, Terminal *); ~Conductor() override; bool isValid() const; private: Conductor(const Conductor &); public: enum { Type = UserType + 1001 }; enum Highlight { None, Normal, Alert }; Terminal *terminal1; Terminal *terminal2; public: /** @brief type Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into a conductor. @return the QGraphicsItem type */ int type() const override { return Type; } Diagram *diagram() const; ConductorTextItem *textItem() const; void updatePath(const QRectF & = QRectF()); //This method do nothing, it's only made to be used with Q_PROPERTY //It's used to anim the path when is change void updatePathAnimate(const int = 1) {updatePath();} int fakePath() {return 1;} void paint( QPainter *, const QStyleOptionGraphicsItem *, QWidget *) override; QRectF boundingRect() const override; QPainterPath shape() const override; virtual QPainterPath nearShape() const; qreal length() const; ConductorSegment *middleSegment(); QPointF posForText(Qt::Orientations &flag); void refreshText(); void setPath(const QPainterPath &path); QPainterPath path() const; public: static bool valideXml (QDomElement &); bool fromXml (const QDomElement &) override; //QDomElement toXml (QDomDocument &, QHash &) const; QDomElement toXml (QDomDocument &doc) const override; private: bool pathFromXml(const QDomElement &); public: QVector handlerPoints() const; const QList segmentsList() const; void setPropertyToPotential( const ConductorProperties &property, bool only_text = false); void setProperties(const ConductorProperties &property); ConductorProperties properties() const; void setProfile(const ConductorProfile &, Qt::Corner); ConductorProfile profile(Qt::Corner) const; void setProfiles(const ConductorProfilesGroup &); ConductorProfilesGroup profiles() const; void calculateTextItemPosition(); virtual Highlight highlight() const; virtual void setHighlighted(Highlight); QSet relatedPotentialConductors( const bool all_diagram = true, QList *t_list=nullptr); QETDiagramEditor* diagramEditor() const; void editProperty (); autonum::sequentialNumbers sequenceNum () const {return m_autoNum_seq;} autonum::sequentialNumbers& rSequenceNum() {return m_autoNum_seq;} void setSequenceNum(const autonum::sequentialNumbers& sn); QList junctions() const; private: void setUpConnectionForFormula( QString old_formula, QString new_formula); autonum::sequentialNumbers m_autoNum_seq; public: void setFreezeLabel(bool freeze); public slots: void displayedTextChanged(); protected: void mouseDoubleClickEvent( QGraphicsSceneMouseEvent *event) override; void mousePressEvent(QGraphicsSceneMouseEvent *event) override; void mouseReleaseEvent( QGraphicsSceneMouseEvent *event) override; void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override; void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override; QVariant itemChange( GraphicsItemChange, const QVariant &) override; bool sceneEventFilter( QGraphicsItem *watched, QEvent *event) override; private: void adjusteHandlerPos(); void handlerMousePressEvent( QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event); void handlerMouseMoveEvent( QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event); void handlerMouseReleaseEvent( QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event); void addHandler(); void removeHandler(); QVector m_handler_vector; int m_vector_index = -1; bool m_mouse_over{false}; /// Functional properties ConductorProperties m_properties; /// Text input for non simple, non-singleline conductors ConductorTextItem *m_text_item{nullptr}; /// Segments composing the conductor ConductorSegment *segments{nullptr}; /// Attributs related to mouse interaction bool m_moving_segment{false}; int moved_point; qreal m_previous_z_value; ConductorSegment *m_moved_segment; QPointF before_mov_text_pos_; /// Whether the conductor was manually modified by users bool modified_path{false}; /// Whether the current profile should be saved as soon as possible bool has_to_save_profile{false}; /// conductor profile: "photography" of what the conductor is supposed to look /// like - there is one profile per kind of traject ConductorProfilesGroup conductor_profiles; /// Define whether and how the conductor should be highlighted Highlight must_highlight_{Conductor::None}; bool m_valid; bool m_freeze_label = false; /// QPen et QBrush objects used to draw conductors static QPen conductor_pen; static QBrush conductor_brush; static bool pen_and_brush_initialized; QPainterPath m_path; private: void segmentsToPath(); void saveProfile(bool = true); void generateConductorPath(const QPointF &, Qet::Orientation, const QPointF &, Qet::Orientation); void updateConductorPath(const QPointF &, Qet::Orientation, const QPointF &, Qet::Orientation); uint segmentsCount(QET::ConductorSegmentType = QET::Both) const; QList segmentsToPoints() const; QList bends() const; void pointsToSegments(const QList&); Qt::Corner currentPathType() const; void deleteSegments(); static int getCoeff(const qreal &, const qreal &); static int getSign(const qreal &); QHash shareOffsetBetweenSegments(const qreal &offset, const QList &, const qreal & = 0.01) const; static QPointF extendTerminal(const QPointF &, Qet::Orientation, qreal = 9.0); static Qt::Corner movementType(const QPointF &, const QPointF &); static QPointF movePointIntoPolygon(const QPointF &, const QPainterPath &); }; Conductor * longuestConductorInPotential (Conductor *conductor, bool all_diagram = false); QList relatedConductors (const Conductor *conductor); //return true if @a is between or at @b and @c. template bool isBetween (const T a, const T b, const T c) { return (b <= c)? (a >= b && a <= c) : (a <= b && a >= c); } #endif