aboutsummaryrefslogtreecommitdiffstats
path: root/src/ui/widgets
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/widgets')
-rw-r--r--src/ui/widgets/Attachments.cpp180
-rw-r--r--src/ui/widgets/EditorPage.cpp106
-rw-r--r--src/ui/widgets/FilePage.cpp88
-rw-r--r--src/ui/widgets/HelpPage.cpp83
-rw-r--r--src/ui/widgets/InfoBoardWidget.cpp2
-rw-r--r--src/ui/widgets/KeyList.cpp69
-rw-r--r--src/ui/widgets/TextEdit.cpp564
-rw-r--r--src/ui/widgets/VerifyKeyDetailBox.cpp2
8 files changed, 1037 insertions, 57 deletions
diff --git a/src/ui/widgets/Attachments.cpp b/src/ui/widgets/Attachments.cpp
new file mode 100644
index 00000000..8f741f66
--- /dev/null
+++ b/src/ui/widgets/Attachments.cpp
@@ -0,0 +1,180 @@
+/**
+ * This file is part of GPGFrontend.
+ *
+ * GPGFrontend 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+/* TODO:
+ * - check content encoding (base64 / quoted-printable) and apply appropriate opperation (maybe already in mime.cpp)
+ * - check memory usage, use less copy operations / more references
+ * - possibility to clear attachment-view , e.g. with decryption or encrypting a new message
+ * - save all: like in thunderbird, one folder, all files go there
+ */
+
+/*
+ * - save, delete (clear) all
+ * - each line save & clear button
+ * - attached files to view-menu
+ * - also an open button, whichs should save file to tmp-folder, and open with correct app (via QDesktopServices)
+ */
+
+
+#include "ui/widgets/Attachments.h"
+
+Attachments::Attachments(QWidget *parent)
+ : QWidget(parent) {
+ table = new AttachmentTableModel(this);
+
+ tableView = new QTableView;
+ tableView->setModel(table);
+ tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
+ // only one entry should be selected at time
+ tableView->setSelectionMode(QAbstractItemView::SingleSelection);
+ tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ tableView->setFocusPolicy(Qt::NoFocus);
+ tableView->setAlternatingRowColors(true);
+ tableView->verticalHeader()->hide();
+ tableView->setShowGrid(false);
+ tableView->setColumnWidth(0, 300);
+ tableView->horizontalHeader()->setStretchLastSection(true);
+
+ auto *layout = new QVBoxLayout;
+ layout->addWidget(tableView);
+ layout->setContentsMargins(0, 0, 0, 0);
+ setLayout(layout);
+ createActions();
+
+}
+
+void Attachments::contextMenuEvent(QContextMenuEvent *event) {
+ QMenu menu(this);
+ menu.addAction(saveFileAct);
+ // enable open with only if allowed by user
+ if (settings.value("mime/openAttachment").toBool())
+ menu.addAction(openFileAct);
+
+ menu.exec(event->globalPos());
+}
+
+void Attachments::createActions() {
+ saveFileAct = new QAction(tr("Save File"), this);
+ saveFileAct->setToolTip(tr("Save this file"));
+ saveFileAct->setIcon(QIcon(":filesave.png"));
+ connect(saveFileAct, SIGNAL(triggered()), this, SLOT(slotSaveFile()));
+
+ openFileAct = new QAction(tr("Open File"), this);
+ openFileAct->setToolTip(tr("Open this file"));
+ openFileAct->setIcon(QIcon(":fileopen.png"));
+ connect(openFileAct, SIGNAL(triggered()), this, SLOT(slotOpenFile()));
+
+}
+
+void Attachments::slotSaveFile() {
+
+ QModelIndexList indexes = tableView->selectionModel()->selection().indexes();
+
+ if (indexes.empty()) {
+ return;
+ }
+
+ // only singe-selection possible now: TODO: foreach
+ MimePart mp = table->getMimePart(indexes.at(0).row());
+ QString filename = mp.header.getParam("Content-Type", "name");
+ // TODO: find out why filename is quoted
+ filename.chop(1);
+ filename.remove(0, 1);
+ // TODO: check if really base64
+ saveByteArrayToFile(QByteArray::fromBase64(mp.body), filename);
+
+}
+
+void Attachments::saveByteArrayToFile(QByteArray outBuffer, QString filename) {
+
+ //QString path="";
+ QString path = std::move(filename);
+ QString outfileName = QFileDialog::getSaveFileName(this, tr("Save File"), path);
+
+ if (outfileName.isEmpty()) return;
+
+ QFile outfile(outfileName);
+ if (!outfile.open(QFile::WriteOnly)) {
+ QMessageBox::warning(this, tr("File"),
+ tr("Cannot write file %1:\n%2.")
+ .arg(outfileName)
+ .arg(outfile.errorString()));
+ return;
+ }
+
+ QDataStream out(&outfile);
+ out.writeRawData(outBuffer.data(), outBuffer.length());
+ outfile.close();
+}
+
+/**
+ * WIP: TODO:
+ * - create attachments dir if not existing
+ * - ask for cleanup of dir on exit
+ * - remove code-duplication with saveByteArrayToFile
+ */
+void Attachments::slotOpenFile() {
+
+ // TODO: make attachmentdir constant or configurable
+ QString attachmentDir = qApp->applicationDirPath() + "/attachments/";
+ //QDir p = QDir(qApp->applicationDirPath() + "/attachments/");
+ if (!QDir(attachmentDir).exists()) {
+ QDir().mkpath(attachmentDir);
+ }
+
+ QModelIndexList indexes = tableView->selectionModel()->selection().indexes();
+ MimePart mp = table->getMimePart(indexes.at(0).row());
+
+// qDebug() << "mime: " << mp.header.getValue("Content-Type");
+
+ QString filename = mp.header.getParam("Content-Type", "name");
+ // TODO: find out why filename is quoted
+// qDebug() << "file: " << filename;
+ filename.chop(1);
+ filename.remove(0, 1);
+ filename.prepend(attachmentDir);
+
+ // qDebug() << "file: " << filename;
+ QByteArray outBuffer = QByteArray::fromBase64(mp.body);
+
+
+ QFile outfile(filename);
+ if (!outfile.open(QFile::WriteOnly)) {
+ QMessageBox::warning(this, tr("File"),
+ tr("Cannot write file %1:\n%2.")
+ .arg(filename)
+ .arg(outfile.errorString()));
+ return;
+ }
+
+ QDataStream out(&outfile);
+ out.writeRawData(outBuffer.data(), outBuffer.length());
+ outfile.close();
+ QDesktopServices::openUrl(QUrl("file://" + filename, QUrl::TolerantMode));
+}
+
+void Attachments::addMimePart(MimePart *mp) {
+ table->add(*mp);
+}
+
diff --git a/src/ui/widgets/EditorPage.cpp b/src/ui/widgets/EditorPage.cpp
new file mode 100644
index 00000000..cb4ca5ef
--- /dev/null
+++ b/src/ui/widgets/EditorPage.cpp
@@ -0,0 +1,106 @@
+/**
+ * This file is part of GPGFrontend.
+ *
+ * GPGFrontend 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "ui/widgets/EditorPage.h"
+
+#include <utility>
+
+EditorPage::EditorPage(QString filePath, QWidget *parent) : QWidget(parent),
+ fullFilePath(std::move(filePath)) {
+ // Set the Textedit properties
+ textPage = new QTextEdit();
+ textPage->setAcceptRichText(false);
+
+ // Set the layout style
+ mainLayout = new QVBoxLayout();
+ mainLayout->setSpacing(0);
+ mainLayout->addWidget(textPage);
+ mainLayout->setContentsMargins(0, 0, 0, 0);
+ setLayout(mainLayout);
+
+ setAttribute(Qt::WA_DeleteOnClose);
+ textPage->setFocus();
+
+ //connect(textPage, SIGNAL(textChanged()), this, SLOT(formatGpgHeader()));
+}
+
+const QString &EditorPage::getFilePath() const {
+ return fullFilePath;
+}
+
+QTextEdit *EditorPage::getTextPage() {
+ return textPage;
+}
+
+void EditorPage::setFilePath(const QString &filePath) {
+ fullFilePath = filePath;
+}
+
+void EditorPage::showNotificationWidget(QWidget *widget, const char *className) {
+ widget->setProperty(className, true);
+ mainLayout->addWidget(widget);
+}
+
+void EditorPage::closeNoteByClass(const char *className) {
+ QList<QWidget *> widgets = findChildren<QWidget *>();
+ foreach(QWidget *widget, widgets) {
+ if (widget->property(className) == true) {
+ widget->close();
+ }
+ }
+}
+
+void EditorPage::slotFormatGpgHeader() {
+
+ QString content = textPage->toPlainText();
+
+ // Get positions of the gpg-headers, if they exist
+ int start = content.indexOf(GpgConstants::PGP_SIGNED_BEGIN);
+ int startSig = content.indexOf(GpgConstants::PGP_SIGNATURE_BEGIN);
+ int endSig = content.indexOf(GpgConstants::PGP_SIGNATURE_END);
+
+ if (start < 0 || startSig < 0 || endSig < 0 || signMarked) {
+ return;
+ }
+
+ signMarked = true;
+
+ // Set the fontstyle for the header
+ QTextCharFormat signFormat;
+ signFormat.setForeground(QBrush(QColor::fromRgb(80, 80, 80)));
+ signFormat.setFontPointSize(9);
+
+ // set font style for the signature
+ QTextCursor cursor(textPage->document());
+ cursor.setPosition(startSig, QTextCursor::MoveAnchor);
+ cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, endSig);
+ cursor.setCharFormat(signFormat);
+
+ // set the font style for the header
+ int headEnd = content.indexOf("\n\n", start);
+ cursor.setPosition(start, QTextCursor::MoveAnchor);
+ cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, headEnd);
+ cursor.setCharFormat(signFormat);
+
+}
diff --git a/src/ui/widgets/FilePage.cpp b/src/ui/widgets/FilePage.cpp
new file mode 100644
index 00000000..e3d73670
--- /dev/null
+++ b/src/ui/widgets/FilePage.cpp
@@ -0,0 +1,88 @@
+/**
+ * This file is part of GPGFrontend.
+ *
+ * GPGFrontend 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "ui/widgets/FilePage.h"
+
+FilePage::FilePage(QWidget *parent) : QWidget(parent) {
+ qDebug() << "New File Page";
+
+ dirModel = new QFileSystemModel();
+
+ dirModel->setRootPath(QDir::currentPath());
+
+ dirTreeView = new QTreeView();
+ dirTreeView->setModel(dirModel);
+ dirTreeView->setAnimated(true);
+ dirTreeView->setIndentation(20);
+ dirTreeView->setSortingEnabled(true);
+ dirTreeView->setRootIndex(dirModel->index(QDir::currentPath()));
+
+ upLevelButton = new QPushButton("UP Level");
+ connect(upLevelButton, SIGNAL(clicked(bool)), this, SLOT(slotUpLevel()));
+
+ auto *menuLayout = new QHBoxLayout();
+ menuLayout->addWidget(upLevelButton);
+ menuLayout->addStretch(0);
+
+ auto *layout = new QVBoxLayout();
+ layout->addLayout(menuLayout);
+ layout->addWidget(dirTreeView);
+
+ this->setLayout(layout);
+
+ connect(dirTreeView, SIGNAL(clicked(const QModelIndex &)), this, SLOT(fileTreeViewItemClicked(const QModelIndex &)));
+ connect(dirTreeView, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(fileTreeViewItemDoubleClicked(const QModelIndex &)));
+
+}
+
+void FilePage::fileTreeViewItemClicked(const QModelIndex &index) {
+ mPath = dirModel->fileInfo(index).absoluteFilePath();
+ qDebug() << "mPath" << mPath;
+}
+
+void FilePage::slotUpLevel() {
+ QModelIndex currentRoot = dirTreeView->rootIndex();
+ mPath = dirModel->fileInfo(currentRoot).absoluteFilePath();
+ auto fileInfo = QFileInfo(mPath);
+ if(fileInfo.isDir() && fileInfo.isReadable() && fileInfo.isExecutable()) {
+ dirTreeView->setRootIndex(currentRoot.parent());
+ }
+ qDebug() << "Current Root mPath" << mPath;
+}
+
+void FilePage::fileTreeViewItemDoubleClicked(const QModelIndex &index) {
+ mPath = dirModel->fileInfo(index).absoluteFilePath();
+ auto fileInfo = QFileInfo(mPath);
+ if(fileInfo.isDir() && fileInfo.isReadable() && fileInfo.isExecutable()) {
+ dirTreeView->setRootIndex(index);
+ }
+ qDebug() << "Index mPath" << mPath;
+}
+
+void FilePage::getSelected(QString &path) {
+ QModelIndex index = dirTreeView->currentIndex();
+ QVariant data = dirTreeView->model()->data(index);
+ path = data.toString();
+ qDebug() << "Target Path" << mPath;
+}
diff --git a/src/ui/widgets/HelpPage.cpp b/src/ui/widgets/HelpPage.cpp
new file mode 100644
index 00000000..e018da81
--- /dev/null
+++ b/src/ui/widgets/HelpPage.cpp
@@ -0,0 +1,83 @@
+/**
+ * This file is part of GPGFrontend.
+ *
+ * GPGFrontend 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "ui/widgets/HelpPage.h"
+
+#include <utility>
+
+HelpPage::HelpPage(const QString &path, QWidget *parent) :
+ QWidget(parent) {
+
+ browser = new QTextBrowser();
+ auto *mainLayout = new QVBoxLayout();
+ mainLayout->setSpacing(0);
+ mainLayout->addWidget(browser);
+ mainLayout->setContentsMargins(0, 0, 0, 0);
+ setLayout(mainLayout);
+
+ connect(browser, SIGNAL(anchorClicked(QUrl)), this, SLOT(slotOpenUrl(QUrl)));
+ browser->setOpenLinks(false);
+ browser->setSource(localizedHelp(QUrl(path)));
+ browser->setFocus();
+
+}
+
+void HelpPage::slotOpenUrl(const QUrl &url) {
+ browser->setSource(localizedHelp(url));
+};
+
+/**
+ * @brief HelpPage::localizedHelp
+ * check if the requested file is also available with the locale,
+ * e.g. return index.de.html if index.html was requested but the
+ * locale is de and index.de.html is available
+ * @param url
+ * @return
+ */
+QUrl HelpPage::localizedHelp(const QUrl &url) {
+ QString path = url.toLocalFile();
+ QString filename = path.mid(path.lastIndexOf("/") + 1);
+ QString filepath = path.left(path.lastIndexOf("/") + 1);
+ QStringList fileparts = filename.split(".");
+
+ //QSettings settings;
+ QString lang = QSettings().value("int/lang", QLocale::system().name()).toString();
+ if (lang.isEmpty()) {
+ lang = QLocale::system().name();
+ }
+
+ fileparts.insert(1, lang);
+ QString langfile = filepath + fileparts.join(".");
+
+ if (QFile(QUrl(langfile).toLocalFile()).exists()) {
+ return langfile;
+ } else {
+ return path;
+ }
+
+}
+
+QTextBrowser *HelpPage::getBrowser() {
+ return browser;
+}
diff --git a/src/ui/widgets/InfoBoardWidget.cpp b/src/ui/widgets/InfoBoardWidget.cpp
index bfd0c643..76f82505 100644
--- a/src/ui/widgets/InfoBoardWidget.cpp
+++ b/src/ui/widgets/InfoBoardWidget.cpp
@@ -60,7 +60,7 @@ InfoBoardWidget::InfoBoardWidget(QWidget *parent, GpgME::GpgContext *ctx, KeyLis
}
void InfoBoardWidget::slotImportFromKeyserver() {
- auto *importDialog = new KeyServerImportDialog(mCtx, mKeyList, this);
+ auto *importDialog = new KeyServerImportDialog(mCtx, mKeyList, false, this);
importDialog->slotImport(*keysNotInList);
}
diff --git a/src/ui/widgets/KeyList.cpp b/src/ui/widgets/KeyList.cpp
index dccf1a56..6982c3a2 100644
--- a/src/ui/widgets/KeyList.cpp
+++ b/src/ui/widgets/KeyList.cpp
@@ -30,7 +30,8 @@ KeyList::KeyList(GpgME::GpgContext *ctx,
KeyListRow::KeyType selectType,
KeyListColumn::InfoType infoType,
QWidget *parent)
- : QWidget(parent), mSelectType(selectType), mInfoType(infoType)
+ : QWidget(parent), mSelectType(selectType), mInfoType(infoType), appPath(qApp->applicationDirPath()),
+ settings(appPath + "/conf/gpgfrontend.ini", QSettings::IniFormat)
{
mCtx = ctx;
@@ -304,14 +305,12 @@ void KeyList::addMenuAction(QAction *act)
void KeyList::dropEvent(QDropEvent* event)
{
-// importKeyDialog();
- QSettings settings;
auto *dialog = new QDialog();
dialog->setWindowTitle(tr("Import Keys"));
QLabel *label;
- label = new QLabel(tr("You've dropped something on the keylist.\n gpg4usb will now try to import key(s).")+"\n");
+ label = new QLabel(tr("You've dropped something on the table.\n GpgFrontend will now try to import key(s).")+"\n");
// "always import keys"-CheckBox
auto *checkBox = new QCheckBox(tr("Always import without bothering."));
@@ -345,7 +344,7 @@ void KeyList::dropEvent(QDropEvent* event)
if (event->mimeData()->hasUrls())
{
- foreach (QUrl tmp, event->mimeData()->urls())
+ for (const QUrl& tmp : event->mimeData()->urls())
{
QFile file;
file.setFileName(tmp.toLocalFile());
@@ -380,56 +379,7 @@ void KeyList::dragEnterEvent(QDragEnterEvent *event)
void KeyList::importKeys(QByteArray inBuffer)
{
GpgImportInformation result = mCtx->importKey(std::move(inBuffer));
- new KeyImportDetailDialog(mCtx, result, this);
-}
-
-void KeyList::uploadKeyToServer(QByteArray *keys)
-{
- QUrl reqUrl("http://localhost:11371/pks/add");
- qnam = new QNetworkAccessManager(this);
-
- QUrl params;
- keys->replace("\n", "%0D%0A")
- .replace("(", "%28")
- .replace(")", "%29")
- .replace("/", "%2F")
- .replace(":", "%3A")
- .replace("+","%2B")
- .replace(' ', '+');
-
- QUrlQuery q;
-
- q.addQueryItem("keytext", *keys);
-
- params = q.query(QUrl::FullyEncoded).toUtf8();
-
- QNetworkRequest req(reqUrl);
-
- req.setHeader(QNetworkRequest::ContentTypeHeader,"application/x-www-form-urlencoded");
-
- QNetworkReply *reply = qnam->post(req,params.toEncoded());
- connect(reply, SIGNAL(finished()),
- this, SLOT(uploadFinished()));
- qDebug() << "REQURL: " << reqUrl;
- qDebug() << "PARAMS.ENCODED: " << params.toEncoded();
-}
-
-void KeyList::uploadFinished()
-{
- auto *reply = qobject_cast<QNetworkReply *>(sender());
-
- QByteArray response = reply->readAll();
- qDebug() << "RESPNOSE: " << response.data();
- //reply->readAll();
- qDebug() << "ERROR: " << reply->error();
- if (reply->error()) {
- qDebug() << "Error while contacting keyserver!";
- return;
- } else {
- qDebug() << "Success while contacting keyserver!";
- }
-
- reply->deleteLater();
+ new KeyImportDetailDialog(mCtx, result, false, this);
}
void KeyList::getCheckedKeys(QVector<GpgKey> &keys) {
@@ -472,3 +422,12 @@ void KeyList::getPrivateCheckedKeys(QVector<GpgKey> &keys) {
}
}
}
+
+GpgKey KeyList::getSelectedKey() {
+ for (int i = 0; i < mKeyList->rowCount(); i++) {
+ if (mKeyList->item(i, 0)->isSelected() == 1) {
+ return buffered_keys[i];
+ }
+ }
+ return GpgKey();
+}
diff --git a/src/ui/widgets/TextEdit.cpp b/src/ui/widgets/TextEdit.cpp
new file mode 100644
index 00000000..49049baa
--- /dev/null
+++ b/src/ui/widgets/TextEdit.cpp
@@ -0,0 +1,564 @@
+/**
+ * This file is part of GPGFrontend.
+ *
+ * GPGFrontend 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "ui/widgets/TextEdit.h"
+
+TextEdit::TextEdit() {
+ countPage = 0;
+ tabWidget = new QTabWidget(this);
+ tabWidget->setMovable(true);
+ tabWidget->setTabsClosable(true);
+ tabWidget->setDocumentMode(true);
+
+ auto *layout = new QVBoxLayout;
+ layout->addWidget(tabWidget);
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->setSpacing(0);
+ setLayout(layout);
+
+ // Front in same width
+ this->setFont({"Courier"});
+
+ connect(tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(removeTab(int)));
+ slotNewTab();
+ setAcceptDrops(false);
+}
+
+void TextEdit::slotNewTab() {
+ QString header = tr("untitled") +
+ QString::number(++countPage) + ".txt";
+
+ auto *page = new EditorPage();
+ tabWidget->addTab(page, header);
+ tabWidget->setCurrentIndex(tabWidget->count() - 1);
+ page->getTextPage()->setFocus();
+ connect(page->getTextPage()->document(), SIGNAL(modificationChanged(bool)), this, SLOT(slotShowModified()));
+}
+
+void TextEdit::slotNewHelpTab(const QString &title, const QString &path) const {
+
+ auto *page = new HelpPage(path);
+ tabWidget->addTab(page, title);
+ tabWidget->setCurrentIndex(tabWidget->count() - 1);
+
+}
+
+void TextEdit::slotNewFileTab() const {
+
+ auto *page = new FilePage();
+ tabWidget->addTab(page, "File");
+ tabWidget->setCurrentIndex(tabWidget->count() - 1);
+
+}
+
+void TextEdit::slotOpen() {
+ QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Open file"),
+ QDir::currentPath());
+ foreach (QString fileName, fileNames) {
+ if (!fileName.isEmpty()) {
+ QFile file(fileName);
+
+ if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ auto *page = new EditorPage(fileName);
+
+ QTextStream in(&file);
+ QApplication::setOverrideCursor(Qt::WaitCursor);
+ page->getTextPage()->setPlainText(in.readAll());
+ page->setFilePath(fileName);
+ QTextDocument *document = page->getTextPage()->document();
+ document->setModified(false);
+
+ tabWidget->addTab(page, strippedName(fileName));
+ tabWidget->setCurrentIndex(tabWidget->count() - 1);
+ QApplication::restoreOverrideCursor();
+ page->getTextPage()->setFocus();
+ connect(page->getTextPage()->document(), SIGNAL(modificationChanged(bool)), this,
+ SLOT(slotShowModified()));
+ //enableAction(true)
+ file.close();
+ } else {
+ QMessageBox::warning(this, tr("Application"),
+ tr("Cannot read file %1:\n%2.")
+ .arg(fileName)
+ .arg(file.errorString()));
+ }
+ }
+ }
+}
+
+void TextEdit::slotSave() {
+ if (tabWidget->count() == 0 || slotCurPage() == 0) {
+ return;
+ }
+
+ QString fileName = slotCurPage()->getFilePath();
+
+ if (fileName.isEmpty()) {
+ //QString docname = tabWidget->tabText(tabWidget->currentIndex());
+ //docname.remove(0,2);
+ slotSaveAs();
+ } else {
+ saveFile(fileName);
+ }
+}
+
+bool TextEdit::saveFile(const QString &fileName) {
+ if (fileName.isEmpty()) {
+ return false;
+ }
+
+ QFile file(fileName);
+
+ if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ EditorPage *page = slotCurPage();
+
+ QTextStream outputStream(&file);
+ QApplication::setOverrideCursor(Qt::WaitCursor);
+ outputStream << page->getTextPage()->toPlainText();
+ QApplication::restoreOverrideCursor();
+ QTextDocument *document = page->getTextPage()->document();
+
+ document->setModified(false);
+
+ int curIndex = tabWidget->currentIndex();
+ tabWidget->setTabText(curIndex, strippedName(fileName));
+ page->setFilePath(fileName);
+ // statusBar()->showMessage(tr("File saved"), 2000);
+ file.close();
+ return true;
+ } else {
+ QMessageBox::warning(this, tr("File"),
+ tr("Cannot write file %1:\n%2.")
+ .arg(fileName)
+ .arg(file.errorString()));
+ return false;
+ }
+}
+
+
+bool TextEdit::slotSaveAs() {
+ if (tabWidget->count() == 0 || slotCurPage() == 0) {
+ return true;
+ }
+
+ EditorPage *page = slotCurPage();
+ QString path;
+ if (page->getFilePath() != "") {
+ path = page->getFilePath();
+ } else {
+ path = tabWidget->tabText(tabWidget->currentIndex()).remove(0, 2);
+ }
+
+ QString fileName = QFileDialog::getSaveFileName(this, tr("Save file "),
+ path);
+ return saveFile(fileName);
+}
+
+void TextEdit::slotCloseTab() {
+ removeTab(tabWidget->currentIndex());
+ if (tabWidget->count() != 0) {
+ slotCurPage()->getTextPage()->setFocus();
+ }
+}
+
+void TextEdit::removeTab(int index) {
+ // Do nothing, if no tab is opened
+ if (tabWidget->count() == 0) {
+ return;
+ }
+
+ // get the index of the actual current tab
+ int lastIndex = tabWidget->currentIndex();
+
+ // set the focus to argument index
+ tabWidget->setCurrentIndex(index);
+
+ if (maybeSaveCurrentTab(true)) {
+ tabWidget->removeTab(index);
+
+ if (index >= lastIndex) {
+ tabWidget->setCurrentIndex(lastIndex);
+ } else {
+ tabWidget->setCurrentIndex(lastIndex - 1);
+ }
+ }
+
+ if (tabWidget->count() == 0) {
+ // enableAction(false);
+ }
+}
+
+
+/**
+ * Check if current may need to be saved.
+ * Call this function before closing the currently active tab-
+ *
+ * If it returns false, the close event should be aborted.
+ */
+bool TextEdit::maybeSaveCurrentTab(bool askToSave) {
+
+ EditorPage *page = slotCurPage();
+ // if this page is no textedit, there should be nothing to save
+ if (page == nullptr) {
+ return true;
+ }
+ QTextDocument *document = page->getTextPage()->document();
+
+ if (document->isModified()) {
+ QMessageBox::StandardButton result = QMessageBox::Cancel;
+
+ // write title of tab to docname and remove the leading *
+ QString docname = tabWidget->tabText(tabWidget->currentIndex());
+ docname.remove(0, 2);
+
+ const QString &filePath = page->getFilePath();
+ if (askToSave) {
+ result = QMessageBox::warning(this, tr("Unsaved document"),
+ tr("<h3>The document \"%1\" has been modified.<br/>Do you want to save your changes?</h3>").arg(
+ docname) +
+ tr("<b>Note:</b> If you don't save these files, all changes are lost.<br/>"),
+ QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
+ }
+ if ((result == QMessageBox::Save) || (!askToSave)) {
+ if (filePath == "") {
+ //QString docname = tabWidget->tabText(tabWidget->currentIndex());
+ //docname.remove(0,2);
+ return slotSaveAs();
+ } else {
+ return saveFile(filePath);
+ }
+ } else if (result == QMessageBox::Discard) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool TextEdit::maybeSaveAnyTab() {
+ // get a list of all unsaved documents and their tabids
+ QHash<int, QString> unsavedDocs = this->unsavedDocuments();
+
+ /*
+ * no unsaved documents, so app can be closed
+ */
+ if (unsavedDocs.empty()) {
+ return true;
+ }
+ /*
+ * only 1 unsaved document -> set modified tab as current
+ * and show normal unsaved doc dialog
+ */
+ if (unsavedDocs.size() == 1) {
+ int modifiedTab = unsavedDocs.keys().at(0);
+ tabWidget->setCurrentIndex(modifiedTab);
+ return maybeSaveCurrentTab(true);
+ }
+
+ /*
+ * more than one unsaved documents
+ */
+ if (unsavedDocs.size() > 1) {
+ QHashIterator<int, QString> i(unsavedDocs);
+
+ QuitDialog *dialog;
+ dialog = new QuitDialog(this, unsavedDocs);
+ int result = dialog->exec();
+
+ // if result is QDialog::Rejected, discard or cancel was clicked
+ if (result == QDialog::Rejected) {
+ // return true, if discard is clicked, so app can be closed
+ if (dialog->isDiscarded()) {
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ bool allsaved = true;
+ QList<int> tabIdsToSave = dialog->getTabIdsToSave();
+
+ foreach (int tabId, tabIdsToSave) {
+ tabWidget->setCurrentIndex(tabId);
+ if (!maybeSaveCurrentTab(false)) {
+ allsaved = false;
+ }
+ }
+ if (allsaved) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+ // code should never reach this statement
+ return false;
+}
+
+
+QTextEdit *TextEdit::curTextPage() const {
+ auto *curTextPage = qobject_cast<EditorPage *>(tabWidget->currentWidget());
+ if (curTextPage != nullptr) {
+ return curTextPage->getTextPage();
+ } else {
+ return nullptr;
+ }
+}
+
+QTextBrowser *TextEdit::curHelpPage() const {
+ auto *curHelpPage = qobject_cast<HelpPage *>(tabWidget->currentWidget());
+ if (curHelpPage != nullptr) {
+ return curHelpPage->getBrowser();
+ } else {
+ return nullptr;
+ }
+}
+
+int TextEdit::tabCount() const {
+ return tabWidget->count();
+}
+
+EditorPage *TextEdit::slotCurPage() const {
+ auto *curPage = qobject_cast<EditorPage *>(tabWidget->currentWidget());
+ return curPage;
+}
+
+void TextEdit::slotQuote() const {
+ if (tabWidget->count() == 0 || curTextPage() == nullptr) {
+ return;
+ }
+
+ QTextCursor cursor(curTextPage()->document());
+
+ // beginEditBlock and endEditBlock() let operation look like single undo/redo operation
+ cursor.beginEditBlock();
+ cursor.setPosition(0);
+ cursor.insertText("> ");
+ while (!cursor.isNull() && !cursor.atEnd()) {
+ cursor.movePosition(QTextCursor::EndOfLine);
+ cursor.movePosition(QTextCursor::NextCharacter);
+ if (!cursor.atEnd()) {
+ cursor.insertText("> ");
+ }
+ }
+ cursor.endEditBlock();
+}
+
+void TextEdit::slotFillTextEditWithText(const QString &text) const {
+ QTextCursor cursor(curTextPage()->document());
+ cursor.beginEditBlock();
+ this->curTextPage()->selectAll();
+ this->curTextPage()->insertPlainText(text);
+ cursor.endEditBlock();
+}
+
+void TextEdit::loadFile(const QString &fileName) {
+ QFile file(fileName);
+ if (!file.open(QFile::ReadOnly | QFile::Text)) {
+ QMessageBox::warning(this, tr("Application"),
+ tr("Cannot read file %1:\n%2.")
+ .arg(fileName)
+ .arg(file.errorString()));
+ return;
+ }
+ QTextStream in(&file);
+ QApplication::setOverrideCursor(Qt::WaitCursor);
+ curTextPage()->setPlainText(in.readAll());
+ QApplication::restoreOverrideCursor();
+ slotCurPage()->setFilePath(fileName);
+ tabWidget->setTabText(tabWidget->currentIndex(), strippedName(fileName));
+ file.close();
+ // statusBar()->showMessage(tr("File loaded"), 2000);
+}
+
+QString TextEdit::strippedName(const QString &fullFileName) {
+ return QFileInfo(fullFileName).fileName();
+}
+
+void TextEdit::slotPrint() {
+ if (tabWidget->count() == 0) {
+ return;
+ }
+
+#ifndef QT_NO_PRINTER
+ QTextDocument *document;
+ if (curTextPage() == nullptr) {
+ document = curHelpPage()->document();
+ } else {
+ document = curTextPage()->document();
+ }
+ QPrinter printer;
+
+ auto *dlg = new QPrintDialog(&printer, this);
+ if (dlg->exec() != QDialog::Accepted) {
+ return;
+ }
+ document->print(&printer);
+
+ //statusBar()->showMessage(tr("Ready"), 2000);
+#endif
+}
+
+void TextEdit::slotShowModified() const {
+ int index = tabWidget->currentIndex();
+ QString title = tabWidget->tabText(index);
+ // if doc is modified now, add leading * to title,
+ // otherwise remove the leading * from the title
+ if (curTextPage()->document()->isModified()) {
+ tabWidget->setTabText(index, title.prepend("* "));
+ } else {
+ tabWidget->setTabText(index, title.remove(0, 2));
+ }
+}
+
+void TextEdit::slotSwitchTabUp() const {
+ if (tabWidget->count() > 1) {
+ int newindex = (tabWidget->currentIndex() + 1) % (tabWidget->count());
+ tabWidget->setCurrentIndex(newindex);
+ }
+}
+
+void TextEdit::slotSwitchTabDown() const {
+ if (tabWidget->count() > 1) {
+ int newindex = (tabWidget->currentIndex() - 1 + tabWidget->count()) % tabWidget->count();
+ tabWidget->setCurrentIndex(newindex);
+ }
+}
+
+/*
+ * return a hash of tabindexes and title of unsaved tabs
+ */
+QHash<int, QString> TextEdit::unsavedDocuments() const {
+ QHash<int, QString> unsavedDocs; // this list could be used to implement gedit like "unsaved changed"-dialog
+
+ for (int i = 0; i < tabWidget->count(); i++) {
+ auto *ep = qobject_cast<EditorPage *>(tabWidget->widget(i));
+ if (ep != nullptr && ep->getTextPage()->document()->isModified()) {
+ QString docname = tabWidget->tabText(i);
+ // remove * before name of modified doc
+ docname.remove(0, 2);
+ unsavedDocs.insert(i, docname);
+ }
+ }
+ return unsavedDocs;
+}
+
+void TextEdit::slotCut() const {
+ if (tabWidget->count() == 0 || curTextPage() == nullptr) {
+ return;
+ }
+
+ curTextPage()->cut();
+}
+
+void TextEdit::slotCopy() const {
+ if (tabWidget->count() == 0) {
+ return;
+ }
+
+ if (curTextPage() != nullptr) {
+ curTextPage()->copy();
+ } else {
+ curHelpPage()->copy();
+ }
+
+
+}
+
+void TextEdit::slotPaste() const {
+ if (tabWidget->count() == 0 || curTextPage() == nullptr) {
+ return;
+ }
+
+ curTextPage()->paste();
+}
+
+void TextEdit::slotUndo() const {
+ if (tabWidget->count() == 0 || curTextPage() == nullptr) {
+ return;
+ }
+
+ curTextPage()->undo();
+}
+
+void TextEdit::slotRedo() const {
+ if (tabWidget->count() == 0 || curTextPage() == nullptr) {
+ return;
+ }
+
+ curTextPage()->redo();
+}
+
+void TextEdit::slotZoomIn() const {
+ if (tabWidget->count() == 0) {
+ return;
+ }
+
+ if (curTextPage() != nullptr) {
+ curTextPage()->zoomIn();
+ } else {
+ curHelpPage()->zoomIn();
+ }
+
+}
+
+void TextEdit::slotZoomOut() const {
+ if (tabWidget->count() == 0) {
+ return;
+ }
+
+ if (curTextPage() != nullptr) {
+ curTextPage()->zoomOut();
+ } else {
+ curHelpPage()->zoomOut();
+ }
+}
+
+void TextEdit::slotSelectAll() const {
+ if (tabWidget->count() == 0 || curTextPage() == nullptr) {
+ return;
+ }
+
+ curTextPage()->selectAll();
+}
+
+/*void TextEdit::dragEnterEvent(QDragEnterEvent *event)
+{
+ if (event->mimeData()->hasFormat("text/plain"))
+ qDebug() << "enter textedit drag action";
+ event->acceptProposedAction();
+}
+
+void TextEdit::dropEvent(QDropEvent* event)
+{
+ curTextPage()->setPlainText(event->mimeData()->text());
+
+ foreach (QUrl tmp, event->mimeData()->urls())
+ {
+ qDebug() << tmp;
+ }
+
+ //event->acceptProposedAction();
+}
+*/
diff --git a/src/ui/widgets/VerifyKeyDetailBox.cpp b/src/ui/widgets/VerifyKeyDetailBox.cpp
index 3091d672..3a0695b8 100644
--- a/src/ui/widgets/VerifyKeyDetailBox.cpp
+++ b/src/ui/widgets/VerifyKeyDetailBox.cpp
@@ -141,7 +141,7 @@ VerifyKeyDetailBox::VerifyKeyDetailBox(QWidget *parent, GpgME::GpgContext *ctx,
}
void VerifyKeyDetailBox::slotImportFormKeyserver() {
- auto *importDialog = new KeyServerImportDialog(mCtx, mKeyList, this);
+ auto *importDialog = new KeyServerImportDialog(mCtx, mKeyList, false, this);
importDialog->slotImport(QStringList(fpr));
}