diff --git a/Applications/CoreApp/target_libraries.cmake b/Applications/CoreApp/target_libraries.cmake index 2882a92b6b..1339ede64f 100644 --- a/Applications/CoreApp/target_libraries.cmake +++ b/Applications/CoreApp/target_libraries.cmake @@ -1,9 +1,10 @@ # A list of plug-in targets which should be automatically enabled # (or be available in external projects) for this application. set(target_libraries org_blueberry_compat org_blueberry_ui_qt + org_blueberry_ui_qt_help org_mitk_gui_qt_application ) diff --git a/Applications/ExtApp/target_libraries.cmake b/Applications/ExtApp/target_libraries.cmake index afa3ba95e1..5f13e45c94 100644 --- a/Applications/ExtApp/target_libraries.cmake +++ b/Applications/ExtApp/target_libraries.cmake @@ -1,9 +1,10 @@ # A list of plug-in targets which should be automatically enabled # (or be available in external projects) for this application. set(target_libraries org_blueberry_compat org_blueberry_ui_qt + org_blueberry_ui_qt_help org_mitk_gui_qt_extapplication ) diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/CMakeLists.txt b/BlueBerry/Bundles/org.blueberry.ui.qt.help/CMakeLists.txt new file mode 100644 index 0000000000..cc50551d93 --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/CMakeLists.txt @@ -0,0 +1,13 @@ +PROJECT(org_blueberry_ui_qt_help) + +SET(QT_USE_QTHELP 1) +SET(QT_USE_QTWEBKIT 1) +SET(QT_USE_QTNETWORK 1) + +MACRO_CREATE_CTK_PLUGIN( + EXPORT_DIRECTIVE org_blueberry_ui_qt_help_EXPORT + EXPORTED_INCLUDE_SUFFIXES src +) + +TARGET_LINK_LIBRARIES(${PROJECT_NAME} + ${QT_QTHELP_LIBRARY} ${QT_QTWEBKIT_LIBRARY} ${QT_QTNETWORK_LIBRARY}) diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/documentation/doxygen/modules.dox b/BlueBerry/Bundles/org.blueberry.ui.qt.help/documentation/doxygen/modules.dox new file mode 100644 index 0000000000..5e117fce39 --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/documentation/doxygen/modules.dox @@ -0,0 +1,46 @@ +/** + \defgroup org_blueberry_ui_qt_help org.blueberry.ui.qt.help Plugin + \ingroup BlueBerryPlugins + + \brief Provides access to Qt Help information from inside the Workbench. + + This plug-in collects all Qt QCH files (*.qch) from plug-ins in the RESOLVED + state and registers them internally. The plug-in can be configured using the + CTK Config Admin service and it listens to certain event topics on the CTK + Event Admin. + + The following configuration properties for the service PID "org.blueberry.services.help" + are supported: + + - \b homePage A QString property containing the a qthelp url pointing + to the applications home page. + + The plug-in subscribes to the following event topics: + + - \b org/blueberry/help/CONTEXTHELP_REQUESTED signals a request for showing context + sensitive help. If no properties are attached to the event, a qthelp url is constructed + using the currently active part ID from the workbench. If the url is invalid, the + home page is shown instead. +

+ Supported event properties are: + - \e url Show the given url + + The example below demonstrates how to provide configuration data for the + org.blueberry.ui.qt.help plug-in. + + \snippet org.blueberry.ui.qt.help-config/main.cpp 0 + + Requesting context help may look like this: + + \snippet org.blueberry.ui.qt.help-config/main.cpp 1 + +*/ + +/** + \defgroup org_blueberry_ui_qt_help_internal Internal + \ingroup org_blueberry_ui_qt_help + + \brief This subcategory includes the internal classes of the org.blueberry.ui.qt.help plugin. Other + plugins must not rely on these classes. They contain implementation details and their interface + may change at any time. We mean it. +*/ diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/files.cmake b/BlueBerry/Bundles/org.blueberry.ui.qt.help/files.cmake new file mode 100644 index 0000000000..1e5db2792d --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/files.cmake @@ -0,0 +1,58 @@ +SET(SRC_CPP_FILES + +) + +SET(INTERNAL_CPP_FILES + berryHelpContentView.cpp + berryHelpEditor.cpp + berryHelpEditorFindWidget.cpp + berryHelpEditorInput.cpp + berryHelpIndexView.cpp + berryHelpPerspective.cpp + berryHelpPluginActivator.cpp + berryHelpSearchView.cpp + berryHelpTopicChooser.cpp + berryHelpWebView.cpp + + berryQHelpEngineConfiguration.cpp + berryQHelpEngineWrapper.cpp +) + +SET(CPP_FILES ) + +SET(MOC_H_FILES + src/internal/berryHelpContentView.h + src/internal/berryHelpEditor.h + src/internal/berryHelpEditorFindWidget.h + src/internal/berryHelpIndexView.h + src/internal/berryHelpPerspective.h + src/internal/berryHelpPluginActivator.h + src/internal/berryHelpSearchView.h + src/internal/berryHelpTopicChooser.h + src/internal/berryHelpWebView.h + + src/internal/berryQHelpEngineConfiguration.h + src/internal/berryQHelpEngineWrapper.h +) + +SET(CACHED_RESOURCE_FILES + plugin.xml + + resources/help.png +) + +SET(QRC_FILES + resources/org_blueberry_ui_qt_help.qrc +) + +SET(UI_FILES + src/internal/berryHelpTopicChooser.ui +) + +foreach(file ${SRC_CPP_FILES}) + SET(CPP_FILES ${CPP_FILES} src/${file}) +endforeach(file ${SRC_CPP_FILES}) + +foreach(file ${INTERNAL_CPP_FILES}) + SET(CPP_FILES ${CPP_FILES} src/internal/${file}) +endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/manifest_headers.cmake b/BlueBerry/Bundles/org.blueberry.ui.qt.help/manifest_headers.cmake new file mode 100644 index 0000000000..705b1660ce --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/manifest_headers.cmake @@ -0,0 +1,6 @@ +set(Plugin-Name "BlueBerry Help Plugin") +set(Plugin-Version "1.0.0") +set(Plugin-Vendor "DKFZ, Medical and Biological Informatics") +set(Plugin-ContactAddress "http://www.mitk.org") +set(Require-Plugin org.blueberry.ui.qt) + diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/plugin.xml b/BlueBerry/Bundles/org.blueberry.ui.qt.help/plugin.xml new file mode 100644 index 0000000000..1636232a0f --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/plugin.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/resources/clear.png b/BlueBerry/Bundles/org.blueberry.ui.qt.help/resources/clear.png new file mode 100644 index 0000000000..7132b26959 Binary files /dev/null and b/BlueBerry/Bundles/org.blueberry.ui.qt.help/resources/clear.png differ diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/resources/close.png b/BlueBerry/Bundles/org.blueberry.ui.qt.help/resources/close.png new file mode 100644 index 0000000000..ef9e02086c Binary files /dev/null and b/BlueBerry/Bundles/org.blueberry.ui.qt.help/resources/close.png differ diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/resources/find.png b/BlueBerry/Bundles/org.blueberry.ui.qt.help/resources/find.png new file mode 100644 index 0000000000..1151a3b2cd Binary files /dev/null and b/BlueBerry/Bundles/org.blueberry.ui.qt.help/resources/find.png differ diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/resources/go-home.png b/BlueBerry/Bundles/org.blueberry.ui.qt.help/resources/go-home.png new file mode 100644 index 0000000000..a9ea913383 Binary files /dev/null and b/BlueBerry/Bundles/org.blueberry.ui.qt.help/resources/go-home.png differ diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/resources/go-next.png b/BlueBerry/Bundles/org.blueberry.ui.qt.help/resources/go-next.png new file mode 100644 index 0000000000..b7b093b7b9 Binary files /dev/null and b/BlueBerry/Bundles/org.blueberry.ui.qt.help/resources/go-next.png differ diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/resources/go-previous.png b/BlueBerry/Bundles/org.blueberry.ui.qt.help/resources/go-previous.png new file mode 100644 index 0000000000..00257051db Binary files /dev/null and b/BlueBerry/Bundles/org.blueberry.ui.qt.help/resources/go-previous.png differ diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/resources/help.png b/BlueBerry/Bundles/org.blueberry.ui.qt.help/resources/help.png new file mode 100644 index 0000000000..3d9bb73911 Binary files /dev/null and b/BlueBerry/Bundles/org.blueberry.ui.qt.help/resources/help.png differ diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/resources/org_blueberry_ui_qt_help.qrc b/BlueBerry/Bundles/org.blueberry.ui.qt.help/resources/org_blueberry_ui_qt_help.qrc new file mode 100644 index 0000000000..47b457415b --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/resources/org_blueberry_ui_qt_help.qrc @@ -0,0 +1,12 @@ + + + find.png + go-home.png + go-next.png + go-previous.png + zoom-in.png + zoom-out.png + close.png + clear.png + + diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/resources/zoom-in.png b/BlueBerry/Bundles/org.blueberry.ui.qt.help/resources/zoom-in.png new file mode 100644 index 0000000000..2acdd8f514 Binary files /dev/null and b/BlueBerry/Bundles/org.blueberry.ui.qt.help/resources/zoom-in.png differ diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/resources/zoom-out.png b/BlueBerry/Bundles/org.blueberry.ui.qt.help/resources/zoom-out.png new file mode 100644 index 0000000000..c5524f7284 Binary files /dev/null and b/BlueBerry/Bundles/org.blueberry.ui.qt.help/resources/zoom-out.png differ diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpContentView.cpp b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpContentView.cpp new file mode 100644 index 0000000000..cb456dcf70 --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpContentView.cpp @@ -0,0 +1,211 @@ +/*========================================================================= + +Program: BlueBerry Platform +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifdef __MINGW32__ +// We need to inlclude winbase.h here in order to declare +// atomic intrinsics like InterlockedIncrement correctly. +// Otherwhise, they would be declared wrong within qatomic_windows.h . +#include +#endif + +#include "berryHelpContentView.h" + +#include "berryHelpPluginActivator.h" +#include "berryHelpEditor.h" +#include "berryHelpEditorInput.h" +#include "berryHelpWebView.h" +#include "berryQHelpEngineWrapper.h" + +#include + +#include +#include +#include +#include +#include +#include + +namespace berry { + +HelpContentWidget::HelpContentWidget() + : QTreeView(0) + , m_SortModel(new QSortFilterProxyModel(this)) + , m_SourceModel(0) +{ + header()->hide(); + setUniformRowHeights(true); + connect(this, SIGNAL(activated(QModelIndex)), + this, SLOT(showLink(QModelIndex))); + + m_SortModel->setDynamicSortFilter(true); + QTreeView::setModel(m_SortModel); +} + +QModelIndex HelpContentWidget::indexOf(const QUrl &link) +{ + QHelpContentModel *contentModel = + qobject_cast(m_SourceModel); + if (!contentModel || link.scheme() != QLatin1String("qthelp")) + return QModelIndex(); + + m_syncIndex = QModelIndex(); + for (int i=0; irowCount(); ++i) + { + QHelpContentItem *itm = + contentModel->contentItemAt(contentModel->index(i, 0)); + if (itm && itm->url().host() == link.host()) + { + QString path = link.path(); + if (path.startsWith(QLatin1Char('/'))) + path = path.mid(1); + if (searchContentItem(contentModel, contentModel->index(i, 0), path)) + { + return m_syncIndex; + } + } + } + return QModelIndex(); +} + +void HelpContentWidget::setModel(QAbstractItemModel *model) +{ + m_SourceModel = model; + m_SortModel->setSourceModel(model); +} + +bool HelpContentWidget::searchContentItem(QHelpContentModel *model, + const QModelIndex &parent, const QString &path) +{ + QHelpContentItem *parentItem = model->contentItemAt(parent); + if (!parentItem) + return false; + + if (QDir::cleanPath(parentItem->url().path()) == path) + { + m_syncIndex = m_SortModel->mapFromSource(parent); + return true; + } + + for (int i=0; ichildCount(); ++i) + { + if (searchContentItem(model, model->index(i, 0, parent), path)) + return true; + } + return false; +} + +void HelpContentWidget::showLink(const QModelIndex &index) +{ + QHelpContentModel *contentModel = qobject_cast(m_SourceModel); + if (!contentModel) + return; + + QHelpContentItem *item = contentModel->contentItemAt(m_SortModel->mapToSource(index)); + if (!item) + return; + QUrl url = item->url(); + if (url.isValid()) + emit linkActivated(url); +} + +HelpContentView::HelpContentView() + : m_ContentWidget(0) +{ +} + +HelpContentView::~HelpContentView() +{ +} + +void HelpContentView::CreateQtPartControl(QWidget* parent) +{ + if (m_ContentWidget == 0) + { + QVBoxLayout* verticalLayout = new QVBoxLayout(parent); + verticalLayout->setSpacing(0); + verticalLayout->setContentsMargins(0, 0, 0, 0); + + QHelpEngineWrapper& helpEngine = HelpPluginActivator::getInstance()->getQHelpEngine(); + m_ContentWidget = new HelpContentWidget(); + m_ContentWidget->setModel(helpEngine.contentModel()); + m_ContentWidget->sortByColumn(0, Qt::AscendingOrder); + connect(helpEngine.contentModel(), SIGNAL(contentsCreationStarted()), + this, SLOT(setContentsWidgetBusy())); + connect(helpEngine.contentModel(), SIGNAL(contentsCreated()), + this, SLOT(unsetContentsWidgetBusy())); + verticalLayout->addWidget(m_ContentWidget); + + m_ContentWidget->setContextMenuPolicy(Qt::CustomContextMenu); + + connect(m_ContentWidget, SIGNAL(customContextMenuRequested(QPoint)), + this, SLOT(showContextMenu(QPoint))); + connect(m_ContentWidget, SIGNAL(linkActivated(QUrl)), this, SLOT(linkActivated(QUrl))); + } +} + +void HelpContentView::linkActivated(const QUrl &link) +{ + IWorkbenchPage::Pointer page = this->GetSite()->GetPage(); + HelpPluginActivator::linkActivated(page, link); +} + +void HelpContentView::showContextMenu(const QPoint &pos) +{ + if (!m_ContentWidget->indexAt(pos).isValid()) + return; + + QHelpContentModel* contentModel = + qobject_cast(m_ContentWidget->model()); + QHelpContentItem *itm = + contentModel->contentItemAt(m_ContentWidget->currentIndex()); + + QMenu menu; + QAction *curTab = menu.addAction(tr("Open Link")); + QAction *newTab = menu.addAction(tr("Open Link in New Tab")); + if (!HelpWebView::canOpenPage(itm->url().path())) + newTab->setEnabled(false); + + menu.move(m_ContentWidget->mapToGlobal(pos)); + + QAction *action = menu.exec(); + if (curTab == action) + { + linkActivated(itm->url()); + } + else if (newTab == action) + { + IEditorInput::Pointer input(new HelpEditorInput(itm->url())); + this->GetSite()->GetPage()->OpenEditor(input, HelpEditor::EDITOR_ID); + } +} + +void HelpContentView::SetFocus() +{ + m_ContentWidget->setFocus(); +} + +void HelpContentView::setContentsWidgetBusy() +{ + m_ContentWidget->setCursor(Qt::WaitCursor); +} + +void HelpContentView::unsetContentsWidgetBusy() +{ + m_ContentWidget->unsetCursor(); +} + +} diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpContentView.h b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpContentView.h new file mode 100644 index 0000000000..0cfd3cedab --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpContentView.h @@ -0,0 +1,100 @@ +/*========================================================================= + +Program: BlueBerry Platform +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef BERRYHELPCONTENTVIEW_H_ +#define BERRYHELPCONTENTVIEW_H_ + +#include + +#include + +class QSortFilterProxyModel; +class QHelpContentModel; + +namespace berry { + +class HelpContentWidget : public QTreeView +{ + Q_OBJECT + +public: + HelpContentWidget(); + QModelIndex indexOf(const QUrl &link); + + void setModel(QAbstractItemModel *model); + +Q_SIGNALS: + + /** + * This signal is emitted when a content item is activated and + * its associated \a link should be shown. + */ + void linkActivated(const QUrl &link); + +private Q_SLOTS: + + /** + * Returns the index of the content item with the \a link. + * An invalid index is returned if no such an item exists. + */ + void showLink(const QModelIndex &index); + +private: + bool searchContentItem(QHelpContentModel* model, + const QModelIndex &parent, const QString &path); + QModelIndex m_syncIndex; + QSortFilterProxyModel* m_SortModel; + QAbstractItemModel* m_SourceModel; +}; + +class HelpContentView : public QtViewPart +{ + Q_OBJECT + +public: + + HelpContentView(); + ~HelpContentView(); + + void SetFocus(); + +protected: + + void CreateQtPartControl(QWidget* parent); + +protected Q_SLOTS: + + void linkActivated(const QUrl& link); + +private Q_SLOTS: + + void showContextMenu(const QPoint &pos); + + void setContentsWidgetBusy(); + void unsetContentsWidgetBusy(); + +private: + + Q_DISABLE_COPY(HelpContentView) + + HelpContentWidget* m_ContentWidget; + +}; + +} // namespace berry + +#endif /*BERRYHELPCONTENTVIEW_H_*/ diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpEditor.cpp b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpEditor.cpp new file mode 100644 index 0000000000..4a3e285ebe --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpEditor.cpp @@ -0,0 +1,329 @@ +/*========================================================================= + +Program: BlueBerry Platform +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "berryHelpEditor.h" + +#include "berryHelpEditorInput.h" +#include "berryHelpPluginActivator.h" +#include "berryHelpPerspective.h" +#include "berryHelpWebView.h" +#include "berryQHelpEngineWrapper.h" +#include "berryHelpEditorFindWidget.h" +#include "berryHelpPluginActivator.h" +#include "berryQHelpEngineWrapper.h" + +#include +#include +#include +#include + +#include +#include +#include + +namespace berry { + +const std::string HelpEditor::EDITOR_ID = "org.blueberry.editors.help"; + +HelpEditor::HelpEditor() + : m_ToolBar(0) + , m_WebView(0) +{ + +} + +HelpEditor::~HelpEditor() +{ + // we need to wrap the RemovePartListener call inside a + // register/unregister block to prevent infinite recursion + // due to the destruction of temporary smartpointer to this + this->Register(); + this->GetSite()->GetPage()->RemovePartListener(IPartListener::Pointer(this)); + this->GetSite()->GetPage()->GetWorkbenchWindow()->RemovePerspectiveListener(IPerspectiveListener::Pointer(this)); + this->UnRegister(false); +} + +void HelpEditor::Init(berry::IEditorSite::Pointer site, berry::IEditorInput::Pointer input) +{ + if (input.Cast().IsNull()) + throw PartInitException("Invalid Input: Must be berry::HelpEditorInput"); + + this->SetSite(site); + site->GetPage()->AddPartListener(IPartListener::Pointer(this)); + site->GetPage()->GetWorkbenchWindow()->AddPerspectiveListener(IPerspectiveListener::Pointer(this)); + + m_WebView = new HelpWebView(site, 0); + + connect(m_WebView, SIGNAL(loadFinished(bool)), this, SLOT(InitializeTitle())); + + this->DoSetInput(input); +} + +void HelpEditor::CreateQtPartControl(QWidget* parent) +{ + QVBoxLayout* verticalLayout = new QVBoxLayout(parent); + verticalLayout->setSpacing(0); + verticalLayout->setContentsMargins(0, 0, 0, 0); + + m_ToolBar = new QToolBar(parent); + m_ToolBar->setMaximumHeight(32); + verticalLayout->addWidget(m_ToolBar); + + m_WebView->setParent(parent); + m_WebView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + verticalLayout->addWidget(m_WebView); + + m_FindWidget = new HelpEditorFindWidget(parent); + m_FindWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum); + verticalLayout->addWidget(m_FindWidget); + m_FindWidget->hide(); + + connect(m_FindWidget, SIGNAL(findNext()), this, SLOT(findNext())); + connect(m_FindWidget, SIGNAL(findPrevious()), this, SLOT(findPrevious())); + connect(m_FindWidget, SIGNAL(find(QString, bool)), this, + SLOT(find(QString, bool))); + connect(m_FindWidget, SIGNAL(escapePressed()), m_WebView, SLOT(setFocus())); + + // Fill the editor toolbar + m_BackAction = m_ToolBar->addAction(QIcon(":/org.blueberry.ui.qt.help/go-previous.png"), "Go back", + m_WebView, SLOT(backward())); + m_ForwardAction = m_ToolBar->addAction(QIcon(":/org.blueberry.ui.qt.help/go-next.png"), "Go forward", + m_WebView, SLOT(forward())); + m_HomeAction = m_ToolBar->addAction(QIcon(":/org.blueberry.ui.qt.help/go-home.png"), "Go home", + m_WebView, SLOT(home())); + + m_ToolBar->addSeparator(); + + m_FindAction = m_ToolBar->addAction(QIcon(":/org.blueberry.ui.qt.help/find.png"), "Find in text", + this, SLOT(ShowTextSearch())); + + m_ToolBar->addSeparator(); + + m_ZoomIn = m_ToolBar->addAction(QIcon(":/org.blueberry.ui.qt.help/zoom-in.png"), "Zoom in", m_WebView, SLOT(scaleUp())); + m_ZoomOut = m_ToolBar->addAction(QIcon(":/org.blueberry.ui.qt.help/zoom-out.png"), "Zoom out", m_WebView, SLOT(scaleDown())); + + m_ToolBar->addSeparator(); + + m_OpenHelpMode = m_ToolBar->addAction("Switch to Help mode", this, SLOT(OpenHelpPerspective())); + IPerspectiveDescriptor::Pointer currPersp = this->GetSite()->GetPage()->GetPerspective(); + m_OpenHelpMode->setEnabled(!(currPersp.IsNotNull() && currPersp->GetId() == HelpPerspective::ID)); + + connect(m_WebView, SIGNAL(backwardAvailable(bool)), m_BackAction, SLOT(setEnabled(bool))); + connect(m_WebView, SIGNAL(forwardAvailable(bool)), m_ForwardAction, SLOT(setEnabled(bool))); + + m_BackAction->setEnabled(false); + m_ForwardAction->setEnabled(false); + m_HomeAction->setEnabled(!HelpPluginActivator::getInstance()->getQHelpEngine().homePage().isEmpty()); + + connect(&HelpPluginActivator::getInstance()->getQHelpEngine(), SIGNAL(homePageChanged(QString)), + this, SLOT(HomePageChanged(QString))); +} + +void HelpEditor::DoSetInput(IEditorInput::Pointer input) +{ + if (input.IsNull()) + { + // close editor + class CloseEditorRunnable : public Poco::Runnable + { + private: + IEditorPart::Pointer editor; + + public: + CloseEditorRunnable(IEditorPart::Pointer editor) + : editor(editor) + {} + + void run() + { + editor->GetSite()->GetPage()->CloseEditor(editor, false); + delete this; + } + }; + + Display::GetDefault()->AsyncExec(new CloseEditorRunnable(IEditorPart::Pointer(this))); + } + else + { + // an empty url represents the home page + HelpEditorInput::Pointer helpInput = input.Cast(); + QString currHomePage = HelpPluginActivator::getInstance()->getQHelpEngine().homePage(); + if (helpInput->GetUrl().isEmpty() && !currHomePage.isEmpty()) + { + helpInput = HelpEditorInput::Pointer(new HelpEditorInput(currHomePage)); + } + QtEditorPart::SetInput(helpInput); + m_WebView->setSource(helpInput->GetUrl()); + } +} + +void HelpEditor::SetInputWithNotify(IEditorInput::Pointer input) +{ + DoSetInput(input); + FirePropertyChange(IWorkbenchPartConstants::PROP_INPUT); +} + +void HelpEditor::SetInput(IEditorInput::Pointer input) +{ + SetInputWithNotify(input); +} + +void HelpEditor::HomePageChanged(const QString &page) +{ + if (page.isEmpty()) + { + m_HomeAction->setEnabled(false); + } + + m_HomeAction->setEnabled(true); + if (this->GetEditorInput().Cast()->GetUrl().isEmpty()) + { + IEditorInput::Pointer newInput(new HelpEditorInput(page)); + DoSetInput(newInput); + } +} + +void HelpEditor::OpenHelpPerspective() +{ + PlatformUI::GetWorkbench()->ShowPerspective(HelpPerspective::ID, this->GetSite()->GetPage()->GetWorkbenchWindow()); +} + +void HelpEditor::InitializeTitle() +{ + std::string title = m_WebView->title().toStdString(); + this->SetPartName(title); +} + +void HelpEditor::ShowTextSearch() +{ + m_FindWidget->show(); +} + +void HelpEditor::SetFocus() +{ + m_WebView->setFocus(); + + enableShortcuts(); +} + +QWebPage *HelpEditor::GetQWebPage() const +{ + return m_WebView->page(); +} + +IPartListener::Events::Types HelpEditor::GetPartEventTypes() const +{ + return IPartListener::Events::DEACTIVATED; +} + +void HelpEditor::PartDeactivated(IWorkbenchPartReference::Pointer partRef) +{ + if (partRef == GetSite()->GetPage()->GetReference(IWorkbenchPart::Pointer(this))) + disableShortcuts(); +} + +IPerspectiveListener::Events::Types HelpEditor::GetPerspectiveEventTypes() const +{ + return IPerspectiveListener::Events::ACTIVATED | IPerspectiveListener::Events::DEACTIVATED; +} + +void HelpEditor::PerspectiveActivated(SmartPointer page, IPerspectiveDescriptor::Pointer perspective) +{ + if (perspective->GetId() == HelpPerspective::ID) + { + m_OpenHelpMode->setEnabled(false); + } +} + +void HelpEditor::PerspectiveDeactivated(SmartPointer page, IPerspectiveDescriptor::Pointer perspective) +{ + if (perspective->GetId() == HelpPerspective::ID) + { + m_OpenHelpMode->setEnabled(true); + } +} + +void HelpEditor::findNext() +{ + find(m_FindWidget->text(), true); +} + +void HelpEditor::findPrevious() +{ + find(m_FindWidget->text(), false); +} + +void HelpEditor::find(const QString &ttf, bool forward) +{ + bool found = findInWebPage(ttf, forward); + + if (!found && ttf.isEmpty()) + found = true; // the line edit is empty, no need to mark it red... + + if (!m_FindWidget->isVisible()) + m_FindWidget->show(); + m_FindWidget->setPalette(found); +} + +bool HelpEditor::findInWebPage(const QString &ttf, bool forward) +{ + bool found = false; + QWebPage::FindFlags options; + if (!ttf.isEmpty()) + { + if (!forward) + options |= QWebPage::FindBackward; + + if (m_FindWidget->caseSensitive()) + options |= QWebPage::FindCaseSensitively; + + found = m_WebView->findText(ttf, options); + + if (!found) + { + options |= QWebPage::FindWrapsAroundDocument; + found = m_WebView->findText(ttf, options); + } + } + // force highlighting of all other matches, also when empty (clear) + options = QWebPage::HighlightAllOccurrences; + if (m_FindWidget->caseSensitive()) + options |= QWebPage::FindCaseSensitively; + m_WebView->findText(QLatin1String(""), options); + m_WebView->findText(ttf, options); + return found; +} + +void HelpEditor::enableShortcuts() +{ + m_BackAction->setShortcut(QKeySequence::Back); + m_ForwardAction->setShortcut(QKeySequence::Forward); + m_FindAction->setShortcut(QKeySequence::Find); + m_ZoomIn->setShortcut(QKeySequence::ZoomIn); + m_ZoomOut->setShortcut(QKeySequence::ZoomOut); +} + +void HelpEditor::disableShortcuts() +{ + m_BackAction->setShortcut(QKeySequence()); + m_ForwardAction->setShortcut(QKeySequence()); + m_FindAction->setShortcut(QKeySequence()); + m_ZoomIn->setShortcut(QKeySequence()); + m_ZoomOut->setShortcut(QKeySequence()); +} + +} diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpEditor.h b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpEditor.h new file mode 100644 index 0000000000..41b831f502 --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpEditor.h @@ -0,0 +1,110 @@ +/*========================================================================= + +Program: BlueBerry Platform +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef BERRYHELPEDITOR_H_ +#define BERRYHELPEDITOR_H_ + +#include +#include +#include +#include + +class QToolBar; +class QWebPage; + +namespace berry { + +class HelpWebView; +class HelpEditorFindWidget; + +class HelpEditor : public QtEditorPart, public IReusableEditor, public IPartListener, public IPerspectiveListener +{ + Q_OBJECT + +public: + berryObjectMacro(HelpEditor) + + static const std::string EDITOR_ID; + + HelpEditor(); + ~HelpEditor(); + + void Init(berry::IEditorSite::Pointer site, berry::IEditorInput::Pointer input); + + void SetFocus(); + + void DoSave() {} + void DoSaveAs() {} + bool IsDirty() const { return false; } + bool IsSaveAsAllowed() const { return false; } + + QWebPage* GetQWebPage() const; + + IPartListener::Events::Types GetPartEventTypes() const; + void PartDeactivated(IWorkbenchPartReference::Pointer /*partRef*/); + + IPerspectiveListener::Events::Types GetPerspectiveEventTypes() const; + void PerspectiveActivated(SmartPointer page, IPerspectiveDescriptor::Pointer perspective); + void PerspectiveDeactivated(SmartPointer page, IPerspectiveDescriptor::Pointer perspective); + +protected: + + void CreateQtPartControl(QWidget* parent); + + void DoSetInput(IEditorInput::Pointer input); + void SetInputWithNotify(IEditorInput::Pointer input); + void SetInput(IEditorInput::Pointer input); + +private Q_SLOTS: + + void HomePageChanged(const QString& page); + void OpenHelpPerspective(); + + void InitializeTitle(); + void ShowTextSearch(); + + void findNext(); + void findPrevious(); + void find(const QString& ttf, bool forward); + +private: + + bool findInWebPage(const QString& ttf, bool forward); + + void enableShortcuts(); + void disableShortcuts(); + +private: + + Q_DISABLE_COPY(HelpEditor) + + QToolBar* m_ToolBar; + HelpWebView* m_WebView; + HelpEditorFindWidget* m_FindWidget; + + QAction* m_BackAction; + QAction* m_ForwardAction; + QAction* m_FindAction; + QAction* m_ZoomIn; + QAction* m_ZoomOut; + QAction* m_OpenHelpMode; + QAction* m_HomeAction; +}; + +} // end namespace berry + +#endif /*BERRYHELPEDITOR_H_*/ diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpEditorFindWidget.cpp b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpEditorFindWidget.cpp new file mode 100644 index 0000000000..4bfaaeac99 --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpEditorFindWidget.cpp @@ -0,0 +1,169 @@ +/*========================================================================= + +Program: BlueBerry Platform +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "berryHelpEditorFindWidget.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace berry { + +HelpEditorFindWidget::HelpEditorFindWidget(QWidget *parent) + : QWidget(parent) + , appPalette(qApp->palette()) +{ + installEventFilter(this); + QHBoxLayout *hboxLayout = new QHBoxLayout(this); + QString resourcePath = QLatin1String(":/org.blueberry.ui.qt.help"); + +#ifndef Q_OS_MAC + hboxLayout->setMargin(0); + hboxLayout->setSpacing(6); +#endif + + toolClose = setupToolButton(QLatin1String(""), + resourcePath + QLatin1String("/close.png")); + hboxLayout->addWidget(toolClose); + connect(toolClose, SIGNAL(clicked()), SLOT(hide())); + + editFind = new QLineEdit(this); + hboxLayout->addWidget(editFind); + editFind->setMinimumSize(QSize(150, 0)); + connect(editFind, SIGNAL(textChanged(QString)), this, + SLOT(textChanged(QString))); + connect(editFind, SIGNAL(returnPressed()), this, SIGNAL(findNext())); + connect(editFind, SIGNAL(textChanged(QString)), this, SLOT(updateButtons())); + + toolPrevious = setupToolButton(tr("Previous"), + resourcePath + QLatin1String("/go-previous.png")); + connect(toolPrevious, SIGNAL(clicked()), this, SIGNAL(findPrevious())); + + hboxLayout->addWidget(toolPrevious); + + toolNext = setupToolButton(tr("Next"), + resourcePath + QLatin1String("/go-next.png")); + hboxLayout->addWidget(toolNext); + connect(toolNext, SIGNAL(clicked()), this, SIGNAL(findNext())); + + checkCase = new QCheckBox(tr("Case Sensitive"), this); + hboxLayout->addWidget(checkCase); + + setMinimumWidth(minimumSizeHint().width()); + + updateButtons(); +} + +HelpEditorFindWidget::~HelpEditorFindWidget() +{ +} + +void HelpEditorFindWidget::show() +{ + QWidget::show(); + editFind->selectAll(); + editFind->setFocus(Qt::ShortcutFocusReason); +} + +void HelpEditorFindWidget::showAndClear() +{ + show(); + editFind->clear(); +} + +QString HelpEditorFindWidget::text() const +{ + return editFind->text(); +} + +bool HelpEditorFindWidget::caseSensitive() const +{ + return checkCase->isChecked(); +} + +void HelpEditorFindWidget::setPalette(bool found) +{ + QPalette palette = editFind->palette(); + palette.setColor(QPalette::Active, QPalette::Base, found ? Qt::white + : QColor(255, 102, 102)); + editFind->setPalette(palette); +} + +void HelpEditorFindWidget::hideEvent(QHideEvent* event) +{ + // TODO: remove this once webkit supports setting the palette + if (!event->spontaneous()) + qApp->setPalette(appPalette); +} + +void HelpEditorFindWidget::showEvent(QShowEvent* event) +{ + // TODO: remove this once webkit supports setting the palette + if (!event->spontaneous()) + { + QPalette p = appPalette; + p.setColor(QPalette::Inactive, QPalette::Highlight, + p.color(QPalette::Active, QPalette::Highlight)); + p.setColor(QPalette::Inactive, QPalette::HighlightedText, + p.color(QPalette::Active, QPalette::HighlightedText)); + qApp->setPalette(p); + } +} + +void HelpEditorFindWidget::updateButtons() +{ + const bool enable = !editFind->text().isEmpty(); + toolNext->setEnabled(enable); + toolPrevious->setEnabled(enable); +} + +void HelpEditorFindWidget::textChanged(const QString &text) +{ + emit find(text, true); +} + +bool HelpEditorFindWidget::eventFilter(QObject *object, QEvent *e) +{ + if (e->type() == QEvent::KeyPress) + { + if ((static_cast(e))->key() == Qt::Key_Escape) + { + hide(); + emit escapePressed(); + } + } + return QWidget::eventFilter(object, e); +} + +QToolButton* HelpEditorFindWidget::setupToolButton(const QString &text, const QString &icon) +{ + QToolButton *toolButton = new QToolButton(this); + + toolButton->setText(text); + toolButton->setAutoRaise(true); + toolButton->setIcon(QIcon(icon)); + toolButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + + return toolButton; +} + +} diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpEditorFindWidget.h b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpEditorFindWidget.h new file mode 100644 index 0000000000..784fe1e4db --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpEditorFindWidget.h @@ -0,0 +1,85 @@ +/*========================================================================= + +Program: BlueBerry Platform +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef BERRYHELPEDITORFINDWIDGET_H +#define BERRYHELPEDITORFINDWIDGET_H + +#include + +class QCheckBox; +class QLabel; +class QLineEdit; +class QToolButton; + + +namespace berry { + +class HelpEditorFindWidget : public QWidget +{ + Q_OBJECT + +public: + + HelpEditorFindWidget(QWidget *parent = 0); + ~HelpEditorFindWidget(); + + void show(); + void showAndClear(); + + QString text() const; + bool caseSensitive() const; + + void setPalette(bool found); + +Q_SIGNALS: + + void escapePressed(); + + void findNext(); + void findPrevious(); + void find(const QString &text, bool forward); + +protected: + + void hideEvent(QHideEvent* event); + void showEvent(QShowEvent * event); + +private Q_SLOTS: + + void updateButtons(); + void textChanged(const QString &text); + +private: + + bool eventFilter(QObject *object, QEvent *e); + QToolButton* setupToolButton(const QString &text, const QString &icon); + +private: + + QPalette appPalette; + + QLineEdit *editFind; + QCheckBox *checkCase; + QToolButton *toolNext; + QToolButton *toolClose; + QToolButton *toolPrevious; + +}; + +} // end namespace berry + +#endif // BERRYHELPEDITORFINDWIDGET_H diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpEditorInput.cpp b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpEditorInput.cpp new file mode 100644 index 0000000000..4dc9f12846 --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpEditorInput.cpp @@ -0,0 +1,60 @@ +/*========================================================================= + +Program: BlueBerry Platform +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "berryHelpEditorInput.h" + +#include + +namespace berry +{ + +HelpEditorInput::HelpEditorInput(const QUrl &url) + : url(url) +{ + +} + +bool HelpEditorInput::Exists() const +{ + return !url.isEmpty(); +} + +std::string HelpEditorInput::GetName() const +{ + if (url.isEmpty()) return "Untitled"; + return url.toString().toStdString(); +} + +std::string HelpEditorInput::GetToolTipText() const +{ + return url.toString().toStdString(); +} + +bool HelpEditorInput::operator==(const berry::Object* o) const +{ + if (const HelpEditorInput* input = dynamic_cast(o)) + return this->url == input->url; + + return false; +} + +QUrl HelpEditorInput::GetUrl() const +{ + return url; +} + +} diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpEditorInput.h b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpEditorInput.h new file mode 100644 index 0000000000..cfe862b8e0 --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpEditorInput.h @@ -0,0 +1,50 @@ +/*========================================================================= + +Program: BlueBerry Platform +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef BERRYHELPEDITORINPUT_H_ +#define BERRYHELPEDITORINPUT_H_ + +#include + +#include + +namespace berry +{ + +class HelpEditorInput : public berry::IEditorInput +{ +public: + berryObjectMacro(HelpEditorInput) + + HelpEditorInput(const QUrl& url = QUrl()); + + bool Exists() const; + std::string GetName() const; + std::string GetToolTipText() const; + + bool operator==(const berry::Object*) const; + + QUrl GetUrl() const; + +private: + + QUrl url; +}; + +} + +#endif /*BERRYHELPEDITORINPUT_H_*/ diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpIndexView.cpp b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpIndexView.cpp new file mode 100644 index 0000000000..157c45b041 --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpIndexView.cpp @@ -0,0 +1,326 @@ +/*========================================================================= + +Program: BlueBerry Platform +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifdef __MINGW32__ +// We need to inlclude winbase.h here in order to declare +// atomic intrinsics like InterlockedIncrement correctly. +// Otherwhise, they would be declared wrong within qatomic_windows.h . +#include +#endif + +#include "berryHelpIndexView.h" + +#include "berryHelpPluginActivator.h" +#include "berryHelpEditor.h" +#include "berryHelpEditorInput.h" +#include "berryHelpWebView.h" +#include "berryQHelpEngineWrapper.h" +#include "berryHelpTopicChooser.h" + +#include + +#include + +#include +#include +#include +#include +#include + +namespace berry { + +HelpIndexWidget::HelpIndexWidget() + : QListView(0) +{ + setEditTriggers(QAbstractItemView::NoEditTriggers); + setUniformItemSizes(true); + connect(this, SIGNAL(activated(QModelIndex)), + this, SLOT(showLink(QModelIndex))); +} + +void HelpIndexWidget::showLink(const QModelIndex &index) +{ + if (!index.isValid()) + return; + + QHelpIndexModel *indexModel = qobject_cast(model()); + if (!indexModel) + return; + QVariant v = indexModel->data(index, Qt::DisplayRole); + QString name; + if (v.isValid()) + name = v.toString(); + + QMap links = indexModel->linksForKeyword(name); + if (links.count() == 1) + { + emit linkActivated(links.constBegin().value(), name); + } + else if (links.count() > 1) + { + emit linksActivated(links, name); + } +} + +void HelpIndexWidget::activateCurrentItem() +{ + showLink(currentIndex()); +} + +void HelpIndexWidget::filterIndices(const QString &filter, const QString &wildcard) +{ + QHelpIndexModel *indexModel = qobject_cast(model()); + if (!indexModel) + return; + QModelIndex idx = indexModel->filter(filter, wildcard); + if (idx.isValid()) + setCurrentIndex(idx); +} + +HelpIndexView::HelpIndexView() + : m_IndexWidget(0) +{ +} + +HelpIndexView::~HelpIndexView() +{ +} + +void HelpIndexView::CreateQtPartControl(QWidget* parent) +{ + if (m_IndexWidget == 0) + { + QVBoxLayout *layout = new QVBoxLayout(parent); + //QLabel *l = new QLabel(tr("&Look for:")); + //layout->addWidget(l); + + m_SearchLineEdit = new ctkSearchBox(parent); + m_SearchLineEdit->setClearIcon(QIcon(":/org.blueberry.ui.qt.help/clear.png")); + m_SearchLineEdit->setPlaceholderText("Filter..."); + m_SearchLineEdit->setContentsMargins(2,2,2,0); + //l->setBuddy(m_SearchLineEdit); + connect(m_SearchLineEdit, SIGNAL(textChanged(QString)), this, + SLOT(filterIndices(QString))); + m_SearchLineEdit->installEventFilter(this); + layout->setMargin(0); + layout->setSpacing(2); + layout->addWidget(m_SearchLineEdit); + + QHelpEngineWrapper& helpEngine = HelpPluginActivator::getInstance()->getQHelpEngine(); + m_IndexWidget = new HelpIndexWidget(); + m_IndexWidget->setModel(helpEngine.indexModel()); + connect(helpEngine.indexModel(), SIGNAL(indexCreationStarted()), + this, SLOT(setIndexWidgetBusy())); + connect(helpEngine.indexModel(), SIGNAL(indexCreated()), + this, SLOT(unsetIndexWidgetBusy())); + m_IndexWidget->installEventFilter(this); + + connect(helpEngine.indexModel(), SIGNAL(indexCreationStarted()), this, + SLOT(disableSearchLineEdit())); + connect(helpEngine.indexModel(), SIGNAL(indexCreated()), this, + SLOT(enableSearchLineEdit())); + connect(m_IndexWidget, SIGNAL(linkActivated(QUrl,QString)), this, + SLOT(linkActivated(QUrl))); + connect(m_IndexWidget, SIGNAL(linksActivated(QMap,QString)), + this, SLOT(linksActivated(QMap,QString))); + connect(m_SearchLineEdit, SIGNAL(returnPressed()), m_IndexWidget, + SLOT(activateCurrentItem())); + layout->addWidget(m_IndexWidget); + + m_IndexWidget->viewport()->installEventFilter(this); + } +} + +void HelpIndexView::SetFocus() +{ + if (!(m_IndexWidget->hasFocus() || m_SearchLineEdit->hasFocus())) + { + m_SearchLineEdit->setFocus(); + } +} + +void HelpIndexView::filterIndices(const QString &filter) +{ + if (filter.contains(QLatin1Char('*'))) + m_IndexWidget->filterIndices(filter, filter); + else + m_IndexWidget->filterIndices(filter, QString()); +} + +bool HelpIndexView::eventFilter(QObject *obj, QEvent *e) +{ + if (obj == m_SearchLineEdit && e->type() == QEvent::KeyPress) + { + QKeyEvent *ke = static_cast(e); + QModelIndex idx = m_IndexWidget->currentIndex(); + switch (ke->key()) + { + case Qt::Key_Up: + idx = m_IndexWidget->model()->index(idx.row()-1, + idx.column(), idx.parent()); + if (idx.isValid()) + { + m_IndexWidget->setCurrentIndex(idx); + return true; + } + break; + case Qt::Key_Down: + idx = m_IndexWidget->model()->index(idx.row()+1, + idx.column(), idx.parent()); + if (idx.isValid()) + { + m_IndexWidget->setCurrentIndex(idx); + return true; + } + break; + default: ; // stop complaining + } + } + else if (obj == m_IndexWidget && e->type() == QEvent::ContextMenu) + { + QContextMenuEvent *ctxtEvent = static_cast(e); + QModelIndex idx = m_IndexWidget->indexAt(ctxtEvent->pos()); + if (idx.isValid()) + { + QMenu menu; + QAction *curTab = menu.addAction(tr("Open Link")); + QAction *newTab = menu.addAction(tr("Open Link in New Tab")); + menu.move(m_IndexWidget->mapToGlobal(ctxtEvent->pos())); + + QAction *action = menu.exec(); + if (curTab == action) + m_IndexWidget->activateCurrentItem(); + else if (newTab == action) + { + open(m_IndexWidget, idx); + } + } + } + else if (m_IndexWidget && obj == m_IndexWidget->viewport() + && e->type() == QEvent::MouseButtonRelease) + { + QMouseEvent *mouseEvent = static_cast(e); + QModelIndex idx = m_IndexWidget->indexAt(mouseEvent->pos()); + if (idx.isValid()) + { + Qt::MouseButtons button = mouseEvent->button(); + if (((button == Qt::LeftButton) && (mouseEvent->modifiers() & Qt::ControlModifier)) + || (button == Qt::MidButton)) + { + open(m_IndexWidget, idx); + } + } + } +#ifdef Q_OS_MAC + else if (obj == m_IndexWidget && e->type() == QEvent::KeyPress) + { + QKeyEvent *ke = static_cast(e); + if (ke->key() == Qt::Key_Return || ke->key() == Qt::Key_Enter) + m_IndexWidget->activateCurrentItem(); + } +#endif + return QObject::eventFilter(obj, e); +} + +void HelpIndexView::enableSearchLineEdit() +{ + m_SearchLineEdit->setDisabled(false); + filterIndices(m_SearchLineEdit->text()); +} + +void HelpIndexView::disableSearchLineEdit() +{ + m_SearchLineEdit->setDisabled(true); +} + +void HelpIndexView::setIndexWidgetBusy() +{ + m_IndexWidget->setCursor(Qt::WaitCursor); +} + +void HelpIndexView::unsetIndexWidgetBusy() +{ + m_IndexWidget->unsetCursor(); +} + +void HelpIndexView::setSearchLineEditText(const QString &text) +{ + m_SearchLineEdit->setText(text); +} + +QString HelpIndexView::searchLineEditText() const +{ + return m_SearchLineEdit->text(); +} + +void HelpIndexView::focusInEvent(QFocusEvent *e) +{ + if (e->reason() != Qt::MouseFocusReason) + { + m_SearchLineEdit->selectAll(); + m_SearchLineEdit->setFocus(); + } +} + +void HelpIndexView::open(HelpIndexWidget* indexWidget, const QModelIndex &index) +{ + QHelpIndexModel *model = qobject_cast(indexWidget->model()); + if (model) + { + QString keyword = model->data(index, Qt::DisplayRole).toString(); + QMap links = model->linksForKeyword(keyword); + + QUrl url; + if (links.count() > 1) + { + HelpTopicChooser tc(m_IndexWidget, keyword, links); + if (tc.exec() == QDialog::Accepted) + url = tc.link(); + } + else if (links.count() == 1) + { + url = links.constBegin().value(); + } + else + { + return; + } + + //if (!HelpWebView::canOpenPage(url.path())) + IEditorInput::Pointer input(new HelpEditorInput(url)); + this->GetSite()->GetPage()->OpenEditor(input, HelpEditor::EDITOR_ID); + } +} + +void HelpIndexView::linkActivated(const QUrl& link) +{ + IWorkbenchPage::Pointer page = this->GetSite()->GetPage(); + + HelpPluginActivator::linkActivated(page, link); +} + +void HelpIndexView::linksActivated(const QMap& links, const QString& keyword) +{ + HelpTopicChooser tc(m_IndexWidget, keyword, links); + if (tc.exec() == QDialog::Accepted) + { + IWorkbenchPage::Pointer page = this->GetSite()->GetPage(); + HelpPluginActivator::linkActivated(page, tc.link()); + } +} + +} diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpIndexView.h b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpIndexView.h new file mode 100644 index 0000000000..390ac1a51a --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpIndexView.h @@ -0,0 +1,123 @@ +/*========================================================================= + +Program: BlueBerry Platform +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef BERRYHELPINDEXVIEW_H_ +#define BERRYHELPINDEXVIEW_H_ + +#include + +#include +#include + +class ctkSearchBox; +class QHelpIndexWidget; + +namespace berry { + +class HelpIndexWidget : public QListView +{ + Q_OBJECT + +Q_SIGNALS: + + /** + * This signal is emitted when an item is activated and its + * associated \a link should be shown. To know where the link + * belongs to, the \a keyword is given as a second paremeter. + */ + void linkActivated(const QUrl &link, const QString &keyword); + + /** + * This signal is emitted when the item representing the \a keyword + * is activated and the item has more than one link associated. + * The \a links consist of the document title and their URL. + */ + void linksActivated(const QMap &links, + const QString &keyword); + +public: + + HelpIndexWidget(); + +public Q_SLOTS: + + /** + * Filters the indices according to \a filter or \a wildcard. + * The item with the best match is set as current item. + */ + void filterIndices(const QString &filter, + const QString &wildcard = QString()); + + /** + * Activates the current item which will result eventually in + * the emitting of a linkActivated() or linksActivated() + * signal. + */ + void activateCurrentItem(); + +private Q_SLOTS: + void showLink(const QModelIndex &index); +}; + +class HelpIndexView : public QtViewPart +{ + Q_OBJECT + +public: + + HelpIndexView(); + ~HelpIndexView(); + + void SetFocus(); + +protected: + + void CreateQtPartControl(QWidget* parent); + + void setSearchLineEditText(const QString &text); + QString searchLineEditText() const; + +protected Q_SLOTS: + + void linkActivated(const QUrl& link); + void linksActivated(const QMap &links, const QString &keyword); + +private Q_SLOTS: + + void filterIndices(const QString &filter); + void enableSearchLineEdit(); + void disableSearchLineEdit(); + + void setIndexWidgetBusy(); + void unsetIndexWidgetBusy(); + +private: + + bool eventFilter(QObject *obj, QEvent *e); + void focusInEvent(QFocusEvent *e); + void open(HelpIndexWidget *indexWidget, const QModelIndex &index); + + Q_DISABLE_COPY(HelpIndexView) + + ctkSearchBox* m_SearchLineEdit; + HelpIndexWidget* m_IndexWidget; + +}; + +} // namespace berry + +#endif /*BERRYHELPINDEXVIEW_H_*/ diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpPerspective.cpp b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpPerspective.cpp new file mode 100644 index 0000000000..4cd6fb4410 --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpPerspective.cpp @@ -0,0 +1,42 @@ +/*========================================================================= + + Program: BlueBerry Platform + Language: C++ + Date: $Date$ + Version: $Revision$ + + Copyright (c) German Cancer Research Center, Division of Medical and + Biological Informatics. All rights reserved. + See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "berryHelpPerspective.h" + +namespace berry { + +const std::string HelpPerspective::ID = "org.blueberry.perspectives.help"; + +HelpPerspective::HelpPerspective() +{ + +} + +void HelpPerspective::CreateInitialLayout(berry::IPageLayout::Pointer layout) +{ + std::string editorArea = layout->GetEditorArea(); + + layout->AddView("org.blueberry.views.helpsearch", + berry::IPageLayout::LEFT, 0.3, editorArea); + + berry::IFolderLayout::Pointer leftFolder = + layout->CreateFolder("lefttop", berry::IPageLayout::TOP, 0.65f, "org.blueberry.views.helpsearch"); + leftFolder->AddView("org.blueberry.views.helpcontents"); + leftFolder->AddView("org.blueberry.views.helpindex"); +} + +} diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpPerspective.h b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpPerspective.h new file mode 100644 index 0000000000..40c2004874 --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpPerspective.h @@ -0,0 +1,45 @@ +/*========================================================================= + + Program: BlueBerry Platform + Language: C++ + Date: $Date$ + Version: $Revision$ + + Copyright (c) German Cancer Research Center, Division of Medical and + Biological Informatics. All rights reserved. + See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + + +#ifndef BERRYHELPPERSPECTIVE_H_ +#define BERRYHELPPERSPECTIVE_H_ + +#include + +#include + +namespace berry { + +class HelpPerspective : public QObject, public berry::IPerspectiveFactory +{ + Q_OBJECT + Q_INTERFACES(berry::IPerspectiveFactory) + +public: + + static const std::string ID; + + HelpPerspective(); + + void CreateInitialLayout(berry::IPageLayout::Pointer layout); + +}; + +} + +#endif /* BERRYHELPPERSPECTIVE_H_ */ diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpPluginActivator.cpp b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpPluginActivator.cpp new file mode 100644 index 0000000000..c82c41b90a --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpPluginActivator.cpp @@ -0,0 +1,457 @@ +/*========================================================================= + +Program: BlueBerry Platform +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "berryHelpPluginActivator.h" + +#include "berryHelpContentView.h" +#include "berryHelpIndexView.h" +#include "berryHelpSearchView.h" +#include "berryHelpEditor.h" +#include "berryHelpEditorInput.h" +#include "berryHelpPerspective.h" + +#include "berryQHelpEngineConfiguration.h" +#include "berryQHelpEngineWrapper.h" + +#include + +#include + +#include +#include +#include + +namespace berry { + +class HelpPerspectiveListener : public IPerspectiveListener +{ +public: + + Events::Types GetPerspectiveEventTypes() const; + + void PerspectiveOpened(SmartPointer page, IPerspectiveDescriptor::Pointer perspective); + void PerspectiveChanged(SmartPointer page, IPerspectiveDescriptor::Pointer perspective, const std::string &changeId); +}; + +class HelpWindowListener : public IWindowListener +{ +public: + + HelpWindowListener(); + ~HelpWindowListener(); + + void WindowClosed(IWorkbenchWindow::Pointer window); + void WindowOpened(IWorkbenchWindow::Pointer window); + +private: + + // We use the same perspective listener for every window + IPerspectiveListener::Pointer perspListener; +}; + + +HelpPluginActivator* HelpPluginActivator::instance = 0; + +HelpPluginActivator::HelpPluginActivator() + : pluginListener(0) +{ + this->instance = this; +} + +HelpPluginActivator::~HelpPluginActivator() +{ + instance = 0; +} + +void +HelpPluginActivator::start(ctkPluginContext* context) +{ + BERRY_REGISTER_EXTENSION_CLASS(berry::HelpContentView, context) + BERRY_REGISTER_EXTENSION_CLASS(berry::HelpIndexView, context) + BERRY_REGISTER_EXTENSION_CLASS(berry::HelpSearchView, context) + BERRY_REGISTER_EXTENSION_CLASS(berry::HelpEditor, context) + BERRY_REGISTER_EXTENSION_CLASS(berry::HelpPerspective, context) + + QFileInfo qhcInfo = context->getDataFile("qthelpcollection.qhc"); + helpEngine.reset(new QHelpEngineWrapper(qhcInfo.absoluteFilePath())); + if (!helpEngine->setupData()) + { + BERRY_ERROR << "QHelpEngine set-up failed: " << helpEngine->error().toStdString(); + return; + } + + helpEngineConfiguration.reset(new QHelpEngineConfiguration(context, *helpEngine.data())); + + delete pluginListener; + pluginListener = new QCHPluginListener(context, helpEngine.data()); + context->connectPluginListener(pluginListener, SLOT(pluginChanged(ctkPluginEvent))); + + // register all QCH files from all the currently installed plugins + pluginListener->processPlugins(); + + helpEngine->initialDocSetupDone(); + + // Register a wnd listener which registers a perspective listener for each + // new window. The perspective listener opens the help home page in the window + // if no other help page is opened yet. + wndListener = IWindowListener::Pointer(new HelpWindowListener()); + PlatformUI::GetWorkbench()->AddWindowListener(wndListener); + + // Register an event handler for CONTEXTHELP_REQUESTED events + helpContextHandler.reset(new HelpContextHandler); + ctkDictionary helpHandlerProps; + helpHandlerProps.insert(ctkEventConstants::EVENT_TOPIC, "org/blueberry/ui/help/CONTEXTHELP_REQUESTED"); + context->registerService(helpContextHandler.data(), helpHandlerProps); +} + +void +HelpPluginActivator::stop(ctkPluginContext* /*context*/) +{ + delete pluginListener; + pluginListener = 0; + + if (PlatformUI::IsWorkbenchRunning()) + { + PlatformUI::GetWorkbench()->RemoveWindowListener(wndListener); + } + wndListener = 0; +} + +HelpPluginActivator *HelpPluginActivator::getInstance() +{ + return instance; +} + +QHelpEngineWrapper& HelpPluginActivator::getQHelpEngine() +{ + return *helpEngine; +} + +void HelpPluginActivator::linkActivated(IWorkbenchPage::Pointer page, const QUrl &link) +{ + IEditorInput::Pointer input(new HelpEditorInput(link)); + + // see if an editor with the same input is already open + IEditorPart::Pointer reuseEditor = page->FindEditor(input); + if (reuseEditor) + { + // just activate it + page->Activate(reuseEditor); + } + else + { + // reuse the currently active editor, if it is a HelpEditor + reuseEditor = page->GetActiveEditor(); + if (reuseEditor.IsNotNull() && page->GetReference(reuseEditor)->GetId() == HelpEditor::EDITOR_ID) + { + page->ReuseEditor(reuseEditor.Cast(), input); + page->Activate(reuseEditor); + } + else + { + // get the last used HelpEditor instance + std::vector editors = + page->FindEditors(IEditorInput::Pointer(0), HelpEditor::EDITOR_ID, IWorkbenchPage::MATCH_ID); + if (editors.empty()) + { + // no HelpEditor is currently open, create a new one + page->OpenEditor(input, HelpEditor::EDITOR_ID); + } + else + { + // reuse an existing editor + reuseEditor = editors.front()->GetEditor(false); + page->ReuseEditor(reuseEditor.Cast(), input); + page->Activate(reuseEditor); + } + } + } +} + +QCHPluginListener::QCHPluginListener(ctkPluginContext* context, QHelpEngine* helpEngine) + : delayRegistration(true), context(context), helpEngine(helpEngine) +{} + +void QCHPluginListener::processPlugins() +{ + QMutexLocker lock(&mutex); + processPlugins_unlocked(); +} + +void QCHPluginListener::pluginChanged(const ctkPluginEvent& event) +{ + QMutexLocker lock(&mutex); + if (delayRegistration) + { + this->processPlugins_unlocked(); + return; + } + + /* Only should listen for RESOLVED and UNRESOLVED events. + * + * When a plugin is updated the Framework will publish an UNRESOLVED and + * then a RESOLVED event which should cause the plugin to be removed + * and then added back into the registry. + * + * When a plugin is uninstalled the Framework should publish an UNRESOLVED + * event and then an UNINSTALLED event so the plugin will have been removed + * by the UNRESOLVED event before the UNINSTALLED event is published. + */ + QSharedPointer plugin = event.getPlugin(); + switch (event.getType()) + { + case ctkPluginEvent::RESOLVED : + addPlugin(plugin); + break; + case ctkPluginEvent::UNRESOLVED : + removePlugin(plugin); + break; + } +} + +void QCHPluginListener::processPlugins_unlocked() +{ + if (!delayRegistration) return; + + foreach (QSharedPointer plugin, context->getPlugins()) + { + if (isPluginResolved(plugin)) + addPlugin(plugin); + else + removePlugin(plugin); + } + + delayRegistration = false; +} + +bool QCHPluginListener::isPluginResolved(QSharedPointer plugin) +{ + return (plugin->getState() & (ctkPlugin::RESOLVED | ctkPlugin::ACTIVE | ctkPlugin::STARTING | ctkPlugin::STOPPING)) != 0; +} + +void QCHPluginListener::removePlugin(QSharedPointer plugin) +{ + // bail out if system plugin + if (plugin->getPluginId() == 0) return; + + QFileInfo qchDirInfo = context->getDataFile("qch_files/" + QString::number(plugin->getPluginId())); + if (qchDirInfo.exists()) + { + QDir qchDir(qchDirInfo.absoluteFilePath()); + QStringList qchEntries = qchDir.entryList(QStringList("*.qch")); + QStringList qchFiles; + foreach(QString qchEntry, qchEntries) + { + qchFiles << qchDir.absoluteFilePath(qchEntry); + } + // unregister the cached qch files + foreach(QString qchFile, qchFiles) + { + QString namespaceName = QHelpEngineCore::namespaceName(qchFile); + if (namespaceName.isEmpty()) + { + BERRY_ERROR << "Could not get the namespace for qch file " << qchFile.toStdString(); + continue; + } + else + { + if (!helpEngine->unregisterDocumentation(namespaceName)) + { + BERRY_ERROR << "Unregistering qch namespace " << namespaceName.toStdString() << " failed: " << helpEngine->error().toStdString(); + } + } + } + // clean the directory + foreach(QString qchEntry, qchEntries) + { + qchDir.remove(qchEntry); + } + } +} + +void QCHPluginListener::addPlugin(QSharedPointer plugin) +{ + // bail out if system plugin + if (plugin->getPluginId() == 0) return; + + QFileInfo qchDirInfo = context->getDataFile("qch_files/" + QString::number(plugin->getPluginId())); + QUrl location(plugin->getLocation()); + QFileInfo pluginFileInfo(location.toLocalFile()); + + if (!qchDirInfo.exists() || qchDirInfo.lastModified() < pluginFileInfo.lastModified()) + { + removePlugin(plugin); + + if (!qchDirInfo.exists()) + { + QDir().mkpath(qchDirInfo.absoluteFilePath()); + } + + QStringList localQCHFiles; + QStringList resourceList = plugin->findResources("/", "*.qch", true); + foreach(QString resource, resourceList) + { + QByteArray content = plugin->getResource(resource); + QFile localFile(qchDirInfo.absoluteFilePath() + "/" + resource.section('/', -1)); + localFile.open(QIODevice::WriteOnly); + localFile.write(content); + localFile.close(); + if (localFile.error() != QFile::NoError) + { + BERRY_WARN << "Error writing " << localFile.fileName().toStdString() + << ": " << localFile.errorString().toStdString(); + } + else + { + localQCHFiles << localFile.fileName(); + } + } + + foreach(QString qchFile, localQCHFiles) + { + if (!helpEngine->registerDocumentation(qchFile)) + { + BERRY_ERROR << "Registering qch file " << qchFile.toStdString() << " failed: " << helpEngine->error().toStdString(); + } + } + } + +} + +IPerspectiveListener::Events::Types HelpPerspectiveListener::GetPerspectiveEventTypes() const +{ + return Events::OPENED | Events::CHANGED; +} + +void HelpPerspectiveListener::PerspectiveOpened(SmartPointer page, IPerspectiveDescriptor::Pointer perspective) +{ + // if no help editor is opened, open one showing the home page + if (perspective->GetId() == HelpPerspective::ID && + page->FindEditors(IEditorInput::Pointer(0), HelpEditor::EDITOR_ID, IWorkbenchPage::MATCH_ID).empty()) + { + IEditorInput::Pointer input(new HelpEditorInput()); + page->OpenEditor(input, HelpEditor::EDITOR_ID); + } +} + +void HelpPerspectiveListener::PerspectiveChanged(SmartPointer page, IPerspectiveDescriptor::Pointer perspective, const std::string &changeId) +{ + if (perspective->GetId() == HelpPerspective::ID && changeId == IWorkbenchPage::CHANGE_RESET) + { + PerspectiveOpened(page, perspective); + } +} + +HelpWindowListener::HelpWindowListener() + : perspListener(new HelpPerspectiveListener()) +{ + // Register perspective listener for already opened windows + typedef std::vector WndVec; + WndVec windows = PlatformUI::GetWorkbench()->GetWorkbenchWindows(); + for (WndVec::iterator i = windows.begin(); i != windows.end(); ++i) + { + (*i)->AddPerspectiveListener(perspListener); + } +} + +HelpWindowListener::~HelpWindowListener() +{ + typedef std::vector WndVec; + WndVec windows = PlatformUI::GetWorkbench()->GetWorkbenchWindows(); + for (WndVec::iterator i = windows.begin(); i != windows.end(); ++i) + { + (*i)->RemovePerspectiveListener(perspListener); + } +} + +void HelpWindowListener::WindowClosed(IWorkbenchWindow::Pointer window) +{ + window->RemovePerspectiveListener(perspListener); +} + +void HelpWindowListener::WindowOpened(IWorkbenchWindow::Pointer window) +{ + window->AddPerspectiveListener(perspListener); +} + +void HelpContextHandler::handleEvent(const ctkEvent &event) +{ + struct _runner : public Poco::Runnable + { + _runner(const ctkEvent& ev) : ev(ev) {} + + void run() + { + QUrl helpUrl; + if (ev.containsProperty("url")) + { + helpUrl = QUrl(ev.getProperty("url").toString()); + } + else + { + helpUrl = contextUrl(); + } + + HelpPluginActivator::linkActivated(PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetActivePage(), + helpUrl); + delete this; + } + + QUrl contextUrl() const + { + berry::IWorkbench* currentWorkbench = berry::PlatformUI::GetWorkbench(); + if (currentWorkbench) + { + berry::IWorkbenchWindow::Pointer currentWorkbenchWindow = currentWorkbench->GetActiveWorkbenchWindow(); + if (currentWorkbenchWindow) + { + berry::IWorkbenchPage::Pointer currentPage = currentWorkbenchWindow->GetActivePage(); + if (currentPage) + { + berry::IWorkbenchPart::Pointer currentPart = currentPage->GetActivePart(); + if (currentPart) + { + QString pluginID = QString::fromStdString(currentPart->GetSite()->GetPluginId()); + QString viewID = QString::fromStdString(currentPart->GetSite()->GetId()); + QString loc = "qthelp://" + pluginID + "/bundle/%1"; + + QHelpEngineWrapper& helpEngine = HelpPluginActivator::getInstance()->getQHelpEngine(); + QUrl contextUrl(loc.arg(viewID.replace(".", "_"))); + QUrl url = helpEngine.findFile(contextUrl); + if (url.isValid()) return url; + else + { + BERRY_INFO << "Context help url invalid: " << contextUrl.toString().toStdString(); + } + url = helpEngine.findFile(QUrl(loc.arg("index.html"))); + return url; + } + } + } + } + return QUrl(); + } + + ctkEvent ev; + }; + // sync with GUI thread + Display::GetDefault()->AsyncExec(new _runner(event)); +} + +} + +Q_EXPORT_PLUGIN2(org_blueberry_ui_qt_help, berry::HelpPluginActivator) diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpPluginActivator.h b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpPluginActivator.h new file mode 100644 index 0000000000..9e8a7a8627 --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpPluginActivator.h @@ -0,0 +1,122 @@ +/*========================================================================= + +Program: BlueBerry Platform +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef BERRYLOGPLUGIN_H_ +#define BERRYLOGPLUGIN_H_ + +#include + +#include +#include + +#include +#include + +#include +#include + +class QHelpEngine; + +namespace berry { + +class QHelpEngineConfiguration; +class QHelpEngineWrapper; +class QCHPluginListener; + +class HelpContextHandler : public QObject, public ctkEventHandler +{ + Q_OBJECT + Q_INTERFACES(ctkEventHandler) + +public: + + void handleEvent(const ctkEvent& event); +}; + +class HelpPluginActivator : public QObject, public ctkPluginActivator +{ + Q_OBJECT + Q_INTERFACES(ctkPluginActivator) + +public: + + HelpPluginActivator(); + ~HelpPluginActivator(); + + void start(ctkPluginContext* context); + void stop(ctkPluginContext* context); + + static HelpPluginActivator* getInstance(); + + static void linkActivated(IWorkbenchPage::Pointer page, const QUrl &link); + + QHelpEngineWrapper& getQHelpEngine(); + +public Q_SLOTS: + + void contextHelpRequested(const ctkEvent& event); + +private: + + Q_DISABLE_COPY(HelpPluginActivator) + + static HelpPluginActivator* instance; + + QScopedPointer helpEngine; + QScopedPointer helpEngineConfiguration; + QScopedPointer helpContextHandler; + + QCHPluginListener* pluginListener; + IWindowListener::Pointer wndListener; +}; + +/** + * A listener for CTK plugin events. When plugins come and go we look to see + * if there are any qch files and update the QHelpEngine accordingly. + */ +class QCHPluginListener : public QObject { + + Q_OBJECT + +public: + + QCHPluginListener(ctkPluginContext* context, QHelpEngine* helpEngine); + + void processPlugins(); + +public Q_SLOTS: + + void pluginChanged(const ctkPluginEvent& event); + +private: + + void processPlugins_unlocked(); + + bool isPluginResolved(QSharedPointer plugin); + + void removePlugin(QSharedPointer plugin); + void addPlugin(QSharedPointer plugin); + + QMutex mutex; + bool delayRegistration; + ctkPluginContext* context; + QHelpEngine* helpEngine; +}; + +} + +#endif /*BERRYLOGPLUGIN_H_*/ diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpSearchView.cpp b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpSearchView.cpp new file mode 100644 index 0000000000..38522bb97b --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpSearchView.cpp @@ -0,0 +1,243 @@ +/*========================================================================= + +Program: BlueBerry Platform +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifdef __MINGW32__ +// We need to inlclude winbase.h here in order to declare +// atomic intrinsics like InterlockedIncrement correctly. +// Otherwhise, they would be declared wrong within qatomic_windows.h . +#include +#endif + +#include "berryHelpSearchView.h" + +#include "berryHelpPluginActivator.h" +#include "berryQHelpEngineWrapper.h" +#include "berryHelpEditorInput.h" +#include "berryHelpEditor.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace berry { + +HelpSearchView::HelpSearchView() + : m_ZoomCount(0) + , m_Parent(0) + , m_SearchEngine(HelpPluginActivator::getInstance()->getQHelpEngine().searchEngine()) + , m_ResultWidget(0) + , m_QueryWidget(0) +{ +} + +HelpSearchView::~HelpSearchView() +{ + // prevent deletion of the widget + m_ResultWidget->setParent(0); +} + +void HelpSearchView::CreateQtPartControl(QWidget* parent) +{ + if (m_ResultWidget == 0) + { + m_Parent = parent; + + QVBoxLayout* vLayout = new QVBoxLayout(parent); + + // This will be lead to strange behavior when using multiple instances of this view + // because the QHelpSearchResultWidget instance is shared. The new view will + // reparent the widget. + m_ResultWidget = m_SearchEngine->resultWidget(); + m_QueryWidget = new QHelpSearchQueryWidget(); + + vLayout->addWidget(m_QueryWidget); + vLayout->addWidget(m_ResultWidget); + + connect(m_QueryWidget, SIGNAL(search()), this, SLOT(search())); + connect(m_ResultWidget, SIGNAL(requestShowLink(QUrl)), this, + SLOT(requestShowLink(QUrl))); + + connect(m_SearchEngine, SIGNAL(searchingStarted()), this, + SLOT(searchingStarted())); + connect(m_SearchEngine, SIGNAL(searchingFinished(int)), this, + SLOT(searchingFinished(int))); + + QTextBrowser* browser = qFindChild(m_ResultWidget); + if (browser) // Will be null if QtHelp was configured not to use CLucene. + { + browser->viewport()->installEventFilter(this); + browser->setContextMenuPolicy(Qt::CustomContextMenu); + connect(browser, SIGNAL(customContextMenuRequested(QPoint)), + this, SLOT(showContextMenu(QPoint))); + } + } +} + +void HelpSearchView::SetFocus() +{ + if (!(m_ResultWidget->hasFocus())) + { + m_QueryWidget->setFocus(); + } +} + +void HelpSearchView::zoomIn() +{ + QTextBrowser* browser = qFindChild(m_ResultWidget); + if (browser && m_ZoomCount != 10) + { + m_ZoomCount++; + browser->zoomIn(); + } +} + +void HelpSearchView::zoomOut() +{ + QTextBrowser* browser = qFindChild(m_ResultWidget); + if (browser && m_ZoomCount != -5) + { + m_ZoomCount--; + browser->zoomOut(); + } +} + +void HelpSearchView::resetZoom() +{ + if (m_ZoomCount == 0) + return; + + QTextBrowser* browser = qFindChild(m_ResultWidget); + if (browser) + { + browser->zoomOut(m_ZoomCount); + m_ZoomCount = 0; + } +} + +void HelpSearchView::search() const +{ + QList query = m_SearchEngine->queryWidget()->query(); + m_SearchEngine->search(query); +} + +void HelpSearchView::searchingStarted() +{ + m_Parent->setCursor(QCursor(Qt::WaitCursor)); +} + +void HelpSearchView::searchingFinished(int hits) +{ + Q_UNUSED(hits) + m_Parent->unsetCursor(); + //qApp->restoreOverrideCursor(); +} + +void HelpSearchView::requestShowLink(const QUrl &link) +{ + HelpPluginActivator::linkActivated(this->GetSite()->GetPage(), link); +} + +bool HelpSearchView::eventFilter(QObject* o, QEvent *e) +{ + QTextBrowser* browser = qFindChild(m_ResultWidget); + if (browser && o == browser->viewport() + && e->type() == QEvent::MouseButtonRelease) + { + QMouseEvent* me = static_cast(e); + QUrl link = m_ResultWidget->linkAt(me->pos()); + if (!link.isEmpty() || link.isValid()) + { + bool controlPressed = me->modifiers() & Qt::ControlModifier; + if((me->button() == Qt::LeftButton && controlPressed) + || (me->button() == Qt::MidButton)) + { + IEditorInput::Pointer input(new HelpEditorInput(link)); + this->GetSite()->GetPage()->OpenEditor(input, HelpEditor::EDITOR_ID); + } + } + } + return QObject::eventFilter(o,e); +} + +void HelpSearchView::showContextMenu(const QPoint& point) +{ + QMenu menu; + + QTextBrowser* browser = qFindChild(m_ResultWidget); + if (!browser) + return; + +// QPoint point = browser->mapFromGlobal(pos); +// if (!browser->rect().contains(point, true)) +// return; + + QUrl link = browser->anchorAt(point); + + QKeySequence keySeq(QKeySequence::Copy); + QAction *copyAction = menu.addAction(tr("&Copy") + QLatin1String("\t") + + keySeq.toString(QKeySequence::NativeText)); + copyAction->setEnabled(QTextCursor(browser->textCursor()).hasSelection()); + + QAction *copyAnchorAction = menu.addAction(tr("Copy &Link Location")); + copyAnchorAction->setEnabled(!link.isEmpty() && link.isValid()); + + keySeq = QKeySequence(Qt::CTRL); + QAction *newTabAction = menu.addAction(tr("Open Link in New Tab") + + QLatin1String("\t") + keySeq.toString(QKeySequence::NativeText) + + QLatin1String("LMB")); + newTabAction->setEnabled(!link.isEmpty() && link.isValid()); + + menu.addSeparator(); + + keySeq = QKeySequence::SelectAll; + QAction *selectAllAction = menu.addAction(tr("Select All") + + QLatin1String("\t") + keySeq.toString(QKeySequence::NativeText)); + + QAction *usedAction = menu.exec(browser->mapToGlobal(point)); + if (usedAction == copyAction) + { + QTextCursor cursor = browser->textCursor(); + if (!cursor.isNull() && cursor.hasSelection()) + { + QString selectedText = cursor.selectedText(); + QMimeData *data = new QMimeData(); + data->setText(selectedText); + QApplication::clipboard()->setMimeData(data); + } + } + else if (usedAction == copyAnchorAction) + { + QApplication::clipboard()->setText(link.toString()); + } + else if (usedAction == newTabAction) + { + IEditorInput::Pointer input(new HelpEditorInput(link)); + this->GetSite()->GetPage()->OpenEditor(input, HelpEditor::EDITOR_ID); + } + else if (usedAction == selectAllAction) + { + browser->selectAll(); + } +} + +} diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpSearchView.h b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpSearchView.h new file mode 100644 index 0000000000..82e7915fdd --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpSearchView.h @@ -0,0 +1,76 @@ +/*========================================================================= + +Program: BlueBerry Platform +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef BERRYHELPSEARCHVIEW_H_ +#define BERRYHELPSEARCHVIEW_H_ + +#include + +class QHelpSearchEngine; +class QHelpSearchResultWidget; +class QHelpSearchQueryWidget; + +namespace berry { + +class HelpSearchView : public QtViewPart +{ + Q_OBJECT + +public: + + HelpSearchView(); + ~HelpSearchView(); + + void SetFocus(); + +protected: + + void CreateQtPartControl(QWidget* parent); + +private Q_SLOTS: + + void zoomIn(); + void zoomOut(); + void resetZoom(); + + void search() const; + void searchingStarted(); + void searchingFinished(int hits); + + void showContextMenu(const QPoint& pos); + void requestShowLink(const QUrl& link); + +private: + + bool eventFilter(QObject* o, QEvent *e); + void keyPressEvent(QKeyEvent *keyEvent); + +private: + + Q_DISABLE_COPY(HelpSearchView) + + int m_ZoomCount; + QWidget* m_Parent; + QHelpSearchEngine* m_SearchEngine; + QHelpSearchResultWidget* m_ResultWidget; + QHelpSearchQueryWidget* m_QueryWidget; + +}; + +} // namespace berry + +#endif /*BERRYHELPSEARCHVIEW_H_*/ diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpTopicChooser.cpp b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpTopicChooser.cpp new file mode 100644 index 0000000000..802747ec6e --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpTopicChooser.cpp @@ -0,0 +1,61 @@ +/*========================================================================= + +Program: BlueBerry Platform +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "berryHelpTopicChooser.h" + +namespace berry { + +HelpTopicChooser::HelpTopicChooser(QWidget *parent, const QString &keyword, + const QMap &links) + : QDialog(parent) +{ + ui.setupUi(this); + ui.label->setText(tr("Choose a topic for %1:").arg(keyword)); + + QMap::const_iterator it = links.constBegin(); + for (; it != links.constEnd(); ++it) + { + ui.listWidget->addItem(it.key()); + m_links.append(it.value()); + } + + if (ui.listWidget->count() != 0) + ui.listWidget->setCurrentRow(0); + ui.listWidget->setFocus(); + + connect(ui.buttonDisplay, SIGNAL(clicked()), this, SLOT(accept())); + connect(ui.buttonCancel, SIGNAL(clicked()), this, SLOT(reject())); + connect(ui.listWidget, SIGNAL(itemActivated(QListWidgetItem*)), this, + SLOT(accept())); +} + +QUrl HelpTopicChooser::link() const +{ + QListWidgetItem *item = ui.listWidget->currentItem(); + if (!item) + return QUrl(); + + QString title = item->text(); + if (title.isEmpty()) + return QUrl(); + + const int row = ui.listWidget->row(item); + Q_ASSERT(row < m_links.count()); + return m_links.at(row); +} + +} diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpTopicChooser.h b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpTopicChooser.h new file mode 100644 index 0000000000..1766d53e0a --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpTopicChooser.h @@ -0,0 +1,49 @@ +/*========================================================================= + +Program: BlueBerry Platform +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef BERRYHELPTOPICCHOOSER_H +#define BERRYHELPTOPICCHOOSER_H + +#include + +#include +#include +#include +#include + +#include + +namespace berry { + +class HelpTopicChooser : public QDialog +{ + Q_OBJECT + +public: + HelpTopicChooser(QWidget *parent, const QString &keyword, + const QMap &links); + + QUrl link() const; + +private: + Ui::HelpTopicChooser ui; + QList m_links; +}; + +} + +#endif // BERRYHELPTOPICCHOOSER_H diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpTopicChooser.ui b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpTopicChooser.ui new file mode 100644 index 0000000000..ab1cff97ae --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpTopicChooser.ui @@ -0,0 +1,92 @@ + + + HelpTopicChooser + + + + 0 + 0 + 391 + 223 + + + + Choose Topic + + + true + + + + 6 + + + 11 + + + + + &Topics + + + listWidget + + + + + + + + + + 6 + + + 0 + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + &Display + + + true + + + true + + + + + + + &Close + + + true + + + + + + + + + + diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpWebView.cpp b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpWebView.cpp new file mode 100644 index 0000000000..93925c4e44 --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpWebView.cpp @@ -0,0 +1,520 @@ +/*========================================================================= + +Program: BlueBerry Platform +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#include "berryHelpWebView.h" + +#include "berryHelpPluginActivator.h" +#include "berryHelpEditor.h" +#include "berryHelpEditorInput.h" +#include "berryQHelpEngineWrapper.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +namespace berry { + +struct ExtensionMap { + const char *extension; + const char *mimeType; +} extensionMap[] = { + { ".bmp", "image/bmp" }, + { ".css", "text/css" }, + { ".gif", "image/gif" }, + { ".html", "text/html" }, + { ".htm", "text/html" }, + { ".ico", "image/x-icon" }, + { ".jpeg", "image/jpeg" }, + { ".jpg", "image/jpeg" }, + { ".js", "application/x-javascript" }, + { ".mng", "video/x-mng" }, + { ".pbm", "image/x-portable-bitmap" }, + { ".pgm", "image/x-portable-graymap" }, + { ".pdf", "application/pdf" }, + { ".png", "image/png" }, + { ".ppm", "image/x-portable-pixmap" }, + { ".rss", "application/rss+xml" }, + { ".svg", "image/svg+xml" }, + { ".svgz", "image/svg+xml" }, + { ".text", "text/plain" }, + { ".tif", "image/tiff" }, + { ".tiff", "image/tiff" }, + { ".txt", "text/plain" }, + { ".xbm", "image/x-xbitmap" }, + { ".xml", "text/xml" }, + { ".xpm", "image/x-xpm" }, + { ".xsl", "text/xsl" }, + { ".xhtml", "application/xhtml+xml" }, + { ".wml", "text/vnd.wap.wml" }, + { ".wmlc", "application/vnd.wap.wmlc" }, + { "about:blank", 0 }, + { 0, 0 } +}; + + +const QString HelpWebView::m_PageNotFoundMessage = + QCoreApplication::translate("org.blueberry.ui.qt.help", "Error 404...


The page could not be found


'%1'" + "

"); + +class HelpNetworkReply : public QNetworkReply +{ +public: + HelpNetworkReply(const QNetworkRequest &request, const QByteArray &fileData, + const QString &mimeType); + + virtual void abort(); + + virtual qint64 bytesAvailable() const + { return data.length() + QNetworkReply::bytesAvailable(); } + +protected: + virtual qint64 readData(char *data, qint64 maxlen); + +private: + QByteArray data; + qint64 origLen; +}; + +HelpNetworkReply::HelpNetworkReply(const QNetworkRequest &request, + const QByteArray &fileData, const QString& mimeType) + : data(fileData), origLen(fileData.length()) +{ + setRequest(request); + setOpenMode(QIODevice::ReadOnly); + + setHeader(QNetworkRequest::ContentTypeHeader, mimeType); + setHeader(QNetworkRequest::ContentLengthHeader, QByteArray::number(origLen)); + QTimer::singleShot(0, this, SIGNAL(metaDataChanged())); + QTimer::singleShot(0, this, SIGNAL(readyRead())); +} + +void HelpNetworkReply::abort() +{ +} + +qint64 HelpNetworkReply::readData(char *buffer, qint64 maxlen) +{ + qint64 len = qMin(qint64(data.length()), maxlen); + if (len) { + memcpy(buffer, data.constData(), len); + data.remove(0, len); + } + if (!data.length()) + QTimer::singleShot(0, this, SIGNAL(finished())); + return len; +} + +class HelpNetworkAccessManager : public QNetworkAccessManager +{ +public: + HelpNetworkAccessManager(QObject *parent); + +protected: + virtual QNetworkReply *createRequest(Operation op, + const QNetworkRequest &request, + QIODevice *outgoingData = 0); +}; + +HelpNetworkAccessManager::HelpNetworkAccessManager(QObject *parent) + : QNetworkAccessManager(parent) +{ +} + +QNetworkReply *HelpNetworkAccessManager::createRequest(Operation /*op*/, + const QNetworkRequest &request, + QIODevice* /*outgoingData*/) +{ + QString url = request.url().toString(); + QHelpEngine& helpEngine = HelpPluginActivator::getInstance()->getQHelpEngine(); + + // TODO: For some reason the url to load is already wrong (passed from webkit) + // though the css file and the references inside should work that way. One + // possible problem might be that the css is loaded at the same level as the + // html, thus a path inside the css like (../images/foo.png) might cd out of + // the virtual folder + // if (!helpEngine.findFile(url).isValid()) { + // if (url.startsWith(AbstractHelpWebView::DocPath)) { + // QUrl newUrl = request.url(); + // if (!newUrl.path().startsWith(QLatin1String("/qdoc/"))) { + // newUrl.setPath(QLatin1String("qdoc") + newUrl.path()); + // url = newUrl.toString(); + // } + // } + // } + + const QString &mimeType = HelpWebView::mimeFromUrl(url); + const QByteArray &data = helpEngine.findFile(url).isValid() + ? helpEngine.fileData(url) + : HelpWebView::m_PageNotFoundMessage.arg(url).toUtf8(); + return new HelpNetworkReply(request, data, mimeType.isEmpty() + ? QLatin1String("application/octet-stream") : mimeType); +} + +class HelpPage : public QWebPage +{ + +public: + + HelpPage(IEditorSite::Pointer editorSite, QObject *parent); + +protected: + + virtual QWebPage *createWindow(QWebPage::WebWindowType); + virtual void triggerAction(WebAction action, bool checked = false); + + virtual bool acceptNavigationRequest(QWebFrame *frame, + const QNetworkRequest &request, + NavigationType type); + +private: + + IEditorSite::Pointer m_EditorSite; + bool m_CloseNewTabIfNeeded; + + friend class HelpWebView; + QUrl m_loadingUrl; + Qt::MouseButtons m_pressedButtons; + Qt::KeyboardModifiers m_keyboardModifiers; + +}; + +HelpPage::HelpPage(IEditorSite::Pointer editorSite, QObject *parent) + : QWebPage(parent) + , m_EditorSite(editorSite) + , m_CloseNewTabIfNeeded(false) + , m_pressedButtons(Qt::NoButton) + , m_keyboardModifiers(Qt::NoModifier) +{ + +} + +QWebPage *HelpPage::createWindow(QWebPage::WebWindowType type) +{ + IEditorInput::Pointer input(new HelpEditorInput(QUrl())); + IEditorPart::Pointer editorPart = m_EditorSite->GetPage()->OpenEditor(input, HelpEditor::EDITOR_ID); + HelpEditor::Pointer helpEditor = editorPart.Cast(); + HelpPage* newPage = static_cast(helpEditor->GetQWebPage()); + if (newPage) + newPage->m_CloseNewTabIfNeeded = m_CloseNewTabIfNeeded; + m_CloseNewTabIfNeeded = false; + return newPage; +} + +void HelpPage::triggerAction(WebAction action, bool checked) +{ + switch (action) + { + case OpenLinkInNewWindow: + m_CloseNewTabIfNeeded = true; + default: // fall through + QWebPage::triggerAction(action, checked); + break; + } +} + +bool HelpPage::acceptNavigationRequest(QWebFrame *, + const QNetworkRequest &request, + QWebPage::NavigationType type) +{ + const bool closeNewTab = m_CloseNewTabIfNeeded; + m_CloseNewTabIfNeeded = false; + +// const QUrl &url = request.url(); +// if (AbstractHelpWebView::launchWithExternalApp(url)) +// { +// if (closeNewTab) +// QMetaObject::invokeMethod(centralWidget, "closeTab"); +// return false; +// } + +// if (type == QWebPage::NavigationTypeLinkClicked +// && (m_keyboardModifiers & Qt::ControlModifier +// || m_pressedButtons == Qt::MidButton)) +// { +// if (centralWidget->newEmptyTab()) +// centralWidget->setSource(url); +// m_pressedButtons = Qt::NoButton; +// m_keyboardModifiers = Qt::NoModifier; +// return false; +// } + +// m_loadingUrl = url; // because of async page loading, we will hit some kind + // of race condition while using a remote command, like a combination of + // SetSource; SyncContent. SetSource would be called and SyncContents shortly + // afterwards, but the page might not have finished loading and the old url + // would be returned. + return true; +} + +// -- HelpWebView + +HelpWebView::HelpWebView(IEditorSite::Pointer editorSite, QWidget *parent, qreal zoom) + : QWebView(parent) + //, parentWidget(parent) + , m_LoadFinished(false) + , m_HelpEngine(HelpPluginActivator::getInstance()->getQHelpEngine()) +{ + setAcceptDrops(false); + + setPage(new HelpPage(editorSite, parent)); + + page()->setNetworkAccessManager(new HelpNetworkAccessManager(this)); + + QAction* action = pageAction(QWebPage::OpenLinkInNewWindow); + action->setText(tr("Open Link in New Tab")); + if (!parent) + action->setVisible(false); + + pageAction(QWebPage::DownloadLinkToDisk)->setVisible(false); + pageAction(QWebPage::DownloadImageToDisk)->setVisible(false); + pageAction(QWebPage::OpenImageInNewWindow)->setVisible(false); + + connect(pageAction(QWebPage::Copy), SIGNAL(changed()), this, + SLOT(actionChanged())); + connect(pageAction(QWebPage::Back), SIGNAL(changed()), this, + SLOT(actionChanged())); + connect(pageAction(QWebPage::Forward), SIGNAL(changed()), this, + SLOT(actionChanged())); + connect(page(), SIGNAL(linkHovered(QString,QString,QString)), this, + SIGNAL(highlighted(QString))); + connect(this, SIGNAL(urlChanged(QUrl)), this, SIGNAL(sourceChanged(QUrl))); + connect(this, SIGNAL(loadStarted()), this, SLOT(setLoadStarted())); + connect(this, SIGNAL(loadFinished(bool)), this, SLOT(setLoadFinished(bool))); + connect(page(), SIGNAL(printRequested(QWebFrame*)), this, SIGNAL(printRequested())); + + setFont(viewerFont()); + setTextSizeMultiplier(zoom == 0.0 ? 1.0 : zoom); +} + +HelpWebView::~HelpWebView() +{ +} + +QFont HelpWebView::viewerFont() const +{ + //if (m_HelpEngine.usesBrowserFont()) + // return m_HelpEngine.browserFont(); + + QWebSettings *webSettings = QWebSettings::globalSettings(); + return QFont(webSettings->fontFamily(QWebSettings::StandardFont), + webSettings->fontSize(QWebSettings::DefaultFontSize)); +} + +void HelpWebView::setViewerFont(const QFont &font) +{ + QWebSettings *webSettings = settings(); + webSettings->setFontFamily(QWebSettings::StandardFont, font.family()); + webSettings->setFontSize(QWebSettings::DefaultFontSize, font.pointSize()); +} + +void HelpWebView::scaleUp() +{ + setTextSizeMultiplier(textSizeMultiplier() + 0.1); +} + +void HelpWebView::scaleDown() +{ + setTextSizeMultiplier(qMax(0.0, textSizeMultiplier() - 0.1)); +} + +void HelpWebView::resetScale() +{ + setTextSizeMultiplier(1.0); +} + +bool HelpWebView::handleForwardBackwardMouseButtons(QMouseEvent *e) +{ + if (e->button() == Qt::XButton1) + { + triggerPageAction(QWebPage::Back); + return true; + } + + if (e->button() == Qt::XButton2) + { + triggerPageAction(QWebPage::Forward); + return true; + } + + return false; +} + +QUrl HelpWebView::source() const +{ + HelpPage *currentPage = static_cast (page()); + if (currentPage && !hasLoadFinished()) + { + // see HelpPage::acceptNavigationRequest(...) + return currentPage->m_loadingUrl; + } + return url(); +} + +void HelpWebView::setSource(const QUrl &url) +{ + if (m_HelpEngine.findFile(url).isValid()) + load(url); + else + setHtml(m_PageNotFoundMessage.arg(url.toString())); +} + +void HelpWebView::wheelEvent(QWheelEvent *e) +{ + if (e->modifiers()& Qt::ControlModifier) + { + e->accept(); + e->delta() > 0 ? scaleUp() : scaleDown(); + } + else + { + QWebView::wheelEvent(e); + } +} + +void HelpWebView::mouseReleaseEvent(QMouseEvent *e) +{ +#ifndef Q_OS_LINUX + if (handleForwardBackwardMouseButtons(e)) + return; +#endif + + QWebView::mouseReleaseEvent(e); +} + +void HelpWebView::actionChanged() +{ + QAction *a = qobject_cast(sender()); + if (a == pageAction(QWebPage::Copy)) + emit copyAvailable(a->isEnabled()); + else if (a == pageAction(QWebPage::Back)) + emit backwardAvailable(a->isEnabled()); + else if (a == pageAction(QWebPage::Forward)) + emit forwardAvailable(a->isEnabled()); +} + +void HelpWebView::mousePressEvent(QMouseEvent *event) +{ +#ifdef Q_OS_LINUX + if (handleForwardBackwardMouseButtons(event)) + return; +#endif + + HelpPage *currentPage = static_cast(page()); + if (currentPage) + { + currentPage->m_pressedButtons = event->buttons(); + currentPage->m_keyboardModifiers = event->modifiers(); + } + QWebView::mousePressEvent(event); +} + +void HelpWebView::setLoadStarted() +{ + m_LoadFinished = false; +} + +void HelpWebView::setLoadFinished(bool ok) +{ + m_LoadFinished = ok; + emit sourceChanged(url()); +} + +QString HelpWebView::mimeFromUrl(const QUrl &url) +{ + const QString &path = url.path(); + const int index = path.lastIndexOf(QLatin1Char('.')); + const QByteArray &ext = path.mid(index).toUtf8().toLower(); + + const ExtensionMap *e = extensionMap; + while (e->extension) + { + if (ext == e->extension) + return QLatin1String(e->mimeType); + ++e; + } + return QLatin1String(""); +} + +bool HelpWebView::canOpenPage(const QString &url) +{ + return !mimeFromUrl(url).isEmpty(); +} + +bool HelpWebView::isLocalUrl(const QUrl &url) +{ + const QString &scheme = url.scheme(); + return scheme.isEmpty() + || scheme == QLatin1String("file") + || scheme == QLatin1String("qrc") + || scheme == QLatin1String("data") + || scheme == QLatin1String("qthelp") + || scheme == QLatin1String("about"); +} + +bool HelpWebView::launchWithExternalApp(const QUrl &url) +{ + if (isLocalUrl(url)) + { + const QHelpEngine& helpEngine = HelpPluginActivator::getInstance()->getQHelpEngine(); + const QUrl &resolvedUrl = helpEngine.findFile(url); + if (!resolvedUrl.isValid()) + return false; + + const QString& path = resolvedUrl.path(); + if (!canOpenPage(path)) + { + QTemporaryFile tmpTmpFile; + if (!tmpTmpFile.open()) + return false; + + const QString &extension = QFileInfo(path).completeSuffix(); + QFile actualTmpFile(tmpTmpFile.fileName() % QLatin1String(".") + % extension); + if (!actualTmpFile.open(QIODevice::ReadWrite | QIODevice::Truncate)) + return false; + + actualTmpFile.write(helpEngine.fileData(resolvedUrl)); + actualTmpFile.close(); + return QDesktopServices::openUrl(QUrl(actualTmpFile.fileName())); + } + } + else if (url.scheme() == QLatin1String("http")) + { + return QDesktopServices::openUrl(url); + } + return false; +} + +void HelpWebView::home() +{ + setSource(m_HelpEngine.homePage()); +} + +} diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpWebView.h b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpWebView.h new file mode 100644 index 0000000000..a93a749b4c --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryHelpWebView.h @@ -0,0 +1,109 @@ +/*========================================================================= + +Program: BlueBerry Platform +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef BERRYHELPWEBVIEW_H +#define BERRYHELPWEBVIEW_H + +#include +#include + +#include + +#include + + +namespace berry { + +class QHelpEngineWrapper; + +class HelpWebView : public QWebView +{ + Q_OBJECT + +public: + explicit HelpWebView(IEditorSite::Pointer editorSite, QWidget *parent, qreal zoom = 0.0); + ~HelpWebView(); + + QFont viewerFont() const; + void setViewerFont(const QFont &font); + + qreal scale() const { return textSizeMultiplier(); } + + bool handleForwardBackwardMouseButtons(QMouseEvent *e); + + QUrl source() const; + void setSource(const QUrl &url); + + inline QString documentTitle() const + { return title(); } + + inline bool hasSelection() const + { return !selectedText().isEmpty(); } // ### this is suboptimal + + inline void copy() + { return triggerPageAction(QWebPage::Copy); } + + inline bool isForwardAvailable() const + { return pageAction(QWebPage::Forward)->isEnabled(); } + inline bool isBackwardAvailable() const + { return pageAction(QWebPage::Back)->isEnabled(); } + inline bool hasLoadFinished() const + { return m_LoadFinished; } + + static QString mimeFromUrl(const QUrl &url); + static bool canOpenPage(const QString &url); + static bool isLocalUrl(const QUrl &url); + static bool launchWithExternalApp(const QUrl &url); + static const QString m_PageNotFoundMessage; + +public Q_SLOTS: + + void backward() { back(); } + void home(); + + void scaleUp(); + void scaleDown(); + void resetScale(); + +Q_SIGNALS: + void copyAvailable(bool enabled); + void forwardAvailable(bool enabled); + void backwardAvailable(bool enabled); + void highlighted(const QString &); + void sourceChanged(const QUrl &); + void printRequested(); + +protected: + virtual void wheelEvent(QWheelEvent *); + void mouseReleaseEvent(QMouseEvent *e); + void mousePressEvent(QMouseEvent *event); + +private Q_SLOTS: + void actionChanged(); + void setLoadStarted(); + void setLoadFinished(bool ok); + +private: + + bool m_LoadFinished; + QHelpEngineWrapper& m_HelpEngine; +}; + +} + +#endif // BERRYHELPWEBVIEW_H diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryQHelpEngineConfiguration.cpp b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryQHelpEngineConfiguration.cpp new file mode 100644 index 0000000000..ec136dc0f9 --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryQHelpEngineConfiguration.cpp @@ -0,0 +1,66 @@ +/*========================================================================= + +Program: BlueBerry Platform +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#include "berryQHelpEngineConfiguration.h" +#include "berryQHelpEngineWrapper.h" + +#include + + +namespace berry { + +QString QHelpEngineConfiguration::PID = "org.blueberry.services.help"; + +QHelpEngineConfiguration::QHelpEngineConfiguration(ctkPluginContext* context, + QHelpEngineWrapper& helpEngine) + : helpEngine(helpEngine) +{ + QMutexLocker lock(&mutex); + registration = context->registerService(this, getDefaults()); +} + +void QHelpEngineConfiguration::updated(const ctkDictionary &properties) +{ + if (properties.isEmpty()) + { + QMutexLocker lock(&mutex); + registration.setProperties(getDefaults()); + } + else + { + QMetaObject::invokeMethod(this, "configurationChanged", Q_ARG(ctkDictionary, properties)); + + QMutexLocker lock(&mutex); + registration.setProperties(properties); + } +} + +void QHelpEngineConfiguration::configurationChanged(const ctkDictionary& properties) +{ + helpEngine.setHomePage(properties["homePage"].toString()); +} + +ctkDictionary QHelpEngineConfiguration::getDefaults() const +{ + ctkDictionary defaults; + defaults.insert("homePage", ""); + defaults.insert(ctkPluginConstants::SERVICE_PID, PID); + return defaults; +} + +} diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryQHelpEngineConfiguration.h b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryQHelpEngineConfiguration.h new file mode 100644 index 0000000000..77f0bf1666 --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryQHelpEngineConfiguration.h @@ -0,0 +1,63 @@ +/*========================================================================= + +Program: BlueBerry Platform +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef BERRYQHELPENGINECONFIGURATION_H +#define BERRYQHELPENGINECONFIGURATION_H + +#include + +#include +#include + + +namespace berry { + +class QHelpEngineWrapper; + +class QHelpEngineConfiguration : public QObject, public ctkManagedService +{ + Q_OBJECT + Q_INTERFACES(ctkManagedService) + +public: + + QHelpEngineConfiguration(ctkPluginContext* context, QHelpEngineWrapper& helpEngine); + + void updated(const ctkDictionary &properties); + +public Q_SLOTS: + + void configurationChanged(const ctkDictionary &properties); + +private: + + Q_DISABLE_COPY(QHelpEngineConfiguration) + + ctkDictionary getDefaults() const; + + static QString PID; + + QMutex mutex; + ctkServiceRegistration registration; + + QHelpEngineWrapper& helpEngine; +}; + +} + +#endif // BERRYQHELPENGINECONFIGURATION_H diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryQHelpEngineWrapper.cpp b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryQHelpEngineWrapper.cpp new file mode 100644 index 0000000000..ae5c1aea94 --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryQHelpEngineWrapper.cpp @@ -0,0 +1,65 @@ +/*========================================================================= + + Program: BlueBerry Platform + Language: C++ + Date: $Date$ + Version: $Revision$ + + Copyright (c) German Cancer Research Center, Division of Medical and + Biological Informatics. All rights reserved. + See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "berryQHelpEngineWrapper.h" + +#include + + +namespace berry { + +QHelpEngineWrapper::QHelpEngineWrapper(const QString &collectionFile) + : QHelpEngine(collectionFile) +{ + /* + * Otherwise we will waste time if several new docs are found, + * because we will start to index them, only to be interrupted + * by the next request. Also, there is a nasty SQLITE bug that will + * cause the application to hang for minutes in that case. + * This call is reverted by initalDocSetupDone(), which must be + * called after the new docs have been installed. + */ + disconnect(this, SIGNAL(setupFinished()), + searchEngine(), SLOT(indexDocumentation())); +} + +QHelpEngineWrapper::~QHelpEngineWrapper() +{ +} + +void QHelpEngineWrapper::initialDocSetupDone() +{ + connect(this, SIGNAL(setupFinished()), + searchEngine(), SLOT(indexDocumentation())); + setupData(); +} + +const QString QHelpEngineWrapper::homePage() const +{ + return m_HomePage; +} + +void QHelpEngineWrapper::setHomePage(const QString &page) +{ + if (m_HomePage != page) + { + m_HomePage = page; + emit homePageChanged(page); + } +} + +} // end namespace berry diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryQHelpEngineWrapper.h b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryQHelpEngineWrapper.h new file mode 100644 index 0000000000..436c5473ed --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/src/internal/berryQHelpEngineWrapper.h @@ -0,0 +1,57 @@ +/*========================================================================= + + Program: BlueBerry Platform + Language: C++ + Date: $Date$ + Version: $Revision$ + + Copyright (c) German Cancer Research Center, Division of Medical and + Biological Informatics. All rights reserved. + See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#ifndef BERRYQHELPENGINEWRAPPER_H +#define BERRYQHELPENGINEWRAPPER_H + +#include + + +namespace berry { + +class QHelpEngineWrapper : public QHelpEngine +{ + Q_OBJECT + Q_DISABLE_COPY(QHelpEngineWrapper) + +public: + + QHelpEngineWrapper(const QString &collectionFile); + ~QHelpEngineWrapper(); + + /* + * To be called after the initial search for qch files finished. + * This will mainly cause the search index to be updated, if necessary. + */ + void initialDocSetupDone(); + + const QString homePage() const; + void setHomePage(const QString &page); + +Q_SIGNALS: + + void homePageChanged(const QString& page); + +private: + + QString m_HomePage; + +}; + +} // end namespace berry + +#endif // BERRYQHELPENGINEWRAPPER_H diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt.help/target_libraries.cmake b/BlueBerry/Bundles/org.blueberry.ui.qt.help/target_libraries.cmake new file mode 100644 index 0000000000..9412e38dde --- /dev/null +++ b/BlueBerry/Bundles/org.blueberry.ui.qt.help/target_libraries.cmake @@ -0,0 +1,9 @@ +# See CMake/ctkFunctionGetTargetLibraries.cmake +# +# This file should list the libraries required to build the current CTK plugin. +# For specifying required plugins, see the manifest_headers.cmake file. +# + +SET(target_libraries + CTKWidgets +) diff --git a/BlueBerry/Bundles/org.blueberry.ui.qt/src/berryQtAssistantUtil.h b/BlueBerry/Bundles/org.blueberry.ui.qt/src/berryQtAssistantUtil.h index bd1f6068bb..3c0f3c5a31 100644 --- a/BlueBerry/Bundles/org.blueberry.ui.qt/src/berryQtAssistantUtil.h +++ b/BlueBerry/Bundles/org.blueberry.ui.qt/src/berryQtAssistantUtil.h @@ -1,74 +1,80 @@ /*========================================================================= Program: BlueBerry Platform Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef BERRYQTASSISTANTUTIL_H_ #define BERRYQTASSISTANTUTIL_H_ #include #include #include #include #include #include #include namespace berry { +/** + * \deprecated + * + * This class is deprecated. Please use the org.blueberry.ui.qt.help + * plug-in if you want to access help contents in your application. + */ class BERRY_UI_QT QtAssistantUtil { public: static void OpenAssistant(const QString& startPage = ""); static void CloseAssistant(); /** * @brief With this method you can open the help-page of the active bundle. */ static void OpenActivePartHelp(); // for legacy BlueBerry bundle support static bool RegisterQCHFiles(const std::vector& bundles); static bool RegisterQCHFiles(const QStringList& qchFiles); static bool UnregisterQCHFiles(const QStringList& qchFiles); static void SetHelpCollectionFile(const QString& file); static QString GetHelpCollectionFile(); static void SetDefaultHelpUrl(const QString& defaultUrl); private: static QProcess* assistantProcess; static QString helpCollectionFile; static QString defaultHelpUrl; static QSet registeredBundles; static QString GetAssistantExecutable(); static QStringList ExtractQCHFiles(const std::vector& bundles); static bool CallQtAssistant(const QStringList& qchFiles, bool registerFile = true); }; } #endif /* BERRYQTASSISTANTUTIL_H_ */ diff --git a/BlueBerry/CMakeLists.txt b/BlueBerry/CMakeLists.txt index 7bd929fd2e..335a90b3a6 100644 --- a/BlueBerry/CMakeLists.txt +++ b/BlueBerry/CMakeLists.txt @@ -1,297 +1,298 @@ PROJECT(BlueBerry) CMAKE_MINIMUM_REQUIRED(VERSION 2.8.4) SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/CMake/") INCLUDE(MacroParseArguments) INCLUDE(MacroConvertSchema) INCLUDE(MacroOrganizeSources) INCLUDE(berryPluginHelpers) INCLUDE(MacroCollectPlugins) INCLUDE(MacroParseManifest) INCLUDE(MacroCreatePlugin) INCLUDE(MacroCreateCTKPlugin) INCLUDE(MacroCreateQtHelp) INCLUDE(MacroInstallPlugin) INCLUDE(MacroInstallCTKPlugin) INCLUDE(FunctionCreateProvisioningFile) IF(MSVC) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4250 /wd4275 /wd4251 /wd4503") ENDIF() IF (NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY) SET (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) ENDIF () FIND_PACKAGE(mbilog REQUIRED) INCLUDE_DIRECTORIES(${mbilog_INCLUDE_DIRS}) OPTION(BLUEBERRY_USE_QT "Use the Qt GUI toolkit" OFF) IF(NOT DESIRED_QT_VERSION) SET(DESIRED_QT_VERSION 4 CACHE STRING "Desired Qt version" FORCE) MARK_AS_ADVANCED(DESIRED_QT_VERSION) ENDIF() IF(BLUEBERRY_USE_QT AND NOT DESIRED_QT_VERSION EQUAL 4) MESSAGE("Attention: Qt4 GUI libraries are required to build the BlueBerry Qt plug-ins.") ENDIF() IF(BLUEBERRY_USE_QT AND DESIRED_QT_VERSION EQUAL 4) SET(BUILD_QT_PLUGINS 1) FIND_PACKAGE(Qt4 4.6.2 REQUIRED) IF(QT_QMAKE_CHANGED) SET(QT_HELPGENERATOR_EXECUTABLE NOTFOUND) SET(QT_COLLECTIONGENERATOR_EXECUTABLE NOTFOUND) SET(QT_ASSISTANT_EXECUTABLE NOTFOUND) ENDIF() FIND_PROGRAM(QT_HELPGENERATOR_EXECUTABLE NAMES qhelpgenerator qhelpgenerator-qt4 qhelpgenerator4 PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH ) FIND_PROGRAM(QT_COLLECTIONGENERATOR_EXECUTABLE NAMES qcollectiongenerator qcollectiongenerator-qt4 qcollectiongenerator4 PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH ) FIND_PROGRAM(QT_ASSISTANT_EXECUTABLE NAMES assistant-qt4 assistant4 assistant PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH ) OPTION(BLUEBERRY_USE_QT_HELP "Enable support for integrating bundle documentation into Qt Help" ON) MARK_AS_ADVANCED(BLUEBERRY_USE_QT_HELP QT_HELPGENERATOR_EXECUTABLE QT_COLLECTIONGENERATOR_EXECUTABLE QT_ASSISTANT_EXECUTABLE) SET(_doxygen_too_old 1) IF(BLUEBERRY_USE_QT_HELP) FIND_PACKAGE(Doxygen) IF(DOXYGEN_FOUND) EXECUTE_PROCESS(COMMAND ${DOXYGEN_EXECUTABLE} --version OUTPUT_VARIABLE _doxygen_version) IF(${_doxygen_version} VERSION_GREATER 1.6.0 OR ${_doxygen_version} VERSION_EQUAL 1.6.0) SET(_doxygen_too_old 0) ENDIF() ENDIF() ELSE(BLUEBERRY_USE_QT_HELP) CONFIGURE_FILE(../Documentation/pregenerated/MITKBlankPage.qch ${MITK_BINARY_DIR}/bin/ExtBundles/org.mitk.gui.qt.extapplication/resources/MITKBlankPage.qch COPYONLY) CONFIGURE_FILE(../Documentation/pregenerated/MitkExtQtHelpCollection.qhc ${MITK_BINARY_DIR}/bin/ExtBundles/org.mitk.gui.qt.extapplication/resources/MitkExtQtHelpCollection.qhc COPYONLY) ENDIF(BLUEBERRY_USE_QT_HELP) IF (BLUEBERRY_USE_QT_HELP AND _doxygen_too_old) MESSAGE("Doxygen was not found or is too old. Version 1.6.0 or later is needed if BLUEBERRY_USE_QT_HELP is ON") SET(BLUEBERRY_USE_QT_HELP OFF CACHE BOOL "Enable support for integrating bundle documentation into Qt Help" FORCE) ENDIF() IF(BLUEBERRY_USE_QT_HELP AND NOT QT_HELPGENERATOR_EXECUTABLE) MESSAGE("You have enabled Qt Help support, but QT_HELPGENERATOR_EXECUTABLE is empty") SET(BLUEBERRY_USE_QT_HELP OFF CACHE BOOL "Enable support for integrating bundle documentation into Qt Help" FORCE) ENDIF() INCLUDE(${QT_USE_FILE}) ELSE() FIND_PACKAGE(Qt4 4.6.2 COMPONENTS QtCore REQUIRED) INCLUDE(${QT_USE_FILE}) ENDIF() # ========= CTK specific CMake stuff ============ CMAKE_POLICY(SET CMP0012 NEW) FIND_PACKAGE(CTK REQUIRED) # Extract all library names starting with org_blueberry_ MACRO(GetMyTargetLibraries all_target_libraries varname) SET(re_ctkplugin "^org_blueberry_[a-zA-Z0-9_]+$") SET(_tmp_list) LIST(APPEND _tmp_list ${all_target_libraries}) ctkMacroListFilter(_tmp_list re_ctkplugin OUTPUT_VARIABLE ${varname}) ENDMACRO() # ================================================ OPTION(BLUEBERRY_BUILD_ALL_PLUGINS "Build all BlueBerry plugins (overriding selection)" OFF) MARK_AS_ADVANCED(BLUEBERRY_BUILD_ALL_PLUGINS) IF(BLUEBERRY_BUILD_ALL_PLUGINS) SET(BLUEBERRY_BUILD_ALL_PLUGINS_OPTION "FORCE_BUILD_ALL") ENDIF() OPTION(BLUEBERRY_STATIC "Build all plugins as static libraries" OFF) MARK_AS_ADVANCED(BLUEBERRY_STATIC) OPTION(BLUEBERRY_DEBUG_SMARTPOINTER "Enable code for debugging smart pointers" OFF) MARK_AS_ADVANCED(BLUEBERRY_DEBUG_SMARTPOINTER) FIND_PACKAGE(Poco REQUIRED) FIND_PACKAGE(Ant) FIND_PACKAGE(Eclipse) SET(BLUEBERRY_SOURCE_DIR ${BlueBerry_SOURCE_DIR}) SET(BLUEBERRY_BINARY_DIR ${BlueBerry_BINARY_DIR}) SET(BLUEBERRY_PLUGINS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Bundles) SET(BLUEBERRY_PLUGINS_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/Bundles) SET(OSGI_APP solstice) SET(OSGI_UI_APP solstice_ui) # Force should be removed after everybody has configured their old binary tree SET(BLUEBERRY_PLUGINS_OUTPUT_DIR ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/BlueBerry CACHE PATH "Directory where to build the BlueBerry Bundles" FORCE) MARK_AS_ADVANCED(BLUEBERRY_PLUGINS_OUTPUT_DIR) # Clear the cache variables SET(BLUEBERRY_PLUGIN_SOURCE_DIRS "" CACHE INTERNAL "List of base plugin source directories" FORCE) SET(BLUEBERRY_PLUGIN_BINARY_DIRS "" CACHE INTERNAL "List of base plugin binary directories" FORCE) IF (Eclipse_DIR) SET(BLUEBERRY_DOC_TOOLS_DIR "${Eclipse_DIR}" CACHE PATH "Directory containing additional tools needed for generating the documentation") ELSE () SET(BLUEBERRY_DOC_TOOLS_DIR "" CACHE PATH "Directory containing additional tools needed for generating the documentation") ENDIF () SET(BLUEBERRY_DEBUG_POSTFIX d) # Testing options OPTION(BLUEBERRY_BUILD_TESTING "Build the BlueBerry tests." ${BUILD_TESTING}) IF(WIN32) SET(_gui_testing_default "ON") ELSE() SET(_gui_testing_default "OFF") ENDIF() OPTION(BLUEBERRY_ENABLE_GUI_TESTING "Enable the BlueBerry GUI tests" ${_gui_testing_default}) MARK_AS_ADVANCED(BLUEBERRY_ENABLE_GUI_TESTING) IF(BLUEBERRY_BUILD_TESTING) ENABLE_TESTING() ENDIF() # Add CTK plugins SET(_ctk_plugins Bundles/org.blueberry.osgi:ON Bundles/org.blueberry.compat:OFF Bundles/org.blueberry.core.runtime:OFF Bundles/org.blueberry.core.expressions:OFF Bundles/org.blueberry.solstice.common:OFF Bundles/org.blueberry.core.commands:OFF Bundles/org.blueberry.core.jobs:OFF Bundles/org.blueberry.ui:OFF Bundles/org.blueberry.ui.qt:OFF + Bundles/org.blueberry.ui.qt.help:OFF Bundles/org.blueberry.ui.qt.log:OFF Bundles/org.blueberry.ui.qt.objectinspector:OFF ) SET(_ctk_test_plugins ) SET(_ctk_plugins_include_dirs ${Poco_INCLUDE_DIRS} ) SET(_ctk_plugins_link_dirs ${Poco_LIBRARY_DIR} ) INCLUDE_DIRECTORIES(${_ctk_plugins_include_dirs}) LINK_DIRECTORIES(${_ctk_plugins_link_dirs}) IF(BLUEBERRY_BUILD_TESTING) INCLUDE(berryTestingHelpers) SET(BLUEBERRY_TEST_APP "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${OSGI_APP}") GET_TARGET_PROPERTY(_is_macosx_bundle ${OSGI_APP} MACOSX_BUNDLE) IF(APPLE AND _is_macosx_bundle) SET(BLUEBERRY_TEST_APP "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${OSGI_APP}.app/Contents/MacOS/${OSGI_APP}") ENDIF() SET(_ctk_testinfrastructure_plugins Bundles/org.blueberry.test:ON Bundles/org.blueberry.uitest:ON ) SET(_ctk_test_plugins # Testing/org.blueberry.core.runtime.tests:ON # Testing/org.blueberry.osgi.tests:ON ) IF(BLUEBERRY_ENABLE_GUI_TESTING) # LIST(APPEND _ctk_test_plugins Testing/org.blueberry.ui.tests:ON) SET(BLUEBERRY_UI_TEST_APP "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${OSGI_UI_APP}") GET_TARGET_PROPERTY(_is_macosx_bundle ${OSGI_UI_APP} MACOSX_BUNDLE) IF(APPLE AND _is_macosx_bundle) SET(BLUEBERRY_UI_TEST_APP "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${OSGI_UI_APP}.app/Contents/MacOS/${OSGI_UI_APP}") ENDIF() ENDIF() ENDIF() SET(BLUEBERRY_TESTING_PROVISIONING_FILE "${BlueBerry_BINARY_DIR}/BlueBerryTesting.provisioning") ADD_CUSTOM_TARGET(BlueBerry) ctkMacroSetupPlugins(${_ctk_plugins} ${_ctk_testinfrastructure_plugins} ${_ctk_test_plugins} BUILD_OPTION_PREFIX BLUEBERRY_BUILD_ BUILD_ALL ${BLUEBERRY_BUILD_ALL_PLUGINS} COMPACT_OPTIONS) SET(BLUEBERRY_PROVISIONING_FILE "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/BlueBerry.provisioning") FunctionCreateProvisioningFile( FILE ${BLUEBERRY_PROVISIONING_FILE} PLUGINS ${_ctk_plugins} ) FunctionCreateProvisioningFile( FILE ${BLUEBERRY_TESTING_PROVISIONING_FILE} INCLUDE ${BLUEBERRY_PROVISIONING_FILE} PLUGINS ${_ctk_testinfrastructure_plugins} ${_ctk_test_plugins} ) if(${CMAKE_PROJECT_NAME}_PLUGIN_LIBRARIES) add_dependencies(BlueBerry ${${CMAKE_PROJECT_NAME}_PLUGIN_LIBRARIES}) endif() set_property(TARGET ${${CMAKE_PROJECT_NAME}_PLUGIN_LIBRARIES} PROPERTY LABELS BlueBerry) SET(BB_PLUGIN_USE_FILE "${BlueBerry_BINARY_DIR}/BlueBerryPluginUseFile.cmake") IF(${PROJECT_NAME}_PLUGIN_LIBRARIES) ctkFunctionGeneratePluginUseFile(${BB_PLUGIN_USE_FILE}) ELSE() FILE(REMOVE ${BB_PLUGIN_USE_FILE}) SET(BB_PLUGIN_USE_FILE ) ENDIF() # CTK Plugin Exports SET(BB_PLUGIN_EXPORTS_FILE "${CMAKE_CURRENT_BINARY_DIR}/BlueBerryPluginExports.cmake") GetMyTargetLibraries("${${PROJECT_NAME}_PLUGIN_LIBRARIES}" my_plugin_targets) SET(additional_export_targets mbilog PocoFoundation PocoUtil PocoXML) IF(BLUEBERRY_BUILD_TESTING) LIST(APPEND additional_export_targets CppUnit) ENDIF() export(TARGETS ${my_plugin_targets} ${additional_export_targets} FILE ${BB_PLUGIN_EXPORTS_FILE}) ADD_SUBDIRECTORY(Documentation) CONFIGURE_FILE(BlueBerryConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/BlueBerryConfig.cmake @ONLY) diff --git a/BlueBerry/Documentation/snippets/org.blueberry.ui.qt.help-config/main.cpp b/BlueBerry/Documentation/snippets/org.blueberry.ui.qt.help-config/main.cpp new file mode 100644 index 0000000000..044238921f --- /dev/null +++ b/BlueBerry/Documentation/snippets/org.blueberry.ui.qt.help-config/main.cpp @@ -0,0 +1,115 @@ + +#include + +#include +#include +#include +#include +#include + +class MyApplicationPlugin : public QObject, public ctkPluginActivator +{ + Q_OBJECT + Q_INTERFACES(ctkPluginActivator) + +public: + + MyApplicationPlugin(); + ~MyApplicationPlugin(); + + //! [0] + void start(ctkPluginContext* context) + { + // Get a service reference for the Config Admin service + ctkServiceReference cmRef = context->getServiceReference(); + ctkConfigurationAdmin* configAdmin = 0; + if (cmRef) + { + configAdmin = context->getService(cmRef); + } + + // Use the CTK Configuration Admin service to configure the BlueBerry help system. + // This assumes that the plug-in providing the Config Admin implementation is + // already active. + if (configAdmin) + { + // Get a ctkConfiguration object for the PID "org.blueberry.services.help" + // (or create an unbound instance if it does not exist yet). + ctkConfigurationPtr conf = configAdmin->getConfiguration("org.blueberry.services.help", QString()); + + // Configure the help system using a custom home page + ctkDictionary helpProps; + helpProps.insert("homePage", "qthelp://org.company.plugin/bundle/index.html"); + conf->update(helpProps); + + // Unget the service + context->ungetService(cmRef); + } + else + { + // Warn that the Config Admin service is unavailable + } + } + //! [0] + + void stop(ctkPluginContext *context); + + //! [1] + void requestHelp(ctkPluginContext* context) + { + if (context == 0) + { + // Warn that the plugin context is zero + return; + } + + // Check if the org.blueberry.ui.qt.help plug-in is installed and started + QList > plugins = context->getPlugins(); + foreach(QSharedPointer p, plugins) + { + if (p->getSymbolicName() == "org.blueberry.ui.qt.help" && + p->getState() != ctkPlugin::ACTIVE) + { + // The plug-in is in RESOLVED state but is not started yet. + // Try to activate the plug-in explicitly, so that it can react + // to events send via the CTK Event Admin. + try + { + p->start(ctkPlugin::START_TRANSIENT); + } + catch (const ctkPluginException& pe) + { + // Warn that activating the org.blueberry.ui.qt.help plug-in failed + return; + } + } + } + + ctkServiceReference eventAdminRef = context->getServiceReference(); + ctkEventAdmin* eventAdmin = 0; + if (eventAdminRef) + { + eventAdmin = context->getService(eventAdminRef); + } + + if (eventAdmin == 0) + { + // Warn that the ctkEventAdmin service was not found + } + else + { + // Create the event and send it asynchronuously + ctkEvent ev("org/blueberry/ui/help/CONTEXTHELP_REQUESTED"); + eventAdmin->postEvent(ev); + } + } + //! [1] + +private: + +}; + +int main(int argc, char* argv[]) +{ + return 0; +} diff --git a/CMakeExternals/CTK.cmake b/CMakeExternals/CTK.cmake index 76234df9cf..afb4863bcf 100644 --- a/CMakeExternals/CTK.cmake +++ b/CMakeExternals/CTK.cmake @@ -1,63 +1,64 @@ #----------------------------------------------------------------------------- # CTK #----------------------------------------------------------------------------- IF(MITK_USE_CTK) # Sanity checks IF(DEFINED CTK_DIR AND NOT EXISTS ${CTK_DIR}) MESSAGE(FATAL_ERROR "CTK_DIR variable is defined but corresponds to non-existing directory") ENDIF() SET(proj CTK) SET(proj_DEPENDENCIES ) SET(CTK_DEPENDS ${proj}) IF(NOT DEFINED CTK_DIR) - SET(revision_tag 6f26c34) + SET(revision_tag 34a638b) IF(${proj}_REVISION_TAG) SET(revision_tag ${${proj}_REVISION_TAG}) ENDIF() SET(ctk_optional_cache_args ) IF(MITK_USE_Python) LIST(APPEND ctk_optional_cache_args -DCTK_LIB_Scripting/Python/Widgets:BOOL=ON ) ENDIF() FOREACH(type RUNTIME ARCHIVE LIBRARY) IF(DEFINED CTK_PLUGIN_${type}_OUTPUT_DIRECTORY) LIST(APPEND mitk_optional_cache_args -DCTK_PLUGIN_${type}_OUTPUT_DIRECTORY:PATH=${CTK_PLUGIN_${type}_OUTPUT_DIRECTORY}) ENDIF() ENDFOREACH() ExternalProject_Add(${proj} GIT_REPOSITORY http://github.com/commontk/CTK.git GIT_TAG ${revision_tag} BINARY_DIR ${proj}-build UPDATE_COMMAND "" INSTALL_COMMAND "" CMAKE_GENERATOR ${gen} CMAKE_ARGS ${ep_common_args} ${ctk_optional_cache_args} -DDESIRED_QT_VERSION:STRING=4 -DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE} -DGit_EXECUTABLE:FILEPATH=${GIT_EXECUTABLE} -DGIT_EXECUTABLE:FILEPATH=${GIT_EXECUTABLE} -DCTK_LIB_PluginFramework:BOOL=ON -DCTK_LIB_DICOM/Widgets:BOOL=ON -DCTK_PLUGIN_org.commontk.eventadmin:BOOL=ON + -DCTK_PLUGIN_org.commontk.configadmin:BOOL=ON -DCTK_USE_GIT_PROTOCOL:BOOL=OFF DEPENDS ${proj_DEPENDENCIES} ) SET(CTK_DIR ${CMAKE_CURRENT_BINARY_DIR}/${proj}-build) ELSE() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") ENDIF() ENDIF()