aboutsummaryrefslogtreecommitdiffstats
path: root/src/ui/widgets/TextEditTabWidget.cpp
diff options
context:
space:
mode:
authorsaturneric <[email protected]>2024-11-24 20:17:43 +0000
committersaturneric <[email protected]>2024-11-24 20:17:43 +0000
commitb4e556d834a0c1e1cedbbda0a91cd892f9105d20 (patch)
tree6fe99ac300a8643daa7177b8f83820acb097f9aa /src/ui/widgets/TextEditTabWidget.cpp
parentfix: solve key list drag and drop refreshing issue (diff)
downloadGpgFrontend-b4e556d834a0c1e1cedbbda0a91cd892f9105d20.tar.gz
GpgFrontend-b4e556d834a0c1e1cedbbda0a91cd892f9105d20.zip
feat: allow drag and drop to open text file
Diffstat (limited to 'src/ui/widgets/TextEditTabWidget.cpp')
-rw-r--r--src/ui/widgets/TextEditTabWidget.cpp242
1 files changed, 242 insertions, 0 deletions
diff --git a/src/ui/widgets/TextEditTabWidget.cpp b/src/ui/widgets/TextEditTabWidget.cpp
new file mode 100644
index 00000000..c782e868
--- /dev/null
+++ b/src/ui/widgets/TextEditTabWidget.cpp
@@ -0,0 +1,242 @@
+/**
+ * Copyright (C) 2021-2024 Saturneric <[email protected]>
+ *
+ * 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.
+ *
+ * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from
+ * the gpg4usb project, which is under GPL-3.0-or-later.
+ *
+ * All the source code of GpgFrontend was modified and released by
+ * Saturneric <[email protected]> starting on May 12, 2021.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+#include "TextEditTabWidget.h"
+
+#include "core/function/GlobalSettingStation.h"
+#include "core/model/CacheObject.h"
+#include "ui/widgets/PlainTextEditorPage.h"
+#include "widgets/FilePage.h"
+
+namespace GpgFrontend::UI {
+
+TextEditTabWidget::TextEditTabWidget(QWidget* parent) : QTabWidget(parent) {
+ setAcceptDrops(true);
+}
+
+void TextEditTabWidget::dragEnterEvent(QDragEnterEvent* event) {
+ event->acceptProposedAction();
+}
+
+void TextEditTabWidget::dropEvent(QDropEvent* event) {
+ if (!event->mimeData()->hasUrls()) return;
+
+ auto urls = event->mimeData()->urls();
+
+ for (const auto& url : urls) {
+ QString local_file = url.toLocalFile();
+
+ QFileInfo file_info(local_file);
+ if (file_info.size() > static_cast<qint64>(1024 * 1024)) {
+ QMessageBox::warning(
+ this, tr("File Too Large"),
+ tr("The file \"%1\" is larger than 1MB and will not be opened.")
+ .arg(file_info.fileName()));
+ continue;
+ }
+
+ QFile file(local_file);
+ if (!file.open(QIODevice::ReadOnly)) {
+ QMessageBox::warning(
+ this, tr("File Open Error"),
+ tr("The file \"%1\" could not be opened.").arg(file_info.fileName()));
+ continue;
+ }
+ QByteArray file_data = file.read(1024);
+ file.close();
+
+ if (file_data.contains('\0')) {
+ QMessageBox::warning(this, tr("Binary File Detected"),
+ tr("The file \"%1\" appears to be a binary file "
+ "and will not be opened.")
+ .arg(file_info.fileName()));
+ continue;
+ }
+
+ SlotOpenFile(local_file);
+ }
+
+ event->acceptProposedAction();
+}
+
+void TextEditTabWidget::SlotOpenFile(const QString& path) {
+ QFile file(path);
+ auto result = file.open(QIODevice::ReadOnly | QIODevice::Text);
+ if (result) {
+ auto* page = new PlainTextEditorPage(path);
+ connect(page->GetTextPage()->document(),
+ &QTextDocument::modificationChanged, this,
+ &TextEditTabWidget::SlotShowModified);
+ // connect to cache recovery fucntion
+ connect(page->GetTextPage()->document(), &QTextDocument::contentsChanged,
+ this, &TextEditTabWidget::slot_save_status_to_cache_for_recovery);
+
+ QApplication::setOverrideCursor(Qt::WaitCursor);
+ auto index = this->addTab(page, stripped_name(path));
+ this->setTabIcon(index, QIcon(":/icons/file.png"));
+ this->setCurrentIndex(this->count() - 1);
+ QApplication::restoreOverrideCursor();
+ page->GetTextPage()->setFocus();
+ page->ReadFile();
+ } else {
+ QMessageBox::warning(
+ this, tr("Warning"),
+ tr("Cannot read file %1:\n%2.").arg(path).arg(file.errorString()));
+ }
+
+ file.close();
+}
+void TextEditTabWidget::SlotShowModified(bool changed) {
+ // get current tab
+ int index = this->currentIndex();
+ QString title = this->tabText(index);
+
+ // if changed
+ if (!changed) {
+ this->setTabText(index, title.remove(0, 2));
+ return;
+ }
+
+ // if doc is modified now, add leading * to title,
+ // otherwise remove the leading * from the title
+ if (CurTextPage()->GetTextPage()->document()->isModified()) {
+ this->setTabText(index, title.trimmed().prepend("* "));
+ } else {
+ this->setTabText(index, title.remove(0, 2));
+ }
+}
+auto TextEditTabWidget::CurTextPage() const -> PlainTextEditorPage* {
+ return qobject_cast<PlainTextEditorPage*>(this->currentWidget());
+}
+
+auto TextEditTabWidget::SlotCurPageTextEdit() -> PlainTextEditorPage* {
+ auto* cur_page = qobject_cast<PlainTextEditorPage*>(this->currentWidget());
+ return cur_page;
+}
+
+auto TextEditTabWidget::CurFilePage() const -> FilePage* {
+ auto* cur_file_page = qobject_cast<FilePage*>(this->currentWidget());
+ if (cur_file_page != nullptr) {
+ return cur_file_page;
+ }
+ return nullptr;
+}
+
+auto TextEditTabWidget::stripped_name(const QString& full_file_name)
+ -> QString {
+ return QFileInfo(full_file_name).fileName();
+}
+
+void TextEditTabWidget::slot_save_status_to_cache_for_recovery() {
+ if (this->text_page_data_modified_count_++ % 8 != 0) return;
+
+ auto settings = GlobalSettingStation::GetInstance().GetSettings();
+
+ bool restore_text_editor_page =
+ settings.value("basic/restore_text_editor_page", false).toBool();
+ if (!restore_text_editor_page) {
+ FLOG_D("restore_text_editor_page is false, ignoring...");
+ return;
+ }
+
+ int tab_count = this->count();
+ std::vector<std::tuple<int, QString, QString>> unsaved_pages;
+
+ for (int i = 0; i < tab_count; i++) {
+ auto* target_page = qobject_cast<PlainTextEditorPage*>(this->widget(i));
+
+ // if this page is no textedit, there should be nothing to save
+ if (target_page == nullptr) {
+ continue;
+ }
+
+ auto* document = target_page->GetTextPage()->document();
+ auto tab_title = this->tabText(i);
+ if (!target_page->ReadDone() || !target_page->isEnabled() ||
+ !document->isModified()) {
+ continue;
+ }
+
+ unsaved_pages.emplace_back(i, tab_title, document->toRawText());
+ }
+
+ CacheObject cache("editor_unsaved_pages");
+ QJsonArray unsaved_page_array;
+ for (const auto& page : unsaved_pages) {
+ const auto [index, title, content] = page;
+
+ QJsonObject page_json;
+ page_json["index"] = index;
+ page_json["title"] = title;
+ page_json["content"] = content;
+
+ unsaved_page_array.push_back(page_json);
+ }
+
+ cache.setArray(unsaved_page_array);
+}
+
+void TextEditTabWidget::SlotNewTab() {
+ QString header = tr("untitled") + QString::number(++count_page_) + ".txt";
+
+ auto* page = new PlainTextEditorPage();
+ auto index = this->addTab(page, header);
+ this->setTabIcon(index, QIcon(":/icons/file.png"));
+ this->setCurrentIndex(this->count() - 1);
+ page->GetTextPage()->setFocus();
+ connect(page->GetTextPage()->document(), &QTextDocument::modificationChanged,
+ this, &TextEditTabWidget::SlotShowModified);
+ connect(page->GetTextPage()->document(), &QTextDocument::contentsChanged,
+ this, &TextEditTabWidget::slot_save_status_to_cache_for_recovery);
+}
+void TextEditTabWidget::SlotNewTabWithContent(QString title,
+ const QString& content) {
+ QString header = tr("untitled") + QString::number(++count_page_) + ".txt";
+ if (!title.isEmpty()) {
+ // modify title
+ if (!title.isEmpty() && title[0] == '*') {
+ title.remove(0, 1);
+ }
+ // set title
+ header = title;
+ }
+
+ auto* page = new PlainTextEditorPage();
+ auto index = this->addTab(page, header);
+ this->setTabIcon(index, QIcon(":/icons/file.png"));
+ this->setCurrentIndex(this->count() - 1);
+ page->GetTextPage()->setFocus();
+ connect(page->GetTextPage()->document(), &QTextDocument::modificationChanged,
+ this, &TextEditTabWidget::SlotShowModified);
+ connect(page->GetTextPage()->document(), &QTextDocument::contentsChanged,
+ this, &TextEditTabWidget::slot_save_status_to_cache_for_recovery);
+
+ // set content with modified status
+ page->GetTextPage()->document()->setPlainText(content);
+}
+} // namespace GpgFrontend::UI