Core: Directly store text changes made in text object
Store changes made in TextDocumentEditorView immediately to TextDocument. This fixes the issue reported in https://forum.freecad.org/viewtopic.php?p=786175#p786175
This commit is contained in:
@@ -22,11 +22,11 @@
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
# include <QApplication>
|
||||
# include <QClipboard>
|
||||
# include <QMessageBox>
|
||||
# include <QPushButton>
|
||||
# include <QString>
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QString>
|
||||
#endif
|
||||
|
||||
#include "TextDocumentEditorView.h"
|
||||
@@ -37,25 +37,27 @@
|
||||
|
||||
using namespace Gui;
|
||||
|
||||
TYPESYSTEM_SOURCE_ABSTRACT(Gui::TextDocumentEditorView, Gui::MDIView)
|
||||
TYPESYSTEM_SOURCE_ABSTRACT(Gui::TextDocumentEditorView, Gui::MDIView) // NOLINT
|
||||
|
||||
TextDocumentEditorView::TextDocumentEditorView(
|
||||
App::TextDocument* txtDoc, QPlainTextEdit* e,
|
||||
QWidget* parent)
|
||||
: MDIView(
|
||||
Application::Instance->getDocument(txtDoc->getDocument()),
|
||||
parent),
|
||||
editor {e}, textDocument {txtDoc}
|
||||
TextDocumentEditorView::TextDocumentEditorView(App::TextDocument* txtDoc,
|
||||
QPlainTextEdit* e,
|
||||
QWidget* parent)
|
||||
: MDIView(Application::Instance->getDocument(txtDoc->getDocument()), parent)
|
||||
, editor {e}
|
||||
, textDocument {txtDoc}
|
||||
{
|
||||
setupEditor();
|
||||
setupConnection();
|
||||
setCentralWidget(editor);
|
||||
|
||||
// clang-format off
|
||||
// update editor actions on request
|
||||
Gui::MainWindow* mw = Gui::getMainWindow();
|
||||
connect(editor, &QPlainTextEdit::undoAvailable, mw, &MainWindow::updateEditorActions);
|
||||
connect(editor, &QPlainTextEdit::redoAvailable, mw, &MainWindow::updateEditorActions);
|
||||
connect(editor, &QPlainTextEdit::copyAvailable, mw, &MainWindow::updateEditorActions);
|
||||
connect(editor, &QPlainTextEdit::textChanged, this, &TextDocumentEditorView::textChanged);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
TextDocumentEditorView::~TextDocumentEditorView()
|
||||
@@ -71,11 +73,6 @@ void TextDocumentEditorView::showEvent(QShowEvent* event)
|
||||
MDIView::showEvent(event);
|
||||
}
|
||||
|
||||
void TextDocumentEditorView::hideEvent(QHideEvent* event)
|
||||
{
|
||||
MDIView::hideEvent(event);
|
||||
}
|
||||
|
||||
void TextDocumentEditorView::closeEvent(QCloseEvent* event)
|
||||
{
|
||||
MDIView::closeEvent(event);
|
||||
@@ -86,209 +83,52 @@ void TextDocumentEditorView::closeEvent(QCloseEvent* event)
|
||||
}
|
||||
}
|
||||
|
||||
bool TextDocumentEditorView::event(QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::Show && sourceModified) {
|
||||
refresh();
|
||||
sourceModified = false;
|
||||
}
|
||||
return MDIView::event(event);
|
||||
}
|
||||
|
||||
void TextDocumentEditorView::setupEditor()
|
||||
{
|
||||
// clang-format off
|
||||
connect(getEditor()->document(), &QTextDocument::modificationChanged,
|
||||
this, &TextDocumentEditorView::setWindowModified);
|
||||
setWindowTitle(QString::fromUtf8(textDocument->Label.getValue())
|
||||
+ QString::fromLatin1("[*]"));
|
||||
getEditor()->setPlainText(
|
||||
QString::fromUtf8(textDocument->Text.getValue()));
|
||||
// clang-format on
|
||||
labelChanged();
|
||||
refresh();
|
||||
}
|
||||
|
||||
void TextDocumentEditorView::setupConnection()
|
||||
{
|
||||
//NOLINTBEGIN
|
||||
textConnection = textDocument->connectText(
|
||||
std::bind(&TextDocumentEditorView::sourceChanged, this));
|
||||
labelConnection = textDocument->connectLabel(
|
||||
std::bind(&TextDocumentEditorView::labelChanged, this));
|
||||
//NOLINTEND
|
||||
// NOLINTBEGIN
|
||||
textConnection =
|
||||
textDocument->connectText(std::bind(&TextDocumentEditorView::sourceChanged, this));
|
||||
labelConnection =
|
||||
textDocument->connectLabel(std::bind(&TextDocumentEditorView::labelChanged, this));
|
||||
// NOLINTEND
|
||||
}
|
||||
|
||||
void TextDocumentEditorView::sourceChanged()
|
||||
{
|
||||
if (getMainWindow()->activeWindow() == this) {
|
||||
refresh();
|
||||
sourceModified = false;
|
||||
} else {
|
||||
sourceModified = true;
|
||||
}
|
||||
refresh();
|
||||
}
|
||||
|
||||
void TextDocumentEditorView::textChanged()
|
||||
{
|
||||
saveToObject();
|
||||
}
|
||||
|
||||
void TextDocumentEditorView::labelChanged()
|
||||
{
|
||||
setWindowTitle(QString::fromUtf8(textDocument->Label.getValue())
|
||||
+ QString::fromLatin1("[*]"));
|
||||
setWindowTitle(QString::fromUtf8(textDocument->Label.getValue()) + QString::fromLatin1("[*]"));
|
||||
}
|
||||
|
||||
void TextDocumentEditorView::refresh()
|
||||
{
|
||||
QString text = QString::fromUtf8(
|
||||
textDocument->Text.getValue());
|
||||
if (isEditorModified()) {
|
||||
QMessageBox msgBox {this};
|
||||
msgBox.setWindowTitle(tr("Text updated"));
|
||||
msgBox.setIcon(QMessageBox::Question);
|
||||
msgBox.setText(tr(
|
||||
"The text of the underlying object has changed. "
|
||||
"Discard changes and reload the text from the object?"));
|
||||
msgBox.addButton(
|
||||
tr("Yes, reload."), QMessageBox::YesRole);
|
||||
QPushButton* noBtt = msgBox.addButton(QMessageBox::No);
|
||||
msgBox.exec();
|
||||
if (msgBox.clickedButton() == noBtt)
|
||||
return;
|
||||
}
|
||||
QString text = QString::fromUtf8(textDocument->Text.getValue());
|
||||
getEditor()->setPlainText(text);
|
||||
}
|
||||
|
||||
bool TextDocumentEditorView::onMsg(const char* msg, const char**)
|
||||
{
|
||||
// don't allow any actions if the editor is being closed
|
||||
if (aboutToClose)
|
||||
return false;
|
||||
|
||||
if (strcmp(msg,"Save") == 0) {
|
||||
saveToObject();
|
||||
return getGuiDocument()->save();
|
||||
}
|
||||
if (strcmp(msg,"Cut") == 0) {
|
||||
getEditor()->cut();
|
||||
return true;
|
||||
}
|
||||
if (strcmp(msg,"Copy") == 0) {
|
||||
getEditor()->copy();
|
||||
return true;
|
||||
}
|
||||
if (strcmp(msg,"Paste") == 0) {
|
||||
getEditor()->paste();
|
||||
return true;
|
||||
}
|
||||
if (strcmp(msg,"Undo") == 0) {
|
||||
getEditor()->undo();
|
||||
return true;
|
||||
}
|
||||
if (strcmp(msg,"Redo") == 0) {
|
||||
getEditor()->redo();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TextDocumentEditorView::isEditorModified() const
|
||||
{
|
||||
return getEditor()->document()->isModified();
|
||||
}
|
||||
|
||||
bool TextDocumentEditorView::onHasMsg(const char* msg) const
|
||||
{
|
||||
// don't allow any actions if the editor is being closed
|
||||
if (aboutToClose)
|
||||
return false;
|
||||
|
||||
if (strcmp(msg,"Save") == 0) {
|
||||
return true;
|
||||
}
|
||||
if (strcmp(msg,"Cut") == 0) {
|
||||
return (!getEditor()->isReadOnly() &&
|
||||
getEditor()->textCursor().hasSelection());
|
||||
}
|
||||
if (strcmp(msg,"Copy") == 0) {
|
||||
return (getEditor()->textCursor().hasSelection());
|
||||
}
|
||||
if (strcmp(msg,"Paste") == 0) {
|
||||
if (getEditor()->isReadOnly())
|
||||
return false;
|
||||
QClipboard *cb = QApplication::clipboard();
|
||||
QString text = cb->text();
|
||||
return !text.isEmpty();
|
||||
}
|
||||
if (strcmp(msg,"Undo") == 0) {
|
||||
return (getEditor()->document()->isUndoAvailable());
|
||||
}
|
||||
if (strcmp(msg,"Redo") == 0) {
|
||||
return (getEditor()->document()->isRedoAvailable());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int TextDocumentEditorView::execSaveDialog()
|
||||
{
|
||||
this->setFocus();
|
||||
QMessageBox box(this);
|
||||
box.setIcon(QMessageBox::Question);
|
||||
box.setWindowTitle(tr("Unsaved document"));
|
||||
box.setText(tr("Do you want to save your changes before closing?"));
|
||||
box.setInformativeText(tr("If you don't save, your changes will be lost."));
|
||||
box.setStandardButtons(QMessageBox::Discard | QMessageBox::Cancel | QMessageBox::Save);
|
||||
box.setDefaultButton(QMessageBox::Save);
|
||||
box.setEscapeButton(QMessageBox::Cancel);
|
||||
|
||||
// add shortcuts
|
||||
QAbstractButton* saveBtn = box.button(QMessageBox::Save);
|
||||
if (saveBtn->shortcut().isEmpty()) {
|
||||
QString text = saveBtn->text();
|
||||
text.prepend(QLatin1Char('&'));
|
||||
saveBtn->setShortcut(QKeySequence::mnemonic(text));
|
||||
}
|
||||
|
||||
QAbstractButton* discardBtn = box.button(QMessageBox::Discard);
|
||||
if (discardBtn->shortcut().isEmpty()) {
|
||||
QString text = discardBtn->text();
|
||||
text.prepend(QLatin1Char('&'));
|
||||
discardBtn->setShortcut(QKeySequence::mnemonic(text));
|
||||
}
|
||||
|
||||
box.adjustSize();
|
||||
return box.exec();
|
||||
}
|
||||
|
||||
bool TextDocumentEditorView::canClose()
|
||||
{
|
||||
if (getGuiDocument()->isAboutToClose()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (getEditor()->document()->isModified()) {
|
||||
switch (execSaveDialog())
|
||||
{
|
||||
case QMessageBox::Save:
|
||||
saveToObject();
|
||||
if (getGuiDocument()->isLastView()) {
|
||||
return getGuiDocument()->save();
|
||||
}
|
||||
return true;
|
||||
case QMessageBox::Discard:
|
||||
return true;
|
||||
case QMessageBox::Cancel:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// this view belongs to the document so we have to ask the user
|
||||
// how to continue if this is the last view
|
||||
return MDIView::canClose();
|
||||
}
|
||||
}
|
||||
|
||||
void TextDocumentEditorView::saveToObject()
|
||||
{
|
||||
boost::signals2::shared_connection_block textBlock {textConnection};
|
||||
textDocument->Text.setValue(
|
||||
getEditor()->document()->toPlainText().toUtf8());
|
||||
textDocument->Text.setValue(getEditor()->document()->toPlainText().toUtf8());
|
||||
textDocument->purgeTouched();
|
||||
getEditor()->document()->setModified(false);
|
||||
}
|
||||
|
||||
QStringList TextDocumentEditorView::undoActions() const
|
||||
@@ -305,4 +145,74 @@ QStringList TextDocumentEditorView::redoActions() const
|
||||
return redo;
|
||||
}
|
||||
|
||||
bool TextDocumentEditorView::onHasMsg(const char* msg) const
|
||||
{
|
||||
// don't allow any actions if the editor is being closed
|
||||
if (aboutToClose) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp(msg, "Save") == 0) {
|
||||
return true;
|
||||
}
|
||||
if (strcmp(msg, "Cut") == 0) {
|
||||
return (!getEditor()->isReadOnly() && getEditor()->textCursor().hasSelection());
|
||||
}
|
||||
if (strcmp(msg, "Copy") == 0) {
|
||||
return (getEditor()->textCursor().hasSelection());
|
||||
}
|
||||
if (strcmp(msg, "Paste") == 0) {
|
||||
if (getEditor()->isReadOnly()) {
|
||||
return false;
|
||||
}
|
||||
QClipboard* cb = QApplication::clipboard();
|
||||
QString text = cb->text();
|
||||
return !text.isEmpty();
|
||||
}
|
||||
if (strcmp(msg, "Undo") == 0) {
|
||||
return (getEditor()->document()->isUndoAvailable());
|
||||
}
|
||||
if (strcmp(msg, "Redo") == 0) {
|
||||
return (getEditor()->document()->isRedoAvailable());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TextDocumentEditorView::onMsg(const char* msg, const char** output)
|
||||
{
|
||||
Q_UNUSED(output)
|
||||
|
||||
// don't allow any actions if the editor is being closed
|
||||
if (aboutToClose) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp(msg, "Save") == 0) {
|
||||
saveToObject();
|
||||
getGuiDocument()->save();
|
||||
return true;
|
||||
}
|
||||
if (strcmp(msg, "Cut") == 0) {
|
||||
getEditor()->cut();
|
||||
return true;
|
||||
}
|
||||
if (strcmp(msg, "Copy") == 0) {
|
||||
getEditor()->copy();
|
||||
return true;
|
||||
}
|
||||
if (strcmp(msg, "Paste") == 0) {
|
||||
getEditor()->paste();
|
||||
return true;
|
||||
}
|
||||
if (strcmp(msg, "Undo") == 0) {
|
||||
getEditor()->undo();
|
||||
return true;
|
||||
}
|
||||
if (strcmp(msg, "Redo") == 0) {
|
||||
getEditor()->redo();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#include "moc_TextDocumentEditorView.cpp"
|
||||
|
||||
@@ -23,60 +23,65 @@
|
||||
#ifndef GUI_TEXTDOCUMENTEDITORVIEW_H
|
||||
#define GUI_TEXTDOCUMENTEDITORVIEW_H
|
||||
|
||||
#include <string>
|
||||
#include <QPlainTextEdit>
|
||||
|
||||
#include <App/TextDocument.h>
|
||||
#include <Gui/MDIView.h>
|
||||
|
||||
|
||||
namespace Gui {
|
||||
namespace Gui
|
||||
{
|
||||
|
||||
class GuiExport TextDocumentEditorView : public MDIView {
|
||||
class GuiExport TextDocumentEditorView: public MDIView
|
||||
{
|
||||
Q_OBJECT
|
||||
TYPESYSTEM_HEADER_WITH_OVERRIDE();
|
||||
Q_DISABLE_COPY_MOVE(TextDocumentEditorView)
|
||||
TYPESYSTEM_HEADER_WITH_OVERRIDE(); // NOLINT
|
||||
|
||||
public:
|
||||
TextDocumentEditorView(
|
||||
App::TextDocument* textDocument,
|
||||
QPlainTextEdit* editor, QWidget* parent);
|
||||
TextDocumentEditorView(App::TextDocument* textDocument,
|
||||
QPlainTextEdit* editor,
|
||||
QWidget* parent);
|
||||
~TextDocumentEditorView() override;
|
||||
const char *getName() const override { return "TextDocumentEditorView"; }
|
||||
bool onMsg(const char* msg, const char**) override;
|
||||
const char* getName() const override
|
||||
{
|
||||
return "TextDocumentEditorView";
|
||||
}
|
||||
bool onMsg(const char* msg, const char** output) override;
|
||||
bool onHasMsg(const char* msg) const override;
|
||||
bool canClose() override;
|
||||
|
||||
bool event(QEvent *event) override;
|
||||
|
||||
QPlainTextEdit* getEditor() const { return editor; }
|
||||
App::TextDocument* getTextObject() const { return textDocument; }
|
||||
QPlainTextEdit* getEditor() const
|
||||
{
|
||||
return editor;
|
||||
}
|
||||
App::TextDocument* getTextObject() const
|
||||
{
|
||||
return textDocument;
|
||||
}
|
||||
QStringList undoActions() const override;
|
||||
QStringList redoActions() const override;
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent*) override;
|
||||
void hideEvent(QHideEvent*) override;
|
||||
void closeEvent(QCloseEvent*) override;
|
||||
void showEvent(QShowEvent* event) override;
|
||||
void closeEvent(QCloseEvent* event) override;
|
||||
|
||||
private:
|
||||
void setupEditor();
|
||||
void setupConnection();
|
||||
void saveToObject();
|
||||
void sourceChanged();
|
||||
void textChanged();
|
||||
void labelChanged();
|
||||
void refresh();
|
||||
bool isEditorModified() const;
|
||||
int execSaveDialog();
|
||||
|
||||
private:
|
||||
QPlainTextEdit *const editor;
|
||||
App::TextDocument *const textDocument;
|
||||
QPlainTextEdit* const editor;
|
||||
App::TextDocument* const textDocument;
|
||||
boost::signals2::connection textConnection;
|
||||
boost::signals2::connection labelConnection;
|
||||
bool sourceModified = false;
|
||||
bool aboutToClose = false;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Gui
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user