diff --git a/kuiviewer/kuiviewer_part.cpp b/kuiviewer/kuiviewer_part.cpp index a5a20d9..c7b4bde 100644 --- a/kuiviewer/kuiviewer_part.cpp +++ b/kuiviewer/kuiviewer_part.cpp @@ -1,283 +1,319 @@ /* * This file is part of the kuiviewer package * Copyright (c) 2003 Richard Moore * Copyright (c) 2003 Ian Reinhart Geiser * Copyright (c) 2017 Friedrich W. H. Kossebau * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License version 2 as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #define TRANSLATION_DOMAIN "kuiviewer" #include "kuiviewer_part.h" #include // KF #include #include #include #include #include #include #include #include // Qt #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY(KUIViewerPartFactory, registerPlugin();) KUIViewerPart::KUIViewerPart(QWidget* parentWidget, QObject* parent, const QVariantList& /*args*/) : KParts::ReadOnlyPart(parent) , m_subWindow(nullptr) , m_view(nullptr) { // we need an instance KAboutData about(QStringLiteral("kuiviewerpart"), i18n("KUIViewerPart"), QStringLiteral("0.2"), i18n("Displays Designer's UI files"), KAboutLicense::LGPL); about.addAuthor(i18n("Richard Moore"), i18n("Original author"), QStringLiteral("rich@kde.org")); about.addAuthor(i18n("Ian Reinhart Geiser"), i18n("Original author"), QStringLiteral("geiseri@kde.org")); setComponentData(about); // this should be your custom internal widget m_widget = new QMdiArea(parentWidget); m_widget->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); m_widget->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); // notify the part that this is our internal widget setWidget(m_widget); // set our XML-UI resource file setXMLFile(QStringLiteral("kuiviewer_part.rc")); m_style = actionCollection()->add(QStringLiteral("change_style")); m_style->setText(i18n("Style")); connect(m_style, static_cast(&KSelectAction::triggered), this, &KUIViewerPart::slotStyle); //m_style->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_S)); m_style->setEditable(false); m_styleFromConfig = KConfigGroup(KSharedConfig::openConfig(), "General").readEntry("currentWidgetStyle", QString()); const QStringList styles = QStyleFactory::keys(); m_style->setItems(QStringList(i18nc("Default style", "Default")) + styles); m_style->setCurrentItem(0); // empty or incorrect value means the default value of currentWidgetStyle, // which leads to the Default option. if (!m_styleFromConfig.isEmpty()) { QStringList::ConstIterator it = styles.begin(); QStringList::ConstIterator end = styles.end(); // Skip the default item int idx = 1; for (; it != end; ++it, ++idx) { if ((*it).toLower() == m_styleFromConfig.toLower()) { m_style->setCurrentItem(idx); break; } } } m_style->setToolTip(i18n("Set the style used for the view.")); m_style->setMenuAccelsEnabled(true); m_copy = KStandardAction::copy(this, &KUIViewerPart::slotGrab, actionCollection()); m_copy->setText(i18n("Copy as Image")); updateActions(); // Commented out to fix warning (rich) // slot should probably be called saveAs() for consistency with // KParts::ReadWritePart BTW. // KStandardAction::saveAs(this, SLOT(slotSave()), actionCollection()); } KUIViewerPart::~KUIViewerPart() { } static QStringList designerPluginPaths() { QStringList paths; const QStringList& libraryPaths = QApplication::libraryPaths(); for (const auto& path : libraryPaths) { paths.append(path + QLatin1String("/designer")); } return paths; } bool KUIViewerPart::openFile() { // m_file is always local so we can use QFile on it QFile file(localFilePath()); if (!file.open(QIODevice::ReadOnly|QIODevice::Text)) { qCDebug(KUIVIEWERPART) << "Could not open UI file: " << file.errorString(); + if (m_previousUrl != url()) { + // drop previous view state + m_previousScrollPosition = QPoint(); + m_previousSize = QSize(); + } return false; } if (m_subWindow) { m_widget->removeSubWindow(m_subWindow); delete m_view; delete m_subWindow; m_subWindow = nullptr; } QFormBuilder builder; builder.setPluginPath(designerPluginPaths()); m_view = builder.load(&file, nullptr); updateActions(); if (!m_view) { qCDebug(KUIVIEWERPART) << "Could not load UI file: " << builder.errorString(); + if (m_previousUrl != url()) { + // drop previous view state + m_previousScrollPosition = QPoint(); + m_previousSize = QSize(); + } return false; } // hack ahead: // UI files have a size set for the widget they define. The QMdiSubWindow relies on sizeHint() // during the show event though it seems, to calculate the initial window size, and then discards // the widget size initially set from the builder in the following layout-ruled geometry update. // Enforcing the initial size by manually setting it afterwards to the widget itself seems not possible, // due to the layout government based on window size. // To inject the initial widget size into the initial window geometry, as hack the min and max sizes are // temporarily set to the wanted size and, once the window is shown, reset to their initial values. const QSize widgetSize = m_view->size(); const QSize origWidgetMinimumSize = m_view->minimumSize(); const QSize origWidgetMaximumSize = m_view->maximumSize(); restyleView(m_style->currentText()); m_view->setMinimumSize(widgetSize); m_view->setMaximumSize(widgetSize); const Qt::WindowFlags windowFlags(Qt::SubWindow|Qt::CustomizeWindowHint|Qt::WindowTitleHint); m_subWindow = m_widget->addSubWindow(m_view, windowFlags); // prevent focus stealing by adding the window in disabled state m_subWindow->setEnabled(false); m_subWindow->show(); // and restore minimum size m_view->setMinimumSize(origWidgetMinimumSize); m_view->setMaximumSize(origWidgetMaximumSize); m_widget->setActiveSubWindow(m_subWindow); m_subWindow->setEnabled(true); + // restore view state if reload + if (url() == m_previousUrl) { + qCDebug(KUIVIEWERPART) << "Restoring previous view state"; + m_subWindow->move(m_previousScrollPosition); + if (m_previousSize.isValid()) { + m_subWindow->resize(m_previousSize); + } + } + return true; } +bool KUIViewerPart::closeUrl() +{ + // store view state if file could be loaded + // otherwise keep old in case same url will get reloaded again and then successfully + if (m_subWindow) { + m_previousScrollPosition = m_subWindow->pos(); + m_previousSize = m_subWindow->size(); + } + // store last used url + const auto activeUrl = url(); + if (activeUrl.isValid()) { + m_previousUrl = activeUrl; + } + + return ReadOnlyPart::closeUrl(); +} + void KUIViewerPart::updateActions() { const bool hasView = !m_view.isNull(); m_style->setEnabled(hasView); m_copy->setEnabled(hasView); } void KUIViewerPart::restyleView(const QString& styleName) { QStyle* style = QStyleFactory::create(styleName); m_view->setStyle(style); const QList childWidgets = m_view->findChildren(); for (auto child : childWidgets) { child->setStyle(style); } } void KUIViewerPart::setWidgetSize(const QSize& size) { if (m_view.isNull()) { return; } // hack: enforce widget size by setting min/max sizes to wanted size // and then have layout update the complete window const QSize origWidgetMinimumSize = m_view->minimumSize(); const QSize origWidgetMaximumSize = m_view->maximumSize(); m_view->setMinimumSize(size); m_view->setMaximumSize(size); m_subWindow->updateGeometry(); // restore m_view->setMinimumSize(origWidgetMinimumSize); m_view->setMaximumSize(origWidgetMaximumSize); } QPixmap KUIViewerPart::renderWidgetAsPixmap() const { if (m_view.isNull()) { return QPixmap(); } return m_view->grab(); } void KUIViewerPart::slotStyle(int) { if (m_view.isNull()) { updateActions(); return; } m_view->hide(); const QString styleName = m_style->currentText(); qCDebug(KUIVIEWERPART) << "Style selectd:" << styleName; restyleView(styleName); m_view->show(); /* the style changed, update the configuration */ if (m_styleFromConfig != styleName) { KSharedConfig::Ptr cfg = KSharedConfig::openConfig(); KConfigGroup cg(cfg, "General"); if (m_style->currentItem() > 0) { /* A style different from the default */ cg.writeEntry("currentWidgetStyle", styleName); } else { /* default style: remove the entry */ cg.deleteEntry("currentWidgetStyle"); } cfg->sync(); } } void KUIViewerPart::slotGrab() { if (m_view.isNull()) { updateActions(); return; } const QPixmap pixmap = m_view->grab(); QApplication::clipboard()->setPixmap(pixmap); } #include "kuiviewer_part.moc" diff --git a/kuiviewer/kuiviewer_part.h b/kuiviewer/kuiviewer_part.h index 50b5c95..aabe97d 100644 --- a/kuiviewer/kuiviewer_part.h +++ b/kuiviewer/kuiviewer_part.h @@ -1,89 +1,93 @@ /* * This file is part of the kuiviewer package * Copyright (c) 2003 Richard Moore * Copyright (c) 2003 Ian Reinhart Geiser * Copyright (c) 2017 Friedrich W. H. Kossebau * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License version 2 as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KUIVIEWERPART_H #define KUIVIEWERPART_H #include "kuiviewer_part_interface.h" // KF #include // Qt #include +#include #include class KSelectAction; class QMdiArea; class QMdiSubWindow; /** * This is a "Part". It that does all the real work in a KPart * application. * * @short Main Part * @author Richard Moore * @version 0.1 */ class KUIViewerPart : public KParts::ReadOnlyPart, public KUIViewerPartInterface { Q_OBJECT Q_INTERFACES(KUIViewerPartInterface) public: /** * Default constructor */ KUIViewerPart(QWidget* parentWidget, QObject* parent, const QVariantList& args); /** * Destructor */ ~KUIViewerPart() override; public Q_SLOTS: void slotStyle(int); void slotGrab(); void updateActions(); public: void setWidgetSize(const QSize& size) override; QPixmap renderWidgetAsPixmap() const override; protected: - /** - * This must be implemented by each part - */ bool openFile() override; + bool closeUrl() override; + private: void restyleView(const QString& styleName); private: QMdiArea* m_widget; QMdiSubWindow* m_subWindow; QPointer m_view; KSelectAction* m_style; QAction* m_copy; QString m_styleFromConfig; + + QUrl m_previousUrl; + QPoint m_previousScrollPosition; + QSize m_previousSize; }; #endif // KUIVIEWERPART_H