1 /*
2 	This is part of TeXworks, an environment for working with TeX documents
3 	Copyright (C) 2007-2016  Jonathan Kew, Stefan Löffler, Charlie Sharpsteen
4 
5 	This program is free software; you can redistribute it and/or modify
6 	it under the terms of the GNU General Public License as published by
7 	the Free Software Foundation; either version 2 of the License, or
8 	(at your option) any later version.
9 
10 	This program is distributed in the hope that it will be useful,
11 	but WITHOUT ANY WARRANTY; without even the implied warranty of
12 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 	GNU General Public License for more details.
14 
15 	You should have received a copy of the GNU General Public License
16 	along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 
18 	For links to further information, or to contact the authors,
19 	see <http://www.tug.org/texworks/>.
20 */
21 
22 #include "PrefsDialog.h"
23 #include "DefaultPrefs.h"
24 #include "TWApp.h"
25 #include "PDFDocument.h"
26 #include "TeXHighlighter.h"
27 #include "CompletingEdit.h"
28 
29 #include <QFontDatabase>
30 #include <QTextCodec>
31 #include <QSet>
32 #include <QFileDialog>
33 #include <QMainWindow>
34 #include <QToolBar>
35 #include <QDesktopWidget>
36 //#include <QtAlgorithms>
37 #include <QMessageBox>
38 
PrefsDialog(QWidget * parent)39 PrefsDialog::PrefsDialog(QWidget *parent)
40 	: QDialog(parent)
41 {
42 	init();
43 }
44 
init()45 void PrefsDialog::init()
46 {
47 	setupUi(this);
48 
49 	connect(buttonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(buttonClicked(QAbstractButton*)));
50 
51 	connect(binPathList, SIGNAL(itemSelectionChanged()), this, SLOT(updatePathButtons()));
52 	connect(pathUp, SIGNAL(clicked()), this, SLOT(movePathUp()));
53 	connect(pathDown, SIGNAL(clicked()), this, SLOT(movePathDown()));
54 	connect(pathAdd, SIGNAL(clicked()), this, SLOT(addPath()));
55 	connect(pathRemove, SIGNAL(clicked()), this, SLOT(removePath()));
56 
57 	connect(toolList, SIGNAL(itemSelectionChanged()), this, SLOT(updateToolButtons()));
58 	connect(toolList, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(editTool(QListWidgetItem*)));
59 	connect(toolUp, SIGNAL(clicked()), this, SLOT(moveToolUp()));
60 	connect(toolDown, SIGNAL(clicked()), this, SLOT(moveToolDown()));
61 	connect(toolAdd, SIGNAL(clicked()), this, SLOT(addTool()));
62 	connect(toolRemove, SIGNAL(clicked()), this, SLOT(removeTool()));
63 	connect(toolEdit, SIGNAL(clicked()), this, SLOT(editTool()));
64 
65 	connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(changedTabPanel(int)));
66 
67 	pathsChanged = toolsChanged = false;
68 }
69 
changedTabPanel(int index)70 void PrefsDialog::changedTabPanel(int index)
71 {
72 	// this all feels a bit hacky, but seems to keep things tidy on Mac OS X at least
73 	QWidget *page = tabWidget->widget(index);
74 	page->clearFocus();
75 	switch (index) {
76 		case 0: // General
77 			if (page->focusWidget() != NULL)
78 				page->focusWidget()->clearFocus();
79 			break;
80 		case 1: // Editor
81 			editorFont->setFocus();
82 			editorFont->lineEdit()->selectAll();
83 			break;
84 		case 2: // Preview
85 			scale->setFocus();
86 			scale->selectAll();
87 			break;
88 		case 3: // Typesetting
89 			binPathList->setFocus();
90 			break;
91 		case 4: // Script
92 			if (page->focusWidget() != NULL)
93 				page->focusWidget()->clearFocus();
94 			break;
95 	}
96 }
97 
updatePathButtons()98 void PrefsDialog::updatePathButtons()
99 {
100 	int selRow = -1;
101 	if (binPathList->selectedItems().count() > 0)
102 		selRow = binPathList->currentRow();
103 	pathRemove->setEnabled(selRow != -1);
104 	pathUp->setEnabled(selRow > 0);
105 	pathDown->setEnabled(selRow != -1 && selRow < binPathList->count() - 1);
106 }
107 
movePathUp()108 void PrefsDialog::movePathUp()
109 {
110 	int selRow = -1;
111 	if (binPathList->selectedItems().count() > 0)
112 		selRow = binPathList->currentRow();
113 	if (selRow > 0) {
114 		QListWidgetItem *item = binPathList->takeItem(selRow);
115 		binPathList->insertItem(selRow - 1, item);
116 		binPathList->setCurrentItem(binPathList->item(selRow - 1));
117 		pathsChanged = true;
118 	}
119 }
120 
movePathDown()121 void PrefsDialog::movePathDown()
122 {
123 	int selRow = -1;
124 	if (binPathList->selectedItems().count() > 0)
125 		selRow = binPathList->currentRow();
126 	if (selRow != -1 &&  selRow < binPathList->count() - 1) {
127 		QListWidgetItem *item = binPathList->takeItem(selRow);
128 		binPathList->insertItem(selRow + 1, item);
129 		binPathList->setCurrentItem(binPathList->item(selRow + 1));
130 		pathsChanged = true;
131 	}
132 }
133 
addPath()134 void PrefsDialog::addPath()
135 {
136 	QString dir = QFileDialog::getExistingDirectory(this, tr("Choose Directory"),
137 					 "/usr", /*0*/ /*QFileDialog::DontUseNativeDialog*/
138 								QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
139 	// remove the trailing / (if any)
140 	dir = QDir::fromNativeSeparators(dir);
141 #if defined(Q_OS_WIN)
142 	if (dir.length() > 2)
143 #else
144 	if (dir.length() > 1)
145 #endif
146 		if (dir.at(dir.length() - 1) == '/')
147 			dir.chop(1);
148 	if (dir != "") {
149 		binPathList->addItem(dir);
150 		binPathList->setCurrentItem(binPathList->item(binPathList->count() - 1));
151 		pathsChanged = true;
152 	}
153 }
154 
removePath()155 void PrefsDialog::removePath()
156 {
157 	if (binPathList->currentRow() > -1)
158 		if (binPathList->currentItem()->isSelected()) {
159 			binPathList->takeItem(binPathList->currentRow());
160 			pathsChanged = true;
161 		}
162 }
163 
updateToolButtons()164 void PrefsDialog::updateToolButtons()
165 {
166 	int selRow = -1;
167 	if (toolList->selectedItems().count() > 0)
168 		selRow = toolList->currentRow();
169 	toolEdit->setEnabled(selRow != -1);
170 	toolRemove->setEnabled(selRow != -1);
171 	toolUp->setEnabled(selRow > 0);
172 	toolDown->setEnabled(selRow != -1 && selRow < toolList->count() - 1);
173 }
174 
moveToolUp()175 void PrefsDialog::moveToolUp()
176 {
177 	int selRow = -1;
178 	if (toolList->selectedItems().count() > 0)
179 		selRow = toolList->currentRow();
180 	if (selRow > 0) {
181 		QListWidgetItem *item = toolList->takeItem(selRow);
182 		toolList->insertItem(selRow - 1, item);
183 		toolList->setCurrentItem(toolList->item(selRow - 1));
184 		Engine e = engineList.takeAt(selRow);
185 		engineList.insert(selRow - 1, e);
186 		refreshDefaultTool();
187 		toolsChanged = true;
188 	}
189 }
190 
moveToolDown()191 void PrefsDialog::moveToolDown()
192 {
193 	int selRow = -1;
194 	if (toolList->selectedItems().count() > 0)
195 		selRow = toolList->currentRow();
196 	if (selRow != -1 &&  selRow < toolList->count() - 1) {
197 		QListWidgetItem *item = toolList->takeItem(selRow);
198 		toolList->insertItem(selRow + 1, item);
199 		toolList->setCurrentItem(toolList->item(selRow + 1));
200 		Engine e = engineList.takeAt(selRow);
201 		engineList.insert(selRow + 1, e);
202 		refreshDefaultTool();
203 		toolsChanged = true;
204 	}
205 }
206 
addTool()207 void PrefsDialog::addTool()
208 {
209 	Engine e;
210 	e.setName(tr("New Tool"));
211 	e.setShowPdf(true);
212 	if (ToolConfig::doToolConfig(this, e) == QDialog::Accepted) {
213 		engineList.append(e);
214 		toolList->addItem(e.name());
215 		refreshDefaultTool();
216 		toolsChanged = true;
217 	}
218 }
219 
removeTool()220 void PrefsDialog::removeTool()
221 {
222 	if (toolList->currentRow() > -1)
223 		if (toolList->currentItem()->isSelected()) {
224 			engineList.removeAt(toolList->currentRow());
225 			toolList->takeItem(toolList->currentRow());
226 			refreshDefaultTool();
227 			toolsChanged = true;
228 		}
229 }
230 
editTool(QListWidgetItem * item)231 void PrefsDialog::editTool(QListWidgetItem* item)
232 {
233 	int row = -1;
234 	if (item)
235 		row = toolList->row(item);
236 	else if (toolList->currentRow() > -1 && toolList->currentItem()->isSelected())
237 		row = toolList->currentRow();
238 	if (row > -1) {
239 		Engine e = engineList[toolList->currentRow()];
240 		if (ToolConfig::doToolConfig(this, e) == QDialog::Accepted) {
241 			engineList[toolList->currentRow()] = e;
242 			toolList->currentItem()->setText(e.name());
243 			toolsChanged = true;
244 		}
245 	}
246 }
247 
refreshDefaultTool()248 void PrefsDialog::refreshDefaultTool()
249 {
250 	QString val;
251 	int toolIndex = -1, defaultIndex = -1;
252 
253 	if (defaultTool->count() > 0)
254 		val = defaultTool->currentText();
255 	defaultTool->clear();
256 	foreach (Engine e, engineList) {
257 		defaultTool->addItem(e.name());
258 		if (e.name() == val)
259 			toolIndex = defaultTool->count() - 1;
260 		if (e.name() == DEFAULT_ENGINE_NAME)
261 			defaultIndex = defaultTool->count() - 1;
262 	}
263 
264 	if (toolIndex >= 0)
265 		defaultTool->setCurrentIndex(toolIndex);
266 	else if (defaultIndex >= 0)
267 		defaultTool->setCurrentIndex(defaultIndex);
268 }
269 
buttonClicked(QAbstractButton * whichButton)270 void PrefsDialog::buttonClicked(QAbstractButton *whichButton)
271 {
272 	if (buttonBox->buttonRole(whichButton) == QDialogButtonBox::ResetRole)
273 		restoreDefaults();
274 }
275 
restoreDefaults()276 void PrefsDialog::restoreDefaults()
277 {
278 	switch (tabWidget->currentIndex()) {
279 		case 0:
280 			// General
281 			switch (kDefault_ToolBarIcons) {
282 				case 1:
283 					smallIcons->setChecked(true);
284 					break;
285 				case 2:
286 					mediumIcons->setChecked(true);
287 					break;
288 				case 3:
289 					largeIcons->setChecked(true);
290 					break;
291 			}
292 			showText->setChecked(kDefault_ToolBarText);
293 			switch (kDefault_LaunchOption) {
294 				case 1:
295 				default:
296 					blankDocument->setChecked(true);
297 					break;
298 				case 2:
299 					templateDialog->setChecked(true);
300 					break;
301 				case 3:
302 					openDialog->setChecked(true);
303 					break;
304 			}
305 			localePopup->setCurrentIndex(kDefault_Locale);
306 			openPDFwithTeX->setChecked(kDefault_OpenPDFwithTeX);
307 			break;
308 
309 		case 1:
310 			// Editor
311 			{
312 				QFont font;
313 				editorFont->setEditText(font.family());
314 				fontSize->setValue(font.pointSize());
315 			}
316 			tabWidth->setValue(kDefault_TabWidth);
317 			lineNumbers->setChecked(kDefault_LineNumbers);
318 			wrapLines->setChecked(kDefault_WrapLines);
319 			syntaxColoring->setCurrentIndex(kDefault_SyntaxColoring);
320 			autoIndent->setCurrentIndex(kDefault_IndentMode);
321 			smartQuotes->setCurrentIndex(kDefault_QuotesMode);
322 			language->setCurrentIndex(kDefault_SpellcheckLanguage);
323 			encoding->setCurrentIndex(encoding->findText("UTF-8"));
324 			highlightCurrentLine->setChecked(kDefault_HighlightCurrentLine);
325 			autocompleteEnabled->setChecked(kDefault_AutocompleteEnabled);
326 			break;
327 
328 		case 2:
329 			// Preview
330 			switch (kDefault_PreviewScaleOption) {
331 				default:
332 					actualSize->setChecked(true);
333 					break;
334 				case 2:
335 					fitWidth->setChecked(true);
336 					break;
337 				case 3:
338 					fitWindow->setChecked(true);
339 					break;
340 				case 4:
341 					fixedScale->setChecked(true);
342 					break;
343 			}
344 			scale->setValue(kDefault_PreviewScale);
345 			switch (kDefault_PDFPageMode) {
346 				case QtPDF::PDFDocumentView::PageMode_SinglePage:
347 					pdfPageMode->setCurrentIndex(0);
348 					break;
349 				case QtPDF::PDFDocumentView::PageMode_OneColumnContinuous:
350 				default:
351 					pdfPageMode->setCurrentIndex(1);
352 					break;
353 				case QtPDF::PDFDocumentView::PageMode_TwoColumnContinuous:
354 					pdfPageMode->setCurrentIndex(2);
355 				break;
356 			}
357 
358 			resolution->setDpi(QApplication::desktop()->physicalDpiX());
359 
360 			switch (kDefault_MagnifierSize) {
361 				case 1:
362 					smallMag->setChecked(true);
363 					break;
364 				default:
365 					mediumMag->setChecked(true);
366 					break;
367 				case 3:
368 					largeMag->setChecked(true);
369 					break;
370 			}
371 			circularMag->setChecked(kDefault_CircularMagnifier);
372 			break;
373 
374 		case 3:
375 			// Typesetting
376 			TWApp::instance()->setDefaultEngineList();
377 			TWApp::instance()->setDefaultPaths();
378 			initPathAndToolLists();
379 			autoHideOutput->setCurrentIndex(kDefault_HideConsole);
380 			pathsChanged = true;
381 			toolsChanged = true;
382 			break;
383 
384 		case 4:
385 			// Scripts
386 			allowScriptFileReading->setChecked(kDefault_AllowScriptFileReading);
387 			allowScriptFileWriting->setChecked(kDefault_AllowScriptFileWriting);
388 			enableScriptingPlugins->setChecked(kDefault_EnableScriptingPlugins);
389 			allowSystemCommands->setChecked(kDefault_AllowSystemCommands);
390 			scriptDebugger->setChecked(kDefault_ScriptDebugger);
391 			break;
392 	}
393 }
394 
initPathAndToolLists()395 void PrefsDialog::initPathAndToolLists()
396 {
397 	binPathList->clear();
398 	toolList->clear();
399 	binPathList->addItems(TWApp::instance()->getPrefsBinaryPaths());
400 	engineList = TWApp::instance()->getEngineList();
401 	foreach (Engine e, engineList) {
402 		toolList->addItem(e.name());
403 		defaultTool->addItem(e.name());
404 		if (e.name() == TWApp::instance()->getDefaultEngine().name())
405 			defaultTool->setCurrentIndex(defaultTool->count() - 1);
406 	}
407 	if (binPathList->count() > 0)
408 		binPathList->setCurrentItem(binPathList->item(0));
409 	if (toolList->count() > 0)
410 		toolList->setCurrentItem(toolList->item(0));
411 	updatePathButtons();
412 	updateToolButtons();
413 }
414 
415 const int kSystemLocaleIndex = 0;
416 const int kEnglishLocaleIndex = 1;
417 const int kFirstTranslationIndex = 1;
418 
419 typedef QPair<QString, QString> DictPair;
420 
dictPairLessThan(const DictPair & d1,const DictPair & d2)421 static bool dictPairLessThan(const DictPair& d1, const DictPair& d2)
422 {
423 	return d1.first.toLower() < d2.first.toLower();
424 }
425 
doPrefsDialog(QWidget * parent)426 QDialog::DialogCode PrefsDialog::doPrefsDialog(QWidget *parent)
427 {
428 	PrefsDialog dlg(NULL);
429 
430 	QStringList nameList;
431 	foreach (QTextCodec *codec, *TWUtils::findCodecs())
432 		nameList.append(codec->name());
433 	dlg.encoding->addItems(nameList);
434 
435 	QStringList syntaxOptions = TeXHighlighter::syntaxOptions();
436 	dlg.syntaxColoring->addItems(syntaxOptions);
437 
438 	QStringList indentModes = CompletingEdit::autoIndentModes();
439 	dlg.autoIndent->addItems(indentModes);
440 
441 	QStringList quotesModes = CompletingEdit::smartQuotesModes();
442 	dlg.smartQuotes->addItems(quotesModes);
443 
444 	QList< DictPair > dictList;
445 	foreach (const QString& dictKey, TWUtils::getDictionaryList()->uniqueKeys()) {
446 		QString dict, label;
447 		QLocale loc;
448 
449 		foreach (dict, TWUtils::getDictionaryList()->values(dictKey)) {
450 			loc = QLocale(dict);
451 			if (loc.language() != QLocale::C) break;
452 		}
453 
454 		if (loc.language() == QLocale::C)
455 			label = dict;
456 		else {
457 			label = QLocale::languageToString(loc.language());
458 			QLocale::Country country = loc.country();
459 			if (country != QLocale::AnyCountry)
460 				label += " - " + QLocale::countryToString(country);
461 			label += " (" + dict + ")";
462 		}
463 
464 		dictList << qMakePair(label, dict);
465 	}
466 	qSort(dictList.begin(), dictList.end(), dictPairLessThan);
467 	foreach (const DictPair& dict, dictList)
468 		dlg.language->addItem(dict.first, dict.second);
469 
470 	QSETTINGS_OBJECT(settings);
471 	// initialize controls based on the current settings
472 
473 	// General
474 	int oldIconSize = settings.value("toolBarIconSize", kDefault_ToolBarIcons).toInt();
475 	switch (oldIconSize) {
476 		case 1:
477 			dlg.smallIcons->setChecked(true);
478 			break;
479 		case 3:
480 			dlg.largeIcons->setChecked(true);
481 			break;
482 		default:
483 			dlg.mediumIcons->setChecked(true);
484 			break;
485 	}
486 	bool oldShowText = settings.value("toolBarShowText", kDefault_ToolBarText).toBool();
487 	dlg.showText->setChecked(oldShowText);
488 
489 	switch (settings.value("launchOption", kDefault_LaunchOption).toInt()) {
490 		default:
491 			dlg.blankDocument->setChecked(true);
492 			break;
493 		case 2:
494 			dlg.templateDialog->setChecked(true);
495 			break;
496 		case 3:
497 			dlg.openDialog->setChecked(true);
498 			break;
499 	}
500 	dlg.openPDFwithTeX->setChecked(settings.value("openPDFwithTeX", kDefault_OpenPDFwithTeX).toBool());
501 
502 	QString oldLocale = settings.value("locale").toString();
503 	// System and English are predefined at index 0 and 1 (see constants above)
504 	dlg.localePopup->addItem(tr("System default [%1]").arg(QLocale::languageToString(QLocale(QLocale::system().name()).language())));
505 	int oldLocaleIndex = oldLocale.isEmpty() ? kSystemLocaleIndex : kEnglishLocaleIndex;
506 	QStringList *trList = TWUtils::getTranslationList();
507 	QStringList::ConstIterator iter;
508 	for (iter = trList->constBegin(); iter != trList->constEnd(); ++iter) {
509 		QLocale loc(*iter);
510 		QLocale::Language	language = loc.language();
511 		QString locName;
512 		if (language == QLocale::C)
513 			locName = *iter;
514 		else {
515 			locName = QLocale::languageToString(language);
516 			if (iter->contains('_')) {
517 				QLocale::Country	country  = loc.country();
518 				if (country != QLocale::AnyCountry)
519 					locName += " (" + QLocale::countryToString(country) + ")";
520 			}
521 		}
522 		dlg.localePopup->addItem(locName);
523 		if (*iter == oldLocale)
524 			oldLocaleIndex = dlg.localePopup->count() - 1;
525 	}
526 	dlg.localePopup->setCurrentIndex(oldLocaleIndex);
527 
528 	// Editor
529 	dlg.syntaxColoring->setCurrentIndex(settings.contains("syntaxColoring")
530 							? 1 + syntaxOptions.indexOf(settings.value("syntaxColoring").toString())
531 							: 1 + kDefault_SyntaxColoring);
532 	dlg.autoIndent->setCurrentIndex(settings.contains("autoIndent")
533 							? 1 + indentModes.indexOf(settings.value("autoIndent").toString())
534 							: 1 + kDefault_IndentMode);
535 	dlg.smartQuotes->setCurrentIndex(settings.contains("smartQuotes")
536 							? 1 + quotesModes.indexOf(settings.value("smartQuotes").toString())
537 							: 1 + kDefault_QuotesMode);
538 	dlg.lineNumbers->setChecked(settings.value("lineNumbers", kDefault_LineNumbers).toBool());
539 	dlg.wrapLines->setChecked(settings.value("wrapLines", kDefault_WrapLines).toBool());
540 	dlg.tabWidth->setValue(settings.value("tabWidth", kDefault_TabWidth).toInt());
541 	QFontDatabase fdb;
542 	dlg.editorFont->addItems(fdb.families());
543 	QString fontString = settings.value("font").toString();
544 	QFont font;
545 	if (fontString != "")
546 		font.fromString(fontString);
547 	dlg.editorFont->setCurrentIndex(fdb.families().indexOf(font.family()));
548 	dlg.fontSize->setValue(font.pointSize());
549 	dlg.encoding->setCurrentIndex(nameList.indexOf(TWApp::instance()->getDefaultCodec()->name()));
550 	dlg.highlightCurrentLine->setChecked(settings.value("highlightCurrentLine", kDefault_HighlightCurrentLine).toBool());
551 	dlg.autocompleteEnabled->setChecked(settings.value("autocompleteEnabled", kDefault_AutocompleteEnabled).toBool());
552 
553 	QString defDict = settings.value("language", "None").toString();
554 	int i = dlg.language->findData(defDict);
555 	if (i >= 0)
556 		dlg.language->setCurrentIndex(i);
557 
558 	// Preview
559 	switch (settings.value("scaleOption", kDefault_PreviewScaleOption).toInt()) {
560 		default:
561 			dlg.actualSize->setChecked(true);
562 			break;
563 		case 2:
564 			dlg.fitWidth->setChecked(true);
565 			break;
566 		case 3:
567 			dlg.fitWindow->setChecked(true);
568 			break;
569 		case 4:
570 			dlg.fixedScale->setChecked(true);
571 			break;
572 	}
573 	dlg.scale->setValue(settings.value("previewScale", kDefault_PreviewScale).toInt());
574 	switch (settings.value("pdfPageMode", kDefault_PDFPageMode).toInt()) {
575 		case QtPDF::PDFDocumentView::PageMode_SinglePage:
576 			dlg.pdfPageMode->setCurrentIndex(0);
577 			break;
578 		case QtPDF::PDFDocumentView::PageMode_OneColumnContinuous:
579 		default:
580 			dlg.pdfPageMode->setCurrentIndex(1);
581 			break;
582 		case QtPDF::PDFDocumentView::PageMode_TwoColumnContinuous:
583 			dlg.pdfPageMode->setCurrentIndex(2);
584 			break;
585 	}
586 
587 	double oldResolution = settings.value("previewResolution", QApplication::desktop()->physicalDpiX()).toDouble();
588 	dlg.resolution->setDpi(oldResolution);
589 
590 	int oldMagSize = settings.value("magnifierSize", kDefault_MagnifierSize).toInt();
591 	switch (oldMagSize) {
592 		case 1:
593 			dlg.smallMag->setChecked(true);
594 			break;
595 		default:
596 			dlg.mediumMag->setChecked(true);
597 			break;
598 		case 3:
599 			dlg.largeMag->setChecked(true);
600 			break;
601 	}
602 	bool oldCircular = settings.value("circularMagnifier", kDefault_CircularMagnifier).toBool();
603 	dlg.circularMag->setChecked(oldCircular);
604 
605 	// Typesetting
606 	dlg.initPathAndToolLists();
607 	QVariant hideConsoleSetting = settings.value("autoHideConsole", kDefault_HideConsole);
608 	// Backwards compatibility to Tw 0.4.0 and before
609 	if (hideConsoleSetting.toString() == "true" || hideConsoleSetting.toString() == "false")
610 		hideConsoleSetting = (hideConsoleSetting.toBool() ? kDefault_HideConsole : 0);
611 	dlg.autoHideOutput->setCurrentIndex(hideConsoleSetting.toInt());
612 
613 	// Scripts
614 	dlg.allowScriptFileReading->setChecked(settings.value("allowScriptFileReading", kDefault_AllowScriptFileReading).toBool());
615 	dlg.allowScriptFileWriting->setChecked(settings.value("allowScriptFileWriting", kDefault_AllowScriptFileWriting).toBool());
616 	dlg.allowSystemCommands->setChecked(settings.value("allowSystemCommands", kDefault_AllowSystemCommands).toBool());
617 	dlg.enableScriptingPlugins->setChecked(settings.value("enableScriptingPlugins", kDefault_EnableScriptingPlugins).toBool());
618 	// there is always at least JSScriptInterface
619 	if (TWApp::instance()->getScriptManager()->languages().size() <= 1)
620 		dlg.enableScriptingPlugins->setEnabled(false);
621 	dlg.scriptDebugger->setChecked(settings.value("scriptDebugger", kDefault_ScriptDebugger).toBool());
622 #if QT_VERSION < 0x040500
623 	dlg.scriptDebugger->setEnabled(false);
624 #endif
625 
626 	// Decide which tab to select initially
627 	if (sCurrentTab == -1) {
628 		if (parent && parent->inherits("TeXDocument"))
629 			sCurrentTab = 1;
630 		else if (parent && parent->inherits("PDFDocument"))
631 			sCurrentTab = 2;
632 		else
633 			sCurrentTab = 0;
634 	}
635 	if (sCurrentTab != dlg.tabWidget->currentIndex())
636 		dlg.tabWidget->setCurrentIndex(sCurrentTab);
637 
638 	dlg.show();
639 
640 	DialogCode	result = (DialogCode)dlg.exec();
641 
642 	if (result == Accepted) {
643 		sCurrentTab = dlg.tabWidget->currentIndex();
644 
645 		// General
646 		int iconSize = 2;
647 		if (dlg.smallIcons->isChecked())
648 			iconSize = 1;
649 		else if (dlg.largeIcons->isChecked())
650 			iconSize = 3;
651 		bool showText = dlg.showText->isChecked();
652 		if (iconSize != oldIconSize || showText != oldShowText) {
653 			settings.setValue("toolBarIconSize", iconSize);
654 			settings.setValue("toolBarShowText", showText);
655 			foreach (QWidget *widget, qApp->topLevelWidgets()) {
656 				QMainWindow *theWindow = qobject_cast<QMainWindow*>(widget);
657 				if (theWindow != NULL)
658 					TWUtils::applyToolbarOptions(theWindow, iconSize, showText);
659 			}
660 		}
661 
662 		int launchOption = 1;
663 		if (dlg.templateDialog->isChecked())
664 			launchOption = 2;
665 		else if (dlg.openDialog->isChecked())
666 			launchOption = 3;
667 		settings.setValue("launchOption", launchOption);
668 
669 		settings.setValue("openPDFwithTeX", dlg.openPDFwithTeX->isChecked());
670 
671 		if (dlg.localePopup->currentIndex() != oldLocaleIndex) {
672 			switch (dlg.localePopup->currentIndex()) {
673 				case kSystemLocaleIndex: // system locale
674 					{
675 						QString locale = QLocale::system().name();
676 						TWApp::instance()->applyTranslation(locale);
677 						settings.remove("locale");
678 					}
679 					break;
680 				default:
681 					{
682 						QString locale = trList->at(dlg.localePopup->currentIndex() - kFirstTranslationIndex);
683 						TWApp::instance()->applyTranslation(locale);
684 						settings.setValue("locale", locale);
685 					}
686 					break;
687 			}
688 		}
689 
690 		// Editor
691 		settings.setValue("syntaxColoring", dlg.syntaxColoring->currentText());
692 		settings.setValue("autoIndent", dlg.autoIndent->currentText());
693 		settings.setValue("smartQuotes", dlg.smartQuotes->currentText());
694 		settings.setValue("lineNumbers", dlg.lineNumbers->isChecked());
695 		settings.setValue("wrapLines", dlg.wrapLines->isChecked());
696 		settings.setValue("tabWidth", dlg.tabWidth->value());
697 		font = QFont(dlg.editorFont->currentText());
698 		font.setPointSize(dlg.fontSize->value());
699 		settings.setValue("font", font.toString());
700 		TWApp::instance()->setDefaultCodec(QTextCodec::codecForName(dlg.encoding->currentText().toLatin1()));
701 		if (dlg.language->currentIndex() >= 0) {
702 			QVariant data = dlg.language->itemData(dlg.language->currentIndex());
703 			if (data.isValid())
704 				settings.setValue("language", data);
705 			else
706 				settings.setValue("language", "None");
707 		}
708 		else
709 			settings.setValue("language", "None");
710 		bool highlightLine = dlg.highlightCurrentLine->isChecked();
711 		settings.setValue("highlightCurrentLine", highlightLine);
712 		CompletingEdit::setHighlightCurrentLine(highlightLine);
713 
714 		bool autocompleteEnabled = dlg.autocompleteEnabled->isChecked();
715 		settings.setValue("autocompleteEnabled", autocompleteEnabled);
716 		CompletingEdit::setAutocompleteEnabled(autocompleteEnabled);
717 
718 		// Since the tab width can't be set by any other means, forcibly update
719 		// all windows now
720 		foreach (QWidget* widget, TWApp::instance()->allWidgets()) {
721 			QTextEdit* editor = qobject_cast<QTextEdit*>(widget);
722 			if (editor)
723 			    editor->setTabStopWidth(dlg.tabWidth->value());
724 		}
725 
726 		// Preview
727 		int scaleOption = 1;
728 		if (dlg.fitWidth->isChecked())
729 			scaleOption = 2;
730 		else if (dlg.fitWindow->isChecked())
731 			scaleOption = 3;
732 		else if (dlg.fixedScale->isChecked())
733 			scaleOption = 4;
734 		int scale = dlg.scale->value();
735 		settings.setValue("scaleOption", scaleOption);
736 		settings.setValue("previewScale", scale);
737 		switch (dlg.pdfPageMode->currentIndex()) {
738 			case 0:
739 				settings.setValue("pdfPageMode", QtPDF::PDFDocumentView::PageMode_SinglePage);
740 				break;
741 			case 1:
742 				settings.setValue("pdfPageMode", QtPDF::PDFDocumentView::PageMode_OneColumnContinuous);
743 				break;
744 			case 2:
745 				settings.setValue("pdfPageMode", QtPDF::PDFDocumentView::PageMode_TwoColumnContinuous);
746 				break;
747 		}
748 
749 		double resolution = dlg.resolution->dpi();
750 		if (resolution != oldResolution) {
751 			settings.setValue("previewResolution", resolution);
752 			foreach (QWidget *widget, qApp->topLevelWidgets()) {
753 				PDFDocument *thePdfDoc = qobject_cast<PDFDocument*>(widget);
754 				if (thePdfDoc != NULL)
755 					thePdfDoc->setResolution(resolution);
756 			}
757 		}
758 
759 		int magSize = 2;
760 		if (dlg.smallMag->isChecked())
761 			magSize = 1;
762 		else if (dlg.largeMag->isChecked())
763 			magSize = 3;
764 		settings.setValue("magnifierSize", magSize);
765 		bool circular = dlg.circularMag->isChecked();
766 		settings.setValue("circularMagnifier", circular);
767 		if (oldMagSize != magSize || oldCircular != circular) {
768 			foreach (QWidget *widget, qApp->topLevelWidgets()) {
769 				PDFDocument *thePdfDoc = qobject_cast<PDFDocument*>(widget);
770 				if (thePdfDoc != NULL)
771 					thePdfDoc->resetMagnifier();
772 			}
773 		}
774 
775 		// Typesetting
776 		if (dlg.pathsChanged) {
777 			QStringList paths;
778 			for (int i = 0; i < dlg.binPathList->count(); ++i)
779 				paths << dlg.binPathList->item(i)->text();
780 			TWApp::instance()->setBinaryPaths(paths);
781 		}
782 		if (dlg.toolsChanged)
783 			TWApp::instance()->setEngineList(dlg.engineList);
784 		TWApp::instance()->setDefaultEngine(dlg.defaultTool->currentText());
785 		settings.setValue("autoHideConsole", dlg.autoHideOutput->currentIndex());
786 
787 		// Scripts
788 		settings.setValue("allowScriptFileReading", dlg.allowScriptFileReading->isChecked());
789 		settings.setValue("allowScriptFileWriting", dlg.allowScriptFileWriting->isChecked());
790 		settings.setValue("allowSystemCommands", dlg.allowSystemCommands->isChecked());
791 		settings.setValue("enableScriptingPlugins", dlg.enableScriptingPlugins->isChecked());
792 		settings.setValue("scriptDebugger", dlg.scriptDebugger->isChecked());
793 		// with changed settings, the availability of scripts may have changed
794 		// (e.g., because of enabling/disabling the use of scripting plugins)
795 		TWApp::instance()->updateScriptsList();
796 	}
797 
798 	return result;
799 }
800 
801 int PrefsDialog::sCurrentTab = -1;
802 
ToolConfig(QWidget * parent)803 ToolConfig::ToolConfig(QWidget *parent)
804 	: QDialog(parent)
805 {
806 	init();
807 }
808 
init()809 void ToolConfig::init()
810 {
811 	setupUi(this);
812 
813 	connect(arguments, SIGNAL(itemSelectionChanged()), this, SLOT(updateArgButtons()));
814 	connect(argUp, SIGNAL(clicked()), this, SLOT(moveArgUp()));
815 	connect(argDown, SIGNAL(clicked()), this, SLOT(moveArgDown()));
816 	connect(argAdd, SIGNAL(clicked()), this, SLOT(addArg()));
817 	connect(argRemove, SIGNAL(clicked()), this, SLOT(removeArg()));
818 	connect(btnBrowseForProgram, SIGNAL(clicked()), this, SLOT(browseForProgram()));
819 }
820 
browseForProgram()821 void ToolConfig::browseForProgram()
822 {
823 	QFileInfo info(program->text());
824 	QString str = QFileDialog::getOpenFileName(this, tr("Select program file"),
825 											   info.exists() ? info.canonicalFilePath() : QString());
826 	if (!str.isNull()) {
827 		info.setFile(str);
828 		if (!info.isExecutable()) {
829 			QMessageBox::warning(this, tr("Invalid program"),
830 								 tr("The file '%1' is not executable!").arg(info.fileName()));
831 			return;
832 		}
833 		program->setText(info.canonicalFilePath());
834 	}
835 }
836 
updateArgButtons()837 void ToolConfig::updateArgButtons()
838 {
839 	int selRow = -1;
840 	if (arguments->selectedItems().count() > 0)
841 		selRow = arguments->currentRow();
842 	argRemove->setEnabled(selRow != -1);
843 	argUp->setEnabled(selRow > 0);
844 	argDown->setEnabled(selRow != -1 && selRow < arguments->count() - 1);
845 }
846 
moveArgUp()847 void ToolConfig::moveArgUp()
848 {
849 	int selRow = -1;
850 	if (arguments->selectedItems().count() > 0)
851 		selRow = arguments->currentRow();
852 	if (selRow > 0) {
853 		QListWidgetItem *item = arguments->takeItem(selRow);
854 		arguments->insertItem(selRow - 1, item);
855 		arguments->setCurrentItem(arguments->item(selRow - 1));
856 	}
857 }
858 
moveArgDown()859 void ToolConfig::moveArgDown()
860 {
861 	int selRow = -1;
862 	if (arguments->selectedItems().count() > 0)
863 		selRow = arguments->currentRow();
864 	if (selRow != -1 &&  selRow < arguments->count() - 1) {
865 		QListWidgetItem *item = arguments->takeItem(selRow);
866 		arguments->insertItem(selRow + 1, item);
867 		arguments->setCurrentItem(arguments->item(selRow + 1));
868 	}
869 }
870 
addArg()871 void ToolConfig::addArg()
872 {
873 	arguments->addItem(tr("NewArgument"));
874 	QListWidgetItem* item = arguments->item(arguments->count() - 1);
875 	item->setFlags(item->flags() | Qt::ItemIsEditable);
876 	arguments->setCurrentItem(item);
877 	arguments->editItem(item);
878 }
879 
removeArg()880 void ToolConfig::removeArg()
881 {
882 	if (arguments->currentRow() > -1)
883 		if (arguments->currentItem()->isSelected())
884 			arguments->takeItem(arguments->currentRow());
885 }
886 
doToolConfig(QWidget * parent,Engine & engine)887 QDialog::DialogCode ToolConfig::doToolConfig(QWidget *parent, Engine &engine)
888 {
889 	ToolConfig dlg(parent);
890 
891 	dlg.toolName->setText(engine.name());
892 	dlg.program->setText(engine.program());
893 	dlg.arguments->addItems(engine.arguments());
894 	for (int i = 0; i < dlg.arguments->count(); ++i) {
895 		QListWidgetItem *item = dlg.arguments->item(i);
896 		item->setFlags(item->flags() | Qt::ItemIsEditable);
897 	}
898 	dlg.viewPdf->setChecked(engine.showPdf());
899 
900 	dlg.show();
901 
902 	DialogCode	result = (DialogCode)dlg.exec();
903 	if (result == Accepted) {
904 		dlg.arguments->setCurrentItem(NULL); // ensure editing is terminated
905 		engine.setName(dlg.toolName->text());
906 		engine.setProgram(dlg.program->text());
907 		QStringList args;
908 		for (int i = 0; i < dlg.arguments->count(); ++i)
909 			args << dlg.arguments->item(i)->text();
910 		engine.setArguments(args);
911 		engine.setShowPdf(dlg.viewPdf->isChecked());
912 	}
913 
914 	return result;
915 }
916