File indexing completed on 2024-05-19 13:31:44

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 KDIFF3_H
0012 #define KDIFF3_H
0013 
0014 #include "diff.h"
0015 #include "defmac.h"
0016 #include "combiners.h"
0017 #include "SourceData.h"
0018 #include "TypeUtils.h"
0019 
0020 #include <boost/signals2.hpp>
0021 
0022 #include <memory>
0023 
0024 // include files for Qt
0025 #include <QAction>
0026 #include <QApplication>
0027 #include <QEventLoop>
0028 #include <QPointer>
0029 #include <QScrollBar>
0030 #include <QSharedPointer>
0031 #include <QSplitter>
0032 
0033 // include files for KDE
0034 #include <KConfigGroup>
0035 #include <KMainWindow>
0036 #include <KSharedConfig>
0037 #include <KToggleAction>
0038 #include <QShortcut>
0039 
0040 // forward declaration of the KDiff3 classes
0041 class Options;
0042 class OptionDialog;
0043 
0044 class Overview;
0045 enum class e_OverviewMode;
0046 class FindDialog;
0047 //class ManualDiffHelpDialog;
0048 class DiffTextWindow;
0049 class DiffTextWindowFrame;
0050 class MergeResultWindow;
0051 class WindowTitleWidget;
0052 
0053 class QStatusBar;
0054 class QMenu;
0055 
0056 class KToolBar;
0057 class KActionCollection;
0058 
0059 class KDiff3Shell;
0060 class DirectoryMergeWindow;
0061 class DirectoryMergeInfo;
0062 
0063 class ReversibleScrollBar : public QScrollBar
0064 {
0065     Q_OBJECT
0066     bool* m_pbRightToLeftLanguage;
0067     qint32 m_realVal;
0068 
0069   public:
0070     ReversibleScrollBar(Qt::Orientation o, bool* pbRightToLeftLanguage)
0071         : QScrollBar(o)
0072     {
0073         m_pbRightToLeftLanguage = pbRightToLeftLanguage;
0074         m_realVal = 0;
0075         chk_connect_a(this, &ReversibleScrollBar::valueChanged, this, &ReversibleScrollBar::slotValueChanged);
0076     }
0077     void setAgain() { setValue(m_realVal); }
0078 
0079     void setValue(qint32 i)
0080     {
0081         if(m_pbRightToLeftLanguage != nullptr && *m_pbRightToLeftLanguage)
0082             QScrollBar::setValue(maximum() - (i - minimum()));
0083         else
0084             QScrollBar::setValue(i);
0085     }
0086 
0087     [[nodiscard]] qint32 value() const
0088     {
0089         return m_realVal;
0090     }
0091   public Q_SLOTS:
0092     void slotValueChanged(qint32 i)
0093     {
0094         m_realVal = i;
0095         if(m_pbRightToLeftLanguage != nullptr && *m_pbRightToLeftLanguage)
0096             m_realVal = maximum() - (i - minimum());
0097         Q_EMIT valueChanged2(m_realVal);
0098     }
0099 
0100   Q_SIGNALS:
0101     void valueChanged2(qint32);
0102 };
0103 
0104 /*
0105   InitFlag
0106 */
0107 
0108 enum class InitFlag
0109 {
0110     loadFiles = 1,
0111     useCurrentEncoding = 2,
0112     autoSolve = 4,
0113     initGUI = 8,
0114     defaultFlags = loadFiles | autoSolve | initGUI
0115 };
0116 
0117 Q_DECLARE_FLAGS(InitFlags, InitFlag);
0118 Q_DECLARE_OPERATORS_FOR_FLAGS(InitFlags);
0119 
0120 class KDiff3App: public QMainWindow
0121 {
0122     Q_OBJECT
0123 
0124   public:
0125     /** constructor of KDiff3App, calls all init functions to create the application.
0126      */
0127     KDiff3App(QWidget* parent, const QString& name, KDiff3Shell* pKDiff3Shell);
0128     ~KDiff3App() override;
0129 
0130     /** initializes the KActions of the application */
0131     void initActions(KActionCollection*);
0132 
0133     bool restoreWindow(const KSharedConfigPtr config);
0134     void saveWindow(const KSharedConfigPtr config);
0135 
0136     /** save general Options like all bar positions and status as well as the geometry
0137         and the recent file list to the configuration file */
0138     void saveOptions(KSharedConfigPtr);
0139 
0140     /** read general Options again and initialize all variables like the recent file list */
0141     void readOptions(KSharedConfigPtr);
0142 
0143     // Finish initialisation
0144     void completeInit(const QString& fn1 = QString(), const QString& fn2 = QString(), const QString& fn3 = QString());
0145     //Restore goementry and showMainWindow
0146     void showMainWindow();
0147 
0148     /** queryClose is called by KMainWindow on each closeEvent of a window. Against the
0149      * default implementation (only returns true), this calles saveModified() on the document object to ask if the document shall
0150      * be saved if Modified; on cancel the closeEvent is rejected.
0151      * @see KMainWindow#queryClose
0152      * @see KMainWindow#closeEvent
0153      */
0154     virtual bool queryClose();
0155     [[nodiscard]] virtual bool isFileSaved() const;
0156     [[nodiscard]] virtual bool isDirComparison() const;
0157 
0158     static bool isTripleDiff() { return m_bTripleDiff; }
0159 
0160     [[nodiscard]] KActionCollection* actionCollection() const;
0161 
0162     static boost::signals2::signal<QString (), FirstNonEmpty<QString>> getSelection;
0163     static boost::signals2::signal<bool(), or_> allowCopy;
0164     static boost::signals2::signal<bool(), or_> allowCut;
0165 
0166     bool canContinue();
0167 
0168   Q_SIGNALS:
0169     void createNewInstance(const QString& fn1, const QString& fn2, const QString& fn3);
0170 
0171     void sigRecalcWordWrap();
0172 
0173     void finishDrop();
0174 
0175     void showWhiteSpaceToggled();
0176     void showLineNumbersToggled();
0177     void doRefresh();
0178 
0179     void autoSolve();
0180     void unsolve();
0181     void mergeHistory();
0182     void regExpAutoMerge();
0183 
0184     void goCurrent();
0185     void goTop();
0186     void goBottom();
0187     void goPrevUnsolvedConflict();
0188 
0189     void goNextUnsolvedConflict();
0190     void goPrevConflict();
0191 
0192     void goNextConflict();
0193     void goPrevDelta();
0194     void goNextDelta();
0195 
0196     void cut();
0197 
0198     void copy();
0199 
0200     void selectAll();
0201 
0202     void changeOverViewMode(e_OverviewMode);
0203 public Q_SLOTS:
0204 
0205     /** open a file and load it into the document*/
0206     void slotFileOpen();
0207     void slotFileOpen2(QStringList &errors, const QString& fn1, const QString& fn2, const QString& fn3, const QString& ofn,
0208                        const QString& an1, const QString& an2, const QString& an3, TotalDiffStatus* pTotalDiffStatus);
0209 
0210     void slotFileNameChanged(const QString& fileName, e_SrcSelector winIdx);
0211 
0212     /** save a document */
0213     void slotFileSave();
0214     /** save a document by a new filename*/
0215     void slotFileSaveAs();
0216 
0217     void slotFilePrint();
0218 
0219     /** closes all open windows by calling close() on each memberList item until the list is empty, then quits the application.
0220      * If queryClose() returns false because the user canceled the saveModified() dialog, the closing breaks.
0221      */
0222     void slotFileQuit();
0223 
0224     void slotEditUndo(){};
0225     /** put the marked text/object into the clipboard and remove
0226      *  it from the document
0227      */
0228     void slotEditCut();
0229     /** put the marked text/object into the clipboard
0230      */
0231     void slotEditCopy();
0232     /** paste the clipboard into the document
0233      */
0234     void slotEditPaste();
0235     /** toggles the statusbar
0236      */
0237     void slotViewStatusBar();
0238     /** changes the statusbar contents for the standard label permanently, used to indicate current actions.
0239      * @param text the text that is displayed in the statusbar
0240      */
0241     void slotStatusMsg(const QString& text);
0242 
0243     void resizeDiffTextWindowHeight(qint32 newHeight);
0244     void slotRecalcWordWrap();
0245     void postRecalcWordWrap();
0246     void slotFinishRecalcWordWrap(qint32 visibleTextWidth);
0247 
0248     void showPopupMenu(const QPoint& point);
0249 
0250     void scrollDiffTextWindow(qint32 deltaX, qint32 deltaY);
0251     void scrollMergeResultWindow(qint32 deltaX, qint32 deltaY);
0252     void sourceMask(qint32 srcMask, qint32 enabledMask);
0253 
0254     void slotDirShowBoth();
0255     void slotDirViewToggle();
0256 
0257     void slotUpdateAvailabilities();
0258     void slotEditSelectAll();
0259     void slotEditFind();
0260     void slotEditFindNext();
0261     void slotGoCurrent();
0262     void slotGoTop();
0263     void slotGoBottom();
0264     void slotGoPrevUnsolvedConflict();
0265     void slotGoNextUnsolvedConflict();
0266     void slotGoPrevConflict();
0267     void slotGoNextConflict();
0268     void slotGoPrevDelta();
0269     void slotGoNextDelta();
0270     void slotGoToLine();
0271     void slotChooseA();
0272     void slotChooseB();
0273     void slotChooseC();
0274     void slotAutoSolve();
0275     void slotUnsolve();
0276     void slotMergeHistory();
0277     void slotRegExpAutoMerge();
0278     void slotConfigure();
0279     void slotConfigureKeys();
0280     void slotRefresh();
0281     void slotSelectionEnd();
0282     void slotSelectionStart();
0283     void slotClipboardChanged();
0284     void slotOutputModified(bool);
0285     void slotFinishMainInit();
0286     void slotMergeCurrentFile();
0287     void slotReload();
0288     void slotShowWhiteSpaceToggled();
0289     void slotShowLineNumbersToggled();
0290     void slotAutoAdvanceToggled();
0291     void slotWordWrapToggled();
0292     void slotShowWindowAToggled();
0293     void slotShowWindowBToggled();
0294     void slotShowWindowCToggled();
0295     void slotWinFocusNext();
0296     void slotWinFocusPrev();
0297     void slotWinToggleSplitterOrientation();
0298     void slotOverviewNormal();
0299     void slotOverviewAB();
0300     void slotOverviewAC();
0301     void slotOverviewBC();
0302     void slotSplitDiff();
0303     void slotJoinDiffs();
0304     void slotAddManualDiffHelp();
0305     void slotClearManualDiffHelpList();
0306     void slotNoRelevantChangesDetected();
0307     void slotEncodingChanged(const QByteArray&);
0308 
0309     void slotFinishDrop();
0310 
0311     void setHScrollBarRange();
0312 
0313     void slotFocusChanged(QWidget *old, QWidget *now);
0314   Q_SIGNALS:
0315     void updateAvailabilities();
0316 
0317   protected:
0318     void setLockPainting(bool bLock);
0319     void createCaption();
0320     void initDirectoryMergeActions();
0321     /** sets up the statusbar for the main window by initialzing a statuslabel. */
0322     void initStatusBar();
0323 
0324     /** creates the centerwidget of the KMainWindow instance and sets it as the view */
0325     void initView();
0326 
0327   private:
0328     void mainInit(TotalDiffStatus* pTotalDiffStatus, const InitFlags inFlags = InitFlag::defaultFlags);
0329     void mainWindowEnable(bool bEnable);
0330     void wheelEvent(QWheelEvent* pWheelEvent) override;
0331     void keyPressEvent(QKeyEvent* event) override;
0332     void resizeEvent(QResizeEvent*) override;
0333 
0334     void doFileCompare();
0335     bool doDirectoryCompare(const bool bCreateNewInstance);
0336     void improveFilenames();
0337 
0338     void choose(e_SrcSelector choice);
0339 
0340     [[nodiscard]] QStatusBar* statusBar() const;
0341     [[nodiscard]] KToolBar* toolBar(const QLatin1String &toolBarId) const;
0342     void recalcWordWrap(qint32 visibleTextWidthForPrinting = -1);
0343 
0344     bool canCut();
0345     bool canCopy();
0346 
0347     bool mInitCalled = false;
0348 
0349     // QAction pointers to enable/disable actions
0350     QPointer<QAction> fileOpen;
0351     QPointer<QAction> fileSave;
0352     QPointer<QAction> fileSaveAs;
0353     QPointer<QAction> filePrint;
0354     QPointer<QAction> fileQuit;
0355     QPointer<QAction> fileReload;
0356     QPointer<QAction> editUndo;
0357     QPointer<QAction> editCut;
0358     QPointer<QAction> editCopy;
0359     QPointer<QAction> editPaste;
0360     QPointer<QAction> editSelectAll;
0361     KToggleAction* viewStatusBar = nullptr;
0362 
0363     QPointer<QShortcut> mEscapeAction;
0364     ////////////////////////////////////////////////////////////////////////
0365     // Special KDiff3 specific stuff starts here
0366     QPointer<QAction> editFind;
0367     QPointer<QAction> editFindNext;
0368 
0369     QPointer<QAction> mGoCurrent;
0370     QPointer<QAction> mGoTop;
0371     QPointer<QAction> mGoBottom;
0372     QPointer<QAction> mGoPrevUnsolvedConflict;
0373     QPointer<QAction> mGoNextUnsolvedConflict;
0374     QPointer<QAction> mGoPrevConflict;
0375     QPointer<QAction> mGoNextConflict;
0376     QPointer<QAction> mGoPrevDelta;
0377     QPointer<QAction> mGoNextDelta;
0378     QPointer<QAction> mGotoLine;
0379     KToggleAction* chooseA = nullptr;
0380     KToggleAction* chooseB = nullptr;
0381     KToggleAction* chooseC = nullptr;
0382     KToggleAction* autoAdvance = nullptr;
0383     KToggleAction* wordWrap = nullptr;
0384     QPointer<QAction> splitDiff;
0385     QPointer<QAction> joinDiffs;
0386     QPointer<QAction> addManualDiffHelp;
0387     QPointer<QAction> clearManualDiffHelpList;
0388     KToggleAction* showWhiteSpaceCharacters = nullptr;
0389     KToggleAction* showWhiteSpace = nullptr;
0390     KToggleAction* showLineNumbers = nullptr;
0391     QPointer<QAction> mAutoSolve;
0392     QPointer<QAction> mUnsolve;
0393     QPointer<QAction> mMergeHistory;
0394     QPointer<QAction> mergeRegExp;
0395     KToggleAction* showWindowA = nullptr;
0396     KToggleAction* showWindowB = nullptr;
0397     KToggleAction* showWindowC = nullptr;
0398     QPointer<QAction> winFocusNext;
0399     QPointer<QAction> winFocusPrev;
0400     QPointer<QAction> winToggleSplitOrientation;
0401     KToggleAction* dirShowBoth = nullptr;
0402     QPointer<QAction> dirViewToggle;
0403     KToggleAction* overviewModeNormal = nullptr;
0404     KToggleAction* overviewModeAB = nullptr;
0405     KToggleAction* overviewModeAC = nullptr;
0406     KToggleAction* overviewModeBC = nullptr;
0407 
0408     QMenu* m_pMergeEditorPopupMenu = nullptr;
0409 
0410     QWidget* m_pMainWidget = nullptr; // Contains vertical splitter and horiz scrollbar
0411     QWidget* m_pCentralWidget = nullptr;
0412     QWidget* m_pMergeWindowFrame = nullptr;
0413     ReversibleScrollBar* m_pHScrollBar = nullptr;
0414 
0415     QPointer<DiffTextWindow> m_pDiffTextWindow1;
0416     QPointer<DiffTextWindow> m_pDiffTextWindow2;
0417     QPointer<DiffTextWindow> m_pDiffTextWindow3;
0418     DiffTextWindowFrame* m_pDiffTextWindowFrame1 = nullptr;
0419     DiffTextWindowFrame* m_pDiffTextWindowFrame2 = nullptr;
0420     DiffTextWindowFrame* m_pDiffTextWindowFrame3 = nullptr;
0421     QSplitter* m_pDiffWindowSplitter = nullptr;
0422 
0423     MergeResultWindow* m_pMergeResultWindow = nullptr;
0424     WindowTitleWidget* m_pMergeResultWindowTitle = nullptr;
0425     static bool m_bTripleDiff;
0426 
0427     QDockWidget* m_pDirectoryMergeDock = nullptr;
0428     DirectoryMergeWindow* m_pDirectoryMergeWindow = nullptr;
0429     QDockWidget* m_pDirectoryMergeInfoDock = nullptr;
0430     DirectoryMergeInfo* m_pDirectoryMergeInfo = nullptr;
0431     bool m_bDirCompare = false;
0432 
0433     Overview* m_pOverview = nullptr;
0434 
0435     QWidget* m_pCornerWidget = nullptr;
0436 
0437     TotalDiffStatus *m_totalDiffStatus = new TotalDiffStatus();
0438 
0439     QSharedPointer<SourceData> m_sd1 = QSharedPointer<SourceData>::create();
0440     QSharedPointer<SourceData> m_sd2 = QSharedPointer<SourceData>::create();
0441     QSharedPointer<SourceData> m_sd3 = QSharedPointer<SourceData>::create();
0442 
0443     QString m_outputFilename;
0444     bool m_bDefaultFilename = true;
0445 
0446     DiffList m_diffList12;
0447     DiffList m_diffList23;
0448     DiffList m_diffList13;
0449     Diff3LineList m_diff3LineList;
0450     Diff3LineVector mDiff3LineVector;
0451     ManualDiffHelpList m_manualDiffHelpList;
0452 
0453     LineType m_neededLines = 0;
0454     qint32 m_DTWHeight = 0;
0455     bool m_bOutputModified = false;
0456     bool m_bFileSaved = false;
0457     bool m_bTimerBlock = false; // Synchronization
0458 
0459     OptionDialog* m_pOptionDialog = nullptr;
0460     FindDialog* m_pFindDialog = nullptr;
0461 
0462     bool m_bFinishMainInit = false;
0463     bool m_bLoadFiles = false;
0464 
0465     KDiff3Shell* m_pKDiff3Shell = nullptr;
0466     bool m_bAutoFlag = false;
0467     bool m_bAutoMode = false;
0468     bool m_bRecalcWordWrapPosted = false;
0469 
0470     qint32 m_firstD3LIdx = 0; // only needed during recalcWordWrap
0471     QPointer<QEventLoop> m_pEventLoopForPrinting;
0472 
0473     bool mRunnablesStarted = false;
0474 
0475     QStringList mErrors;
0476     /*
0477       This list exists solely to auto disconnect boost signals.
0478     */
0479     std::list<boost::signals2::scoped_connection> connections;
0480 };
0481 
0482 extern std::unique_ptr<Options> gOptions;
0483 
0484 #endif // KDIFF3_H