1 /*
2  * KDiff3 - Text Diff And Merge Tool
3  *
4  * SPDX-FileCopyrightText: 2002-2011 Joachim Eibl, joachim.eibl at gmx.de
5  * SPDX-FileCopyrightText: 2018-2020 Michael Reeves reeves.87@gmail.com
6  * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8 #include "optiondialog.h"
9 #include "OptionItems.h"
10 #include "ui_scroller.h"
11 
12 #include "common.h"
13 #include "defmac.h"
14 #include "smalldialogs.h"
15 
16 #include <map>
17 
18 #include <KColorButton>
19 #include <KHelpClient>
20 #include <KLocalizedString>
21 #include <KMessageBox>
22 #include <KToolBar>
23 
24 #include <QApplication>
25 #include <QCheckBox>
26 #include <QComboBox>
27 #include <QDialogButtonBox>
28 #include <QFontDatabase>
29 #include <QFontDialog>
30 #include <QFrame>
31 #include <QGridLayout>
32 #include <QGroupBox>
33 #include <QLabel>
34 #include <QLayout>
35 #include <QLineEdit>
36 #include <QPixmap>
37 #include <QPlainTextEdit>
38 #include <QPointer>
39 #include <QPushButton>
40 #include <QRadioButton>
41 #include <QTextCodec>
42 #include <QScrollArea>
43 
44 const QString OptionDialog::s_historyEntryStartRegExpToolTip = i18n("A version control history entry consists of several lines.\n"
45                                                 "Specify the regular expression to detect the first line (without the leading comment).\n"
46                                                 "Use parentheses to group the keys you want to use for sorting.\n"
47                                                 "If left empty, then KDiff3 assumes that empty lines separate history entries.\n"
48                                                 "See the documentation for details.");
49 const QString OptionDialog::s_historyEntryStartSortKeyOrderToolTip = i18n("Each pair of parentheses used in the regular expression for the history start entry\n"
50                                                       "groups a key that can be used for sorting.\n"
51                                                       "Specify the list of keys (that are numbered in order of occurrence\n"
52                                                       "starting with 1) using ',' as separator (e.g. \"4,5,6,1,2,3,7\").\n"
53                                                       "If left empty, then no sorting will be done.\n"
54                                                       "See the documentation for details.");
55 const QString OptionDialog::s_autoMergeRegExpToolTip = i18n("Regular expression for lines where KDiff3 should automatically choose one source.\n"
56                                         "When a line with a conflict matches the regular expression then\n"
57                                         "- if available - C, otherwise B will be chosen.");
58 const QString OptionDialog::s_historyStartRegExpToolTip = i18n("Regular expression for the start of the version control history entry.\n"
59                                            "Usually this line contains the \"$Log$\" keyword.\n"
60                                            "Default value: \".*\\$Log.*\\$.*\"");
61 
62 class OptionCheckBox : public QCheckBox, public OptionBool
63 {
64   public:
OptionCheckBox(const QString & text,bool bDefaultVal,const QString & saveName,bool * pbVar,QWidget * pParent)65     OptionCheckBox(const QString& text, bool bDefaultVal, const QString& saveName, bool* pbVar,
66                    QWidget* pParent)
67         : QCheckBox(text, pParent), OptionBool(pbVar, bDefaultVal, saveName)
68     {}
setToDefault()69     void setToDefault() override { setChecked(getDefault()); }
setToCurrent()70     void setToCurrent() override { setChecked(getCurrent()); }
71 
72     using OptionBool::apply;
apply()73     void apply() override { apply(isChecked()); }
74 
75   private:
76     Q_DISABLE_COPY(OptionCheckBox)
77 };
78 
79 class OptionRadioButton : public QRadioButton, public OptionBool
80 {
81   public:
OptionRadioButton(const QString & text,bool bDefaultVal,const QString & saveName,bool * pbVar,QWidget * pParent)82     OptionRadioButton(const QString& text, bool bDefaultVal, const QString& saveName, bool* pbVar,
83                       QWidget* pParent)
84         : QRadioButton(text, pParent), OptionBool(pbVar, bDefaultVal, saveName)
85     {}
setToDefault()86     void setToDefault() override { setChecked(getDefault()); }
setToCurrent()87     void setToCurrent() override { setChecked(getCurrent()); }
88 
89     using OptionBool::apply;
apply()90     void apply() override { apply(isChecked()); }
91 
92   private:
93     Q_DISABLE_COPY(OptionRadioButton)
94 };
95 
FontChooser(QWidget * pParent)96 FontChooser::FontChooser(QWidget* pParent)
97     : QGroupBox(pParent)
98 {
99     QVBoxLayout* pLayout = new QVBoxLayout(this);
100     m_pLabel = new QLabel(QString());
101     pLayout->addWidget(m_pLabel);
102 
103     QChar visualTab(0x2192);
104     QChar visualSpace((ushort)0xb7);
105     m_pExampleTextEdit = new QPlainTextEdit(i18n("The quick brown fox jumps over the river\n"
106                                                  "but the little red hen escapes with a shiver.\n"
107                                                  ":-)") +
108                                                 visualTab + visualSpace,
109                                             this);
110     m_pExampleTextEdit->setFont(m_font);
111     m_pExampleTextEdit->setReadOnly(true);
112     pLayout->addWidget(m_pExampleTextEdit);
113 
114     m_pSelectFont = new QPushButton(i18n("Change Font"));
115     m_pSelectFont->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
116     chk_connect(m_pSelectFont, &QPushButton::clicked, this, &FontChooser::slotSelectFont);
117     pLayout->addWidget(m_pSelectFont);
118     pLayout->setAlignment(m_pSelectFont, Qt::AlignRight);
119 }
120 
font()121 QFont FontChooser::font()
122 {
123     return m_font; //QFont("courier",10);
124 }
125 
setFont(const QFont & font,bool)126 void FontChooser::setFont(const QFont& font, bool)
127 {
128     m_font = font;
129     m_pExampleTextEdit->setFont(m_font);
130     m_pLabel->setText(i18n("Font: %1, %2, %3\n\nExample:", m_font.family(), m_font.styleName(), m_font.pointSize()));
131 
132     //update();
133 }
134 
slotSelectFont()135 void FontChooser::slotSelectFont()
136 {
137     bool bOk;
138     m_font = QFontDialog::getFont(&bOk, m_font);
139     m_pExampleTextEdit->setFont(m_font);
140     m_pLabel->setText(i18n("Font: %1, %2, %3\n\nExample:", m_font.family(), m_font.styleName(), m_font.pointSize()));
141 }
142 
143 class OptionFontChooser : public FontChooser, public OptionFont
144 {
145   public:
OptionFontChooser(const QFont & defaultVal,const QString & saveName,QFont * pVar,QWidget * pParent)146     OptionFontChooser(const QFont& defaultVal, const QString& saveName, QFont* pVar, QWidget* pParent) : FontChooser(pParent),
147                                                                                                                             OptionFont(pVar, defaultVal, saveName)
148     {}
149 
setToDefault()150     void setToDefault() override { setFont(getDefault(), false); }
setToCurrent()151     void setToCurrent() override { setFont(getCurrent(), false); }
152     using OptionFont::apply;
apply()153     void apply() override { apply(font()); }
154   private:
155     Q_DISABLE_COPY(OptionFontChooser)
156 };
157 
158 class OptionColorButton : public KColorButton, public OptionColor
159 {
160   public:
OptionColorButton(const QColor & defaultVal,const QString & saveName,QColor * pVar,QWidget * pParent)161     OptionColorButton(const QColor &defaultVal, const QString& saveName, QColor* pVar, QWidget* pParent)
162         : KColorButton(pParent), OptionColor(pVar, defaultVal, saveName)
163     {}
164 
setToDefault()165     void setToDefault() override { setColor(getDefault()); }
setToCurrent()166     void setToCurrent() override { setColor(getCurrent()); }
167     using OptionColor::apply;
apply()168     void apply() override { apply(color()); }
169 
170   private:
171     Q_DISABLE_COPY(OptionColorButton)
172 };
173 
174 class OptionLineEdit : public QComboBox, public OptionString
175 {
176   public:
OptionLineEdit(const QString & defaultVal,const QString & saveName,QString * pVar,QWidget * pParent)177     OptionLineEdit(const QString& defaultVal, const QString& saveName, QString* pVar,
178                    QWidget* pParent)
179         : QComboBox(pParent), OptionString(pVar, defaultVal, saveName)
180     {
181         setMinimumWidth(50);
182         setEditable(true);
183         m_list.push_back(defaultVal);
184         insertText();
185     }
setToDefault()186     void setToDefault() override
187     {
188         setEditText(getDefault());
189     }
setToCurrent()190     void setToCurrent() override
191     {
192         setEditText(getCurrent());
193     }
194 
195     using OptionString::apply;
apply()196     void apply() override
197     {
198         apply(currentText());
199         insertText();
200     }
write(ValueMap * config) const201     void write(ValueMap* config) const override
202     {
203         config->writeEntry(m_saveName, m_list);
204     }
read(ValueMap * config)205     void read(ValueMap* config) override
206     {
207         m_list = config->readEntry(m_saveName, QStringList(m_defaultVal));
208         if(!m_list.empty()) setCurrent(m_list.front());
209         clear();
210         insertItems(0, m_list);
211     }
212 
213   private:
insertText()214     void insertText()
215     { // Check if the text exists. If yes remove it and push it in as first element
216         QString current = currentText();
217         m_list.removeAll(current);
218         m_list.push_front(current);
219         clear();
220         if(m_list.size() > 10)
221             m_list.erase(m_list.begin() + 10, m_list.end());
222         insertItems(0, m_list);
223     }
224 
225     Q_DISABLE_COPY(OptionLineEdit)
226     QStringList m_list;
227 };
228 
229 class OptionIntEdit : public QLineEdit, public OptionNum<int>
230 {
231   public:
OptionIntEdit(int defaultVal,const QString & saveName,int * pVar,int rangeMin,int rangeMax,QWidget * pParent)232     OptionIntEdit(int defaultVal, const QString& saveName, int* pVar, int rangeMin, int rangeMax,
233                   QWidget* pParent)
234         : QLineEdit(pParent), OptionNum<int>(pVar, defaultVal, saveName)
235     {
236         QIntValidator* v = new QIntValidator(this);
237         v->setRange(rangeMin, rangeMax);
238         setValidator(v);
239     }
setToDefault()240     void setToDefault() override
241     {
242         //QString::setNum does not account for locale settings
243         setText(OptionNum::toString(getDefault()));
244     }
245 
setToCurrent()246     void setToCurrent() override
247     {
248         setText(getString());
249     }
250 
251     using OptionNum<int>::apply;
apply()252     void apply() override
253     {
254         const QIntValidator* v = static_cast<const QIntValidator*>(validator());
255         setCurrent( qBound(v->bottom(), text().toInt(), v->top()) );
256 
257         setText(getString());
258     }
259 
260   private:
261     Q_DISABLE_COPY(OptionIntEdit)
262 };
263 
264 class OptionComboBox : public QComboBox, public OptionItemBase
265 {
266   public:
OptionComboBox(int defaultVal,const QString & saveName,int * pVarNum,QWidget * pParent)267     OptionComboBox(int defaultVal, const QString& saveName, int* pVarNum,
268                    QWidget* pParent)
269         : QComboBox(pParent), OptionItemBase(saveName)
270     {
271         setMinimumWidth(50);
272         m_pVarNum = pVarNum;
273         m_pVarStr = nullptr;
274         m_defaultVal = defaultVal;
275         setEditable(false);
276     }
OptionComboBox(int defaultVal,const QString & saveName,QString * pVarStr,QWidget * pParent)277     OptionComboBox(int defaultVal, const QString& saveName, QString* pVarStr,
278                    QWidget* pParent)
279         : QComboBox(pParent), OptionItemBase(saveName)
280     {
281         m_pVarNum = nullptr;
282         m_pVarStr = pVarStr;
283         m_defaultVal = defaultVal;
284         setEditable(false);
285     }
setToDefault()286     void setToDefault() override
287     {
288         setCurrentIndex(m_defaultVal);
289         if(m_pVarStr != nullptr) {
290             *m_pVarStr = currentText();
291         }
292     }
setToCurrent()293     void setToCurrent() override
294     {
295         if(m_pVarNum != nullptr)
296             setCurrentIndex(*m_pVarNum);
297         else
298             setText(*m_pVarStr);
299     }
300     using OptionItemBase::apply;
apply()301     void apply() override
302     {
303         if(m_pVarNum != nullptr) {
304             *m_pVarNum = currentIndex();
305         }
306         else
307         {
308             *m_pVarStr = currentText();
309         }
310     }
write(ValueMap * config) const311     void write(ValueMap* config) const override
312     {
313         if(m_pVarStr != nullptr)
314             config->writeEntry(m_saveName, *m_pVarStr);
315         else
316             config->writeEntry(m_saveName, *m_pVarNum);
317     }
read(ValueMap * config)318     void read(ValueMap* config) override
319     {
320         if(m_pVarStr != nullptr)
321             setText(config->readEntry(m_saveName, currentText()));
322         else
323             *m_pVarNum = config->readEntry(m_saveName, *m_pVarNum);
324     }
preserve()325     void preserve() override
326     {
327         if(m_pVarStr != nullptr) {
328             m_preservedStrVal = *m_pVarStr;
329         }
330         else
331         {
332             m_preservedNumVal = *m_pVarNum;
333         }
334     }
unpreserve()335     void unpreserve() override
336     {
337         if(m_pVarStr != nullptr) {
338             *m_pVarStr = m_preservedStrVal;
339         }
340         else
341         {
342             *m_pVarNum = m_preservedNumVal;
343         }
344     }
345 
346   private:
347     Q_DISABLE_COPY(OptionComboBox)
348     int* m_pVarNum;
349     int m_preservedNumVal = 0;
350     QString* m_pVarStr;
351     QString m_preservedStrVal;
352     int m_defaultVal;
353 
setText(const QString & s)354     void setText(const QString& s)
355     {
356         // Find the string in the combobox-list, don't change the value if nothing fits.
357         for(int i = 0; i < count(); ++i)
358         {
359             if(itemText(i) == s)
360             {
361                 if(m_pVarNum != nullptr) *m_pVarNum = i;
362                 if(m_pVarStr != nullptr) *m_pVarStr = s;
363                 setCurrentIndex(i);
364                 return;
365             }
366         }
367     }
368 };
369 
370 class OptionEncodingComboBox : public QComboBox, public OptionCodec
371 {
372     Q_OBJECT
373     QVector<QTextCodec*> m_codecVec;
374     QTextCodec** m_ppVarCodec;
375 
376   public:
OptionEncodingComboBox(const QString & saveName,QTextCodec ** ppVarCodec,QWidget * pParent)377     OptionEncodingComboBox(const QString& saveName, QTextCodec** ppVarCodec,
378                            QWidget* pParent)
379         : QComboBox(pParent), OptionCodec(saveName)
380     {
381         m_ppVarCodec = ppVarCodec;
382         insertCodec(i18n("Unicode, 8 bit"), QTextCodec::codecForName("UTF-8"));
383         insertCodec(i18n("Unicode"), QTextCodec::codecForName("iso-10646-UCS-2"));
384         insertCodec(i18n("Latin1"), QTextCodec::codecForName("iso 8859-1"));
385 
386         // First sort codec names:
387         std::map<QString, QTextCodec*> names;
388         const QList<int> mibs = QTextCodec::availableMibs();
389         for(int i: mibs)
390         {
391             QTextCodec* c = QTextCodec::codecForMib(i);
392             if(c != nullptr)
393                 names[QString(QLatin1String(c->name())).toUpper()] = c;
394         }
395 
396         std::map<QString, QTextCodec*>::const_iterator it;
397         for(const auto& pair: names)
398         {
399             insertCodec("", pair.second);
400         }
401 
402         setToolTip(i18n(
403             "Change this if non-ASCII characters are not displayed correctly."));
404     }
insertCodec(const QString & visibleCodecName,QTextCodec * c)405     void insertCodec(const QString& visibleCodecName, QTextCodec* c)
406     {
407         if(c != nullptr)
408         {
409             const QByteArray nameArray = c->name();
410             const QLatin1String codecName = QLatin1String(nameArray);
411 
412             for(int i = 0; i < m_codecVec.size(); ++i)
413             {
414                 if(c == m_codecVec[i])
415                     return; // don't insert any codec twice
416             }
417 
418             // The m_codecVec.size will at this point return the value we need for the index.
419             if(codecName == defaultName())
420                 saveDefaultIndex(m_codecVec.size());
421             QString itemText = visibleCodecName.isEmpty() ? codecName : visibleCodecName + QLatin1String(" (") + codecName + QLatin1String(")");
422             addItem(itemText, m_codecVec.size());
423             m_codecVec.push_back(c);
424         }
425     }
setToDefault()426     void setToDefault() override
427     {
428         int index = getDefaultIndex();
429 
430         setCurrentIndex(index);
431         if(m_ppVarCodec != nullptr)
432         {
433             *m_ppVarCodec = m_codecVec[index];
434         }
435     }
setToCurrent()436     void setToCurrent() override
437     {
438         if(m_ppVarCodec != nullptr)
439         {
440             for(int i = 0; i < m_codecVec.size(); ++i)
441             {
442                 if(*m_ppVarCodec == m_codecVec[i])
443                 {
444                     setCurrentIndex(i);
445                     break;
446                 }
447             }
448         }
449     }
450     using OptionCodec::apply;
apply()451     void apply() override
452     {
453         if(m_ppVarCodec != nullptr)
454         {
455             *m_ppVarCodec = m_codecVec[currentIndex()];
456         }
457     }
write(ValueMap * config) const458     void write(ValueMap* config) const override
459     {
460         if(m_ppVarCodec != nullptr) config->writeEntry(m_saveName, (const char*)(*m_ppVarCodec)->name());
461     }
read(ValueMap * config)462     void read(ValueMap* config) override
463     {
464         QString codecName = config->readEntry(m_saveName, (const char*)m_codecVec[currentIndex()]->name());
465         for(int i = 0; i < m_codecVec.size(); ++i)
466         {
467             if(codecName == QLatin1String(m_codecVec[i]->name()))
468             {
469                 setCurrentIndex(i);
470                 if(m_ppVarCodec != nullptr) *m_ppVarCodec = m_codecVec[i];
471                 break;
472             }
473         }
474     }
475 
476   protected:
preserve()477     void preserve() override { m_preservedVal = currentIndex(); }
unpreserve()478     void unpreserve() override { setCurrentIndex(m_preservedVal); }
479     int m_preservedVal;
480 };
481 
addOptionItem(OptionItemBase * p)482 void OptionDialog::addOptionItem(OptionItemBase* p)
483 {
484     m_options->addOptionItem(p);
485 }
486 
OptionDialog(bool bShowDirMergeSettings,QWidget * parent)487 OptionDialog::OptionDialog(bool bShowDirMergeSettings, QWidget* parent) : KPageDialog(parent)
488 {
489     setFaceType(List);
490     setWindowTitle(i18n("Configure"));
491     setStandardButtons(QDialogButtonBox::Help | QDialogButtonBox::RestoreDefaults | QDialogButtonBox::Apply | QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
492 
493     setModal(true);
494     setMinimumSize(600, 500);
495 
496     //showButtonSeparator( true );
497     //setHelp( "kdiff3/index.html", QString::null );
498 
499     m_options->init();
500     setupFontPage();
501     setupColorPage();
502     setupEditPage();
503     setupDiffPage();
504     setupMergePage();
505     setupOtherOptions();
506     if(bShowDirMergeSettings)
507         setupDirectoryMergePage();
508 
509     setupRegionalPage();
510     setupIntegrationPage();
511 
512     // Initialize all values in the dialog
513     resetToDefaults();
514     slotApply();
515     chk_connect(button(QDialogButtonBox::Apply), &QPushButton::clicked, this, &OptionDialog::slotApply);
516     chk_connect(button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &OptionDialog::slotOk);
517     chk_connect(button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked, this, &OptionDialog::slotDefault);
518     chk_connect(button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &QDialog::reject);
519     chk_connect(button(QDialogButtonBox::Help), &QPushButton::clicked, this, &OptionDialog::helpRequested);
520 }
521 
helpRequested()522 void OptionDialog::helpRequested()
523 {
524     KHelpClient::invokeHelp(QStringLiteral("kdiff3/index.html"));
525 }
526 
527 OptionDialog::~OptionDialog() = default;
528 
setupOtherOptions()529 void OptionDialog::setupOtherOptions()
530 {
531     //TODO move to Options class
532     addOptionItem(new OptionToggleAction(false, "AutoAdvance", &m_options->m_bAutoAdvance));
533     addOptionItem(new OptionToggleAction(true, "ShowWhiteSpaceCharacters", &m_options->m_bShowWhiteSpaceCharacters));
534     addOptionItem(new OptionToggleAction(true, "ShowWhiteSpace", &m_options->m_bShowWhiteSpace));
535     addOptionItem(new OptionToggleAction(false, "ShowLineNumbers", &m_options->m_bShowLineNumbers));
536     addOptionItem(new OptionToggleAction(true, "HorizDiffWindowSplitting", &m_options->m_bHorizDiffWindowSplitting));
537     addOptionItem(new OptionToggleAction(false, "WordWrap", &m_options->m_bWordWrap));
538 
539     addOptionItem(new OptionToggleAction(true, "ShowIdenticalFiles", &m_options->m_bDmShowIdenticalFiles));
540 
541     addOptionItem(new OptionStringList(&m_options->m_recentAFiles, "RecentAFiles"));
542     addOptionItem(new OptionStringList(&m_options->m_recentBFiles, "RecentBFiles"));
543     addOptionItem(new OptionStringList(&m_options->m_recentCFiles, "RecentCFiles"));
544     addOptionItem(new OptionStringList(&m_options->m_recentOutputFiles, "RecentOutputFiles"));
545     addOptionItem(new OptionStringList(&m_options->m_recentEncodings, "RecentEncodings"));
546 }
547 
setupFontPage()548 void OptionDialog::setupFontPage()
549 {
550     QFrame* page = new QFrame();
551     KPageWidgetItem* pageItem = new KPageWidgetItem(page, i18n("Font"));
552 
553     pageItem->setHeader(i18n("Editor & Diff Output Font"));
554     //not all themes have this icon
555     if(QIcon::hasThemeIcon(QStringLiteral("font-select-symbolic")))
556         pageItem->setIcon(QIcon::fromTheme(QStringLiteral("font-select-symbolic")));
557     else
558         pageItem->setIcon(QIcon::fromTheme(QStringLiteral("preferences-desktop-font")));
559     addPage(pageItem);
560 
561     QVBoxLayout* topLayout = new QVBoxLayout(page);
562     topLayout->setContentsMargins(5, 5, 5, 5);
563 
564     //requires QT 5.2 or later.
565     static const QFont defaultFont = QFontDatabase::systemFont(QFontDatabase::FixedFont);
566     static QFont defaultAppFont = QApplication::font();
567 
568     OptionFontChooser* pAppFontChooser = new OptionFontChooser(defaultAppFont, "ApplicationFont", &m_options->m_appFont, page);
569     addOptionItem(pAppFontChooser);
570     topLayout->addWidget(pAppFontChooser);
571     pAppFontChooser->setTitle(i18n("Application font"));
572 
573     OptionFontChooser* pFontChooser = new OptionFontChooser(defaultFont, "Font", &m_options->m_font, page);
574     addOptionItem(pFontChooser);
575     topLayout->addWidget(pFontChooser);
576     pFontChooser->setTitle(i18n("File view font"));
577 
578     QGridLayout* gbox = new QGridLayout();
579     topLayout->addLayout(gbox);
580     //int line=0;
581 
582     // This currently does not work (see rendering in class DiffTextWindow)
583     //OptionCheckBox* pItalicDeltas = new OptionCheckBox( i18n("Italic font for deltas"), false, "ItalicForDeltas", &m_options->m_bItalicForDeltas, page, this );
584     //addOptionItem(pItalicDeltas);
585     //gbox->addWidget( pItalicDeltas, line, 0, 1, 2 );
586     //pItalicDeltas->setToolTip( i18n(
587     //   "Selects the italic version of the font for differences.\n"
588     //   "If the font doesn't support italic characters, then this does nothing.")
589     //   );
590 }
591 
setupColorPage()592 void OptionDialog::setupColorPage()
593 {
594     QScrollArea* pageFrame = new QScrollArea();
595     KPageWidgetItem* pageItem = new KPageWidgetItem(pageFrame, i18nc("Title for color settings page","Color"));
596     pageItem->setHeader(i18n("Colors Settings"));
597     pageItem->setIcon(QIcon::fromTheme(QStringLiteral("colormanagement")));
598     addPage(pageItem);
599 
600     QVBoxLayout* scrollLayout = new QVBoxLayout();
601     scrollLayout->setContentsMargins(2, 2, 2, 2);
602     scrollLayout->addWidget(pageFrame);
603 
604     QScopedPointer<Ui::ScrollArea> scrollArea(new Ui::ScrollArea());
605     scrollArea->setupUi(pageFrame);
606 
607     QWidget* page = pageFrame->findChild<QWidget*>("contents");
608     QVBoxLayout* topLayout = new QVBoxLayout(page);
609     topLayout->setContentsMargins(5, 5, 5, 5);
610 
611     QGridLayout* gbox = new QGridLayout();
612     gbox->setColumnStretch(1, 5);
613     topLayout->addLayout(gbox);
614 
615     QLabel* label;
616     int line = 0;
617 
618     int depth = QPixmap::defaultDepth();
619     bool bLowColor = depth <= 8;
620 
621     label = new QLabel(i18n("Editor and Diff Views:"), page);
622     gbox->addWidget(label, line, 0);
623     QFont f(label->font());
624     f.setBold(true);
625     label->setFont(f);
626     ++line;
627 
628     OptionColorButton* pFgColor = new OptionColorButton(Qt::black, "FgColor", &m_options->m_fgColor, page);
629     label = new QLabel(i18n("Foreground color:"), page);
630     label->setBuddy(pFgColor);
631     addOptionItem(pFgColor);
632     gbox->addWidget(label, line, 0);
633     gbox->addWidget(pFgColor, line, 1);
634     ++line;
635 
636     OptionColorButton* pBgColor = new OptionColorButton(Qt::white, "BgColor", &m_options->m_bgColor, page);
637     label = new QLabel(i18n("Background color:"), page);
638     label->setBuddy(pBgColor);
639     addOptionItem(pBgColor);
640     gbox->addWidget(label, line, 0);
641     gbox->addWidget(pBgColor, line, 1);
642 
643     ++line;
644 
645     OptionColorButton* pDiffBgColor = new OptionColorButton(
646         bLowColor ? QColor(Qt::lightGray) : qRgb(224, 224, 224), "DiffBgColor", &m_options->m_diffBgColor, page);
647     label = new QLabel(i18n("Diff background color:"), page);
648     label->setBuddy(pDiffBgColor);
649     addOptionItem(pDiffBgColor);
650     gbox->addWidget(label, line, 0);
651     gbox->addWidget(pDiffBgColor, line, 1);
652     ++line;
653 
654     OptionColorButton* pColorA = new OptionColorButton(
655         bLowColor ? qRgb(0, 0, 255) : qRgb(0, 0, 200) /*blue*/, "ColorA", &m_options->m_colorA, page);
656     label = new QLabel(i18n("Color A:"), page);
657     label->setBuddy(pColorA);
658     addOptionItem(pColorA);
659     gbox->addWidget(label, line, 0);
660     gbox->addWidget(pColorA, line, 1);
661     ++line;
662 
663     OptionColorButton* pColorB = new OptionColorButton(
664         bLowColor ? qRgb(0, 128, 0) : qRgb(0, 150, 0) /*green*/, "ColorB", &m_options->m_colorB, page);
665     label = new QLabel(i18n("Color B:"), page);
666     label->setBuddy(pColorB);
667     addOptionItem(pColorB);
668     gbox->addWidget(label, line, 0);
669     gbox->addWidget(pColorB, line, 1);
670     ++line;
671 
672     OptionColorButton* pColorC = new OptionColorButton(
673         bLowColor ? qRgb(128, 0, 128) : qRgb(150, 0, 150) /*magenta*/, "ColorC", &m_options->m_colorC, page);
674     label = new QLabel(i18n("Color C:"), page);
675     label->setBuddy(pColorC);
676     addOptionItem(pColorC);
677     gbox->addWidget(label, line, 0);
678     gbox->addWidget(pColorC, line, 1);
679     ++line;
680 
681     OptionColorButton* pColorForConflict = new OptionColorButton(Qt::red, "ColorForConflict", &m_options->m_colorForConflict, page);
682     label = new QLabel(i18n("Conflict color:"), page);
683     label->setBuddy(pColorForConflict);
684     addOptionItem(pColorForConflict);
685     gbox->addWidget(label, line, 0);
686     gbox->addWidget(pColorForConflict, line, 1);
687     ++line;
688 
689     OptionColorButton* pColor = new OptionColorButton(
690         bLowColor ? qRgb(192, 192, 192) : qRgb(220, 220, 100), "CurrentRangeBgColor", &m_options->m_currentRangeBgColor, page);
691     label = new QLabel(i18n("Current range background color:"), page);
692     label->setBuddy(pColor);
693     addOptionItem(pColor);
694     gbox->addWidget(label, line, 0);
695     gbox->addWidget(pColor, line, 1);
696     ++line;
697 
698     pColor = new OptionColorButton(
699         bLowColor ? qRgb(255, 255, 0) : qRgb(255, 255, 150), "CurrentRangeDiffBgColor", &m_options->m_currentRangeDiffBgColor, page);
700     label = new QLabel(i18n("Current range diff background color:"), page);
701     label->setBuddy(pColor);
702     addOptionItem(pColor);
703     gbox->addWidget(label, line, 0);
704     gbox->addWidget(pColor, line, 1);
705     ++line;
706 
707     pColor = new OptionColorButton(qRgb(0xff, 0xd0, 0x80), "ManualAlignmentRangeColor", &m_options->m_manualHelpRangeColor, page);
708     label = new QLabel(i18n("Color for manually aligned difference ranges:"), page);
709     label->setBuddy(pColor);
710     addOptionItem(pColor);
711     gbox->addWidget(label, line, 0);
712     gbox->addWidget(pColor, line, 1);
713     ++line;
714 
715     label = new QLabel(i18n("Folder Comparison View:"), page);
716     gbox->addWidget(label, line, 0);
717     label->setFont(f);
718     ++line;
719 
720     pColor = new OptionColorButton(qRgb(0, 0xd0, 0), "NewestFileColor", &m_options->m_newestFileColor, page);
721     label = new QLabel(i18n("Newest file color:"), page);
722     label->setBuddy(pColor);
723     addOptionItem(pColor);
724     gbox->addWidget(label, line, 0);
725     gbox->addWidget(pColor, line, 1);
726     QString dirColorTip = i18n("Changing this color will only be effective when starting the next folder comparison.");
727     label->setToolTip(dirColorTip);
728     ++line;
729 
730     pColor = new OptionColorButton(qRgb(0xf0, 0, 0), "OldestFileColor", &m_options->m_oldestFileColor, page);
731     label = new QLabel(i18n("Oldest file color:"), page);
732     label->setBuddy(pColor);
733     addOptionItem(pColor);
734     gbox->addWidget(label, line, 0);
735     gbox->addWidget(pColor, line, 1);
736     label->setToolTip(dirColorTip);
737     ++line;
738 
739     pColor = new OptionColorButton(qRgb(0xc0, 0xc0, 0), "MidAgeFileColor", &m_options->m_midAgeFileColor, page);
740     label = new QLabel(i18n("Middle age file color:"), page);
741     label->setBuddy(pColor);
742     addOptionItem(pColor);
743     gbox->addWidget(label, line, 0);
744     gbox->addWidget(pColor, line, 1);
745     label->setToolTip(dirColorTip);
746     ++line;
747 
748     pColor = new OptionColorButton(qRgb(0, 0, 0), "MissingFileColor", &m_options->m_missingFileColor, page);
749     label = new QLabel(i18n("Color for missing files:"), page);
750     label->setBuddy(pColor);
751     addOptionItem(pColor);
752     gbox->addWidget(label, line, 0);
753     gbox->addWidget(pColor, line, 1);
754     label->setToolTip(dirColorTip);
755     ++line;
756 
757     topLayout->addStretch(10);
758 }
759 
setupEditPage()760 void OptionDialog::setupEditPage()
761 {
762     QScrollArea* pageFrame = new QScrollArea();
763     KPageWidgetItem* pageItem = new KPageWidgetItem(pageFrame, i18n("Editor"));
764     pageItem->setHeader(i18n("Editor Behavior"));
765     pageItem->setIcon(QIcon::fromTheme(QStringLiteral("accessories-text-editor")));
766     addPage(pageItem);
767 
768     QVBoxLayout* scrollLayout = new QVBoxLayout();
769     scrollLayout->setContentsMargins(2, 2, 2, 2);
770     scrollLayout->addWidget(pageFrame);
771 
772     QScopedPointer<Ui::ScrollArea> scrollArea(new Ui::ScrollArea());
773     scrollArea->setupUi(pageFrame);
774 
775     QWidget* page = pageFrame->findChild<QWidget*>("contents");
776 
777     QVBoxLayout* topLayout = new QVBoxLayout(page);
778     topLayout->setContentsMargins(5, 5, 5, 5);
779 
780     QGridLayout* gbox = new QGridLayout();
781     gbox->setColumnStretch(1, 5);
782     topLayout->addLayout(gbox);
783     QLabel* label;
784     int line = 0;
785 
786     OptionCheckBox* pReplaceTabs = new OptionCheckBox(i18n("Tab inserts spaces"), false, "ReplaceTabs", &m_options->m_bReplaceTabs, page);
787     addOptionItem(pReplaceTabs);
788     gbox->addWidget(pReplaceTabs, line, 0, 1, 2);
789     pReplaceTabs->setToolTip(i18n(
790         "On: Pressing tab generates the appropriate number of spaces.\n"
791         "Off: A tab character will be inserted."));
792     ++line;
793 
794     OptionIntEdit* pTabSize = new OptionIntEdit(8, "TabSize", &m_options->m_tabSize, 1, 100, page);
795     label = new QLabel(i18n("Tab size:"), page);
796     label->setBuddy(pTabSize);
797     addOptionItem(pTabSize);
798     gbox->addWidget(label, line, 0);
799     gbox->addWidget(pTabSize, line, 1);
800     ++line;
801 
802     OptionCheckBox* pAutoIndentation = new OptionCheckBox(i18n("Auto indentation"), true, "AutoIndentation", &m_options->m_bAutoIndentation, page);
803     gbox->addWidget(pAutoIndentation, line, 0, 1, 2);
804     addOptionItem(pAutoIndentation);
805     pAutoIndentation->setToolTip(i18n(
806         "On: The indentation of the previous line is used for a new line.\n"));
807     ++line;
808 
809     OptionCheckBox* pAutoCopySelection = new OptionCheckBox(i18n("Auto copy selection"), false, "AutoCopySelection", &m_options->m_bAutoCopySelection, page);
810     gbox->addWidget(pAutoCopySelection, line, 0, 1, 2);
811     addOptionItem(pAutoCopySelection);
812     pAutoCopySelection->setToolTip(i18n(
813         "On: Any selection is immediately written to the clipboard.\n"
814         "Off: You must explicitly copy e.g. via Ctrl-C."));
815     ++line;
816 
817     label = new QLabel(i18n("Line end style:"), page);
818     gbox->addWidget(label, line, 0);
819 
820     OptionComboBox* pLineEndStyle = new OptionComboBox(eLineEndStyleAutoDetect, "LineEndStyle", (int*)&m_options->m_lineEndStyle, page);
821     gbox->addWidget(pLineEndStyle, line, 1);
822     addOptionItem(pLineEndStyle);
823     pLineEndStyle->insertItem(eLineEndStyleUnix, i18nc("Unix line ending", "Unix"));
824     pLineEndStyle->insertItem(eLineEndStyleDos, i18nc("Dos/Windows line ending", "Dos/Windows"));
825     pLineEndStyle->insertItem(eLineEndStyleAutoDetect, i18nc("Automatically detected line ending", "Autodetect"));
826 
827     label->setToolTip(i18n(
828         "Sets the line endings for when an edited file is saved.\n"
829         "DOS/Windows: CR+LF; UNIX: LF; with CR=0D, LF=0A"));
830     ++line;
831 
832     topLayout->addStretch(10);
833 }
834 
setupDiffPage()835 void OptionDialog::setupDiffPage()
836 {
837     QScrollArea* pageFrame = new QScrollArea();
838     KPageWidgetItem* pageItem = new KPageWidgetItem(pageFrame, i18n("Diff"));
839     pageItem->setHeader(i18n("Diff Settings"));
840     pageItem->setIcon(QIcon::fromTheme(QStringLiteral("text-x-patch")));
841     addPage(pageItem);
842 
843     QVBoxLayout* scrollLayout = new QVBoxLayout();
844     scrollLayout->setContentsMargins(2, 2, 2, 2);
845     scrollLayout->addWidget(pageFrame);
846 
847     QScopedPointer<Ui::ScrollArea> scrollArea(new Ui::ScrollArea());
848     scrollArea->setupUi(pageFrame);
849 
850     QWidget* page = pageFrame->findChild<QWidget*>("contents");
851 
852     QVBoxLayout* topLayout = new QVBoxLayout(page);
853     topLayout->setContentsMargins(5, 5, 5, 5);
854 
855     QGridLayout* gbox = new QGridLayout();
856     gbox->setColumnStretch(1, 5);
857     topLayout->addLayout(gbox);
858     int line = 0;
859 
860     QLabel* label = nullptr;
861 
862     m_options->m_bPreserveCarriageReturn = false;
863     /*
864     OptionCheckBox* pPreserveCarriageReturn = new OptionCheckBox( i18n("Preserve carriage return"), false, "PreserveCarriageReturn", &m_options->m_bPreserveCarriageReturn, page, this );
865     addOptionItem(pPreserveCarriageReturn);
866     gbox->addWidget( pPreserveCarriageReturn, line, 0, 1, 2 );
867     pPreserveCarriageReturn->setToolTip( i18n(
868        "Show carriage return characters '\\r' if they exist.\n"
869        "Helps to compare files that were modified under different operating systems.")
870        );
871     ++line;
872 */
873     OptionCheckBox* pIgnoreNumbers = new OptionCheckBox(i18n("Ignore numbers (treat as white space)"), false, "IgnoreNumbers", &m_options->m_bIgnoreNumbers, page);
874     gbox->addWidget(pIgnoreNumbers, line, 0, 1, 2);
875     addOptionItem(pIgnoreNumbers);
876     pIgnoreNumbers->setToolTip(i18n(
877         "Ignore number characters during line matching phase. (Similar to Ignore white space.)\n"
878         "Might help to compare files with numeric data."));
879     ++line;
880 
881     OptionCheckBox* pIgnoreComments = new OptionCheckBox(i18n("Ignore C/C++ comments (treat as white space)"), false, "IgnoreComments", &m_options->m_bIgnoreComments, page);
882     gbox->addWidget(pIgnoreComments, line, 0, 1, 2);
883     addOptionItem(pIgnoreComments);
884     pIgnoreComments->setToolTip(i18n("Treat C/C++ comments like white space."));
885     ++line;
886 
887     OptionCheckBox* pIgnoreCase = new OptionCheckBox(i18n("Ignore case (treat as white space)"), false, "IgnoreCase", &m_options->m_bIgnoreCase, page);
888     gbox->addWidget(pIgnoreCase, line, 0, 1, 2);
889     addOptionItem(pIgnoreCase);
890     pIgnoreCase->setToolTip(i18n(
891         "Treat case differences like white space changes. ('a'<=>'A')"));
892     ++line;
893 
894     label = new QLabel(i18n("Preprocessor command:"), page);
895     gbox->addWidget(label, line, 0);
896     OptionLineEdit* pLE = new OptionLineEdit("", "PreProcessorCmd", &m_options->m_PreProcessorCmd, page);
897     gbox->addWidget(pLE, line, 1);
898     addOptionItem(pLE);
899     label->setToolTip(i18n("User defined pre-processing. (See the docs for details.)"));
900     ++line;
901 
902     label = new QLabel(i18n("Line-matching preprocessor command:"), page);
903     gbox->addWidget(label, line, 0);
904     pLE = new OptionLineEdit("", "LineMatchingPreProcessorCmd", &m_options->m_LineMatchingPreProcessorCmd, page);
905     gbox->addWidget(pLE, line, 1);
906     addOptionItem(pLE);
907     label->setToolTip(i18n("This pre-processor is only used during line matching.\n(See the docs for details.)"));
908     ++line;
909 
910     OptionCheckBox* pTryHard = new OptionCheckBox(i18n("Try hard (slower)"), true, "TryHard", &m_options->m_bTryHard, page);
911     gbox->addWidget(pTryHard, line, 0, 1, 2);
912     addOptionItem(pTryHard);
913     pTryHard->setToolTip(i18n(
914         "Enables the --minimal option for the external diff.\n"
915         "The analysis of big files will be much slower."));
916     ++line;
917 
918     OptionCheckBox* pDiff3AlignBC = new OptionCheckBox(i18n("Align B and C for 3 input files"), false, "Diff3AlignBC", &m_options->m_bDiff3AlignBC, page);
919     gbox->addWidget(pDiff3AlignBC, line, 0, 1, 2);
920     addOptionItem(pDiff3AlignBC);
921     pDiff3AlignBC->setToolTip(i18n(
922         "Try to align B and C when comparing or merging three input files.\n"
923         "Not recommended for merging because merge might get more complicated.\n"
924         "(Default is off.)"));
925     ++line;
926 
927     topLayout->addStretch(10);
928 }
929 
setupMergePage()930 void OptionDialog::setupMergePage()
931 {
932     QScrollArea* pageFrame = new QScrollArea();
933     KPageWidgetItem* pageItem = new KPageWidgetItem(pageFrame, i18nc("Settings page", "Merge"));
934     pageItem->setHeader(i18n("Merge Settings"));
935     pageItem->setIcon(QIcon::fromTheme(QStringLiteral("merge")));
936     addPage(pageItem);
937 
938     QVBoxLayout* scrollLayout = new QVBoxLayout();
939     scrollLayout->setContentsMargins(2, 2, 2, 2);
940     scrollLayout->addWidget(pageFrame);
941 
942     QScopedPointer<Ui::ScrollArea> scrollArea(new Ui::ScrollArea());
943     scrollArea->setupUi(pageFrame);
944 
945     QWidget* page = pageFrame->findChild<QWidget*>("contents");
946 
947     QVBoxLayout* topLayout = new QVBoxLayout(page);
948     topLayout->setContentsMargins(5, 5, 5, 5);
949 
950     QGridLayout* gbox = new QGridLayout();
951     gbox->setColumnStretch(1, 5);
952     topLayout->addLayout(gbox);
953     int line = 0;
954 
955     QLabel* label = nullptr;
956 
957     label = new QLabel(i18n("Auto advance delay (ms):"), page);
958     gbox->addWidget(label, line, 0);
959     OptionIntEdit* pAutoAdvanceDelay = new OptionIntEdit(500, "AutoAdvanceDelay", &m_options->m_autoAdvanceDelay, 0, 2000, page);
960     gbox->addWidget(pAutoAdvanceDelay, line, 1);
961     addOptionItem(pAutoAdvanceDelay);
962     label->setToolTip(i18n(
963         "When in Auto-Advance mode the result of the current selection is shown \n"
964         "for the specified time, before jumping to the next conflict. Range: 0-2000 ms"));
965     ++line;
966 
967     OptionCheckBox* pShowInfoDialogs = new OptionCheckBox(i18n("Show info dialogs"), true, "ShowInfoDialogs", &m_options->m_bShowInfoDialogs, page);
968     gbox->addWidget(pShowInfoDialogs, line, 0, 1, 2);
969     addOptionItem(pShowInfoDialogs);
970     pShowInfoDialogs->setToolTip(i18n("Show a dialog with information about the number of conflicts."));
971     ++line;
972 
973     label = new QLabel(i18n("White space 2-file merge default:"), page);
974     gbox->addWidget(label, line, 0);
975     OptionComboBox* pWhiteSpace2FileMergeDefault = new OptionComboBox(0, "WhiteSpace2FileMergeDefault", &m_options->m_whiteSpace2FileMergeDefault, page);
976     gbox->addWidget(pWhiteSpace2FileMergeDefault, line, 1);
977     addOptionItem(pWhiteSpace2FileMergeDefault);
978     pWhiteSpace2FileMergeDefault->insertItem(0, i18n("Manual Choice"));
979     pWhiteSpace2FileMergeDefault->insertItem(1, i18n("A"));
980     pWhiteSpace2FileMergeDefault->insertItem(2, i18n("B"));
981     label->setToolTip(i18n(
982         "Allow the merge algorithm to automatically select an input for "
983         "white-space-only changes."));
984     ++line;
985 
986     label = new QLabel(i18n("White space 3-file merge default:"), page);
987     gbox->addWidget(label, line, 0);
988     OptionComboBox* pWhiteSpace3FileMergeDefault = new OptionComboBox(0, "WhiteSpace3FileMergeDefault", &m_options->m_whiteSpace3FileMergeDefault, page);
989     gbox->addWidget(pWhiteSpace3FileMergeDefault, line, 1);
990     addOptionItem(pWhiteSpace3FileMergeDefault);
991     pWhiteSpace3FileMergeDefault->insertItem(0, i18n("Manual Choice"));
992     pWhiteSpace3FileMergeDefault->insertItem(1, i18n("A"));
993     pWhiteSpace3FileMergeDefault->insertItem(2, i18n("B"));
994     pWhiteSpace3FileMergeDefault->insertItem(3, i18n("C"));
995     label->setToolTip(i18n(
996         "Allow the merge algorithm to automatically select an input for "
997         "white-space-only changes."));
998     ++line;
999 
1000     QGroupBox* pGroupBox = new QGroupBox(i18n("Automatic Merge Regular Expression"));
1001     gbox->addWidget(pGroupBox, line, 0, 1, 2);
1002     ++line;
1003     {
1004         gbox = new QGridLayout(pGroupBox);
1005         gbox->setColumnStretch(1, 10);
1006         line = 0;
1007 
1008         label = new QLabel(i18n("Auto merge regular expression:"), page);
1009         gbox->addWidget(label, line, 0);
1010         m_pAutoMergeRegExpLineEdit = new OptionLineEdit(".*\\$(Version|Header|Date|Author).*\\$.*", "AutoMergeRegExp", &m_options->m_autoMergeRegExp, page);
1011         gbox->addWidget(m_pAutoMergeRegExpLineEdit, line, 1);
1012         addOptionItem(m_pAutoMergeRegExpLineEdit);
1013         label->setToolTip(s_autoMergeRegExpToolTip);
1014         ++line;
1015 
1016         OptionCheckBox* pAutoMergeRegExp = new OptionCheckBox(i18n("Run regular expression auto merge on merge start"), false, "RunRegExpAutoMergeOnMergeStart", &m_options->m_bRunRegExpAutoMergeOnMergeStart, page);
1017         addOptionItem(pAutoMergeRegExp);
1018         gbox->addWidget(pAutoMergeRegExp, line, 0, 1, 2);
1019         pAutoMergeRegExp->setToolTip(i18n("Run the merge for auto merge regular expressions\n"
1020                                           "immediately when a merge starts.\n"));
1021         ++line;
1022     }
1023 
1024     pGroupBox = new QGroupBox(i18n("Version Control History Merging"));
1025     gbox->addWidget(pGroupBox, line, 0, 1, 2);
1026     ++line;
1027     {
1028         gbox = new QGridLayout(pGroupBox);
1029         gbox->setColumnStretch(1, 10);
1030         line = 0;
1031 
1032         label = new QLabel(i18n("History start regular expression:"), page);
1033         gbox->addWidget(label, line, 0);
1034         m_pHistoryStartRegExpLineEdit = new OptionLineEdit(".*\\$Log.*\\$.*", "HistoryStartRegExp", &m_options->m_historyStartRegExp, page);
1035         gbox->addWidget(m_pHistoryStartRegExpLineEdit, line, 1);
1036         addOptionItem(m_pHistoryStartRegExpLineEdit);
1037         label->setToolTip(s_historyStartRegExpToolTip);
1038         ++line;
1039 
1040         label = new QLabel(i18n("History entry start regular expression:"), page);
1041         gbox->addWidget(label, line, 0);
1042         // Example line:  "** \main\rolle_fsp_dev_008\1   17 Aug 2001 10:45:44   rolle"
1043         QString historyEntryStartDefault =
1044             "\\s*\\\\main\\\\(\\S+)\\s+"                         // Start with  "\main\"
1045             "([0-9]+) "                                          // day
1046             "(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) " //month
1047             "([0-9][0-9][0-9][0-9]) "                            // year
1048             "([0-9][0-9]:[0-9][0-9]:[0-9][0-9])\\s+(.*)";        // time, name
1049 
1050         m_pHistoryEntryStartRegExpLineEdit = new OptionLineEdit(historyEntryStartDefault, "HistoryEntryStartRegExp", &m_options->m_historyEntryStartRegExp, page);
1051         gbox->addWidget(m_pHistoryEntryStartRegExpLineEdit, line, 1);
1052         addOptionItem(m_pHistoryEntryStartRegExpLineEdit);
1053         label->setToolTip(s_historyEntryStartRegExpToolTip);
1054         ++line;
1055 
1056         m_pHistoryMergeSorting = new OptionCheckBox(i18n("History merge sorting"), false, "HistoryMergeSorting", &m_options->m_bHistoryMergeSorting, page);
1057         gbox->addWidget(m_pHistoryMergeSorting, line, 0, 1, 2);
1058         addOptionItem(m_pHistoryMergeSorting);
1059         m_pHistoryMergeSorting->setToolTip(i18n("Sort version control history by a key."));
1060         ++line;
1061         //QString branch = newHistoryEntry.cap(1);
1062         //int day    = newHistoryEntry.cap(2).toInt();
1063         //int month  = QString("Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec").find(newHistoryEntry.cap(3))/4 + 1;
1064         //int year   = newHistoryEntry.cap(4).toInt();
1065         //QString time = newHistoryEntry.cap(5);
1066         //QString name = newHistoryEntry.cap(6);
1067         QString defaultSortKeyOrder = "4,3,2,5,1,6"; //QDate(year,month,day).toString(Qt::ISODate) +" "+ time + " " + branch + " " + name;
1068 
1069         label = new QLabel(i18n("History entry start sort key order:"), page);
1070         gbox->addWidget(label, line, 0);
1071         m_pHistorySortKeyOrderLineEdit = new OptionLineEdit(defaultSortKeyOrder, "HistoryEntryStartSortKeyOrder", &m_options->m_historyEntryStartSortKeyOrder, page);
1072         gbox->addWidget(m_pHistorySortKeyOrderLineEdit, line, 1);
1073         addOptionItem(m_pHistorySortKeyOrderLineEdit);
1074         label->setToolTip(s_historyEntryStartSortKeyOrderToolTip);
1075         m_pHistorySortKeyOrderLineEdit->setEnabled(false);
1076         chk_connect(m_pHistoryMergeSorting, &OptionCheckBox::toggled, m_pHistorySortKeyOrderLineEdit, &OptionLineEdit::setEnabled);
1077         ++line;
1078 
1079         m_pHistoryAutoMerge = new OptionCheckBox(i18n("Merge version control history on merge start"), false, "RunHistoryAutoMergeOnMergeStart", &m_options->m_bRunHistoryAutoMergeOnMergeStart, page);
1080         addOptionItem(m_pHistoryAutoMerge);
1081         gbox->addWidget(m_pHistoryAutoMerge, line, 0, 1, 2);
1082         m_pHistoryAutoMerge->setToolTip(i18n("Run version control history automerge on merge start."));
1083         ++line;
1084 
1085         OptionIntEdit* pMaxNofHistoryEntries = new OptionIntEdit(-1, "MaxNofHistoryEntries", &m_options->m_maxNofHistoryEntries, -1, 1000, page);
1086         label = new QLabel(i18n("Max number of history entries:"), page);
1087         gbox->addWidget(label, line, 0);
1088         gbox->addWidget(pMaxNofHistoryEntries, line, 1);
1089         addOptionItem(pMaxNofHistoryEntries);
1090         pMaxNofHistoryEntries->setToolTip(i18n("Cut off after specified number. Use -1 for infinite number of entries."));
1091         ++line;
1092     }
1093 
1094     QPushButton* pButton = new QPushButton(i18n("Test your regular expressions"), page);
1095     gbox->addWidget(pButton, line, 0);
1096     chk_connect(pButton, &QPushButton::clicked, this, &OptionDialog::slotHistoryMergeRegExpTester);
1097     ++line;
1098 
1099     label = new QLabel(i18n("Irrelevant merge command:"), page);
1100     gbox->addWidget(label, line, 0);
1101     OptionLineEdit* pLE = new OptionLineEdit("", "IrrelevantMergeCmd", &m_options->m_IrrelevantMergeCmd, page);
1102     gbox->addWidget(pLE, line, 1);
1103     addOptionItem(pLE);
1104     label->setToolTip(i18n("If specified this script is run after automerge\n"
1105                            "when no other relevant changes were detected.\n"
1106                            "Called with the parameters: filename1 filename2 filename3"));
1107     ++line;
1108 
1109     OptionCheckBox* pAutoSaveAndQuit = new OptionCheckBox(i18n("Auto save and quit on merge without conflicts"), false,
1110                                                           "AutoSaveAndQuitOnMergeWithoutConflicts", &m_options->m_bAutoSaveAndQuitOnMergeWithoutConflicts, page);
1111     gbox->addWidget(pAutoSaveAndQuit, line, 0, 1, 2);
1112     addOptionItem(pAutoSaveAndQuit);
1113     pAutoSaveAndQuit->setToolTip(i18n("If KDiff3 was started for a file-merge from the command line and all\n"
1114                                       "conflicts are solvable without user interaction then automatically save and quit.\n"
1115                                       "(Similar to command line option \"--auto\".)"));
1116     ++line;
1117 
1118     topLayout->addStretch(10);
1119 }
1120 
setupDirectoryMergePage()1121 void OptionDialog::setupDirectoryMergePage()
1122 {
1123     QScrollArea*  pageFrame = new QScrollArea();
1124     KPageWidgetItem* pageItem = new KPageWidgetItem(pageFrame, i18n("Folder"));
1125     pageItem->setHeader(i18n("Folder"));
1126     pageItem->setIcon(QIcon::fromTheme(QStringLiteral("inode-directory")));
1127     addPage(pageItem);
1128 
1129     QVBoxLayout* scrollLayout = new QVBoxLayout();
1130     scrollLayout->setContentsMargins(2, 2, 2, 2);
1131     scrollLayout->addWidget(pageFrame);
1132 
1133     QScopedPointer<Ui::ScrollArea> scrollArea(new Ui::ScrollArea());
1134     scrollArea->setupUi(pageFrame);
1135 
1136     QWidget* page = pageFrame->findChild<QWidget*>("contents");
1137     QVBoxLayout* topLayout = new QVBoxLayout(page);
1138     topLayout->setContentsMargins(5, 5, 5, 5);
1139 
1140     QGridLayout* gbox = new QGridLayout();
1141     gbox->setColumnStretch(1, 5);
1142     topLayout->addLayout(gbox);
1143     int line = 0;
1144 
1145     OptionCheckBox* pRecursiveDirs = new OptionCheckBox(i18n("Recursive folders"), true, "RecursiveDirs", &m_options->m_bDmRecursiveDirs, page);
1146     gbox->addWidget(pRecursiveDirs, line, 0, 1, 2);
1147     addOptionItem(pRecursiveDirs);
1148     pRecursiveDirs->setToolTip(i18n("Whether to analyze subfolders or not."));
1149     ++line;
1150     QLabel* label = new QLabel(i18n("File pattern(s):"), page);
1151     gbox->addWidget(label, line, 0);
1152     OptionLineEdit* pFilePattern = new OptionLineEdit("*", "FilePattern", &m_options->m_DmFilePattern, page);
1153     gbox->addWidget(pFilePattern, line, 1);
1154     addOptionItem(pFilePattern);
1155     label->setToolTip(i18n(
1156         "Pattern(s) of files to be analyzed. \n"
1157         "Wildcards: '*' and '?'\n"
1158         "Several Patterns can be specified by using the separator: ';'"));
1159     ++line;
1160 
1161     label = new QLabel(i18n("File-anti-pattern(s):"), page);
1162     gbox->addWidget(label, line, 0);
1163     OptionLineEdit* pFileAntiPattern = new OptionLineEdit("*.orig;*.o;*.obj;*.rej;*.bak", "FileAntiPattern", &m_options->m_DmFileAntiPattern, page);
1164     gbox->addWidget(pFileAntiPattern, line, 1);
1165     addOptionItem(pFileAntiPattern);
1166     label->setToolTip(i18n(
1167         "Pattern(s) of files to be excluded from analysis. \n"
1168         "Wildcards: '*' and '?'\n"
1169         "Several Patterns can be specified by using the separator: ';'"));
1170     ++line;
1171 
1172     label = new QLabel(i18n("Folder-anti-pattern(s):"), page);
1173     gbox->addWidget(label, line, 0);
1174     OptionLineEdit* pDirAntiPattern = new OptionLineEdit("CVS;.deps;.svn;.hg;.git", "DirAntiPattern", &m_options->m_DmDirAntiPattern, page);
1175     gbox->addWidget(pDirAntiPattern, line, 1);
1176     addOptionItem(pDirAntiPattern);
1177     label->setToolTip(i18n(
1178         "Pattern(s) of folders to be excluded from analysis. \n"
1179         "Wildcards: '*' and '?'\n"
1180         "Several Patterns can be specified by using the separator: ';'"));
1181     ++line;
1182 
1183     OptionCheckBox* pUseCvsIgnore = new OptionCheckBox(i18n("Use Ignore File"), false, "UseCvsIgnore", &m_options->m_bDmUseCvsIgnore, page);
1184     gbox->addWidget(pUseCvsIgnore, line, 0, 1, 2);
1185     addOptionItem(pUseCvsIgnore);
1186     pUseCvsIgnore->setToolTip(i18n(
1187         "Extends the antipattern to anything that would be ignored by source control.\n"
1188         "Via local ignore files this can be folder-specific."));
1189     ++line;
1190 
1191     OptionCheckBox* pFindHidden = new OptionCheckBox(i18n("Find hidden files and folders"), true, "FindHidden", &m_options->m_bDmFindHidden, page);
1192     gbox->addWidget(pFindHidden, line, 0, 1, 2);
1193     addOptionItem(pFindHidden);
1194     pFindHidden->setToolTip(i18n("Finds hidden files and folders."));
1195     ++line;
1196 
1197     OptionCheckBox* pFollowFileLinks = new OptionCheckBox(i18n("Follow file links"), true, "FollowFileLinks", &m_options->m_bDmFollowFileLinks, page);
1198     gbox->addWidget(pFollowFileLinks, line, 0, 1, 2);
1199     addOptionItem(pFollowFileLinks);
1200     pFollowFileLinks->setToolTip(i18n(
1201         "On: Compare the file the link points to.\n"
1202         "Off: Compare the links."));
1203     ++line;
1204 
1205     OptionCheckBox* pFollowDirLinks = new OptionCheckBox(i18n("Follow folder links"), true, "FollowDirLinks", &m_options->m_bDmFollowDirLinks, page);
1206     gbox->addWidget(pFollowDirLinks, line, 0, 1, 2);
1207     addOptionItem(pFollowDirLinks);
1208     pFollowDirLinks->setToolTip(i18n(
1209         "On: Compare the folder the link points to.\n"
1210         "Off: Compare the links."));
1211     ++line;
1212 
1213 #if defined(Q_OS_WIN)
1214     bool bCaseSensitiveFilenameComparison = false;
1215 #else
1216     bool bCaseSensitiveFilenameComparison = true;
1217 #endif
1218     OptionCheckBox* pCaseSensitiveFileNames = new OptionCheckBox(i18n("Case sensitive filename comparison"), bCaseSensitiveFilenameComparison, "CaseSensitiveFilenameComparison", &m_options->m_bDmCaseSensitiveFilenameComparison, page);
1219     gbox->addWidget(pCaseSensitiveFileNames, line, 0, 1, 2);
1220     addOptionItem(pCaseSensitiveFileNames);
1221     pCaseSensitiveFileNames->setToolTip(i18n(
1222         "The folder comparison will compare files or folders when their names match.\n"
1223         "Set this option if the case of the names must match. (Default for Windows is off, otherwise on.)"));
1224     ++line;
1225 
1226     OptionCheckBox* pUnfoldSubdirs = new OptionCheckBox(i18n("Unfold all subfolders on load"), false, "UnfoldSubdirs", &m_options->m_bDmUnfoldSubdirs, page);
1227     gbox->addWidget(pUnfoldSubdirs, line, 0, 1, 2);
1228     addOptionItem(pUnfoldSubdirs);
1229     pUnfoldSubdirs->setToolTip(i18n(
1230         "On: Unfold all subfolders when starting a folder diff.\n"
1231         "Off: Leave subfolders folded."));
1232     ++line;
1233 
1234     OptionCheckBox* pSkipDirStatus = new OptionCheckBox(i18n("Skip folder status report"), false, "SkipDirStatus", &m_options->m_bDmSkipDirStatus, page);
1235     gbox->addWidget(pSkipDirStatus, line, 0, 1, 2);
1236     addOptionItem(pSkipDirStatus);
1237     pSkipDirStatus->setToolTip(i18n(
1238         "On: Do not show the Folder Comparison Status.\n"
1239         "Off: Show the status dialog on start."));
1240     ++line;
1241 
1242     QGroupBox* pBG = new QGroupBox(i18n("File Comparison Mode"));
1243     gbox->addWidget(pBG, line, 0, 1, 2);
1244 
1245     QVBoxLayout* pBGLayout = new QVBoxLayout(pBG);
1246 
1247     OptionRadioButton* pBinaryComparison = new OptionRadioButton(i18n("Binary comparison"), true, "BinaryComparison", &m_options->m_bDmBinaryComparison, pBG);
1248     addOptionItem(pBinaryComparison);
1249     pBinaryComparison->setToolTip(i18n("Binary comparison of each file. (Default)"));
1250     pBGLayout->addWidget(pBinaryComparison);
1251 
1252     OptionRadioButton* pFullAnalysis = new OptionRadioButton(i18n("Full analysis"), false, "FullAnalysis", &m_options->m_bDmFullAnalysis, pBG);
1253     addOptionItem(pFullAnalysis);
1254     pFullAnalysis->setToolTip(i18n("Do a full analysis and show statistics information in extra columns.\n"
1255                                    "(Slower than a binary comparison, much slower for binary files.)"));
1256     pBGLayout->addWidget(pFullAnalysis);
1257 
1258     OptionRadioButton* pTrustDate = new OptionRadioButton(i18n("Trust the size and modification date (unsafe)"), false, "TrustDate", &m_options->m_bDmTrustDate, pBG);
1259     addOptionItem(pTrustDate);
1260     pTrustDate->setToolTip(i18n("Assume that files are equal if the modification date and file length are equal.\n"
1261                                 "Files with equal contents but different modification dates will appear as different.\n"
1262                                 "Useful for big folders or slow networks."));
1263     pBGLayout->addWidget(pTrustDate);
1264 
1265     OptionRadioButton* pTrustDateFallbackToBinary = new OptionRadioButton(i18n("Trust the size and date, but use binary comparison if date does not match (unsafe)"), false, "TrustDateFallbackToBinary", &m_options->m_bDmTrustDateFallbackToBinary, pBG);
1266     addOptionItem(pTrustDateFallbackToBinary);
1267     pTrustDateFallbackToBinary->setToolTip(i18n("Assume that files are equal if the modification date and file length are equal.\n"
1268                                                 "If the dates are not equal but the sizes are, use binary comparison.\n"
1269                                                 "Useful for big folders or slow networks."));
1270     pBGLayout->addWidget(pTrustDateFallbackToBinary);
1271 
1272     OptionRadioButton* pTrustSize = new OptionRadioButton(i18n("Trust the size (unsafe)"), false, "TrustSize", &m_options->m_bDmTrustSize, pBG);
1273     addOptionItem(pTrustSize);
1274     pTrustSize->setToolTip(i18n("Assume that files are equal if their file lengths are equal.\n"
1275                                 "Useful for big folders or slow networks when the date is modified during download."));
1276     pBGLayout->addWidget(pTrustSize);
1277 
1278     ++line;
1279 
1280     // Some two Dir-options: Affects only the default actions.
1281     OptionCheckBox* pSyncMode = new OptionCheckBox(i18n("Synchronize folders"), false, "SyncMode", &m_options->m_bDmSyncMode, page);
1282     addOptionItem(pSyncMode);
1283     gbox->addWidget(pSyncMode, line, 0, 1, 2);
1284     pSyncMode->setToolTip(i18n(
1285         "Offers to store files in both folders so that\n"
1286         "both folders are the same afterwards.\n"
1287         "Works only when comparing two folders without specifying a destination."));
1288     ++line;
1289 
1290     // Allow white-space only differences to be considered equal
1291     OptionCheckBox* pWhiteSpaceDiffsEqual = new OptionCheckBox(i18n("White space differences considered equal"), true, "WhiteSpaceEqual", &m_options->m_bDmWhiteSpaceEqual, page);
1292     addOptionItem(pWhiteSpaceDiffsEqual);
1293     gbox->addWidget(pWhiteSpaceDiffsEqual, line, 0, 1, 2);
1294     pWhiteSpaceDiffsEqual->setToolTip(i18n(
1295         "If files differ only by white space consider them equal.\n"
1296         "This is only active when full analysis is chosen."));
1297     chk_connect(pFullAnalysis, &OptionRadioButton::toggled, pWhiteSpaceDiffsEqual, &OptionCheckBox::setEnabled);
1298     pWhiteSpaceDiffsEqual->setEnabled(false);
1299     ++line;
1300 
1301     OptionCheckBox* pCopyNewer = new OptionCheckBox(i18n("Copy newer instead of merging (unsafe)"), false, "CopyNewer", &m_options->m_bDmCopyNewer, page);
1302     addOptionItem(pCopyNewer);
1303     gbox->addWidget(pCopyNewer, line, 0, 1, 2);
1304     pCopyNewer->setToolTip(i18n(
1305         "Do not look inside, just take the newer file.\n"
1306         "(Use this only if you know what you are doing!)\n"
1307         "Only effective when comparing two folders."));
1308     ++line;
1309 
1310     OptionCheckBox* pCreateBakFiles = new OptionCheckBox(i18n("Backup files (.orig)"), true, "CreateBakFiles", &m_options->m_bDmCreateBakFiles, page);
1311     gbox->addWidget(pCreateBakFiles, line, 0, 1, 2);
1312     addOptionItem(pCreateBakFiles);
1313     pCreateBakFiles->setToolTip(i18n(
1314         "If a file would be saved over an old file, then the old file\n"
1315         "will be renamed with a '.orig' extension instead of being deleted."));
1316     ++line;
1317 
1318     topLayout->addStretch(10);
1319 }
setupRegionalPage()1320 void OptionDialog::setupRegionalPage()
1321 {
1322     QScrollArea* pageFrame = new QScrollArea();
1323     KPageWidgetItem* pageItem = new KPageWidgetItem(pageFrame, i18n("Regional Settings"));
1324     pageItem->setHeader(i18n("Regional Settings"));
1325     pageItem->setIcon(QIcon::fromTheme(QStringLiteral("preferences-desktop-locale")));
1326     addPage(pageItem);
1327 
1328     QVBoxLayout* scrollLayout = new QVBoxLayout();
1329     scrollLayout->setContentsMargins(2, 2, 2, 2);
1330     scrollLayout->addWidget(pageFrame);
1331 
1332     QScopedPointer<Ui::ScrollArea> scrollArea(new Ui::ScrollArea());
1333     scrollArea->setupUi(pageFrame);
1334 
1335     QWidget* page = pageFrame->findChild<QWidget*>("contents");
1336 
1337     QVBoxLayout* topLayout = new QVBoxLayout(page);
1338     topLayout->setContentsMargins(5, 5, 5, 5);
1339 
1340     QGridLayout* gbox = new QGridLayout();
1341     gbox->setColumnStretch(1, 5);
1342     topLayout->addLayout(gbox);
1343     int line = 0;
1344 
1345     QLabel* label;
1346 
1347     m_pSameEncoding = new OptionCheckBox(i18n("Use the same encoding for everything:"), true, "SameEncoding", &m_options->m_bSameEncoding, page);
1348     addOptionItem(m_pSameEncoding);
1349     gbox->addWidget(m_pSameEncoding, line, 0, 1, 2);
1350     m_pSameEncoding->setToolTip(i18n(
1351         "Enable this allows to change all encodings by changing the first only.\n"
1352         "Disable this if different individual settings are needed."));
1353     ++line;
1354 
1355     label = new QLabel(i18n("Note: Local Encoding is \"%1\"", QLatin1String(QTextCodec::codecForLocale()->name())), page);
1356     gbox->addWidget(label, line, 0);
1357     ++line;
1358 
1359     label = new QLabel(i18n("File Encoding for A:"), page);
1360     gbox->addWidget(label, line, 0);
1361     m_pEncodingAComboBox = new OptionEncodingComboBox("EncodingForA", &m_options->m_pEncodingA, page);
1362     addOptionItem(m_pEncodingAComboBox);
1363     gbox->addWidget(m_pEncodingAComboBox, line, 1);
1364 
1365     QString autoDetectToolTip = i18n(
1366         "If enabled then Unicode (UTF-16 or UTF-8) encoding will be detected.\n"
1367         "If the file is not Unicode then the selected encoding will be used as fallback.\n"
1368         "(Unicode detection depends on the first bytes of a file.)");
1369     m_pAutoDetectUnicodeA = new OptionCheckBox(i18n("Auto Detect Unicode"), true, "AutoDetectUnicodeA", &m_options->m_bAutoDetectUnicodeA, page);
1370     gbox->addWidget(m_pAutoDetectUnicodeA, line, 2);
1371     addOptionItem(m_pAutoDetectUnicodeA);
1372     m_pAutoDetectUnicodeA->setToolTip(autoDetectToolTip);
1373     ++line;
1374 
1375     label = new QLabel(i18n("File Encoding for B:"), page);
1376     gbox->addWidget(label, line, 0);
1377     m_pEncodingBComboBox = new OptionEncodingComboBox("EncodingForB", &m_options->m_pEncodingB, page);
1378     addOptionItem(m_pEncodingBComboBox);
1379     gbox->addWidget(m_pEncodingBComboBox, line, 1);
1380     m_pAutoDetectUnicodeB = new OptionCheckBox(i18n("Auto Detect Unicode"), true, "AutoDetectUnicodeB", &m_options->m_bAutoDetectUnicodeB, page);
1381     addOptionItem(m_pAutoDetectUnicodeB);
1382     gbox->addWidget(m_pAutoDetectUnicodeB, line, 2);
1383     m_pAutoDetectUnicodeB->setToolTip(autoDetectToolTip);
1384     ++line;
1385 
1386     label = new QLabel(i18n("File Encoding for C:"), page);
1387     gbox->addWidget(label, line, 0);
1388     m_pEncodingCComboBox = new OptionEncodingComboBox("EncodingForC", &m_options->m_pEncodingC, page);
1389     addOptionItem(m_pEncodingCComboBox);
1390     gbox->addWidget(m_pEncodingCComboBox, line, 1);
1391     m_pAutoDetectUnicodeC = new OptionCheckBox(i18n("Auto Detect Unicode"), true, "AutoDetectUnicodeC", &m_options->m_bAutoDetectUnicodeC, page);
1392     addOptionItem(m_pAutoDetectUnicodeC);
1393     gbox->addWidget(m_pAutoDetectUnicodeC, line, 2);
1394     m_pAutoDetectUnicodeC->setToolTip(autoDetectToolTip);
1395     ++line;
1396 
1397     label = new QLabel(i18n("File Encoding for Merge Output and Saving:"), page);
1398     gbox->addWidget(label, line, 0);
1399     m_pEncodingOutComboBox = new OptionEncodingComboBox("EncodingForOutput", &m_options->m_pEncodingOut, page);
1400     addOptionItem(m_pEncodingOutComboBox);
1401     gbox->addWidget(m_pEncodingOutComboBox, line, 1);
1402     m_pAutoSelectOutEncoding = new OptionCheckBox(i18n("Auto Select"), true, "AutoSelectOutEncoding", &m_options->m_bAutoSelectOutEncoding, page);
1403     addOptionItem(m_pAutoSelectOutEncoding);
1404     gbox->addWidget(m_pAutoSelectOutEncoding, line, 2);
1405     m_pAutoSelectOutEncoding->setToolTip(i18n(
1406         "If enabled then the encoding from the input files is used.\n"
1407         "In ambiguous cases a dialog will ask the user to choose the encoding for saving."));
1408     ++line;
1409     label = new QLabel(i18n("File Encoding for Preprocessor Files:"), page);
1410     gbox->addWidget(label, line, 0);
1411     m_pEncodingPPComboBox = new OptionEncodingComboBox("EncodingForPP", &m_options->m_pEncodingPP, page);
1412     addOptionItem(m_pEncodingPPComboBox);
1413     gbox->addWidget(m_pEncodingPPComboBox, line, 1);
1414     ++line;
1415 
1416     chk_connect(m_pSameEncoding, &OptionCheckBox::toggled, this, &OptionDialog::slotEncodingChanged);
1417     chk_connect(m_pEncodingAComboBox, static_cast<void (OptionEncodingComboBox::*)(int)>(&OptionEncodingComboBox::activated), this, &OptionDialog::slotEncodingChanged);
1418     chk_connect(m_pAutoDetectUnicodeA, &OptionCheckBox::toggled, this, &OptionDialog::slotEncodingChanged);
1419     chk_connect(m_pAutoSelectOutEncoding, &OptionCheckBox::toggled, this, &OptionDialog::slotEncodingChanged);
1420 
1421     OptionCheckBox* pRightToLeftLanguage = new OptionCheckBox(i18n("Right To Left Language"), false, "RightToLeftLanguage", &m_options->m_bRightToLeftLanguage, page);
1422     addOptionItem(pRightToLeftLanguage);
1423     gbox->addWidget(pRightToLeftLanguage, line, 0, 1, 2);
1424     pRightToLeftLanguage->setToolTip(i18n(
1425         "Some languages are read from right to left.\n"
1426         "This setting will change the viewer and editor accordingly."));
1427     ++line;
1428 
1429     topLayout->addStretch(10);
1430 }
1431 
setupIntegrationPage()1432 void OptionDialog::setupIntegrationPage()
1433 {
1434     QScrollArea* pageFrame = new QScrollArea();
1435     KPageWidgetItem* pageItem = new KPageWidgetItem(pageFrame, i18n("Integration"));
1436     pageItem->setHeader(i18n("Integration Settings"));
1437     pageItem->setIcon(QIcon::fromTheme(QStringLiteral("utilities-terminal")));
1438     addPage(pageItem);
1439 
1440     QVBoxLayout* scrollLayout = new QVBoxLayout();
1441     scrollLayout->setContentsMargins(2, 2, 2, 2);
1442     scrollLayout->addWidget(pageFrame);
1443 
1444     QScopedPointer<Ui::ScrollArea> scrollArea(new Ui::ScrollArea());
1445     scrollArea->setupUi(pageFrame);
1446 
1447     QWidget* page = pageFrame->findChild<QWidget*>("contents");
1448     QVBoxLayout* topLayout = new QVBoxLayout(page);
1449     topLayout->setContentsMargins(5, 5, 5, 5);
1450 
1451     QGridLayout* gbox = new QGridLayout();
1452     gbox->setColumnStretch(2, 5);
1453     topLayout->addLayout(gbox);
1454     int line = 0;
1455 
1456     QLabel* label;
1457     label = new QLabel(i18n("Command line options to ignore:"), page);
1458     gbox->addWidget(label, line, 0);
1459     OptionLineEdit* pIgnorableCmdLineOptions = new OptionLineEdit("-u;-query;-html;-abort", "IgnorableCmdLineOptions", &m_options->m_ignorableCmdLineOptions, page);
1460     gbox->addWidget(pIgnorableCmdLineOptions, line, 1, 1, 2);
1461     addOptionItem(pIgnorableCmdLineOptions);
1462     label->setToolTip(i18n(
1463         "List of command line options that should be ignored when KDiff3 is used by other tools.\n"
1464         "Several values can be specified if separated via ';'\n"
1465         "This will suppress the \"Unknown option\" error."));
1466     ++line;
1467 
1468     OptionCheckBox* pEscapeKeyQuits = new OptionCheckBox(i18n("Quit also via Escape key"), false, "EscapeKeyQuits", &m_options->m_bEscapeKeyQuits, page);
1469     gbox->addWidget(pEscapeKeyQuits, line, 0, 1, 2);
1470     addOptionItem(pEscapeKeyQuits);
1471     pEscapeKeyQuits->setToolTip(i18n(
1472         "Fast method to exit.\n"
1473         "For those who are used to using the Escape key."));
1474     ++line;
1475 
1476     topLayout->addStretch(10);
1477 }
1478 
1479 
slotEncodingChanged()1480 void OptionDialog::slotEncodingChanged()
1481 {
1482     if(m_pSameEncoding->isChecked())
1483     {
1484         m_pEncodingBComboBox->setEnabled(false);
1485         m_pEncodingBComboBox->setCurrentIndex(m_pEncodingAComboBox->currentIndex());
1486         m_pEncodingCComboBox->setEnabled(false);
1487         m_pEncodingCComboBox->setCurrentIndex(m_pEncodingAComboBox->currentIndex());
1488         m_pEncodingOutComboBox->setEnabled(false);
1489         m_pEncodingOutComboBox->setCurrentIndex(m_pEncodingAComboBox->currentIndex());
1490         m_pEncodingPPComboBox->setEnabled(false);
1491         m_pEncodingPPComboBox->setCurrentIndex(m_pEncodingAComboBox->currentIndex());
1492         m_pAutoDetectUnicodeB->setEnabled(false);
1493         m_pAutoDetectUnicodeB->setCheckState(m_pAutoDetectUnicodeA->checkState());
1494         m_pAutoDetectUnicodeC->setEnabled(false);
1495         m_pAutoDetectUnicodeC->setCheckState(m_pAutoDetectUnicodeA->checkState());
1496         m_pAutoSelectOutEncoding->setEnabled(false);
1497         m_pAutoSelectOutEncoding->setCheckState(m_pAutoDetectUnicodeA->checkState());
1498     }
1499     else
1500     {
1501         m_pEncodingBComboBox->setEnabled(true);
1502         m_pEncodingCComboBox->setEnabled(true);
1503         m_pEncodingOutComboBox->setEnabled(true);
1504         m_pEncodingPPComboBox->setEnabled(true);
1505         m_pAutoDetectUnicodeB->setEnabled(true);
1506         m_pAutoDetectUnicodeC->setEnabled(true);
1507         m_pAutoSelectOutEncoding->setEnabled(true);
1508         m_pEncodingOutComboBox->setEnabled(m_pAutoSelectOutEncoding->checkState() == Qt::Unchecked);
1509     }
1510 }
1511 
slotOk()1512 void OptionDialog::slotOk()
1513 {
1514     slotApply();
1515 
1516     accept();
1517 }
1518 
1519 /** Copy the values from the widgets to the public variables.*/
slotApply()1520 void OptionDialog::slotApply()
1521 {
1522     m_options->apply();
1523 
1524     Q_EMIT applyDone();
1525 }
1526 
1527 /** Set the default values in the widgets only, while the
1528     public variables remain unchanged. */
slotDefault()1529 void OptionDialog::slotDefault()
1530 {
1531     int result = KMessageBox::warningContinueCancel(this, i18n("This resets all options. Not only those of the current topic."));
1532     if(result == KMessageBox::Cancel)
1533         return;
1534     else
1535         resetToDefaults();
1536 }
1537 
resetToDefaults()1538 void OptionDialog::resetToDefaults()
1539 {
1540     m_options->resetToDefaults();
1541     slotEncodingChanged();
1542 }
1543 
1544 /** Initialise the widgets using the values in the public varibles. */
setState()1545 void OptionDialog::setState()
1546 {
1547     m_options->setToCurrent();
1548 
1549     slotEncodingChanged();
1550 }
1551 
saveOptions(KSharedConfigPtr config)1552 void OptionDialog::saveOptions(KSharedConfigPtr config)
1553 {
1554     // No i18n()-Translations here!
1555     m_options->saveOptions(config);
1556 }
1557 
readOptions(KSharedConfigPtr config)1558 void OptionDialog::readOptions(KSharedConfigPtr config)
1559 {
1560     // No i18n()-Translations here!
1561     m_options->readOptions(config);
1562 
1563     setState();
1564 }
1565 
parseOptions(const QStringList & optionList)1566 const QString OptionDialog::parseOptions(const QStringList& optionList)
1567 {
1568 
1569     return m_options->parseOptions(optionList);
1570 }
1571 
calcOptionHelp()1572 QString OptionDialog::calcOptionHelp()
1573 {
1574     return m_options->calcOptionHelp();
1575 }
1576 
slotHistoryMergeRegExpTester()1577 void OptionDialog::slotHistoryMergeRegExpTester()
1578 {
1579     QPointer<RegExpTester> dlg=QPointer<RegExpTester>(new RegExpTester(this, s_autoMergeRegExpToolTip, s_historyStartRegExpToolTip,
1580                      s_historyEntryStartRegExpToolTip, s_historyEntryStartSortKeyOrderToolTip));
1581     dlg->init(m_pAutoMergeRegExpLineEdit->currentText(), m_pHistoryStartRegExpLineEdit->currentText(),
1582              m_pHistoryEntryStartRegExpLineEdit->currentText(), m_pHistorySortKeyOrderLineEdit->currentText());
1583     if(dlg->exec())
1584     {
1585         m_pAutoMergeRegExpLineEdit->setEditText(dlg->autoMergeRegExp());
1586         m_pHistoryStartRegExpLineEdit->setEditText(dlg->historyStartRegExp());
1587         m_pHistoryEntryStartRegExpLineEdit->setEditText(dlg->historyEntryStartRegExp());
1588         m_pHistorySortKeyOrderLineEdit->setEditText(dlg->historySortKeyOrder());
1589     }
1590 }
1591 
1592 #include "optiondialog.moc"
1593