~ubuntu-branches/debian/stretch/universalindentgui/stretch

« back to all changes in this revision

Viewing changes to src/mainwindow.cpp~

  • Committer: Bazaar Package Importer
  • Author(s): Fathi Boudra
  • Date: 2009-08-20 13:41:45 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20090820134145-g5wu2b87qz1i9sy9
Tags: 1.1.0-1
* New upstream release.
* Update debian/control:
  - Bump quilt and debhelper build-dependency versions.
  - Bump Standards-Version to 3.8.3 (no changes needed).
* Convert debian/rules to dh usage.
* Rename debian/universalindentgui.lintian to
  debian/universalindentgui.lintian-overrides for dh_lintian usage.
* Add debian/README.source file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
 *   Copyright (C) 2006-2008 by Thomas Schweitzer                          *
 
3
 *   thomas-schweitzer(at)arcor.de                                         *
 
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 version 2.0 as   *
 
7
 *   published by the Free Software Foundation.                            *
 
8
 *                                                                         *
 
9
 *   This program is distributed in the hope that it will be useful,       *
 
10
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 
11
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 
12
 *   GNU General Public License for more details.                          *
 
13
 *                                                                         *
 
14
 *   You should have received a copy of the GNU General Public License     *
 
15
 *   along with this program in the file LICENSE.GPL; if not, write to the *
 
16
 *   Free Software Foundation, Inc.,                                       *
 
17
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 
18
 ***************************************************************************/
 
19
 
 
20
#include "mainwindow.h"
 
21
 
 
22
//! \defgroup grp_MainWindow All concerning main window functionality.
 
23
 
 
24
/*!
 
25
    \class MainWindow
 
26
    \ingroup grp_MainWindow
 
27
    \brief Is the main window of UniversalIndentGUI
 
28
 
 
29
    The MainWindow class is responsible for generating and displaying most of the gui elements.
 
30
    Its look is set in the file "mainwindow.ui". An object for the indent handler is generated here
 
31
    and user actions are being controlled. Is responsible for file open dialogs and indenter selection.
 
32
 */
 
33
 
 
34
/*!
 
35
    \brief Constructs the main window.
 
36
 */
 
37
MainWindow::MainWindow(QString file2OpenOnStart, QWidget *parent) : QMainWindow(parent) {
 
38
    // set the program version, revision and date, which is shown in the main window title and in the about dialog.
 
39
    version = "1.0.1";
 
40
    revision = "854";
 
41
    QDate buildDate(2008, 10, 20);
 
42
    buildDateStr = buildDate.toString("d. MMMM yyyy");
 
43
 
 
44
    // Init of some variables.
 
45
    sourceCodeChanged = false;
 
46
    scrollPositionChanged = false;
 
47
 
 
48
    // Create the settings object, which loads all UiGui settings from a file.
 
49
        settings = UiguiSettings::getInstance();
 
50
 
 
51
    // Initialize the language of the application.
 
52
    initApplicationLanguage();
 
53
 
 
54
    // Creates the main window and initializes it.
 
55
    initMainWindow();
 
56
 
 
57
    // Create toolbar and insert it into the main window.
 
58
    initToolBar();
 
59
 
 
60
    // Create the text edit component using the QScintilla widget.
 
61
    initTextEditor();
 
62
 
 
63
    // Create and init the syntax highlighter.
 
64
    initSyntaxHighlighter();
 
65
 
 
66
    // Create and init the indenter.
 
67
    initIndenter();
 
68
 
 
69
    // Create some menus.
 
70
    createEncodingMenu();
 
71
    createHighlighterMenu();
 
72
        
 
73
 
 
74
    // generate about dialog box
 
75
    aboutDialog = new AboutDialog(this, Qt::SplashScreen, version, revision, buildDateStr);
 
76
    aboutDialogGraphicsView = new AboutDialogGraphicsView(aboutDialog, this);
 
77
    connect( toolBarWidget->pbAbout, SIGNAL(clicked()), this, SLOT(showAboutDialog()) );
 
78
    connect( actionAbout_UniversalIndentGUI, SIGNAL(triggered()), this, SLOT(showAboutDialog()) );
 
79
 
 
80
        // generate settings dialog box
 
81
        settingsDialog = new UiguiSettingsDialog(this, settings);
 
82
    connect( actionShowSettings, SIGNAL(triggered()), settingsDialog, SLOT(showDialog()) );
 
83
 
 
84
    // If a file that should be opened on start has been handed over to the constructor exists, load it
 
85
    if ( QFile::exists(file2OpenOnStart) ) {
 
86
        openSourceFileDialog(file2OpenOnStart);
 
87
    }
 
88
    // Otherwise load the last opened file, if this is enabled in the settings.
 
89
    else {
 
90
        loadLastOpenedFile();
 
91
    }
 
92
 
 
93
    updateSourceView();
 
94
 
 
95
    // Check if a newer version is available but only if the setting for that is enabled and today not already a check has been done.
 
96
    if ( settings->getValueByName("CheckForUpdate").toBool() && QDate::currentDate() != settings->getValueByName("LastUpdateCheck").toDate() ) {
 
97
        updateCheckDialog->checkForUpdate();
 
98
    }
 
99
 
 
100
    // Enable accept dropping of files.
 
101
    setAcceptDrops(true);
 
102
}
 
103
 
 
104
 
 
105
/*!
 
106
    \brief Initializes the main window by creating the main gui and make some settings.
 
107
 */
 
108
void MainWindow::initMainWindow() {
 
109
           // Generate gui as it is build in the file "mainwindow.ui"
 
110
    setupUi(this);
 
111
 
 
112
        // Handle last opened window size
 
113
        // ------------------------------
 
114
        bool maximized = settings->getValueByName("WindowIsMaximized").toBool();
 
115
        QPoint pos = settings->getValueByName("WindowPosition").toPoint();
 
116
        QSize size = settings->getValueByName("WindowSize").toSize();
 
117
        resize(size);
 
118
        move(pos);
 
119
        if ( maximized ) {
 
120
                showMaximized();
 
121
        }
 
122
#ifndef Q_OS_MAC // On Mac restoring the window state causes the screenshot no longer to work.
 
123
    restoreState( settings->getValueByName("MainWindowState").toByteArray() );
 
124
#endif
 
125
 
 
126
    // Handle if first run of this version
 
127
    // -----------------------------------
 
128
    QString readVersion = settings->getValueByName("VersionInSettingsFile").toString();
 
129
        // If version strings are not equal set first run true.
 
130
        if ( readVersion != version ) {
 
131
                isFirstRunOfThisVersion = true;
 
132
        }
 
133
        else {
 
134
                isFirstRunOfThisVersion = false;
 
135
        }
 
136
 
 
137
    // Get last selected file encoding
 
138
        // -------------------------------
 
139
        currentEncoding = settings->getValueByName("FileEncoding").toString();
 
140
 
 
141
    updateCheckDialog = new UpdateCheckDialog(version, settings, this);
 
142
 
 
143
    // Register the syntax highlightning setting in the menu to the settings object.
 
144
    connect( enableSyntaxHighlightningAction, SIGNAL(toggled(bool)), settings, SLOT(handleValueChangeFromExtern(bool)) );
 
145
    connect( settings, SIGNAL(syntaxHighlightningEnabled(bool)), enableSyntaxHighlightningAction, SLOT(setChecked(bool)) );
 
146
    enableSyntaxHighlightningAction->setChecked( settings->getValueByName("SyntaxHighlightningEnabled").toBool() );
 
147
    // Tell the highlighter if it has to be enabled or disabled.
 
148
    connect( settings, SIGNAL(syntaxHighlightningEnabled(bool)), this, SLOT(turnHighlightOnOff(bool)) );
 
149
 
 
150
    // Register the load last file setting in the menu to the settings object.
 
151
    connect( loadLastOpenedFileOnStartupAction, SIGNAL(toggled(bool)), settings, SLOT(handleValueChangeFromExtern(bool)) );
 
152
    connect( settings, SIGNAL(loadLastOpenedFileOnStartup(bool)), loadLastOpenedFileOnStartupAction, SLOT(setChecked(bool)) );
 
153
    loadLastOpenedFileOnStartupAction->setChecked( settings->getValueByName("LoadLastOpenedFileOnStartup").toBool() );
 
154
 
 
155
    // Register the white space setting in the menu to the settings object.
 
156
    connect( whiteSpaceIsVisibleAction, SIGNAL(toggled(bool)), settings, SLOT(handleValueChangeFromExtern(bool)) );
 
157
    connect( settings, SIGNAL(whiteSpaceIsVisible(bool)), whiteSpaceIsVisibleAction, SLOT(setChecked(bool)) );
 
158
    whiteSpaceIsVisibleAction->setChecked( settings->getValueByName("WhiteSpaceIsVisible").toBool() );
 
159
    // Tell the QScintilla editor if it has to show white space.
 
160
    connect( settings, SIGNAL(whiteSpaceIsVisible(bool)), this, SLOT(setWhiteSpaceVisibility(bool)) );
 
161
 
 
162
    // Connect the remaining menu items.
 
163
    connect( actionOpen_Source_File, SIGNAL(triggered()), this, SLOT(openSourceFileDialog()) );
 
164
    connect( actionSave_Source_File_As, SIGNAL(triggered()), this, SLOT(saveasSourceFileDialog()) );
 
165
    connect( actionSave_Source_File, SIGNAL(triggered()), this, SLOT(saveSourceFile()) );
 
166
    connect( actionExportPDF, SIGNAL(triggered()), this, SLOT(exportToPDF()) );
 
167
    connect( actionExportHTML, SIGNAL(triggered()), this, SLOT(exportToHTML()) );
 
168
    connect( actionCheck_for_update, SIGNAL(triggered()), updateCheckDialog, SLOT(checkForUpdateAndShowDialog()) );
 
169
 
 
170
    // Init the menu for selecting one of the recently opened files.
 
171
    updateRecentlyOpenedList();
 
172
    connect( menuRecently_Opened_Files, SIGNAL(triggered(QAction*)), this, SLOT(openFileFromRecentlyOpenedList(QAction*)) );
 
173
    connect( settings, SIGNAL(recentlyOpenedListSize(int)), this, SLOT(updateRecentlyOpenedList()) );
 
174
}
 
175
 
 
176
 
 
177
/*!
 
178
    \brief Creates and inits the tool bar. It is added to the main window.
 
179
 */
 
180
void MainWindow::initToolBar() {
 
181
    // Create the tool bar and add it to the main window.
 
182
    toolBarWidget = new Ui::toolBarWidget();
 
183
    QWidget* helpWidget = new QWidget();
 
184
    toolBarWidget->setupUi(helpWidget);
 
185
    toolBar->addWidget(helpWidget);
 
186
    toolBar->setAllowedAreas( Qt::TopToolBarArea | Qt::BottomToolBarArea );
 
187
 
 
188
    // Connect the tool bar widgets to their functions.
 
189
    connect( toolBarWidget->enableSyntaxHighlightningCheckBox, SIGNAL(toggled(bool)), settings, SLOT(handleValueChangeFromExtern(bool)) );
 
190
    connect( settings, SIGNAL(syntaxHighlightningEnabled(bool)), toolBarWidget->enableSyntaxHighlightningCheckBox, SLOT(setChecked(bool)) );
 
191
    toolBarWidget->enableSyntaxHighlightningCheckBox->setChecked( settings->getValueByName("SyntaxHighlightningEnabled").toBool() );
 
192
    toolBarWidget->enableSyntaxHighlightningCheckBox->hide();
 
193
    connect( toolBarWidget->pbOpen_Source_File, SIGNAL(clicked()), this, SLOT(openSourceFileDialog()) );
 
194
    connect( toolBarWidget->pbExit, SIGNAL(clicked()), this, SLOT(close()));
 
195
    connect( toolBarWidget->cbLivePreview, SIGNAL(toggled(bool)), this, SLOT(previewTurnedOnOff(bool)) );
 
196
    connect( toolBarWidget->cbLivePreview, SIGNAL(toggled(bool)), actionLive_Indent_Preview, SLOT(setChecked(bool)) );
 
197
    connect( actionLive_Indent_Preview, SIGNAL(toggled(bool)), toolBarWidget->cbLivePreview, SLOT(setChecked(bool)) );
 
198
}
 
199
 
 
200
 
 
201
/*!
 
202
    \brief Create and initialize the text editor component. It uses the QScintilla widget.
 
203
 */
 
204
void MainWindow::initTextEditor() {
 
205
 
 
206
    QMessageBox infoQScintillaLoad(NULL);
 
207
    infoQScintillaLoad.setWindowTitle("Loading QScintilla...");
 
208
    infoQScintillaLoad.setText("Trying to load QScintilla library.\nIf anything fails during loading, it might be possible that the debug and release version of QScintilla are mixed.");
 
209
    infoQScintillaLoad.show();
 
210
    // Create the QScintilla widget and add it to the layout.
 
211
    // Try and catch doesn't seem to catch the runtime error when starting UiGUI release with QScintilla debug lib and the other way around.
 
212
    try {
 
213
        qSciSourceCodeEditor = new QsciScintilla(this);
 
214
    }
 
215
    catch (...) {
 
216
        QMessageBox::critical(this, "Error creating QScintilla text editor component!", 
 
217
            "During trying to create the text editor component, that is based on QScintilla, an error occurred. Please make sure that you have installed QScintilla and not mixed release and debug versions." );
 
218
        exit(1);
 
219
    }
 
220
    infoQScintillaLoad.hide();
 
221
 
 
222
        hboxLayout1->addWidget(qSciSourceCodeEditor);
 
223
 
 
224
    // Make some settings for the QScintilla widget.
 
225
    qSciSourceCodeEditor->setUtf8(true);
 
226
    qSciSourceCodeEditor->setMarginLineNumbers(1, true);
 
227
        qSciSourceCodeEditor->setMarginWidth(1, QString("10000") );
 
228
        qSciSourceCodeEditor->setBraceMatching(qSciSourceCodeEditor->SloppyBraceMatch);
 
229
        qSciSourceCodeEditor->setMatchedBraceForegroundColor( QColor("red") );
 
230
        qSciSourceCodeEditor->setFolding(QsciScintilla::BoxedTreeFoldStyle);
 
231
        qSciSourceCodeEditor->setAutoCompletionSource(QsciScintilla::AcsAll);
 
232
        qSciSourceCodeEditor->setAutoCompletionThreshold(3);
 
233
 
 
234
    // Handle if white space is set to be visible
 
235
        bool whiteSpaceIsVisible = settings->getValueByName("WhiteSpaceIsVisible").toBool();
 
236
    setWhiteSpaceVisibility( whiteSpaceIsVisible );
 
237
 
 
238
    // Handle the width of tabs in spaces
 
239
    int tabWidth = settings->getValueByName("TabWidth").toInt();
 
240
    qSciSourceCodeEditor->setTabWidth(tabWidth);
 
241
 
 
242
    // Remember a pointer to the scrollbar of the QScintilla widget used to keep
 
243
    // on the same line as before when turning preview on/off.
 
244
    textEditVScrollBar = qSciSourceCodeEditor->verticalScrollBar();
 
245
 
 
246
    // Add a column row indicator to the status bar.
 
247
    textEditLineColumnInfoLabel = new QLabel( tr("Line %1, Column %2").arg(1).arg(1) );
 
248
    statusbar->addPermanentWidget(textEditLineColumnInfoLabel);
 
249
    connect( qSciSourceCodeEditor, SIGNAL(cursorPositionChanged(int, int)), this, SLOT(setStatusBarCursorPosInfo(int, int)) );
 
250
 
 
251
    // Connect the text editor to dependent functions.
 
252
    connect( qSciSourceCodeEditor, SIGNAL(textChanged()), this, SLOT(sourceCodeChangedHelperSlot()) );
 
253
        connect( qSciSourceCodeEditor, SIGNAL(linesChanged()), this, SLOT(numberOfLinesChanged()) );
 
254
    connect( settings, SIGNAL(tabWidth(int)), qSciSourceCodeEditor, SLOT(setTabWidth(int)) );
 
255
    qSciSourceCodeEditor->setTabWidth( settings->getValueByName("TabWidth").toInt() );
 
256
}
 
257
 
 
258
 
 
259
/*!
 
260
    \brief Create and init the syntax highlighter and set it to use the QScintilla edit component.
 
261
 */
 
262
void MainWindow::initSyntaxHighlighter() {
 
263
    // Create the highlighter.
 
264
    highlighter = new UiguiHighlighter(qSciSourceCodeEditor);
 
265
 
 
266
    // Handle if syntax highlighting is enabled
 
267
        bool syntaxHighlightningEnabled = settings->getValueByName("SyntaxHighlightningEnabled").toBool();
 
268
        if ( syntaxHighlightningEnabled ) {
 
269
        highlighter->turnHighlightOn();
 
270
    }
 
271
    else {
 
272
        highlighter->turnHighlightOff();
 
273
    }
 
274
}
 
275
 
 
276
 
 
277
/*!
 
278
    \brief Initializes the language of UniversalIndentGUI.
 
279
 
 
280
    If the program language is defined in the settings, the corresponding language
 
281
    file will be loaded and set for the application. If not set there, the system
 
282
    default language will be set, if a translation file for that language exists.
 
283
    Returns true, if the translation file could be loaded. Otherwise it returns
 
284
    false and uses the default language, which is English.
 
285
 */
 
286
bool MainWindow::initApplicationLanguage() {
 
287
    QString languageShort;
 
288
 
 
289
    // Get the language settings from the settings object.
 
290
        int languageIndex = settings->getValueByName("Language").toInt();
 
291
 
 
292
    // If no language was set, indicated by a negative index, use the system language.
 
293
    if ( languageIndex < 0 ) {
 
294
        languageShort = QLocale::system().name();
 
295
 
 
296
        // Chinese and Japanese language consist of country and language code.
 
297
        // For all others the language code will be cut off.
 
298
        if ( languageShort.left(2) != "zh" && languageShort.left(2) != "ja" ) {
 
299
            languageShort = languageShort.left(2);
 
300
        }
 
301
 
 
302
        // If no translation file for the systems local language exist, fall back to English.
 
303
        if ( settings->getAvailableTranslations().indexOf(languageShort) < 0 ) {
 
304
            languageShort = "en";
 
305
        }
 
306
 
 
307
        // Set the language setting to the new language.
 
308
        settings->setValueByName("Language", settings->getAvailableTranslations().indexOf(languageShort) );
 
309
    }
 
310
    // If a language was defined in the settings, get this language mnemonic.
 
311
    else {
 
312
        languageShort = settings->getAvailableTranslations().at(languageIndex);
 
313
    }
 
314
 
 
315
    // Load the Qt own translation file and set it for the application.
 
316
    qTTranslator = new QTranslator();
 
317
    bool translationFileLoaded;
 
318
    translationFileLoaded = qTTranslator->load( SettingsPaths::getGlobalFilesPath() + "/translations/qt_" + languageShort );
 
319
    if ( translationFileLoaded ) {
 
320
        qApp->installTranslator(qTTranslator);
 
321
    }
 
322
 
 
323
    // Load the uigui translation file and set it for the application.
 
324
    uiGuiTranslator = new QTranslator();
 
325
    translationFileLoaded = uiGuiTranslator->load( SettingsPaths::getGlobalFilesPath() + "/translations/universalindent_" + languageShort );
 
326
    if ( translationFileLoaded ) {
 
327
        qApp->installTranslator(uiGuiTranslator);
 
328
    }
 
329
 
 
330
    connect( settings, SIGNAL(language(int)), this, SLOT(languageChanged(int)) );
 
331
 
 
332
    return translationFileLoaded;
 
333
}
 
334
 
 
335
 
 
336
/*!
 
337
    \brief Creates and initializes the indenter.
 
338
 */
 
339
void MainWindow::initIndenter() {
 
340
    // Get Id of last selected indenter.
 
341
        currentIndenterID = settings->getValueByName("SelectedIndenter").toInt();
 
342
 
 
343
    // Create the indenter widget with the ID and add it to the layout.
 
344
    indentHandler = new IndentHandler(currentIndenterID, this, centralwidget);
 
345
    vboxLayout->addWidget(indentHandler);
 
346
 
 
347
    // If settings for the indenter have changed, let the main window know aboud it.
 
348
    connect(indentHandler, SIGNAL(indenterSettingsChanged()), this, SLOT(indentSettingsChangedSlot()));
 
349
 
 
350
    // Set this true, so the indenter is called at first program start
 
351
    indentSettingsChanged = true;
 
352
    previewToggled = true;
 
353
 
 
354
    // Handle if indenter parameter tool tips are enabled
 
355
    connect( indenterParameterTooltipsEnabledAction, SIGNAL(toggled(bool)), settings, SLOT(handleValueChangeFromExtern(bool)) );
 
356
    connect( settings, SIGNAL(indenterParameterTooltipsEnabled(bool)), indenterParameterTooltipsEnabledAction, SLOT(setChecked(bool)) );
 
357
    indenterParameterTooltipsEnabledAction->setChecked( settings->getValueByName("IndenterParameterTooltipsEnabled").toBool() );
 
358
 
 
359
    // Add the indenters context menu to the mainwindows menu.
 
360
    menuIndenter->addActions( indentHandler->getIndenterMenuActions() );
 
361
    
 
362
}
 
363
 
 
364
 
 
365
/*!
 
366
    \brief Tries to load the by \a filePath defined file and returns its content as QString.
 
367
 
 
368
    If the file could not be loaded a error dialog will be shown.
 
369
 */
 
370
QString MainWindow::loadFile(QString filePath) {
 
371
 
 
372
    QFile inSrcFile(filePath);
 
373
    QString fileContent = "";
 
374
 
 
375
    if ( !inSrcFile.open(QFile::ReadOnly | QFile::Text) ) {
 
376
        QMessageBox::warning(NULL, tr("Error opening file"), tr("Cannot read the file ")+"\""+filePath+"\"." );
 
377
    }
 
378
    else {
 
379
        QTextStream inSrcStrm(&inSrcFile);
 
380
        QApplication::setOverrideCursor(Qt::WaitCursor);
 
381
        inSrcStrm.setCodec( QTextCodec::codecForName(currentEncoding.toAscii()) );
 
382
        fileContent = inSrcStrm.readAll();
 
383
        QApplication::restoreOverrideCursor();
 
384
        inSrcFile.close();
 
385
 
 
386
                QFileInfo fileInfo(filePath);
 
387
                currentSourceFileExtension = fileInfo.suffix();
 
388
                int indexOfHighlighter = highlighter->setLexerForExtension( currentSourceFileExtension );
 
389
        highlighterActionGroup->actions().at(indexOfHighlighter)->setChecked(true);
 
390
    }
 
391
    return fileContent;
 
392
}
 
393
 
 
394
 
 
395
/*!
 
396
    \brief Calls the source file open dialog to load a source file for the formatting preview.
 
397
 
 
398
    If the file was successfully loaded the indenter will be called to generate the formatted source code.
 
399
 */
 
400
void MainWindow::openSourceFileDialog(QString fileName) {
 
401
    // If the source code file is changed and the shown dialog for saving the file
 
402
    // is canceled, also stop opening another source file.
 
403
    if ( !maybeSave() ) {
 
404
        return;
 
405
    }
 
406
    QString openedSourceFileContent = "";
 
407
    QString fileExtensions = tr("Supported by indenter")+" ("+indentHandler->getPossibleIndenterFileExtensions()+
 
408
                             ");;"+tr("All files")+" (*.*)";
 
409
 
 
410
    //QString openedSourceFileContent = openFileDialog( tr("Choose source code file"), "./", fileExtensions );
 
411
        if ( fileName.isEmpty() ) {
 
412
                fileName = QFileDialog::getOpenFileName( this, tr("Choose source code file"), currentSourceFile, fileExtensions);
 
413
        }
 
414
 
 
415
    if (fileName != "") {
 
416
        currentSourceFile = fileName;
 
417
        QFileInfo fileInfo(fileName);
 
418
        currentSourceFileExtension = fileInfo.suffix();
 
419
 
 
420
        openedSourceFileContent = loadFile(fileName);
 
421
        sourceFileContent = openedSourceFileContent;
 
422
        if ( toolBarWidget->cbLivePreview->isChecked() ) {
 
423
            callIndenter();
 
424
        }
 
425
        sourceCodeChanged = true;
 
426
        previewToggled = true;
 
427
        updateSourceView();
 
428
        updateWindowTitle();
 
429
        updateRecentlyOpenedList();
 
430
        textEditLastScrollPos = 0;
 
431
        textEditVScrollBar->setValue( textEditLastScrollPos );
 
432
 
 
433
        savedSourceContent = openedSourceFileContent;
 
434
        qSciSourceCodeEditor->setModified( false );
 
435
        setWindowModified( false );
 
436
    }
 
437
}
 
438
 
 
439
 
 
440
/*!
 
441
    \brief Calls the source file save as dialog to save a source file under a chosen name.
 
442
 
 
443
    If the file already exists and it should be overwritten, a warning is shown before.
 
444
 */
 
445
bool MainWindow::saveasSourceFileDialog(QAction *chosenEncodingAction) {
 
446
    QString encoding;
 
447
    QString fileExtensions = tr("Supported by indenter")+" ("+indentHandler->getPossibleIndenterFileExtensions()+
 
448
                             ");;"+tr("All files")+" (*.*)";
 
449
 
 
450
    //QString openedSourceFileContent = openFileDialog( tr("Choose source code file"), "./", fileExtensions );
 
451
    QString fileName = QFileDialog::getSaveFileName( this, tr("Save source code file"), currentSourceFile, fileExtensions);
 
452
 
 
453
    // Saving has been canceled if the filename is empty
 
454
    if ( fileName.isEmpty() ) {
 
455
        return false;
 
456
    }
 
457
 
 
458
    savedSourceContent = qSciSourceCodeEditor->text();
 
459
 
 
460
    currentSourceFile = fileName;
 
461
    QFile::remove(fileName);
 
462
    QFile outSrcFile(fileName);
 
463
    outSrcFile.open( QFile::ReadWrite | QFile::Text );
 
464
    
 
465
    // Get current encoding.
 
466
    if ( chosenEncodingAction != NULL ) {
 
467
        encoding = chosenEncodingAction->text();
 
468
    }
 
469
    else {
 
470
        encoding = encodingActionGroup->checkedAction()->text();
 
471
    }
 
472
    QTextStream outSrcStrm(&outSrcFile);
 
473
    outSrcStrm.setCodec( QTextCodec::codecForName(encoding.toAscii()) );
 
474
    outSrcStrm << savedSourceContent;
 
475
    outSrcFile.close();
 
476
 
 
477
    QFileInfo fileInfo(fileName);
 
478
    currentSourceFileExtension = fileInfo.suffix();
 
479
 
 
480
    qSciSourceCodeEditor->setModified( false );
 
481
    setWindowModified( false );
 
482
 
 
483
    updateWindowTitle();
 
484
    return true;
 
485
}
 
486
 
 
487
 
 
488
/*!
 
489
    \brief Saves the currently shown source code to the last save or opened source file.
 
490
 
 
491
    If no source file has been opened, because only the static example has been loaded,
 
492
    the save as file dialog will be shown.
 
493
 */
 
494
bool MainWindow::saveSourceFile() {
 
495
    if ( currentSourceFile.isEmpty() ) {
 
496
        return saveasSourceFileDialog();
 
497
    }
 
498
    else {
 
499
        QFile::remove(currentSourceFile);
 
500
        QFile outSrcFile(currentSourceFile);
 
501
        savedSourceContent = qSciSourceCodeEditor->text();
 
502
        outSrcFile.open( QFile::ReadWrite | QFile::Text );
 
503
 
 
504
        // Get current encoding.
 
505
        QString currentEncoding = encodingActionGroup->checkedAction()->text();
 
506
        QTextStream outSrcStrm(&outSrcFile);
 
507
        outSrcStrm.setCodec( QTextCodec::codecForName(currentEncoding.toAscii()) );
 
508
        outSrcStrm << savedSourceContent;
 
509
        outSrcFile.close();
 
510
 
 
511
        qSciSourceCodeEditor->setModified( false );
 
512
        setWindowModified( false );
 
513
    }
 
514
    return true;
 
515
}
 
516
 
 
517
 
 
518
/*!
 
519
    \brief Shows a file open dialog.
 
520
 
 
521
    Shows a file open dialog with the title \a dialogHeaderStr starting in the directory \a startPath
 
522
    and with a file mask defined by \a fileMaskStr. Returns the contents of the file as QString.
 
523
 */
 
524
QString MainWindow::openFileDialog(QString dialogHeaderStr, QString startPath, QString fileMaskStr) {
 
525
 
 
526
    QString fileContent = "";
 
527
 
 
528
    QString fileName = QFileDialog::getOpenFileName( NULL, dialogHeaderStr, startPath, fileMaskStr);
 
529
 
 
530
    if (fileName != "") {
 
531
        fileContent = loadFile(fileName);
 
532
    }
 
533
 
 
534
    return fileContent;
 
535
}
 
536
 
 
537
 
 
538
/*!
 
539
    \brief Updates the displaying of the source code.
 
540
 
 
541
    Updates the text edit field, which is showing the loaded, and if preview is enabled formatted, source code.
 
542
    Reassigns the line numbers and in case of switch between preview and none preview keeps the text field
 
543
    at the same line number.
 
544
 */
 
545
void MainWindow::updateSourceView()
 
546
{
 
547
    textEditLastScrollPos = textEditVScrollBar->value();
 
548
 
 
549
    if ( toolBarWidget->cbLivePreview->isChecked() ) {
 
550
        sourceViewContent = sourceFormattedContent;
 
551
    }
 
552
    else {
 
553
        sourceViewContent = sourceFileContent;
 
554
    }
 
555
 
 
556
    if (previewToggled) {
 
557
        disconnect( qSciSourceCodeEditor, SIGNAL(textChanged ()), this, SLOT(sourceCodeChangedHelperSlot()) );
 
558
                bool textIsModified = isWindowModified();
 
559
        qSciSourceCodeEditor->setText(sourceViewContent);
 
560
                setWindowModified(textIsModified);
 
561
        previewToggled = false;
 
562
        connect( qSciSourceCodeEditor, SIGNAL(textChanged ()), this, SLOT(sourceCodeChangedHelperSlot()) );
 
563
    }
 
564
 
 
565
    textEditVScrollBar->setValue( textEditLastScrollPos );
 
566
}
 
567
 
 
568
 
 
569
/*!
 
570
    \brief Calls the selected indenter with the currently loaded source code to retrieve the formatted source code.
 
571
 
 
572
    The original loaded source code file will not be changed.
 
573
 */
 
574
void MainWindow::callIndenter() {
 
575
    QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
 
576
    sourceFormattedContent = indentHandler->callIndenter(sourceFileContent, currentSourceFileExtension);
 
577
    //updateSourceView();
 
578
    QApplication::restoreOverrideCursor();
 
579
}
 
580
 
 
581
 
 
582
/*!
 
583
    \brief Switches the syntax highlighting corresponding to the value \a turnOn either on or off.
 
584
 */
 
585
void MainWindow::turnHighlightOnOff(bool turnOn) {
 
586
    if ( turnOn ) {
 
587
        highlighter->turnHighlightOn();
 
588
    }
 
589
    else {
 
590
        highlighter->turnHighlightOff();
 
591
    }
 
592
    previewToggled = true;
 
593
    updateSourceView();
 
594
}
 
595
 
 
596
 
 
597
/*!
 
598
    \brief Added this slot to avoid multiple calls because of changed text.
 
599
 */
 
600
void MainWindow::sourceCodeChangedHelperSlot() {
 
601
        QTimer::singleShot(0, this, SLOT(sourceCodeChangedSlot()));
 
602
}
 
603
 
 
604
 
 
605
/*!
 
606
    \brief Is emitted whenever the text inside the source view window changes. Calls the indenter
 
607
    to format the changed source code.
 
608
 */
 
609
void MainWindow::sourceCodeChangedSlot() {
 
610
    QChar enteredCharacter;
 
611
        int cursorPos, cursorPosAbsolut, cursorLine;
 
612
        QString text;
 
613
 
 
614
    sourceCodeChanged = true;
 
615
    if ( scrollPositionChanged ) {
 
616
        scrollPositionChanged = false;
 
617
    }
 
618
 
 
619
    // Get the content text of the text editor.
 
620
    sourceFileContent = qSciSourceCodeEditor->text();
 
621
        
 
622
    // Get the position of the cursor in the unindented text.
 
623
    if ( sourceFileContent.isEmpty() ) {
 
624
        // Add this line feed, because AStyle has problems with a totally emtpy file.
 
625
        sourceFileContent += "\n";
 
626
        cursorPosAbsolut = 0;
 
627
        cursorPos = 0;
 
628
        cursorLine = 0;
 
629
        enteredCharacter = sourceFileContent.at(cursorPosAbsolut);
 
630
    }
 
631
    else {
 
632
        qSciSourceCodeEditor->getCursorPosition(&cursorLine, &cursorPos);
 
633
        cursorPosAbsolut = qSciSourceCodeEditor->SendScintilla(QsciScintillaBase::SCI_GETCURRENTPOS);
 
634
            text = qSciSourceCodeEditor->text(cursorLine);
 
635
        if ( cursorPosAbsolut > 0 ) {
 
636
            cursorPosAbsolut--;
 
637
        }
 
638
        if ( cursorPos > 0 ) {
 
639
            cursorPos--;
 
640
        }
 
641
        enteredCharacter = sourceFileContent.at(cursorPosAbsolut);
 
642
    }
 
643
 
 
644
    // Call the indenter to reformat the text.
 
645
    if ( toolBarWidget->cbLivePreview->isChecked() ) {
 
646
        callIndenter();
 
647
        previewToggled = true;
 
648
    }
 
649
 
 
650
    // Update the text editor.
 
651
    updateSourceView();
 
652
 
 
653
    if ( toolBarWidget->cbLivePreview->isChecked() && !enteredCharacter.isNull() && enteredCharacter != 10 ) {
 
654
        //const char ch = enteredCharacter.toAscii();
 
655
 
 
656
        int saveCursorLine = cursorLine;
 
657
        int saveCursorPos = cursorPos;
 
658
 
 
659
        bool charFound = false;
 
660
 
 
661
        // Search forward
 
662
        for ( cursorLine = saveCursorLine; cursorLine-saveCursorLine < 6 && cursorLine < qSciSourceCodeEditor->lines(); cursorLine++ ) {
 
663
            text = qSciSourceCodeEditor->text(cursorLine);
 
664
            while ( cursorPos < text.count() && enteredCharacter != text.at(cursorPos)) {
 
665
                cursorPos++;
 
666
            }
 
667
            if ( cursorPos >= text.count() ) {
 
668
                cursorPos = 0;
 
669
            } 
 
670
            else {
 
671
                charFound = true;
 
672
                break;
 
673
            }
 
674
        }
 
675
 
 
676
        // If foward search did not find the character, search backward
 
677
        if ( !charFound ) {
 
678
            text = qSciSourceCodeEditor->text(saveCursorLine);
 
679
            cursorPos = saveCursorPos;
 
680
            if ( cursorPos >= text.count() ) {
 
681
                cursorPos = text.count() - 1;
 
682
            }
 
683
 
 
684
            for ( cursorLine = saveCursorLine; saveCursorLine-cursorLine < 6 && cursorLine >= 0; cursorLine-- ) {
 
685
                text = qSciSourceCodeEditor->text(cursorLine);
 
686
                while ( cursorPos >= 0 && enteredCharacter != text.at(cursorPos)) {
 
687
                    cursorPos--;
 
688
                }
 
689
                if ( cursorPos < 0 ) {
 
690
                    cursorPos = qSciSourceCodeEditor->lineLength(cursorLine-1) - 1;
 
691
                } 
 
692
                else {
 
693
                    charFound = true;
 
694
                    break;
 
695
                }
 
696
            }
 
697
        }
 
698
 
 
699
        // If the character was found set its new cursor position...
 
700
        if ( charFound ) {
 
701
            qSciSourceCodeEditor->setCursorPosition( cursorLine, cursorPos+1 );
 
702
        }
 
703
        // ...if it was not found, set the previous cursor position.
 
704
        else {
 
705
            qSciSourceCodeEditor->setCursorPosition( saveCursorLine, saveCursorPos+1 );
 
706
        }
 
707
    }
 
708
    // set the previous cursor position.
 
709
    else if ( enteredCharacter == 10 ) {
 
710
        qSciSourceCodeEditor->setCursorPosition( cursorLine, cursorPos );
 
711
    }
 
712
 
 
713
 
 
714
    if ( toolBarWidget->cbLivePreview->isChecked() ) {
 
715
        sourceCodeChanged = false;
 
716
    }
 
717
 
 
718
    if ( savedSourceContent == qSciSourceCodeEditor->text() ) {
 
719
        qSciSourceCodeEditor->setModified( false );
 
720
        setWindowModified( false );
 
721
    }
 
722
    else {
 
723
        qSciSourceCodeEditor->setModified( true ); // Has no effect according to QScintilla docs.
 
724
        setWindowModified( true );
 
725
    }
 
726
 
 
727
    // Could set cursor this way and use normal linear search in text instead of columns and rows.
 
728
    //qSciSourceCodeEditor->SendScintilla(QsciScintillaBase::SCI_SETCURRENTPOS, 50);
 
729
    //qSciSourceCodeEditor->SendScintilla(QsciScintillaBase::SCI_SETANCHOR, 50);
 
730
}
 
731
 
 
732
 
 
733
/*!
 
734
    \brief This slot is called whenever one of the indenter settings are changed.
 
735
 
 
736
    It calls the selected indenter if the preview is turned on. If preview
 
737
    is not active a flag is set, that the settings have changed.
 
738
 */
 
739
void MainWindow::indentSettingsChangedSlot() {
 
740
    indentSettingsChanged = true;
 
741
 
 
742
        int cursorLine, cursorPos;
 
743
        qSciSourceCodeEditor->getCursorPosition(&cursorLine, &cursorPos);
 
744
 
 
745
    if ( toolBarWidget->cbLivePreview->isChecked() ) {
 
746
        callIndenter();
 
747
        previewToggled = true;
 
748
 
 
749
        updateSourceView();
 
750
        if (sourceCodeChanged) {
 
751
/*            savedCursor = qSciSourceCodeEditor->textCursor();
 
752
            if ( cursorPos >= qSciSourceCodeEditor->text().count() ) {
 
753
                cursorPos = qSciSourceCodeEditor->text().count() - 1;
 
754
            }
 
755
            savedCursor.setPosition( cursorPos );
 
756
            qSciSourceCodeEditor->setTextCursor( savedCursor );
 
757
*/
 
758
            sourceCodeChanged = false;
 
759
        }
 
760
        indentSettingsChanged = false;
 
761
    }
 
762
    else {
 
763
        updateSourceView();
 
764
    }
 
765
 
 
766
    if ( savedSourceContent == qSciSourceCodeEditor->text() ) {
 
767
        qSciSourceCodeEditor->setModified( false );
 
768
        setWindowModified( false );
 
769
    }
 
770
    else {
 
771
        qSciSourceCodeEditor->setModified( true ); // Has no effect according to QScintilla docs.
 
772
        setWindowModified( true );
 
773
    }
 
774
}
 
775
 
 
776
 
 
777
/*!
 
778
    \brief This slot is called whenever the preview button is turned on or off.
 
779
 
 
780
    It calls the selected indenter to format the current source code if
 
781
    the code has been changed since the last indenter call.
 
782
 */
 
783
void MainWindow::previewTurnedOnOff(bool turnOn) {
 
784
    previewToggled = true;
 
785
 
 
786
        int cursorLine, cursorPos;
 
787
        qSciSourceCodeEditor->getCursorPosition(&cursorLine, &cursorPos);
 
788
 
 
789
    if ( turnOn && (indentSettingsChanged || sourceCodeChanged) ) {
 
790
        callIndenter();
 
791
    }
 
792
    updateSourceView();
 
793
    if (sourceCodeChanged) {
 
794
/*        savedCursor = qSciSourceCodeEditor->textCursor();
 
795
        if ( cursorPos >= qSciSourceCodeEditor->text().count() ) {
 
796
            cursorPos = qSciSourceCodeEditor->text().count() - 1;
 
797
        }
 
798
        savedCursor.setPosition( cursorPos );
 
799
        qSciSourceCodeEditor->setTextCursor( savedCursor );
 
800
*/
 
801
        sourceCodeChanged = false;
 
802
    }
 
803
    indentSettingsChanged = false;
 
804
 
 
805
    if ( savedSourceContent == qSciSourceCodeEditor->text() ) {
 
806
        qSciSourceCodeEditor->setModified( false );
 
807
        setWindowModified( false );
 
808
    }
 
809
    else {
 
810
        qSciSourceCodeEditor->setModified( true );
 
811
        setWindowModified( true );
 
812
    }
 
813
}
 
814
 
 
815
 
 
816
/*!
 
817
    \brief This slot updates the main window title to show the currently opened
 
818
    source code filename.
 
819
 */
 
820
void MainWindow::updateWindowTitle() {
 
821
    this->setWindowTitle( "UniversalIndentGUI " + version +" [*]"+ currentSourceFile);
 
822
}
 
823
 
 
824
 
 
825
/*!
 
826
    \brief Opens a dialog to save the current source code as a PDF document.
 
827
 */
 
828
void MainWindow::exportToPDF() {
 
829
    QString fileExtensions = tr("PDF Document")+" (*.pdf)";
 
830
 
 
831
    QString fileName = currentSourceFile;
 
832
    QFileInfo fileInfo(fileName);
 
833
    QString fileExtension = fileInfo.suffix();
 
834
 
 
835
    fileName.replace( fileName.length()-fileExtension.length(), fileExtension.length(), "pdf" );
 
836
    fileName = QFileDialog::getSaveFileName( this, tr("Export source code file"), fileName, fileExtensions);
 
837
 
 
838
    if ( !fileName.isEmpty() ) {
 
839
        QsciPrinter printer(QPrinter::HighResolution);
 
840
        printer.setOutputFormat(QPrinter::PdfFormat);
 
841
        printer.setOutputFileName(fileName);
 
842
                printer.printRange(qSciSourceCodeEditor);
 
843
    }
 
844
}
 
845
 
 
846
 
 
847
/*!
 
848
    \brief Opens a dialog to save the current source code as a HTML document.
 
849
 */
 
850
void MainWindow::exportToHTML() {
 
851
        QString fileExtensions = tr("HTML Document")+" (*.html)";
 
852
 
 
853
    QString fileName = currentSourceFile;
 
854
    QFileInfo fileInfo(fileName);
 
855
    QString fileExtension = fileInfo.suffix();
 
856
 
 
857
    fileName.replace( fileName.length()-fileExtension.length(), fileExtension.length(), "html" );
 
858
    fileName = QFileDialog::getSaveFileName( this, tr("Export source code file"), fileName, fileExtensions);
 
859
 
 
860
    if ( !fileName.isEmpty() ) {
 
861
        // Create a document from which HTML code can be generated.
 
862
        QTextDocument sourceCodeDocument( qSciSourceCodeEditor->text() );
 
863
        sourceCodeDocument.setDefaultFont( QFont("Courier", 12, QFont::Normal) );
 
864
        QString sourceCodeAsHTML = sourceCodeDocument.toHtml();
 
865
        // To ensure that empty lines are kept in the HTML code make this replacement.
 
866
        sourceCodeAsHTML.replace("\"></p>", "\"><br /></p>");
 
867
 
 
868
        // Write the HTML file.
 
869
        QFile::remove(fileName);
 
870
        QFile outSrcFile(fileName);
 
871
        outSrcFile.open( QFile::ReadWrite | QFile::Text );
 
872
        outSrcFile.write( sourceCodeAsHTML.toAscii() );
 
873
        outSrcFile.close();
 
874
    }
 
875
}
 
876
 
 
877
 
 
878
/*!
 
879
    \brief Loads the last opened file if this option is enabled in the settings. 
 
880
    
 
881
    If the file does not exist, the default example file is tried to be loaded. If even that
 
882
    fails a very small code example is shown.
 
883
    If the setting for opening the last file is disabled, the editor is empty on startup.
 
884
*/
 
885
void MainWindow::loadLastOpenedFile() {
 
886
    // Get setting for last opened source code file.
 
887
        loadLastSourceCodeFileOnStartup = settings->getValueByName("LoadLastOpenedFileOnStartup").toBool();
 
888
 
 
889
        // Only load last source code file if set to do so
 
890
        if ( loadLastSourceCodeFileOnStartup ) {
 
891
        // From the list of last opened files get the first one.
 
892
        currentSourceFile = settings->getValueByName("LastOpenedFiles").toString().split("|").first();
 
893
 
 
894
                // If source file exist load it.
 
895
                if ( QFile::exists(currentSourceFile) ) {
 
896
                        QFileInfo fileInfo(currentSourceFile);
 
897
                        currentSourceFile = fileInfo.absoluteFilePath();
 
898
                        sourceFileContent = loadFile(currentSourceFile);
 
899
                }
 
900
        // If the last opened source code file does not exist, try to load the default example.cpp file.
 
901
        else if ( QFile::exists( SettingsPaths::getIndenterPath() + "/example.cpp" ) ) {
 
902
                        QFileInfo fileInfo( SettingsPaths::getIndenterPath() + "/example.cpp" );
 
903
                        currentSourceFile = fileInfo.absoluteFilePath();
 
904
                        sourceFileContent = loadFile(currentSourceFile);
 
905
                }
 
906
                // If neither the example source code file exists show some small code example.
 
907
                else {
 
908
                        currentSourceFile = "untitled.cpp";
 
909
                        currentSourceFileExtension = "cpp";
 
910
                        sourceFileContent = "if(x==\"y\"){x=z;}";
 
911
                }
 
912
        }
 
913
        // if last opened source file should not be loaded make some default settings.
 
914
        else {
 
915
                currentSourceFile = "untitled.cpp";
 
916
                currentSourceFileExtension = "cpp";
 
917
                sourceFileContent = "";
 
918
        }
 
919
    savedSourceContent = sourceFileContent;
 
920
 
 
921
    // Update the mainwindow title to show the name of the loaded source code file.
 
922
    updateWindowTitle();
 
923
}
 
924
 
 
925
 
 
926
/*!
 
927
    \brief Saves the settings for the main application to the file "UniversalIndentGUI.ini".
 
928
 
 
929
    Settings are for example last selected indenter, last loaded config file and so on.
 
930
*/
 
931
void MainWindow::saveSettings() {
 
932
        settings->setValueByName( "FileEncoding", currentEncoding );
 
933
    settings->setValueByName( "VersionInSettingsFile", version );
 
934
        settings->setValueByName( "WindowIsMaximized", isMaximized() );
 
935
        if ( !isMaximized() ) {
 
936
                settings->setValueByName( "WindowPosition", pos() );
 
937
                settings->setValueByName( "WindowSize", size() );
 
938
        }
 
939
    settings->setValueByName( "MainWindowState", saveState() );
 
940
 
 
941
    // Also save the syntax highlight style for all lexers.
 
942
    highlighter->writeCurrentSettings("");
 
943
}
 
944
 
 
945
 
 
946
/*!
 
947
    \brief Is always called when the program is quit. Calls the saveSettings function before really quits.
 
948
*/
 
949
void MainWindow::closeEvent( QCloseEvent *event ) {
 
950
    if ( maybeSave() ) {
 
951
        saveSettings();
 
952
        event->accept();
 
953
    }
 
954
    else {
 
955
        event->ignore();
 
956
    }
 
957
}
 
958
 
 
959
 
 
960
/*!
 
961
    \brief This function is setup to capture tooltip events. 
 
962
    
 
963
    All widgets that are created by the indentHandler object and are responsible 
 
964
    for indenter parameters are connected with this event filter. 
 
965
    So depending on the settings the tooltips can be enabled and disabled for these widgets.
 
966
 */
 
967
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
 
968
{
 
969
    if ( event->type() == QEvent::ToolTip) {
 
970
        if ( indenterParameterTooltipsEnabledAction->isChecked() ) {
 
971
            return QMainWindow::eventFilter(obj, event);
 
972
        }
 
973
        else {
 
974
            //QToolTip::showText( QPoint(100,100) , "Test1");
 
975
            return true;
 
976
        }
 
977
    } else {
 
978
        // pass the event on to the parent class
 
979
        return QMainWindow::eventFilter(obj, event);
 
980
    }
 
981
}
 
982
 
 
983
 
 
984
/*!
 
985
    \brief Is called at application exit and asks whether to save the source code file, if it has been changed.
 
986
 */
 
987
bool MainWindow::maybeSave()
 
988
{
 
989
    if ( isWindowModified() ) {
 
990
        int ret = QMessageBox::warning(this, tr("Modified code"),
 
991
            tr("The source code has been modified.\n"
 
992
            "Do you want to save your changes?"),
 
993
            QMessageBox::Yes | QMessageBox::Default,
 
994
            QMessageBox::No,
 
995
            QMessageBox::Cancel | QMessageBox::Escape);
 
996
        if (ret == QMessageBox::Yes) {
 
997
            return saveSourceFile();
 
998
        }
 
999
        else if (ret == QMessageBox::Cancel) {
 
1000
            return false;
 
1001
        }
 
1002
    }
 
1003
    return true;
 
1004
}
 
1005
 
 
1006
 
 
1007
/*!
 
1008
    \brief This slot is called whenever a language is selected in the menu. It tries to find the
 
1009
    corresponding action in the languageInfoList and sets the language.
 
1010
 */
 
1011
void MainWindow::languageChanged(int languageIndex) {
 
1012
    // Get the mnemonic of the new selected language.
 
1013
        QString languageShort = settings->getAvailableTranslations().at(languageIndex);
 
1014
 
 
1015
        // Remove the old qt translation.
 
1016
        qApp->removeTranslator( qTTranslator );
 
1017
 
 
1018
    // Remove the old uigui translation.
 
1019
        qApp->removeTranslator( uiGuiTranslator );
 
1020
 
 
1021
    // Load the Qt own translation file and set it for the application.
 
1022
    bool translationFileLoaded;
 
1023
    translationFileLoaded = qTTranslator->load( SettingsPaths::getGlobalFilesPath() + "/translations/qt_" + languageShort );
 
1024
    if ( translationFileLoaded ) {
 
1025
        qApp->installTranslator(qTTranslator);
 
1026
    }
 
1027
 
 
1028
    // Load the uigui translation file and set it for the application.
 
1029
    translationFileLoaded = uiGuiTranslator->load( SettingsPaths::getGlobalFilesPath() + "/translations/universalindent_" + languageShort );
 
1030
    if ( translationFileLoaded ) {
 
1031
        qApp->installTranslator(uiGuiTranslator);
 
1032
    }
 
1033
}
 
1034
 
 
1035
 
 
1036
/*!
 
1037
    \brief Creates a menu entries in the file menu for opening and saving a file with different encodings.
 
1038
*/
 
1039
void MainWindow::createEncodingMenu() {
 
1040
    QAction *encodingAction;
 
1041
    QString encodingName;
 
1042
 
 
1043
    encodingsList = QStringList() << "UTF-8" << "UTF-16" << "UTF-16BE" << "UTF-16LE"
 
1044
            << "Apple Roman" << "Big5" << "Big5-HKSCS" << "EUC-JP" << "EUC-KR" << "GB18030-0"
 
1045
            << "IBM 850" << "IBM 866" << "IBM 874" << "ISO 2022-JP" << "ISO 8859-1" << "ISO 8859-13"
 
1046
            << "Iscii-Bng" << "JIS X 0201" << "JIS X 0208" << "KOI8-R" << "KOI8-U" << "MuleLao-1"
 
1047
            << "ROMAN8" << "Shift-JIS" << "TIS-620" << "TSCII" << "Windows-1250" << "WINSAMI2";
 
1048
 
 
1049
    encodingActionGroup = new QActionGroup(this);
 
1050
    saveEncodedActionGroup = new QActionGroup(this);
 
1051
 
 
1052
    // Loop for each available encoding
 
1053
    foreach ( encodingName, encodingsList ) {
 
1054
        // Create actions for the "reopen" menu
 
1055
        encodingAction = new QAction(encodingName, encodingActionGroup);
 
1056
        encodingAction->setStatusTip( tr("Reopen the currently opened source code file by using the text encoding scheme ") + encodingName );
 
1057
        encodingAction->setCheckable(true);
 
1058
        if ( encodingName == currentEncoding ) {
 
1059
            encodingAction->setChecked(true);
 
1060
        }
 
1061
 
 
1062
        // Create actions for the "save as encoded" menu
 
1063
        encodingAction = new QAction(encodingName, saveEncodedActionGroup);
 
1064
        encodingAction->setStatusTip( tr("Save the currently opened source code file by using the text encoding scheme ") + encodingName );
 
1065
    }
 
1066
 
 
1067
    encodingMenu->addActions( encodingActionGroup->actions() );
 
1068
    connect( encodingActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(encodingChanged(QAction*)) );
 
1069
 
 
1070
    saveEncodedMenu->addActions( saveEncodedActionGroup->actions() );
 
1071
    connect( saveEncodedActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(saveAsOtherEncoding(QAction*)) );
 
1072
}
 
1073
 
 
1074
 
 
1075
/*!
 
1076
    \brief This slot calls the save dialog to save the current source file with another encoding.
 
1077
 
 
1078
    If the saving is successful and not aborted, the currently used encoding, visible in the
 
1079
    "reopen" menu, is also changed to the new encoding.
 
1080
*/
 
1081
void MainWindow::saveAsOtherEncoding(QAction *chosenEncodingAction) {
 
1082
    bool fileWasSaved = saveasSourceFileDialog(chosenEncodingAction);
 
1083
 
 
1084
    // If the file was save with another encoding, change the selected encoding in the reopen menu.
 
1085
    if ( fileWasSaved ) {
 
1086
        foreach ( QAction *action, encodingActionGroup->actions() ) {
 
1087
            if ( action->text() == chosenEncodingAction->text() ) {
 
1088
                action->setChecked(true);
 
1089
                return;
 
1090
            }
 
1091
        }
 
1092
    }
 
1093
}
 
1094
 
 
1095
 
 
1096
/*!
 
1097
    \brief This slot is called whenever an encoding is selected in the settings menu.
 
1098
*/
 
1099
void MainWindow::encodingChanged(QAction* encodingAction) {
 
1100
    if ( maybeSave() ) {
 
1101
        QFile inSrcFile(currentSourceFile);
 
1102
        QString fileContent = "";
 
1103
 
 
1104
        if ( !inSrcFile.open(QFile::ReadOnly | QFile::Text) ) {
 
1105
            QMessageBox::warning(NULL, tr("Error opening file"), tr("Cannot read the file ")+"\""+currentSourceFile+"\"." );
 
1106
        }
 
1107
        else {
 
1108
            QTextStream inSrcStrm(&inSrcFile);
 
1109
            QApplication::setOverrideCursor(Qt::WaitCursor);
 
1110
            QString encodingName = encodingAction->text();
 
1111
                        currentEncoding = encodingName;
 
1112
            inSrcStrm.setCodec( QTextCodec::codecForName(encodingName.toAscii()) );
 
1113
            fileContent = inSrcStrm.readAll();
 
1114
            QApplication::restoreOverrideCursor();
 
1115
            inSrcFile.close();
 
1116
            qSciSourceCodeEditor->setText( fileContent );
 
1117
                        qSciSourceCodeEditor->setModified(false);
 
1118
        }
 
1119
    }
 
1120
}
 
1121
 
 
1122
 
 
1123
/*!
 
1124
        \brief Creates a menu entry under the settings menu for all available text encodings.
 
1125
*/
 
1126
void MainWindow::createHighlighterMenu() {
 
1127
        QAction *highlighterAction;
 
1128
        QString highlighterName;
 
1129
 
 
1130
        highlighterActionGroup = new QActionGroup(this);
 
1131
 
 
1132
        // Loop for each known highlighter
 
1133
    foreach ( highlighterName, highlighter->getAvailableHighlighters() ) {
 
1134
                highlighterAction = new QAction(highlighterName, highlighterActionGroup);
 
1135
                highlighterAction->setStatusTip( tr("Set the syntax highlightning to ") + highlighterName );
 
1136
                highlighterAction->setCheckable(true);
 
1137
        }
 
1138
        highlighterMenu->addActions( highlighterActionGroup->actions() );
 
1139
    menuSettings->insertMenu(indenterParameterTooltipsEnabledAction, highlighterMenu );
 
1140
 
 
1141
        connect( highlighterActionGroup, SIGNAL(triggered(QAction*)), highlighter, SLOT(setHighlighterByAction(QAction*)) );
 
1142
}
 
1143
 
 
1144
 
 
1145
/*!
 
1146
        \brief Is called whenever the white space visibility is being changed in the menu.
 
1147
 */
 
1148
void MainWindow::setWhiteSpaceVisibility(bool visible) {
 
1149
        if ( visible ) {
 
1150
                qSciSourceCodeEditor->setWhitespaceVisibility(QsciScintilla::WsVisible);
 
1151
        }
 
1152
        else {
 
1153
                qSciSourceCodeEditor->setWhitespaceVisibility(QsciScintilla::WsInvisible);
 
1154
        }
 
1155
}
 
1156
 
 
1157
/*!
 
1158
        \brief This slot is called whenever the number of lines in the editor changes
 
1159
        and adapts the margin for the displayed line numbers.
 
1160
*/
 
1161
void MainWindow::numberOfLinesChanged() {
 
1162
        QString lineNumbers;
 
1163
        lineNumbers.setNum( qSciSourceCodeEditor->lines()*10 );
 
1164
        qSciSourceCodeEditor->setMarginWidth(1, lineNumbers);
 
1165
}
 
1166
 
 
1167
 
 
1168
/*!
 
1169
    \brief Catches language change events and retranslates all needed widgets.
 
1170
 */
 
1171
void MainWindow::changeEvent(QEvent *event) {
 
1172
    int i = 0;
 
1173
 
 
1174
    if (event->type() == QEvent::LanguageChange) {
 
1175
        QString languageName;
 
1176
 
 
1177
        // Translate the main window.
 
1178
        retranslateUi(this);
 
1179
        updateWindowTitle();
 
1180
 
 
1181
        // Translate the toolbar.
 
1182
        toolBarWidget->retranslateUi(toolBar);
 
1183
 
 
1184
        // Translate the indent handler widget.
 
1185
        indentHandler->retranslateUi();
 
1186
 
 
1187
         // Translate the load encoding menu.
 
1188
        QList<QAction *> encodingActionList = encodingActionGroup->actions();
 
1189
        for ( i = 0; i < encodingActionList.size(); i++ ) {
 
1190
            encodingActionList.at(i)->setStatusTip( tr("Reopen the currently opened source code file by using the text encoding scheme ") + encodingsList.at(i) );
 
1191
        }
 
1192
 
 
1193
        // Translate the save encoding menu.
 
1194
        encodingActionList = saveEncodedActionGroup->actions();
 
1195
        for ( i = 0; i < encodingActionList.size(); i++ ) {
 
1196
            encodingActionList.at(i)->setStatusTip( tr("Save the currently opened source code file by using the text encoding scheme ") + encodingsList.at(i) );
 
1197
        }
 
1198
 
 
1199
        // Translate the highlighter menu.
 
1200
        QList<QAction *> actionList = highlighterMenu->actions();
 
1201
        i = 0;
 
1202
        foreach ( QString highlighterName, highlighter->getAvailableHighlighters() ) {
 
1203
            QAction *highlighterAction = actionList.at(i);
 
1204
            highlighterAction->setStatusTip( tr("Set the syntax highlightning to ") + highlighterName );
 
1205
            i++;
 
1206
        }
 
1207
 
 
1208
        // Translate the line and column indicators in the statusbar.
 
1209
        int line, column;
 
1210
        qSciSourceCodeEditor->getCursorPosition( &line, &column );
 
1211
        setStatusBarCursorPosInfo( line, column );
 
1212
    } 
 
1213
    else {
 
1214
        QWidget::changeEvent(event);
 
1215
    }
 
1216
}
 
1217
 
 
1218
 
 
1219
 
 
1220
/*!
 
1221
    \brief Updates the list of recently opened files. 
 
1222
    
 
1223
    Therefore the currently open file is set at the lists first position 
 
1224
    regarding the in the settings set maximum list length. Overheads of the 
 
1225
    list will be cut off. The new list will be updated to the settings and 
 
1226
    the recently opened menu will be updated too.
 
1227
 */
 
1228
void MainWindow::updateRecentlyOpenedList() {
 
1229
 
 
1230
        QString fileName;
 
1231
    QString filePath;
 
1232
    QStringList recentlyOpenedList = settings->getValueByName("LastOpenedFiles").toString().split("|");
 
1233
    QList<QAction*> recentlyOpenedActionList = menuRecently_Opened_Files->actions();
 
1234
 
 
1235
    // Check if the currently open file is in the list of recently opened.
 
1236
    int indexOfCurrentFile = recentlyOpenedList.indexOf( currentSourceFile );
 
1237
 
 
1238
    // If it is in the list of recently opened files and not at the first position, move it to the first pos.
 
1239
    if ( indexOfCurrentFile > 0 ) {
 
1240
        recentlyOpenedList.move(indexOfCurrentFile, 0);
 
1241
        recentlyOpenedActionList.move(indexOfCurrentFile, 0);
 
1242
    }
 
1243
    // Put the current file at the first position if it not already is and is not empty.
 
1244
    else if ( indexOfCurrentFile == -1 && !currentSourceFile.isEmpty() ) {
 
1245
        recentlyOpenedList.insert(0, currentSourceFile);
 
1246
                QAction *recentlyOpenedAction = new QAction(QFileInfo(currentSourceFile).fileName(), menuRecently_Opened_Files);
 
1247
                recentlyOpenedAction->setStatusTip(currentSourceFile);
 
1248
        recentlyOpenedActionList.insert(0, recentlyOpenedAction );
 
1249
    }
 
1250
 
 
1251
        // Get the maximum recently opened list size.
 
1252
        int recentlyOpenedListMaxSize = settings->getValueByName("RecentlyOpenedListSize").toInt();
 
1253
 
 
1254
        // Loop for each filepath in the recently opened list, remove non existing files and
 
1255
        // loop only as long as maximum allowed list entries are set.
 
1256
    for ( int i = 0; i < recentlyOpenedList.size() && i < recentlyOpenedListMaxSize; ) {
 
1257
                filePath = recentlyOpenedList.at(i);
 
1258
        QFileInfo fileInfo(filePath);
 
1259
 
 
1260
                // If the file does no longer exist, remove it from the list.
 
1261
                if ( !fileInfo.exists() ) {
 
1262
                        recentlyOpenedList.takeAt(i);
 
1263
            if ( i < recentlyOpenedActionList.size()-2 ) {
 
1264
                QAction* action = recentlyOpenedActionList.takeAt(i);
 
1265
                delete action;
 
1266
            }
 
1267
                }
 
1268
        // else if its not already in the menu, add it to the menu.
 
1269
        else {
 
1270
            if ( i >= recentlyOpenedActionList.size()-2 ) {
 
1271
                QAction *recentlyOpenedAction = new QAction(fileInfo.fileName(), menuRecently_Opened_Files);
 
1272
                recentlyOpenedAction->setStatusTip(filePath);
 
1273
                recentlyOpenedActionList.insert( recentlyOpenedActionList.size()-2, recentlyOpenedAction );
 
1274
            }
 
1275
            i++;
 
1276
        }
 
1277
        }
 
1278
 
 
1279
        // Trim the list to its in the settings allowed maximum size.
 
1280
        while ( recentlyOpenedList.size() > recentlyOpenedListMaxSize ) {
 
1281
                recentlyOpenedList.takeLast();
 
1282
        QAction* action = recentlyOpenedActionList.takeAt( recentlyOpenedActionList.size()-3 );
 
1283
        delete action;
 
1284
        }
 
1285
 
 
1286
    // Add all actions to the menu.
 
1287
    menuRecently_Opened_Files->addActions(recentlyOpenedActionList);
 
1288
 
 
1289
    // Write the new recently opened list to the settings.
 
1290
    settings->setValueByName( "LastOpenedFiles", recentlyOpenedList.join("|") );
 
1291
 
 
1292
    // Enable or disable "actionClear_Recently_Opened_List" if list is [not] emtpy
 
1293
    if ( recentlyOpenedList.isEmpty() ) {
 
1294
        actionClear_Recently_Opened_List->setEnabled(false);
 
1295
    }
 
1296
    else {
 
1297
        actionClear_Recently_Opened_List->setEnabled(true);
 
1298
    }
 
1299
}
 
1300
 
 
1301
 
 
1302
/*!
 
1303
    \brief This slot empties the list of recently opened files.
 
1304
 */
 
1305
void MainWindow::clearRecentlyOpenedList() {
 
1306
    QStringList recentlyOpenedList = settings->getValueByName("LastOpenedFiles").toString().split("|");
 
1307
    QList<QAction*> recentlyOpenedActionList = menuRecently_Opened_Files->actions();
 
1308
 
 
1309
    while ( recentlyOpenedList.size() > 0 ) {
 
1310
                recentlyOpenedList.takeLast();
 
1311
        QAction* action = recentlyOpenedActionList.takeAt( recentlyOpenedActionList.size()-3 );
 
1312
        delete action;
 
1313
        }
 
1314
 
 
1315
    // Write the new recently opened list to the settings.
 
1316
    settings->setValueByName( "LastOpenedFiles", recentlyOpenedList.join("|") );
 
1317
 
 
1318
    // Disable "actionClear_Recently_Opened_List"
 
1319
    actionClear_Recently_Opened_List->setEnabled(false);
 
1320
}
 
1321
 
 
1322
 
 
1323
/*!
 
1324
    \brief This slot is called if an entry from the list of recently opened files is
 
1325
    being selected.
 
1326
 */
 
1327
void MainWindow::openFileFromRecentlyOpenedList(QAction* recentlyOpenedAction) {
 
1328
    // If the selected action from the recently opened list menu is the clear action
 
1329
    // call the slot to clear the list and then leave.
 
1330
    if ( recentlyOpenedAction == actionClear_Recently_Opened_List ) {
 
1331
        clearRecentlyOpenedList();
 
1332
        return;
 
1333
    }
 
1334
 
 
1335
    QString fileName = recentlyOpenedAction->text();
 
1336
    int indexOfSelectedFile = menuRecently_Opened_Files->actions().indexOf( recentlyOpenedAction );
 
1337
    QStringList recentlyOpenedList = settings->getValueByName("LastOpenedFiles").toString().split("|");
 
1338
    QString filePath = recentlyOpenedList.at(indexOfSelectedFile);
 
1339
        QFileInfo fileInfo(filePath);
 
1340
 
 
1341
        // If the file exists, open it.
 
1342
        if ( fileInfo.exists() ) {
 
1343
                openSourceFileDialog(filePath);
 
1344
        }
 
1345
        // If it does not exist, show a warning message and update the list of recently opened files.
 
1346
        else {
 
1347
                QMessageBox::warning(NULL, tr("File no longer exists"), tr("The file %1 in the list of recently opened files does no longer exist.") );
 
1348
        // The function updateRecentlyOpenedList() has to be called via a singleShot so it is executed after this
 
1349
        // function (openFileFromRecentlyOpenedList) has already been left. This has to be done because
 
1350
        // a Qt3Support function tries to emit a signal based on the existing actions and deleting
 
1351
        // any of these actions in updateRecentlyOpenedList() causes an error.
 
1352
                QTimer::singleShot(0, this, SLOT(updateRecentlyOpenedList()) );
 
1353
        }
 
1354
}
 
1355
 
 
1356
 
 
1357
/*!
 
1358
    \brief If the dragged in object contains urls/paths to a file, accept the drag.
 
1359
 */
 
1360
void MainWindow::dragEnterEvent(QDragEnterEvent *event) {
 
1361
    if ( event->mimeData()->hasUrls() ) {
 
1362
        event->acceptProposedAction();
 
1363
    }
 
1364
}
 
1365
 
 
1366
 
 
1367
/*!
 
1368
    \brief If the dropped in object contains urls/paths to a file, open that file.
 
1369
 */
 
1370
void MainWindow::dropEvent(QDropEvent *event) {
 
1371
    if ( event->mimeData()->hasUrls() ) {
 
1372
        QString filePathName = event->mimeData()->urls().first().toLocalFile();
 
1373
        openSourceFileDialog(filePathName);
 
1374
    }
 
1375
 
 
1376
    event->acceptProposedAction();
 
1377
}
 
1378
 
 
1379
 
 
1380
/*!
 
1381
    \brief If the dropped in object contains urls/paths to a file, open that file.
 
1382
*/
 
1383
void MainWindow::showAboutDialog() {
 
1384
        QPixmap originalPixmap = QPixmap::grabWindow(QApplication::desktop()->screen()->winId());
 
1385
        //qDebug("in main pixmap width %d, numScreens = %d", originalPixmap.size().width(), QApplication::desktop()->availableGeometry().width());
 
1386
        aboutDialogGraphicsView->setScreenshotPixmap( originalPixmap );
 
1387
        aboutDialogGraphicsView->show();
 
1388
}
 
1389
 
 
1390
 
 
1391
/*!
 
1392
    \brief Sets the label in the status bar to show the \a line and \a column number.
 
1393
*/
 
1394
void MainWindow::setStatusBarCursorPosInfo( int line, int column ) {
 
1395
    textEditLineColumnInfoLabel->setText( tr("Line %1, Column %2").arg(line+1).arg(column+1) );
 
1396
}