/* Copyright 2006-2026 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 DIAGRAMEVENTADDPASTE_H #define DIAGRAMEVENTADDPASTE_H #include "diagrameventinterface.h" #include "../diagramcontent.h" #include "../autoNum/elementautonumschemecommand.h" #include #include #include class CablePart; class QStatusBar; /** @brief The DiagramEventAddPaste class Paste the clipboard as a placement you can still move. The pasted items are added straight away and follow the cursor until a left click drops them; Escape or a right click takes them away again. This is the same interaction as placing a new element, so a paste behaves like every other "put something on the folio" action. The items are the real ones from the start, not a preview: Diagram::fromXml creates them, this class moves them, and PasteDiagramCommand is pushed only once they are dropped. That keeps one copy of the paste logic rather than two, and means a cancelled paste leaves nothing on the undo stack. */ class DiagramEventAddPaste : public DiagramEventInterface { Q_OBJECT public: ///Items with a position of their own. Conductors are left out ///deliberately: they are drawn from their terminals, so they ///follow when the elements they attach to move. static const int MovableItems = DiagramContent::Elements | DiagramContent::TextFields | DiagramContent::Images | DiagramContent::Shapes | DiagramContent::Tables | DiagramContent::TerminalStrip; ///Where the group starts, relative to what was copied. enum PastePlacement { ///Move the group so its top left lands at \a start_pos ///(normally the cursor): Ctrl+V, the copy appears under ///the pointer and follows it. UnderCursor, ///Leave the group at its original XML position and warp ///the OS cursor to the group's origin so the baseline ///matches what is on screen: Ctrl+Shift+V, "paste at the ///origin point". AtOrigin }; DiagramEventAddPaste(Diagram *diagram, const QPointF &start_pos, PastePlacement placement = UnderCursor); ~DiagramEventAddPaste() override; void mouseMoveEvent (QGraphicsSceneMouseEvent *event) override; void mousePressEvent (QGraphicsSceneMouseEvent *event) override; void mouseReleaseEvent (QGraphicsSceneMouseEvent *event) override; void keyPressEvent (QKeyEvent *event) override; void init() override; ///@return true if the clipboard holds something this can paste. static bool clipboardHasDiagram(); private: void moveTo(const QPointF &scene_pos); void commit(); void cancel(); void showHint(); void removeItems(); DiagramContent m_content; ///The cable lines the same fragment carried, if any. They are ///not part of a DiagramContent -- the cable owns them -- so ///they travel beside it: moved with the rest of the paste, ///wired where it lands, and taken away whole if it never lands. QList m_cables; ///The cable lines among them, as plain items. Their setPos() is ///a translation rather than a move: CablePart works in scene ///coordinates and keeps itself at the origin, folding whatever ///it is handed into its own geometry and into the colour labels ///it carries (CablePart::itemChange). Everything else in ///m_relative_pos is given a place to stand; these are given a ///step to take. QSet m_cable_items; ///The step already handed to those cable lines. They take the ///difference to the new one, because for them a setPos() is an ///addition: handing them the baseline-relative position on every ///mouse move would add it again each time and let the line run ///away from the rest of the paste. QPointF m_cable_delta; /// The numberings the pasted copy carries QList m_copied_schemes; ///Each movable item's position relative to the group's top left, ///taken once so repeated moves cannot accumulate rounding drift. QHash m_relative_pos; ///Where this paste starts: UnderCursor moves the group to ///start_pos, AtOrigin leaves it at its original XML position. PastePlacement m_placement{UnderCursor}; ///Where the group's grid-snapped top left sits when the paste ///started, in scene coordinates -- under the cursor for ///UnderCursor, the copy's own origin for AtOrigin. QPointF m_group_origin; ///Cursor position (scene coords) the delta-based movement in ///moveTo() measures from. Equal to m_group_origin: either the ///group was put there (UnderCursor) or the cursor was warped ///there (AtOrigin). QPointF m_initial_cursor; ///Whether m_initial_cursor holds a usable baseline. A flag rather ///than testing m_initial_cursor.isNull(), which cannot tell "not ///set yet" from a baseline that is legitimately scene (0,0). bool m_baseline_captured{false}; QPointer m_status_bar; bool m_finished{false}; }; #endif // DIAGRAMEVENTADDPASTE_H