File indexing completed on 2024-10-13 05:04:12

0001 // clang-format off
0002 /*
0003  * KDiff3 - Text Diff And Merge Tool
0004  *
0005  * SPDX-FileCopyrightText: 2002-2011 Joachim Eibl, joachim.eibl at gmx.de
0006  * SPDX-FileCopyrightText: 2018-2020 Michael Reeves reeves.87@gmail.com
0007  * SPDX-License-Identifier: GPL-2.0-or-later
0008  */
0009 // clang-format on
0010 
0011 #ifndef MERGERESULTWINDOW_H
0012 #define MERGERESULTWINDOW_H
0013 
0014 #include "diff.h"
0015 #include "FileNameLineEdit.h"
0016 #include "MergeEditLine.h"
0017 #include "options.h"
0018 #include "Overview.h"
0019 #include "selection.h"
0020 #include "LineRef.h"
0021 #include "TypeUtils.h"
0022 
0023 #include <boost/signals2.hpp>
0024 #include <memory>
0025 
0026 #include <QLineEdit>
0027 #include <QPointer>
0028 #include <QSharedPointer>
0029 #include <QStatusBar>
0030 #include <QTextLayout>
0031 #include <QTimer>
0032 #include <QWidget>
0033 
0034 class QPainter;
0035 class RLPainter;
0036 class QScrollBar;
0037 class KActionCollection;
0038 class KToggleAction;
0039 
0040 class KDiff3App;
0041 class UndoRecord;
0042 
0043 class MergeResultWindow: public QWidget
0044 {
0045     Q_OBJECT
0046   public:
0047     static QPointer<QScrollBar> mVScrollBar;
0048 
0049     MergeResultWindow(QWidget* pParent, QStatusBar* pStatusBar);
0050 
0051     void init(
0052         const std::shared_ptr<LineDataVector> &pLineDataA, LineRef sizeA,
0053         const std::shared_ptr<LineDataVector> &pLineDataB, LineRef sizeB,
0054         const std::shared_ptr<LineDataVector> &pLineDataC, LineRef sizeC,
0055         const Diff3LineList* pDiff3LineList,
0056         TotalDiffStatus* pTotalDiffStatus,
0057         bool bAutoSolve
0058     );
0059 
0060     void setupConnections(const KDiff3App* app);
0061 
0062     static void initActions(KActionCollection* ac);
0063 
0064     void connectActions() const;
0065     void reset();
0066 
0067     bool saveDocument(const QString& fileName, const char* encoding, e_LineEndStyle eLineEndStyle);
0068     [[nodiscard]] qint32 getNumberOfUnsolvedConflicts(qint32* pNrOfWhiteSpaceConflicts = nullptr) const;
0069     void choose(const e_SrcSelector selector);
0070     void chooseGlobal(e_SrcSelector selector, bool bConflictsOnly, bool bWhiteSpaceOnly);
0071 
0072     [[nodiscard]] qint32 getMaxTextWidth(); // width of longest text line
0073     [[nodiscard]] LineType getNofLines() const;
0074     [[nodiscard]] qint32 getVisibleTextAreaWidth() const; // text area width without the border
0075     [[nodiscard]] qint32 getNofVisibleLines() const;
0076     [[nodiscard]] QString getSelection() const;
0077     void resetSelection();
0078     void showNumberOfConflicts(bool showIfNone = false);
0079     [[nodiscard]] bool isDeltaAboveCurrent() const;
0080     [[nodiscard]] bool isDeltaBelowCurrent() const;
0081     [[nodiscard]] bool isConflictAboveCurrent() const;
0082     [[nodiscard]] bool isConflictBelowCurrent() const;
0083     [[nodiscard]] bool isUnsolvedConflictAtCurrent() const;
0084     [[nodiscard]] bool isUnsolvedConflictAboveCurrent() const;
0085     [[nodiscard]] bool isUnsolvedConflictBelowCurrent() const;
0086     bool findString(const QString& s, LineRef& d3vLine, QtSizeType& posInLine, bool bDirDown, bool bCaseSensitive);
0087     void setSelection(LineType firstLine, QtSizeType startPos, LineType lastLine, QtSizeType endPos);
0088     [[nodiscard]] e_OverviewMode getOverviewMode() const;
0089 
0090     void slotUpdateAvailabilities();
0091 
0092   private:
0093     static QPointer<QAction> chooseAEverywhere;
0094     static QPointer<QAction> chooseBEverywhere;
0095     static QPointer<QAction> chooseCEverywhere;
0096     static QPointer<QAction> chooseAForUnsolvedConflicts;
0097     static QPointer<QAction> chooseBForUnsolvedConflicts;
0098     static QPointer<QAction> chooseCForUnsolvedConflicts;
0099     static QPointer<QAction> chooseAForUnsolvedWhiteSpaceConflicts;
0100     static QPointer<QAction> chooseBForUnsolvedWhiteSpaceConflicts;
0101     static QPointer<QAction> chooseCForUnsolvedWhiteSpaceConflicts;
0102 
0103     struct HistoryMapEntry {
0104         MergeEditLineList mellA;
0105         MergeEditLineList mellB;
0106         MergeEditLineList mellC;
0107         MergeEditLineList& choice(bool bThreeInputs);
0108         bool staysInPlace(bool bThreeInputs, Diff3LineList::const_iterator& iHistoryEnd);
0109     };
0110     typedef std::map<QString, HistoryMapEntry> HistoryMap;
0111 
0112     enum class Direction
0113     {
0114         eUp,
0115         eDown
0116     };
0117 
0118     enum class EndPoint
0119     {
0120         eDelta,
0121         eConflict,
0122         eUnsolvedConflict,
0123         eLine,
0124         eEnd
0125     };
0126 
0127     enum class RangeMark
0128     {
0129         none = 0,
0130         begin = 1,
0131         end = 2,
0132         current = 4
0133     };
0134     Q_DECLARE_FLAGS(RangeFlags, RangeMark);
0135 
0136     std::shared_ptr<UndoRecord> mUndoRec;
0137 
0138     std::shared_ptr<LineDataVector> m_pldA = nullptr;
0139     std::shared_ptr<LineDataVector> m_pldB = nullptr;
0140     std::shared_ptr<LineDataVector> m_pldC = nullptr;
0141     LineRef m_sizeA = 0;
0142     LineRef m_sizeB = 0;
0143     LineRef m_sizeC = 0;
0144 
0145     const Diff3LineList* m_pDiff3LineList = nullptr;
0146     TotalDiffStatus* m_pTotalDiffStatus = nullptr;
0147 
0148     qint32 m_delayedDrawTimer = 0;
0149     e_OverviewMode mOverviewMode = e_OverviewMode::eOMNormal;
0150     QString m_persistentStatusMessage;
0151 
0152     MergeBlockList m_mergeBlockList;
0153     MergeBlockList::iterator m_currentMergeBlockIt;
0154 
0155     qint32 m_currentPos;
0156 
0157     QPixmap m_pixmap;
0158     LineRef m_firstLine = 0;
0159     qint32 m_horizScrollOffset = 0;
0160     LineType m_nofLines = 0;
0161     qint32 m_maxTextWidth = -1;
0162     bool m_bMyUpdate = false;
0163     bool m_bInsertMode = true;
0164     bool m_bModified = false;
0165     void setModified(bool bModified = true);
0166 
0167     qint32 m_scrollDeltaX = 0;
0168     qint32 m_scrollDeltaY = 0;
0169     SafeInt<qint32> m_cursorXPos = 0;
0170     SafeInt<qint32> m_cursorXPixelPos = 0;
0171     LineRef m_cursorYPos = 0;
0172     qint32 m_cursorOldXPixelPos = 0;
0173     bool m_bCursorOn = true; // blinking on and off each second
0174     QTimer m_cursorTimer;
0175     bool m_bCursorUpdate = false;
0176     QStatusBar* m_pStatusBar;
0177 
0178     Selection m_selection;
0179     /*
0180       This list exists solely to auto disconnect boost signals.
0181     */
0182     std::list<boost::signals2::scoped_connection> connections;
0183     // Overrides
0184     void paintEvent(QPaintEvent* e) override;
0185     void timerEvent(QTimerEvent*) override;
0186     bool event(QEvent*) override;
0187     void mousePressEvent(QMouseEvent* e) override;
0188     void mouseDoubleClickEvent(QMouseEvent* e) override;
0189     void mouseReleaseEvent(QMouseEvent*) override;
0190     void mouseMoveEvent(QMouseEvent*) override;
0191     void resizeEvent(QResizeEvent* e) override;
0192     void keyPressEvent(QKeyEvent* e) override;
0193     void wheelEvent(QWheelEvent* pWheelEvent) override;
0194     void focusInEvent(QFocusEvent* e) override;
0195     //Costum functions
0196     void merge(bool bAutoSolve, e_SrcSelector defaultSelector, bool bConflictsOnly = false, bool bWhiteSpaceOnly = false);
0197     QString getString(qint32 lineIdx);
0198     void showUnsolvedConflictsStatusMessage();
0199 
0200     void collectHistoryInformation(e_SrcSelector src, const HistoryRange& historyRange, HistoryMap& historyMap, std::list<HistoryMap::iterator>& hitList);
0201 
0202     bool isItAtEnd(bool bIncrement, const MergeBlockList::const_iterator i) const
0203     {
0204         if(bIncrement)
0205             return i != m_mergeBlockList.end();
0206         else
0207             return i != m_mergeBlockList.begin();
0208     }
0209 
0210     bool checkOverviewIgnore(const MergeBlockList::const_iterator i) const;
0211 
0212     void go(Direction eDir, EndPoint eEndPoint);
0213     bool calcIteratorFromLineNr(
0214         LineType line,
0215         MergeBlockList::iterator& mbIt,
0216         MergeEditLineList::iterator& melIt);
0217 
0218     qint32 getTextXOffset() const;
0219     QVector<QTextLayout::FormatRange> getTextLayoutForLine(LineRef line, const QString& s, QTextLayout& textLayout);
0220     void myUpdate(qint32 afterMilliSecs);
0221     void writeLine(
0222         RLPainter& p, LineRef line, const QString& str,
0223         enum e_SrcSelector srcSelect, e_MergeDetails mergeDetails, RangeFlags rangeMark, bool bUserModified, bool bLineRemoved, bool bWhiteSpaceConflict);
0224     void setFastSelector(MergeBlockList::iterator i);
0225     LineRef convertToLine(qint32 y);
0226 
0227     bool canCut() { return hasFocus() && !getSelection().isEmpty(); }
0228     bool canCopy() { return hasFocus() && !getSelection().isEmpty(); }
0229 
0230     bool deleteSelection2(QString& str, SafeInt<qint32>& x, qint32& y,
0231                           MergeBlockList::iterator& mbIt, MergeEditLineList::iterator& melIt);
0232     bool doRelevantChangesExist();
0233 
0234   public Q_SLOTS:
0235     void setOverviewMode(e_OverviewMode eOverviewMode);
0236     void setFirstLine(LineRef firstLine);
0237     void setHorizScrollOffset(const qint32 horizScrollOffset);
0238 
0239     void slotGoCurrent();
0240     void slotGoTop();
0241     void slotGoBottom();
0242     void slotGoPrevDelta();
0243     void slotGoNextDelta();
0244     void slotGoPrevUnsolvedConflict();
0245     void slotGoNextUnsolvedConflict();
0246     void slotGoPrevConflict();
0247     void slotGoNextConflict();
0248     void slotAutoSolve();
0249     void slotUnsolve();
0250     void slotMergeHistory();
0251     void slotRegExpAutoMerge();
0252     void slotSplitDiff(LineType firstD3lLineIdx, LineType lastD3lLineIdx);
0253     void slotJoinDiffs(LineType firstD3lLineIdx, LineType lastD3lLineIdx);
0254     void slotSetFastSelectorLine(LineType);
0255     void setPaintingAllowed(bool);
0256     void updateSourceMask();
0257     void slotStatusMessageChanged(const QString&);
0258 
0259     void slotChooseAEverywhere() { chooseGlobal(e_SrcSelector::A, false, false); }
0260     void slotChooseBEverywhere() { chooseGlobal(e_SrcSelector::B, false, false); }
0261     void slotChooseCEverywhere() { chooseGlobal(e_SrcSelector::C, false, false); }
0262 
0263     void slotChooseAForUnsolvedConflicts() { chooseGlobal(e_SrcSelector::A, true, false); }
0264     void slotChooseBForUnsolvedConflicts() { chooseGlobal(e_SrcSelector::B, true, false); }
0265     void slotChooseCForUnsolvedConflicts() { chooseGlobal(e_SrcSelector::C, true, false); }
0266 
0267     void slotChooseAForUnsolvedWhiteSpaceConflicts() { chooseGlobal(e_SrcSelector::A, true, true); }
0268     void slotChooseBForUnsolvedWhiteSpaceConflicts() { chooseGlobal(e_SrcSelector::B, true, true); }
0269     void slotChooseCForUnsolvedWhiteSpaceConflicts() { chooseGlobal(e_SrcSelector::C, true, true); }
0270 
0271     void slotRefresh();
0272 
0273     void slotResize();
0274 
0275     void slotCut();
0276     void slotCopy();
0277     void slotSelectAll();
0278 
0279     void scrollVertically(qint32 deltaY);
0280 
0281     void deleteSelection();
0282     void pasteClipboard(bool bFromSelection);
0283   private Q_SLOTS:
0284     void slotCursorUpdate();
0285 
0286   Q_SIGNALS:
0287     void statusBarMessage(const QString& message);
0288     void scrollMergeResultWindow(qint32 deltaX, qint32 deltaY);
0289     void modifiedChanged(bool bModified);
0290     void setFastSelectorRange(LineRef line1, LineType nofLines);
0291     void sourceMask(qint32 srcMask, qint32 enabledMask);
0292     void resizeSignal();
0293     void selectionEnd();
0294     void newSelection();
0295     void updateAvailabilities();
0296     void showPopupMenu(const QPoint& point);
0297     void noRelevantChangesDetected();
0298 };
0299 
0300 class QLineEdit;
0301 class QComboBox;
0302 class QLabel;
0303 
0304 class WindowTitleWidget: public QWidget
0305 {
0306     Q_OBJECT
0307   private:
0308     struct {
0309         QByteArray name;
0310         bool hasBOM = false;
0311     } EcodingItemData;
0312 
0313     QLabel*      m_pLabel;
0314     FileNameLineEdit*   m_pFileNameLineEdit;
0315     //QPushButton* m_pBrowseButton;
0316     QLabel*      m_pModifiedLabel;
0317     QLabel*      m_pLineEndStyleLabel;
0318     QComboBox*   m_pLineEndStyleSelector;
0319     QLabel*      m_pEncodingLabel;
0320     QComboBox* m_pEncodingSelector;
0321 
0322   public:
0323     WindowTitleWidget();
0324     const char* getEncoding();
0325     void setFileName(const QString& fileName);
0326     QString getFileName();
0327     void setEncodings(const char* pCodecForA, const char* pCodecForB, const char* pCodecForC);
0328     void setEncoding(const char* encoding);
0329     void setLineEndStyles(e_LineEndStyle eLineEndStyleA, e_LineEndStyle eLineEndStyleB, e_LineEndStyle eLineEndStyleC);
0330     e_LineEndStyle getLineEndStyle();
0331 
0332     bool eventFilter(QObject* o, QEvent* e) override;
0333   public Q_SLOTS:
0334     void slotSetModified(bool bModified);
0335     //private Q_SLOTS:
0336     //   void slotBrowseButtonClicked();
0337 };
0338 
0339 #endif