diff options
Diffstat (limited to 'src/ui/widgets')
-rw-r--r-- | src/ui/widgets/Attachments.cpp | 180 | ||||
-rw-r--r-- | src/ui/widgets/EditorPage.cpp | 106 | ||||
-rw-r--r-- | src/ui/widgets/FilePage.cpp | 88 | ||||
-rw-r--r-- | src/ui/widgets/HelpPage.cpp | 83 | ||||
-rw-r--r-- | src/ui/widgets/InfoBoardWidget.cpp | 2 | ||||
-rw-r--r-- | src/ui/widgets/KeyList.cpp | 69 | ||||
-rw-r--r-- | src/ui/widgets/TextEdit.cpp | 564 | ||||
-rw-r--r-- | src/ui/widgets/VerifyKeyDetailBox.cpp | 2 |
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)); } |