/***********************************************************************
*
* Copyright (C) 2014-2020 wereturtle
* Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Graeme Gott
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
***********************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "ColorHelper.h"
#include "DocumentHistory.h"
#include "DocumentManager.h"
#include "DocumentStatistics.h"
#include "DocumentStatisticsWidget.h"
#include "Exporter.h"
#include "ExporterFactory.h"
#include "find_dialog.h"
#include "HtmlPreview.h"
#include "HudWindow.h"
#include "LocaleDialog.h"
#include "MainWindow.h"
#include "MessageBoxHelper.h"
#include "Outline.h"
#include "PreferencesDialog.h"
#include "PreviewOptionsDialog.h"
#include "SandboxedWebPage.h"
#include "SessionStatistics.h"
#include "SessionStatisticsWidget.h"
#include "SimpleFontDialog.h"
#include "StyleSheetManagerDialog.h"
#include "ThemeFactory.h"
#include "ThemeSelectionDialog.h"
#define GW_MAIN_WINDOW_GEOMETRY_KEY "Window/mainWindowGeometry"
#define GW_MAIN_WINDOW_STATE_KEY "Window/mainWindowState"
#define GW_OUTLINE_HUD_GEOMETRY_KEY "HUD/outlineHudGeometry"
#define GW_CHEAT_SHEET_HUD_GEOMETRY_KEY "HUD/cheatSheetHudGeometry"
#define GW_DOCUMENT_STATISTICS_HUD_GEOMETRY_KEY "HUD/documentStatisticsHudGeometry"
#define GW_SESSION_STATISTICS_HUD_GEOMETRY_KEY "HUD/sessionStatisticsHudGeometry"
#define GW_OUTLINE_HUD_OPEN_KEY "HUD/outlineHudOpen"
#define GW_CHEAT_SHEET_HUD_OPEN_KEY "HUD/cheatSheetHudOpen"
#define GW_DOCUMENT_STATISTICS_HUD_OPEN_KEY "HUD/documentStatisticsHudOpen"
#define GW_SESSION_STATISTICS_HUD_OPEN_KEY "HUD/sessionStatisticsHudOpen"
MainWindow::MainWindow(const QString& filePath, QWidget* parent)
: QMainWindow(parent)
{
QString fileToOpen;
setWindowIcon(QIcon(":/resources/images/ghostwriter.svg"));
this->setObjectName("mainWindow");
this->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
qApp->installEventFilter(this);
menuBarHeight = 0;
lastMousePos = QPoint(-1, -1);
appSettings = AppSettings::getInstance();
cheatSheetWidget = new QListWidget();
// We need to set an empty style for the scrollbar in order for the
// scrollbar CSS stylesheet to take full effect. Otherwise, the scrollbar's
// background color will have the Windows 98 checkered look rather than
// being a solid or transparent color.
//
cheatSheetWidget->verticalScrollBar()->setStyle(new QCommonStyle());
cheatSheetWidget->horizontalScrollBar()->setStyle(new QCommonStyle());
cheatSheetWidget->setSelectionMode(QAbstractItemView::NoSelection);
cheatSheetWidget->setAlternatingRowColors(appSettings->getAlternateHudRowColorsEnabled());
cheatSheetWidget->addItem(tr("# Heading 1"));
cheatSheetWidget->addItem(tr("## Heading 2"));
cheatSheetWidget->addItem(tr("### Heading 3"));
cheatSheetWidget->addItem(tr("#### Heading 4"));
cheatSheetWidget->addItem(tr("##### Heading 5"));
cheatSheetWidget->addItem(tr("###### Heading 6"));
cheatSheetWidget->addItem(tr("*Emphasis* _Emphasis_"));
cheatSheetWidget->addItem(tr("**Strong** __Strong__"));
cheatSheetWidget->addItem(tr("1. Numbered List"));
cheatSheetWidget->addItem(tr("* Bullet List"));
cheatSheetWidget->addItem(tr("+ Bullet List"));
cheatSheetWidget->addItem(tr("- Bullet List"));
cheatSheetWidget->addItem(tr("> Block Quote"));
cheatSheetWidget->addItem(tr("`Code Span`"));
cheatSheetWidget->addItem(tr("``` Code Block"));
cheatSheetWidget->addItem(tr("[Link](http://url.com \"Title\")"));
cheatSheetWidget->addItem(tr("[Reference Link][ID]"));
cheatSheetWidget->addItem(tr("[ID]: http://url.com \"Reference Definition\""));
cheatSheetWidget->addItem(tr(""));
cheatSheetWidget->addItem(tr("--- *** ___ Horizontal Rule"));
cheatSheetHud =
createHudWindow
(
tr("Cheat Sheet"),
cheatSheetWidget,
GW_CHEAT_SHEET_HUD_GEOMETRY_KEY,
GW_CHEAT_SHEET_HUD_OPEN_KEY
);
documentStatsWidget = new DocumentStatisticsWidget();
documentStatsWidget->verticalScrollBar()->setStyle(new QCommonStyle());
documentStatsWidget->horizontalScrollBar()->setStyle(new QCommonStyle());
documentStatsWidget->setSelectionMode(QAbstractItemView::NoSelection);
documentStatsWidget->setAlternatingRowColors(appSettings->getAlternateHudRowColorsEnabled());
documentStatsHud =
createHudWindow
(
tr("Document Statistics"),
documentStatsWidget,
GW_DOCUMENT_STATISTICS_HUD_GEOMETRY_KEY,
GW_DOCUMENT_STATISTICS_HUD_OPEN_KEY
);
sessionStatsWidget =new SessionStatisticsWidget();
sessionStatsWidget->verticalScrollBar()->setStyle(new QCommonStyle());
sessionStatsWidget->horizontalScrollBar()->setStyle(new QCommonStyle());
sessionStatsWidget->setSelectionMode(QAbstractItemView::NoSelection);
sessionStatsWidget->setAlternatingRowColors(appSettings->getAlternateHudRowColorsEnabled());
sessionStatsHud =
createHudWindow
(
tr("Session Statistics"),
sessionStatsWidget,
GW_SESSION_STATISTICS_HUD_GEOMETRY_KEY,
GW_SESSION_STATISTICS_HUD_OPEN_KEY
);
connect(appSettings, SIGNAL(hideHudsOnPreviewChanged(bool)), this, SLOT(onHideHudsOnPreviewChanged(bool)));
MarkdownDocument* document = new MarkdownDocument();
editor = new MarkdownEditor(document, this);
editor->setFont(appSettings->getFont().family(), appSettings->getFont().pointSize());
editor->setUseUnderlineForEmphasis(appSettings->getUseUnderlineForEmphasis());
editor->setHighlightLineBreaks(appSettings->getHighlightLineBreaks());
editor->setEnableLargeHeadingSizes(appSettings->getLargeHeadingSizesEnabled());
editor->setAutoMatchEnabled(appSettings->getAutoMatchEnabled());
editor->setBulletPointCyclingEnabled(appSettings->getBulletPointCyclingEnabled());
editor->setPlainText("");
editor->setEditorWidth((EditorWidth) appSettings->getEditorWidth());
editor->setEditorCorners((InterfaceStyle) appSettings->getInterfaceStyle());
editor->setBlockquoteStyle(appSettings->getBlockquoteStyle());
editor->setSpellCheckEnabled(appSettings->getLiveSpellCheckEnabled());
connect(editor, SIGNAL(fontSizeChanged(int)), this, SLOT(onFontSizeChanged(int)));
connect(editor, SIGNAL(typingPaused()), this, SLOT(onTypingPaused()));
connect(editor, SIGNAL(typingResumed()), this, SLOT(onTypingResumed()));
// We need to set an empty style for the editor's scrollbar in order for the
// scrollbar CSS stylesheet to take full effect. Otherwise, the scrollbar's
// background color will have the Windows 98 checkered look rather than
// being a solid or transparent color.
//
editor->verticalScrollBar()->setStyle(new QCommonStyle());
editor->horizontalScrollBar()->setStyle(new QCommonStyle());
outlineWidget = new Outline(editor, this);
outlineWidget->setAlternatingRowColors(appSettings->getAlternateHudRowColorsEnabled());
// Set empty style so that scrollbar styling takes full effect.
//
outlineWidget->verticalScrollBar()->setStyle(new QCommonStyle());
outlineWidget->horizontalScrollBar()->setStyle(new QCommonStyle());
outlineHud =
createHudWindow
(
tr("Outline"),
outlineWidget,
GW_OUTLINE_HUD_GEOMETRY_KEY,
GW_OUTLINE_HUD_OPEN_KEY
);
documentStats = new DocumentStatistics(document, this);
connect(documentStats, SIGNAL(wordCountChanged(int)), documentStatsWidget, SLOT(setWordCount(int)));
connect(documentStats, SIGNAL(characterCountChanged(int)), documentStatsWidget, SLOT(setCharacterCount(int)));
connect(documentStats, SIGNAL(sentenceCountChanged(int)), documentStatsWidget, SLOT(setSentenceCount(int)));
connect(documentStats, SIGNAL(paragraphCountChanged(int)), documentStatsWidget, SLOT(setParagraphCount(int)));
connect(documentStats, SIGNAL(pageCountChanged(int)), documentStatsWidget, SLOT(setPageCount(int)));
connect(documentStats, SIGNAL(complexWordsChanged(int)), documentStatsWidget, SLOT(setComplexWords(int)));
connect(documentStats, SIGNAL(readingTimeChanged(int)), documentStatsWidget, SLOT(setReadingTime(int)));
connect(documentStats, SIGNAL(lixReadingEaseChanged(int)), documentStatsWidget, SLOT(setLixReadingEase(int)));
connect(documentStats, SIGNAL(readabilityIndexChanged(int)), documentStatsWidget, SLOT(setReadabilityIndex(int)));
connect(editor, SIGNAL(textSelected(QString,int,int)), documentStats, SLOT(onTextSelected(QString,int,int)));
connect(editor, SIGNAL(textDeselected()), documentStats, SLOT(onTextDeselected()));
sessionStats = new SessionStatistics(this);
connect(documentStats, SIGNAL(totalWordCountChanged(int)), sessionStats, SLOT(onDocumentWordCountChanged(int)));
connect(sessionStats, SIGNAL(wordCountChanged(int)), sessionStatsWidget, SLOT(setWordCount(int)));
connect(sessionStats, SIGNAL(pageCountChanged(int)), sessionStatsWidget, SLOT(setPageCount(int)));
connect(sessionStats, SIGNAL(wordsPerMinuteChanged(int)), sessionStatsWidget, SLOT(setWordsPerMinute(int)));
connect(sessionStats, SIGNAL(writingTimeChanged(unsigned long)), sessionStatsWidget, SLOT(setWritingTime(unsigned long)));
connect(sessionStats, SIGNAL(idleTimePercentageChanged(int)), sessionStatsWidget, SLOT(setIdleTime(int)));
connect(editor, SIGNAL(typingPaused()), sessionStats, SLOT(onTypingPaused()));
connect(editor, SIGNAL(typingResumed()), sessionStats, SLOT(onTypingResumed()));
documentManager = new DocumentManager(editor, outlineWidget, documentStats, sessionStats, this);
documentManager->setAutoSaveEnabled(appSettings->getAutoSaveEnabled());
documentManager->setFileBackupEnabled(appSettings->getBackupFileEnabled());
documentManager->setFileHistoryEnabled(appSettings->getFileHistoryEnabled());
setWindowTitle(documentManager->getDocument()->getDisplayName() + "[*] - " + qAppName());
connect(documentManager, SIGNAL(documentDisplayNameChanged(QString)), this, SLOT(changeDocumentDisplayName(QString)));
connect(documentManager, SIGNAL(documentModifiedChanged(bool)), this, SLOT(setWindowModified(bool)));
connect(documentManager, SIGNAL(operationStarted(QString)), this, SLOT(onOperationStarted(QString)));
connect(documentManager, SIGNAL(operationUpdate(QString)), this, SLOT(onOperationStarted(QString)));
connect(documentManager, SIGNAL(operationFinished()), this, SLOT(onOperationFinished()));
connect(documentManager, SIGNAL(documentClosed()), this, SLOT(refreshRecentFiles()));
editor->setAutoMatchEnabled('\"', appSettings->getAutoMatchCharEnabled('\"'));
editor->setAutoMatchEnabled('\'', appSettings->getAutoMatchCharEnabled('\''));
editor->setAutoMatchEnabled('(', appSettings->getAutoMatchCharEnabled('('));
editor->setAutoMatchEnabled('[', appSettings->getAutoMatchCharEnabled('['));
editor->setAutoMatchEnabled('{', appSettings->getAutoMatchCharEnabled('{'));
editor->setAutoMatchEnabled('*', appSettings->getAutoMatchCharEnabled('*'));
editor->setAutoMatchEnabled('_', appSettings->getAutoMatchCharEnabled('_'));
editor->setAutoMatchEnabled('`', appSettings->getAutoMatchCharEnabled('`'));
editor->setAutoMatchEnabled('setupPaperMargins(editorWidth);
// Scroll to cursor position.
editor->centerCursor();
}
void MainWindow::applyStatusBarStyle()
{
QString styleSheet = "";
QTextStream stream(&styleSheet);
int border = 0;
if
(
(EditorAspectStretch == theme.getEditorAspect())
||
htmlPreview->isVisible()
)
{
border = 1;
}
QColor borderColor = theme.getDefaultTextColor();
borderColor.setAlpha(30);
QString borderColorRGBA = ColorHelper::toRgbaString(borderColor);
stream
setGraphicsEffect(colorizeEffect);
}
// Remove menu bar text drop shadow effect.
this->menuBar()->setGraphicsEffect(NULL);
}
else
{
// Make the UI chrome color an off white. A drop shadow will be
// applied to supply contrast with the background image.
//
QColor chromeFgColor = QColor("#e5e8e8");
menuBarItemFgColorRGB = ColorHelper::toRgbString(chromeFgColor);
menuBarItemBgColorRGBA = "transparent";
menuBarItemFgPressColorRGB = menuBarItemFgColorRGB;
chromeFgColor.setAlpha(50);
menuBarItemBgPressColorRGBA = ColorHelper::toRgbaString(chromeFgColor);
fullScreenIcon = ":/resources/images/fullscreen-light.svg";
focusIcon = ":/resources/images/focus-light.svg";
hemingwayIcon = ":/resources/images/hemingway-light.svg";
htmlPreviewIcon = ":/resources/images/html-preview-light.svg";
hideOpenHudsIcon = ":/resources/images/hide-huds-light.svg";
copyHtmlIcon = ":/resources/images/copy-html-light.svg";
exportIcon = ":/resources/images/export-light.svg";
markdownOptionsIcon = ":/resources/images/configure-light.svg";
statusBarItemFgColorRGB = menuBarItemFgColorRGB;
statusBarButtonFgPressHoverColorRGB = menuBarItemFgPressColorRGB;
statusBarButtonBgPressHoverColorRGBA = menuBarItemBgPressColorRGBA;
// Set drop shadow effect for status bar widgets.
foreach (QWidget* widget, statusBarWidgets)
{
QGraphicsDropShadowEffect* chromeDropShadowEffect = new QGraphicsDropShadowEffect();
chromeDropShadowEffect->setColor(QColor(Qt::black));
chromeDropShadowEffect->setBlurRadius(3.5);
chromeDropShadowEffect->setXOffset(1.0);
chromeDropShadowEffect->setYOffset(1.0);
widget->setGraphicsEffect(chromeDropShadowEffect);
}
QGraphicsDropShadowEffect* menuBarTextDropShadowEffect = new QGraphicsDropShadowEffect();
menuBarTextDropShadowEffect->setColor(QColor(Qt::black));
menuBarTextDropShadowEffect->setBlurRadius(3.5);
menuBarTextDropShadowEffect->setXOffset(1.0);
menuBarTextDropShadowEffect->setYOffset(1.0);
// Set drop shadow effect for menu bar text.
this->menuBar()->setGraphicsEffect(menuBarTextDropShadowEffect);
}
editor->setAspect(theme.getEditorAspect());
styleSheet = "";
QString corners = "";
QString scrollBarRadius = "0px";
QString scrollAreaPadding = "3px 3px 0px 3px";
if (EditorAspectCenter == theme.getEditorAspect())
{
scrollAreaPadding = "3px";
}
if (InterfaceStyleRounded == appSettings->getInterfaceStyle())
{
if (EditorAspectCenter == theme.getEditorAspect())
{
corners = "border-radius: 8;";
}
scrollBarRadius = "4px";
}
QString defaultTextColorRGB =
ColorHelper::toRgbString(theme.getDefaultTextColor());
stream
setText(tr("Hide Open &HUD Windows"));
hideOpenHudsButton->blockSignals(true);
hideOpenHudsButton->setChecked(false);
hideOpenHudsButton->setToolTip(tr("Hide Open HUD Windows"));
hideOpenHudsButton->blockSignals(false);
// Set focus on the editor.
this->activateWindow();
}
else
{
hideOpenHudsAction->setText(tr("Show Open &HUD Windows"));
hideOpenHudsButton->blockSignals(true);
hideOpenHudsButton->setChecked(true);
hideOpenHudsButton->setToolTip(tr("Show Open HUD Windows"));
hideOpenHudsButton->blockSignals(false);
}
}