From fc36dfed0d67f8bb8347577be1c20ecf5606eb78 Mon Sep 17 00:00:00 2001 From: Markus Hovorka Date: Mon, 3 Jul 2017 14:43:47 +0200 Subject: [PATCH] Add TextDocument with full size editor A new document object App::TextDocument. It has a property Text which holds the text of the document as a string. This commit also contains a full size editor based on QPlainTextEdit. It can only be used by the TextDocument and has a read only mode invoked for read only documents (ReadOnly property set to true). The editor is invoked by a double click on the TextDocument. --- src/App/Application.cpp | 2 + src/App/CMakeLists.txt | 2 + src/App/TextDocument.cpp | 63 ++++++++ src/App/TextDocument.h | 61 +++++++ src/Gui/Application.cpp | 2 + src/Gui/CMakeLists.txt | 5 + src/Gui/Icons/TextDocument.svg | 230 +++++++++++++++++++++++++++ src/Gui/Icons/resource.qrc | 1 + src/Gui/TextDocumentEditorView.cpp | 168 +++++++++++++++++++ src/Gui/TextDocumentEditorView.h | 71 +++++++++ src/Gui/ViewProviderTextDocument.cpp | 72 +++++++++ src/Gui/ViewProviderTextDocument.h | 49 ++++++ 12 files changed, 726 insertions(+) create mode 100644 src/App/TextDocument.cpp create mode 100644 src/App/TextDocument.h create mode 100644 src/Gui/Icons/TextDocument.svg create mode 100644 src/Gui/TextDocumentEditorView.cpp create mode 100644 src/Gui/TextDocumentEditorView.h create mode 100644 src/Gui/ViewProviderTextDocument.cpp create mode 100644 src/Gui/ViewProviderTextDocument.h diff --git a/src/App/Application.cpp b/src/App/Application.cpp index 23925fe2a7..36be8c761f 100644 --- a/src/App/Application.cpp +++ b/src/App/Application.cpp @@ -106,6 +106,7 @@ #include "OriginFeature.h" #include "Origin.h" #include "MaterialObject.h" +#include "TextDocument.h" #include "Expression.h" #include "Transactions.h" #include @@ -1301,6 +1302,7 @@ void Application::initTypes(void) App ::MeasureDistance ::init(); App ::MaterialObject ::init(); App ::MaterialObjectPython ::init(); + App ::TextDocument ::init(); App ::Placement ::init(); App ::OriginFeature ::init(); App ::Plane ::init(); diff --git a/src/App/CMakeLists.txt b/src/App/CMakeLists.txt index 4c4de306c7..9ad7024b87 100644 --- a/src/App/CMakeLists.txt +++ b/src/App/CMakeLists.txt @@ -150,6 +150,7 @@ SET(Document_CPP_SRCS VRMLObject.cpp MaterialObject.cpp MergeDocuments.cpp + TextDocument.cpp ) SET(Document_HPP_SRCS @@ -187,6 +188,7 @@ SET(Document_HPP_SRCS VRMLObject.h MaterialObject.h MergeDocuments.h + TextDocument.h ) SET(Document_SRCS ${Document_CPP_SRCS} diff --git a/src/App/TextDocument.cpp b/src/App/TextDocument.cpp new file mode 100644 index 0000000000..625d9ba040 --- /dev/null +++ b/src/App/TextDocument.cpp @@ -0,0 +1,63 @@ +/*************************************************************************** + * Copyright (c) 2017 Markus Hovorka * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" + +#include +#include +#include + +#include "DocumentObject.h" +#include "TextDocument.h" + + +using namespace App; + +PROPERTY_SOURCE(App::TextDocument, App::DocumentObject) + +TextDocument::TextDocument() +{ + ADD_PROPERTY_TYPE( + Text, (""), 0, App::Prop_Hidden, + "Content of the document."); + ADD_PROPERTY_TYPE( + ReadOnly, (false), 0, App::Prop_None, + "Defines whether the content can be edited."); +} + +void TextDocument::onChanged(const Property* prop) +{ + if (prop == &Text) + textChanged(); + DocumentObject::onChanged(prop); +} + +const char* TextDocument::getViewProviderName() const +{ + return "Gui::ViewProviderTextDocument"; +} + +boost::signals2::connection TextDocument::connect(const TextSlot &sub) +{ + return textChanged.connect(sub); +} diff --git a/src/App/TextDocument.h b/src/App/TextDocument.h new file mode 100644 index 0000000000..bb628cecdc --- /dev/null +++ b/src/App/TextDocument.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * Copyright (c) 2017 Markus Hovorka * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef APP_TEXTDOCUMENT_H +#define APP_TEXTDOCUMENT_H + + +#include +#include + +#include "DocumentObject.h" +#include "PropertyStandard.h" + + +namespace App +{ + +class AppExport TextDocument : public App::DocumentObject { + PROPERTY_HEADER(App::TextDocument); +public: + using TextSignal = boost::signals2::signal; + using TextSlot = TextSignal::slot_type; + + PropertyString Text; + PropertyBool ReadOnly; + + TextDocument(); + ~TextDocument() {}; + + void onChanged(const Property* prop); + const char* getViewProviderName() const; + + boost::signals2::connection connect(const TextSlot &sub); +private: + TextSignal textChanged; +}; + +} + + +#endif diff --git a/src/Gui/Application.cpp b/src/Gui/Application.cpp index 9489a43dfd..6ea262a5e2 100644 --- a/src/Gui/Application.cpp +++ b/src/Gui/Application.cpp @@ -115,6 +115,7 @@ #include "ViewProviderPart.h" #include "ViewProviderOrigin.h" #include "ViewProviderMaterialObject.h" +#include "ViewProviderTextDocument.h" #include "ViewProviderGroupExtension.h" #include "Language/Translator.h" @@ -1547,6 +1548,7 @@ void Application::initTypes(void) Gui::ViewProviderOrigin ::init(); Gui::ViewProviderMaterialObject ::init(); Gui::ViewProviderMaterialObjectPython ::init(); + Gui::ViewProviderTextDocument ::init(); // Workbench Gui::Workbench ::init(); diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index f332924b4d..4839548443 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -242,6 +242,7 @@ set(Gui_MOC_HDRS DockWindowManager.h DocumentRecovery.h EditorView.h + TextDocumentEditorView.h ExpressionCompleter.h DlgExpressionInput.h FileDialog.h @@ -631,6 +632,7 @@ SOURCE_GROUP("Dock Windows" FILES ${Dock_Windows_SRCS}) SET(Editor_CPP_SRCS CallTips.cpp EditorView.cpp + TextDocumentEditorView.cpp PythonConsole.cpp PythonConsolePy.cpp PythonDebugger.cpp @@ -641,6 +643,7 @@ SET(Editor_CPP_SRCS SET(Editor_HPP_SRCS CallTips.h EditorView.h + TextDocumentEditorView.h PythonConsole.h PythonConsolePy.h PythonDebugger.h @@ -896,6 +899,7 @@ SET(Viewprovider_CPP_SRCS ViewProviderPart.cpp ViewProviderOrigin.cpp ViewProviderMaterialObject.cpp + ViewProviderTextDocument.cpp ) SET(Viewprovider_SRCS ${Viewprovider_CPP_SRCS} @@ -924,6 +928,7 @@ SET(Viewprovider_SRCS ViewProviderPart.h ViewProviderOrigin.h ViewProviderMaterialObject.h + ViewProviderTextDocument.h ) SOURCE_GROUP("View3D\\Viewprovider" FILES ${Viewprovider_SRCS}) diff --git a/src/Gui/Icons/TextDocument.svg b/src/Gui/Icons/TextDocument.svg new file mode 100644 index 0000000000..5735b436ba --- /dev/null +++ b/src/Gui/Icons/TextDocument.svg @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + 2005-10-15 + + + Andreas Nilsson + + + + + edit + copy + + + + + + Jakub Steiner + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Gui/Icons/resource.qrc b/src/Gui/Icons/resource.qrc index c976aee3aa..9d3890449a 100644 --- a/src/Gui/Icons/resource.qrc +++ b/src/Gui/Icons/resource.qrc @@ -11,6 +11,7 @@ freecad.svg freecad-doc.png bulb.svg + TextDocument.svg button_down.svg button_left.svg button_right.svg diff --git a/src/Gui/TextDocumentEditorView.cpp b/src/Gui/TextDocumentEditorView.cpp new file mode 100644 index 0000000000..b223f960bb --- /dev/null +++ b/src/Gui/TextDocumentEditorView.cpp @@ -0,0 +1,168 @@ +/*************************************************************************** + * Copyright (c) 2017 Markus Hovorka * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "TextDocumentEditorView.h" + + +using namespace Gui; + +TextDocumentEditorView::TextDocumentEditorView( + App::TextDocument* txtDoc, QPlainTextEdit* e, + QWidget* parent) + : MDIView( + Application::Instance->getDocument(txtDoc->getDocument()), + parent), + editor {e}, textDocument {txtDoc} +{ + setupEditor(); + setupConnection(); + setCentralWidget(editor); +} + +TextDocumentEditorView::~TextDocumentEditorView() +{ + textConnection.disconnect(); +} + +bool TextDocumentEditorView::event(QEvent *event) +{ + if (event->type() == QEvent::Show && sourceModified) { + refresh(); + sourceModified = false; + } + return MDIView::event(event); +} + +void TextDocumentEditorView::setupEditor() +{ + connect(getEditor()->document(), SIGNAL(modificationChanged(bool)), + this, SLOT(setWindowModified(bool))); + getEditor()->setReadOnly(textDocument->ReadOnly.getValue()); + setWindowTitle(QString::fromLatin1(textDocument->Label.getValue()) + + QString::fromLatin1("[*]")); + getEditor()->setPlainText( + QString::fromUtf8(textDocument->Text.getValue())); +} + +void TextDocumentEditorView::setupConnection() +{ + textConnection = textDocument->connect( + boost::bind(&TextDocumentEditorView::sourceChanged, this)); +} + +void TextDocumentEditorView::sourceChanged() +{ + if (getMainWindow()->activeWindow() == this) { + refresh(); + sourceModified = false; + } else { + sourceModified = true; + } +} + +void TextDocumentEditorView::refresh() +{ + QString text = QString::fromStdString( + textDocument->Text.getStrValue()); + if (isEditorModified()) { + QMessageBox msgBox {this}; + msgBox.setWindowTitle(QString::fromUtf8("Text updated")); + msgBox.setIcon(QMessageBox::Question); + msgBox.setText(QString::fromUtf8( + "The text of the underlying object has changed. " + "Discard changes and reload the text from the object?")); + QPushButton* yesBtt = msgBox.addButton( + QString::fromUtf8("Yes, reload."), QMessageBox::YesRole); + QPushButton* noBtt = msgBox.addButton( + QString::fromUtf8("No"), QMessageBox::NoRole); + msgBox.exec(); + if (msgBox.clickedButton() == noBtt) + return; + } + getEditor()->setPlainText(text); +} + +bool TextDocumentEditorView::onMsg(const char* msg, const char**) +{ + if (strcmp(msg,"Save") == 0) { + saveToObject(); + return true; + } + return false; +} + +bool TextDocumentEditorView::isEditorModified() const +{ + return getEditor()->document()->isModified(); +} + +bool TextDocumentEditorView::onHasMsg(const char* msg) const +{ + if (strcmp(msg,"Save") == 0) + return isEditorModified(); + return false; +} + +bool TextDocumentEditorView::canClose() +{ + if (!getEditor()->document()->isModified()) + return true; + + this->setFocus(); + + QString question { + tr("The document has been modified.\n" + "Do you want to save your changes?")}; + auto reply = QMessageBox::question( + this, tr("Unsaved document"), question, + QMessageBox::Yes|QMessageBox::Default, QMessageBox::No, + QMessageBox::Cancel|QMessageBox::Escape); + if (reply == QMessageBox::Yes) + saveToObject(); + return reply != QMessageBox::Cancel; +} + +void TextDocumentEditorView::saveToObject() +{ + boost::signals2::shared_connection_block textBlock {textConnection}; + textDocument->Text.setValue( + getEditor()->document()->toPlainText().toStdString()); + getEditor()->document()->setModified(false); +} + + +#include "moc_TextDocumentEditorView.cpp" diff --git a/src/Gui/TextDocumentEditorView.h b/src/Gui/TextDocumentEditorView.h new file mode 100644 index 0000000000..34d116b5af --- /dev/null +++ b/src/Gui/TextDocumentEditorView.h @@ -0,0 +1,71 @@ +/*************************************************************************** + * Copyright (c) 2017 Markus Hovorka * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef GUI_TEXTDOCUMENTEDITORVIEW_H +#define GUI_TEXTDOCUMENTEDITORVIEW_H + +#include "PreCompiled.h" + +#include +#include +#include + +#include +#include +#include + + +namespace Gui { + +class GuiExport TextDocumentEditorView : public MDIView { + Q_OBJECT +public: + TextDocumentEditorView( + App::TextDocument* textDocument, + QPlainTextEdit* editor, QWidget* parent); + ~TextDocumentEditorView(); + const char *getName() const { return "TextDocumentEditorView"; } + bool onMsg(const char* msg, const char**); + bool onHasMsg(const char* msg) const; + bool canClose() override; + + bool event(QEvent *event); + + QPlainTextEdit* getEditor() const { return editor; } + App::TextDocument* getTextObject() const { return textDocument; } +private: + void setupEditor(); + void setupConnection(); + void saveToObject(); + void sourceChanged(); + void refresh(); + bool isEditorModified() const; + QPlainTextEdit *const editor; + App::TextDocument *const textDocument; + boost::signals2::connection textConnection; + bool sourceModified = false; +}; + +} + +#endif diff --git a/src/Gui/ViewProviderTextDocument.cpp b/src/Gui/ViewProviderTextDocument.cpp new file mode 100644 index 0000000000..cb4e7fdfae --- /dev/null +++ b/src/Gui/ViewProviderTextDocument.cpp @@ -0,0 +1,72 @@ +/*************************************************************************** + * Copyright (c) 2017 Markus Hovorka * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" + +#ifndef _PreComp_ +#include +#endif + +#include +#include +#include +#include +#include + +#include "ViewProviderTextDocument.h" + + +using namespace Gui; + +PROPERTY_SOURCE(Gui::ViewProviderTextDocument, Gui::ViewProviderDocumentObject) + +ViewProviderTextDocument::ViewProviderTextDocument() +{ + sPixmap = "TextDocument"; +} + +bool ViewProviderTextDocument::doubleClicked() +{ + if (!activateView()) { + auto* editorWidget = new QPlainTextEdit {}; + getMainWindow()->addWindow( + new TextDocumentEditorView { + static_cast(getObject()), + editorWidget, getMainWindow()}); + } + return true; +} + +bool ViewProviderTextDocument::activateView() const +{ + auto views = getDocument()->getMDIViewsOfType( + TextDocumentEditorView::getClassTypeId()); + for (auto v : views) { + auto textView = static_cast(v); + if (textView->getTextObject() == getObject()) { + getMainWindow()->setActiveWindow(textView); + return true; + } + } + return false; +} diff --git a/src/Gui/ViewProviderTextDocument.h b/src/Gui/ViewProviderTextDocument.h new file mode 100644 index 0000000000..e8c9e89ab9 --- /dev/null +++ b/src/Gui/ViewProviderTextDocument.h @@ -0,0 +1,49 @@ +/*************************************************************************** + * Copyright (c) 2017 Markus Hovorka * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef GUI_ViewProviderTextDocument_H +#define GUI_ViewProviderTextDocument_H + + +#include "PreCompiled.h" +#include "ViewProviderDocumentObject.h" + + +namespace Gui { + +class GuiExport ViewProviderTextDocument : public ViewProviderDocumentObject { + PROPERTY_HEADER(Gui::ViewProviderTextDocument); +public: + ViewProviderTextDocument(); + ~ViewProviderTextDocument() {} + + bool doubleClicked(); + bool isShow() const { return true; } +private: + bool activateView() const; +}; + +} + +#endif +