summaryrefslogtreecommitdiffstats
path: root/src/kdiff3.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/kdiff3.cpp')
-rw-r--r--src/kdiff3.cpp992
1 files changed, 992 insertions, 0 deletions
diff --git a/src/kdiff3.cpp b/src/kdiff3.cpp
new file mode 100644
index 0000000..5bc2102
--- /dev/null
+++ b/src/kdiff3.cpp
@@ -0,0 +1,992 @@
+/***************************************************************************
+ kdiff3.cpp - description
+ -------------------
+ begin : Don Jul 11 12:31:29 CEST 2002
+ copyright : (C) 2002-2007 by Joachim Eibl
+ email : joachim.eibl at gmx.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program 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. *
+ * *
+ ***************************************************************************/
+
+#include "difftextwindow.h"
+#include "mergeresultwindow.h"
+
+#include <iostream>
+
+// include files for QT
+#include <qdir.h>
+#include <qprinter.h>
+#include <qpainter.h>
+#include <qsplitter.h>
+#include <qlineedit.h>
+#include <qcheckbox.h>
+#include <qpushbutton.h>
+#include <qpopupmenu.h>
+#include <qlabel.h>
+#include <qtextedit.h>
+#include <qlayout.h>
+#include <qpaintdevicemetrics.h>
+
+// include files for KDE
+#include <kiconloader.h>
+#include <kmessagebox.h>
+#include <kfiledialog.h>
+#include <kmenubar.h>
+#include <kstatusbar.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <kstdaction.h>
+#include <kcmdlineargs.h>
+#include <kprinter.h>
+//#include <kkeydialog.h>
+
+// application specific includes
+#include "kdiff3.h"
+#include "optiondialog.h"
+#include "fileaccess.h"
+#include "kdiff3_part.h"
+#include "directorymergewindow.h"
+#include "smalldialogs.h"
+
+#define ID_STATUS_MSG 1
+
+KActionCollection* KDiff3App::actionCollection()
+{
+ if ( m_pKDiff3Shell==0 )
+ return m_pKDiff3Part->actionCollection();
+ else
+ return m_pKDiff3Shell->actionCollection();
+}
+
+KStatusBar* KDiff3App::statusBar()
+{
+ if ( m_pKDiff3Shell==0 )
+ return 0;
+ else
+ return m_pKDiff3Shell->statusBar();
+}
+
+KToolBar* KDiff3App::toolBar(const char* toolBarId )
+{
+ if ( m_pKDiff3Shell==0 )
+ return 0;
+ else
+ return m_pKDiff3Shell->toolBar( toolBarId );
+}
+
+bool KDiff3App::isPart()
+{
+ return m_pKDiff3Shell==0;
+}
+
+bool KDiff3App::isFileSaved()
+{
+ return m_bFileSaved;
+}
+
+KDiff3App::KDiff3App(QWidget* pParent, const char* name, KDiff3Part* pKDiff3Part )
+ :QSplitter(pParent, name) //previously KMainWindow
+{
+ m_pKDiff3Part = pKDiff3Part;
+ m_pKDiff3Shell = dynamic_cast<KParts::MainWindow*>(pParent);
+
+ setCaption( "KDiff3" );
+
+ m_pMainSplitter = 0;
+ m_pDirectoryMergeWindow = 0;
+ m_pCornerWidget = 0;
+ m_pMainWidget = 0;
+ m_pDiffTextWindow1 = 0;
+ m_pDiffTextWindow2 = 0;
+ m_pDiffTextWindow3 = 0;
+ m_pDiffTextWindowFrame1 = 0;
+ m_pDiffTextWindowFrame2 = 0;
+ m_pDiffTextWindowFrame3 = 0;
+ m_pDiffWindowSplitter = 0;
+ m_pOverview = 0;
+ m_bTripleDiff = false;
+ m_pMergeResultWindow = 0;
+ m_pMergeWindowFrame = 0;
+ m_bOutputModified = false;
+ m_bFileSaved = false;
+ m_bTimerBlock = false;
+ m_pHScrollBar = 0;
+
+ // Needed before any file operations via FileAccess happen.
+ if (!g_pProgressDialog)
+ {
+ g_pProgressDialog = new ProgressDialog(0);
+ g_pProgressDialog->setStayHidden( true );
+ }
+
+ // All default values must be set before calling readOptions().
+ m_pOptionDialog = new OptionDialog( m_pKDiff3Shell!=0, this );
+ connect( m_pOptionDialog, SIGNAL(applyClicked()), this, SLOT(slotRefresh()) );
+
+ m_pOptionDialog->readOptions( isPart() ? m_pKDiff3Part->instance()->config() : kapp->config() );
+
+ // Option handling: Only when pParent==0 (no parent)
+ KCmdLineArgs *args = isPart() ? 0 : KCmdLineArgs::parsedArgs();
+
+ if (args)
+ {
+ QString s;
+ QString title;
+ if ( args->isSet("confighelp") )
+ {
+ s = m_pOptionDialog->calcOptionHelp();
+ title = i18n("Current Configuration:");
+ }
+ else
+ {
+ s = m_pOptionDialog->parseOptions( args->getOptionList("cs") );
+ title = i18n("Config Option Error:");
+ }
+ if (!s.isEmpty())
+ {
+#ifdef _WIN32
+ // A windows program has no console
+ //KMessageBox::information(0, s,i18n("KDiff3-Usage"));
+ QDialog* pDialog = new QDialog(this,"",true,Qt::WDestructiveClose);
+ pDialog->setCaption(title);
+ QVBoxLayout* pVBoxLayout = new QVBoxLayout( pDialog );
+ QTextEdit* pTextEdit = new QTextEdit(pDialog);
+ pTextEdit->setText(s);
+ pTextEdit->setReadOnly(true);
+ pTextEdit->setWordWrap(QTextEdit::NoWrap);
+ pVBoxLayout->addWidget(pTextEdit);
+ pDialog->resize(600,400);
+ pDialog->exec();
+#else
+ std::cerr << title.latin1() << std::endl;
+ std::cerr << s.latin1() << std::endl;
+#endif
+ exit(1);
+ }
+ }
+
+ m_sd1.setOptionDialog(m_pOptionDialog);
+ m_sd2.setOptionDialog(m_pOptionDialog);
+ m_sd3.setOptionDialog(m_pOptionDialog);
+
+ if (args!=0)
+ {
+ m_outputFilename = args->getOption("output");
+ if ( m_outputFilename.isEmpty() )
+ m_outputFilename = args->getOption("out");
+ }
+
+ m_bAutoFlag = args!=0 && args->isSet("auto");
+ m_bAutoMode = m_bAutoFlag || m_pOptionDialog->m_bAutoSaveAndQuitOnMergeWithoutConflicts;
+ if ( m_bAutoMode && m_outputFilename.isEmpty() )
+ {
+ if ( m_bAutoFlag )
+ {
+ //KMessageBox::information(this, i18n("Option --auto used, but no output file specified."));
+ std::cerr << i18n("Option --auto used, but no output file specified.").ascii()<<std::endl;
+ }
+ m_bAutoMode = false;
+ }
+ g_pProgressDialog->setStayHidden( m_bAutoMode );
+
+ if ( m_outputFilename.isEmpty() && args!=0 && args->isSet("merge") )
+ {
+ m_outputFilename = "unnamed.txt";
+ m_bDefaultFilename = true;
+ }
+ else
+ m_bDefaultFilename = false;
+
+ g_bAutoSolve = args!=0 && !args->isSet("qall"); // Note that this is effective only once.
+
+ if ( args!=0 )
+ {
+ m_sd1.setFilename( args->getOption("base") );
+ if ( m_sd1.isEmpty() )
+ {
+ if ( args->count() > 0 ) m_sd1.setFilename( args->url(0).url() ); // args->arg(0)
+ if ( args->count() > 1 ) m_sd2.setFilename( args->url(1).url() );
+ if ( args->count() > 2 ) m_sd3.setFilename( args->url(2).url() );
+ }
+ else
+ {
+ if ( args->count() > 0 ) m_sd2.setFilename( args->url(0).url() );
+ if ( args->count() > 1 ) m_sd3.setFilename( args->url(1).url() );
+ }
+
+
+ QCStringList aliasList = args->getOptionList("fname");
+ QCStringList::Iterator ali = aliasList.begin();
+
+ QString an1 = args->getOption("L1");
+ if ( !an1.isEmpty() ) { m_sd1.setAliasName(an1); }
+ else if ( ali != aliasList.end() ) { m_sd1.setAliasName(*ali); ++ali; }
+
+ QString an2 = args->getOption("L2");
+ if ( !an2.isEmpty() ) { m_sd2.setAliasName(an2); }
+ else if ( ali != aliasList.end() ) { m_sd2.setAliasName(*ali); ++ali; }
+
+ QString an3 = args->getOption("L3");
+ if ( !an3.isEmpty() ) { m_sd3.setAliasName(an3); }
+ else if ( ali != aliasList.end() ) { m_sd3.setAliasName(*ali); ++ali; }
+ }
+ ///////////////////////////////////////////////////////////////////
+ // call inits to invoke all other construction parts
+ initActions(actionCollection());
+ initStatusBar();
+
+ m_pFindDialog = new FindDialog( this );
+ connect( m_pFindDialog, SIGNAL(findNext()), this, SLOT(slotEditFindNext()));
+
+ autoAdvance->setChecked( m_pOptionDialog->m_bAutoAdvance );
+ showWhiteSpaceCharacters->setChecked( m_pOptionDialog->m_bShowWhiteSpaceCharacters );
+ showWhiteSpace->setChecked( m_pOptionDialog->m_bShowWhiteSpace );
+ showWhiteSpaceCharacters->setEnabled( m_pOptionDialog->m_bShowWhiteSpace );
+ showLineNumbers->setChecked( m_pOptionDialog->m_bShowLineNumbers );
+ wordWrap->setChecked( m_pOptionDialog->m_bWordWrap );
+ if ( ! isPart() )
+ {
+ viewToolBar->setChecked( m_pOptionDialog->m_bShowToolBar );
+ viewStatusBar->setChecked( m_pOptionDialog->m_bShowStatusBar );
+ slotViewToolBar();
+ slotViewStatusBar();
+ if( toolBar("mainToolBar")!=0 )
+ toolBar("mainToolBar")->setBarPos( (KToolBar::BarPosition) m_pOptionDialog->m_toolBarPos );
+/* QSize size = m_pOptionDialog->m_geometry;
+ QPoint pos = m_pOptionDialog->m_position;
+ if(!size.isEmpty())
+ {
+ m_pKDiff3Shell->resize( size );
+ QRect visibleRect = QRect( pos, size ) & QApplication::desktop()->rect();
+ if ( visibleRect.width()>100 && visibleRect.height()>100 )
+ m_pKDiff3Shell->move( pos );
+ }*/
+ }
+ slotRefresh();
+
+ m_pMainSplitter = this; //new QSplitter(this);
+ m_pMainSplitter->setOrientation( Vertical );
+// setCentralWidget( m_pMainSplitter );
+ m_pDirectoryMergeSplitter = new QSplitter( m_pMainSplitter );
+ m_pDirectoryMergeSplitter->setOrientation( Horizontal );
+ m_pDirectoryMergeWindow = new DirectoryMergeWindow( m_pDirectoryMergeSplitter, m_pOptionDialog,
+ KApplication::kApplication()->iconLoader() );
+ m_pDirectoryMergeInfo = new DirectoryMergeInfo( m_pDirectoryMergeSplitter );
+ m_pDirectoryMergeWindow->setDirectoryMergeInfo( m_pDirectoryMergeInfo );
+ connect( m_pDirectoryMergeWindow, SIGNAL(startDiffMerge(QString,QString,QString,QString,QString,QString,QString,TotalDiffStatus*)),
+ this, SLOT( slotFileOpen2(QString,QString,QString,QString,QString,QString,QString,TotalDiffStatus*)));
+ connect( m_pDirectoryMergeWindow, SIGNAL(selectionChanged()), this, SLOT(slotUpdateAvailabilities()));
+ connect( m_pDirectoryMergeWindow, SIGNAL(currentChanged(QListViewItem*)), this, SLOT(slotUpdateAvailabilities()));
+ connect( m_pDirectoryMergeWindow, SIGNAL(checkIfCanContinue(bool*)), this, SLOT(slotCheckIfCanContinue(bool*)));
+ connect( m_pDirectoryMergeWindow, SIGNAL(updateAvailabilities()), this, SLOT(slotUpdateAvailabilities()));
+ connect( m_pDirectoryMergeWindow, SIGNAL(statusBarMessage(const QString&)), this, SLOT(slotStatusMsg(const QString&)));
+
+ m_pDirectoryMergeWindow->initDirectoryMergeActions( this, actionCollection() );
+
+ if ( args!=0 ) args->clear(); // Free up some memory.
+
+ if (m_pKDiff3Shell==0)
+ {
+ completeInit();
+ }
+}
+
+
+void KDiff3App::completeInit( const QString& fn1, const QString& fn2, const QString& fn3 )
+{
+ if (m_pKDiff3Shell!=0)
+ {
+ QSize size=m_pOptionDialog->m_geometry;
+ QPoint pos=m_pOptionDialog->m_position;
+ if(!size.isEmpty())
+ {
+ m_pKDiff3Shell->resize( size );
+ QRect visibleRect = QRect( pos, size ) & QApplication::desktop()->rect();
+ if ( visibleRect.width()>100 && visibleRect.height()>100 )
+ m_pKDiff3Shell->move( pos );
+ if (!m_bAutoMode)
+ {
+ if ( m_pOptionDialog->m_bMaximised )
+ m_pKDiff3Shell->showMaximized();
+ else
+ m_pKDiff3Shell->show();
+ }
+ }
+ }
+ if ( ! fn1.isEmpty() ) { m_sd1.setFilename(fn1); }
+ if ( ! fn2.isEmpty() ) { m_sd2.setFilename(fn2); }
+ if ( ! fn3.isEmpty() ) { m_sd3.setFilename(fn3); }
+
+ bool bSuccess = improveFilenames(false);
+
+ if ( m_bAutoFlag && m_bAutoMode && m_bDirCompare )
+ {
+ std::cerr << i18n("Option --auto ignored for directory comparison.").ascii()<<std::endl;
+ m_bAutoMode = false;
+ }
+ if (!m_bDirCompare)
+ {
+ m_pDirectoryMergeSplitter->hide();
+
+ init( m_bAutoMode );
+ if ( m_bAutoMode )
+ {
+ SourceData* pSD=0;
+ if ( m_sd3.isEmpty() )
+ {
+ if ( m_totalDiffStatus.bBinaryAEqB ){ pSD = &m_sd1; }
+ }
+ else
+ {
+ if ( m_totalDiffStatus.bBinaryBEqC ){ pSD = &m_sd3; } // B==C (assume A is old)
+ else if ( m_totalDiffStatus.bBinaryAEqB ){ pSD = &m_sd3; } // assuming C has changed
+ else if ( m_totalDiffStatus.bBinaryAEqC ){ pSD = &m_sd2; } // assuming B has changed
+ }
+
+ if ( pSD!=0 )
+ {
+ // Save this file directly, not via the merge result window.
+ bool bSuccess = false;
+ FileAccess fa( m_outputFilename );
+ if ( m_pOptionDialog->m_bDmCreateBakFiles && fa.exists() )
+ {
+ QString newName = m_outputFilename + ".orig";
+ if ( FileAccess::exists( newName ) ) FileAccess::removeFile( newName );
+ if ( !FileAccess::exists( newName ) ) fa.rename( newName );
+ }
+
+ bSuccess = pSD->saveNormalDataAs( m_outputFilename );
+ if ( bSuccess ) ::exit(0);
+ else KMessageBox::error( this, i18n("Saving failed.") );
+ }
+ else if ( m_pMergeResultWindow->getNrOfUnsolvedConflicts() == 0 )
+ {
+ bool bSuccess = m_pMergeResultWindow->saveDocument( m_pMergeResultWindowTitle->getFileName(), m_pMergeResultWindowTitle->getEncoding() );
+ if ( bSuccess ) ::exit(0);
+ }
+ }
+ }
+ m_bAutoMode = false;
+
+ if (m_pKDiff3Shell)
+ {
+ if ( m_pOptionDialog->m_bMaximised )
+ m_pKDiff3Shell->showMaximized();
+ else
+ m_pKDiff3Shell->show();
+ }
+
+ g_pProgressDialog->setStayHidden( false );
+
+ if (statusBar() !=0 )
+ statusBar()->setSizeGripEnabled(true);
+
+ slotClipboardChanged(); // For initialisation.
+
+ slotUpdateAvailabilities();
+
+ if ( ! m_bDirCompare && m_pKDiff3Shell!=0 )
+ {
+ bool bFileOpenError = false;
+ if ( ! m_sd1.isEmpty() && !m_sd1.hasData() ||
+ ! m_sd2.isEmpty() && !m_sd2.hasData() ||
+ ! m_sd3.isEmpty() && !m_sd3.hasData() )
+ {
+ QString text( i18n("Opening of these files failed:") );
+ text += "\n\n";
+ if ( ! m_sd1.isEmpty() && !m_sd1.hasData() )
+ text += " - " + m_sd1.getAliasName() + "\n";
+ if ( ! m_sd2.isEmpty() && !m_sd2.hasData() )
+ text += " - " + m_sd2.getAliasName() + "\n";
+ if ( ! m_sd3.isEmpty() && !m_sd3.hasData() )
+ text += " - " + m_sd3.getAliasName() + "\n";
+
+ KMessageBox::sorry( this, text, i18n("File Open Error") );
+ bFileOpenError = true;
+ }
+
+ if ( m_sd1.isEmpty() || m_sd2.isEmpty() || bFileOpenError )
+ slotFileOpen();
+ }
+ else if ( !bSuccess ) // Directory open failed
+ {
+ slotFileOpen();
+ }
+}
+
+KDiff3App::~KDiff3App()
+{
+
+}
+
+void KDiff3App::initActions( KActionCollection* ac )
+{
+ if (ac==0) KMessageBox::error(0, "actionCollection==0");
+
+ fileOpen = KStdAction::open(this, SLOT(slotFileOpen()), ac);
+ fileOpen->setStatusText(i18n("Opens documents for comparison..."));
+
+ fileReload = new KAction(i18n("Reload"), /*QIconSet(QPixmap(reloadIcon)),*/ Key_F5, this, SLOT(slotReload()), ac, "file_reload");
+
+ fileSave = KStdAction::save(this, SLOT(slotFileSave()), ac);
+ fileSave->setStatusText(i18n("Saves the merge result. All conflicts must be solved!"));
+ fileSaveAs = KStdAction::saveAs(this, SLOT(slotFileSaveAs()), ac);
+ fileSaveAs->setStatusText(i18n("Saves the current document as..."));
+ filePrint = KStdAction::print(this, SLOT(slotFilePrint()), ac);
+ filePrint->setStatusText(i18n("Print the differences"));
+ fileQuit = KStdAction::quit(this, SLOT(slotFileQuit()), ac);
+ fileQuit->setStatusText(i18n("Quits the application"));
+ editCut = KStdAction::cut(this, SLOT(slotEditCut()), ac);
+ editCut->setStatusText(i18n("Cuts the selected section and puts it to the clipboard"));
+ editCopy = KStdAction::copy(this, SLOT(slotEditCopy()), ac);
+ editCopy->setStatusText(i18n("Copies the selected section to the clipboard"));
+ editPaste = KStdAction::paste(this, SLOT(slotEditPaste()), ac);
+ editPaste->setStatusText(i18n("Pastes the clipboard contents to actual position"));
+ editSelectAll = KStdAction::selectAll(this, SLOT(slotEditSelectAll()), ac);
+ editSelectAll->setStatusText(i18n("Select everything in current window"));
+ editFind = KStdAction::find(this, SLOT(slotEditFind()), ac);
+ editFind->setStatusText(i18n("Search for a string"));
+ editFindNext = KStdAction::findNext(this, SLOT(slotEditFindNext()), ac);
+ editFindNext->setStatusText(i18n("Search again for the string"));
+ viewToolBar = KStdAction::showToolbar(this, SLOT(slotViewToolBar()), ac);
+ viewToolBar->setStatusText(i18n("Enables/disables the toolbar"));
+ viewStatusBar = KStdAction::showStatusbar(this, SLOT(slotViewStatusBar()), ac);
+ viewStatusBar->setStatusText(i18n("Enables/disables the statusbar"));
+ KStdAction::keyBindings(this, SLOT(slotConfigureKeys()), ac);
+ KAction* pAction = KStdAction::preferences(this, SLOT(slotConfigure()), ac );
+ if ( isPart() )
+ pAction->setText(i18n("Configure KDiff3..."));
+
+
+#include "xpm/downend.xpm"
+#include "xpm/currentpos.xpm"
+#include "xpm/down1arrow.xpm"
+#include "xpm/down2arrow.xpm"
+#include "xpm/upend.xpm"
+#include "xpm/up1arrow.xpm"
+#include "xpm/up2arrow.xpm"
+#include "xpm/prevunsolved.xpm"
+#include "xpm/nextunsolved.xpm"
+#include "xpm/iconA.xpm"
+#include "xpm/iconB.xpm"
+#include "xpm/iconC.xpm"
+#include "xpm/autoadvance.xpm"
+#include "xpm/showwhitespace.xpm"
+#include "xpm/showwhitespacechars.xpm"
+#include "xpm/showlinenumbers.xpm"
+//#include "reload.xpm"
+
+ goCurrent = new KAction(i18n("Go to Current Delta"), QIconSet(QPixmap(currentpos)), CTRL+Key_Space, this, SLOT(slotGoCurrent()), ac, "go_current");
+ goTop = new KAction(i18n("Go to First Delta"), QIconSet(QPixmap(upend)), 0, this, SLOT(slotGoTop()), ac, "go_top");
+ goBottom = new KAction(i18n("Go to Last Delta"), QIconSet(QPixmap(downend)), 0, this, SLOT(slotGoBottom()), ac, "go_bottom");
+ QString omitsWhitespace = ".\n" + i18n("(Skips white space differences when \"Show White Space\" is disabled.)");
+ QString includeWhitespace = ".\n" + i18n("(Does not skip white space differences even when \"Show White Space\" is disabled.)");
+ goPrevDelta = new KAction(i18n("Go to Previous Delta"), QIconSet(QPixmap(up1arrow)), CTRL+Key_Up, this, SLOT(slotGoPrevDelta()), ac, "go_prev_delta");
+ goPrevDelta->setToolTip( goPrevDelta->text() + omitsWhitespace );
+ goNextDelta = new KAction(i18n("Go to Next Delta"), QIconSet(QPixmap(down1arrow)), CTRL+Key_Down, this, SLOT(slotGoNextDelta()), ac, "go_next_delta");
+ goNextDelta->setToolTip( goNextDelta->text() + omitsWhitespace );
+ goPrevConflict = new KAction(i18n("Go to Previous Conflict"), QIconSet(QPixmap(up2arrow)), CTRL+Key_PageUp, this, SLOT(slotGoPrevConflict()), ac, "go_prev_conflict");
+ goPrevConflict->setToolTip( goPrevConflict->text() + omitsWhitespace );
+ goNextConflict = new KAction(i18n("Go to Next Conflict"), QIconSet(QPixmap(down2arrow)), CTRL+Key_PageDown, this, SLOT(slotGoNextConflict()), ac, "go_next_conflict");
+ goNextConflict->setToolTip( goNextConflict->text() + omitsWhitespace );
+ goPrevUnsolvedConflict = new KAction(i18n("Go to Previous Unsolved Conflict"), QIconSet(QPixmap(prevunsolved)), 0, this, SLOT(slotGoPrevUnsolvedConflict()), ac, "go_prev_unsolved_conflict");
+ goPrevUnsolvedConflict->setToolTip( goPrevUnsolvedConflict->text() + includeWhitespace );
+ goNextUnsolvedConflict = new KAction(i18n("Go to Next Unsolved Conflict"), QIconSet(QPixmap(nextunsolved)), 0, this, SLOT(slotGoNextUnsolvedConflict()), ac, "go_next_unsolved_conflict");
+ goNextUnsolvedConflict->setToolTip( goNextUnsolvedConflict->text() + includeWhitespace );
+ chooseA = new KToggleAction(i18n("Select Line(s) From A"), QIconSet(QPixmap(iconA)), CTRL+Key_1, this, SLOT(slotChooseA()), ac, "merge_choose_a");
+ chooseB = new KToggleAction(i18n("Select Line(s) From B"), QIconSet(QPixmap(iconB)), CTRL+Key_2, this, SLOT(slotChooseB()), ac, "merge_choose_b");
+ chooseC = new KToggleAction(i18n("Select Line(s) From C"), QIconSet(QPixmap(iconC)), CTRL+Key_3, this, SLOT(slotChooseC()), ac, "merge_choose_c");
+ autoAdvance = new KToggleAction(i18n("Automatically Go to Next Unsolved Conflict After Source Selection"), QIconSet(QPixmap(autoadvance)), 0, this, SLOT(slotAutoAdvanceToggled()), ac, "merge_autoadvance");
+
+ showWhiteSpaceCharacters = new KToggleAction(i18n("Show Space && Tabulator Characters for Differences"), QIconSet(QPixmap(showwhitespacechars)), 0, this, SLOT(slotShowWhiteSpaceToggled()), ac, "diff_show_whitespace_characters");
+ showWhiteSpace = new KToggleAction(i18n("Show White Space"), QIconSet(QPixmap(showwhitespace)), 0, this, SLOT(slotShowWhiteSpaceToggled()), ac, "diff_show_whitespace");
+
+ showLineNumbers = new KToggleAction(i18n("Show Line Numbers"), QIconSet(QPixmap(showlinenumbers)), 0, this, SLOT(slotShowLineNumbersToggled()), ac, "diff_showlinenumbers");
+ chooseAEverywhere = new KAction(i18n("Choose A Everywhere"), CTRL+SHIFT+Key_1, this, SLOT(slotChooseAEverywhere()), ac, "merge_choose_a_everywhere");
+ chooseBEverywhere = new KAction(i18n("Choose B Everywhere"), CTRL+SHIFT+Key_2, this, SLOT(slotChooseBEverywhere()), ac, "merge_choose_b_everywhere");
+ chooseCEverywhere = new KAction(i18n("Choose C Everywhere"), CTRL+SHIFT+Key_3, this, SLOT(slotChooseCEverywhere()), ac, "merge_choose_c_everywhere");
+ chooseAForUnsolvedConflicts = new KAction(i18n("Choose A for All Unsolved Conflicts"), 0, this, SLOT(slotChooseAForUnsolvedConflicts()), ac, "merge_choose_a_for_unsolved_conflicts");
+ chooseBForUnsolvedConflicts = new KAction(i18n("Choose B for All Unsolved Conflicts"), 0, this, SLOT(slotChooseBForUnsolvedConflicts()), ac, "merge_choose_b_for_unsolved_conflicts");
+ chooseCForUnsolvedConflicts = new KAction(i18n("Choose C for All Unsolved Conflicts"), 0, this, SLOT(slotChooseCForUnsolvedConflicts()), ac, "merge_choose_c_for_unsolved_conflicts");
+ chooseAForUnsolvedWhiteSpaceConflicts = new KAction(i18n("Choose A for All Unsolved Whitespace Conflicts"), 0, this, SLOT(slotChooseAForUnsolvedWhiteSpaceConflicts()), ac, "merge_choose_a_for_unsolved_whitespace_conflicts");
+ chooseBForUnsolvedWhiteSpaceConflicts = new KAction(i18n("Choose B for All Unsolved Whitespace Conflicts"), 0, this, SLOT(slotChooseBForUnsolvedWhiteSpaceConflicts()), ac, "merge_choose_b_for_unsolved_whitespace_conflicts");
+ chooseCForUnsolvedWhiteSpaceConflicts = new KAction(i18n("Choose C for All Unsolved Whitespace Conflicts"), 0, this, SLOT(slotChooseCForUnsolvedWhiteSpaceConflicts()), ac, "merge_choose_c_for_unsolved_whitespace_conflicts");
+ autoSolve = new KAction(i18n("Automatically Solve Simple Conflicts"), 0, this, SLOT(slotAutoSolve()), ac, "merge_autosolve");
+ unsolve = new KAction(i18n("Set Deltas to Conflicts"), 0, this, SLOT(slotUnsolve()), ac, "merge_autounsolve");
+ mergeRegExp = new KAction(i18n("Run Regular Expression Auto Merge"), 0, this, SLOT(slotRegExpAutoMerge()),ac, "merge_regexp_automerge" );
+ mergeHistory = new KAction(i18n("Automatically Solve History Conflicts"), 0, this, SLOT(slotMergeHistory()), ac, "merge_versioncontrol_history" );
+ splitDiff = new KAction(i18n("Split Diff At Selection"), 0, this, SLOT(slotSplitDiff()), ac, "merge_splitdiff");
+ joinDiffs = new KAction(i18n("Join Selected Diffs"), 0, this, SLOT(slotJoinDiffs()), ac, "merge_joindiffs");
+
+ showWindowA = new KToggleAction(i18n("Show Window A"), 0, this, SLOT(slotShowWindowAToggled()), ac, "win_show_a");
+ showWindowB = new KToggleAction(i18n("Show Window B"), 0, this, SLOT(slotShowWindowBToggled()), ac, "win_show_b");
+ showWindowC = new KToggleAction(i18n("Show Window C"), 0, this, SLOT(slotShowWindowCToggled()), ac, "win_show_c");
+ winFocusNext = new KAction(i18n("Focus Next Window"), ALT+Key_Right, this, SLOT(slotWinFocusNext()), ac, "win_focus_next");
+
+ overviewModeNormal = new KToggleAction(i18n("Normal Overview"), 0, this, SLOT(slotOverviewNormal()), ac, "diff_overview_normal");
+ overviewModeAB = new KToggleAction(i18n("A vs. B Overview"), 0, this, SLOT(slotOverviewAB()), ac, "diff_overview_ab");
+ overviewModeAC = new KToggleAction(i18n("A vs. C Overview"), 0, this, SLOT(slotOverviewAC()), ac, "diff_overview_ac");
+ overviewModeBC = new KToggleAction(i18n("B vs. C Overview"), 0, this, SLOT(slotOverviewBC()), ac, "diff_overview_bc");
+ wordWrap = new KToggleAction(i18n("Word Wrap Diff Windows"), 0, this, SLOT(slotWordWrapToggled()), ac, "diff_wordwrap");
+ addManualDiffHelp = new KAction(i18n("Add Manual Diff Alignment"), Qt::CTRL+Qt::Key_Y, this, SLOT(slotAddManualDiffHelp()), ac, "diff_add_manual_diff_help");
+ clearManualDiffHelpList = new KAction(i18n("Clear All Manual Diff Alignments"), Qt::CTRL+Qt::SHIFT+Qt::Key_Y, this, SLOT(slotClearManualDiffHelpList()), ac, "diff_clear_manual_diff_help_list");
+
+#ifdef _WIN32
+ new KAction(i18n("Focus Next Window"), Qt::CTRL+Qt::Key_Tab, this, SLOT(slotWinFocusNext()), ac, "win_focus_next", false, false);
+#endif
+ winFocusPrev = new KAction(i18n("Focus Prev Window"), Qt::ALT+Qt::Key_Left, this, SLOT(slotWinFocusPrev()), ac, "win_focus_prev");
+ winToggleSplitOrientation = new KAction(i18n("Toggle Split Orientation"), 0, this, SLOT(slotWinToggleSplitterOrientation()), ac, "win_toggle_split_orientation");
+
+ dirShowBoth = new KToggleAction(i18n("Dir && Text Split Screen View"), 0, this, SLOT(slotDirShowBoth()), ac, "win_dir_show_both");
+ dirShowBoth->setChecked( true );
+ dirViewToggle = new KAction(i18n("Toggle Between Dir && Text View"), 0, this, SLOT(slotDirViewToggle()), actionCollection(), "win_dir_view_toggle");
+
+ m_pMergeEditorPopupMenu = new QPopupMenu( this );
+ chooseA->plug( m_pMergeEditorPopupMenu );
+ chooseB->plug( m_pMergeEditorPopupMenu );
+ chooseC->plug( m_pMergeEditorPopupMenu );
+}
+
+
+void KDiff3App::showPopupMenu( const QPoint& point )
+{
+ m_pMergeEditorPopupMenu->popup( point );
+}
+
+void KDiff3App::initStatusBar()
+{
+ ///////////////////////////////////////////////////////////////////
+ // STATUSBAR
+ if (statusBar() !=0 )
+ statusBar()->message( i18n("Ready.") );
+}
+
+void KDiff3App::saveOptions( KConfig* config )
+{
+ if ( !m_bAutoMode )
+ {
+ if (!isPart())
+ {
+ m_pOptionDialog->m_bMaximised = m_pKDiff3Shell->isMaximized();
+ if( ! m_pKDiff3Shell->isMaximized() && m_pKDiff3Shell->isVisible() )
+ {
+ m_pOptionDialog->m_geometry = m_pKDiff3Shell->size();
+ m_pOptionDialog->m_position = m_pKDiff3Shell->pos();
+ }
+ if ( toolBar("mainToolBar")!=0 )
+ m_pOptionDialog->m_toolBarPos = (int) toolBar("mainToolBar")->barPos();
+ }
+
+ m_pOptionDialog->saveOptions( config );
+ }
+}
+
+
+
+
+bool KDiff3App::queryClose()
+{
+ saveOptions( isPart() ? m_pKDiff3Part->instance()->config() : kapp->config() );
+
+ if(m_bOutputModified)
+ {
+ int result = KMessageBox::warningYesNoCancel(this,
+ i18n("The merge result hasn't been saved."),
+ i18n("Warning"), i18n("Save && Quit"), i18n("Quit Without Saving") );
+ if ( result==KMessageBox::Cancel )
+ return false;
+ else if ( result==KMessageBox::Yes )
+ {
+ slotFileSave();
+ if ( m_bOutputModified )
+ {
+ KMessageBox::sorry(this, i18n("Saving the merge result failed."), i18n("Warning") );
+ return false;
+ }
+ }
+ }
+
+ m_bOutputModified = false;
+
+ if ( m_pDirectoryMergeWindow->isDirectoryMergeInProgress() )
+ {
+ int result = KMessageBox::warningYesNo(this,
+ i18n("You are currently doing a directory merge. Are you sure, you want to abort?"),
+ i18n("Warning"), i18n("Quit"), i18n("Continue Merging") );
+ if ( result!=KMessageBox::Yes )
+ return false;
+ }
+
+ return true;
+}
+
+
+/////////////////////////////////////////////////////////////////////
+// SLOT IMPLEMENTATION
+/////////////////////////////////////////////////////////////////////
+
+
+void KDiff3App::slotFileSave()
+{
+ if ( m_bDefaultFilename )
+ {
+ slotFileSaveAs();
+ }
+ else
+ {
+ slotStatusMsg(i18n("Saving file..."));
+
+ bool bSuccess = m_pMergeResultWindow->saveDocument( m_outputFilename, m_pMergeResultWindowTitle->getEncoding() );
+ if ( bSuccess )
+ {
+ m_bFileSaved = true;
+ m_bOutputModified = false;
+ if ( m_bDirCompare )
+ m_pDirectoryMergeWindow->mergeResultSaved(m_outputFilename);
+ }
+
+ slotStatusMsg(i18n("Ready."));
+ }
+}
+
+void KDiff3App::slotFileSaveAs()
+{
+ slotStatusMsg(i18n("Saving file with a new filename..."));
+
+ QString s = KFileDialog::getSaveURL( QDir::currentDirPath(), 0, this, i18n("Save As...") ).url();
+ if(!s.isEmpty())
+ {
+ m_outputFilename = s;
+ m_pMergeResultWindowTitle->setFileName( m_outputFilename );
+ bool bSuccess = m_pMergeResultWindow->saveDocument( m_outputFilename, m_pMergeResultWindowTitle->getEncoding() );
+ if ( bSuccess )
+ {
+ m_bOutputModified = false;
+ if ( m_bDirCompare )
+ m_pDirectoryMergeWindow->mergeResultSaved(m_outputFilename);
+ }
+ //setCaption(url.fileName(),doc->isModified());
+
+ m_bDefaultFilename = false;
+ }
+
+ slotStatusMsg(i18n("Ready."));
+}
+
+
+void printDiffTextWindow( MyPainter& painter, const QRect& view, const QString& headerText, DiffTextWindow* pDiffTextWindow, int line, int linesPerPage, QColor fgColor )
+{
+ QRect clipRect = view;
+ clipRect.setTop(0);
+ painter.setClipRect( clipRect );
+ painter.translate( view.left() , 0 );
+ QFontMetrics fm = painter.fontMetrics();
+ //if ( fm.width(headerText) > view.width() )
+ {
+ // A simple wrapline algorithm
+ int l=0;
+ for (unsigned int p=0; p<headerText.length(); )
+ {
+ QString s = headerText.mid(p);
+ unsigned int i;
+ for(i=2;i<s.length();++i)
+ if (fm.width(s,i)>view.width())
+ {
+ --i;
+ break;
+ }
+ //QString s2 = s.left(i);
+ painter.drawText( 0, l*fm.height() + fm.ascent(), s.left(i) );
+ p+=i;
+ ++l;
+ }
+ painter.setPen( fgColor );
+ painter.drawLine( 0, view.top()-2, view.width(), view.top()-2 );
+ }
+
+ painter.translate( 0, view.top() );
+ pDiffTextWindow->print( painter, view, line, linesPerPage );
+ painter.resetXForm();
+}
+
+void KDiff3App::slotFilePrint()
+{
+ if ( !m_pDiffTextWindow1 )
+ return;
+
+ KPrinter printer;
+
+ int firstSelectionD3LIdx = -1;
+ int lastSelectionD3LIdx = -1;
+ if ( m_pDiffTextWindow1 ) { m_pDiffTextWindow1->getSelectionRange(&firstSelectionD3LIdx, &lastSelectionD3LIdx, eD3LLineCoords); }
+ if ( firstSelectionD3LIdx<0 && m_pDiffTextWindow2 ) { m_pDiffTextWindow2->getSelectionRange(&firstSelectionD3LIdx, &lastSelectionD3LIdx, eD3LLineCoords); }
+ if ( firstSelectionD3LIdx<0 && m_pDiffTextWindow3 ) { m_pDiffTextWindow3->getSelectionRange(&firstSelectionD3LIdx, &lastSelectionD3LIdx, eD3LLineCoords); }
+#ifdef KREPLACEMENTS_H // Currently PrintSelection is not supported in KDEs print dialog.
+ if ( firstSelectionD3LIdx>=0 )
+ {
+ printer.setOptionEnabled(KPrinter::PrintSelection,true);
+ }
+#endif
+
+ printer.setPageSelection(KPrinter::ApplicationSide);
+ printer.setMinMax(1,10000);
+ printer.setCurrentPage(10000);
+
+ int currentFirstLine = m_pDiffTextWindow1->getFirstLine();
+ int currentFirstD3LIdx = m_pDiffTextWindow1->convertLineToDiff3LineIdx( currentFirstLine );
+
+ // do some printer initialization
+ printer.setFullPage( false );
+
+ // initialize the printer using the print dialog
+ if ( printer.setup( this ) )
+ {
+ slotStatusMsg( i18n( "Printing..." ) );
+ // create a painter to paint on the printer object
+ MyPainter painter( 0, m_pOptionDialog->m_bRightToLeftLanguage, width(), fontMetrics().width('W') );
+
+ // start painting
+ if( !painter.begin( &printer ) ) { // paint on printer
+ slotStatusMsg( i18n( "Printing aborted." ) );
+ return;
+ }
+ QPaintDeviceMetrics metrics( painter.device() );
+ int dpiy = metrics.logicalDpiY();
+ int columnDistance = (int) ( (0.5/2.54)*dpiy ); // 0.5 cm between the columns
+
+ int columns = m_bTripleDiff ? 3 : 2;
+ int columnWidth = ( metrics.width() - (columns-1)*columnDistance ) / columns;
+
+ QFont f = m_pOptionDialog->m_font;
+ f.setPointSizeFloat(f.pointSizeFloat()-1); // Print with slightly smaller font.
+ painter.setFont( f );
+ QFontMetrics fm = painter.fontMetrics();
+
+ QString topLineText = i18n("Top line");
+
+ //int headerWidth = fm.width( m_sd1.getAliasName() + ", "+topLineText+": 01234567" );
+ int headerLines = fm.width( m_sd1.getAliasName() + ", "+topLineText+": 01234567" )/columnWidth+1;
+
+ int headerMargin = headerLines * fm.height() + 3; // Text + one horizontal line
+ int footerMargin = fm.height() + 3;
+
+ QRect view ( 0, headerMargin, metrics.width(), metrics.height() - (headerMargin + footerMargin) );
+ QRect view1( 0*(columnWidth + columnDistance), view.top(), columnWidth, view.height() );
+ QRect view2( 1*(columnWidth + columnDistance), view.top(), columnWidth, view.height() );
+ QRect view3( 2*(columnWidth + columnDistance), view.top(), columnWidth, view.height() );
+
+ int linesPerPage = view.height() / fm.height();
+ int charactersPerLine = columnWidth / fm.width("W");
+ if ( m_pOptionDialog->m_bWordWrap )
+ {
+ // For printing the lines are wrapped differently (this invalidates the first line)
+ recalcWordWrap( charactersPerLine );
+ }
+
+ int totalNofLines = max2(m_pDiffTextWindow1->getNofLines(), m_pDiffTextWindow2->getNofLines());
+ if ( m_bTripleDiff && m_pDiffTextWindow3)
+ totalNofLines = max2(totalNofLines, m_pDiffTextWindow3->getNofLines());
+
+ QValueList<int> pageList = printer.pageList();
+
+ bool bPrintCurrentPage=false;
+ bool bFirstPrintedPage = false;
+
+ bool bPrintSelection = false;
+ int totalNofPages = (totalNofLines+linesPerPage-1) / linesPerPage;
+ int line=-1;
+ int selectionEndLine = -1;
+
+#ifdef KREPLACEMENTS_H
+ if ( printer.printRange()==KPrinter::AllPages )
+ {
+ pageList.clear();
+ for(int i=0; i<totalNofPages; ++i)
+ {
+ pageList.push_back(i+1);
+ }
+ }
+
+ if ( printer.printRange()==KPrinter::Selection )
+#else
+ if ( !pageList.empty() && pageList.front()==9999 )
+#endif
+ {
+ bPrintSelection = true;
+ if ( firstSelectionD3LIdx >=0 )
+ {
+ line = m_pDiffTextWindow1->convertDiff3LineIdxToLine( firstSelectionD3LIdx );
+ selectionEndLine = m_pDiffTextWindow1->convertDiff3LineIdxToLine( lastSelectionD3LIdx+1 );
+ totalNofPages = (selectionEndLine-line+linesPerPage-1) / linesPerPage;
+ }
+ }
+
+ int page = 1;
+
+ QValueList<int>::iterator pageListIt = pageList.begin();
+ for(;;)
+ {
+ if (!bPrintSelection)
+ {
+ if (pageListIt==pageList.end())
+ break;
+ page = *pageListIt;
+ line = (page - 1) * linesPerPage;
+ if (page==10000) // This means "Print the current page"
+ {
+ bPrintCurrentPage=true;
+ // Detect the first visible line in the window.
+ line = m_pDiffTextWindow1->convertDiff3LineIdxToLine( currentFirstD3LIdx );
+ }
+ }
+ else
+ {
+ if ( line>=selectionEndLine )
+ {
+ break;
+ }
+ else
+ {
+ if ( selectionEndLine-line < linesPerPage )
+ linesPerPage=selectionEndLine-line;
+ }
+ }
+ if (line>=0 && line<totalNofLines )
+ {
+
+ if (bFirstPrintedPage)
+ printer.newPage();
+
+ painter.setClipping(true);
+
+ painter.setPen( m_pOptionDialog->m_colorA );
+ QString headerText1 = m_sd1.getAliasName() + ", "+topLineText+": " + QString::number(m_pDiffTextWindow1->calcTopLineInFile(line)+1);
+ printDiffTextWindow( painter, view1, headerText1, m_pDiffTextWindow1, line, linesPerPage, m_pOptionDialog->m_fgColor );
+
+ painter.setPen( m_pOptionDialog->m_colorB );
+ QString headerText2 = m_sd2.getAliasName() + ", "+topLineText+": " + QString::number(m_pDiffTextWindow2->calcTopLineInFile(line)+1);
+ printDiffTextWindow( painter, view2, headerText2, m_pDiffTextWindow2, line, linesPerPage, m_pOptionDialog->m_fgColor );
+
+ if ( m_bTripleDiff && m_pDiffTextWindow3 )
+ {
+ painter.setPen( m_pOptionDialog->m_colorC );
+ QString headerText3 = m_sd3.getAliasName() + ", "+topLineText+": " + QString::number(m_pDiffTextWindow3->calcTopLineInFile(line)+1);
+ printDiffTextWindow( painter, view3, headerText3, m_pDiffTextWindow3, line, linesPerPage, m_pOptionDialog->m_fgColor );
+ }
+ painter.setClipping(false);
+
+ painter.setPen( m_pOptionDialog->m_fgColor );
+ painter.drawLine( 0, view.bottom()+3, view.width(), view.bottom()+3 );
+ QString s = bPrintCurrentPage ? QString("")
+ : QString::number( page ) + "/" + QString::number(totalNofPages);
+ if ( bPrintSelection ) s+=" (" + i18n("Selection") + ")";
+ painter.drawText( (view.right() - painter.fontMetrics().width( s ))/2,
+ view.bottom() + painter.fontMetrics().ascent() + 5, s );
+
+ bFirstPrintedPage = true;
+ }
+
+ if ( bPrintSelection )
+ {
+ line+=linesPerPage;
+ ++page;
+ }
+ else
+ {
+ ++pageListIt;
+ }
+ }
+
+ painter.end();
+
+ if ( m_pOptionDialog->m_bWordWrap )
+ {
+ recalcWordWrap();
+ m_pDiffVScrollBar->setValue( m_pDiffTextWindow1->convertDiff3LineIdxToLine( currentFirstD3LIdx ) );
+ }
+
+ slotStatusMsg( i18n( "Printing completed." ) );
+ }
+ else
+ {
+ slotStatusMsg( i18n( "Printing aborted." ) );
+ }
+}
+
+void KDiff3App::slotFileQuit()
+{
+ slotStatusMsg(i18n("Exiting..."));
+
+ if( !queryClose() )
+ return; // Don't quit
+
+ KApplication::exit( isFileSaved() ? 0 : 1 );
+}
+
+
+
+void KDiff3App::slotViewToolBar()
+{
+ slotStatusMsg(i18n("Toggling toolbar..."));
+ m_pOptionDialog->m_bShowToolBar = viewToolBar->isChecked();
+ ///////////////////////////////////////////////////////////////////
+ // turn Toolbar on or off
+ if ( toolBar("mainToolBar") !=0 )
+ {
+ if(!m_pOptionDialog->m_bShowToolBar)
+ {
+ toolBar("mainToolBar")->hide();
+ }
+ else
+ {
+ toolBar("mainToolBar")->show();
+ }
+ }
+
+ slotStatusMsg(i18n("Ready."));
+}
+
+void KDiff3App::slotViewStatusBar()
+{
+ slotStatusMsg(i18n("Toggle the statusbar..."));
+ m_pOptionDialog->m_bShowStatusBar = viewStatusBar->isChecked();
+ ///////////////////////////////////////////////////////////////////
+ //turn Statusbar on or off
+ if (statusBar() !=0 )
+ {
+ if(!viewStatusBar->isChecked())
+ {
+ statusBar()->hide();
+ }
+ else
+ {
+ statusBar()->show();
+ }
+ }
+
+ slotStatusMsg(i18n("Ready."));
+}
+
+
+void KDiff3App::slotStatusMsg(const QString &text)
+{
+ ///////////////////////////////////////////////////////////////////
+ // change status message permanently
+ if (statusBar() !=0 )
+ {
+ statusBar()->clear();
+ statusBar()->message( text );
+ }
+}
+
+
+
+
+#include "kdiff3.moc"