5 Commits

Author SHA1 Message Date
dab0f14d34 Merge pull request 'Version 3.0.0' (#2) from rc into main
Reviewed-on: #2
2025-03-27 11:34:43 +01:00
03ccf03808 set dock properties 2025-03-27 11:33:23 +01:00
cdeb1205ef rework ui 2025-03-27 11:29:55 +01:00
c4d74bb22b fix first tab 2024-11-28 22:15:31 +01:00
f99ab4741b add thread, export to pdf, new css 2024-11-28 19:14:32 +01:00
10 changed files with 1311 additions and 172 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -7,7 +7,7 @@ CONFIG += c++17
win32:VERSION = 3.0.0.0 # major.minor.patch.build win32:VERSION = 3.0.0.0 # major.minor.patch.build
else:VERSION = 3.0.0 # major.minor.patch else:VERSION = 3.0.0 # major.minor.patch
DEFINES += APP_VERSION=\"\\\"$${VERSION}-rc1\\\"\" DEFINES += APP_VERSION=\"\\\"$${VERSION}\\\"\"
DEFINES += APP_NAME=\"\\\"WorkPad\\\"\" DEFINES += APP_NAME=\"\\\"WorkPad\\\"\"
# remove possible other optimization flags # remove possible other optimization flags
@@ -111,4 +111,5 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target !isEmpty(target.path): INSTALLS += target
RESOURCES += \ RESOURCES += \
icons.qrc icons.qrc \
static.qrc

1106
resources/style.css Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -19,5 +19,9 @@ int ExportDialog::getResult()
{ {
return MARKDOWN; return MARKDOWN;
} }
else if (ui->pdfRadio->isChecked())
{
return PDF;
}
return PLAIN; return PLAIN;
} }

View File

@@ -5,6 +5,7 @@
#define MARKDOWN 1 #define MARKDOWN 1
#define PLAIN 2 #define PLAIN 2
#define PDF 3
namespace Ui { namespace Ui {
class ExportDialog; class ExportDialog;

View File

@@ -35,10 +35,10 @@
</rect> </rect>
</property> </property>
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Orientation::Horizontal</enum>
</property> </property>
<property name="standardButtons"> <property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> <set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
</property> </property>
</widget> </widget>
<widget class="QRadioButton" name="markdownButton"> <widget class="QRadioButton" name="markdownButton">
@@ -61,7 +61,7 @@
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>30</x> <x>30</x>
<y>60</y> <y>40</y>
<width>92</width> <width>92</width>
<height>23</height> <height>23</height>
</rect> </rect>
@@ -70,6 +70,19 @@
<string>Text file</string> <string>Text file</string>
</property> </property>
</widget> </widget>
<widget class="QRadioButton" name="pdfRadio">
<property name="geometry">
<rect>
<x>30</x>
<y>60</y>
<width>92</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>PDF file</string>
</property>
</widget>
</widget> </widget>
<resources/> <resources/>
<connections> <connections>

View File

@@ -7,35 +7,71 @@
#include "renamedialog.h" #include "renamedialog.h"
#include "exportdialog.h" #include "exportdialog.h"
#include <chrono>
MainWindow::MainWindow(QWidget *parent) MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent) : QMainWindow(parent)
, ui(new Ui::MainWindow) , ui(new Ui::MainWindow)
{ {
ui->setupUi(this); ui->setupUi(this);
timer = new QTimer(this); timer = new QTimer(this);
updateViewThread = nullptr;
parser = std::make_shared<maddy::Parser>(); parser = std::make_shared<maddy::Parser>();
// open stylesheet resource
QFile f(":/css/resources/style.css");
f.open(QFile::OpenModeFlag::ReadOnly);
style = f.readAll();
f.close();
connect(ui->actionAdd_folder, &QAction::triggered, this, &MainWindow::createFolder); connect(ui->actionAdd_folder, &QAction::triggered, this, &MainWindow::createFolder);
connect(ui->actionAdd, &QAction::triggered, this, &MainWindow::createNote); connect(ui->actionAdd, &QAction::triggered, this, &MainWindow::createNote);
connect(ui->actionSave, &QAction::triggered, this, &MainWindow::save); connect(ui->actionSave, &QAction::triggered, this, &MainWindow::save);
connect(ui->actionSettings, &QAction::triggered, this, &MainWindow::showSettingsBox); connect(ui->actionSettings, &QAction::triggered, this, &MainWindow::showSettingsBox);
connect(ui->contentEdit, &QPlainTextEdit::textChanged, this, &MainWindow::markdownContentChanged);
connect(ui->plainTextEdit, &QPlainTextEdit::textChanged, this, &MainWindow::plainContentChanged); connect(ui->plainTextEdit, &QPlainTextEdit::textChanged, this, &MainWindow::plainContentChanged);
connect(ui->treeWidget, &QTreeWidget::itemSelectionChanged, this, &MainWindow::selectionChanged); connect(ui->treeWidget, &QTreeWidget::itemSelectionChanged, this, &MainWindow::selectionChanged);
connect(ui->treeWidget, &QTreeWidget::customContextMenuRequested, this, &MainWindow::prepareMenu); connect(ui->treeWidget, &QTreeWidget::customContextMenuRequested, this, &MainWindow::prepareMenu);
connect(this, &MainWindow::updateViewers, this, &MainWindow::viewReady); connect(this, &MainWindow::updateViewers, this, &MainWindow::viewReady);
const QFont fixedFont = QFontDatabase::systemFont(QFontDatabase::FixedFont); const QFont fixedFont = QFontDatabase::systemFont(QFontDatabase::FixedFont);
ui->contentEdit->setFont(fixedFont);
ui->plainTextEdit->setFont(fixedFont); ui->plainTextEdit->setFont(fixedFont);
ui->treeWidget->setContextMenuPolicy(Qt::CustomContextMenu); ui->treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
ui->renderingProgressBar->setVisible(false);
this->savemng = new SaveManager(); this->savemng = new SaveManager();
this->cfgmng = new ConfigManager(); this->cfgmng = new ConfigManager();
updateListView(); updateListView();
connect(timer, &QTimer::timeout, this, &MainWindow::save); connect(timer, &QTimer::timeout, this, &MainWindow::save);
// start render thread
threaddone = new bool(false);
queue = new QVector<QString>;
queueMutex = new QMutex();
updateViewThread = new std::thread([this](){
while (!*threaddone) {
queueMutex->lock();
if (queue->count() == 0) {
queueMutex->unlock();
std::this_thread::sleep_for(std::chrono::milliseconds(500));
continue;
}
QString content = (*queue)[0];
queue->pop_front();
queueMutex->unlock();
std::stringstream markdownInput(content.toStdString());
QString htmlOutput = "<html><body class='markdown-body'>";
htmlOutput += QString::fromStdString(parser->Parse(markdownInput));
htmlOutput += "</body><style>" + style + "</style></html>";
emit updateViewers(htmlOutput);
}
});
} }
MainWindow::~MainWindow() MainWindow::~MainWindow()
{ {
*threaddone = true;
updateViewThread->join();
delete queue;
delete queueMutex;
delete threaddone;
delete updateViewThread;
delete timer; delete timer;
delete savemng; delete savemng;
delete ui; delete ui;
@@ -94,19 +130,14 @@ void MainWindow::selectionChanged()
return; return;
} }
ui->plainTextEdit->blockSignals(true); ui->plainTextEdit->blockSignals(true);
ui->contentEdit->blockSignals(true);
this->setWindowTitle(n->getTitle() + " - WorkPad"); this->setWindowTitle(n->getTitle() + " - WorkPad");
ui->titleLabel->setText(n->getTitle());
ui->plainTextEdit->setDisabled(false); ui->plainTextEdit->setDisabled(false);
ui->contentEdit->setDisabled(false);
ui->plainTextEdit->setPlainText(n->getContent()); ui->plainTextEdit->setPlainText(n->getContent());
ui->contentEdit->setPlainText(n->getContent());
updateHTMLView(); updateHTMLView();
ui->plainTextEdit->blockSignals(false); ui->plainTextEdit->blockSignals(false);
ui->contentEdit->blockSignals(false);
} }
else else
{ {
@@ -309,6 +340,10 @@ void MainWindow::exportNote()
{ {
filter = "Markdown file (*.md)"; filter = "Markdown file (*.md)";
} }
else if (fileType == PDF)
{
filter = "PDF file (*.pdf)";
}
QString fileName = QFileDialog::getSaveFileName(this, tr("Export note"), "", filter); QString fileName = QFileDialog::getSaveFileName(this, tr("Export note"), "", filter);
if (!fileName.isEmpty()) if (!fileName.isEmpty())
{ {
@@ -320,14 +355,28 @@ void MainWindow::exportNote()
{ {
fileName += ".txt"; fileName += ".txt";
} }
else if (fileType == PDF && !fileName.endsWith(".pdf", Qt::CaseInsensitive))
{
fileName += ".pdf";
}
if (fileType == PDF)
{
ui->webEngineViewer->printToPdf(fileName);
}
else
{
QFile *f = new QFile(fileName); QFile *f = new QFile(fileName);
if (f->open(QIODevice::WriteOnly)) if (f->open(QIODevice::WriteOnly))
{ {
f->write(n->getContent().toUtf8()); f->write(n->getContent().toUtf8());
f->close(); f->close();
} }
delete f; delete f;
} }
}
} }
} }
} }
@@ -335,29 +384,28 @@ void MainWindow::exportNote()
void MainWindow::viewReady(QString html) void MainWindow::viewReady(QString html)
{ {
if (queue->count() == 0)
{
ui->renderingProgressBar->setVisible(false);
}
ui->webEngineViewer->setHtml(html); ui->webEngineViewer->setHtml(html);
ui->webEngineEditor->setHtml(html);
} }
void MainWindow::markdownContentChanged() void MainWindow::markdownContentChanged()
{ {
timer->stop(); timer->stop();
ui->plainTextEdit->blockSignals(true); ui->plainTextEdit->blockSignals(true);
ui->contentEdit->blockSignals(true);
if (ui->treeWidget->selectedItems().length() == 1) if (ui->treeWidget->selectedItems().length() == 1)
{ {
QString uuid = ui->treeWidget->selectedItems()[0]->text(COLUMN_UUID); QString uuid = ui->treeWidget->selectedItems()[0]->text(COLUMN_UUID);
Note *n = savemng->getNoteByUUID(uuid); Note *n = savemng->getNoteByUUID(uuid);
if (n != nullptr) { if (n != nullptr) {
QString content = ui->plainTextEdit->toPlainText();
QString content = ui->contentEdit->toPlainText();
ui->plainTextEdit->setPlainText(content);
n->setContent(content); n->setContent(content);
updateHTMLView(); updateHTMLView();
} }
} }
ui->plainTextEdit->blockSignals(false); ui->plainTextEdit->blockSignals(false);
ui->contentEdit->blockSignals(false);
ui->actionSave->setDisabled(false); ui->actionSave->setDisabled(false);
if (cfgmng->getConfiguration()->isEnableAutoSave()) if (cfgmng->getConfiguration()->isEnableAutoSave())
{ {
@@ -369,20 +417,17 @@ void MainWindow::plainContentChanged()
{ {
timer->stop(); timer->stop();
ui->plainTextEdit->blockSignals(true); ui->plainTextEdit->blockSignals(true);
ui->contentEdit->blockSignals(true);
if (ui->treeWidget->selectedItems().length() == 1) if (ui->treeWidget->selectedItems().length() == 1)
{ {
QString uuid = ui->treeWidget->selectedItems()[0]->text(COLUMN_UUID); QString uuid = ui->treeWidget->selectedItems()[0]->text(COLUMN_UUID);
Note *n = savemng->getNoteByUUID(uuid); Note *n = savemng->getNoteByUUID(uuid);
if (n != nullptr) { if (n != nullptr) {
QString content = ui->plainTextEdit->toPlainText(); QString content = ui->plainTextEdit->toPlainText();
ui->contentEdit->setPlainText(content);
n->setContent(content); n->setContent(content);
updateHTMLView(); updateHTMLView();
} }
} }
ui->plainTextEdit->blockSignals(false); ui->plainTextEdit->blockSignals(false);
ui->contentEdit->blockSignals(false);
ui->actionSave->setDisabled(false); ui->actionSave->setDisabled(false);
if (cfgmng->getConfiguration()->isEnableAutoSave()) if (cfgmng->getConfiguration()->isEnableAutoSave())
{ {
@@ -413,35 +458,23 @@ void MainWindow::updateListView()
void MainWindow::updateHTMLView() void MainWindow::updateHTMLView()
{ {
if (threadLock.tryLock()) { queueMutex->lock();
updateViewThread = new std::thread([this](){ ui->renderingProgressBar->setVisible(true);
QString content = ui->plainTextEdit->toPlainText(); if (queue->count() > 4) {
std::stringstream markdownInput(content.toStdString()); queue->pop_front();
QString htmlOutput = QString::fromStdString(parser->Parse(markdownInput));
emit updateViewers(htmlOutput);
threadLock.unlock();
});
} else {
QTimer::singleShot(200, [this]() {
updateHTMLView();
});
} }
queue->append(ui->plainTextEdit->toPlainText());
queueMutex->unlock();
} }
void MainWindow::clearAndDisableFields() void MainWindow::clearAndDisableFields()
{ {
ui->contentEdit->blockSignals(true);
ui->plainTextEdit->blockSignals(true); ui->plainTextEdit->blockSignals(true);
ui->contentEdit->setDisabled(true);
ui->plainTextEdit->setDisabled(true); ui->plainTextEdit->setDisabled(true);
ui->plainTextEdit->clear(); ui->plainTextEdit->clear();
ui->contentEdit->clear();
ui->titleLabel->setText("");
this->setWindowTitle("WorkPad"); this->setWindowTitle("WorkPad");
ui->contentEdit->blockSignals(false);
ui->plainTextEdit->blockSignals(false); ui->plainTextEdit->blockSignals(false);
} }

View File

@@ -61,9 +61,15 @@ private:
SaveManager *savemng; SaveManager *savemng;
ConfigManager *cfgmng; ConfigManager *cfgmng;
QTimer *timer; QTimer *timer;
std::thread *updateViewThread;
std::shared_ptr<maddy::Parser> parser; std::shared_ptr<maddy::Parser> parser;
QMutex threadLock;
QString style;
//shared between threads
QVector<QString>* queue;
QMutex* queueMutex;
bool* threaddone;
std::thread *updateViewThread;
void updateListView(); void updateListView();
void clearAndDisableFields(); void clearAndDisableFields();

View File

@@ -25,66 +25,6 @@
<widget class="QWidget" name="centralwidget"> <widget class="QWidget" name="centralwidget">
<layout class="QHBoxLayout" name="horizontalLayout_2"> <layout class="QHBoxLayout" name="horizontalLayout_2">
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QTreeWidget" name="treeWidget">
<property name="maximumSize">
<size>
<width>250</width>
<height>16777215</height>
</size>
</property>
<property name="editTriggers">
<set>QAbstractItemView::EditTrigger::NoEditTriggers</set>
</property>
<property name="animated">
<bool>true</bool>
</property>
<column>
<property name="text">
<string notr="true">Workspace</string>
</property>
</column>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="titleLabel">
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="tabPosition">
<enum>QTabWidget::TabPosition::South</enum>
</property>
<property name="tabShape">
<enum>QTabWidget::TabShape::Rounded</enum>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab_3">
<attribute name="title">
<string>Plain text</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<item row="2" column="0">
<widget class="QPlainTextEdit" name="plainTextEdit"> <widget class="QPlainTextEdit" name="plainTextEdit">
<property name="enabled"> <property name="enabled">
<bool>false</bool> <bool>false</bool>
@@ -93,66 +33,6 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>Markdown editor</string>
</attribute>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QPlainTextEdit" name="contentEdit">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<kerning>false</kerning>
</font>
</property>
<property name="lineWrapMode">
<enum>QPlainTextEdit::LineWrapMode::NoWrap</enum>
</property>
</widget>
</item>
<item>
<widget class="QWebEngineView" name="webEngineEditor" native="true">
<property name="minimumSize">
<size>
<width>200</width>
<height>200</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Markdown viewer</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QWebEngineView" name="webEngineViewer" native="true"/>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QToolBar" name="toolBar"> <widget class="QToolBar" name="toolBar">
<property name="enabled"> <property name="enabled">
<bool>true</bool> <bool>true</bool>
@@ -191,6 +71,96 @@
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionSettings"/> <addaction name="actionSettings"/>
</widget> </widget>
<widget class="QDockWidget" name="dockWidget_2">
<property name="minimumSize">
<size>
<width>500</width>
<height>84</height>
</size>
</property>
<property name="features">
<set>QDockWidget::DockWidgetFeature::DockWidgetFloatable|QDockWidget::DockWidgetFeature::DockWidgetMovable</set>
</property>
<attribute name="dockWidgetArea">
<number>2</number>
</attribute>
<widget class="QWidget" name="dockWidgetContents_2">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QWebEngineView" name="webEngineViewer" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QProgressBar" name="renderingProgressBar">
<property name="maximumSize">
<size>
<width>160</width>
<height>16777215</height>
</size>
</property>
<property name="maximum">
<number>0</number>
</property>
<property name="value">
<number>0</number>
</property>
<property name="invertedAppearance">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<widget class="QDockWidget" name="dockWidget_3">
<property name="minimumSize">
<size>
<width>250</width>
<height>120</height>
</size>
</property>
<property name="features">
<set>QDockWidget::DockWidgetFeature::NoDockWidgetFeatures</set>
</property>
<attribute name="dockWidgetArea">
<number>1</number>
</attribute>
<widget class="QWidget" name="dockWidgetContents_3">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QTreeWidget" name="treeWidget">
<property name="maximumSize">
<size>
<width>250</width>
<height>16777215</height>
</size>
</property>
<property name="editTriggers">
<set>QAbstractItemView::EditTrigger::NoEditTriggers</set>
</property>
<property name="animated">
<bool>true</bool>
</property>
<column>
<property name="text">
<string notr="true">Workspace</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
</widget>
<action name="actionAdd"> <action name="actionAdd">
<property name="enabled"> <property name="enabled">
<bool>false</bool> <bool>false</bool>

5
static.qrc Normal file
View File

@@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/css">
<file>resources/style.css</file>
</qresource>
</RCC>