ktutorial-commits Mailing List for KTutorial (Page 7)
Status: Alpha
Brought to you by:
danxuliu
You can subscribe to this list here.
2010 |
Jan
(1) |
Feb
(36) |
Mar
(117) |
Apr
(11) |
May
(8) |
Jun
(1) |
Jul
|
Aug
(2) |
Sep
(21) |
Oct
(16) |
Nov
|
Dec
|
---|---|---|---|---|---|---|---|---|---|---|---|---|
2011 |
Jan
(1) |
Feb
|
Mar
(6) |
Apr
(6) |
May
(15) |
Jun
(15) |
Jul
(6) |
Aug
|
Sep
(1) |
Oct
(4) |
Nov
|
Dec
|
2012 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(10) |
Jul
(4) |
Aug
(29) |
Sep
(4) |
Oct
|
Nov
|
Dec
(2) |
From: <dan...@us...> - 2010-05-11 03:39:01
|
Revision: 238 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=238&view=rev Author: danxuliu Date: 2010-05-11 03:38:55 +0000 (Tue, 11 May 2010) Log Message: ----------- Add StepTextWidget to show the text of a step. HTML links in the text with the format "widget:nameOfTheWidget" can be used to highlight the referenced widget when a tutorial is being executed. Modified Paths: -------------- trunk/ktutorial/ktutorial-library/src/view/CMakeLists.txt trunk/ktutorial/ktutorial-library/src/view/StepWidget.cpp trunk/ktutorial/ktutorial-library/src/view/StepWidget.ui trunk/ktutorial/ktutorial-library/tests/view/CMakeLists.txt trunk/ktutorial/ktutorial-library/tests/view/StepWidgetTest.cpp Added Paths: ----------- trunk/ktutorial/ktutorial-library/src/view/StepTextWidget.cpp trunk/ktutorial/ktutorial-library/src/view/StepTextWidget.h trunk/ktutorial/ktutorial-library/tests/view/StepTextWidgetTest.cpp Modified: trunk/ktutorial/ktutorial-library/src/view/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-library/src/view/CMakeLists.txt 2010-04-26 05:30:40 UTC (rev 237) +++ trunk/ktutorial/ktutorial-library/src/view/CMakeLists.txt 2010-05-11 03:38:55 UTC (rev 238) @@ -1,6 +1,7 @@ -include_directories(${CMAKE_CURRENT_BINARY_DIR} ${KDE4_INCLUDES}) +include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${KDE4_INCLUDES}) set(ktutorial_view_SRCS + StepTextWidget.cpp StepWidget.cpp TutorialListModel.cpp TutorialManagerDialog.cpp @@ -13,4 +14,4 @@ kde4_add_library(ktutorial_view ${ktutorial_view_SRCS}) -target_link_libraries(ktutorial_view ${KDE4_KDEUI_LIBS}) +target_link_libraries(ktutorial_view ktutorial_extendedinformation ${KDE4_KDEUI_LIBS}) Added: trunk/ktutorial/ktutorial-library/src/view/StepTextWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/view/StepTextWidget.cpp (rev 0) +++ trunk/ktutorial/ktutorial-library/src/view/StepTextWidget.cpp 2010-05-11 03:38:55 UTC (rev 238) @@ -0,0 +1,208 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include <QContextMenuEvent> +#include <QMenu> + +#include <KDebug> +#include <KLocalizedString> + +#include "StepTextWidget.h" +#include "../KTutorial.h" +#include "../extendedinformation/WidgetHighlighterManager.h" + +using extendedinformation::WidgetHighlighterManager; + +namespace view { + +//public: + +StepTextWidget::StepTextWidget(QWidget* parent /*= 0*/): + KTextEdit(parent), + mCurrentHighlightedWidget(0) { + setReadOnly(true); + setFrameShape(QFrame::NoFrame); + setFrameShadow(QFrame::Plain); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + viewport()->setCursor(Qt::ArrowCursor); + + QPalette palette = this->palette(); + palette.setColor(QPalette::Base, Qt::transparent); + setPalette(palette); + + setAlignment(Qt::AlignJustify | Qt::AlignVCenter); + + //Set a explicit text width to avoid some strange behavior: if the text + //width is set to QWIDGETSIZE_MAX without a previous text width set, the + //size returned by the document has weird values. Anyway, sizeHint is + //usually called before minimumSizeHint, so a text width will be already set + //when minimumSizeHint is called, but just in case. + document()->setTextWidth(0); + + connect(this, SIGNAL(textChanged()), this, SLOT(updateText())); +} + +bool StepTextWidget::eventFilter(QObject* watched, QEvent* event) { + if (watched != mCurrentHighlightedWidget) { + return false; + } + + if (event->type() != QEvent::FocusIn) { + return false; + } + + stopHighlightingCurrentWidget(); + + return false; +} + +int StepTextWidget::heightForWidth(int width) const { + return sizeForWidth(width).height(); +} + +QSize StepTextWidget::minimumSizeHint() const { + QSize size; + size.setHeight(sizeForWidth(QWIDGETSIZE_MAX).height()); + size.setWidth(sizeForWidth(0).width()); + + return size; +} + +QSize StepTextWidget::sizeHint() const { + return sizeForWidth(-1); +} + +//protected: + +void StepTextWidget::contextMenuEvent(QContextMenuEvent* event) { + QString anchor = anchorAt(event->pos()); + if (!anchor.startsWith(QLatin1String("widget:"))) { + KTextEdit::contextMenuEvent(event); + return; + } + + QMenu* menu = new QMenu(this); + + if (mCurrentHighlightedWidget && + mCurrentHighlightedWidget != widgetForAnchor(anchor)) { + stopHighlightingCurrentWidget(); + } + + if (!mCurrentHighlightedWidget) { + menu->addAction(i18nc("@item:inmenu", "Highlight"), + this, SLOT(highlightCurrentWidget())); + + mCurrentHighlightedWidget = widgetForAnchor(anchor); + } else { + menu->addAction(i18nc("@item:inmenu", "Stop highlighting"), + this, SLOT(stopHighlightingCurrentWidget())); + } + + menu->exec(event->globalPos()); + delete menu; +} + +void StepTextWidget::mouseMoveEvent(QMouseEvent* event) { + KTextEdit::mouseMoveEvent(event); + + if (anchorAt(event->pos()).startsWith(QLatin1String("widget:"))) { + viewport()->setCursor(Qt::PointingHandCursor); + } else { + viewport()->setCursor(Qt::ArrowCursor); + } +} + +void StepTextWidget::mousePressEvent(QMouseEvent* event) { + QString anchor = anchorAt(event->pos()); + if (event->button() != Qt::LeftButton || + !anchor.startsWith(QLatin1String("widget:"))) { + KTextEdit::mousePressEvent(event); + return; + } + + if (mCurrentHighlightedWidget && + mCurrentHighlightedWidget != widgetForAnchor(anchor)) { + stopHighlightingCurrentWidget(); + } + + if (!mCurrentHighlightedWidget) { + mCurrentHighlightedWidget = widgetForAnchor(anchor); + + highlightCurrentWidget(); + } else { + stopHighlightingCurrentWidget(); + } +} + +//private: + +QSize StepTextWidget::sizeForWidth(int width) const { + const qreal oldTextWidth = document()->textWidth(); + + if (width >= 0) { + document()->setTextWidth(width); + } else { + document()->adjustSize(); + } + + QSize size = document()->size().toSize(); + + document()->setTextWidth(oldTextWidth); + + return size; +} + +QWidget* StepTextWidget::widgetForAnchor(const QString& anchor) { + QString widgetName = anchor.mid(QString("widget:").length()); + return KTutorial::self()->findObject<QWidget*>(widgetName); +} + +//private slots: + +void StepTextWidget::updateText() { + updateGeometry(); + + if (mCurrentHighlightedWidget) { + stopHighlightingCurrentWidget(); + } +} + +void StepTextWidget::highlightCurrentWidget() { + if (!mCurrentHighlightedWidget) { + kWarning() << "The widget to highlight was not found!"; + } + + WidgetHighlighterManager::self()->highlight(mCurrentHighlightedWidget); + + mCurrentHighlightedWidget->installEventFilter(this); +} + +void StepTextWidget::stopHighlightingCurrentWidget() { + if (!mCurrentHighlightedWidget) { + kWarning() << "The widget to stop highlighting was not found!"; + } + + WidgetHighlighterManager::self()->stopHighlighting(mCurrentHighlightedWidget); + + mCurrentHighlightedWidget->removeEventFilter(this); + mCurrentHighlightedWidget = 0; +} + +} Property changes on: trunk/ktutorial/ktutorial-library/src/view/StepTextWidget.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-library/src/view/StepTextWidget.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/view/StepTextWidget.h (rev 0) +++ trunk/ktutorial/ktutorial-library/src/view/StepTextWidget.h 2010-05-11 03:38:55 UTC (rev 238) @@ -0,0 +1,181 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef VIEW_STEPTEXTWIDGET_H +#define VIEW_STEPTEXTWIDGET_H + +#include <KTextEdit> + +namespace view { + +/** + * A TextEdit with the appearance of a label to show the text of a step. + * It behaves like a QLabel with custom behavior for links. However, as QLabel + * doesn't provide a way to easily extend its link related behavior, a KTextEdit + * with a QLabel appearance (read only, size fit to text, no scroll bars...) is + * used instead. + * + * Links that exhibit a custom behavior are those with the format + * "widget:nameOfTheWidget". When the link is pressed with the left mouse + * button, the widget with the specified name is highlighted. When it is pressed + * again, the highlighting is stopped. If the right button is pressed, a context + * menu with an item to highlight or stop highlighting is shown. + * + * If a widget was being highlighted when the highglighting is started in + * another widget, the highlighting in the previous widget is stopped. The + * highlighting is also stopped when the widget gets the focus, or when the text + * is changed in the StepTextWidget. + * + * When the mouse cursor is moved over a "widget:" link, the arrow cursor is + * changed to a pointing hand cursor. + * + * The links are specified using HTML markup, for example, + * <a href="widget:theNameOfTheWidget">the text of the link</a> + */ +class StepTextWidget: public KTextEdit { +Q_OBJECT +public: + + /** + * Creates a new StepTextWidget. + * + * @param parent The parent widget. + */ + explicit StepTextWidget(QWidget* parent = 0); + + /** + * Watches the widget currently being highlighted and stops the highlighting + * when it is focused. + * + * @param watched The filtered object that received an event. + * @param event The event received. + * @return False, to allow the event to be handled further. + */ + virtual bool eventFilter(QObject* watched, QEvent* event); + + /** + * Returns the height of the size for the given width. + * + * @param width The width to get its height. + * @return The height for the width. + */ + virtual int heightForWidth(int width) const; + + /** + * Returns the recommended minimum size for this StepTextWidget. + * The size has the width of the longest word in the text and the height of + * a single line. + * + * @return The recommended minimum size. + */ + virtual QSize minimumSizeHint() const; + + /** + * Returns the recommended size for this StepTextWidget. + * The size is adjusted to fit the text as a rectangle, with a width bigger + * then the height. + * + * @return The recommended size. + */ + virtual QSize sizeHint() const; + +protected: + + /** + * Shows a custom context menu when a context menu is requested on a + * "widget:" anchor. + * The context menu will contain a "Stop highlighting" or a "Highlight" item + * depending on whether the widget is the one currently being highlighted or + * not. If the widget currently being highlighted is another one, it is + * stopped. + * + * @param event The context menu event. + */ + virtual void contextMenuEvent(QContextMenuEvent* event); + + /** + * Changes the cursor to a pointing hand when it is over a "widget:" anchor. + * + * @param event The mouse move event. + */ + virtual void mouseMoveEvent(QMouseEvent* event); + + /** + * When the mouse is pressed on a "widget:" anchor, it is highlighted or + * stopped being highlighted. + * If the widget currently being highlighted is another one, it is stopped. + * + * @param event The mouse press event. + */ + virtual void mousePressEvent(QMouseEvent* event); + +private: + + /** + * The widget currently being highlighted as a result of activating a link + * in this StepTextWidget. + */ + QWidget* mCurrentHighlightedWidget; + + /** + * Returns the size for the given text width. + * If the width is < 0, the size is adjusted to the text as a rectangle, + * with a width bigger than the height. + * If the width is >= 0, the size is the given width and a height bigger + * enough to show the whole text. The width may be bigger than the given one + * if the given one is not big enough to show the longest word in the text. + * + * @param width The width to get its size. + * @return The size for the width. + */ + QSize sizeForWidth(int width) const; + + /** + * Returns the widget referenced in the given anchor. + * The anchor must have a "widget:name" format. The widget is looked for + * using its name in KTutorial::findObject(QString). + * + * @param anchor The anchor to get its widget. + * @return The widget referenced in the anchor. + */ + QWidget* widgetForAnchor(const QString& anchor); + +private Q_SLOTS: + + /** + * Notifies the layout that the geometry of the widget has changed and stops + * the highlighting of the current widget, if any. + */ + void updateText(); + + /** + * Starts highlighting the current widget. + */ + void highlightCurrentWidget(); + + /** + * Stops highlighting the current widget. + * The current widget is cleared. + */ + void stopHighlightingCurrentWidget(); + +}; + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-library/src/view/StepTextWidget.h ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-library/src/view/StepWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/view/StepWidget.cpp 2010-04-26 05:30:40 UTC (rev 237) +++ trunk/ktutorial/ktutorial-library/src/view/StepWidget.cpp 2010-05-11 03:38:55 UTC (rev 238) @@ -65,7 +65,7 @@ //public slots: void StepWidget::setStep(Step* step) { - ui->textLabel->setText(step->text()); + ui->textWidget->setText(step->text()); setOptions(step->options()); adjustSize(); Modified: trunk/ktutorial/ktutorial-library/src/view/StepWidget.ui =================================================================== --- trunk/ktutorial/ktutorial-library/src/view/StepWidget.ui 2010-04-26 05:30:40 UTC (rev 237) +++ trunk/ktutorial/ktutorial-library/src/view/StepWidget.ui 2010-05-11 03:38:55 UTC (rev 238) @@ -1,7 +1,8 @@ -<ui version="4.0" > +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> <class>StepWidget</class> - <widget class="QWidget" name="StepWidget" > - <property name="geometry" > + <widget class="QWidget" name="StepWidget"> + <property name="geometry"> <rect> <x>0</x> <y>0</y> @@ -9,39 +10,30 @@ <height>306</height> </rect> </property> - <layout class="QVBoxLayout" > - <property name="spacing" > + <layout class="QVBoxLayout"> + <property name="spacing"> <number>0</number> </property> - <property name="leftMargin" > + <property name="margin"> <number>4</number> </property> - <property name="topMargin" > - <number>4</number> - </property> - <property name="rightMargin" > - <number>4</number> - </property> - <property name="bottomMargin" > - <number>4</number> - </property> <item> - <layout class="QHBoxLayout" > - <property name="spacing" > + <layout class="QHBoxLayout"> + <property name="spacing"> <number>0</number> </property> - <property name="leftMargin" > + <property name="leftMargin"> <number>0</number> </property> - <property name="topMargin" > + <property name="topMargin"> <number>0</number> </property> <item> <spacer> - <property name="orientation" > + <property name="orientation"> <enum>Qt::Horizontal</enum> </property> - <property name="sizeHint" > + <property name="sizeHint" stdset="0"> <size> <width>40</width> <height>20</height> @@ -50,17 +42,17 @@ </spacer> </item> <item> - <widget class="KPushButton" name="closeButton" > - <property name="focusPolicy" > + <widget class="KPushButton" name="closeButton"> + <property name="focusPolicy"> <enum>Qt::NoFocus</enum> </property> - <property name="toolTip" > - <string comment="@info:tooltip" >Close this tutorial</string> + <property name="toolTip"> + <string comment="@info:tooltip">Close this tutorial</string> </property> - <property name="whatsThis" > - <string comment="@info:whatsthis" >Click here to close the tutorial.<nl/>The tutorial can be closed when you have finished it, or at any time to cancel it.</string> + <property name="whatsThis"> + <string comment="@info:whatsthis">Click here to close the tutorial.<nl/>The tutorial can be closed when you have finished it, or at any time to cancel it.</string> </property> - <property name="flat" > + <property name="flat"> <bool>true</bool> </property> </widget> @@ -68,32 +60,23 @@ </layout> </item> <item> - <widget class="QLabel" name="textLabel" > - <property name="sizePolicy" > - <sizepolicy vsizetype="MinimumExpanding" hsizetype="MinimumExpanding" > + <widget class="view::StepTextWidget" name="textWidget"> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> - <property name="toolTip" > - <string comment="@info:tooltip" >The instructions for this step</string> + <property name="toolTip"> + <string comment="@info:tooltip">The instructions for this step</string> </property> - <property name="whatsThis" > - <string comment="@info:whatsthis" >Here appear the instructions for each step of the tutorial.<nl/>Once you complete one step, a new step with new instructions will be shown.</string> + <property name="whatsThis"> + <string comment="@info:whatsthis">Here appear the instructions for each step of the tutorial.<nl/>Once you complete one step, a new step with new instructions will be shown.</string> </property> - <property name="text" > - <string/> - </property> - <property name="alignment" > - <set>Qt::AlignJustify|Qt::AlignVCenter</set> - </property> - <property name="wordWrap" > - <bool>true</bool> - </property> </widget> </item> <item> - <widget class="QWidget" native="1" name="optionsWidget" /> + <widget class="QWidget" name="optionsWidget" native="true"/> </item> </layout> </widget> @@ -103,6 +86,11 @@ <extends>QPushButton</extends> <header>kpushbutton.h</header> </customwidget> + <customwidget> + <class>view::StepTextWidget</class> + <extends>QTextEdit</extends> + <header>StepTextWidget.h</header> + </customwidget> </customwidgets> <resources/> <connections/> Modified: trunk/ktutorial/ktutorial-library/tests/view/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-library/tests/view/CMakeLists.txt 2010-04-26 05:30:40 UTC (rev 237) +++ trunk/ktutorial/ktutorial-library/tests/view/CMakeLists.txt 2010-05-11 03:38:55 UTC (rev 238) @@ -17,6 +17,7 @@ ENDMACRO(UNIT_TESTS) unit_tests( + StepTextWidget StepWidget TutorialListModel TutorialManagerDialog @@ -29,6 +30,7 @@ ENDMACRO(MEM_TESTS) mem_tests( + StepTextWidget StepWidget TutorialListModel TutorialManagerDialog Added: trunk/ktutorial/ktutorial-library/tests/view/StepTextWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/view/StepTextWidgetTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-library/tests/view/StepTextWidgetTest.cpp 2010-05-11 03:38:55 UTC (rev 238) @@ -0,0 +1,365 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include <QtTest> +#include <qtest_kde.h> + +#include <KXmlGuiWindow> + +#include "StepTextWidget.h" +#define protected public +#define private public +#include "../KTutorial.h" +#undef private +#undef protected +#include "../extendedinformation/WidgetHighlighter.h" + +using extendedinformation::WidgetHighlighter; + +namespace view { + +class StepTextWidgetTest: public QObject { +Q_OBJECT +public slots: + + void selectFirstContextMenuOption(); + +private slots: + + void init(); + void cleanup(); + + void testConstructor(); + + void testSizeHintWithBiggerText(); + void testSizeHintWithSmallerText(); + + void testHighlightWidgetClickingOnAnchor(); + void testStopHighlightingWidgetClickingOnAnchor(); + void testHighlightWidgetUsingContextMenu(); + void testStopHighlightingWidgetUsingContextMenu(); + void testHighlightSeveralWidgets(); + + void testStopHighlightingWidgetWhenFocused(); + + void testSetTextWhenWidgetIsBeingHighlighted(); + +private: + + QPoint centerOfText(const StepTextWidget& widget, const QString& text); + + void showContextMenuAndSelectFirstOption(const StepTextWidget& widget, + const QPoint& position); + +}; + +void StepTextWidgetTest::init() { + delete KTutorial::sSelf; + KTutorial::sSelf = new KTutorial(); +} + +void StepTextWidgetTest::cleanup() { +} + +void StepTextWidgetTest::testConstructor() { + QWidget parent; + StepTextWidget* widget = new StepTextWidget(&parent); + + QCOMPARE(widget->parentWidget(), &parent); + QVERIFY(widget->isReadOnly()); + QCOMPARE(widget->frameShape(), QFrame::NoFrame); + QCOMPARE(widget->frameShadow(), QFrame::Plain); + QCOMPARE(widget->horizontalScrollBarPolicy(), Qt::ScrollBarAlwaysOff); + QCOMPARE(widget->verticalScrollBarPolicy(), Qt::ScrollBarAlwaysOff); + QCOMPARE(widget->palette().color(QPalette::Base), QColor(Qt::transparent)); +} + +void StepTextWidgetTest::testSizeHintWithBiggerText() { + StepTextWidget widget; + widget.setText("Some short text"); + + QSize oldSizeHint = widget.sizeHint(); + + widget.setText("Some bigger text to be shown hopefully in several lines"); + + QSize newSizeHint = widget.sizeHint(); + QCOMPARE(widget.heightForWidth(newSizeHint.width()), newSizeHint.height()); + QVERIFY(newSizeHint.width() > newSizeHint.height()); + QVERIFY(newSizeHint.height() > widget.minimumSizeHint().height()); + QVERIFY(newSizeHint.width() > widget.minimumSizeHint().width()); + QVERIFY(newSizeHint.height() > oldSizeHint.height()); + QVERIFY(newSizeHint.width() > oldSizeHint.width()); +} + +void StepTextWidgetTest::testSizeHintWithSmallerText() { + StepTextWidget widget; + widget.setText("Some bigger text to be shown hopefully in several lines"); + + QSize oldSizeHint = widget.sizeHint(); + + widget.setText("Some short text"); + + QSize newSizeHint = widget.sizeHint(); + QCOMPARE(widget.heightForWidth(newSizeHint.width()), newSizeHint.height()); + QVERIFY(newSizeHint.width() > newSizeHint.height()); + QVERIFY(newSizeHint.height() < oldSizeHint.height()); + QVERIFY(newSizeHint.width() < oldSizeHint.width()); +} + +void StepTextWidgetTest::testHighlightWidgetClickingOnAnchor() { + KXmlGuiWindow mainWindow; + KTutorial::self()->setup(&mainWindow); + QWidget* widgetToHighlight = new QWidget(&mainWindow); + widgetToHighlight->setObjectName("widgetName"); + + StepTextWidget widget; + widget.setText("The <a href=\"widget:widgetName\">widget to highlight</a>"); + widget.show(); + + QPoint position = centerOfText(widget, "widget to highlight"); + QTest::mouseClick(widget.viewport(), Qt::LeftButton, Qt::NoModifier, + position, 500); + + QVERIFY(widgetToHighlight->findChild<WidgetHighlighter*>("")); +} + +void StepTextWidgetTest::testStopHighlightingWidgetClickingOnAnchor() { + KXmlGuiWindow mainWindow; + KTutorial::self()->setup(&mainWindow); + QWidget* widgetToHighlight = new QWidget(&mainWindow); + widgetToHighlight->setObjectName("widgetName"); + + StepTextWidget widget; + widget.setText("The <a href=\"widget:widgetName\">widget to highlight</a>"); + widget.show(); + + QPoint position = centerOfText(widget, "widget to highlight"); + QTest::mouseClick(widget.viewport(), Qt::LeftButton, Qt::NoModifier, + position, 500); + QTest::mouseClick(widget.viewport(), Qt::LeftButton, Qt::NoModifier, + position, 500); + + //Give the highlighter time to stop + QTest::qWait(500); + + QVERIFY(!widgetToHighlight->findChild<WidgetHighlighter*>("")); +} + +void StepTextWidgetTest::testHighlightWidgetUsingContextMenu() { + KXmlGuiWindow mainWindow; + KTutorial::self()->setup(&mainWindow); + QWidget* widgetToHighlight = new QWidget(&mainWindow); + widgetToHighlight->setObjectName("widgetName"); + + StepTextWidget widget; + widget.setText("The <a href=\"widget:widgetName\">widget to highlight</a>"); + widget.show(); + + //Give the widget time to be shown + QTest::qWait(500); + + QPoint position = centerOfText(widget, "widget to highlight"); + showContextMenuAndSelectFirstOption(widget, position); + + QVERIFY(widgetToHighlight->findChild<WidgetHighlighter*>("")); +} + +void StepTextWidgetTest::testStopHighlightingWidgetUsingContextMenu() { + KXmlGuiWindow mainWindow; + KTutorial::self()->setup(&mainWindow); + QWidget* widgetToHighlight = new QWidget(&mainWindow); + widgetToHighlight->setObjectName("widgetName"); + + StepTextWidget widget; + widget.setText("The <a href=\"widget:widgetName\">widget to highlight</a>"); + widget.show(); + + //Give the widget time to be shown + QTest::qWait(500); + + QPoint position = centerOfText(widget, "widget to highlight"); + showContextMenuAndSelectFirstOption(widget, position); + QTest::qWait(500); + showContextMenuAndSelectFirstOption(widget, position); + + //Give the highlighter time to stop + QTest::qWait(500); + + QVERIFY(!widgetToHighlight->findChild<WidgetHighlighter*>("")); +} + +void StepTextWidgetTest::testHighlightSeveralWidgets() { + KXmlGuiWindow mainWindow; + KTutorial::self()->setup(&mainWindow); + QWidget* widgetToHighlight1 = new QWidget(&mainWindow); + widgetToHighlight1->setObjectName("widget1"); + QWidget* widgetToHighlight2 = new QWidget(&mainWindow); + widgetToHighlight2->setObjectName("widget2"); + QWidget* widgetToHighlight3 = new QWidget(&mainWindow); + widgetToHighlight3->setObjectName("widget3"); + + StepTextWidget widget; + widget.setText("The <a href=\"widget:widget1\">first widget</a>, " +"<a href=\"widget:widget2\">second widget</a> and " +"<a href=\"widget:widget3\">third widget</a>"); + widget.show(); + + QPoint position1 = centerOfText(widget, "first widget"); + QPoint position2 = centerOfText(widget, "second widget"); + QPoint position3 = centerOfText(widget, "third widget"); + + QTest::mouseClick(widget.viewport(), Qt::LeftButton, Qt::NoModifier, + position1, 500); + QTest::mouseClick(widget.viewport(), Qt::LeftButton, Qt::NoModifier, + position2, 500); + + //Give the highlighter time to stop + QTest::qWait(500); + + QVERIFY(!widgetToHighlight1->findChild<WidgetHighlighter*>("")); + QVERIFY(widgetToHighlight2->findChild<WidgetHighlighter*>("")); + QVERIFY(!widgetToHighlight3->findChild<WidgetHighlighter*>("")); + + showContextMenuAndSelectFirstOption(widget, position3); + + //Give the highlighter time to stop + QTest::qWait(500); + + QVERIFY(!widgetToHighlight1->findChild<WidgetHighlighter*>("")); + QVERIFY(!widgetToHighlight2->findChild<WidgetHighlighter*>("")); + QVERIFY(widgetToHighlight3->findChild<WidgetHighlighter*>("")); + + showContextMenuAndSelectFirstOption(widget, position1); + + //Give the highlighter time to stop + QTest::qWait(500); + + QVERIFY(widgetToHighlight1->findChild<WidgetHighlighter*>("")); + QVERIFY(!widgetToHighlight2->findChild<WidgetHighlighter*>("")); + QVERIFY(!widgetToHighlight3->findChild<WidgetHighlighter*>("")); + + QTest::mouseClick(widget.viewport(), Qt::LeftButton, Qt::NoModifier, + position1, 500); + + //Give the highlighter time to stop + QTest::qWait(500); + + QVERIFY(!widgetToHighlight1->findChild<WidgetHighlighter*>("")); + QVERIFY(!widgetToHighlight2->findChild<WidgetHighlighter*>("")); + QVERIFY(!widgetToHighlight3->findChild<WidgetHighlighter*>("")); + + QTest::mouseClick(widget.viewport(), Qt::LeftButton, Qt::NoModifier, + position2, 500); + QTest::qWait(500); + showContextMenuAndSelectFirstOption(widget, position2); + + //Give the highlighter time to stop + QTest::qWait(500); + + QVERIFY(!widgetToHighlight1->findChild<WidgetHighlighter*>("")); + QVERIFY(!widgetToHighlight2->findChild<WidgetHighlighter*>("")); + QVERIFY(!widgetToHighlight3->findChild<WidgetHighlighter*>("")); +} + +void StepTextWidgetTest::testStopHighlightingWidgetWhenFocused() { + KXmlGuiWindow mainWindow; + KTutorial::self()->setup(&mainWindow); + QWidget* widgetToHighlight = new QWidget(&mainWindow); + widgetToHighlight->setObjectName("widgetName"); + mainWindow.setCentralWidget(widgetToHighlight); + mainWindow.show(); + + StepTextWidget widget; + widget.setText("The <a href=\"widget:widgetName\">widget to highlight</a>"); + widget.show(); + + QPoint position = centerOfText(widget, "widget to highlight"); + QTest::mouseClick(widget.viewport(), Qt::LeftButton, Qt::NoModifier, + position, 500); + + //To get the focus, the parent window of the widget must be active + mainWindow.activateWindow(); + widgetToHighlight->setFocus(); + + //Give the highlighter time to stop + QTest::qWait(500); + + QVERIFY(!widgetToHighlight->findChild<WidgetHighlighter*>("")); +} + +void StepTextWidgetTest::testSetTextWhenWidgetIsBeingHighlighted() { + KXmlGuiWindow mainWindow; + KTutorial::self()->setup(&mainWindow); + QWidget* widgetToHighlight = new QWidget(&mainWindow); + widgetToHighlight->setObjectName("widgetName"); + + StepTextWidget widget; + widget.setText("The <a href=\"widget:widgetName\">widget to highlight</a>"); + widget.show(); + + QPoint position = centerOfText(widget, "widget to highlight"); + QTest::mouseClick(widget.viewport(), Qt::LeftButton, Qt::NoModifier, + position, 500); + + widget.setText("Another text"); + + QVERIFY(!widgetToHighlight->findChild<WidgetHighlighter*>("")); +} + +/////////////////////////////////// Helpers //////////////////////////////////// + +void StepTextWidgetTest::selectFirstContextMenuOption() { + QVERIFY(QApplication::activePopupWidget()); + QTest::keyClick(QApplication::activePopupWidget(), Qt::Key_Down); + QTest::keyClick(QApplication::activePopupWidget(), Qt::Key_Enter); +} + +QPoint StepTextWidgetTest::centerOfText(const StepTextWidget& widget, + const QString& text) { + QTextCursor cursor = widget.document()->find(text); + + //The cursor rect doesn't include the selection, just a tiny rectangle for + //the cursor position. To ensure that the menu is shown on the anchor, set + //the cursor in the middle of the selection + cursor.setPosition((cursor.selectionStart() + cursor.selectionEnd()) / 2); + return widget.cursorRect(cursor).center(); +} + +void StepTextWidgetTest::showContextMenuAndSelectFirstOption( + const StepTextWidget& widget, const QPoint& position) { + //The context menu can't be triggered sending a right mouse button press + //event, as that is platform dependent (that event is not handled by + //QTextEdit or its parents, but by the QApplication for the platform that + //creates a context menu event when needed). A explicit QContextMenuEvent + //must be sent for it to work. + QContextMenuEvent event(QContextMenuEvent::Mouse, position, + widget.mapToGlobal(position)); + + //The context menu contains its own event loop, so it won't return to the + //test code until it is closed. Thus, the commands to execute on the dialog + //must be "queued", as calling QTest::keyClick after the button click won't + //work. + QTimer::singleShot(500, this, SLOT(selectFirstContextMenuOption())); + QApplication::sendEvent(widget.viewport(), &event); +} + +} + +QTEST_KDEMAIN(view::StepTextWidgetTest, GUI) + +#include "StepTextWidgetTest.moc" Property changes on: trunk/ktutorial/ktutorial-library/tests/view/StepTextWidgetTest.cpp ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-library/tests/view/StepWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/view/StepWidgetTest.cpp 2010-04-26 05:30:40 UTC (rev 237) +++ trunk/ktutorial/ktutorial-library/tests/view/StepWidgetTest.cpp 2010-05-11 03:38:55 UTC (rev 238) @@ -28,6 +28,7 @@ #undef protected #include "ui_StepWidget.h" +#include "StepTextWidget.h" #include "../Option.h" #include "../Step.h" @@ -76,7 +77,7 @@ int mDummySlotCallCount; int mAnotherDummySlotCallCount; - QLabel* textLabel(StepWidget* stepWidget); + StepTextWidget* textWidget(StepWidget* stepWidget); KPushButton* closeButton(StepWidget* stepWidget); }; @@ -88,8 +89,8 @@ i18n("Tutorial: %1", QString("Test tutorial"))); QCOMPARE(stepWidget.windowFlags(), Qt::Dialog | Qt::FramelessWindowHint); QVERIFY(closeButton(&stepWidget)); - QVERIFY(textLabel(&stepWidget)); - QCOMPARE(textLabel(&stepWidget)->text(), QString("")); + QVERIFY(textWidget(&stepWidget)); + QCOMPARE(textWidget(&stepWidget)->toPlainText(), QString("")); QVERIFY(stepWidget.mOptionsLayout); QCOMPARE(stepWidget.mOptionsLayout->count(), 0); } @@ -104,7 +105,7 @@ stepWidget.setStep(&step); - QCOMPARE(textLabel(&stepWidget)->text(), QString("First step")); + QCOMPARE(textWidget(&stepWidget)->toPlainText(), QString("First step")); QCOMPARE(stepWidget.mOptionsLayout->count(), 1); KPushButton* button1 = qobject_cast<KPushButton*>( stepWidget.mOptionsLayout->itemAt(0)->widget()); @@ -123,7 +124,7 @@ stepWidget.setStep(&step1); - QCOMPARE(textLabel(&stepWidget)->text(), QString("First step")); + QCOMPARE(textWidget(&stepWidget)->toPlainText(), QString("First step")); QCOMPARE(stepWidget.mOptionsLayout->count(), 1); KPushButton* button = qobject_cast<KPushButton*>( stepWidget.mOptionsLayout->itemAt(0)->widget()); @@ -138,7 +139,7 @@ stepWidget.setStep(&step2); - QCOMPARE(textLabel(&stepWidget)->text(), QString("Second step")); + QCOMPARE(textWidget(&stepWidget)->toPlainText(), QString("Second step")); QCOMPARE(stepWidget.mOptionsLayout->count(), 2); button = qobject_cast<KPushButton*>( stepWidget.mOptionsLayout->itemAt(0)->widget()); @@ -155,7 +156,7 @@ stepWidget.setStep(&step3); - QCOMPARE(textLabel(&stepWidget)->text(), QString("Third step")); + QCOMPARE(textWidget(&stepWidget)->toPlainText(), QString("Third step")); QCOMPARE(stepWidget.mOptionsLayout->count(), 0); QVERIFY(stepWidget.isVisible()); } @@ -169,7 +170,7 @@ stepWidget.setStep(&step); - QCOMPARE(textLabel(&stepWidget)->text(), QString("First step")); + QCOMPARE(textWidget(&stepWidget)->toPlainText(), QString("First step")); QCOMPARE(stepWidget.mOptionsLayout->count(), 1); KPushButton* button1 = qobject_cast<KPushButton*>( stepWidget.mOptionsLayout->itemAt(0)->widget()); @@ -312,8 +313,8 @@ /////////////////////////////////// Helpers //////////////////////////////////// -QLabel* StepWidgetTest::textLabel(StepWidget* stepWidget) { - return stepWidget->ui->textLabel; +StepTextWidget* StepWidgetTest::textWidget(StepWidget* stepWidget) { + return stepWidget->ui->textWidget; } KPushButton* StepWidgetTest::closeButton(StepWidget* stepWidget) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-04-26 07:08:12
|
Revision: 237 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=237&view=rev Author: danxuliu Date: 2010-04-26 05:30:40 +0000 (Mon, 26 Apr 2010) Log Message: ----------- Increase required Qt version, as QEvent::staticMetaObject and QScopedPointer were introduced in Qt 4.6. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/CMakeLists.txt trunk/ktutorial/ktutorial-library/CMakeLists.txt Modified: trunk/ktutorial/ktutorial-editor/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/CMakeLists.txt 2010-04-26 05:24:17 UTC (rev 236) +++ trunk/ktutorial/ktutorial-editor/CMakeLists.txt 2010-04-26 05:30:40 UTC (rev 237) @@ -1,5 +1,6 @@ project(ktutorial-editor) +set(QT_MIN_VERSION "4.6") find_package(KDE4 REQUIRED) include(KDE4Defaults) Modified: trunk/ktutorial/ktutorial-library/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-library/CMakeLists.txt 2010-04-26 05:24:17 UTC (rev 236) +++ trunk/ktutorial/ktutorial-library/CMakeLists.txt 2010-04-26 05:30:40 UTC (rev 237) @@ -1,6 +1,6 @@ project(ktutorial-library) -set(QT_MIN_VERSION "4.5.3") +set(QT_MIN_VERSION "4.6") find_package(KDE4 REQUIRED) enable_testing() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-04-26 07:08:06
|
Revision: 236 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=236&view=rev Author: danxuliu Date: 2010-04-26 05:24:17 +0000 (Mon, 26 Apr 2010) Log Message: ----------- Add completion for event names in WaitForEventWidget. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.h trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForEventWidgetTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.cpp 2010-04-25 23:15:13 UTC (rev 235) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.cpp 2010-04-26 05:24:17 UTC (rev 236) @@ -18,6 +18,8 @@ #include "WaitForEventWidget.h" +#include <QMetaEnum> + #include "ui_WaitForEventWidget.h" #include "../data/WaitForEvent.h" @@ -47,6 +49,8 @@ ui->receiverNameLineEdit->setText(waitForEvent->receiverName()); ui->eventNameLineEdit->setText(waitForEvent->eventName()); + + addItemsToEventNameCompletion(); } WaitForEventWidget::~WaitForEventWidget() { @@ -65,6 +69,18 @@ } } +//private: + +void WaitForEventWidget::addItemsToEventNameCompletion() { + int index = QEvent::staticMetaObject.indexOfEnumerator("Type"); + QMetaEnum eventTypeEnumerator = QEvent::staticMetaObject.enumerator(index); + + KCompletion* completion = ui->eventNameLineEdit->completionObject(); + for (int i=0; i<eventTypeEnumerator.keyCount(); ++i) { + completion->addItem(eventTypeEnumerator.key(i)); + } +} + //private slots: #ifdef QT_QTDBUS_FOUND Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.h 2010-04-25 23:15:13 UTC (rev 235) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.h 2010-04-26 05:24:17 UTC (rev 236) @@ -66,6 +66,12 @@ */ Ui::WaitForEventWidget* ui; + /** + * Adds all the event names to the completion object of the event name line + * edit. + */ + void addItemsToEventNameCompletion(); + private Q_SLOTS: #ifdef QT_QTDBUS_FOUND Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForEventWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForEventWidgetTest.cpp 2010-04-25 23:15:13 UTC (rev 235) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForEventWidgetTest.cpp 2010-04-26 05:24:17 UTC (rev 236) @@ -33,6 +33,8 @@ void testSaveChanges(); + void testEventNameCompletion(); + private: KLineEdit* receiverNameLineEdit(WaitForEventWidget* widget) const; @@ -69,6 +71,16 @@ QCOMPARE(waitFor.eventName(), QString("The new event name")); } +void WaitForEventWidgetTest::testEventNameCompletion() { + WaitForEvent waitFor; + + WaitForEventWidget widget(&waitFor); + + KCompletion* completion = eventNameLineEdit(&widget)->completionObject(); + QCOMPARE(completion->allMatches("Dest").count(), 1); + QCOMPARE(completion->allMatches("Dest")[0], QString("Destroy")); +} + /////////////////////////////////// Helpers //////////////////////////////////// KLineEdit* WaitForEventWidgetTest::receiverNameLineEdit( This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-04-25 23:15:19
|
Revision: 235 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=235&view=rev Author: danxuliu Date: 2010-04-25 23:15:13 +0000 (Sun, 25 Apr 2010) Log Message: ----------- Make destructors virtual. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/FileActions.h trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObjectMapper.h Modified: trunk/ktutorial/ktutorial-editor/src/FileActions.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/FileActions.h 2010-04-25 23:10:44 UTC (rev 234) +++ trunk/ktutorial/ktutorial-editor/src/FileActions.h 2010-04-25 23:15:13 UTC (rev 235) @@ -63,7 +63,7 @@ * Destroys this FileActions. * The entries in the recent files action are saved in the configuration. */ - ~FileActions(); + virtual ~FileActions(); /** * Returns the tutorial URL. Modified: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObjectMapper.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObjectMapper.h 2010-04-25 23:10:44 UTC (rev 234) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObjectMapper.h 2010-04-25 23:15:13 UTC (rev 235) @@ -48,7 +48,7 @@ * Destroys this RemoteObjectMapper. * All the mapped RemoteObjects and RemoteClasses are also destroyed. */ - ~RemoteObjectMapper(); + virtual ~RemoteObjectMapper(); /** * Returns the RemoteObject associated with the given object id. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-04-25 23:10:51
|
Revision: 234 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=234&view=rev Author: danxuliu Date: 2010-04-25 23:10:44 +0000 (Sun, 25 Apr 2010) Log Message: ----------- -Add RemoteClass to act as a proxy for class information provided by the target application. -Provide completion in the signal line edit in WaitForSignalWidget with the signals of the chosen RemoteObject. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/targetapplication/CMakeLists.txt trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObject.cpp trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObject.h trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObjectMapper.cpp trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObjectMapper.h trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeItem.cpp trunk/ktutorial/ktutorial-editor/src/view/WaitForSignalWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/WaitForSignalWidget.h trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/CMakeLists.txt trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassStubs.h trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteEditorSupportTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteEventSpyTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteObjectMapperTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteObjectTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/TargetApplicationStub.cpp Added Paths: ----------- trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteClass.cpp trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteClass.h trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/targetapplication/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/CMakeLists.txt 2010-04-25 23:01:54 UTC (rev 233) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/CMakeLists.txt 2010-04-25 23:10:44 UTC (rev 234) @@ -1,5 +1,6 @@ set(ktutorial_editor_targetapplication_SRCS DBusException.cpp + RemoteClass.cpp RemoteEditorSupport.cpp RemoteEventSpy.cpp RemoteObject.cpp Added: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteClass.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteClass.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteClass.cpp 2010-04-25 23:10:44 UTC (rev 234) @@ -0,0 +1,60 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "RemoteClass.h" + +#include <QtDBus/QtDBus> + +#include "RemoteObjectMapper.h" + +//public: + +RemoteClass::RemoteClass(const QString& service, RemoteObjectMapper* mapper, + const QString& className): + QDBusAbstractInterface(service, "/ktutorial/ObjectRegister", + "org.kde.ktutorial.ClassRegister", + QDBusConnection::sessionBus(), 0), + mMapper(mapper), + mClassName(className) { +} + +QString RemoteClass::className() const { + return mClassName; +} + +RemoteClass* RemoteClass::superClass() throw (DBusException) { + QDBusReply<QString> reply = call("superClass", mClassName); + if (!reply.isValid()) { + throw DBusException(reply.error().message()); + } + + if (reply.value().isEmpty()) { + return 0; + } + + return mMapper->remoteClass(reply.value()); +} + +QStringList RemoteClass::signalList() throw (DBusException) { + QDBusReply<QStringList> reply = call("signalList", mClassName); + if (!reply.isValid()) { + throw DBusException(reply.error().message()); + } + + return reply.value(); +} Property changes on: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteClass.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteClass.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteClass.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteClass.h 2010-04-25 23:10:44 UTC (rev 234) @@ -0,0 +1,99 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef REMOTECLASS_H +#define REMOTECLASS_H + +#include <QDBusAbstractInterface> + +#include "DBusException.h" + +class RemoteObjectMapper; + +/** + * Proxy for remote classes exposed by KTutorial editor support module in + * KTutorial library. + * RemoteClass represents a remote class exposed by ObjectRegister in KTutorial + * library through DBus. Its purpose is provide an API to use the remote + * class/QMetaObject like any other local object, hiding the DBus complexity + * behind it. + * + * To get the data, RemoteClass makes DBus calls to the + * "org.kde.ktutorial.ClassRegistry" interface in the DBus service specified in + * the constructor. + * + * Although the idea is let other objects use it like a local object, it has to + * communicate with the remote ObjectRegistry through DBus anyway, so the + * methods may throw a DBusException if something goes wrong. + */ +class RemoteClass: public QDBusAbstractInterface { +Q_OBJECT +public: + + /** + * Creates a new RemoteClass to represent the remote class with the given + * class name in the given DBus service name. + * + * @param service The DBus service name. + * @param mapper The RemoteObjectMapper to get RemoteClasses from. + * @param className The name of the remote class. + */ + RemoteClass(const QString& service, RemoteObjectMapper* mapper, + const QString& className); + + /** + * Returns the class name. + * + * @return The class name. + */ + QString className() const; + + /** + * Returns the remote super class. + * If it has no super class, a null pointer is returned. + * + * @return The remote super class. + * @throws DBusException If a DBus error happens. + */ + RemoteClass* superClass() throw (DBusException); + + /** + * Returns a list with the signals defined in the remote class. + * The list only includes the signals from the class itself, but not its + * super classes. + * + * @return The signals. + * @throws DBusException If a DBus error happens. + */ + QStringList signalList() throw (DBusException); + +private: + + /** + * The mapper that associates a RemoteClass with its name. + */ + RemoteObjectMapper* mMapper; + + /** + * The name of the remote class. + */ + QString mClassName; + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteClass.h ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObject.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObject.cpp 2010-04-25 23:01:54 UTC (rev 233) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObject.cpp 2010-04-25 23:10:44 UTC (rev 234) @@ -46,13 +46,13 @@ return reply.value(); } -QString RemoteObject::className() throw (DBusException) { +RemoteClass* RemoteObject::remoteClass() throw (DBusException) { QDBusReply<QString> reply = call("className", mObjectId); if (!reply.isValid()) { throw DBusException(reply.error().message()); } - return reply.value(); + return mMapper->remoteClass(reply.value()); } Q_DECLARE_METATYPE(QList<int>) Modified: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObject.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObject.h 2010-04-25 23:01:54 UTC (rev 233) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObject.h 2010-04-25 23:10:44 UTC (rev 234) @@ -23,6 +23,7 @@ #include "DBusException.h" +class RemoteClass; class RemoteObjectMapper; /** @@ -72,12 +73,12 @@ QString name() throw (DBusException); /** - * Returns the class name. + * Returns the remote class. * - * @return The class name. + * @return The remote class. * @throws DBusException If a DBus error happens. */ - QString className() throw (DBusException); + RemoteClass* remoteClass() throw (DBusException); /** * Returns a list with the RemoteObjects that represent the children of this Modified: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObjectMapper.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObjectMapper.cpp 2010-04-25 23:01:54 UTC (rev 233) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObjectMapper.cpp 2010-04-25 23:10:44 UTC (rev 234) @@ -20,6 +20,7 @@ #include <QHash> +#include "RemoteClass.h" #include "RemoteObject.h" //public: @@ -30,6 +31,7 @@ RemoteObjectMapper::~RemoteObjectMapper() { qDeleteAll(mRemoteObjects); + qDeleteAll(mRemoteClasses); } RemoteObject* RemoteObjectMapper::remoteObject(int objectId) { @@ -43,7 +45,21 @@ return remoteObject; } +RemoteClass* RemoteObjectMapper::remoteClass(const QString& className) { + if (mRemoteClasses.contains(className)) { + return mRemoteClasses.value(className); + } + + RemoteClass* remoteClass = new RemoteClass(mService, this, className); + mRemoteClasses.insert(className, remoteClass); + + return remoteClass; +} + void RemoteObjectMapper::clear() { qDeleteAll(mRemoteObjects); mRemoteObjects.clear(); + + qDeleteAll(mRemoteClasses); + mRemoteClasses.clear(); } Modified: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObjectMapper.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObjectMapper.h 2010-04-25 23:01:54 UTC (rev 233) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObjectMapper.h 2010-04-25 23:10:44 UTC (rev 234) @@ -21,17 +21,18 @@ #include <QHash> +class RemoteClass; class RemoteObject; /** - * Map to get a RemoteObject from their objectId. - * The RemoteObjectMapper should be used to get all the RemoteObjects for its - * DBus service. It creates a new RemoteObject when there is no RemoteObject - * for the given id, or returns the previosly created one, depending on the - * case. + * Map to get RemoteObjects and RemoteClasses from their objectId or class name. + * The RemoteObjectMapper should be used to get all the RemoteObjects and + * RemoteClasses for its DBus service. It creates a new RemoteObject when there + * is no RemoteObject for the given id, or returns the previosly created one, + * depending on the case. The same behavior is shown for RemoteClasses. * - * The RemoteObjectMapper also has ownership of the RemoteObjects, so they are - * deleted when the mapper is cleared or destroyed. + * The RemoteObjectMapper also has ownership of the RemoteObjects and + * RemoteClasses, so they are deleted when the mapper is cleared or destroyed. */ class RemoteObjectMapper { public: @@ -39,13 +40,13 @@ /** * Creates a new RemoteObjectMapper for the given DBus service name. * - * @param service The DBus service name of the remote objects. + * @param service The DBus service name of the remote objects and classes. */ RemoteObjectMapper(const QString& service); /** * Destroys this RemoteObjectMapper. - * All the mapped RemoteObjects are also destroyed. + * All the mapped RemoteObjects and RemoteClasses are also destroyed. */ ~RemoteObjectMapper(); @@ -60,8 +61,18 @@ RemoteObject* remoteObject(int objectId); /** - * Destroys all the mapped RemoteObject. + * Returns the RemoteClass associated with the given class name. + * The RemoteClass is destroyed when this RemoteObjectMapper is cleared or + * destroyed, so consider using QPointer to store it. + * + * @param className The name of the remote class. + * @return The RemoteClass. */ + RemoteClass* remoteClass(const QString& className); + + /** + * Destroys all the mapped RemoteObjects and RemoteClasses. + */ void clear(); private: @@ -77,6 +88,12 @@ */ QHash<int, RemoteObject*> mRemoteObjects; + /** + * All the RemoteClasses already requested since the last time this + * RemoteObjectMapper was cleared. + */ + QHash<QString, RemoteClass*> mRemoteClasses; + }; #endif Modified: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeItem.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeItem.cpp 2010-04-25 23:01:54 UTC (rev 233) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeItem.cpp 2010-04-25 23:10:44 UTC (rev 234) @@ -22,6 +22,7 @@ #include <KLocalizedString> #include "RemoteObjectTreeItemUpdater.h" +#include "../targetapplication/RemoteClass.h" #include "../targetapplication/RemoteObject.h" //public: @@ -35,7 +36,7 @@ try { mName = remoteObject->name(); - mClassName = remoteObject->className(); + mClassName = remoteObject->remoteClass()->className(); } catch (DBusException e) { mName = i18nc("@item", "D-Bus Error!"); mClassName = i18nc("@item", "D-Bus Error!"); Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForSignalWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForSignalWidget.cpp 2010-04-25 23:01:54 UTC (rev 233) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForSignalWidget.cpp 2010-04-25 23:10:44 UTC (rev 234) @@ -25,6 +25,7 @@ #include <KMessageBox> #include "RemoteObjectChooser.h" +#include "../targetapplication/RemoteClass.h" #include "../targetapplication/RemoteObject.h" #endif @@ -67,6 +68,24 @@ } } +//private: + +#ifdef QT_QTDBUS_FOUND +void WaitForSignalWidget::setSignalCompletion(RemoteClass* remoteClass) { + KCompletion* completion = ui->signalNameLineEdit->completionObject(); + completion->clear(); + completion->setOrder(KCompletion::Sorted); + + while (remoteClass) { + foreach (QString signal, remoteClass->signalList()) { + completion->addItem(signal); + } + + remoteClass = remoteClass->superClass(); + } +} +#endif + //private slots: #ifdef QT_QTDBUS_FOUND @@ -81,6 +100,7 @@ void WaitForSignalWidget::setChosenRemoteObject(RemoteObject* remoteObject) { try { ui->emitterNameLineEdit->setText(remoteObject->name()); + setSignalCompletion(remoteObject->remoteClass()); } catch (DBusException e) { QString text = i18nc("@label", "The emitter name can not be set, there " "was a problem getting the name from the target application: %1", e.message()); Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForSignalWidget.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForSignalWidget.h 2010-04-25 23:01:54 UTC (rev 233) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForSignalWidget.h 2010-04-25 23:10:44 UTC (rev 234) @@ -21,6 +21,7 @@ #include "EditionWidget.h" +class RemoteClass; class RemoteObject; class WaitForSignal; @@ -66,6 +67,16 @@ */ Ui::WaitForSignalWidget* ui; +#ifdef QT_QTDBUS_FOUND + /** + * Sets the completion of the signal line edit to the signals emitted by the + * given remote class and its super classes. + * + * @param remoteClass The class to get its signal list. + */ + void setSignalCompletion(RemoteClass* remoteClass); +#endif + private Q_SLOTS: #ifdef QT_QTDBUS_FOUND Modified: trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/CMakeLists.txt 2010-04-25 23:01:54 UTC (rev 233) +++ trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/CMakeLists.txt 2010-04-25 23:10:44 UTC (rev 234) @@ -24,6 +24,7 @@ unit_tests( DBusException + RemoteClass RemoteEditorSupport RemoteEventSpy RemoteObject @@ -39,6 +40,7 @@ mem_tests( DBusException + RemoteClass RemoteEditorSupport RemoteEventSpy RemoteObject Modified: trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassStubs.h =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassStubs.h 2010-04-25 23:01:54 UTC (rev 233) +++ trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassStubs.h 2010-04-25 23:10:44 UTC (rev 234) @@ -41,16 +41,45 @@ }; -class StubObjectRegister: public QObject { +class StubClassRegisterAdaptor: public QDBusAbstractAdaptor { Q_OBJECT +Q_CLASSINFO("D-Bus Interface", "org.kde.ktutorial.ClassRegister") +public: + + StubClassRegisterAdaptor(QObject* parent): QDBusAbstractAdaptor(parent) { + } + +public slots: + + QString superClass(const QString& className) { + if (className.startsWith("Child")) { + return className.mid(QString("Child").count()); + } + + return ""; + } + + QStringList signalList(const QString& className) { + QStringList signalList; + for (int i=0; i<3; ++i) { + signalList.append(className + "Signal" + QString::number(i) + "()"); + } + + return signalList; + } +}; + +class StubObjectRegisterAdaptor: public QDBusAbstractAdaptor { +Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.ktutorial.ObjectRegister") public: - StubObjectRegister(QObject* parent = 0): QObject(parent) { + StubObjectRegisterAdaptor(QObject* parent): QDBusAbstractAdaptor(parent) { } public slots: + QString objectName(int objectId) { if (objectId > 100) { return ""; @@ -78,7 +107,19 @@ } return ids; } +}; +//Only one Q_CLASSINFO("D-Bus Interface", "whatever") is supported in +//each class, so adaptors have to be used to represent several interfaces +class StubObjectRegister: public QObject { +Q_OBJECT +public: + + StubObjectRegister(QObject* parent = 0): QObject(parent) { + new StubClassRegisterAdaptor(this); + new StubObjectRegisterAdaptor(this); + } + }; class StubEditorSupport: public QObject { Added: trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassTest.cpp 2010-04-25 23:10:44 UTC (rev 234) @@ -0,0 +1,123 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include <QtTest> + +#include "RemoteClass.h" + +#include <QtDBus/QtDBus> + +#include "RemoteClassStubs.h" +#include "RemoteObjectMapper.h" + +#define EXPECT_EXCEPTION(statement, exception) \ +do {\ + try {\ + statement;\ + QFAIL("Expected " #exception " not thrown");\ + } catch (exception e) {\ + } catch (Exception e) {\ + QFAIL("Expected " #exception " not thrown");\ + }\ +} while (0) + +class RemoteClassTest: public QObject { +Q_OBJECT + +private slots: + + void init(); + void cleanup(); + + void testClassName(); + + void testSuperClass(); + void testSuperClassWhenRemoteClassIsNotAvailable(); + + void testSignalList(); + void testSignalListWhenRemoteClassIsNotAvailable(); + +private: + + StubObjectRegister* mObjectRegister; + + QString mService; + RemoteObjectMapper* mMapper; + +}; + +void RemoteClassTest::init() { + QVERIFY(QDBusConnection::sessionBus().isConnected()); + + mObjectRegister = new StubObjectRegister(); + QDBusConnection::sessionBus().registerObject("/ktutorial/ObjectRegister", + mObjectRegister, QDBusConnection::ExportAdaptors); + + mService = QDBusConnection::sessionBus().baseService(); + mMapper = new RemoteObjectMapper(mService); +} + +void RemoteClassTest::cleanup() { + delete mMapper; + + QDBusConnection::sessionBus().unregisterObject("/ktutorial/ObjectRegister"); + delete mObjectRegister; +} + +void RemoteClassTest::testClassName() { + RemoteClass remoteClass(mService, mMapper, "The class name"); + + QCOMPARE(remoteClass.className(), QString("The class name")); +} + +void RemoteClassTest::testSuperClass() { + RemoteClass remoteClass(mService, mMapper, "ChildClass"); + + QCOMPARE(remoteClass.superClass()->className(), QString("Class")); + QCOMPARE(remoteClass.superClass()->superClass(), (RemoteClass*)0); +} + +void RemoteClassTest::testSuperClassWhenRemoteClassIsNotAvailable() { + RemoteClass remoteClass(mService, mMapper, "Class"); + + QDBusConnection::sessionBus().unregisterObject("/ktutorial/ObjectRegister"); + + EXPECT_EXCEPTION(remoteClass.superClass(), DBusException); +} + +void RemoteClassTest::testSignalList() { + RemoteClass remoteClass(mService, mMapper, "Class"); + + QStringList signalList = remoteClass.signalList(); + QCOMPARE(signalList.count(), 3); + QCOMPARE(signalList[0], QString("ClassSignal0()")); + QCOMPARE(signalList[1], QString("ClassSignal1()")); + QCOMPARE(signalList[2], QString("ClassSignal2()")); +} + +void RemoteClassTest::testSignalListWhenRemoteClassIsNotAvailable() { + RemoteClass remoteClass(mService, mMapper, "Class"); + + QDBusConnection::sessionBus().unregisterObject("/ktutorial/ObjectRegister"); + + EXPECT_EXCEPTION(remoteClass.signalList(), DBusException); +} + +QTEST_MAIN(RemoteClassTest) + +#include "RemoteClassTest.moc" Property changes on: trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassTest.cpp ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteEditorSupportTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteEditorSupportTest.cpp 2010-04-25 23:01:54 UTC (rev 233) +++ trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteEditorSupportTest.cpp 2010-04-25 23:10:44 UTC (rev 234) @@ -80,7 +80,7 @@ mObjectRegister = new StubObjectRegister(); QDBusConnection::sessionBus().registerObject("/ktutorial/ObjectRegister", - mObjectRegister, QDBusConnection::ExportAllSlots); + mObjectRegister, QDBusConnection::ExportAdaptors); } void RemoteEditorSupportTest::cleanup() { Modified: trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteEventSpyTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteEventSpyTest.cpp 2010-04-25 23:01:54 UTC (rev 233) +++ trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteEventSpyTest.cpp 2010-04-25 23:10:44 UTC (rev 234) @@ -52,7 +52,7 @@ mObjectRegister = new StubObjectRegister(); QDBusConnection::sessionBus().registerObject("/ktutorial/ObjectRegister", - mObjectRegister, QDBusConnection::ExportAllSlots); + mObjectRegister, QDBusConnection::ExportAdaptors); } void RemoteEventSpyTest::cleanup() { Modified: trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteObjectMapperTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteObjectMapperTest.cpp 2010-04-25 23:01:54 UTC (rev 233) +++ trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteObjectMapperTest.cpp 2010-04-25 23:10:44 UTC (rev 234) @@ -22,6 +22,7 @@ #include <QtDBus/QtDBus> +#include "RemoteClass.h" #include "RemoteClassStubs.h" #include "RemoteObject.h" @@ -37,6 +38,10 @@ void testRemoteObjectSeveralIds(); void testRemoteObjectTwice(); + void testRemoteClass(); + void testRemoteClassSeveralIds(); + void testRemoteClassTwice(); + void testClear(); private: @@ -49,7 +54,7 @@ mObjectRegister = new StubObjectRegister(); QDBusConnection::sessionBus().registerObject("/ktutorial/ObjectRegister", - mObjectRegister, QDBusConnection::ExportAllSlots); + mObjectRegister, QDBusConnection::ExportAdaptors); } void RemoteObjectMapperTest::cleanup() { @@ -96,20 +101,60 @@ QCOMPARE(remoteObject1->name(), QString("The object name 42")); } +void RemoteObjectMapperTest::testRemoteClass() { + RemoteObjectMapper mapper(QDBusConnection::sessionBus().baseService()); + + RemoteClass* remoteClass = mapper.remoteClass("Class"); + + QVERIFY(remoteClass); + QCOMPARE(remoteClass->className(), QString("Class")); +} + +void RemoteObjectMapperTest::testRemoteClassSeveralIds() { + RemoteObjectMapper mapper(QDBusConnection::sessionBus().baseService()); + + RemoteClass* remoteClass1 = mapper.remoteClass("Class1"); + RemoteClass* remoteClass2 = mapper.remoteClass("Class2"); + RemoteClass* remoteClass3 = mapper.remoteClass("Class3"); + + QVERIFY(remoteClass1); + QVERIFY(remoteClass2); + QVERIFY(remoteClass3); + QVERIFY(remoteClass1 != remoteClass2); + QVERIFY(remoteClass1 != remoteClass3); + QVERIFY(remoteClass2 != remoteClass3); + QCOMPARE(remoteClass1->className(), QString("Class1")); + QCOMPARE(remoteClass2->className(), QString("Class2")); + QCOMPARE(remoteClass3->className(), QString("Class3")); +} + +void RemoteObjectMapperTest::testRemoteClassTwice() { + RemoteObjectMapper mapper(QDBusConnection::sessionBus().baseService()); + + RemoteClass* remoteClass1 = mapper.remoteClass("Class"); + RemoteClass* remoteClass2 = mapper.remoteClass("Class"); + + QVERIFY(remoteClass1); + QVERIFY(remoteClass2); + QVERIFY(remoteClass1 == remoteClass2); + QCOMPARE(remoteClass1->className(), QString("Class")); +} + void RemoteObjectMapperTest::testClear() { RemoteObjectMapper mapper(QDBusConnection::sessionBus().baseService()); - RemoteObject* remoteObject1 = mapper.remoteObject(42); + QPointer<RemoteObject> remoteObject1 = mapper.remoteObject(42); + QPointer<RemoteClass> remoteClass1 = mapper.remoteClass("Class"); mapper.clear(); RemoteObject* remoteObject2 = mapper.remoteObject(42); + RemoteClass* remoteClass2 = mapper.remoteClass("Class"); - QVERIFY(remoteObject1); + QVERIFY(!remoteObject1); QVERIFY(remoteObject2); - QVERIFY(remoteObject1 != remoteObject2); - //remoteObject1 values can not be checked, as it was destroyed when the - //mapper was cleared + QVERIFY(!remoteClass1); + QVERIFY(remoteClass2); } QTEST_MAIN(RemoteObjectMapperTest) Modified: trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteObjectTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteObjectTest.cpp 2010-04-25 23:01:54 UTC (rev 233) +++ trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteObjectTest.cpp 2010-04-25 23:10:44 UTC (rev 234) @@ -22,6 +22,7 @@ #include <QtDBus/QtDBus> +#include "RemoteClass.h" #include "RemoteClassStubs.h" #include "RemoteObjectMapper.h" @@ -49,8 +50,8 @@ void testName(); void testNameWhenRemoteObjectIsNotAvailable(); - void testClassName(); - void testClassNameWhenRemoteObjectIsNotAvailable(); + void testRemoteClass(); + void testRemoteClassWhenRemoteObjectIsNotAvailable(); void testChildren(); void testChildrenWhenRemoteObjectIsNotAvailable(); @@ -69,7 +70,7 @@ mObjectRegister = new StubObjectRegister(); QDBusConnection::sessionBus().registerObject("/ktutorial/ObjectRegister", - mObjectRegister, QDBusConnection::ExportAllSlots); + mObjectRegister, QDBusConnection::ExportAdaptors); mService = QDBusConnection::sessionBus().baseService(); mMapper = new RemoteObjectMapper(mService); @@ -102,18 +103,19 @@ EXPECT_EXCEPTION(remoteObject.name(), DBusException); } -void RemoteObjectTest::testClassName() { +void RemoteObjectTest::testRemoteClass() { RemoteObject remoteObject(mService, mMapper, 42); - QCOMPARE(remoteObject.className(), QString("The class name 42")); + QCOMPARE(remoteObject.remoteClass()->className(), + QString("The class name 42")); } -void RemoteObjectTest::testClassNameWhenRemoteObjectIsNotAvailable() { +void RemoteObjectTest::testRemoteClassWhenRemoteObjectIsNotAvailable() { RemoteObject remoteObject(mService, mMapper, 42); QDBusConnection::sessionBus().unregisterObject("/ktutorial/ObjectRegister"); - EXPECT_EXCEPTION(remoteObject.className(), DBusException); + EXPECT_EXCEPTION(remoteObject.remoteClass(), DBusException); } void RemoteObjectTest::testChildren() { Modified: trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/TargetApplicationStub.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/TargetApplicationStub.cpp 2010-04-25 23:01:54 UTC (rev 233) +++ trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/TargetApplicationStub.cpp 2010-04-25 23:10:44 UTC (rev 234) @@ -36,7 +36,7 @@ StubObjectRegister* objectRegister = new StubObjectRegister(); QDBusConnection::sessionBus().registerObject("/ktutorial/ObjectRegister", - objectRegister, QDBusConnection::ExportAllSlots); + objectRegister, QDBusConnection::ExportAdaptors); return app.exec(); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-04-25 23:02:01
|
Revision: 233 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=233&view=rev Author: danxuliu Date: 2010-04-25 23:01:54 +0000 (Sun, 25 Apr 2010) Log Message: ----------- Provide more information about classes in editor support module, so the superclass or the signal list of a class can be fetched by the editor. Modified Paths: -------------- trunk/ktutorial/ktutorial-library/src/editorsupport/CMakeLists.txt trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupport.cpp trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupport.h trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.cpp trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.h trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegisterAdaptor.h trunk/ktutorial/ktutorial-library/tests/editorsupport/CMakeLists.txt trunk/ktutorial/ktutorial-library/tests/editorsupport/EditorSupportTest.cpp trunk/ktutorial/ktutorial-library/tests/editorsupport/ObjectRegisterTest.cpp Added Paths: ----------- trunk/ktutorial/ktutorial-library/src/editorsupport/ClassRegisterAdaptor.cpp trunk/ktutorial/ktutorial-library/src/editorsupport/ClassRegisterAdaptor.h trunk/ktutorial/ktutorial-library/tests/editorsupport/ClassRegisterAdaptorTest.cpp Modified: trunk/ktutorial/ktutorial-library/src/editorsupport/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/CMakeLists.txt 2010-04-14 01:14:27 UTC (rev 232) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/CMakeLists.txt 2010-04-25 23:01:54 UTC (rev 233) @@ -1,6 +1,7 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR} ${KDE4_INCLUDES}) set(ktutorial_editorsupport_SRCS + ClassRegisterAdaptor.cpp EditorSupport.cpp EditorSupportAdaptor.cpp EventSpy.cpp Added: trunk/ktutorial/ktutorial-library/src/editorsupport/ClassRegisterAdaptor.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/ClassRegisterAdaptor.cpp (rev 0) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/ClassRegisterAdaptor.cpp 2010-04-25 23:01:54 UTC (rev 233) @@ -0,0 +1,85 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include <QMetaClassInfo> + +#include "ClassRegisterAdaptor.h" +#include "ObjectRegister.h" + +namespace editorsupport { + +//public: + +ClassRegisterAdaptor::ClassRegisterAdaptor(ObjectRegister* objectRegister): + QDBusAbstractAdaptor(objectRegister), + mObjectRegister(objectRegister) { +} + +//public slots: + +QString ClassRegisterAdaptor::superClass(const QString& className) const { + const QMetaObject* metaObject = + mObjectRegister->metaObjectForClassName(className); + if (!metaObject) { + return ""; + } + + if (!metaObject->superClass()) { + return ""; + } + + return metaObject->superClass()->className(); +} + +QStringList ClassRegisterAdaptor::signalList(const QString& className) const { + const QMetaObject* metaObject = + mObjectRegister->metaObjectForClassName(className); + if (!metaObject) { + return QStringList(); + } + + QStringList signalList; + for (int i=0; i<metaObject->methodCount(); ++i) { + QMetaMethod method = metaObject->method(i); + if (isSignalDefinedInClass(method, metaObject)) { + signalList.append(method.signature()); + } + } + + return signalList; +} + +//private: + +bool ClassRegisterAdaptor::isSignalDefinedInClass(const QMetaMethod& metaMethod, + const QMetaObject* metaObject) const { + if (metaMethod.methodType() != QMetaMethod::Signal) { + return false; + } + + const QMetaObject* superClass = metaObject; + while ((superClass = superClass->superClass())) { + if (superClass->indexOfSignal(metaMethod.signature()) != -1) { + return false; + } + } + + return true; +} + +} Property changes on: trunk/ktutorial/ktutorial-library/src/editorsupport/ClassRegisterAdaptor.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-library/src/editorsupport/ClassRegisterAdaptor.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/ClassRegisterAdaptor.h (rev 0) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/ClassRegisterAdaptor.h 2010-04-25 23:01:54 UTC (rev 233) @@ -0,0 +1,98 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef EDITORSUPPORT_CLASSREGISTERADAPTOR_H +#define EDITORSUPPORT_CLASSREGISTERADAPTOR_H + +#include <QDBusAbstractAdaptor> +#include <QStringList> + +namespace editorsupport { +class ObjectRegister; +} + +namespace editorsupport { + +/** + * Adaptor to expose an ObjectRegister through DBus. + * It provides methods to get information about the registered QMetaObjects. + * + * @see EditorSupport + */ +class ClassRegisterAdaptor: public QDBusAbstractAdaptor { +Q_OBJECT +Q_CLASSINFO("D-Bus Interface", "org.kde.ktutorial.ClassRegister") +public: + + /** + * Creates a new ClassRegisterAdaptor for the given ObjectRegister. + * + * @param objectRegister The ObjectRegister to adapt. + */ + explicit ClassRegisterAdaptor(ObjectRegister* objectRegister); + +public Q_SLOTS: + + /** + * Returns super class name of the class with the given name. + * If the class name is not registered, or it has no super class, an empty + * string is returned. + * + * @param className The name of the class. + * @return The name of the super class. + */ + QString superClass(const QString& className) const; + + /** + * Returns the signals of the class with the given name. + * If the class is not registered, an empty list is returned. + * + * Only the signals defined in the given class are included in the list. + * Signals from parent classes must be got using the parent class name. + * + * @param className The name of the class. + * @return The list of signals. + */ + QStringList signalList(const QString& className) const; + +private: + + /** + * The ObjectRegister to adapt. + */ + ObjectRegister* mObjectRegister; + + /** + * Checks whether the given meta method is a signal defined in the given + * meta object. + * If the signal is inherited in the given meta object instead of defined in + * it, false is also returned. + * + * @param metaMethod The meta method to check. + * @param metaObject The meta object to check the meta method with. + * @return True if the meta method is a signal defined in the meta object, + * false otherwise. + */ + bool isSignalDefinedInClass(const QMetaMethod& metaMethod, + const QMetaObject* metaObject) const; + +}; + +} + +#endif Property changes on: trunk/ktutorial/ktutorial-library/src/editorsupport/ClassRegisterAdaptor.h ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupport.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupport.cpp 2010-04-14 01:14:27 UTC (rev 232) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupport.cpp 2010-04-25 23:01:54 UTC (rev 233) @@ -22,6 +22,7 @@ #include <KDebug> #include "EditorSupport.h" +#include "ClassRegisterAdaptor.h" #include "EditorSupportAdaptor.h" #include "EventSpy.h" #include "EventSpyAdaptor.h" @@ -53,6 +54,7 @@ QDBusConnection::sessionBus().registerObject("/ktutorial", this); mObjectRegister = new ObjectRegister(this); + new ClassRegisterAdaptor(mObjectRegister); new ObjectRegisterAdaptor(mObjectRegister); QDBusConnection::sessionBus().registerObject("/ktutorial/ObjectRegister", Modified: trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupport.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupport.h 2010-04-14 01:14:27 UTC (rev 232) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupport.h 2010-04-25 23:01:54 UTC (rev 233) @@ -45,7 +45,9 @@ * The object register assigns an id to QObjects to be identified by the remote * KTutorial editor. Using that id, KTutorial editor can request further * information about an object to the ObjectRegister (for example, the object - * name or the class name of an object). + * name or the class name of an object). Moreover, the object register also + * provides information about the classes of the registered objects, like the + * super class or the list of signals defined in each class. * * The event spy filters all the events received by the main window and, * recursively, all its children objects. It is used in the remote KTutorial @@ -57,9 +59,10 @@ * The main object is registered at "/ktutorial" path, and provides the * "org.kde.ktutorial.EditorSupport" interface. The object register is * registered at "/ktutorial/ObjectRegister" path and provides the - * "org.kde.ktutorial.ObjectRegister" interface. Finally, when it is enabled, - * the EventSpy is registered at "/ktutorial/EVentSpy" path and provides the - * "org.kde.ktutorial.EventSpy" interface. + * "org.kde.ktutorial.ObjectRegister" and "org.kde.ktutorial.ClassRegister" + * interfaces. Finally, when it is enabled, the EventSpy is registered at + * "/ktutorial/EVentSpy" path and provides the "org.kde.ktutorial.EventSpy" + * interface. */ class EditorSupport: public QObject { Q_OBJECT Modified: trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.cpp 2010-04-14 01:14:27 UTC (rev 232) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.cpp 2010-04-25 23:01:54 UTC (rev 233) @@ -36,6 +36,8 @@ connect(object, SIGNAL(destroyed(QObject*)), this, SLOT(deregister(QObject*))); mNextId++; + + registerMetaObject(object->metaObject()); } return id; @@ -45,11 +47,31 @@ return mRegisteredObjects.value(objectId); } +const QMetaObject* ObjectRegister::metaObjectForClassName( + const QString& className) const { + return mRegisteredMetaObjects.value(className); +} + void ObjectRegister::clear() { mRegisteredIds.clear(); mRegisteredObjects.clear(); + mRegisteredMetaObjects.clear(); } +//private: + +void ObjectRegister::registerMetaObject(const QMetaObject* metaObject) { + if (mRegisteredMetaObjects.contains(metaObject->className())) { + return; + } + + mRegisteredMetaObjects.insert(metaObject->className(), metaObject); + + if (metaObject->superClass()) { + registerMetaObject(metaObject->superClass()); + } +} + //private slots: void ObjectRegister::deregister(QObject* object) { Modified: trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.h 2010-04-14 01:14:27 UTC (rev 232) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.h 2010-04-25 23:01:54 UTC (rev 233) @@ -31,6 +31,10 @@ * destroyed (if an object is destroyed it is automatically removed from the * register). * + * When an object is registered, its QMetaObject and the QMetaObject of all its + * super classes are also registered. The QMetaObject can be got using the class + * name since then until the register is cleared. + * * Its purpose is assign QObjects an id to allow the remote KTutorial editor to * refer to the objects in the target application. */ @@ -62,6 +66,14 @@ QObject* objectForId(int objectId); /** + * Returns the meta object with the given class name. + * + * @param className The class name to get its meta object. + * @return The meta object with the given class name. + */ + const QMetaObject* metaObjectForClassName(const QString& className) const; + + /** * Removes all the entries in this ObjectRegister. */ void clear(); @@ -83,6 +95,18 @@ */ QHash<int, QObject*> mRegisteredObjects; + /** + * The registered meta objects mapped by their class name. + */ + QHash<QString, const QMetaObject*> mRegisteredMetaObjects; + + /** + * Registers a meta object and the meta objects of all its super classes. + * + * @param metaObject The meta object to register. + */ + void registerMetaObject(const QMetaObject* metaObject); + private Q_SLOTS: /** Modified: trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegisterAdaptor.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegisterAdaptor.h 2010-04-14 01:14:27 UTC (rev 232) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegisterAdaptor.h 2010-04-25 23:01:54 UTC (rev 233) @@ -29,6 +29,7 @@ /** * Adaptor to expose an ObjectRegister through DBus. + * It provides methods to get information about the registered QObjects. * * @see EditorSupport */ Modified: trunk/ktutorial/ktutorial-library/tests/editorsupport/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-library/tests/editorsupport/CMakeLists.txt 2010-04-14 01:14:27 UTC (rev 232) +++ trunk/ktutorial/ktutorial-library/tests/editorsupport/CMakeLists.txt 2010-04-25 23:01:54 UTC (rev 233) @@ -17,6 +17,7 @@ ENDMACRO(UNIT_TESTS) unit_tests( + ClassRegisterAdaptor EditorSupport EditorSupportAdaptor EventSpy @@ -32,6 +33,7 @@ ENDMACRO(MEM_TESTS) mem_tests( + ClassRegisterAdaptor EditorSupport EditorSupportAdaptor EventSpy Added: trunk/ktutorial/ktutorial-library/tests/editorsupport/ClassRegisterAdaptorTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/editorsupport/ClassRegisterAdaptorTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-library/tests/editorsupport/ClassRegisterAdaptorTest.cpp 2010-04-25 23:01:54 UTC (rev 233) @@ -0,0 +1,96 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include <QtTest> + +#include "ClassRegisterAdaptor.h" +#include "ObjectRegister.h" + +namespace editorsupport { + +class ClassRegisterAdaptorTest: public QObject { +Q_OBJECT + +Q_SIGNALS: + + void dummySignal(); + void dummySignal(int argument1, const QString& argument2); + +private slots: + + void testConstructor(); + + void testSuperClass(); + void testSuperClassWithUnknownClassName(); + + void testSignalList(); + void testSignalListWithUnknownClassName(); + +}; + +void ClassRegisterAdaptorTest::testConstructor() { + ObjectRegister objectRegister; + ClassRegisterAdaptor* adaptor = new ClassRegisterAdaptor(&objectRegister); + + QCOMPARE(adaptor->parent(), &objectRegister); +} + +void ClassRegisterAdaptorTest::testSuperClass() { + ObjectRegister objectRegister; + ClassRegisterAdaptor* adaptor = new ClassRegisterAdaptor(&objectRegister); + + objectRegister.idForObject(this); + + QCOMPARE(adaptor->superClass("editorsupport::ClassRegisterAdaptorTest"), + QString("QObject")); + QCOMPARE(adaptor->superClass("QObject"), QString("")); +} + +void ClassRegisterAdaptorTest::testSuperClassWithUnknownClassName() { + ObjectRegister objectRegister; + ClassRegisterAdaptor* adaptor = new ClassRegisterAdaptor(&objectRegister); + + QCOMPARE(adaptor->superClass("UnknownClassName"), QString("")); +} + +void ClassRegisterAdaptorTest::testSignalList() { + ObjectRegister objectRegister; + ClassRegisterAdaptor* adaptor = new ClassRegisterAdaptor(&objectRegister); + + objectRegister.idForObject(this); + + QStringList signalList = + adaptor->signalList("editorsupport::ClassRegisterAdaptorTest"); + QCOMPARE(signalList.count(), 2); + QCOMPARE(signalList[0], QString("dummySignal()")); + QCOMPARE(signalList[1], QString("dummySignal(int,QString)")); +} + +void ClassRegisterAdaptorTest::testSignalListWithUnknownClassName() { + ObjectRegister objectRegister; + ClassRegisterAdaptor* adaptor = new ClassRegisterAdaptor(&objectRegister); + + QStringList signalList = adaptor->signalList("UnknownClassName"); + QCOMPARE(signalList.count(), 0); +} + +} + +QTEST_MAIN(editorsupport::ClassRegisterAdaptorTest) + +#include "ClassRegisterAdaptorTest.moc" Property changes on: trunk/ktutorial/ktutorial-library/tests/editorsupport/ClassRegisterAdaptorTest.cpp ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-library/tests/editorsupport/EditorSupportTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/editorsupport/EditorSupportTest.cpp 2010-04-14 01:14:27 UTC (rev 232) +++ trunk/ktutorial/ktutorial-library/tests/editorsupport/EditorSupportTest.cpp 2010-04-25 23:01:54 UTC (rev 233) @@ -27,8 +27,10 @@ #undef private #undef protected +#include "ClassRegisterAdaptor.h" #include "EventSpy.h" #include "ObjectRegister.h" +#include "ObjectRegisterAdaptor.h" #include "../extendedinformation/WidgetHighlighter.h" using extendedinformation::WidgetHighlighter; @@ -96,7 +98,11 @@ QObject* objectRegisterObject = bus.objectRegisteredAt("/ktutorial/ObjectRegister"); QVERIFY(objectRegisterObject); - QVERIFY(qobject_cast<ObjectRegister*>(objectRegisterObject)); + ObjectRegister* objectRegister = + qobject_cast<ObjectRegister*>(objectRegisterObject); + QVERIFY(objectRegister); + QVERIFY(objectRegister->findChild<ClassRegisterAdaptor*>("")); + QVERIFY(objectRegister->findChild<ObjectRegisterAdaptor*>("")); QVERIFY(!bus.objectRegisteredAt("/ktutorial/EventSpy")); } Modified: trunk/ktutorial/ktutorial-library/tests/editorsupport/ObjectRegisterTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/editorsupport/ObjectRegisterTest.cpp 2010-04-14 01:14:27 UTC (rev 232) +++ trunk/ktutorial/ktutorial-library/tests/editorsupport/ObjectRegisterTest.cpp 2010-04-25 23:01:54 UTC (rev 233) @@ -20,6 +20,18 @@ #include "ObjectRegister.h" +class DummyClass: public QObject { +Q_OBJECT +}; + +class DummyChildClass1: public DummyClass { +Q_OBJECT +}; + +class DummyChildClass2: public DummyClass { +Q_OBJECT +}; + namespace editorsupport { class ObjectRegisterTest: public QObject { @@ -48,17 +60,23 @@ void ObjectRegisterTest::testRegisterObject() { ObjectRegister objectRegister; - QObject object; + DummyChildClass1 object; int id = objectRegister.idForObject(&object); QCOMPARE(objectRegister.objectForId(id), &object); + QCOMPARE(objectRegister.metaObjectForClassName("DummyChildClass1"), + &DummyChildClass1::staticMetaObject); + QCOMPARE(objectRegister.metaObjectForClassName("DummyClass"), + &DummyClass::staticMetaObject); + QCOMPARE(objectRegister.metaObjectForClassName("QObject"), + &QObject::staticMetaObject); } void ObjectRegisterTest::testRegisterObjectSeveralObjects() { ObjectRegister objectRegister; - QObject object1; - QObject object2; + DummyChildClass1 object1; + DummyChildClass2 object2; QObject object3; int id1 = objectRegister.idForObject(&object1); @@ -71,6 +89,14 @@ QCOMPARE(objectRegister.objectForId(id1), &object1); QCOMPARE(objectRegister.objectForId(id2), &object2); QCOMPARE(objectRegister.objectForId(id3), &object3); + QCOMPARE(objectRegister.metaObjectForClassName("DummyChildClass1"), + &DummyChildClass1::staticMetaObject); + QCOMPARE(objectRegister.metaObjectForClassName("DummyChildClass2"), + &DummyChildClass2::staticMetaObject); + QCOMPARE(objectRegister.metaObjectForClassName("DummyClass"), + &DummyClass::staticMetaObject); + QCOMPARE(objectRegister.metaObjectForClassName("QObject"), + &QObject::staticMetaObject); } void ObjectRegisterTest::testRegisterObjectTwice() { @@ -82,6 +108,8 @@ QCOMPARE(id2, id1); QCOMPARE(objectRegister.objectForId(id1), &object); + QCOMPARE(objectRegister.metaObjectForClassName("QObject"), + &QObject::staticMetaObject); } void ObjectRegisterTest::testObjectForIdWithDestroyedObject() { @@ -93,6 +121,8 @@ delete object; QCOMPARE(objectRegister.objectForId(id), (QObject*)0); + QCOMPARE(objectRegister.metaObjectForClassName("QObject"), + &QObject::staticMetaObject); } void ObjectRegisterTest::testClear() { @@ -105,6 +135,7 @@ objectRegister.clear(); QCOMPARE(objectRegister.objectForId(id), (QObject*)0); + QCOMPARE(objectRegister.metaObjectForClassName("QObject"), (QMetaObject*)0); } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-04-14 01:14:33
|
Revision: 232 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=232&view=rev Author: danxuliu Date: 2010-04-14 01:14:27 +0000 (Wed, 14 Apr 2010) Log Message: ----------- Move Exception from root to "util" package to avoid serialization and targetapplication packages linking against the root library. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt trunk/ktutorial/ktutorial-editor/src/serialization/CMakeLists.txt trunk/ktutorial/ktutorial-editor/src/serialization/DeserializationException.h trunk/ktutorial/ktutorial-editor/src/serialization/IOException.h trunk/ktutorial/ktutorial-editor/src/targetapplication/CMakeLists.txt trunk/ktutorial/ktutorial-editor/src/targetapplication/DBusException.h trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt Added Paths: ----------- trunk/ktutorial/ktutorial-editor/src/util/ trunk/ktutorial/ktutorial-editor/src/util/CMakeLists.txt trunk/ktutorial/ktutorial-editor/src/util/Exception.cpp trunk/ktutorial/ktutorial-editor/src/util/Exception.h trunk/ktutorial/ktutorial-editor/tests/unit/util/ trunk/ktutorial/ktutorial-editor/tests/unit/util/CMakeLists.txt trunk/ktutorial/ktutorial-editor/tests/unit/util/ExceptionTest.cpp Removed Paths: ------------- trunk/ktutorial/ktutorial-editor/src/Exception.cpp trunk/ktutorial/ktutorial-editor/src/Exception.h trunk/ktutorial/ktutorial-editor/tests/unit/ExceptionTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt 2010-04-13 20:30:16 UTC (rev 231) +++ trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt 2010-04-14 01:14:27 UTC (rev 232) @@ -7,6 +7,7 @@ add_subdirectory(commands) add_subdirectory(data) add_subdirectory(serialization) +add_subdirectory(util) add_subdirectory(view) if (QT_QTDBUS_FOUND) @@ -16,7 +17,6 @@ set(ktutorial_editor_SRCS EditActions.cpp - Exception.cpp FileActions.cpp KTutorialEditor.cpp ) @@ -30,6 +30,7 @@ target_link_libraries(ktutorial_editor ktutorial_editor_data ktutorial_editor_serialization + ktutorial_editor_util ktutorial_editor_view ) Deleted: trunk/ktutorial/ktutorial-editor/src/Exception.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/Exception.cpp 2010-04-13 20:30:16 UTC (rev 231) +++ trunk/ktutorial/ktutorial-editor/src/Exception.cpp 2010-04-14 01:14:27 UTC (rev 232) @@ -1,36 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * - * dan...@gm... * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 3 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; If not, see <http://www.gnu.org/licenses/>. * - ***************************************************************************/ - -#include "Exception.h" - -//public: - -Exception::Exception(const QString& message): std::exception(), - mMessage(message) { -} - -Exception::~Exception() throw() { -} - -const char* Exception::what() const throw() { - return mMessage.toUtf8(); -} - -QString Exception::message() const throw() { - return mMessage; -} Deleted: trunk/ktutorial/ktutorial-editor/src/Exception.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/Exception.h 2010-04-13 20:30:16 UTC (rev 231) +++ trunk/ktutorial/ktutorial-editor/src/Exception.h 2010-04-14 01:14:27 UTC (rev 232) @@ -1,54 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * - * dan...@gm... * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 3 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; If not, see <http://www.gnu.org/licenses/>. * - ***************************************************************************/ - -#ifndef EXCEPTION_H -#define EXCEPTION_H - -#include <exception> -#include <QString> - -/** - * Base class for exceptions. - */ -class Exception: public std::exception { -public: - - explicit Exception(const QString& message = QString()); - virtual ~Exception() throw(); - - /** - * Returns the exception message. - * - * @return The exception message. - */ - virtual const char* what() const throw(); - - /** - * Returns the exception message. - * - * @return The exception message. - */ - QString message() const throw(); - -private: - - QString mMessage; - -}; - -#endif Modified: trunk/ktutorial/ktutorial-editor/src/serialization/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/CMakeLists.txt 2010-04-13 20:30:16 UTC (rev 231) +++ trunk/ktutorial/ktutorial-editor/src/serialization/CMakeLists.txt 2010-04-14 01:14:27 UTC (rev 232) @@ -9,4 +9,8 @@ kde4_add_library(ktutorial_editor_serialization ${ktutorial_editor_serialization_SRCS}) -target_link_libraries(ktutorial_editor_serialization ktutorial_editor ${KDE4_KIO_LIBS}) +target_link_libraries(ktutorial_editor_serialization + ktutorial_editor_data + ktutorial_editor_util + ${KDE4_KIO_LIBS} +) Modified: trunk/ktutorial/ktutorial-editor/src/serialization/DeserializationException.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/DeserializationException.h 2010-04-13 20:30:16 UTC (rev 231) +++ trunk/ktutorial/ktutorial-editor/src/serialization/DeserializationException.h 2010-04-14 01:14:27 UTC (rev 232) @@ -19,7 +19,7 @@ #ifndef DESERIALIZATIONEXCEPTION_H #define DESERIALIZATIONEXCEPTION_H -#include "../Exception.h" +#include "../util/Exception.h" /** * Thrown when the XML can't be deserialized (for example, when it isn't well Modified: trunk/ktutorial/ktutorial-editor/src/serialization/IOException.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/IOException.h 2010-04-13 20:30:16 UTC (rev 231) +++ trunk/ktutorial/ktutorial-editor/src/serialization/IOException.h 2010-04-14 01:14:27 UTC (rev 232) @@ -19,7 +19,7 @@ #ifndef IOEXCEPTION_H #define IOEXCEPTION_H -#include "../Exception.h" +#include "../util/Exception.h" /** * Thrown when an input/ouput operation fails (for example, writing to an Modified: trunk/ktutorial/ktutorial-editor/src/targetapplication/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/CMakeLists.txt 2010-04-13 20:30:16 UTC (rev 231) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/CMakeLists.txt 2010-04-14 01:14:27 UTC (rev 232) @@ -9,4 +9,8 @@ kde4_add_library(ktutorial_editor_targetapplication ${ktutorial_editor_targetapplication_SRCS}) -target_link_libraries(ktutorial_editor_targetapplication ktutorial_editor ${QT_QTDBUS_LIBRARY} ${KDE4_KDECORE_LIBS}) +target_link_libraries(ktutorial_editor_targetapplication + ktutorial_editor_util + ${QT_QTDBUS_LIBRARY} + ${KDE4_KDECORE_LIBS} +) Modified: trunk/ktutorial/ktutorial-editor/src/targetapplication/DBusException.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/DBusException.h 2010-04-13 20:30:16 UTC (rev 231) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/DBusException.h 2010-04-14 01:14:27 UTC (rev 232) @@ -19,7 +19,7 @@ #ifndef DBUSEXCEPTION_H #define DBUSEXCEPTION_H -#include "../Exception.h" +#include "../util/Exception.h" /** * Thrown when a DBus error happened. Added: trunk/ktutorial/ktutorial-editor/src/util/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/util/CMakeLists.txt (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/util/CMakeLists.txt 2010-04-14 01:14:27 UTC (rev 232) @@ -0,0 +1,5 @@ +set(ktutorial_editor_util_SRCS + Exception.cpp +) + +kde4_add_library(ktutorial_editor_util ${ktutorial_editor_util_SRCS}) Property changes on: trunk/ktutorial/ktutorial-editor/src/util/CMakeLists.txt ___________________________________________________________________ Added: svn:eol-style + native Copied: trunk/ktutorial/ktutorial-editor/src/util/Exception.cpp (from rev 198, trunk/ktutorial/ktutorial-editor/src/Exception.cpp) =================================================================== --- trunk/ktutorial/ktutorial-editor/src/util/Exception.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/util/Exception.cpp 2010-04-14 01:14:27 UTC (rev 232) @@ -0,0 +1,36 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "Exception.h" + +//public: + +Exception::Exception(const QString& message): std::exception(), + mMessage(message) { +} + +Exception::~Exception() throw() { +} + +const char* Exception::what() const throw() { + return mMessage.toUtf8(); +} + +QString Exception::message() const throw() { + return mMessage; +} Copied: trunk/ktutorial/ktutorial-editor/src/util/Exception.h (from rev 198, trunk/ktutorial/ktutorial-editor/src/Exception.h) =================================================================== --- trunk/ktutorial/ktutorial-editor/src/util/Exception.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/util/Exception.h 2010-04-14 01:14:27 UTC (rev 232) @@ -0,0 +1,54 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef EXCEPTION_H +#define EXCEPTION_H + +#include <exception> +#include <QString> + +/** + * Base class for exceptions. + */ +class Exception: public std::exception { +public: + + explicit Exception(const QString& message = QString()); + virtual ~Exception() throw(); + + /** + * Returns the exception message. + * + * @return The exception message. + */ + virtual const char* what() const throw(); + + /** + * Returns the exception message. + * + * @return The exception message. + */ + QString message() const throw(); + +private: + + QString mMessage; + +}; + +#endif Modified: trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt 2010-04-13 20:30:16 UTC (rev 231) +++ trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt 2010-04-14 01:14:27 UTC (rev 232) @@ -4,31 +4,5 @@ if (QT_QTDBUS_FOUND) add_subdirectory(targetapplication) endif (QT_QTDBUS_FOUND) +add_subdirectory(util) add_subdirectory(view) - -# Used by kde4_add_unit_test to set the full path to test executables -set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) - -include_directories(${ktutorial-editor_SOURCE_DIR}/src/ ${KDE4_INCLUDES}) - -MACRO(UNIT_TESTS) - FOREACH(_className ${ARGN}) - set(_testName ${_className}Test) - kde4_add_unit_test(${_testName} TESTNAME ktutorial-editor-unit-${_testName} ${_testName}.cpp) - target_link_libraries(${_testName} ktutorial_editor ${QT_QTTEST_LIBRARY}) - ENDFOREACH(_className) -ENDMACRO(UNIT_TESTS) - -unit_tests( - Exception -) - -MACRO(MEM_TESTS) - FOREACH(_testname ${ARGN}) - add_test(ktutorial-editor-unit-mem-${_testname} ${CMAKE_CURRENT_SOURCE_DIR}/runMemcheck.py ${CMAKE_CURRENT_BINARY_DIR}/${_testname}Test ${CMAKE_CURRENT_BINARY_DIR}) - ENDFOREACH(_testname) -ENDMACRO(MEM_TESTS) - -mem_tests( - Exception -) Deleted: trunk/ktutorial/ktutorial-editor/tests/unit/ExceptionTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/ExceptionTest.cpp 2010-04-13 20:30:16 UTC (rev 231) +++ trunk/ktutorial/ktutorial-editor/tests/unit/ExceptionTest.cpp 2010-04-14 01:14:27 UTC (rev 232) @@ -1,49 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * - * dan...@gm... * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 3 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; If not, see <http://www.gnu.org/licenses/>. * - ***************************************************************************/ - -#include <QtTest> - -#include "Exception.h" - -class ExceptionTest: public QObject { -Q_OBJECT - -private slots: - - void testConstructor(); - void testConstructorEmpty(); - -}; - -void ExceptionTest::testConstructor() { - Exception exception(QString("The message")); - - QCOMPARE(exception.what(), "The message"); - QCOMPARE(exception.message(), QString("The message")); -} - -void ExceptionTest::testConstructorEmpty() { - Exception exception; - - QCOMPARE(exception.what(), ""); - QCOMPARE(exception.message(), QString("")); -} - -QTEST_MAIN(ExceptionTest) - -#include "ExceptionTest.moc" Added: trunk/ktutorial/ktutorial-editor/tests/unit/util/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/util/CMakeLists.txt (rev 0) +++ trunk/ktutorial/ktutorial-editor/tests/unit/util/CMakeLists.txt 2010-04-14 01:14:27 UTC (rev 232) @@ -0,0 +1,26 @@ +# Used by kde4_add_unit_test to set the full path to test executables +set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) + +include_directories(${ktutorial-editor_SOURCE_DIR}/src/util ${KDE4_INCLUDES}) + +MACRO(UNIT_TESTS) + FOREACH(_className ${ARGN}) + set(_testName ${_className}Test) + kde4_add_unit_test(${_testName} TESTNAME ktutorial-editor-unit-${_testName} ${_testName}.cpp) + target_link_libraries(${_testName} ktutorial_editor_util ${QT_QTTEST_LIBRARY}) + ENDFOREACH(_className) +ENDMACRO(UNIT_TESTS) + +unit_tests( + Exception +) + +MACRO(MEM_TESTS) + FOREACH(_testname ${ARGN}) + add_test(ktutorial-editor-unit-mem-${_testname} ${CMAKE_CURRENT_SOURCE_DIR}/../runMemcheck.py ${CMAKE_CURRENT_BINARY_DIR}/${_testname}Test ${CMAKE_CURRENT_BINARY_DIR}) + ENDFOREACH(_testname) +ENDMACRO(MEM_TESTS) + +mem_tests( + Exception +) Property changes on: trunk/ktutorial/ktutorial-editor/tests/unit/util/CMakeLists.txt ___________________________________________________________________ Added: svn:eol-style + native Copied: trunk/ktutorial/ktutorial-editor/tests/unit/util/ExceptionTest.cpp (from rev 198, trunk/ktutorial/ktutorial-editor/tests/unit/ExceptionTest.cpp) =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/util/ExceptionTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/tests/unit/util/ExceptionTest.cpp 2010-04-14 01:14:27 UTC (rev 232) @@ -0,0 +1,49 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include <QtTest> + +#include "Exception.h" + +class ExceptionTest: public QObject { +Q_OBJECT + +private slots: + + void testConstructor(); + void testConstructorEmpty(); + +}; + +void ExceptionTest::testConstructor() { + Exception exception(QString("The message")); + + QCOMPARE(exception.what(), "The message"); + QCOMPARE(exception.message(), QString("The message")); +} + +void ExceptionTest::testConstructorEmpty() { + Exception exception; + + QCOMPARE(exception.what(), ""); + QCOMPARE(exception.message(), QString("")); +} + +QTEST_MAIN(ExceptionTest) + +#include "ExceptionTest.moc" This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-04-13 20:30:23
|
Revision: 231 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=231&view=rev Author: danxuliu Date: 2010-04-13 20:30:16 +0000 (Tue, 13 Apr 2010) Log Message: ----------- -Add RemoteObjectChooser (and related classes) to select a remote object from a running application. Use it in WaitForEvent and WaitForWidget. -Add a helper class to execute dialogs that do not finish when they are hidden (required by RemoteObjectChooser to safely hide all the windows and dialogs except itself). Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/EditActions.cpp trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.h trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.ui trunk/ktutorial/ktutorial-editor/src/view/WaitForSignalWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/WaitForSignalWidget.h trunk/ktutorial/ktutorial-editor/src/view/WaitForSignalWidget.ui trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt Added Paths: ----------- trunk/ktutorial/ktutorial-editor/src/view/DialogRunner.cpp trunk/ktutorial/ktutorial-editor/src/view/DialogRunner.h trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.cpp trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.h trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.ui trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeItem.cpp trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeItem.h trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeItemUpdater.cpp trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeItemUpdater.h trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeSelectionManager.cpp trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeSelectionManager.h trunk/ktutorial/ktutorial-editor/src/view/TargetApplicationView.cpp trunk/ktutorial/ktutorial-editor/src/view/TargetApplicationView.h trunk/ktutorial/ktutorial-editor/tests/unit/view/DialogRunnerTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectChooserTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectTreeItemTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectTreeItemUpdaterTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectTreeSelectionManagerTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/EditActions.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/EditActions.cpp 2010-04-13 20:11:06 UTC (rev 230) +++ trunk/ktutorial/ktutorial-editor/src/EditActions.cpp 2010-04-13 20:30:16 UTC (rev 231) @@ -28,6 +28,7 @@ #include "commands/TutorialCommands.h" #include "data/Reaction.h" #include "data/Step.h" +#include "view/DialogRunner.h" #include "view/EditionDialog.h" #include "view/LicenseWidget.h" #include "view/ReactionWidget.h" @@ -213,10 +214,7 @@ EditionDialog* dialog = new EditionDialog(commandWidget, mTutorialEditor); dialog->setObjectName("editionDialog"); - int dialogCode = dialog->exec(); - dialog->deleteLater(); - - return dialogCode; + return DialogRunner(dialog).exec(); } //private slots: Modified: trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp 2010-04-13 20:11:06 UTC (rev 230) +++ trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp 2010-04-13 20:30:16 UTC (rev 231) @@ -35,6 +35,10 @@ #include "view/TutorialTreeItem.h" #include "view/TutorialTreeSelectionManager.h" +#ifdef QT_QTDBUS_FOUND +#include "targetapplication/TargetApplication.h" +#endif + //public: KTutorialEditor::KTutorialEditor(): KXmlGuiWindow(0), @@ -63,6 +67,12 @@ setupGUI(); } +KTutorialEditor::~KTutorialEditor() { +#ifdef QT_QTDBUS_FOUND + delete TargetApplication::self(); +#endif +} + Tutorial* KTutorialEditor::tutorial() { return mTutorial; } @@ -136,6 +146,10 @@ delete mTutorial; mTutorial = tutorial; + +#ifdef QT_QTDBUS_FOUND + TargetApplication::self()->setTargetApplicationFilePath(""); +#endif } void KTutorialEditor::setupDocks() { Modified: trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h 2010-04-13 20:11:06 UTC (rev 230) +++ trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h 2010-04-13 20:30:16 UTC (rev 231) @@ -41,6 +41,12 @@ KTutorialEditor(); /** + * Destroys this KTutorialEditor. + * The target application is also killed if it is running. + */ + virtual ~KTutorialEditor(); + + /** * Returns the tutorial being edited. * * @return The tutorial being edited. Modified: trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2010-04-13 20:11:06 UTC (rev 230) +++ trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2010-04-13 20:30:16 UTC (rev 231) @@ -2,6 +2,7 @@ ActionListWidget.cpp AutoExpandableTreeView.cpp CommandWidget.cpp + DialogRunner.cpp EditionDialog.cpp EditionWidget.cpp LicenseWidget.cpp @@ -29,6 +30,18 @@ WaitForWidget.cpp ) +if (QT_QTDBUS_FOUND) + add_definitions(-DQT_QTDBUS_FOUND) + set(ktutorial_editor_view_SRCS + ${ktutorial_editor_view_SRCS} + RemoteObjectChooser.cpp + RemoteObjectTreeItem.cpp + RemoteObjectTreeItemUpdater.cpp + RemoteObjectTreeSelectionManager.cpp + TargetApplicationView.cpp + ) +endif (QT_QTDBUS_FOUND) + kde4_add_ui_files(ktutorial_editor_view_SRCS CustomCodeWidget.ui LicenseWidget.ui @@ -41,10 +54,23 @@ WaitForWidget.ui ) +if (QT_QTDBUS_FOUND) + kde4_add_ui_files(ktutorial_editor_view_SRCS + RemoteObjectChooser.ui + ) +endif (QT_QTDBUS_FOUND) + kde4_add_library(ktutorial_editor_view ${ktutorial_editor_view_SRCS}) target_link_libraries(ktutorial_editor_view ktutorial_editor_commands ktutorial_editor_data ${KDE4_KDEUI_LIBS} + ${KDE4_KIO_LIBS} ) + +if (QT_QTDBUS_FOUND) + target_link_libraries(ktutorial_editor_view + ktutorial_editor_targetapplication + ) +endif (QT_QTDBUS_FOUND) Added: trunk/ktutorial/ktutorial-editor/src/view/DialogRunner.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/DialogRunner.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/DialogRunner.cpp 2010-04-13 20:30:16 UTC (rev 231) @@ -0,0 +1,59 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "DialogRunner.h" + +#include <QDialog> +#include <QEventLoop> + +//public: + +DialogRunner::DialogRunner(QDialog* dialog, QObject* parent): + QObject(parent), + mDialog(dialog) { + Q_ASSERT(dialog); +} + +int DialogRunner::exec() { + Q_ASSERT(mDialog); + + mDialog->setModal(true); + mDialog->show(); + + connect(mDialog, SIGNAL(finished(int)), this, SLOT(exitEventLoop())); + connect(mDialog, SIGNAL(destroyed(QObject*)), this, SLOT(exitEventLoop())); + + mEventLoop = new QEventLoop(); + mEventLoop->exec(QEventLoop::DialogExec); + delete mEventLoop; + + if (!mDialog) { + return QDialog::Rejected; + } + + int result = mDialog->result(); + mDialog->deleteLater(); + + return result; +} + +//private slots: + +void DialogRunner::exitEventLoop() { + mEventLoop->exit(); +} Property changes on: trunk/ktutorial/ktutorial-editor/src/view/DialogRunner.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/DialogRunner.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/DialogRunner.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/DialogRunner.h 2010-04-13 20:30:16 UTC (rev 231) @@ -0,0 +1,79 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef DIALOGRUNNER_H +#define DIALOGRUNNER_H + +#include <QObject> +#include <QPointer> + +class QDialog; +class QEventLoop; + +/** + * Convenience class to execute modal dialogs that can be hidden without ending + * their execution. + * DialogRunner just shows the given dialog as a modal dialog and executes an + * event loop to block in the exec() method until the user closes the dialog or + * the dialog is destroyed. The dialog can be hidden and shown again without + * causing the exec method to return (in contrast with QDialog::exec() that + * returns when the dialog is hidden). + * + * Once the event loop ends, the dialog is scheduled for deletion. + */ +class DialogRunner: public QObject { +Q_OBJECT +public: + + /** + * Creates a new DialogRunner for the given dialog and with the given + * parent. + * + * @param dialog The dialog to execute. + * @param parent The parent object of this DialogRunner. + */ + explicit DialogRunner(QDialog* dialog, QObject* parent = 0); + + /** + * Shows the dialog as a modal dialog, blocking until the user closes it. + */ + int exec(); + +private: + + /** + * The dialog to execute. + */ + QPointer<QDialog> mDialog; + + /** + * The event loop to block exec method in. + */ + QEventLoop* mEventLoop; + +private Q_SLOTS: + + /** + * Exits the event loop. + * When the event loop exits, exec method is no longer blocked and returns. + */ + void exitEventLoop(); + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/view/DialogRunner.h ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.cpp 2010-04-13 20:30:16 UTC (rev 231) @@ -0,0 +1,204 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "RemoteObjectChooser.h" +#include "ui_RemoteObjectChooser.h" + +#include <QPushButton> + +#include <KDebug> +#include <KDialogButtonBox> +#include <KMessageBox> + +#include "RemoteObjectTreeItem.h" +#include "RemoteObjectTreeItemUpdater.h" +#include "RemoteObjectTreeSelectionManager.h" +#include "TreeModel.h" +#include "TargetApplicationView.h" +#include "../targetapplication/RemoteEditorSupport.h" +#include "../targetapplication/RemoteEventSpy.h" +#include "../targetapplication/RemoteObject.h" +#include "../targetapplication/TargetApplication.h" + +//public: + +RemoteObjectChooser::RemoteObjectChooser(QWidget* parent): + QWidget(parent), + mCurrentRemoteObject(0), + mSuccessfullyStarted(false) { + setWindowFlags(Qt::Window); + Q_ASSERT(parent); + + ui = new Ui::RemoteObjectChooser(); + ui->setupUi(this); + + QPushButton* button = ui->dialogButtonBox->button(QDialogButtonBox::Ok); + button->setObjectName("okButton"); + button->setEnabled(false); + connect(button, SIGNAL(clicked(bool)), this, SLOT(accept())); + + button = ui->dialogButtonBox->button(QDialogButtonBox::Cancel); + button->setObjectName("cancelButton"); + connect(button, SIGNAL(clicked(bool)), this, SLOT(cancel())); + + connect(TargetApplication::self(), SIGNAL(started()), + this, SLOT(handleTargetApplicationStarted())); + connect(TargetApplication::self(), + SIGNAL(startFailed(TargetApplication::Error)), + this, SLOT(cancel())); + connect(TargetApplication::self(), SIGNAL(finished()), + this, SLOT(handleTargetApplicationFinished())); + + if (TargetApplication::self()->remoteEditorSupport()) { + handleTargetApplicationStarted(); + } else { + TargetApplicationView* targetApplicationView = + new TargetApplicationView(TargetApplication::self(), this); + targetApplicationView->start(); + } +} + +RemoteObjectChooser::~RemoteObjectChooser() { + if (mCurrentRemoteObject && + TargetApplication::self()->remoteEditorSupport()) { + TargetApplication::self()->remoteEditorSupport()-> + stopHighlighting(mCurrentRemoteObject); + } + + delete ui; +} + +//protected: + +void RemoteObjectChooser::closeEvent(QCloseEvent* event) { + QWidget::closeEvent(event); + showParentWindows(this); + deleteLater(); +} + +//private: + +void RemoteObjectChooser::hideParentWindows(QWidget* widget) { + if (!widget || !widget->parentWidget()) { + return; + } + + if (widget->parentWidget()->windowFlags() & (Qt::Window | Qt::Dialog)) { + widget->parentWidget()->hide(); + } + + hideParentWindows(widget->parentWidget()); +} + +void RemoteObjectChooser::showParentWindows(QWidget* widget) { + if (!widget || !widget->parentWidget()) { + return; + } + + //Show them in inverse order, because showing first a dialog and then its + //parent window would create an entry for the dialog and another entry for + //the window in the task bar + showParentWindows(widget->parentWidget()); + + if (widget->parentWidget()->windowFlags() & (Qt::Window | Qt::Dialog)) { + widget->parentWidget()->show(); + } +} + +//private slots: + +void RemoteObjectChooser::handleTargetApplicationStarted() { + hideParentWindows(this); + + RemoteEditorSupport* remoteEditorSupport = + TargetApplication::self()->remoteEditorSupport(); + + RemoteObject* mainWindow = remoteEditorSupport->mainWindow(); + RemoteObjectTreeItem* rootItem = new RemoteObjectTreeItem(mainWindow); + TreeModel* treeModel = new TreeModel(rootItem, this); + ui->remoteObjectsTreeView->setModel(treeModel); + + RemoteObjectTreeItemUpdater* updater = + new RemoteObjectTreeItemUpdater(this); + rootItem->setUpdater(updater); + + try { + updater->setRemoteEventSpy(remoteEditorSupport->enableEventSpy()); + } catch (DBusException e) { + kWarning() << "Remote event spy could not be enabled in the target " + << "application. Children objects will not be added and " + << "removed automatically in the list to reflect the " + << "changes in the remote objects (" << e.message() << ")."; + } + + //Parent object is set to the selection model, so the manager is also + //deleted when the selection model it watches is deleted + QItemSelectionModel* selectionModel = + ui->remoteObjectsTreeView->selectionModel(); + RemoteObjectTreeSelectionManager* selectionManager = + new RemoteObjectTreeSelectionManager(selectionModel, selectionModel); + connect(selectionManager, SIGNAL(remoteObjectSelected(RemoteObject*)), + this, SLOT(setCurrentRemoteObject(RemoteObject*))); + + mSuccessfullyStarted = true; +} + +void RemoteObjectChooser::handleTargetApplicationFinished() { + //If the application is running but it was not successfully started (the + //application does not have the KTutorial editor support module) + //this RemoteObjectChooser is just closed. The TargetApplicationView takes + //care of notifying the user about the problem. + if (!mSuccessfullyStarted) { + return; + } + + QString text = i18nc("@label", "The target application has been closed, " +"but it must be running to be able to choose the objects."); + QString caption = i18nc("@title:window", "Target application closed"); + KMessageBox::sorry(this, text, caption); + + close(); +} + +void RemoteObjectChooser::setCurrentRemoteObject(RemoteObject* remoteObject) { + if (mCurrentRemoteObject && mCurrentRemoteObject != remoteObject) { + TargetApplication::self()->remoteEditorSupport()-> + stopHighlighting(mCurrentRemoteObject); + } + + mCurrentRemoteObject = remoteObject; + + if (mCurrentRemoteObject) { + TargetApplication::self()->remoteEditorSupport()-> + highlight(mCurrentRemoteObject); + ui->dialogButtonBox->button(QDialogButtonBox::Ok)->setEnabled(true); + } else { + ui->dialogButtonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + } +} + +void RemoteObjectChooser::accept() { + Q_ASSERT(mCurrentRemoteObject); + + emit remoteObjectChosen(mCurrentRemoteObject); + close(); +} + +void RemoteObjectChooser::cancel() { + close(); +} Property changes on: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.h 2010-04-13 20:30:16 UTC (rev 231) @@ -0,0 +1,171 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef REMOTEOBJECTCHOOSER_H +#define REMOTEOBJECTCHOOSER_H + +#include <QWidget> + +class RemoteObject; + +namespace Ui { +class RemoteObjectChooser; +} + +/** + * Widget to choose a remote object from all the available remote objects in the + * target application. + * The RemoteObjectChooser shows a window with a list containing all the objects + * that can be accesed by KTutorial in the target application. The target + * application must be running, so it is started when the RemoteObjectChooser is + * created. If the target application is closed, the RemoteObjectChooser is also + * closed (after notifying the user). + * + * When the target application is successfully started, the RemoteObjectChooser + * hides all its parent dialogs and windows. Only the RemoteObjectChooser itself + * is kept shown to avoid the rest of windows of KTutorial editor to get in the + * way of the user when he interacts with the target application. + * + * When the user selects a remote object in the list and that object represents + * a widget, the widget is highlighted in the target application. + * + * The window contains an "Ok" and a "Cancel" button, like the ones found in + * dialogs. A window is used instead of a dialog to be shown in the task bar (as + * after hidding the rest of KTutorial editor windows no entry would be shown if + * this were a dialog). When there is a remote object selected and the "Ok" + * button is clicked, signal remoteObjectChosen(RemoteObject*) is emitted. + * + * The RemoteObjectChooser deletes itself once it has been closed, no matter the + * reason why. + */ +class RemoteObjectChooser: public QWidget { +Q_OBJECT +public: + + /** + * Creates a new RemoteObjectChooser with the given parent. + * The target application is started. + * + * @param parent The parent QWidget. + */ + explicit RemoteObjectChooser(QWidget* parent = 0); + + /** + * Destroys this RemoteObjectChooser. + * The highlighting in the current remote object is stopped, if any. + */ + virtual ~RemoteObjectChooser(); + +Q_SIGNALS: + + /** + * Emitted when the user chooses a RemoteObject. + * + * @param remoteObject The chosen RemoteObject. + */ + void remoteObjectChosen(RemoteObject* remoteObject); + +protected: + + /** + * Executes KDialog handler, shows again the parent windows and schedules + * this RemoteObjectChooser for deletion. + * close() can't be redefined to restore the parent windows, as it doesn't + * get a close triggered by the window manager (like using ALT+F4) (and it + * is not even a virtual method). Moreover, close() itself sends a + * QCloseEvent, which is handled by this method. + * Likely, Qt::WA_DeleteOnClose isn't used as it will delete this + * RemoteObjectChooser only through close(), but not through a QCloseEvent. + * Instead, this RemoteObjectChooser is scheduled for deletion after + * receiving a QCloseEvent. + * + * @param event The QCloseEvent. + */ + virtual void closeEvent(QCloseEvent* event); + +private: + + /** + * The Ui Designer generated class. + */ + Ui::RemoteObjectChooser* ui; + + /** + * The RemoteObject currently selected in the list. + */ + RemoteObject* mCurrentRemoteObject; + + /** + * True if the target application has been successfully started, false + * otherwise. + */ + bool mSuccessfullyStarted; + + /** + * Hide all the parent widgets of the given widget that are windows or + * dialogs. + * + * @param widget The widget to hide its parents. + */ + void hideParentWindows(QWidget* widget); + + /** + * Shows all the parent widgets of the given widget that are windows or + * dialogs. + * + * @param widget The widget to show its parents. + */ + void showParentWindows(QWidget* widget); + +private Q_SLOTS: + + /** + * Hides the parent windows and dialogs and sets up the models for the tree + * view. + */ + void handleTargetApplicationStarted(); + + /** + * If the target application was finished after starting successfully, a + * warning is shown to the user and this RemoteObjectChooser is closed. + */ + void handleTargetApplicationFinished(); + + /** + * Sets the current remote object. + * The current remote object is highlighted, and the highlighting in the + * previous one is stopped. + * + * @param remoteObject The current remote object to set. + */ + void setCurrentRemoteObject(RemoteObject* remoteObject); + + /** + * Emits remoteObjectChosen(RemoteObject*) and closes this + * RemoteObjectChooser. + */ + void accept(); + + /** + * Closes this RemoteObjectChooser. + */ + void cancel(); + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.h ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.ui =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.ui (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.ui 2010-04-13 20:30:16 UTC (rev 231) @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>RemoteObjectChooser</class> + <widget class="QWidget" name="RemoteObjectChooser"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle"> + <string comment="@title:window">Target application objects</string> + </property> + <property name="whatsThis"> + <string comment="@info:whatsthis"><p>Chooser for objects in the target application.</p> +<p>The objects shown in the list are all the objects accessible through KTutorial. They are shown in a tree structure to represent the parent and child relationships the objects have.</p> +<p>Note, however, that not all the objects have a name set in the target application. KTutorial needs to know the name of the object to find it, so if an object does not have a name KTutorial will not be able to use it.</p></string> + </property> + <layout class="QVBoxLayout" name="remoteObjectChooserVerticalLayout"> + <item> + <widget class="AutoExpandableTreeView" name="remoteObjectsTreeView"/> + </item> + <item> + <widget class="KDialogButtonBox" name="dialogButtonBox"> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>KDialogButtonBox</class> + <extends>QDialogButtonBox</extends> + <header>kdialogbuttonbox.h</header> + </customwidget> + <customwidget> + <class>AutoExpandableTreeView</class> + <extends>QTreeView</extends> + <header>AutoExpandableTreeView.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> Added: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeItem.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeItem.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeItem.cpp 2010-04-13 20:30:16 UTC (rev 231) @@ -0,0 +1,138 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "RemoteObjectTreeItem.h" + +#include <KDebug> +#include <KLocalizedString> + +#include "RemoteObjectTreeItemUpdater.h" +#include "../targetapplication/RemoteObject.h" + +//public: + +RemoteObjectTreeItem::RemoteObjectTreeItem(RemoteObject* remoteObject, + TreeItem* parent): + TreeItem(parent), + mRemoteObject(remoteObject), + mUpdater(0) { + Q_ASSERT(remoteObject); + + try { + mName = remoteObject->name(); + mClassName = remoteObject->className(); + } catch (DBusException e) { + mName = i18nc("@item", "D-Bus Error!"); + mClassName = i18nc("@item", "D-Bus Error!"); + } + + if (mName.isEmpty()) { + mName = i18nc("@item", "Object without name!"); + } + + if (mClassName.isEmpty()) { + mClassName = i18nc("@item", "No class name!"); + } + + updateChildren(); +} + +QString RemoteObjectTreeItem::text() const { + return i18nc("@item Object name (Class name)", "%1 (%2)", mName, + mClassName); +} + +RemoteObject* RemoteObjectTreeItem::remoteObject() const { + return mRemoteObject; +} + +void RemoteObjectTreeItem::setUpdater(RemoteObjectTreeItemUpdater* updater) { + Q_ASSERT(updater); + + mUpdater = updater; + + updater->registerRemoteObjectTreeItem(this); + + foreach (RemoteObjectTreeItem* child, mChildRemoteObjectTreeItems) { + child->setUpdater(updater); + } +} + +void RemoteObjectTreeItem::updateChildren() { + QList<RemoteObject*> children; + try { + children = mRemoteObject->children(); + } catch (DBusException e) { + kWarning() << "The children for the remote object with id " + << mRemoteObject->objectId() << " could not be updated (" + << e.message() << ")."; + return; + } + + int i=0; + while (i < mChildRemoteObjectTreeItems.count()) { + if (i >= children.count() || + mChildRemoteObjectTreeItems[i]->remoteObject() != children[i]) { + removeChildRemoteObject( + mChildRemoteObjectTreeItems[i]->remoteObject()); + } else { + i++; + } + } + + while (i < children.count()) { + addChildRemoteObject(children[i]); + i++; + } +} + +//private: + +RemoteObjectTreeItem* RemoteObjectTreeItem::remoteObjectTreeItemForRemoteObject( + RemoteObject* child) const { + foreach (RemoteObjectTreeItem* remoteObjectTreeItem, + mChildRemoteObjectTreeItems) { + if (remoteObjectTreeItem->remoteObject() == child) { + return remoteObjectTreeItem; + } + } + + return 0; +} + +//private slots: + +void RemoteObjectTreeItem::addChildRemoteObject(RemoteObject* child) { + RemoteObjectTreeItem* remoteObjectTreeItem = + new RemoteObjectTreeItem(child, this); + appendChild(remoteObjectTreeItem); + mChildRemoteObjectTreeItems.append(remoteObjectTreeItem); + + if (mUpdater) { + remoteObjectTreeItem->setUpdater(mUpdater); + } +} + +void RemoteObjectTreeItem::removeChildRemoteObject(RemoteObject* child) { + RemoteObjectTreeItem* remoteObjectTreeItem = + remoteObjectTreeItemForRemoteObject(child); + + removeChild(remoteObjectTreeItem); + mChildRemoteObjectTreeItems.removeOne(remoteObjectTreeItem); + delete remoteObjectTreeItem; +} Property changes on: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeItem.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeItem.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeItem.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeItem.h 2010-04-13 20:30:16 UTC (rev 231) @@ -0,0 +1,149 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef REMOTEOBJECTTREEITEM_H +#define REMOTEOBJECTTREEITEM_H + +#include "TreeItem.h" + +class RemoteObject; +class RemoteObjectTreeItemUpdater; + +/** + * A TreeItem that represents a RemoteObject. + * The tree representation of a RemoteObject is: + * The object name (The class name) + * |-The child 1 name (The child 1 class name) + * | ... + * |-The child 2 name (The child 2 class name) + * | ... + * ... + * + * If the RemoteObject returns an empty object name or an empty class name + * (for example, because the id is wrong), a placeholder is used instead. Name + * placeholder is "Object without name!", and the class name placeholder is + * "No class name!". + * + * If a D-Bus error happens, the placeholder for each element is "D-Bus Error!". + * No children are shown if a D-Bus error happened. + * + * RemoteObjects does not provide information about changes in their children. A + * helper class, RemoteObjectTreeItemUpdater, is used for this. + * RemoteObjectTreeItem can work without an updater, but changes in the children + * will not be shown if updateChildren() is not called explicitly. + * + * @see RemoteObjectTreeItemUpdater + */ +class RemoteObjectTreeItem: public TreeItem { +Q_OBJECT +public: + + /** + * Creates a new RemoteObjectTreeItem for the given RemoteObject and with + * the given parent. + * + * @param remoteObject The RemoteObject to represent. + * @param parent The parent TreeItem. + */ + explicit RemoteObjectTreeItem(RemoteObject* remoteObject, + TreeItem* parent = 0); + + /** + * Returns "The class name (The class name)", or a placeholder if the names + * are empty or can not be got. + * + * @return The text for this TreeItem. + */ + virtual QString text() const; + + /** + * Returns the RemoteObject. + * + * @return The RemoteObject. + */ + RemoteObject* remoteObject() const; + + /** + * Sets the updater to register the children tree items in. + * + * @param updater The updater to register the children tree items in. + */ + void setUpdater(RemoteObjectTreeItemUpdater* updater); + + /** + * Updates the children tree items based on the current children of the + * remote object, adding or removing them as necessary. + */ + void updateChildren(); + +private: + + /** + * The RemoteObject. + */ + RemoteObject* mRemoteObject; + + /** + * The updater for this RemoteObjectTreeItem and all its children. + */ + RemoteObjectTreeItemUpdater* mUpdater; + + /** + * The name of the RemoteObject. + */ + QString mName; + + /** + * The class name of the RemoteObject. + */ + QString mClassName; + + /** + * The RemoteObjectTreeItems for each child RemoteObject in the + * RemoteObject. + */ + QList<RemoteObjectTreeItem*> mChildRemoteObjectTreeItems; + + /** + * Returns the RemoteObjectTreeItem for the given child RemoteObject. + * + * @param child The child RemoteObject to get its RemoteObjectTreeItem. + * @return The RemoteObjectTreeItem. + */ + RemoteObjectTreeItem* remoteObjectTreeItemForRemoteObject( + RemoteObject* child) const; + + /** + * Adds a new RemoteObjectTreeItem when a child RemoteObject is added in the + * RemoteObject. + * + * @param child The child RemoteObject added in the RemoteObject. + */ + void addChildRemoteObject(RemoteObject* child); + + /** + * Removes the RemoteObjectTreeItem for the child RemoteObject removed in + * the RemoteObject. + * + * @param child The child RemoteObject removed in the RemoteObject. + */ + void removeChildRemoteObject(RemoteObject* child); + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeItem.h ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeItemUpdater.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeItemUpdater.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeItemUpdater.cpp 2010-04-13 20:30:16 UTC (rev 231) @@ -0,0 +1,60 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "RemoteObjectTreeItemUpdater.h" +#include "RemoteObjectTreeItem.h" +#include "../targetapplication/RemoteEventSpy.h" + +//public: + +RemoteObjectTreeItemUpdater::RemoteObjectTreeItemUpdater(QObject* parent): + QObject(parent) { +} + +void RemoteObjectTreeItemUpdater::setRemoteEventSpy( + RemoteEventSpy* remoteEventSpy) { + connect(remoteEventSpy, SIGNAL(eventReceived(RemoteObject*, QString)), + this, SLOT(handleEventReceived(RemoteObject*, QString))); +} + +void RemoteObjectTreeItemUpdater::registerRemoteObjectTreeItem( + RemoteObjectTreeItem* item) { + mRemoteObjectTreeItems.insert(item->remoteObject(), item); +} + +//private slots: + +void RemoteObjectTreeItemUpdater::handleEventReceived( + RemoteObject* remoteObject, + const QString& eventType) { + if (!mRemoteObjectTreeItems.contains(remoteObject)) { + return; + } + + if (!mRemoteObjectTreeItems.value(remoteObject)) { + //The tree item was deleted, so an entry is no longer needed for it + mRemoteObjectTreeItems.remove(remoteObject); + return; + } + + if (eventType != "ChildAdded" && eventType != "ChildRemoved") { + return; + } + + mRemoteObjectTreeItems.value(remoteObject)->updateChildren(); +} Property changes on: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeItemUpdater.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeItemUpdater.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeItemUpdater.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeItemUpdater.h 2010-04-13 20:30:16 UTC (rev 231) @@ -0,0 +1,93 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef REMOTEOBJECTTREEITEMUPDATER_H +#define REMOTEOBJECTTREEITEMUPDATER_H + +#include <QHash> +#include <QObject> +#include <QPointer> + +class RemoteEventSpy; +class RemoteObject; +class RemoteObjectTreeItem; + +/** + * Helper class for RemoteObjectTreeItem to notify when it should update its + * children tree items. + * RemoteObjectTreeItems can not update their list of children tree items by + * themselves, as RemoteObject does not provide that information. The + * RemoteEventSpy has to be used to watch events in all the RemoteObjects and + * update the tree items when a ChildAdded or a ChildRemoved event is received. + * + * RemoteObjectTreeItems should not be registered directly with the updater. The + * updater must be set in the root RemoteObjectTreeItem to update. The tree item + * will take care of registering its children with the updater when necessary. + * Thus, the whole tree is updated, instead of only the registered item. + * + * @see RemoteObjectTreeItem + */ +class RemoteObjectTreeItemUpdater: public QObject { +Q_OBJECT +public: + + /** + * Creates a new RemoteObjectTreeItemUpdater. + * + * @param parent The parent object. + */ + explicit RemoteObjectTreeItemUpdater(QObject* parent = 0); + + /** + * Sets the RemoteEventSpy to check its events. + * + * @param remoteEventSpy The RemoteEventSpy. + */ + void setRemoteEventSpy(RemoteEventSpy* remoteEventSpy); + + /** + * Registers a new RemoteObjectTreeItem to be updated. + * + * @param remoteObjectTreeItem The RemoteObjectTreeItem to register. + */ + void registerRemoteObjectTreeItem( + RemoteObjectTreeItem* remoteObjectTreeItem); + +private: + + /** + * The RemoteObjectTreeItems to update, identified by their RemoteObject. + */ + QHash<RemoteObject*, QPointer<RemoteObjectTreeItem> > + mRemoteObjectTreeItems; + +private Q_SLOTS: + + /** + * If the event is a ChildAdded or a ChildRemoved, the RemoteObjectTreeItem + * that represents the remoteObject is told to update its children. + * + * @param remoteObject The RemoteObject to update. + * @param eventType The type of the event received. + */ + void handleEventReceived(RemoteObject* remoteObject, + const QString& eventType); + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeItemUpdater.h ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeSelectionManager.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeSelectionManager.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeSelectionManager.cpp 2010-04-13 20:30:16 UTC (rev 231) @@ -0,0 +1,95 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "RemoteObjectTreeSelectionManager.h" + +#include "RemoteObjectTreeItem.h" + +//public: + +RemoteObjectTreeSelectionManager::RemoteObjectTreeSelectionManager( + QItemSelectionModel* itemSelectionModel, + QObject* parent): QObject(parent) { + connect(itemSelectionModel, + SIGNAL(selectionChanged(QItemSelection, QItemSelection)), + this, + SLOT(handleSelectionChanged(QItemSelection, QItemSelection))); +} + +//private: + +void RemoteObjectTreeSelectionManager::updateRemoteObjectSelection( + TreeItem* selected, + TreeItem* deselected) { + RemoteObject* selectedRemoteObject = getRemoteObjectForTreeItem(selected); + RemoteObject* deselectedRemoteObject = getRemoteObjectForTreeItem( + deselected); + + if (selectedRemoteObject && + selectedRemoteObject != deselectedRemoteObject) { + emit remoteObjectSelected(selectedRemoteObject); + return; + } + + if (!selectedRemoteObject && deselectedRemoteObject) { + emit remoteObjectSelected(0); + return; + } +} + +RemoteObject* RemoteObjectTreeSelectionManager::getRemoteObjectForTreeItem( + TreeItem* item) { + if (qobject_cast<RemoteObjectTreeItem*>(item)) { + return static_cast<RemoteObjectTreeItem*>(item)->remoteObject(); + } + + if (item == 0 || item->parent() == 0) { + return 0; + } + + return getRemoteObjectForTreeItem(item->parent()); +} + +//private slots: + +void RemoteObjectTreeSelectionManager::handleSelectionChanged( + const QItemSelection& selected, + const QItemSelection& deselected) { + //Only single selections are supported + Q_ASSERT(selected.count() <= 1); + Q_ASSERT(deselected.count() <= 1); + + TreeItem* selectedItem = 0; + TreeItem* deselectedItem = 0; + + if (selected.count() == 1) { + Q_ASSERT(selected.at(0).indexes().count() == 1); + + QModelIndex index = selected.at(0).indexes().at(0); + selectedItem = static_cast<TreeItem*>(index.internalPointer()); + } + + if (deselected.count() == 1) { + Q_ASSERT(deselected.at(0).indexes().count() == 1); + + QModelIndex index = deselected.at(0).indexes().at(0); + deselectedItem = static_cast<TreeItem*>(index.internalPointer()); + } + + updateRemoteObjectSelection(selectedItem, deselectedItem); +} Property changes on: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeSelectionManager.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeSelectionManager.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeSelectionManager.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeSelectionManager.h 2010-04-13 20:30:16 UTC (rev 231) @@ -0,0 +1,99 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef REMOTEOBJECTTREESELECTIONMANAGER_H +#define REMOTEOBJECTTREESELECTIONMANAGER_H + +#include <QItemSelectionModel> +#include <QObject> + +class RemoteObject; +class TreeItem; + +/** + * Watches the QItemSelectionModel of a TreeModel composed by + * RemoteObjectTreeItems for changes in the selection. + * When an item is selected in the TreeModel, + * remoteObjectSelected(RemoteObject*) signal is emitted with the RemoteObject + * represented by the selected item. + * + * Only single item selections are supported. + */ +class RemoteObjectTreeSelectionManager: public QObject { +Q_OBJECT +public: + + /** + * Creates a new RemoteObjectTreeSelectionManager that watchs the given + * selection model. + * + * @param itemSelectionModel The selection model to watch for changes in the + * selection. + * @param parent The parent object. + */ + explicit RemoteObjectTreeSelectionManager( + QItemSelectionModel* itemSelectionModel, QObject* parent = 0); + +Q_SIGNALS: + + /** + * Emitted when a RemoteObject is selected. + * If the RemoteObject is deselected and the new selected item isn't a + * RemoteObject, the signal is emitted with a null pointer. + * + * @param remoteObject The selected RemoteObject, or null if it was + * deselected. + */ + void remoteObjectSelected(RemoteObject* remoteObject); + +private: + + /** + * Emits remoteObjectSelected(RemoteObject*) signal based on the selected + * and deselected items. + * + * @param selected The selected item, if any. + * @param deselected The deselected item, if any. + */ + void updateRemoteObjectSelection(TreeItem* selected, TreeItem* deselected); + + /** + * Returns the RemoteObject represented by the given item. + * If the item doesn't represent a RemoteObject or there is no item, a null + * pointer is returned. + * + * @param item The item to get its represented RemoteObject. + * @return The RemoteObject. + */ + RemoteObject* getRemoteObjectForTreeItem(TreeItem* item); + +private Q_SLOTS: + + /** + * Handles a change in the selection in the watched selection model. + * Signals are emitted as needed based on the selected and deselected items. + * + * @param selected The item selection of selected items. + * @param selected The item selection of deselected items. + */ + void handleSelectionChanged(const QItemSelection& selected, + const QItemSelection& deselected); + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeSelectionManager.h ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/TargetApplicationView.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/TargetApplicationView.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/TargetApplicationView.cpp 2010-04-13 20:30:16 UTC (rev 231) @@ -0,0 +1,109 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "TargetApplicationView.h" + +#include <QApplication> +#include <QScopedPointer> + +#include <KFileDialog> +#include <KFileFilterCombo> +#include <KLocalizedString> +#include <KMessageBox> + +//public: + +TargetApplicationView::TargetApplicationView( + TargetApplication* targetApplication, QWidget* parent): + QObject(parent), + mTargetApplication(targetApplication), + mParent(parent) { +} + +void TargetApplicationView::start() { + if (mTargetApplication->remoteEditorSupport()) { + return; + } + + if (mTargetApplication->targetApplicationFilePath().isEmpty()) { + QString path = askApplicationFilePath(); + + if (path.isEmpty()) { + return; + } + + ... [truncated message content] |
From: <dan...@us...> - 2010-04-13 20:11:13
|
Revision: 230 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=230&view=rev Author: danxuliu Date: 2010-04-13 20:11:06 +0000 (Tue, 13 Apr 2010) Log Message: ----------- Add initial version of target application module to interact with the KTutorial editor support module in applications using KTutorial. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt Added Paths: ----------- trunk/ktutorial/ktutorial-editor/src/targetapplication/ trunk/ktutorial/ktutorial-editor/src/targetapplication/CMakeLists.txt trunk/ktutorial/ktutorial-editor/src/targetapplication/DBusException.cpp trunk/ktutorial/ktutorial-editor/src/targetapplication/DBusException.h trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.cpp trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.h trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEventSpy.cpp trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEventSpy.h trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObject.cpp trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObject.h trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObjectMapper.cpp trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObjectMapper.h trunk/ktutorial/ktutorial-editor/src/targetapplication/TargetApplication.cpp trunk/ktutorial/ktutorial-editor/src/targetapplication/TargetApplication.h trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/ trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/CMakeLists.txt trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/DBusExceptionTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/DummyApplication.cpp trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassStubs.h trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteEditorSupportTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteEventSpyTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteObjectMapperTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteObjectTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/TargetApplicationStub.cpp trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/TargetApplicationTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt 2010-04-13 18:49:12 UTC (rev 229) +++ trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt 2010-04-13 20:11:06 UTC (rev 230) @@ -9,6 +9,11 @@ add_subdirectory(serialization) add_subdirectory(view) +if (QT_QTDBUS_FOUND) + add_definitions(-DQT_QTDBUS_FOUND) + add_subdirectory(targetapplication) +endif (QT_QTDBUS_FOUND) + set(ktutorial_editor_SRCS EditActions.cpp Exception.cpp @@ -28,6 +33,11 @@ ktutorial_editor_view ) +if (QT_QTDBUS_FOUND) + target_link_libraries(ktutorial_editor ktutorial_editor_targetapplication) +endif (QT_QTDBUS_FOUND) + + kde4_add_executable(ktutorial-editor main.cpp) target_link_libraries(ktutorial-editor ktutorial_editor) Added: trunk/ktutorial/ktutorial-editor/src/targetapplication/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/CMakeLists.txt (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/CMakeLists.txt 2010-04-13 20:11:06 UTC (rev 230) @@ -0,0 +1,12 @@ +set(ktutorial_editor_targetapplication_SRCS + DBusException.cpp + RemoteEditorSupport.cpp + RemoteEventSpy.cpp + RemoteObject.cpp + RemoteObjectMapper.cpp + TargetApplication.cpp +) + +kde4_add_library(ktutorial_editor_targetapplication ${ktutorial_editor_targetapplication_SRCS}) + +target_link_libraries(ktutorial_editor_targetapplication ktutorial_editor ${QT_QTDBUS_LIBRARY} ${KDE4_KDECORE_LIBS}) Property changes on: trunk/ktutorial/ktutorial-editor/src/targetapplication/CMakeLists.txt ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/targetapplication/DBusException.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/DBusException.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/DBusException.cpp 2010-04-13 20:11:06 UTC (rev 230) @@ -0,0 +1,27 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "DBusException.h" + +//public: + +DBusException::DBusException(const QString& message): Exception(message) { +} + +DBusException::~DBusException() throw() { +} Property changes on: trunk/ktutorial/ktutorial-editor/src/targetapplication/DBusException.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/targetapplication/DBusException.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/DBusException.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/DBusException.h 2010-04-13 20:11:06 UTC (rev 230) @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef DBUSEXCEPTION_H +#define DBUSEXCEPTION_H + +#include "../Exception.h" + +/** + * Thrown when a DBus error happened. + */ +class DBusException: public Exception { +public: + + explicit DBusException(const QString& message = QString()); + virtual ~DBusException() throw(); + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/targetapplication/DBusException.h ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.cpp 2010-04-13 20:11:06 UTC (rev 230) @@ -0,0 +1,93 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "RemoteEditorSupport.h" + +#include <QDBusReply> + +#include "RemoteEventSpy.h" +#include "RemoteObject.h" +#include "RemoteObjectMapper.h" + +//public: + +RemoteEditorSupport::RemoteEditorSupport(const QString& service, + RemoteObjectMapper* mapper): + QDBusAbstractInterface(service, "/ktutorial", + "org.kde.ktutorial.EditorSupport", + QDBusConnection::sessionBus(), 0), + mMapper(mapper), + mRemoteEventSpy(0) { +} + +RemoteEditorSupport::~RemoteEditorSupport() { + delete mRemoteEventSpy; +} + +RemoteObject* RemoteEditorSupport::mainWindow() throw (DBusException) { + QDBusReply<int> reply = call("mainWindowObjectId"); + if (!reply.isValid()) { + throw DBusException(reply.error().message()); + } + + return mMapper->remoteObject(reply.value()); +} + +void RemoteEditorSupport::highlight(RemoteObject* remoteWidget) + throw (DBusException) { + QDBusReply<void> reply = call("highlight", remoteWidget->objectId()); + if (!reply.isValid()) { + throw DBusException(reply.error().message()); + } +} + +void RemoteEditorSupport::stopHighlighting(RemoteObject* remoteWidget) + throw (DBusException) { + QDBusReply<void> reply = call("stopHighlighting", remoteWidget->objectId()); + if (!reply.isValid()) { + throw DBusException(reply.error().message()); + } +} + +RemoteEventSpy* RemoteEditorSupport::enableEventSpy() throw (DBusException) { + if (mRemoteEventSpy) { + return mRemoteEventSpy; + } + + QDBusReply<void> reply = call("enableEventSpy"); + if (!reply.isValid()) { + throw DBusException(reply.error().message()); + } + + mRemoteEventSpy = new RemoteEventSpy(service(), mMapper); + return mRemoteEventSpy; +} + +void RemoteEditorSupport::disableEventSpy() throw (DBusException) { + if (!mRemoteEventSpy) { + return; + } + + QDBusReply<void> reply = call("disableEventSpy"); + if (!reply.isValid()) { + throw DBusException(reply.error().message()); + } + + delete mRemoteEventSpy; + mRemoteEventSpy = 0; +} Property changes on: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.h 2010-04-13 20:11:06 UTC (rev 230) @@ -0,0 +1,125 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef REMOTEEDITORSUPPORT_H +#define REMOTEEDITORSUPPORT_H + +#include <QDBusAbstractInterface> + +#include "DBusException.h" + +class RemoteEventSpy; +class RemoteObject; +class RemoteObjectMapper; + +/** + * Proxy for the remote EditorSupport exposed by KTutorial editor support module + * in KTutorial library. + * RemoteEditorSupport represents a remote EditorSupport exposed through DBus. + * Its purpose is provide an API to use the remote EditorSupport like any other + * local object, hiding the DBus complexity behind it. + * + * RemoteEditorSupport makes DBus calls to "org.kde.ktutorial.EditorSupport" + * interface in the DBus service specified in the constructor. + * + * Although the idea is let other objects use it like a local object, it has to + * communicate with the remote EditorSupport through DBus anyway, so the methods + * may throw a DBusException if something goes wrong. + */ +class RemoteEditorSupport: public QDBusAbstractInterface { +Q_OBJECT +public: + + /** + * Creates a new RemoteEditorSupport to represent a remote EditorSupport in + * the given DBus service. + * + * @param service The DBus service name. + * @param mapper The RemoteObjectMapper to get RemoteObjects from. + */ + RemoteEditorSupport(const QString& service, RemoteObjectMapper* mapper); + + /** + * Destroys this RemoteEditorSupport. + * The RemoteEventSpy is also destroyed, if any. + */ + virtual ~RemoteEditorSupport(); + + /** + * Returns the RemoteObject that represents the main window of the + * application. + * + * @return The RemoteObject for the main window. + * @throws DBusException If a DBus error happens. + */ + RemoteObject* mainWindow() throw (DBusException); + + /** + * Highlights the widget represented by the given remote object. + * If the object does not represent a widget nothing is highlighted. + * + * @param remoteWidget The RemoteObject for the widget to highlight. + * @throws DBusException If a DBus error happens. + */ + void highlight(RemoteObject* remoteWidget) throw (DBusException); + + /** + * Stops highlighting the widget represented by the given remote object. + * If the object does not represent a widget no highlighting is stopped. + * + * @param remoteWidget The RemoteObject for the widget to stop highlighting. + * @throws DBusException If a DBus error happens. + */ + void stopHighlighting(RemoteObject* remoteWidget) throw (DBusException); + + /** + * Enables the EventSpy in the remote EditorSupport and returns a proxy for + * it. + * If the EventSpy was already enabled, the already created proxy is + * returned again. + * The RemoteEventSpy is destroyed when the EventSpy is disabled or this + * RemoteEditorSupport destroyed, so consider using QPointer to store it. + * + * @return A proxy for the remote EventSpy. + * @throws DBusException If a DBus error happens. + */ + RemoteEventSpy* enableEventSpy() throw (DBusException); + + /** + * Disables the EventSpy in the remote EditorSupport and destroys the proxy + * for it. + * + * @throws DBusException If a DBus error happens. + */ + void disableEventSpy() throw (DBusException); + +private: + + /** + * The mapper that associates a RemoteObject with its object id. + */ + RemoteObjectMapper* mMapper; + + /** + * The RemoteEventSpy, if enabled. + */ + RemoteEventSpy* mRemoteEventSpy; + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.h ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEventSpy.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEventSpy.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEventSpy.cpp 2010-04-13 20:11:06 UTC (rev 230) @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "RemoteEventSpy.h" + +#include <QDBusInterface> + +#include "RemoteObjectMapper.h" + +//public: + +RemoteEventSpy::RemoteEventSpy(const QString& service, + RemoteObjectMapper* mapper): QObject(), + mMapper(mapper) { + + //RemoteEventSpy class can not inherit from QDBusInterface as that breaks + //the "magic" done by QDbusInterface (it redefines qt_metacall and things + //like that) and signals can not be connected so easily + QDBusInterface* interface = new QDBusInterface( + service, "/ktutorial/EventSpy", "org.kde.ktutorial.EventSpy", + QDBusConnection::sessionBus(), this); + connect(interface, SIGNAL(eventReceived(int, QString)), + this, SLOT(handleEventReceived(int, QString))); +} + +//private: + +void RemoteEventSpy::handleEventReceived(int objectId, + const QString& eventType) { + emit eventReceived(mMapper->remoteObject(objectId), eventType); +} Property changes on: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEventSpy.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEventSpy.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEventSpy.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEventSpy.h 2010-04-13 20:11:06 UTC (rev 230) @@ -0,0 +1,81 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef REMOTEEVENTSPY_H +#define REMOTEEVENTSPY_H + +#include <QObject> + +class RemoteObject; +class RemoteObjectMapper; + +/** + * Proxy for the remote EventSpy exposed by KTutorial editor support module in + * KTutorial library. + * RemoteEventSpy represents a remote EventSpy exposed through DBus. Its purpose + * is provide an API to use the remote EventSpy like any other local object, + * hiding the DBus complexity behind it. + * + * RemoteEventSpy handles the eventReceived signal emitted by + * "org.kde.ktutorial.EventSpy" interface in the DBus service specified in the + * constructor and emits an equivalent signal replacing the object id with a + * RemoteObject proxy. + */ +class RemoteEventSpy: public QObject { +Q_OBJECT +public: + + /** + * Creates a new RemoteEventSpy to represent a remote EventSpy in the given + * DBus service. + * + * @param service The DBus service name. + * @param mapper The RemoteObjectMapper to get RemoteObjects from. + */ + RemoteEventSpy(const QString& service, RemoteObjectMapper* mapper); + +Q_SIGNALS: + + /** + * Emitted when the remote object receives an event. + * + * @param remoteObject The proxy for the real remote object. + * @param eventType The type of the event received. + */ + void eventReceived(RemoteObject* remoteObject, const QString& eventType); + +private: + + /** + * The mapper that associates a RemoteObject with its object id. + */ + RemoteObjectMapper* mMapper; + +private Q_SLOTS: + + /** + * Handles an event reception notified by the EventSpy. + * + * @param objectId The id of the remote object that received the event. + * @param eventType The type of the event received. + */ + void handleEventReceived(int objectId, const QString& eventType); + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEventSpy.h ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObject.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObject.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObject.cpp 2010-04-13 20:11:06 UTC (rev 230) @@ -0,0 +1,74 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "RemoteObject.h" + +#include <QtDBus/QtDBus> + +#include "RemoteObjectMapper.h" + +//public: + +RemoteObject::RemoteObject(const QString& service, RemoteObjectMapper* mapper, + int objectId): + QDBusAbstractInterface(service, "/ktutorial/ObjectRegister", + "org.kde.ktutorial.ObjectRegister", + QDBusConnection::sessionBus(), 0), + mMapper(mapper), + mObjectId(objectId) { +} + +int RemoteObject::objectId() const { + return mObjectId; +} + +QString RemoteObject::name() throw (DBusException) { + QDBusReply<QString> reply = call("objectName", mObjectId); + if (!reply.isValid()) { + throw DBusException(reply.error().message()); + } + + return reply.value(); +} + +QString RemoteObject::className() throw (DBusException) { + QDBusReply<QString> reply = call("className", mObjectId); + if (!reply.isValid()) { + throw DBusException(reply.error().message()); + } + + return reply.value(); +} + +Q_DECLARE_METATYPE(QList<int>) + +QList<RemoteObject*> RemoteObject::children() throw (DBusException) { + qDBusRegisterMetaType< QList<int> >(); + + QDBusReply< QList<int> > reply = call("childObjectIds", mObjectId); + if (!reply.isValid()) { + throw DBusException(reply.error().message()); + } + + QList<RemoteObject*> children; + foreach (int childObjectId, reply.value()) { + children.append(mMapper->remoteObject(childObjectId)); + } + + return children; +} Property changes on: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObject.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObject.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObject.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObject.h 2010-04-13 20:11:06 UTC (rev 230) @@ -0,0 +1,105 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef REMOTEOBJECT_H +#define REMOTEOBJECT_H + +#include <QDBusAbstractInterface> + +#include "DBusException.h" + +class RemoteObjectMapper; + +/** + * Proxy for remote objects exposed by KTutorial editor support module in + * KTutorial library. + * RemoteObject represents a remote object exposed by ObjectRegister in + * KTutorial library through DBus. Its purpose is provide an API to use the + * remote object like any other local object, hiding the DBus complexity behind + * it. + * + * To get the data, RemoteObject makes DBus calls to the + * "org.kde.ktutorial.ObjectRegistry" interface in the DBus service specified in + * the constructor. + * + * Although the idea is let other objects use it like a local object, it has to + * communicate with the remote ObjectRegistry through DBus anyway, so the + * methods may throw a DBusException if something goes wrong. + */ +class RemoteObject: public QDBusAbstractInterface { +Q_OBJECT +public: + + /** + * Creates a new RemoteObject to represent the remote object with the given + * id in the given DBus service name. + * + * @param service The DBus service name. + * @param mapper The RemoteObjectMapper to get RemoteObjects from. + * @param objectId The id of the remote object. + */ + RemoteObject(const QString& service, RemoteObjectMapper* mapper, + int objectId); + + /** + * Returns the id of the remote object. + * + * @return The id of the remote object. + */ + int objectId() const; + + /** + * Returns the object name. + * + * @return The object name. + * @throws DBusException If a DBus error happens. + */ + QString name() throw (DBusException); + + /** + * Returns the class name. + * + * @return The class name. + * @throws DBusException If a DBus error happens. + */ + QString className() throw (DBusException); + + /** + * Returns a list with the RemoteObjects that represent the children of this + * remote object. + * + * @return The child remote objects. + * @throws DBusException If a DBus error happens. + */ + QList<RemoteObject*> children() throw (DBusException); + +private: + + /** + * The mapper that associates a RemoteObject with its object id. + */ + RemoteObjectMapper* mMapper; + + /** + * The id of the remote object. + */ + int mObjectId; + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObject.h ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObjectMapper.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObjectMapper.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObjectMapper.cpp 2010-04-13 20:11:06 UTC (rev 230) @@ -0,0 +1,49 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "RemoteObjectMapper.h" + +#include <QHash> + +#include "RemoteObject.h" + +//public: + +RemoteObjectMapper::RemoteObjectMapper(const QString& service): + mService(service) { +} + +RemoteObjectMapper::~RemoteObjectMapper() { + qDeleteAll(mRemoteObjects); +} + +RemoteObject* RemoteObjectMapper::remoteObject(int objectId) { + if (mRemoteObjects.contains(objectId)) { + return mRemoteObjects.value(objectId); + } + + RemoteObject* remoteObject = new RemoteObject(mService, this, objectId); + mRemoteObjects.insert(objectId, remoteObject); + + return remoteObject; +} + +void RemoteObjectMapper::clear() { + qDeleteAll(mRemoteObjects); + mRemoteObjects.clear(); +} Property changes on: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObjectMapper.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObjectMapper.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObjectMapper.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObjectMapper.h 2010-04-13 20:11:06 UTC (rev 230) @@ -0,0 +1,82 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef REMOTEOBJECTMAPPER_H +#define REMOTEOBJECTMAPPER_H + +#include <QHash> + +class RemoteObject; + +/** + * Map to get a RemoteObject from their objectId. + * The RemoteObjectMapper should be used to get all the RemoteObjects for its + * DBus service. It creates a new RemoteObject when there is no RemoteObject + * for the given id, or returns the previosly created one, depending on the + * case. + * + * The RemoteObjectMapper also has ownership of the RemoteObjects, so they are + * deleted when the mapper is cleared or destroyed. + */ +class RemoteObjectMapper { +public: + + /** + * Creates a new RemoteObjectMapper for the given DBus service name. + * + * @param service The DBus service name of the remote objects. + */ + RemoteObjectMapper(const QString& service); + + /** + * Destroys this RemoteObjectMapper. + * All the mapped RemoteObjects are also destroyed. + */ + ~RemoteObjectMapper(); + + /** + * Returns the RemoteObject associated with the given object id. + * The RemoteObject is destroyed when this RemoteObjectMapper is cleared or + * destroyed, so consider using QPointer to store it. + * + * @param objectId The id of the remote object. + * @return The RemoteObject. + */ + RemoteObject* remoteObject(int objectId); + + /** + * Destroys all the mapped RemoteObject. + */ + void clear(); + +private: + + /** + * The DBus service name of the remote objects. + */ + QString mService; + + /** + * All the RemoteObjects already requested since the last time this + * RemoteObjectMapper was cleared. + */ + QHash<int, RemoteObject*> mRemoteObjects; + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteObjectMapper.h ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/targetapplication/TargetApplication.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/TargetApplication.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/TargetApplication.cpp 2010-04-13 20:11:06 UTC (rev 230) @@ -0,0 +1,174 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "TargetApplication.h" + +#include <QtDBus/QtDBus> + +#include <KProcess> +#include <KUrl> + +#include "RemoteEditorSupport.h" +#include "RemoteObjectMapper.h" + +//public: + +TargetApplication* TargetApplication::self() { + return sSelf; +} + +TargetApplication::~TargetApplication() { + if (mProcess) { + mProcess->kill(); + mProcess->waitForFinished(100); + } +} + +QString TargetApplication::targetApplicationFilePath() const { + return mTargetApplicationFilePath; +} + +void TargetApplication::setTargetApplicationFilePath( + const QString& targetApplicationFilePath) { + KUrl url(targetApplicationFilePath); + url.cleanPath(); + + if (url.isRelative()) { + mTargetApplicationFilePath = ""; + } else { + mTargetApplicationFilePath = url.toLocalFile(); + } +} + +RemoteEditorSupport* TargetApplication::remoteEditorSupport() { + return mRemoteEditorSupport; +} + +void TargetApplication::start() { + if (mProcess && mProcess->program()[0] == mTargetApplicationFilePath) { + return; + } + + if (!QDBusConnection::sessionBus().isConnected()) { + emit startFailed(NoDBusConnection); + return; + } + + if (mProcess) { + mProcess->kill(); + //Don't start the new target application until the old one is dead. + //It may freeze the editor GUI, but it is unlikely that a process gets + //enough time being killed to be noticed + mProcess->waitForFinished(-1); + } + + mProcess = new KProcess(this); + mProcess->setProgram(mTargetApplicationFilePath); + + mServiceName.clear(); + + QDBusConnectionInterface* interface = + QDBusConnection::sessionBus().interface(); + connect(interface, SIGNAL(serviceRegistered(QString)), + this, SLOT(checkNewService(QString))); + connect(interface, SIGNAL(serviceOwnerChanged(QString, QString, QString)), + this, SLOT(checkNewService(QString))); + + connect(mProcess, SIGNAL(error(QProcess::ProcessError)), + this, SLOT(handleProcessError(QProcess::ProcessError))); + + connect(mProcess, SIGNAL(finished(int)), + this, SLOT(clean())); + + mServiceDiscoveryTimer.setInterval(3000); + mServiceDiscoveryTimer.setSingleShot(true); + connect(mProcess, SIGNAL(started()), + &mServiceDiscoveryTimer, SLOT(start())); + connect(&mServiceDiscoveryTimer, SIGNAL(timeout()), + this, SLOT(handleTargetApplicationDoesNotSupportKTutorial())); + + mProcess->start(); +} + +//private: + +TargetApplication* TargetApplication::sSelf = new TargetApplication(); + +TargetApplication::TargetApplication(): + mProcess(0), + mMapper(0), + mRemoteEditorSupport(0) { +} + +//private slots: + +void TargetApplication::checkNewService(const QString& service) { + QDBusInterface interface(service, "/ktutorial", + "org.kde.ktutorial.EditorSupport"); + if (!interface.isValid()) { + return; + } + + QDBusReply<QString> reply = interface.call("applicationFilePath"); + if (!reply.isValid()) { + return; + } + + if (reply.value() != mTargetApplicationFilePath) { + return; + } + + mServiceDiscoveryTimer.stop(); + + mServiceName = service; + mMapper = new RemoteObjectMapper(mServiceName); + mRemoteEditorSupport = new RemoteEditorSupport(mServiceName, mMapper); + + emit started(); + + disconnect(QDBusConnection::sessionBus().interface(), 0, this, 0); +} + +void TargetApplication::handleProcessError(QProcess::ProcessError error) { + if (error != QProcess::FailedToStart) { + return; + } + + mServiceDiscoveryTimer.stop(); + + emit startFailed(InvalidPath); +} + +void TargetApplication::handleTargetApplicationDoesNotSupportKTutorial() { + mProcess->kill(); + + emit startFailed(InvalidApplication); +} + +void TargetApplication::clean() { + //Don't delete it directly, as waitForFinished crashes somewhere internally + //due to an event problem + mProcess->deleteLater(); + mProcess = 0; + delete mRemoteEditorSupport; + mRemoteEditorSupport = 0; + delete mMapper; + mMapper = 0; + + emit finished(); +} Property changes on: trunk/ktutorial/ktutorial-editor/src/targetapplication/TargetApplication.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/targetapplication/TargetApplication.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/TargetApplication.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/TargetApplication.h 2010-04-13 20:11:06 UTC (rev 230) @@ -0,0 +1,238 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef TARGETAPPLICATION_H +#define TARGETAPPLICATION_H + +#include <QObject> +#include <QProcess> +#include <QTimer> + +class KProcess; +class RemoteEditorSupport; +class RemoteObjectMapper; + +/** + * Class to execute a target application and communicate with it through D-Bus. + * The target application is the application that the tutorial will be part of. + * Using TargetApplication class a new instance of a target application can be + * executed and, through D-Bus, KTutorial editor can communicate with it to + * introspect its structure. The target application must have KTutorial enabled + * in order to use the KTutorial editor support module. Applications that do not + * use KTutorial can not be introspected. + * + * Knowing the structure of the target application, KTutorial editor can provide + * valuable information to the tutorial author like the name of an object or its + * class, so the tutorial author can design the tutorial more easily. + * + * The TargetApplication can be started using method start(). The method returns + * immediately, and when the application is really running the started() signal + * is emitted. If the application could not be executed, or it was executed but + * other problem happened (for example, if the target application does not + * support KTutorial), startFailed(Error) signal is emitted instead. + * + * Once the target application has been started, remoteEditorSupport + * returns a RemoteEditorSupport connected to the remote + * "org.kde.ktutorial.EditorSupport" interface exposed by the target + * application. + * + * The target application will be killed when the TargetApplication is + * destroyed, or when the start method is called again after setting a different + * application file path. In any of those cases, or if the target application + * was closed externally (by the user), finished() signal is emitted. + */ +class TargetApplication: public QObject { +Q_OBJECT +public: + + /** + * The type of error that made starting the target application fail. + */ + enum Error { + + /** + * The application was started, but it does not support KTutorial. + */ + InvalidApplication, + + /** + * The application was not even started. + */ + InvalidPath, + + /** + * The application was started, but there is no D-Bus connection to + * communicate with it. + */ + NoDBusConnection + }; + + /** + * Returns the only instance of TargetApplication class. + * + * @return The TargetApplication instance. + */ + static TargetApplication* self(); + + /** + * Destroys this TargetApplication. + * If the target application is running, it is killed. + */ + virtual ~TargetApplication(); + + /** + * Returns the executable for the target application. + * + * @return The target application file path. + */ + QString targetApplicationFilePath() const; + + /** + * Sets the executable for the target application. + * The executable must be an absolute path. A relative path will be set as + * an empty string. If the path is absolute but contains "." and ".." + * components they are resolved and the clean path is set. + * + * @param applicationFilePath The target application file path. + */ + void setTargetApplicationFilePath(const QString& targetApplicationFilePath); + + /** + * Returns the RemoteEditorSupport for the target application. + * If the application is not running a null pointer is returned. + * + * @return The RemoteEditorSupport for the target application. + */ + RemoteEditorSupport* remoteEditorSupport(); + + /** + * Starts a new TargetApplication. + * When the target application is running, started() signal is emitted. If + * there is no application file path, the application file path is not valid + * or the application does not support KTutorial editor, startFailed(Error) + * signal is emitted instead. + * + * If the target application was already started nothing is done (even + * started() signal is not emitted). + */ + void start(); + +Q_SIGNALS: + + /** + * Emitted when the target application was started and there is a D-Bus + * connection to it. + */ + void started(); + + /** + * Emitted when the target application could not be started successfully. + * + * @param error The type of error that happened. + */ + void startFailed(TargetApplication::Error error); + + /** + * Emitted when the target application was finished for any reason. + */ + void finished(); + +private: + + /** + * The only instance of TargetApplication. + */ + static TargetApplication* sSelf; + + /** + * The executable for the target application. + */ + QString mTargetApplicationFilePath; + + /** + * The process executing the target application, if any. + */ + KProcess* mProcess; + + /** + * Timer to give time to "/ktutorial" object to appear in some new service + * of the bus. + * If the timer ends and the object was not found, the target application + * seems to not to support KTutorial editor. + */ + QTimer mServiceDiscoveryTimer; + + /** + * The D-Bus service name provided by the target application, if any. + */ + QString mServiceName; + + /** + * The mapper that associates RemoteObjects with their object id. + */ + RemoteObjectMapper* mMapper; + + /** + * The RemoteEditorSupport for the target application, if any. + */ + RemoteEditorSupport* mRemoteEditorSupport; + + /** + * Creats a new TargetApplication. + * Hidden to avoid classes other than TargetApplication itself to create + * objects of it. + */ + TargetApplication(); + +private Q_SLOTS: + + /** + * Checks if the new service found in the session bus is the one from the + * started target application. + * When the service is found, the target application has started from + * KTutorial editor point of view. Signal started() is emitted in that case. + * + * @param service The D-Bus service to check. + */ + void checkNewService(const QString& service); + + /** + * Checks if the process could not be started. + * Signal startFailed(Error), with InvalidPath, is emitted in that case. + * + * @param error The process error. + */ + void handleProcessError(QProcess::ProcessError error); + + /** + * Called when the time out to find the D-Bus service expired. + * Signal startFailed(Error), with InvalidApplication, is emitted in that + * case. + */ + void handleTargetApplicationDoesNotSupportKTutorial(); + + /** + * Called when the process has finished. + * The process, mapper and remote editor support are deleted, and the + * finished() signal is emitted. + */ + void clean(); + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/targetapplication/TargetApplication.h ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt 2010-04-13 18:49:12 UTC (rev 229) +++ trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt 2010-04-13 20:11:06 UTC (rev 230) @@ -1,6 +1,9 @@ add_subdirectory(commands) add_subdirectory(data) add_subdirectory(serialization) +if (QT_QTDBUS_FOUND) + add_subdirectory(targetapplication) +endif (QT_QTDBUS_FOUND) add_subdirectory(view) # Used by kde4_add_unit_test to set the full path to test executables Added: trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/CMakeLists.txt (rev 0) +++ trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/CMakeLists.txt 2010-04-13 20:11:06 UTC (rev 230) @@ -0,0 +1,47 @@ +# Used by kde4_add_unit_test to set the full path to test executables +set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) + +include_directories(${ktutorial-editor_SOURCE_DIR}/src/targetapplication ${KDE4_INCLUDES}) + +# Remote class stubs are QObjects, so moc files have to be generated for them +qt4_wrap_cpp(dbus_interface_stubs_MOC RemoteClassStubs.h) + +# Dummy application to be executed in TargetApplication test +add_executable(DummyApplication DummyApplication.cpp) +target_link_libraries(DummyApplication ${KDE4_KDEUI_LIBS} ${QT_QTDBUS_LIBRARY}) + +# Target application stub to be executed in TargetApplication test +add_executable(TargetApplicationStub TargetApplicationStub.cpp ${dbus_interface_stubs_MOC}) +target_link_libraries(TargetApplicationStub ${KDE4_KDEUI_LIBS} ${QT_QTDBUS_LIBRARY}) + +MACRO(UNIT_TESTS) + FOREACH(_className ${ARGN}) + set(_testName ${_className}Test) + kde4_add_unit_test(${_testName} TESTNAME ktutorial-editor-unit-${_testName} ${_testName}.cpp ${dbus_interface_stubs_MOC}) + target_link_libraries(${_testName} ktutorial_editor_targetapplication ${QT_QTTEST_LIBRARY}) + ENDFOREACH(_className) +ENDMACRO(UNIT_TESTS) + +unit_tests( + DBusException + RemoteEditorSupport + RemoteEventSpy + RemoteObject + RemoteObjectMapper + TargetApplication +) + +MACRO(MEM_TESTS) + FOREACH(_testname ${ARGN}) + add_test(ktutorial-editor-unit-mem-${_testname} ${CMAKE_CURRENT_SOURCE_DIR}/../runMemcheck.py ${CMAKE_CURRENT_BINARY_DIR}/${_testname}Test ${CMAKE_CURRENT_BINARY_DIR}) + ENDFOREACH(_testname) +ENDMACRO(MEM_TESTS) + +mem_tests( + DBusException + RemoteEditorSupport + RemoteEventSpy + RemoteObject + RemoteObjectMapper + TargetApplication +) Property changes on: trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/CMakeLists.txt ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/DBusExceptionTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/DBusExceptionTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/DBusExceptionTest.cpp 2010-04-13 20:11:06 UTC (rev 230) @@ -0,0 +1,49 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include <QtTest> + +#include "DBusException.h" + +class DBusExceptionTest: public QObject { +Q_OBJECT + +private slots: + + void testConstructor(); + void testConstructorEmpty(); + +}; + +void DBusExceptionTest::testConstructor() { + DBusException exception(QString("The message")); + + QCOMPARE(exception.what(), "The message"); + QCOMPARE(exception.message(), QString("The message")); +} + +void DBusExceptionTest::testConstructorEmpty() { + DBusException exception; + + QCOMPARE(exception.what(), ""); + QCOMPARE(exception.message(), QString("")); +} + +QTEST_MAIN(DBusExceptionTest) + +#include "DBusExceptionTest.moc" Property changes on: trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/DBusExceptionTest.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/DummyApplication.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/DummyApplication.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/DummyApplication.cpp 2010-04-13 20:11:06 UTC (rev 230) @@ -0,0 +1,32 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License a... [truncated message content] |
From: <dan...@us...> - 2010-04-13 18:49:19
|
Revision: 229 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=229&view=rev Author: danxuliu Date: 2010-04-13 18:49:12 +0000 (Tue, 13 Apr 2010) Log Message: ----------- Add initial version of KTutorial editor support module to be able to introspect a running application that uses KTutorial from KTutorial editor. The purpose is ease the design of tutorials being able to know, for example, the name of the objects accessible by KTutorial in the application. Modified Paths: -------------- trunk/ktutorial/ktutorial-library/src/CMakeLists.txt trunk/ktutorial/ktutorial-library/src/KTutorial.cpp trunk/ktutorial/ktutorial-library/tests/CMakeLists.txt Added Paths: ----------- trunk/ktutorial/ktutorial-library/src/editorsupport/ trunk/ktutorial/ktutorial-library/src/editorsupport/CMakeLists.txt trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupport.cpp trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupport.h trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupportAdaptor.cpp trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupportAdaptor.h trunk/ktutorial/ktutorial-library/src/editorsupport/EventSpy.cpp trunk/ktutorial/ktutorial-library/src/editorsupport/EventSpy.h trunk/ktutorial/ktutorial-library/src/editorsupport/EventSpyAdaptor.cpp trunk/ktutorial/ktutorial-library/src/editorsupport/EventSpyAdaptor.h trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.cpp trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.h trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegisterAdaptor.cpp trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegisterAdaptor.h trunk/ktutorial/ktutorial-library/tests/editorsupport/ trunk/ktutorial/ktutorial-library/tests/editorsupport/CMakeLists.txt trunk/ktutorial/ktutorial-library/tests/editorsupport/EditorSupportAdaptorTest.cpp trunk/ktutorial/ktutorial-library/tests/editorsupport/EditorSupportTest.cpp trunk/ktutorial/ktutorial-library/tests/editorsupport/EventSpyAdaptorTest.cpp trunk/ktutorial/ktutorial-library/tests/editorsupport/EventSpyTest.cpp trunk/ktutorial/ktutorial-library/tests/editorsupport/ObjectRegisterAdaptorTest.cpp trunk/ktutorial/ktutorial-library/tests/editorsupport/ObjectRegisterTest.cpp Modified: trunk/ktutorial/ktutorial-library/src/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-library/src/CMakeLists.txt 2010-04-13 18:06:28 UTC (rev 228) +++ trunk/ktutorial/ktutorial-library/src/CMakeLists.txt 2010-04-13 18:49:12 UTC (rev 229) @@ -7,6 +7,11 @@ add_subdirectory(tutorials) add_subdirectory(view) +if (QT_QTDBUS_FOUND) + add_definitions(-DQT_QTDBUS_FOUND) + add_subdirectory(editorsupport) +endif (QT_QTDBUS_FOUND) + include_directories(${CMAKE_CURRENT_BINARY_DIR} ${KDE4_INCLUDES}) set(ktutorial_LIB_SRCS @@ -29,6 +34,10 @@ target_link_libraries(ktutorial ktutorial_scripting ktutorial_tutorials ktutorial_view) +if (QT_QTDBUS_FOUND) + target_link_libraries(ktutorial ktutorial_editorsupport) +endif (QT_QTDBUS_FOUND) + ####### Install the library ####### install(TARGETS ktutorial DESTINATION ${LIB_INSTALL_DIR}) Modified: trunk/ktutorial/ktutorial-library/src/KTutorial.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/KTutorial.cpp 2010-04-13 18:06:28 UTC (rev 228) +++ trunk/ktutorial/ktutorial-library/src/KTutorial.cpp 2010-04-13 18:49:12 UTC (rev 229) @@ -29,6 +29,10 @@ #include "view/StepWidget.h" #include "view/TutorialManagerDialog.h" +#ifdef QT_QTDBUS_FOUND +#include "editorsupport/EditorSupport.h" +#endif + using scripting::ScriptingModule; using scripting::ScriptManager; using view::StepWidget; @@ -72,6 +76,10 @@ registerTutorial(new UsingKTutorial()); ScriptManager().loadTutorials(mTutorialmanager); + +#ifdef QT_QTDBUS_FOUND + (new editorsupport::EditorSupport(this))->setup(window); +#endif } //private: Added: trunk/ktutorial/ktutorial-library/src/editorsupport/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/CMakeLists.txt (rev 0) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/CMakeLists.txt 2010-04-13 18:49:12 UTC (rev 229) @@ -0,0 +1,18 @@ +include_directories(${CMAKE_CURRENT_BINARY_DIR} ${KDE4_INCLUDES}) + +set(ktutorial_editorsupport_SRCS + EditorSupport.cpp + EditorSupportAdaptor.cpp + EventSpy.cpp + EventSpyAdaptor.cpp + ObjectRegister.cpp + ObjectRegisterAdaptor.cpp +) + +kde4_add_library(ktutorial_editorsupport ${ktutorial_editorsupport_SRCS}) + +target_link_libraries(ktutorial_editorsupport + ktutorial_extendedinformation + ${QT_QTDBUS_LIBRARY} + ${KDE4_KDECORE_LIBS} +) Property changes on: trunk/ktutorial/ktutorial-library/src/editorsupport/CMakeLists.txt ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupport.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupport.cpp (rev 0) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupport.cpp 2010-04-13 18:49:12 UTC (rev 229) @@ -0,0 +1,102 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include <QWidget> +#include <QtDBus/QtDBus> + +#include <KDebug> + +#include "EditorSupport.h" +#include "EditorSupportAdaptor.h" +#include "EventSpy.h" +#include "EventSpyAdaptor.h" +#include "ObjectRegister.h" +#include "ObjectRegisterAdaptor.h" +#include "../extendedinformation/WidgetHighlighterManager.h" + +using extendedinformation::WidgetHighlighterManager; + +namespace editorsupport { + +//public: + +EditorSupport::EditorSupport(QObject* parent /*= 0*/): QObject(parent), + mObjectRegister(0), + mEventSpy(0) { +} + +void EditorSupport::setup(QObject* window) { + if (!QDBusConnection::sessionBus().isConnected()) { + kWarning() << "Cannot connect to the D-Bus session bus!\n" + << "KTutorial editor support will not be enabled"; + return; + } + + mWindow = window; + + new EditorSupportAdaptor(this); + QDBusConnection::sessionBus().registerObject("/ktutorial", this); + + mObjectRegister = new ObjectRegister(this); + new ObjectRegisterAdaptor(mObjectRegister); + + QDBusConnection::sessionBus().registerObject("/ktutorial/ObjectRegister", + mObjectRegister); +} + +int EditorSupport::mainWindowObjectId() { + return mObjectRegister->idForObject(mWindow); +} + +void EditorSupport::highlight(int objectId) { + QObject* object = mObjectRegister->objectForId(objectId); + QWidget* widget = qobject_cast<QWidget*>(object); + if (!widget) { + return; + } + + WidgetHighlighterManager::self()->highlight(widget); +} + +void EditorSupport::stopHighlighting(int objectId) { + QObject* object = mObjectRegister->objectForId(objectId); + QWidget* widget = qobject_cast<QWidget*>(object); + if (!widget) { + return; + } + + WidgetHighlighterManager::self()->stopHighlighting(widget); +} + +void EditorSupport::enableEventSpy() { + mEventSpy = new EventSpy(this); + mEventSpy->addObjectToSpy(mWindow); + new EventSpyAdaptor(mEventSpy, mObjectRegister); + + QDBusConnection::sessionBus().registerObject("/ktutorial/EventSpy", + mEventSpy); +} + +void EditorSupport::disableEventSpy() { + QDBusConnection::sessionBus().unregisterObject("/ktutorial/EventSpy"); + + delete mEventSpy; + mEventSpy = 0; +} + +} Property changes on: trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupport.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupport.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupport.h (rev 0) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupport.h 2010-04-13 18:49:12 UTC (rev 229) @@ -0,0 +1,137 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef EDITORSUPPORT_EDITORSUPPORT_H +#define EDITORSUPPORT_EDITORSUPPORT_H + +#include <QObject> + +namespace editorsupport { +class EventSpy; +class EventSupportAdaptor; +class ObjectRegister; +} + +namespace editorsupport { + +/** + * Support module for KTutorial editor to be accessed through D-Bus. + * EditorSupport provides a way to introspect a running application from + * KTutorial editor to help the author to design a tutorial. + * + * EditorSupport is composed by three elements: the main object (this class), + * an object register and an event spy. + * + * The main object sets up the D-Bus objects and provides a way to enable and + * disable the EventSpy (as notifying all the events sent by an application + * through D-Bus is very costly, the EventSpy should be enabled only when + * needed), and highlight and stop the highlighting of widgets. + * + * The object register assigns an id to QObjects to be identified by the remote + * KTutorial editor. Using that id, KTutorial editor can request further + * information about an object to the ObjectRegister (for example, the object + * name or the class name of an object). + * + * The event spy filters all the events received by the main window and, + * recursively, all its children objects. It is used in the remote KTutorial + * editor to know, for example, that some widget got the focus, or that the + * mouse entered in some widget. Using the information provided by the EventSpy, + * the KTutorial editor can provide a way to the tutorial author to select + * widgets directly from a running application just with the mouse. + * + * The main object is registered at "/ktutorial" path, and provides the + * "org.kde.ktutorial.EditorSupport" interface. The object register is + * registered at "/ktutorial/ObjectRegister" path and provides the + * "org.kde.ktutorial.ObjectRegister" interface. Finally, when it is enabled, + * the EventSpy is registered at "/ktutorial/EVentSpy" path and provides the + * "org.kde.ktutorial.EventSpy" interface. + */ +class EditorSupport: public QObject { +Q_OBJECT +public: + + /** + * Creates a new EditorSupport with the given parent. + * + * @param parent The parent QObject. + */ + explicit EditorSupport(QObject* parent = 0); + + /** + * Exposes the editor support interfaces through DBus. + * The window and all its children will be spied when EventSpy is enabled. + * + * @param window The main window in the application. + */ + void setup(QObject* window); + + /** + * Returns the object id of the application main window. + * + * @return The object id of the application main window. + */ + int mainWindowObjectId(); + + /** + * Starts the highlighting animation for the widget associated to the given + * id. + * + * @param objectId The id of the widget to highlight. + */ + void highlight(int objectId); + + /** + * Stops the highlighting animation for the widget associated to the given + * id. + * + * @param objectId The id of the widget to stop highlighting. + */ + void stopHighlighting(int objectId); + + /** + * Enables the EventSpy. + */ + void enableEventSpy(); + + /** + * Disables the EventSpy. + */ + void disableEventSpy(); + +private: + + /** + * The object register. + */ + ObjectRegister* mObjectRegister; + + /** + * The event spy. + */ + EventSpy* mEventSpy; + + /** + * The object to spy its events and the events of its children. + */ + QObject* mWindow; + +}; + +} + +#endif Property changes on: trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupport.h ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupportAdaptor.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupportAdaptor.cpp (rev 0) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupportAdaptor.cpp 2010-04-13 18:49:12 UTC (rev 229) @@ -0,0 +1,60 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include <QCoreApplication> + +#include "EditorSupportAdaptor.h" +#include "EditorSupport.h" +#include "ObjectRegister.h" + +namespace editorsupport { + +//public: + +EditorSupportAdaptor::EditorSupportAdaptor(EditorSupport* editorSupport): + QDBusAbstractAdaptor(editorSupport), + mEditorSupport(editorSupport) { +} + +//public slots: + +QString EditorSupportAdaptor::applicationFilePath() const { + return QCoreApplication::applicationFilePath(); +} + +int EditorSupportAdaptor::mainWindowObjectId() const { + return mEditorSupport->mainWindowObjectId(); +} + +void EditorSupportAdaptor::highlight(int objectId) { + mEditorSupport->highlight(objectId); +} + +void EditorSupportAdaptor::stopHighlighting(int objectId) { + mEditorSupport->stopHighlighting(objectId); +} + +void EditorSupportAdaptor::enableEventSpy() { + mEditorSupport->enableEventSpy(); +} + +void EditorSupportAdaptor::disableEventSpy() { + mEditorSupport->disableEventSpy(); +} + +} Property changes on: trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupportAdaptor.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupportAdaptor.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupportAdaptor.h (rev 0) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupportAdaptor.h 2010-04-13 18:49:12 UTC (rev 229) @@ -0,0 +1,101 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef EDITORSUPPORT_EDITORSUPPORTADAPTOR_H +#define EDITORSUPPORT_EDITORSUPPORTADAPTOR_H + +#include <QDBusAbstractAdaptor> + +namespace editorsupport { +class EditorSupport; +class ObjectRegister; +} + +namespace editorsupport { + +/** + * Adaptor to expose an EditorSupport through DBus. + * + * @see EditorSupport + */ +class EditorSupportAdaptor: public QDBusAbstractAdaptor { +Q_OBJECT +Q_CLASSINFO("D-Bus Interface", "org.kde.ktutorial.EditorSupport") +public: + + /** + * Creates a new EditorSupportAdaptor for the given EditorSupport. + * + * @param editorSupport The EditorSupport to adapt. + */ + explicit EditorSupportAdaptor(EditorSupport* editorSupport); + +public Q_SLOTS: + + /** + * Returns the path to the application file. + * + * @return The path to the application file. + */ + QString applicationFilePath() const; + + /** + * Returns the object id of the application main window. + * + * @return The object id of the application main window. + */ + int mainWindowObjectId() const; + + /** + * Starts the highlighting animation for the widget associated to the given + * id. + * + * @param objectId The id of the widget to highlight. + */ + void highlight(int objectId); + + /** + * Stops the highlighting animation for the widget associated to the given + * id. + * + * @param objectId The id of the widget to stop highlighting. + */ + void stopHighlighting(int objectId); + + /** + * Enables the EventSpy. + */ + void enableEventSpy(); + + /** + * Disables the EventSpy. + */ + void disableEventSpy(); + +private: + + /** + * The EditorSupport to adapt. + */ + EditorSupport* mEditorSupport; + +}; + +} + +#endif Property changes on: trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupportAdaptor.h ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-library/src/editorsupport/EventSpy.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/EventSpy.cpp (rev 0) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/EventSpy.cpp 2010-04-13 18:49:12 UTC (rev 229) @@ -0,0 +1,50 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include <QEvent> + +#include "EventSpy.h" + +namespace editorsupport { + +//public: + +EventSpy::EventSpy(QObject* parent /*= 0*/): QObject(parent) { +} + +void EventSpy::addObjectToSpy(QObject* object) { + object->installEventFilter(this); + + foreach (QObject* child, object->children()) { + addObjectToSpy(child); + } +} + +//protected: + +bool EventSpy::eventFilter(QObject* object, QEvent* event) { + emit eventReceived(object, event); + + if (event->type() == QEvent::ChildAdded) { + addObjectToSpy(static_cast<QChildEvent*>(event)->child()); + } + + return false; +} + +} Property changes on: trunk/ktutorial/ktutorial-library/src/editorsupport/EventSpy.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-library/src/editorsupport/EventSpy.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/EventSpy.h (rev 0) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/EventSpy.h 2010-04-13 18:49:12 UTC (rev 229) @@ -0,0 +1,77 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef EDITORSUPPORT_EVENTSPY_H +#define EDITORSUPPORT_EVENTSPY_H + +#include <QObject> + +namespace editorsupport { + +/** + * Spy to know all the events received in an object hierarchy. + * EventSpy emitts a signal whenever an event is received in any of the spied + * objects or its children (recursively). Even children added to a spied object + * after it was added are spied. + */ +class EventSpy: public QObject { +Q_OBJECT +public: + + /** + * Creates a new EventSpy with the given parent. + * + * @param parent The parent QObject. + */ + explicit EventSpy(QObject* parent = 0); + + /** + * Add object and all its children to spy. + * + * @param object The object to spy. + */ + void addObjectToSpy(QObject* object); + +Q_SIGNALS: + + /** + * Emitted when an event is received in any of the spied objects or their + * children. + * + * @param object The object that received the event. + * @param event The event received. + */ + void eventReceived(QObject* object, QEvent* event); + +protected: + + /** + * Filters the events received in the spied object hierarchies. + * A eventReceived(QObject*, QEvent*) is emitted for each event. + * + * @param object The object that received the event. + * @param event The event received. + * @return False, the let events be handled as necessary. + */ + virtual bool eventFilter(QObject* object, QEvent* event); + +}; + +} + +#endif Property changes on: trunk/ktutorial/ktutorial-library/src/editorsupport/EventSpy.h ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-library/src/editorsupport/EventSpyAdaptor.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/EventSpyAdaptor.cpp (rev 0) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/EventSpyAdaptor.cpp 2010-04-13 18:49:12 UTC (rev 229) @@ -0,0 +1,50 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include <QEvent> +#include <QMetaEnum> + +#include "EventSpyAdaptor.h" +#include "EventSpy.h" +#include "ObjectRegister.h" + +namespace editorsupport { + +//public: + +EventSpyAdaptor::EventSpyAdaptor(EventSpy* eventSpy, + ObjectRegister* objectRegister): + QDBusAbstractAdaptor(eventSpy), + mObjectRegister(objectRegister) { + connect(eventSpy, SIGNAL(eventReceived(QObject*,QEvent*)), + this, SLOT(handleEventReceived(QObject*,QEvent*))); +} + +//private: + +void EventSpyAdaptor::handleEventReceived(QObject* object, QEvent* event) { + int id = mObjectRegister->idForObject(object); + + int index = QEvent::staticMetaObject.indexOfEnumerator("Type"); + QMetaEnum eventTypeEnumerator = QEvent::staticMetaObject.enumerator(index); + QString eventType = eventTypeEnumerator.valueToKey(event->type()); + + emit eventReceived(id, eventType); +} + +} Property changes on: trunk/ktutorial/ktutorial-library/src/editorsupport/EventSpyAdaptor.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-library/src/editorsupport/EventSpyAdaptor.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/EventSpyAdaptor.h (rev 0) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/EventSpyAdaptor.h 2010-04-13 18:49:12 UTC (rev 229) @@ -0,0 +1,83 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef EDITORSUPPORT_EVENTSPYADAPTOR_H +#define EDITORSUPPORT_EVENTSPYADAPTOR_H + +#include <QDBusAbstractAdaptor> + +namespace editorsupport { +class EventSpy; +class ObjectRegister; +} + +namespace editorsupport { + +/** + * Adaptor to expose an EventSpy through DBus. + * + * @see EditorSupport + */ +class EventSpyAdaptor: public QDBusAbstractAdaptor { +Q_OBJECT +Q_CLASSINFO("D-Bus Interface", "org.kde.ktutorial.EventSpy") +public: + + /** + * Creates a new EventSpyAdaptor for the given EventSpy. + * + * @param eventSpy The EventSpy to adapt. + * @param objectRegister The object register to get the object ids from. + */ + explicit EventSpyAdaptor(EventSpy* eventSpy, + ObjectRegister* objectRegister); + +Q_SIGNALS: + + /** + * Emitted when an event is received in any of the spied objects or their + * children. + * + * @param objectId The id of the object that received the event. + * @param eventType The type of the event received. + */ + void eventReceived(int objectId, const QString& eventType); + +private: + + /** + * The register to associate objects with their id. + */ + ObjectRegister* mObjectRegister; + +private Q_SLOTS: + + /** + * Adapts the eventReceived(QObject*, QEvent*) sent by the EventSpy to be + * sent as eventReceived(int, QString). + * + * @param object The object that received the event. + * @param event The event received. + */ + void handleEventReceived(QObject* object, QEvent* event); + +}; + +} + +#endif Property changes on: trunk/ktutorial/ktutorial-library/src/editorsupport/EventSpyAdaptor.h ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.cpp (rev 0) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.cpp 2010-04-13 18:49:12 UTC (rev 229) @@ -0,0 +1,61 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "ObjectRegister.h" + +namespace editorsupport { + +//public: + +ObjectRegister::ObjectRegister(QObject* parent /*= 0*/): QObject(parent), + mNextId(1) { +} + +int ObjectRegister::idForObject(QObject* object) { + int id = mRegisteredIds.value(object); + + if (!id) { + id = mNextId; + mRegisteredObjects.insert(id, object); + mRegisteredIds.insert(object, id); + connect(object, SIGNAL(destroyed(QObject*)), + this, SLOT(deregister(QObject*))); + mNextId++; + } + + return id; +} + +QObject* ObjectRegister::objectForId(int objectId) { + return mRegisteredObjects.value(objectId); +} + +void ObjectRegister::clear() { + mRegisteredIds.clear(); + mRegisteredObjects.clear(); +} + +//private slots: + +void ObjectRegister::deregister(QObject* object) { + int id = mRegisteredIds.value(object); + mRegisteredIds.remove(object); + mRegisteredObjects.remove(id); +} + +} Property changes on: trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.h (rev 0) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.h 2010-04-13 18:49:12 UTC (rev 229) @@ -0,0 +1,99 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef EDITORSUPPORT_OBJECTREGISTER_H +#define EDITORSUPPORT_OBJECTREGISTER_H + +#include <QHash> +#include <QObject> + +namespace editorsupport { + +/** + * Register to associate objects with an id. + * The id for an object is assigned after the first time the id is requested + * for that object, and are valid until the register is cleared or the object is + * destroyed (if an object is destroyed it is automatically removed from the + * register). + * + * Its purpose is assign QObjects an id to allow the remote KTutorial editor to + * refer to the objects in the target application. + */ +class ObjectRegister: public QObject { +Q_OBJECT +public: + + /** + * Creates a new ObjectRegister with the given parent. + * + * @param parent The parent QObject. + */ + explicit ObjectRegister(QObject* parent = 0); + + /** + * Returns the id assigned to the object. + * + * @param object The object to get its id. + * @return The id assigned to the object. + */ + int idForObject(QObject* object); + + /** + * Returns object associated to the id. + * + * @param objectId The id to get its associated object. + * @return The object associated to the id. + */ + QObject* objectForId(int objectId); + + /** + * Removes all the entries in this ObjectRegister. + */ + void clear(); + +private: + + /** + * The next id to assign. + */ + int mNextId; + + /** + * The registered ids mapped by associated object. + */ + QHash<QObject*, int> mRegisteredIds; + + /** + * The registered objects mapped by id. + */ + QHash<int, QObject*> mRegisteredObjects; + +private Q_SLOTS: + + /** + * Deregisters an object automatically when it is destroyed. + * + * @param object The object to deregister. + */ + void deregister(QObject* object); + +}; + +} + +#endif Property changes on: trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.h ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegisterAdaptor.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegisterAdaptor.cpp (rev 0) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegisterAdaptor.cpp 2010-04-13 18:49:12 UTC (rev 229) @@ -0,0 +1,69 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "ObjectRegisterAdaptor.h" +#include "ObjectRegister.h" + +namespace editorsupport { + +//public: + +ObjectRegisterAdaptor::ObjectRegisterAdaptor(ObjectRegister* objectRegister): + QDBusAbstractAdaptor(objectRegister), + mObjectRegister(objectRegister) { +} + +//public slots: + +QString ObjectRegisterAdaptor::objectName(int objectId) const { + QObject* object = mObjectRegister->objectForId(objectId); + if (!object) { + return ""; + } + + return object->objectName(); +} + +QString ObjectRegisterAdaptor::className(int objectId) const { + QObject* object = mObjectRegister->objectForId(objectId); + if (!object) { + return ""; + } + + return object->metaObject()->className(); +} + +QList<int> ObjectRegisterAdaptor::childObjectIds(int objectId) const { + QObject* object = mObjectRegister->objectForId(objectId); + if (!object) { + return QList<int>(); + } + + QList<int> ids; + foreach (QObject* childObject, object->children()) { + ids.append(mObjectRegister->idForObject(childObject)); + } + + return ids; +} + +void ObjectRegisterAdaptor::clear() { + mObjectRegister->clear(); +} + +} Property changes on: trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegisterAdaptor.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegisterAdaptor.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegisterAdaptor.h (rev 0) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegisterAdaptor.h 2010-04-13 18:49:12 UTC (rev 229) @@ -0,0 +1,93 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef EDITORSUPPORT_OBJECTREGISTERADAPTOR_H +#define EDITORSUPPORT_OBJECTREGISTERADAPTOR_H + +#include <QDBusAbstractAdaptor> + +namespace editorsupport { +class ObjectRegister; +} + +namespace editorsupport { + +/** + * Adaptor to expose an ObjectRegister through DBus. + * + * @see EditorSupport + */ +class ObjectRegisterAdaptor: public QDBusAbstractAdaptor { +Q_OBJECT +Q_CLASSINFO("D-Bus Interface", "org.kde.ktutorial.ObjectRegister") +public: + + /** + * Creates a new ObjectRegisterAdaptor for the given ObjectRegister. + * + * @param objectRegister The ObjectRegister to adapt. + */ + explicit ObjectRegisterAdaptor(ObjectRegister* objectRegister); + +public Q_SLOTS: + + /** + * Returns the name of the object with the given id. + * If the id is not registered, an empty string is returned. + * + * @param objectId The id of the object. + * @return The name of the object. + */ + QString objectName(int objectId) const; + + /** + * Returns the class name of the object with the given id. + * If the id is not registered, an empty string is returned. + * + * @param objectId The id of the object. + * @return The class name of the object. + */ + QString className(int objectId) const; + + /** + * Returns a list with the ids of the child objects of the object with the + * given id. + * If the id is not registered, an empty list is returned. + * + * @param objectId The id of the object. + * @return The ids of the child objects. + */ + QList<int> childObjectIds(int objectId) const; + + /** + * Removes all the entries in the ObjectRegister. + */ + void clear(); + +private: + + /** + * The ObjectRegister to adapt. + */ + ObjectRegister* mObjectRegister; + +}; + +} + +#endif Property changes on: trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegisterAdaptor.h ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-library/tests/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-library/tests/CMakeLists.txt 2010-04-13 18:06:28 UTC (rev 228) +++ trunk/ktutorial/ktutorial-library/tests/CMakeLists.txt 2010-04-13 18:49:12 UTC (rev 229) @@ -2,6 +2,10 @@ add_subdirectory(scripting) add_subdirectory(view) +if (QT_QTDBUS_FOUND) + add_subdirectory(editorsupport) +endif (QT_QTDBUS_FOUND) + # Used by kde4_add_unit_test to set the full path to test executables set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) Added: trunk/ktutorial/ktutorial-library/tests/editorsupport/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-library/tests/editorsupport/CMakeLists.txt (rev 0) +++ trunk/ktutorial/ktutorial-library/tests/editorsupport/CMakeLists.txt 2010-04-13 18:49:12 UTC (rev 229) @@ -0,0 +1,41 @@ +# Used by kde4_add_unit_test to set the full path to test executables +set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) + +include_directories(${CMAKE_CURRENT_BINARY_DIR} ${ktutorial-library_SOURCE_DIR}/src/editorsupport ${KDE4_INCLUDES}) + +# Since Qt 4.6.0, this definition is needed for GUI testing. +# It is backwards compatible with previous Qt versions, unlike the alternative +# which is to add #include <QTestGui> in the test files. +add_definitions(-DQT_GUI_LIB) + +MACRO(UNIT_TESTS) + FOREACH(_className ${ARGN}) + set(_testName ${_className}Test) + kde4_add_unit_test(${_testName} TESTNAME ktutorial-${_testName} ${_testName}.cpp) + target_link_libraries(${_testName} ktutorial_editorsupport ${QT_QTTEST_LIBRARY}) + ENDFOREACH(_className) +ENDMACRO(UNIT_TESTS) + +unit_tests( + EditorSupport + EditorSupportAdaptor + EventSpy + EventSpyAdaptor + ObjectRegister + ObjectRegisterAdaptor +) + +MACRO(MEM_TESTS) + FOREACH(_testname ${ARGN}) + add_test(ktutorial-mem-${_testname} ${CMAKE_CURRENT_SOURCE_DIR}/../runMemcheck.py ${CMAKE_CURRENT_BINARY_DIR}/${_testname}Test ${CMAKE_CURRENT_BINARY_DIR}) + ENDFOREACH(_testname) +ENDMACRO(MEM_TESTS) + +mem_tests( + EditorSupport + EditorSupportAdaptor + EventSpy + EventSpyAdaptor + ObjectRegister + ObjectRegisterAdaptor +) Property changes on: trunk/ktutorial/ktutorial-library/tests/editorsupport/CMakeLists.txt ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-library/tests/editorsupport/EditorSupportAdaptorTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/editorsupport/EditorSupportAdaptorTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-library/tests/editorsupport/EditorSupportAdaptorTest.cpp 2010-04-13 18:49:12 UTC (rev 229) @@ -0,0 +1,139 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include <QtTest> + +#include <QWidget> +#include <QtDBus/QtDBus> + +#include "EditorSupportAdaptor.h" + +#include "EditorSupport.h" +#include "EventSpy.h" +#include "ObjectRegister.h" +#include "../extendedinformation/WidgetHighlighter.h" + +using extendedinformation::WidgetHighlighter; + +namespace editorsupport { + +class EditorSupportAdaptorTest: public QObject { +Q_OBJECT + +private slots: + + void testConstructor(); + + void testApplicationFilePath(); + + void testMainWindowObjectId(); + + void testHighlight(); + + void testStopHighlighting(); + + void testEnableEventSpy(); + + void testDisableEventSpy(); + +}; + +void EditorSupportAdaptorTest::testConstructor() { + EditorSupport editorSupport; + EditorSupportAdaptor* adaptor = new EditorSupportAdaptor(&editorSupport); + + QCOMPARE(adaptor->parent(), &editorSupport); +} + +void EditorSupportAdaptorTest::testApplicationFilePath() { + EditorSupport editorSupport; + EditorSupportAdaptor* adaptor = new EditorSupportAdaptor(&editorSupport); + + QCOMPARE(adaptor->applicationFilePath(), + QCoreApplication::applicationFilePath()); +} + +void EditorSupportAdaptorTest::testMainWindowObjectId() { + EditorSupport editorSupport; + QWidget window; + editorSupport.setup(&window); + EditorSupportAdaptor* adaptor = new EditorSupportAdaptor(&editorSupport); + + QCOMPARE(adaptor->mainWindowObjectId(), editorSupport.mainWindowObjectId()); +} + +void EditorSupportAdaptorTest::testHighlight() { + EditorSupport editorSupport; + QWidget window; + editorSupport.setup(&window); + EditorSupportAdaptor* adaptor = new EditorSupportAdaptor(&editorSupport); + + adaptor->highlight(adaptor->mainWindowObjectId()); + + QCOMPARE(window.findChildren<WidgetHighlighter*>().count(), 1); + QVERIFY(window.findChild<WidgetHighlighter*>()); +} + +void EditorSupportAdaptorTest::testStopHighlighting() { + EditorSupport editorSupport; + QWidget window; + editorSupport.setup(&window); + EditorSupportAdaptor* adaptor = new EditorSupportAdaptor(&editorSupport); + + adaptor->highlight(adaptor->mainWindowObjectId()); + adaptor->stopHighlighting(adaptor->mainWindowObjectId()); + + QCOMPARE(window.findChildren<WidgetHighlighter*>().count(), 0); +} + +void EditorSupportAdaptorTest::testEnableEventSpy() { + QDBusConnection bus = QDBusConnection::sessionBus(); + QVERIFY(bus.isConnected()); + + EditorSupport editorSupport; + QWidget window; + editorSupport.setup(&window); + EditorSupportAdaptor* adaptor = new EditorSupportAdaptor(&editorSupport); + + adaptor->enableEventSpy(); + + QObject* spyObject = bus.objectRegisteredAt("/ktutorial/EventSpy"); + QVERIFY(spyObject); + QVERIFY(qobject_cast<EventSpy*>(spyObject)); +} + +void EditorSupportAdaptorTest::testDisableEventSpy() { + QDBusConnection bus = QDBusConnection::sessionBus(); + QVERIFY(bus.isConnected()); + + EditorSupport editorSupport; + QWidget window; + editorSupport.setup(&window); + EditorSupportAdaptor* adaptor = new EditorSupportAdaptor(&editorSupport); + + adaptor->enableEventSpy(); + adaptor->disableEventSpy(); + + QVERIFY(!bus.objectRegisteredAt("/ktutorial/EventSpy")); +} + +} + +QTEST_MAIN(editorsupport::EditorSupportAdaptorTest) + +#include "EditorSupportAdaptorTest.moc" Property changes on: trunk/ktutorial/ktutorial-library/tests/editorsupport/EditorSupportAdaptorTest.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-library/tests/editorsupport/EditorSupportTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/editorsupport/EditorSupportTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-library/tests/editorsupport/EditorSupportTest.cpp 2010-04-13 18:49:12 UTC (rev 229) @@ -0,0 +1,213 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include <QtTest> + +#include <QApplication> +#include <QtDBus/QtDBus> + +#define protected public +#define private public +#include "EditorSupport.h" +#undef private +#undef protected + +#include "EventSpy.h" +#include "ObjectRegister.h" +#include "../extendedinformation/WidgetHighlighter.h" + +using extendedinformation::WidgetHighlighter; + +namespace editorsupport { + +class EditorSupportTest: public QObject { +Q_OBJECT + +public slots: + + void handleEventReceived(int objectId, const QString& eventType) { + Q_UNUSED(objectId); + mEventTypes.append(eventType); + } + +private slots: + + void init(); + + void testConstructor(); + + void testSetup(); + + void testMainWindowObjectId(); + + void testHighlight(); + + void testStopHighlighting(); + + void testEnableEventSpy(); + + void testDisableEventSpy(); + +private: + + QStringList mEventTypes; + +}; + +void EditorSupportTest::init() { + mEventTypes.clear(); +} + +void EditorSupportTest::testConstructor() { + QObject parent; + EditorSupport* editorSupport = new EditorSupport(&parent); + + QCOMPARE(editorSupport->parent(), &parent); +} + +void EditorSupportTest::testSetup() { + QDBusConnection bus = QDBusConnection::sessionBus(); + QVERIFY(bus.isConnected()); + + EditorSupport editorSupport; + QObject mainObject; + + editorSupport.setup(&mainObject); + + QObject* ktutorialObject = bus.objectRegisteredAt("/ktutorial"); + QVERIFY(ktutorialObject); + QVERIFY(qobject_cast<EditorSupport*>(ktutorialObject)); + + QObject* objectRegisterObject = + bus.objectRegisteredAt("/ktutorial/ObjectRegister"); + QVERIFY(objectRegisterObject); + QVERIFY(qobject_cast<ObjectRegister*>(objectRegisterObject)); + + QVERIFY(!bus.objectRegisteredAt("/ktutorial/EventSpy")); +} + +void EditorSupportTest::testMainWindowObjectId() { + EditorSupport editorSupport; + QWidget window; + editorSupport.setup(&window); + + int mainWindowObjectId = editorSupport.mainWindowObjectId(); + + QCOMPARE(editorSupport.mObjectRegister->idForObject(&window), + mainWindowObjectId); +} + +void EditorSupportTest::testHighlight() { + EditorSupport editorSupport; + QWidget window; + editorSupport.setup(&window); + + QWidget* widget = new QWidget(&window); + + int widgetId = editorSupport.mObjectRegister->idForObject(widget); + editorSupport.highlight(widgetId); + + QCOMPARE(widget->findChildren<WidgetHighlighter*>().count(), 1); + QVERIFY(widget->findChild<WidgetHighlighter*>()); +} + +void EditorSupportTest::testStopHighlighting() { + EditorSupport editorSupport; + QWidget window; + editorSupport.setup(&window); + + QWidget* widget = new QWidget(&window); + + int widgetId = editorSupport.mObjectRegister->idForObject(widget); + editorSupport.highlight(widgetId); + editorSupport.stopHighlighting(widgetId); + + QCOMPARE(widget->findChildren<WidgetHighlighter*>().count(), 0); +} + +void EditorSupportTest::testEnableEventSpy() { + QDBusConnection bus = QDBusConnection::sessionBus(); + QVERIFY(bus.isConnected()); + + EditorSupport editorSupport; + QObject mainObject; + editorSupport.setup(&mainObject); + editorSupport.enableEventSpy(); + + QDBusInterface* iface = new QDBusInterface(bus.baseService(), + "/ktutorial/EventSpy", "", + bus, this); + QVERIFY(iface->isValid()); + + connect(iface, SIGNAL(eventReceived(int, QString)), + this, SLOT(handleEventReceived(int, QString))); + + QObject* eventSpyObject = bus.objectRegisteredAt("/ktutorial/EventSpy"); + QVERIFY(eventSpyObject); + QVERIFY(qobject_cast<EventSpy*>(eventSpyObject)); + + //Send an event not managed by QObject to avoid messing up it... [truncated message content] |
From: <dan...@us...> - 2010-04-13 18:06:34
|
Revision: 228 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=228&view=rev Author: danxuliu Date: 2010-04-13 18:06:28 +0000 (Tue, 13 Apr 2010) Log Message: ----------- Add utility classes to highlight widgets with an animation. Modified Paths: -------------- trunk/ktutorial/ktutorial-library/src/CMakeLists.txt trunk/ktutorial/ktutorial-library/tests/CMakeLists.txt Added Paths: ----------- trunk/ktutorial/ktutorial-library/src/extendedinformation/ trunk/ktutorial/ktutorial-library/src/extendedinformation/CMakeLists.txt trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighter.cpp trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighter.h trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighterManager.cpp trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighterManager.h trunk/ktutorial/ktutorial-library/tests/extendedinformation/ trunk/ktutorial/ktutorial-library/tests/extendedinformation/CMakeLists.txt trunk/ktutorial/ktutorial-library/tests/extendedinformation/WidgetHighlighterManagerTest.cpp trunk/ktutorial/ktutorial-library/tests/extendedinformation/WidgetHighlighterTest.cpp Modified: trunk/ktutorial/ktutorial-library/src/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-library/src/CMakeLists.txt 2010-04-01 03:46:38 UTC (rev 227) +++ trunk/ktutorial/ktutorial-library/src/CMakeLists.txt 2010-04-13 18:06:28 UTC (rev 228) @@ -2,6 +2,7 @@ # In order to work, they must be compiled using -fPIC add_definitions("-fPIC") +add_subdirectory(extendedinformation) add_subdirectory(scripting) add_subdirectory(tutorials) add_subdirectory(view) Added: trunk/ktutorial/ktutorial-library/src/extendedinformation/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-library/src/extendedinformation/CMakeLists.txt (rev 0) +++ trunk/ktutorial/ktutorial-library/src/extendedinformation/CMakeLists.txt 2010-04-13 18:06:28 UTC (rev 228) @@ -0,0 +1,10 @@ +include_directories(${CMAKE_CURRENT_BINARY_DIR} ${KDE4_INCLUDES}) + +set(ktutorial_extendedinformation_SRCS + WidgetHighlighter.cpp + WidgetHighlighterManager.cpp +) + +kde4_add_library(ktutorial_extendedinformation ${ktutorial_extendedinformation_SRCS}) + +target_link_libraries(ktutorial_extendedinformation ${KDE4_KDEUI_LIBS}) Property changes on: trunk/ktutorial/ktutorial-library/src/extendedinformation/CMakeLists.txt ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighter.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighter.cpp (rev 0) +++ trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighter.cpp 2010-04-13 18:06:28 UTC (rev 228) @@ -0,0 +1,125 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include <QWidget> + +#include <KColorUtils> + +#include "WidgetHighlighter.h" + +namespace extendedinformation { + +//public: + +WidgetHighlighter::WidgetHighlighter(QWidget* targetWidget): + QObject(targetWidget), + mTargetWidget(targetWidget) { + Q_ASSERT(targetWidget); + + mOriginalPalette = targetWidget->palette(); + + //TODO Use QPropertyAnimation instead? Increase Qt version requirement in + //CMakeLists.txt to Qt 4.6 if done. + mProgress = 0; + mIncreasing = true; + mStopping = false; + + int interval = 25; + int duration = 500; + mProgressForEachTick = interval / (qreal)duration; + + mTimer.setInterval(interval); + connect(&mTimer, SIGNAL(timeout()), this, SLOT(update())); +} + +WidgetHighlighter::~WidgetHighlighter() { + mTargetWidget->setPalette(mOriginalPalette); +} + +//public slots: + +void WidgetHighlighter::start() { + mStopping = false; + mIncreasing = true; + + mTimer.start(); +} + +void WidgetHighlighter::stop() { + mStopping = true; + mIncreasing = false; + + if (mProgress == 0) { + mTimer.stop(); + emit stopped(this); + } +} + +//private: + +void WidgetHighlighter::updateColorGroup(QPalette& palette, + QPalette::ColorGroup colorGroup) { + updateColorRole(palette, colorGroup, QPalette::Window, QPalette::Highlight); + updateColorRole(palette, colorGroup, QPalette::WindowText, + QPalette::HighlightedText); + updateColorRole(palette, colorGroup, QPalette::Base, QPalette::Highlight); + updateColorRole(palette, colorGroup, QPalette::Text, + QPalette::HighlightedText); + updateColorRole(palette, colorGroup, QPalette::Button, QPalette::Highlight); + updateColorRole(palette, colorGroup, QPalette::ButtonText, + QPalette::HighlightedText); +} + +void WidgetHighlighter::updateColorRole(QPalette& palette, + QPalette::ColorGroup colorGroup, + QPalette::ColorRole base, + QPalette::ColorRole tint) { + qreal amount = 0.6 * mProgress; + QColor color = KColorUtils::tint(palette.color(colorGroup, base), + palette.color(colorGroup, tint), + amount); + palette.setColor(colorGroup, base, color); +} + +//private slots: + +void WidgetHighlighter::update(){ + if (mIncreasing) { + mProgress += mProgressForEachTick; + mProgress = qMin<qreal>(1, mProgress); + mIncreasing = mProgress < 1; + } else { + mProgress -= mProgressForEachTick; + mProgress = qMax<qreal>(0, mProgress); + mIncreasing = mProgress == 0; + } + + QPalette updatedPalette = mOriginalPalette; + updateColorGroup(updatedPalette, QPalette::Active); + updateColorGroup(updatedPalette, QPalette::Inactive); + updateColorGroup(updatedPalette, QPalette::Disabled); + + mTargetWidget->setPalette(updatedPalette); + + if (mStopping && mProgress == 0) { + mTimer.stop(); + emit stopped(this); + } +} + +} Property changes on: trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighter.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighter.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighter.h (rev 0) +++ trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighter.h 2010-04-13 18:06:28 UTC (rev 228) @@ -0,0 +1,162 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef WIDGETHIGHLIGHTER_H +#define WIDGETHIGHLIGHTER_H + +#include <QObject> +#include <QPalette> +#include <QTimer> + +namespace extendedinformation { + +/** + * Utility class to highlight a widget. + * WidgetHighlighter executes an animation that modifies the color palette of + * some widget, changing its colors from normal to highlighted and back again. + * + * Once started, the animation goes on indefinitely until the stop slot is + * called. The colors of the palette are set back to the original colors + * animating the change from the current color of the widget to the normal one. + * If the highlighting is started again while the stop animation is running, the + * highlighting animation is started again from the current color (that is, the + * stop animation is cancelled and a new highlight animation is started from + * that point). + * + * WidgetHighlighter should not be created directly. Instead, + * WidgetHighlighterManager should be used, as it takes care of deleting the + * highlighter when no longer needed. + * + * @see WidgetHighlighterManager + */ +class WidgetHighlighter: public QObject { +Q_OBJECT +public: + + /** + * Creates a new WidgetHighlighter for the given widget. + * + * @param targetWidget The widget to highlight. + */ + explicit WidgetHighlighter(QWidget* targetWidget); + + /** + * Destroys this WidgetHighlighter. + * It restores the original palette to the target widget. + */ + virtual ~WidgetHighlighter(); + +public Q_SLOTS: + + /** + * Starts highlighting the target widget. + * If there is a normal animation already running nothing is done. However, + * if there is a stop animation running, it is cancelled and the + * highlighting animation is started again from the current color. + */ + void start(); + + /** + * Stops highlighting the target widget. + * The animation is not stopped sharply, but a stop animation (the widget + * recovering its normal color) is executed. + */ + void stop(); + +Q_SIGNALS: + + /** + * Emitted when the animation has stopped. + * Note that it is emitted when the animation has truly stopped, that is, + * when there is not even an stop animation. + * + * @param widgetHighlighter This WidgetHighlighter. + */ + void stopped(extendedinformation::WidgetHighlighter* widgetHighlighter); + +private: + + /** + * The widget to highlight. + */ + QWidget* mTargetWidget; + + /** + * The original palette used by the widget. + */ + QPalette mOriginalPalette; + + /** + * Timer to update the colors. + */ + QTimer mTimer; + + /** + * The current progress from normal to highlighted colors. + * Range [0-1]. + */ + qreal mProgress; + + /** + * How much advances the progress when an update is done. + */ + qreal mProgressForEachTick; + + /** + * True if the widget is being highlighted, false it is being dehighlighted. + */ + bool mIncreasing; + + /** + * True if the stop animation is being run, false otherwise. + */ + bool mStopping; + + /** + * Updates the color group of the given palette based on the current + * progress. + * + * @param palette The palette to update its colors. + * @param colorGroup The color group of the palette to update. + */ + void updateColorGroup(QPalette& palette, QPalette::ColorGroup colorGroup); + + /** + * Updates the color role "base" tinting it with the color role "tint". + * How much the base color role is tinted depends on the current progress. + * + * @param palette The palette to update its colors. + * @param colorGroup The color group of the palette to update. + * @param base The color role to update. + * @param tint The color role to tint the base color role with. + */ + void updateColorRole(QPalette& palette, QPalette::ColorGroup colorGroup, + QPalette::ColorRole from, QPalette::ColorRole to); + +private Q_SLOTS: + + /** + * Updates the palette of the target widget based on the animation progress. + */ + void update(); + +}; + +} + +#endif Property changes on: trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighter.h ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighterManager.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighterManager.cpp (rev 0) +++ trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighterManager.cpp 2010-04-13 18:06:28 UTC (rev 228) @@ -0,0 +1,68 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include <QWidget> + +#include "WidgetHighlighterManager.h" +#include "WidgetHighlighter.h" + +namespace extendedinformation { + +//public: + +WidgetHighlighterManager* WidgetHighlighterManager::self() { + return sSelf; +} + +void WidgetHighlighterManager::highlight(QWidget* widget) { + WidgetHighlighter* highlighter = widget->findChild<WidgetHighlighter*>(); + if (!highlighter) { + highlighter = new WidgetHighlighter(widget); + connect(highlighter, SIGNAL(stopped(extendedinformation::WidgetHighlighter*)), + this, SLOT(remove(extendedinformation::WidgetHighlighter*))); + } + + highlighter->start(); +} + +void WidgetHighlighterManager::stopHighlighting(QWidget* widget) { + WidgetHighlighter* highlighter = widget->findChild<WidgetHighlighter*>(); + if (!highlighter) { + return; + } + + highlighter->stop(); +} + +//private: + +WidgetHighlighterManager* WidgetHighlighterManager::sSelf = + new WidgetHighlighterManager(); + +WidgetHighlighterManager::WidgetHighlighterManager(): QObject() { +} + +//private slots: + +void WidgetHighlighterManager::remove( + extendedinformation::WidgetHighlighter* highlighter) { + highlighter->setParent(0); + delete highlighter; +} + +} Property changes on: trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighterManager.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighterManager.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighterManager.h (rev 0) +++ trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighterManager.h 2010-04-13 18:06:28 UTC (rev 228) @@ -0,0 +1,96 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef WIDGETHIGHLIGHTERMANAGER_H +#define WIDGETHIGHLIGHTERMANAGER_H + +#include <QHash> +#include <QObject> + +namespace extendedinformation { +class WidgetHighlighter; +} + +namespace extendedinformation { + +/** + * Utility class to manage WidgetHighlighters. + * Starting and stopping the highlighting from WidgetHighlighterManager instead + * of using directly WidgetHighlighter ensures that no overlapping animations + * will be executed. + * + * WidgetHighlighterManager also takes care of deleting the WidgetHighlighter + * when no longer needed, that is, when they are fully stopped (once the stop + * animation has ended). + * + * @see WidgetHighlighter + */ +class WidgetHighlighterManager: public QObject { +Q_OBJECT +public: + + /** + * Returns the only instance of this class. + * + * @return The only instance of this class. + */ + static WidgetHighlighterManager* self(); + + /** + * Starts a WidgetHighlighter for the given widget. + * If the widget was already being highlighted nothing is done. + * + * @param widget The widget to highlight. + */ + void highlight(QWidget* widget); + + /** + * Stops the WidgetHighlighter of the given widget. + * + * @param widget The widget to stop highlighting. + */ + void stopHighlighting(QWidget* widget); + +private: + + /** + * The instance of this class. + */ + static WidgetHighlighterManager* sSelf; + + /** + * Creates a new WidgetHighlighterManager. + * Private to avoid classes other than self to create instances. + */ + WidgetHighlighterManager(); + +private Q_SLOTS: + + /** + * Removes the highlighter from its widget and destroys it. + * Called when the highlighter stopped. + * + * @param highlighter The highlighter to remove. + */ + void remove(extendedinformation::WidgetHighlighter* highlighter); + +}; + +} + +#endif Property changes on: trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighterManager.h ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-library/tests/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-library/tests/CMakeLists.txt 2010-04-01 03:46:38 UTC (rev 227) +++ trunk/ktutorial/ktutorial-library/tests/CMakeLists.txt 2010-04-13 18:06:28 UTC (rev 228) @@ -1,3 +1,4 @@ +add_subdirectory(extendedinformation) add_subdirectory(scripting) add_subdirectory(view) Added: trunk/ktutorial/ktutorial-library/tests/extendedinformation/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-library/tests/extendedinformation/CMakeLists.txt (rev 0) +++ trunk/ktutorial/ktutorial-library/tests/extendedinformation/CMakeLists.txt 2010-04-13 18:06:28 UTC (rev 228) @@ -0,0 +1,33 @@ +# Used by kde4_add_unit_test to set the full path to test executables +set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) + +include_directories(${CMAKE_CURRENT_BINARY_DIR} ${ktutorial-library_SOURCE_DIR}/src/extendedinformation ${KDE4_INCLUDES}) + +# Since Qt 4.6.0, this definition is needed for GUI testing. +# It is backwards compatible with previous Qt versions, unlike the alternative +# which is to add #include <QTestGui> in the test files. +add_definitions(-DQT_GUI_LIB) + +MACRO(UNIT_TESTS) + FOREACH(_className ${ARGN}) + set(_testName ${_className}Test) + kde4_add_unit_test(${_testName} TESTNAME ktutorial-${_testName} ${_testName}.cpp) + target_link_libraries(${_testName} ktutorial_extendedinformation ${QT_QTTEST_LIBRARY}) + ENDFOREACH(_className) +ENDMACRO(UNIT_TESTS) + +unit_tests( + WidgetHighlighter + WidgetHighlighterManager +) + +MACRO(MEM_TESTS) + FOREACH(_testname ${ARGN}) + add_test(ktutorial-mem-${_testname} ${CMAKE_CURRENT_SOURCE_DIR}/../runMemcheck.py ${CMAKE_CURRENT_BINARY_DIR}/${_testname}Test ${CMAKE_CURRENT_BINARY_DIR}) + ENDFOREACH(_testname) +ENDMACRO(MEM_TESTS) + +mem_tests( + WidgetHighlighter + WidgetHighlighterManager +) Property changes on: trunk/ktutorial/ktutorial-library/tests/extendedinformation/CMakeLists.txt ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-library/tests/extendedinformation/WidgetHighlighterManagerTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/extendedinformation/WidgetHighlighterManagerTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-library/tests/extendedinformation/WidgetHighlighterManagerTest.cpp 2010-04-13 18:06:28 UTC (rev 228) @@ -0,0 +1,144 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include <QtTest> + +#include <QWidget> + +#include "WidgetHighlighterManager.h" +#include "WidgetHighlighter.h" + +namespace extendedinformation { + +class WidgetHighlighterManagerTest: public QObject { +Q_OBJECT +private slots: + + void testSelf(); + + void testHighlight(); + void testHighlightWidgetAlreadyHighlighted(); + void testHighlightAfterStopHighlighting(); + + void testStopHighlighting(); + + void testDeleteWidgetWhileHighlighting(); + +}; + +void WidgetHighlighterManagerTest::testSelf() { + WidgetHighlighterManager* manager1 = WidgetHighlighterManager::self(); + WidgetHighlighterManager* manager2 = WidgetHighlighterManager::self(); + + QVERIFY(manager1); + QVERIFY(manager2); + QVERIFY(manager1 == manager2); +} + +void WidgetHighlighterManagerTest::testHighlight() { + QWidget widget; + QPalette palette = widget.palette(); + WidgetHighlighterManager* manager = WidgetHighlighterManager::self(); + + manager->highlight(&widget); + + //Give it some time to update + QTest::qWait(100); + + QCOMPARE(widget.findChildren<WidgetHighlighter*>().count(), 1); + QVERIFY(widget.findChild<WidgetHighlighter*>()); + QVERIFY(widget.palette() != palette); +} + +void WidgetHighlighterManagerTest::testHighlightWidgetAlreadyHighlighted() { + QWidget widget; + WidgetHighlighterManager* manager = WidgetHighlighterManager::self(); + + manager->highlight(&widget); + + WidgetHighlighter* highlighter = widget.findChild<WidgetHighlighter*>(); + + manager->highlight(&widget); + + QCOMPARE(widget.findChildren<WidgetHighlighter*>().count(), 1); + QCOMPARE(widget.findChild<WidgetHighlighter*>(), highlighter); +} + +void WidgetHighlighterManagerTest::testHighlightAfterStopHighlighting() { + QWidget widget; + WidgetHighlighterManager* manager = WidgetHighlighterManager::self(); + + manager->highlight(&widget); + + QPointer<WidgetHighlighter> highlighter = + widget.findChild<WidgetHighlighter*>(); + QVERIFY(highlighter); + + manager->stopHighlighting(&widget); + + QVERIFY(!highlighter); + + QPalette palette = widget.palette(); + manager->highlight(&widget); + + //Give it some time to update + QTest::qWait(100); + + QCOMPARE(widget.findChildren<WidgetHighlighter*>().count(), 1); + QVERIFY(widget.findChild<WidgetHighlighter*>()); + QVERIFY(widget.palette() != palette); +} + +void WidgetHighlighterManagerTest::testStopHighlighting() { + QWidget widget; + QPalette palette = widget.palette(); + WidgetHighlighterManager* manager = WidgetHighlighterManager::self(); + + manager->highlight(&widget); + + //Give it some time to update + QTest::qWait(100); + + manager->stopHighlighting(&widget); + + //Give it some time to update + QTest::qWait(200); + + QCOMPARE(widget.findChildren<WidgetHighlighter*>().count(), 0); + QVERIFY(widget.palette() == palette); +} + +void WidgetHighlighterManagerTest::testDeleteWidgetWhileHighlighting() { + QWidget* widget = new QWidget(); + WidgetHighlighterManager* manager = WidgetHighlighterManager::self(); + + manager->highlight(widget); + + //Give it some time to update + QTest::qWait(100); + + delete widget; + + //No explicit check is made, if it does not crash everything is fine ;) +} + +} + +QTEST_MAIN(extendedinformation::WidgetHighlighterManagerTest) + +#include "WidgetHighlighterManagerTest.moc" Property changes on: trunk/ktutorial/ktutorial-library/tests/extendedinformation/WidgetHighlighterManagerTest.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-library/tests/extendedinformation/WidgetHighlighterTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/extendedinformation/WidgetHighlighterTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-library/tests/extendedinformation/WidgetHighlighterTest.cpp 2010-04-13 18:06:28 UTC (rev 228) @@ -0,0 +1,293 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include <QtTest> + +#include <QApplication> +#include <QWidget> + +#define protected public +#define private public +#include "WidgetHighlighter.h" +#undef private +#undef protected + +//extendedinformation::WidgetHighlighter* must be declared as a metatype to be +//used in qvariant_cast +Q_DECLARE_METATYPE(extendedinformation::WidgetHighlighter*); + +namespace extendedinformation { + +class WidgetHighlighterTest: public QObject { +Q_OBJECT +private slots: + + void testConstructor(); + + void testDestructor(); + + void testStart(); + void testStartAlreadyStarted(); + void testStartWhileStopAnimationIsRunning(); + + void testUpdate(); + void testUpdateWhenProgressIsAlmostOne(); + void testUpdateWhenProgressIsAlmostZero(); + + void testStop(); + void testStopAfterStopAnimationEnded(); + void testStopImmediatelyAfterStart(); + +}; + +void WidgetHighlighterTest::testConstructor() { + QWidget widget; + widget.setPalette(Qt::blue); + QApplication::setPalette(Qt::green); + WidgetHighlighter* highlighter = new WidgetHighlighter(&widget); + + QCOMPARE(highlighter->parent(), &widget); + QVERIFY(highlighter->mOriginalPalette != QApplication::palette()); + QVERIFY(highlighter->mOriginalPalette == widget.palette()); +} + +void WidgetHighlighterTest::testDestructor() { + QWidget widget; + QPalette palette = widget.palette(); + WidgetHighlighter* highlighter = new WidgetHighlighter(&widget); + + widget.setPalette(QPalette(Qt::green)); + delete highlighter; + + QVERIFY(widget.palette() == palette); +} + +void WidgetHighlighterTest::testStart() { + QWidget widget; + QPalette palette = widget.palette(); + WidgetHighlighter* highlighter = new WidgetHighlighter(&widget); + + highlighter->start(); + + //Give it some time to update + QTest::qWait(100); + + QVERIFY(widget.palette() != palette); +} + +void WidgetHighlighterTest::testStartAlreadyStarted() { + QWidget widget; + QPalette palette = widget.palette(); + WidgetHighlighter* highlighter = new WidgetHighlighter(&widget); + + highlighter->start(); + + //Give it some time to update + QTest::qWait(100); + + qreal previousProgress = highlighter->mProgress; + highlighter->start(); + + //Ensure that progress is not reseted + QCOMPARE(highlighter->mProgress, previousProgress); + QVERIFY(widget.palette() != palette); +} + +void WidgetHighlighterTest::testStartWhileStopAnimationIsRunning() { + QWidget widget; + QPalette palette = widget.palette(); + WidgetHighlighter* highlighter = new WidgetHighlighter(&widget); + + highlighter->mProgress = 0.5; + highlighter->start(); + + //Give it some time to update + QTest::qWait(100); + + highlighter->stop(); + + //Give it some time to update + QTest::qWait(100); + + highlighter->start(); + + //Give it some time to update + QTest::qWait(100); + + QVERIFY(highlighter->mProgress > 0.5); + QVERIFY(highlighter->mIncreasing); + QVERIFY(!highlighter->mStopping); + QVERIFY(widget.palette() != palette); +} + +void WidgetHighlighterTest::testUpdate() { + QWidget widget; + WidgetHighlighter* highlighter = new WidgetHighlighter(&widget); + highlighter->mTimer.stop(); + + QPalette palette = widget.palette(); + int previousProgress = highlighter->mProgress; + + highlighter->update(); + + QCOMPARE(highlighter->mProgress, + previousProgress + highlighter->mProgressForEachTick); + QVERIFY(widget.palette().color(QPalette::Window) != + palette.color(QPalette::Window)); + QVERIFY(widget.palette().color(QPalette::WindowText) != + palette.color(QPalette::WindowText)); + QVERIFY(widget.palette().color(QPalette::Base) != + palette.color(QPalette::Base)); + QVERIFY(widget.palette().color(QPalette::Text) != + palette.color(QPalette::Text)); + QVERIFY(widget.palette().color(QPalette::Button) != + palette.color(QPalette::Button)); + QVERIFY(widget.palette().color(QPalette::ButtonText) != + palette.color(QPalette::ButtonText)); +} + +void WidgetHighlighterTest::testUpdateWhenProgressIsAlmostOne() { + QWidget widget; + WidgetHighlighter* highlighter = new WidgetHighlighter(&widget); + highlighter->mTimer.stop(); + + highlighter->mProgress = 0.995; + highlighter->mIncreasing = true; + highlighter->update(); + + //Don't check palette changes here, as with such a small update it could + //have been left unchanged + QCOMPARE(highlighter->mProgress, 1.0); + QCOMPARE(highlighter->mIncreasing, false); + + QPalette palette = widget.palette(); + highlighter->update(); + + QCOMPARE(highlighter->mProgress, 1 - highlighter->mProgressForEachTick); + QCOMPARE(highlighter->mIncreasing, false); + QVERIFY(widget.palette() != palette); +} + +void WidgetHighlighterTest::testUpdateWhenProgressIsAlmostZero() { + QWidget widget; + WidgetHighlighter* highlighter = new WidgetHighlighter(&widget); + highlighter->mTimer.stop(); + + highlighter->mProgress = 0.005; + highlighter->mIncreasing = false; + highlighter->update(); + + //Don't check palette changes here, as with such a small update it could + //have been left unchanged + QCOMPARE(highlighter->mProgress, 0.0); + QCOMPARE(highlighter->mIncreasing, true); + + QPalette palette = widget.palette(); + highlighter->update(); + + QCOMPARE(highlighter->mProgress, highlighter->mProgressForEachTick); + QCOMPARE(highlighter->mIncreasing, true); + QVERIFY(widget.palette() != palette); +} + +void WidgetHighlighterTest::testStop() { + QWidget widget; + QPalette palette = widget.palette(); + WidgetHighlighter* highlighter = new WidgetHighlighter(&widget); + + highlighter->mProgress = 0.5; + highlighter->start(); + + //Give it some time to update + QTest::qWait(100); + + highlighter->stop(); + + //Give it some time to update + QTest::qWait(200); + + QVERIFY(highlighter->mTimer.isActive()); + QVERIFY(highlighter->mProgress < 0.5); + QVERIFY(!highlighter->mIncreasing); + QVERIFY(highlighter->mStopping); + QVERIFY(widget.palette() != palette); +} + +void WidgetHighlighterTest::testStopAfterStopAnimationEnded() { + QWidget widget; + QPalette palette = widget.palette(); + WidgetHighlighter* highlighter = new WidgetHighlighter(&widget); + + highlighter->start(); + + //Give it some time to update + QTest::qWait(100); + + //extendedinformation::WidgetHighlighter* must be registered in order to be + //used with QSignalSpy + int widgetHighlighterStarType = + qRegisterMetaType<extendedinformation::WidgetHighlighter*>( + "extendedinformation::WidgetHighlighter*"); + QSignalSpy stoppedSpy(highlighter, + SIGNAL(stopped(extendedinformation::WidgetHighlighter*))); + + highlighter->stop(); + + //Give it some time to update + QTest::qWait(200); + + QVERIFY(!highlighter->mTimer.isActive()); + QVERIFY(widget.palette() == palette); + QCOMPARE(stoppedSpy.count(), 1); + QVariant argument = stoppedSpy.at(0).at(0); + QCOMPARE(argument.userType(), widgetHighlighterStarType); + QCOMPARE(qvariant_cast<extendedinformation::WidgetHighlighter*>(argument), + highlighter); +} + +void WidgetHighlighterTest::testStopImmediatelyAfterStart() { + QWidget widget; + QPalette palette = widget.palette(); + WidgetHighlighter* highlighter = new WidgetHighlighter(&widget); + + highlighter->start(); + + //extendedinformation::WidgetHighlighter* must be registered in order to be + //used with QSignalSpy + int widgetHighlighterStarType = + qRegisterMetaType<extendedinformation::WidgetHighlighter*>( + "extendedinformation::WidgetHighlighter*"); + QSignalSpy stoppedSpy(highlighter, + SIGNAL(stopped(extendedinformation::WidgetHighlighter*))); + + highlighter->stop(); + + QVERIFY(!highlighter->mTimer.isActive()); + QVERIFY(widget.palette() == palette); + QCOMPARE(stoppedSpy.count(), 1); + QVariant argument = stoppedSpy.at(0).at(0); + QCOMPARE(argument.userType(), widgetHighlighterStarType); + QCOMPARE(qvariant_cast<extendedinformation::WidgetHighlighter*>(argument), + highlighter); +} + +} + +QTEST_MAIN(extendedinformation::WidgetHighlighterTest) + +#include "WidgetHighlighterTest.moc" Property changes on: trunk/ktutorial/ktutorial-library/tests/extendedinformation/WidgetHighlighterTest.cpp ___________________________________________________________________ Added: svn:eol-style + native This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-04-01 03:46:46
|
Revision: 227 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=227&view=rev Author: danxuliu Date: 2010-04-01 03:46:38 +0000 (Thu, 01 Apr 2010) Log Message: ----------- Rename ktutorial-editor.desktop to ktutorial_editor.desktop when it is installed. It seems that "-" is used internally when creating ids for the desktop files to represent a directory, so having "-" in the name confuses the system and as result there is no entry for the desktop file in the menu. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt Modified: trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt 2010-03-31 16:27:52 UTC (rev 226) +++ trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt 2010-04-01 03:46:38 UTC (rev 227) @@ -34,5 +34,10 @@ ####### Install the editor ####### install(TARGETS ktutorial-editor DESTINATION ${BIN_INSTALL_DIR}) -install(FILES ktutorial-editor.desktop DESTINATION ${XDG_APPS_INSTALL_DIR}) +# Desktop files should not contain "-" in their name, as it could confuse the +# desktop id system: +# http://standards.freedesktop.org/menu-spec/latest/go01.html#term-desktop-file-id +install(FILES ktutorial-editor.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} + RENAME ktutorial_editor.desktop +) install(FILES ktutorial-editorui.rc DESTINATION ${DATA_INSTALL_DIR}/ktutorial-editor) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-31 16:28:01
|
Revision: 226 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=226&view=rev Author: danxuliu Date: 2010-03-31 16:27:52 +0000 (Wed, 31 Mar 2010) Log Message: ----------- Fix compiler warnings. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/data/Reaction.cpp trunk/ktutorial/ktutorial-editor/tests/unit/data/ReactionTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/data/Reaction.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/data/Reaction.cpp 2010-03-31 16:21:39 UTC (rev 225) +++ trunk/ktutorial/ktutorial-editor/src/data/Reaction.cpp 2010-03-31 16:27:52 UTC (rev 226) @@ -23,8 +23,8 @@ Reaction::Reaction(QObject* parent): QObject(parent), + mTriggerType(OptionSelected), mWaitFor(0), - mTriggerType(OptionSelected), mResponseType(NextStep) { } Modified: trunk/ktutorial/ktutorial-editor/tests/unit/data/ReactionTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/data/ReactionTest.cpp 2010-03-31 16:21:39 UTC (rev 225) +++ trunk/ktutorial/ktutorial-editor/tests/unit/data/ReactionTest.cpp 2010-03-31 16:27:52 UTC (rev 226) @@ -60,6 +60,7 @@ } bool equals(const WaitFor& waitFor) const { + Q_UNUSED(waitFor); return false; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-31 16:21:50
|
Revision: 225 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=225&view=rev Author: danxuliu Date: 2010-03-31 16:21:39 +0000 (Wed, 31 Mar 2010) Log Message: ----------- Refactor KTutorialEditor class to extract edition related actions to its own class, EditActions. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h Added Paths: ----------- trunk/ktutorial/ktutorial-editor/src/EditActions.cpp trunk/ktutorial/ktutorial-editor/src/EditActions.h Modified: trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt 2010-03-31 06:58:14 UTC (rev 224) +++ trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt 2010-03-31 16:21:39 UTC (rev 225) @@ -10,6 +10,7 @@ add_subdirectory(view) set(ktutorial_editor_SRCS + EditActions.cpp Exception.cpp FileActions.cpp KTutorialEditor.cpp Added: trunk/ktutorial/ktutorial-editor/src/EditActions.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/EditActions.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/EditActions.cpp 2010-03-31 16:21:39 UTC (rev 225) @@ -0,0 +1,307 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "EditActions.h" + +#include <KAction> +#include <KActionCollection> +#include <KLocalizedString> +#include <KUndoStack> + +#include "KTutorialEditor.h" +#include "commands/StepCommands.h" +#include "commands/TutorialCommands.h" +#include "data/Reaction.h" +#include "data/Step.h" +#include "view/EditionDialog.h" +#include "view/LicenseWidget.h" +#include "view/ReactionWidget.h" +#include "view/StepCustomCodeWidget.h" +#include "view/StepDataWidget.h" +#include "view/TutorialCustomCodeWidget.h" +#include "view/TutorialInformationWidget.h" + +//public: + +EditActions::EditActions(KTutorialEditor* tutorialEditor): + QObject(tutorialEditor), + mTutorialEditor(tutorialEditor), + mCurrentStep(0), + mCurrentReaction(0) { + + mUndoStack = new KUndoStack(this); + connect(mUndoStack, SIGNAL(cleanChanged(bool)), + this, SIGNAL(cleanChanged(bool))); + + setupActions(); +} + +void EditActions::clearCommands() { + mUndoStack->clear(); +} + +void EditActions::setClean() { + mUndoStack->setClean(); +} + +//public slots: + +void EditActions::selectStep(Step* step) { + mCurrentStep = step; + + KActionCollection* actionCollection = mTutorialEditor->actionCollection(); + if (mCurrentStep) { + actionCollection->action("setStepData")->setEnabled(true); + actionCollection->action("setStepSetup")->setEnabled(true); + actionCollection->action("setStepTearDown")->setEnabled(true); + actionCollection->action("removeStep")->setEnabled(true); + actionCollection->action("addReaction")->setEnabled(true); + } else { + actionCollection->action("setStepData")->setEnabled(false); + actionCollection->action("setStepSetup")->setEnabled(false); + actionCollection->action("setStepTearDown")->setEnabled(false); + actionCollection->action("removeStep")->setEnabled(false); + actionCollection->action("addReaction")->setEnabled(false); + } +} + +void EditActions::selectReaction(Reaction* reaction) { + mCurrentReaction = reaction; + + KActionCollection* actionCollection = mTutorialEditor->actionCollection(); + if (mCurrentReaction) { + actionCollection->action("setReactionData")->setEnabled(true); + actionCollection->action("removeReaction")->setEnabled(true); + } else { + actionCollection->action("setReactionData")->setEnabled(false); + actionCollection->action("removeReaction")->setEnabled(false); + } +} + +//private: + +void EditActions::setupActions() { + KActionCollection* actionCollection = mTutorialEditor->actionCollection(); + + mUndoStack->createUndoAction(actionCollection); + + mUndoStack->createRedoAction(actionCollection); + + KAction* action = new KAction(this); + action->setText(i18nc("@action", "Set information...")); + action->setStatusTip(i18nc("@info:status", "Set the name and description " +"of the tutorial.")); + action->setIcon(KIcon("documentinfo")); + actionCollection->addAction("setTutorialInformation", action); + connect(action, SIGNAL(triggered(bool)), + this, SLOT(setTutorialInformation())); + + action = new KAction(this); + action->setText(i18nc("@action", "Set license...")); + action->setStatusTip(i18nc("@info:status", "Set the license text of the " +"tutorial.")); + action->setIcon(KIcon("document-edit")); + actionCollection->addAction("setTutorialLicense", action); + connect(action, SIGNAL(triggered(bool)), this, SLOT(setTutorialLicense())); + + action = new KAction(this); + action->setText(i18nc("@action", "Set setup code...")); + action->setStatusTip(i18nc("@info:status", "Set the custom code to be " +"executed when the tutorial starts.")); + action->setIcon(KIcon("code-function")); + actionCollection->addAction("setTutorialSetup", action); + connect(action, SIGNAL(triggered(bool)), this, SLOT(setTutorialSetup())); + + action = new KAction(this); + action->setText(i18nc("@action", "Set tear down code...")); + action->setStatusTip(i18nc("@info:status", "Set the custom code to be " +"executed when the tutorial finishes.")); + action->setIcon(KIcon("code-function")); + actionCollection->addAction("setTutorialTearDown", action); + connect(action, SIGNAL(triggered(bool)), this, SLOT(setTutorialTearDown())); + + action = new KAction(this); + action->setText(i18nc("@action", "Add step...")); + action->setStatusTip(i18nc("@info:status", "Add a new step to the " +"tutorial.")); + action->setIcon(KIcon("list-add")); + actionCollection->addAction("addStep", action); + connect(action, SIGNAL(triggered(bool)), this, SLOT(addStep())); + + action = new KAction(this); + action->setText(i18nc("@action", "Set data...")); + action->setStatusTip(i18nc("@info:status", "Set the name and text of the " +"currently selected step.")); + action->setIcon(KIcon("document-edit")); + action->setEnabled(false); + actionCollection->addAction("setStepData", action); + connect(action, SIGNAL(triggered(bool)), this, SLOT(setStepData())); + + action = new KAction(this); + action->setText(i18nc("@action", "Set setup code...")); + action->setStatusTip(i18nc("@info:status", "Set the custom code to be " +"executed when the tutorial passes to the currently selected step.")); + action->setIcon(KIcon("code-function")); + action->setEnabled(false); + actionCollection->addAction("setStepSetup", action); + connect(action, SIGNAL(triggered(bool)), this, SLOT(setStepSetup())); + + action = new KAction(this); + action->setText(i18nc("@action", "Set tear down code...")); + action->setStatusTip(i18nc("@info:status", "Set the custom code to be " +"executed when the tutorial changes from the currently selected step to " +"another step.")); + action->setIcon(KIcon("code-function")); + action->setEnabled(false); + actionCollection->addAction("setStepTearDown", action); + connect(action, SIGNAL(triggered(bool)), this, SLOT(setStepTearDown())); + + action = new KAction(this); + action->setText(i18nc("@action", "Remove step")); + action->setStatusTip(i18nc("@info:status", "Removes the currently selected " +"step from the tutorial.")); + action->setIcon(KIcon("list-remove")); + action->setEnabled(false); + actionCollection->addAction("removeStep", action); + connect(action, SIGNAL(triggered(bool)), this, SLOT(removeStep())); + + action = new KAction(this); + action->setText(i18nc("@action", "Add reaction...")); + action->setStatusTip(i18nc("@info:status", "Add a new reaction to the " +"selected step.")); + action->setIcon(KIcon("list-add")); + action->setEnabled(false); + actionCollection->addAction("addReaction", action); + connect(action, SIGNAL(triggered(bool)), this, SLOT(addReaction())); + + action = new KAction(this); + action->setText(i18nc("@action", "Set data...")); + action->setStatusTip(i18nc("@info:status", "Set the trigger and the " +"response of the currently selected reaction.")); + action->setIcon(KIcon("document-edit")); + action->setEnabled(false); + actionCollection->addAction("setReactionData", action); + connect(action, SIGNAL(triggered(bool)), this, SLOT(setReactionData())); + + action = new KAction(this); + action->setText(i18nc("@action", "Remove reaction")); + action->setStatusTip(i18nc("@info:status", "Removes the currently selected " +"reaction from its step.")); + action->setIcon(KIcon("list-remove")); + action->setEnabled(false); + actionCollection->addAction("removeReaction", action); + connect(action, SIGNAL(triggered(bool)), this, SLOT(removeReaction())); +} + +int EditActions::showEditionDialog(CommandWidget* commandWidget) { + commandWidget->setUndoStack(mUndoStack); + + EditionDialog* dialog = new EditionDialog(commandWidget, mTutorialEditor); + dialog->setObjectName("editionDialog"); + int dialogCode = dialog->exec(); + dialog->deleteLater(); + + return dialogCode; +} + +//private slots: + +void EditActions::setTutorialInformation() { + showEditionDialog(new TutorialInformationWidget( + mTutorialEditor->tutorial())); +} + +void EditActions::setTutorialLicense() { + showEditionDialog(new LicenseWidget(mTutorialEditor->tutorial())); +} + +void EditActions::setTutorialSetup() { + showEditionDialog(new TutorialCustomCodeWidget(mTutorialEditor->tutorial(), + TutorialCustomCodeWidget::Setup)); +} + +void EditActions::setTutorialTearDown() { + showEditionDialog(new TutorialCustomCodeWidget(mTutorialEditor->tutorial(), + TutorialCustomCodeWidget::TearDown)); +} + +void EditActions::addStep() { + Step* step = new Step(); + + QUndoCommand* parentCommand = new QUndoCommand(); + parentCommand->setText(i18nc("@action", "Add step")); + TutorialCommands(mTutorialEditor->tutorial()).addStep(step, parentCommand); + + CommandWidget* widget = new StepDataWidget(step); + widget->setParentUndoCommand(parentCommand); + if (showEditionDialog(widget) == QDialog::Rejected) { + delete parentCommand; + } +} + +void EditActions::setStepData() { + Q_ASSERT(mCurrentStep); + + showEditionDialog(new StepDataWidget(mCurrentStep)); +} + +void EditActions::setStepSetup() { + showEditionDialog(new StepCustomCodeWidget(mCurrentStep, + StepCustomCodeWidget::Setup)); +} + +void EditActions::setStepTearDown() { + showEditionDialog(new StepCustomCodeWidget(mCurrentStep, + StepCustomCodeWidget::TearDown)); +} + +void EditActions::removeStep() { + Q_ASSERT(mCurrentStep); + + TutorialCommands tutorialCommands(mTutorialEditor->tutorial()); + mUndoStack->push(tutorialCommands.removeStep(mCurrentStep)); +} + +void EditActions::addReaction() { + Q_ASSERT(mCurrentStep); + + Reaction* reaction = new Reaction(); + + QUndoCommand* parentCommand = new QUndoCommand(); + parentCommand->setText(i18nc("@action", "Add reaction")); + StepCommands(mCurrentStep).addReaction(reaction, parentCommand); + + CommandWidget* widget = new ReactionWidget(reaction); + widget->setParentUndoCommand(parentCommand); + if (showEditionDialog(widget) == QDialog::Rejected) { + delete parentCommand; + } +} + +void EditActions::setReactionData() { + Q_ASSERT(mCurrentReaction); + + showEditionDialog(new ReactionWidget(mCurrentReaction)); +} + +void EditActions::removeReaction() { + Q_ASSERT(mCurrentStep); + + mUndoStack->push(StepCommands(mCurrentStep).removeReaction( + mCurrentReaction)); +} Property changes on: trunk/ktutorial/ktutorial-editor/src/EditActions.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/EditActions.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/EditActions.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/EditActions.h 2010-03-31 16:21:39 UTC (rev 225) @@ -0,0 +1,200 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef EDITACTIONS_H +#define EDITACTIONS_H + +#include <QObject> + +class CommandWidget; +class KTutorialEditor; +class KUndoStack; +class Reaction; +class Step; + +/** + * Edition related actions. + * EditActions provide the actions to edit a tutorial (set the setup code, add a + * step...), and also actions to undo and redo the edition. + * + * KTutorialEditor notifies EditActions when a step or reaction is selected, so + * it can know which step or reaction have to be edited. EditActions provides + * information about whether the tutorial is clean (not modified after the last + * time it was saved) or not, and allows to clear the command stack (for + * example, when a new file is opened) or set it as clean. + * + * The KTutorialEditor window is also used as the parent for every dialog shown + * by the actions. + */ +class EditActions: public QObject { +Q_OBJECT +public: + + /** + * Creates a new EditActions for the given KTutorialEditor. + * All the actions are set up and added to the KTutorialEditor. + * + * @param tutorialEditor The KTutorialEditor to work with. + */ + explicit EditActions(KTutorialEditor* tutorialEditor); + +public: + + /** + * Clears the stack of undoable commands. + */ + void clearCommands(); + + /** + * Sets the tutorial as clean. + */ + void setClean(); + +public Q_SLOTS: + + /** + * Sets the current step and enables or disables the actions that depend on + * a step as needed. + * + * @param step The step to select, or null to deselect the current one. + */ + void selectStep(Step* step); + + /** + * Sets the current reaction and enables or disables the actions that depend + * on a reaction as needed. + * + * @param reaction The reaction to select, or null to deselect the current + * one. + */ + void selectReaction(Reaction* reaction); + +Q_SIGNALS: + + /** + * Emitted when the clean state changes. + * + * @param clean True if the tutorial is clean, false otherwise. + */ + void cleanChanged(bool clean); + +private: + + /** + * The KTutorialEditor to work with. + */ + KTutorialEditor* mTutorialEditor; + + /** + * The stack of undoable commands. + */ + KUndoStack* mUndoStack; + + /** + * The currently selected step. + */ + Step* mCurrentStep; + + /** + * The currently selected reaction. + */ + Reaction* mCurrentReaction; + + /** + * Sets up all the edit related actions. + */ + void setupActions(); + + /** + * Shows an EditionDialog for the given CommandWidget. + * The undo stack used in the CommandWidget is mUndoStack. + * + * @param commandWidget The CommandWidget to wrap. + * @return QDialog::Accepted if the dialog was accepted, or + * QDialog::Rejected if the dialog was rejected. + */ + int showEditionDialog(CommandWidget* commandWidget); + +private Q_SLOTS: + + /** + * Shows a TutorialInformationWidget for the tutorial. + */ + void setTutorialInformation(); + + /** + * Shows a LicenseWidget for the tutorial. + */ + void setTutorialLicense(); + + /** + * Shows a TutorialCustomCodeWidget for the setup code of the tutorial. + */ + void setTutorialSetup(); + + /** + * Shows a TutorialCustomCodeWidget for the tear down code of the tutorial. + */ + void setTutorialTearDown(); + + /** + * Adds a new step to the tutorial after showing a StepDataWidget for it. + * The step isn't added if the dialog is cancelled. + */ + void addStep(); + + /** + * Shows a StepDataWidget for the current step. + */ + void setStepData(); + + /** + * Shows a StepCustomCodeWidget for the setup code of the current step. + */ + void setStepSetup(); + + /** + * Shows a StepCustomCodeWidget for the tear down code of the current step. + */ + void setStepTearDown(); + + /** + * Removes the current step from the tutorial. + */ + void removeStep(); + + /** + * Adds a new reaction to the current step after showing a ReactionWidget + * for it. + * The reaction isn't added if the dialog is cancelled. + */ + void addReaction(); + + /** + * Shows a ReactionWidget for the current reaction. + */ + void setReactionData(); + + /** + * Removes the current reaction from its step. + */ + void removeReaction(); + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/EditActions.h ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp 2010-03-31 06:58:14 UTC (rev 224) +++ trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp 2010-03-31 16:21:39 UTC (rev 225) @@ -19,54 +19,45 @@ #include "KTutorialEditor.h" #include <QDockWidget> -#include <QTreeView> #include <KAction> #include <KActionCollection> #include <KApplication> +#include <KConfigGroup> #include <KLocalizedString> -#include <KUndoStack> +#include "EditActions.h" #include "FileActions.h" -#include "commands/StepCommands.h" -#include "commands/TutorialCommands.h" -#include "data/Reaction.h" -#include "data/Step.h" #include "data/Tutorial.h" #include "view/ActionListWidget.h" #include "view/AutoExpandableTreeView.h" -#include "view/EditionDialog.h" -#include "view/LicenseWidget.h" -#include "view/ReactionWidget.h" -#include "view/StepCustomCodeWidget.h" -#include "view/StepDataWidget.h" #include "view/TreeModel.h" -#include "view/TutorialCustomCodeWidget.h" -#include "view/TutorialInformationWidget.h" #include "view/TutorialTreeItem.h" #include "view/TutorialTreeSelectionManager.h" //public: KTutorialEditor::KTutorialEditor(): KXmlGuiWindow(0), - mTutorial(0), - mCurrentStep(0), - mCurrentReaction(0) { + mTutorial(0) { mTreeView = new AutoExpandableTreeView(); mTreeView->setObjectName("centralTreeView"); setCentralWidget(mTreeView); - mUndoStack = new KUndoStack(this); - connect(mUndoStack, SIGNAL(cleanChanged(bool)), + setupDocks(); + + setupActions(); + + connect(mEditActions, SIGNAL(cleanChanged(bool)), this, SIGNAL(cleanChanged(bool))); connect(this, SIGNAL(cleanChanged(bool)), this, SLOT(handleUndoStackCleanChanged(bool))); - setupDocks(); + //The actions can not be added in setupDocks because setupActions() needs + //the docks to be created (to get their toggleAction), so it can be called + //before setupDocks(). + setupActionListWidgets(); - setupActions(); - mFileActions->newTutorial(); setupGUI(); @@ -77,7 +68,7 @@ } void KTutorialEditor::setClean() { - mUndoStack->setClean(); + mEditActions->setClean(); //Force clean state, as setting an empty stack as clean would not emit //cleanChanged() @@ -137,11 +128,11 @@ new TutorialTreeSelectionManager(mTreeView->selectionModel(), mTreeView->selectionModel()); connect(selectionManager, SIGNAL(stepSelected(Step*)), - this, SLOT(selectStep(Step*))); + mEditActions, SLOT(selectStep(Step*))); connect(selectionManager, SIGNAL(reactionSelected(Reaction*)), - this, SLOT(selectReaction(Reaction*))); + mEditActions, SLOT(selectReaction(Reaction*))); - mUndoStack->clear(); + mEditActions->clearCommands(); delete mTutorial; mTutorial = tutorial; @@ -168,144 +159,63 @@ KStandardAction::quit(this, SLOT(close()), actionCollection()); - mUndoStack->createUndoAction(actionCollection()); + mEditActions = new EditActions(this); - mUndoStack->createRedoAction(actionCollection()); + actionCollection()->addAction("showEditTutorialDock", + mTutorialActionDock->toggleViewAction()); + actionCollection()->addAction("showEditStepDock", + mStepActionDock->toggleViewAction()); + actionCollection()->addAction("showEditReactionDock", + mReactionActionDock->toggleViewAction()); +} +void KTutorialEditor::setupActionListWidgets() { ActionListWidget* actionListWidget = new ActionListWidget(mTutorialActionDock); - KAction* action = new KAction(this); - action->setText(i18nc("@action", "Set information...")); - action->setStatusTip(i18nc("@info:status", "Set the name and description " -"of the tutorial.")); - action->setIcon(KIcon("documentinfo")); - actionCollection()->addAction("setTutorialInformation", action); - connect(action, SIGNAL(triggered(bool)), - this, SLOT(setTutorialInformation())); + QAction* action = actionCollection()->action("setTutorialInformation"); actionListWidget->addAction(action); - action = new KAction(this); - action->setText(i18nc("@action", "Set license...")); - action->setStatusTip(i18nc("@info:status", "Set the license text of the " -"tutorial.")); - action->setIcon(KIcon("document-edit")); - actionCollection()->addAction("setTutorialLicense", action); - connect(action, SIGNAL(triggered(bool)), this, SLOT(setTutorialLicense())); + action = actionCollection()->action("setTutorialLicense"); actionListWidget->addAction(action); - action = new KAction(this); - action->setText(i18nc("@action", "Set setup code...")); - action->setStatusTip(i18nc("@info:status", "Set the custom code to be " -"executed when the tutorial starts.")); - action->setIcon(KIcon("code-function")); - actionCollection()->addAction("setTutorialSetup", action); - connect(action, SIGNAL(triggered(bool)), this, SLOT(setTutorialSetup())); + action = actionCollection()->action("setTutorialSetup"); actionListWidget->addAction(action); - action = new KAction(this); - action->setText(i18nc("@action", "Set tear down code...")); - action->setStatusTip(i18nc("@info:status", "Set the custom code to be " -"executed when the tutorial finishes.")); - action->setIcon(KIcon("code-function")); - actionCollection()->addAction("setTutorialTearDown", action); - connect(action, SIGNAL(triggered(bool)), this, SLOT(setTutorialTearDown())); + action = actionCollection()->action("setTutorialTearDown"); actionListWidget->addAction(action); mTutorialActionDock->setWidget(actionListWidget); actionListWidget = new ActionListWidget(mStepActionDock); - action = new KAction(this); - action->setText(i18nc("@action", "Add step...")); - action->setStatusTip(i18nc("@info:status", "Add a new step to the " -"tutorial.")); - action->setIcon(KIcon("list-add")); - actionCollection()->addAction("addStep", action); - connect(action, SIGNAL(triggered(bool)), this, SLOT(addStep())); + action = actionCollection()->action("addStep"); actionListWidget->addAction(action); - action = new KAction(this); - action->setText(i18nc("@action", "Set data...")); - action->setStatusTip(i18nc("@info:status", "Set the name and text of the " -"currently selected step.")); - action->setIcon(KIcon("document-edit")); - action->setEnabled(false); - actionCollection()->addAction("setStepData", action); - connect(action, SIGNAL(triggered(bool)), this, SLOT(setStepData())); + action = actionCollection()->action("setStepData"); actionListWidget->addAction(action); - action = new KAction(this); - action->setText(i18nc("@action", "Set setup code...")); - action->setStatusTip(i18nc("@info:status", "Set the custom code to be " -"executed when the tutorial passes to the currently selected step.")); - action->setIcon(KIcon("code-function")); - action->setEnabled(false); - actionCollection()->addAction("setStepSetup", action); - connect(action, SIGNAL(triggered(bool)), this, SLOT(setStepSetup())); + action = actionCollection()->action("setStepSetup"); actionListWidget->addAction(action); - action = new KAction(this); - action->setText(i18nc("@action", "Set tear down code...")); - action->setStatusTip(i18nc("@info:status", "Set the custom code to be " -"executed when the tutorial changes from the currently selected step to " -"another step.")); - action->setIcon(KIcon("code-function")); - action->setEnabled(false); - actionCollection()->addAction("setStepTearDown", action); - connect(action, SIGNAL(triggered(bool)), this, SLOT(setStepTearDown())); + action = actionCollection()->action("setStepTearDown"); actionListWidget->addAction(action); - action = new KAction(this); - action->setText(i18nc("@action", "Remove step")); - action->setStatusTip(i18nc("@info:status", "Removes the currently selected " -"step from the tutorial.")); - action->setIcon(KIcon("list-remove")); - action->setEnabled(false); - actionCollection()->addAction("removeStep", action); - connect(action, SIGNAL(triggered(bool)), this, SLOT(removeStep())); + action = actionCollection()->action("removeStep"); actionListWidget->addAction(action); mStepActionDock->setWidget(actionListWidget); actionListWidget = new ActionListWidget(mReactionActionDock); - action = new KAction(this); - action->setText(i18nc("@action", "Add reaction...")); - action->setStatusTip(i18nc("@info:status", "Add a new reaction to the " -"selected step.")); - action->setIcon(KIcon("list-add")); - action->setEnabled(false); - actionCollection()->addAction("addReaction", action); - connect(action, SIGNAL(triggered(bool)), this, SLOT(addReaction())); + action = actionCollection()->action("addReaction"); actionListWidget->addAction(action); - action = new KAction(this); - action->setText(i18nc("@action", "Set data...")); - action->setStatusTip(i18nc("@info:status", "Set the trigger and the " -"response of the currently selected reaction.")); - action->setIcon(KIcon("document-edit")); - action->setEnabled(false); - actionCollection()->addAction("setReactionData", action); - connect(action, SIGNAL(triggered(bool)), this, SLOT(setReactionData())); + action = actionCollection()->action("setReactionData"); actionListWidget->addAction(action); - action = new KAction(this); - action->setText(i18nc("@action", "Remove reaction")); - action->setStatusTip(i18nc("@info:status", "Removes the currently selected " -"reaction from its step.")); - action->setIcon(KIcon("list-remove")); - action->setEnabled(false); - actionCollection()->addAction("removeReaction", action); - connect(action, SIGNAL(triggered(bool)), this, SLOT(removeReaction())); + action = actionCollection()->action("removeReaction"); actionListWidget->addAction(action); mReactionActionDock->setWidget(actionListWidget); - - actionCollection()->addAction("showEditTutorialDock", - mTutorialActionDock->toggleViewAction()); - actionCollection()->addAction("showEditStepDock", - mStepActionDock->toggleViewAction()); - actionCollection()->addAction("showEditReactionDock", - mReactionActionDock->toggleViewAction()); } QString KTutorialEditor::captionFromTutorialUrl() { @@ -322,49 +232,8 @@ return caption; } -int KTutorialEditor::showEditionDialog(CommandWidget* commandWidget) { - commandWidget->setUndoStack(mUndoStack); - - EditionDialog* dialog = new EditionDialog(commandWidget, this); - dialog->setObjectName("editionDialog"); - int dialogCode = dialog->exec(); - dialog->deleteLater(); - - return dialogCode; -} - //private slots: -void KTutorialEditor::selectStep(Step* step) { - mCurrentStep = step; - - if (mCurrentStep) { - actionCollection()->action("setStepData")->setEnabled(true); - actionCollection()->action("setStepSetup")->setEnabled(true); - actionCollection()->action("setStepTearDown")->setEnabled(true); - actionCollection()->action("removeStep")->setEnabled(true); - actionCollection()->action("addReaction")->setEnabled(true); - } else { - actionCollection()->action("setStepData")->setEnabled(false); - actionCollection()->action("setStepSetup")->setEnabled(false); - actionCollection()->action("setStepTearDown")->setEnabled(false); - actionCollection()->action("removeStep")->setEnabled(false); - actionCollection()->action("addReaction")->setEnabled(false); - } -} - -void KTutorialEditor::selectReaction(Reaction* reaction) { - mCurrentReaction = reaction; - - if (mCurrentReaction) { - actionCollection()->action("setReactionData")->setEnabled(true); - actionCollection()->action("removeReaction")->setEnabled(true); - } else { - actionCollection()->action("setReactionData")->setEnabled(false); - actionCollection()->action("removeReaction")->setEnabled(false); - } -} - void KTutorialEditor::handleUndoStackCleanChanged(bool clean) { QString caption = captionFromTutorialUrl(); if (clean) { @@ -374,86 +243,3 @@ tutorial was modified but not saved yet", "%1 [not saved]", caption)); } } - -void KTutorialEditor::setTutorialInformation() { - showEditionDialog(new TutorialInformationWidget(mTutorial)); -} - -void KTutorialEditor::setTutorialLicense() { - showEditionDialog(new LicenseWidget(mTutorial)); -} - -void KTutorialEditor::setTutorialSetup() { - showEditionDialog(new TutorialCustomCodeWidget(mTutorial, - TutorialCustomCodeWidget::Setup)); -} - -void KTutorialEditor::setTutorialTearDown() { - showEditionDialog(new TutorialCustomCodeWidget(mTutorial, - TutorialCustomCodeWidget::TearDown)); -} - -void KTutorialEditor::addStep() { - Step* step = new Step(); - - QUndoCommand* parentCommand = new QUndoCommand(); - parentCommand->setText(i18nc("@action", "Add step")); - TutorialCommands(mTutorial).addStep(step, parentCommand); - - CommandWidget* widget = new StepDataWidget(step); - widget->setParentUndoCommand(parentCommand); - if (showEditionDialog(widget) == QDialog::Rejected) { - delete parentCommand; - } -} - -void KTutorialEditor::setStepData() { - Q_ASSERT(mCurrentStep); - - showEditionDialog(new StepDataWidget(mCurrentStep)); -} - -void KTutorialEditor::setStepSetup() { - showEditionDialog(new StepCustomCodeWidget(mCurrentStep, - StepCustomCodeWidget::Setup)); -} - -void KTutorialEditor::setStepTearDown() { - showEditionDialog(new StepCustomCodeWidget(mCurrentStep, - StepCustomCodeWidget::TearDown)); -} - -void KTutorialEditor::removeStep() { - Q_ASSERT(mCurrentStep); - - mUndoStack->push(TutorialCommands(mTutorial).removeStep(mCurrentStep)); -} - -void KTutorialEditor::addReaction() { - Q_ASSERT(mCurrentStep); - - Reaction* reaction = new Reaction(); - - QUndoCommand* parentCommand = new QUndoCommand(); - parentCommand->setText(i18nc("@action", "Add reaction")); - StepCommands(mCurrentStep).addReaction(reaction, parentCommand); - - CommandWidget* widget = new ReactionWidget(reaction); - widget->setParentUndoCommand(parentCommand); - if (showEditionDialog(widget) == QDialog::Rejected) { - delete parentCommand; - } -} - -void KTutorialEditor::setReactionData() { - Q_ASSERT(mCurrentReaction); - - showEditionDialog(new ReactionWidget(mCurrentReaction)); -} - -void KTutorialEditor::removeReaction() { - Q_ASSERT(mCurrentStep); - - mUndoStack->push(StepCommands(mCurrentStep).removeReaction( - mCurrentReaction)); -} Modified: trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h 2010-03-31 06:58:14 UTC (rev 224) +++ trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h 2010-03-31 16:21:39 UTC (rev 225) @@ -22,13 +22,9 @@ #include <KXmlGuiWindow> #include <KUrl> -class CommandWidget; -class EditionWidget; +class EditActions; class FileActions; -class KUndoStack; class QTreeView; -class Reaction; -class Step; class Tutorial; /** @@ -146,9 +142,9 @@ FileActions* mFileActions; /** - * The stack of undoable commands. + * The edit related actions and data. */ - KUndoStack* mUndoStack; + EditActions* mEditActions; /** * The tutorial being edited. @@ -156,16 +152,6 @@ Tutorial* mTutorial; /** - * The currently selected step. - */ - Step* mCurrentStep; - - /** - * The currently selected reaction. - */ - Reaction* mCurrentReaction; - - /** * Sets up the dock widgets. */ void setupDocks(); @@ -176,6 +162,11 @@ void setupActions(); /** + * Sets up the widgets to show the actions in the docks. + */ + void setupActionListWidgets(); + + /** * Returns a caption (window title) string based on the tutorial URL. * The caption contains the URL, which is truncated if it is too lengthy. If * the URL is empty, "New file" is returned. @@ -184,36 +175,9 @@ */ QString captionFromTutorialUrl(); - /** - * Shows an EditionDialog for the given CommandWidget. - * The undo stack used in the CommandWidget is mUndoStack. - * - * @param commandWidget The CommandWidget to wrap. - * @return QDialog::Accepted if the dialog was accepted, or - * QDialog::Rejected if the dialog was rejected. - */ - int showEditionDialog(CommandWidget* commandWidget); - private Q_SLOTS: /** - * Sets the current step and enables or disables the actions that depend on - * a step as needed. - * - * @param step The step to select, or null to deselect the current one. - */ - void selectStep(Step* step); - - /** - * Sets the current reaction and enables or disables the actions that depend - * on a reaction as needed. - * - * @param reaction The reaction to select, or null to deselect the current - * one. - */ - void selectReaction(Reaction* reaction); - - /** * Modifies the caption based on the clean state of the stack. * When the stack is not clean, "[not saved]" is added after the caption * (the URL or "New file", depending on the case). Otherwise, the caption is @@ -223,69 +187,6 @@ */ void handleUndoStackCleanChanged(bool clean); - /** - * Shows a TutorialInformationWidget for the tutorial. - */ - void setTutorialInformation(); - - /** - * Shows a LicenseWidget for the tutorial. - */ - void setTutorialLicense(); - - /** - * Shows a TutorialCustomCodeWidget for the setup code of the tutorial. - */ - void setTutorialSetup(); - - /** - * Shows a TutorialCustomCodeWidget for the tear down code of the tutorial. - */ - void setTutorialTearDown(); - - /** - * Adds a new step to the tutorial after showing a StepDataWidget for it. - * The step isn't added if the dialog is cancelled. - */ - void addStep(); - - /** - * Shows a StepDataWidget for the current step. - */ - void setStepData(); - - /** - * Shows a StepCustomCodeWidget for the setup code of the current step. - */ - void setStepSetup(); - - /** - * Shows a StepCustomCodeWidget for the tear down code of the current step. - */ - void setStepTearDown(); - - /** - * Removes the current step from the tutorial. - */ - void removeStep(); - - /** - * Adds a new reaction to the current step after showing a ReactionWidget - * for it. - * The reaction isn't added if the dialog is cancelled. - */ - void addReaction(); - - /** - * Shows a ReactionWidget for the current reaction. - */ - void setReactionData(); - - /** - * Removes the current reaction from its step. - */ - void removeReaction(); - }; #endif This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-31 06:58:20
|
Revision: 224 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=224&view=rev Author: danxuliu Date: 2010-03-31 06:58:14 +0000 (Wed, 31 Mar 2010) Log Message: ----------- Remove unused forward declaration. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/FileActions.h Modified: trunk/ktutorial/ktutorial-editor/src/FileActions.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/FileActions.h 2010-03-31 06:55:32 UTC (rev 223) +++ trunk/ktutorial/ktutorial-editor/src/FileActions.h 2010-03-31 06:58:14 UTC (rev 224) @@ -23,7 +23,6 @@ #include <KUrl> -class KActionCollection; class KRecentFilesAction; class KTutorialEditor; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-31 06:55:39
|
Revision: 223 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=223&view=rev Author: danxuliu Date: 2010-03-31 06:55:32 +0000 (Wed, 31 Mar 2010) Log Message: ----------- Refactor KTutorialEditor class to extract file related actions to its own class, FileActions. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h Added Paths: ----------- trunk/ktutorial/ktutorial-editor/src/FileActions.cpp trunk/ktutorial/ktutorial-editor/src/FileActions.h Modified: trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt 2010-03-31 05:33:29 UTC (rev 222) +++ trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt 2010-03-31 06:55:32 UTC (rev 223) @@ -11,6 +11,7 @@ set(ktutorial_editor_SRCS Exception.cpp + FileActions.cpp KTutorialEditor.cpp ) Added: trunk/ktutorial/ktutorial-editor/src/FileActions.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/FileActions.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/FileActions.cpp 2010-03-31 06:55:32 UTC (rev 223) @@ -0,0 +1,268 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "FileActions.h" + +#include <KActionCollection> +#include <KFileDialog> +#include <KFileFilterCombo> +#include <KLocalizedString> +#include <KMessageBox> +#include <KRecentFilesAction> +#include <KStandardAction> + +#include "KTutorialEditor.h" +#include "data/Tutorial.h" +#include "serialization/Serialization.h" + +//public: + +FileActions::FileActions(KTutorialEditor* tutorialEditor): + QObject(tutorialEditor), + mTutorialEditor(tutorialEditor), + mClean(true), + mRecentFilesAction(0) { + + setupActions(); + + connect(tutorialEditor, SIGNAL(cleanChanged(bool)), + this, SLOT(handleUndoStackCleanChanged(bool))); +} + +FileActions::~FileActions() { + mRecentFilesAction->saveEntries(KGlobal::config()->group("RecentFiles")); +} + +const KUrl& FileActions::tutorialUrl() const { + return mTutorialUrl; +} + +bool FileActions::queryCloseTutorial() { + if (mClean) { + return true; + } + + QString text = i18nc("@label", "The tutorial has been modified.<nl/>" +"Do you want to save your changes or discard them?"); + QString caption = i18nc("@title:window", "Close tutorial"); + int button = KMessageBox::warningYesNoCancel(mTutorialEditor, text, caption, + KStandardGuiItem::save(), + KStandardGuiItem::discard()); + + if (button == KMessageBox::Cancel) { + return false; + } + + if (button == KMessageBox::Yes) { + return saveTutorial(); + } + + return true; +} + +//public slots: + +//Don't use a reference to the URL, as if it is the argument in +//urlSelected(KUrl) signal emitted by mRecentFilesAction, it is removed in +//mRecentFilesAction->addUrl(KUrl), which leads to a crash +void FileActions::loadTutorialFromUrl(KUrl url) { + if (!queryCloseTutorial()) { + return; + } + + Tutorial* tutorial; + try { + tutorial = Serialization(mTutorialEditor).loadTutorial(url); + } catch (IOException e) { + QString text = i18nc("@label", "There was a problem when trying to " +"open the file:<nl/>%1", e.message()); + QString caption = i18nc("@title:window", "File could not be read"); + KMessageBox::error(mTutorialEditor, text, caption); + return; + } catch (DeserializationException e) { + QString text = i18nc("@label", "There was a problem when trying to " +"load the tutorial:<nl/>%1", e.message()); + QString caption = i18nc("@title:window", "Tutorial could not be " +"loaded"); + KMessageBox::error(mTutorialEditor, text, caption); + return; + } + + mTutorialEditor->setTutorialToBeEdited(tutorial); + mRecentFilesAction->addUrl(url); + mTutorialUrl = url; + mTutorialEditor->setClean(); +} + +void FileActions::newTutorial() { + if (!queryCloseTutorial()) { + return; + } + + mTutorialEditor->setTutorialToBeEdited(); + mTutorialUrl = KUrl(); + //Force clean state, as clearing an empty stack (in setTutorialToBeEdited()) + //would not emit cleanChanged() + mTutorialEditor->setClean(); +} + +void FileActions::handleUndoStackCleanChanged(bool clean) { + mClean = clean; + + KActionCollection* actionCollection = mTutorialEditor->actionCollection(); + if (clean && !mTutorialUrl.isEmpty()) { + actionCollection->action("file_save")->setEnabled(false); + } else { + actionCollection->action("file_save")->setEnabled(true); + } +} + +//private: + +void FileActions::setupActions() { + KActionCollection* actionCollection = mTutorialEditor->actionCollection(); + + KStandardAction::openNew(this, SLOT(newTutorial()), actionCollection); + + KStandardAction::open(this, SLOT(openTutorial()), actionCollection); + + mRecentFilesAction = KStandardAction::openRecent( + this, SLOT(loadTutorialFromUrl(KUrl)), actionCollection); + mRecentFilesAction->loadEntries(KGlobal::config()->group("RecentFiles")); + + KStandardAction::save(this, SLOT(saveTutorial()), actionCollection); + + KStandardAction::saveAs(this, SLOT(saveTutorialAs()), actionCollection); + + KAction* action = new KAction(this); + action->setText(i18nc("@action", "Export...")); + action->setStatusTip(i18nc("@info:status", "Exports the tutorial to a " +"script.")); + action->setIcon(KIcon("document-export")); + actionCollection->addAction("exportTutorial", action); + connect(action, SIGNAL(triggered(bool)), this, SLOT(exportTutorial())); +} + +//private slots: + +void FileActions::openTutorial() { + KUrl url = mTutorialUrl; + QPointer<KFileDialog> dialog = new KFileDialog(url, QString(), + mTutorialEditor); + + dialog->setCaption(i18nc("@title", "Open Tutorial")); + dialog->setOperationMode(KFileDialog::Opening); + dialog->setFilter(i18nc("@item:inlistbox A KFileDialog filter", + "*.xml|XML file")); + + if (dialog->exec() == QDialog::Rejected) { + return; + } + + loadTutorialFromUrl(dialog->selectedUrl()); +} + +bool FileActions::saveTutorial() { + if (mTutorialUrl.isEmpty()) { + return saveTutorialAs(); + } + + const Tutorial* tutorial = mTutorialEditor->tutorial(); + try { + Serialization(mTutorialEditor).saveTutorial(tutorial, mTutorialUrl); + } catch (IOException e) { + QString text = i18nc("@label", "There was a problem when trying to " +"save the tutorial:<nl/>%1", e.message()); + QString caption = i18nc("@title:window", "Tutorial could not be saved"); + KMessageBox::error(mTutorialEditor, text, caption); + return false; + } + + mTutorialEditor->setClean(); + + return true; +} + +bool FileActions::saveTutorialAs() { + const Tutorial* tutorial = mTutorialEditor->tutorial(); + + KUrl url = mTutorialUrl; + QPointer<KFileDialog> dialog = new KFileDialog(url, QString(), + mTutorialEditor); + + dialog->setSelection(tutorial->id()); + dialog->setCaption(i18nc("@title", "Save Tutorial")); + dialog->setOperationMode(KFileDialog::Saving); + dialog->setConfirmOverwrite(true); + dialog->setFilter(i18nc("@item:inlistbox A KFileDialog filter", + "*.xml|XML file")); + dialog->filterWidget()->setEditable(false); + + if (dialog->exec() == QDialog::Rejected) { + return false; + } + + try { + Serialization(mTutorialEditor).saveTutorial(tutorial, + dialog->selectedUrl()); + } catch (IOException e) { + QString text = i18nc("@label", "There was a problem when trying to " +"save the tutorial:<nl/>%1", e.message()); + QString caption = i18nc("@title:window", "Tutorial could not be saved"); + KMessageBox::error(mTutorialEditor, text, caption); + return false; + } + + mRecentFilesAction->addUrl(dialog->selectedUrl()); + mTutorialUrl = dialog->selectedUrl(); + mTutorialEditor->setClean(); + + return true; +} + +void FileActions::exportTutorial() { + const Tutorial* tutorial = mTutorialEditor->tutorial(); + + KUrl url; + QPointer<KFileDialog> dialog = new KFileDialog(url, QString(), + mTutorialEditor); + + dialog->setSelection(tutorial->id()); + dialog->setCaption(i18nc("@title", "Export Tutorial")); + dialog->setOperationMode(KFileDialog::Saving); + dialog->setConfirmOverwrite(true); + dialog->setFilter(Serialization(mTutorialEditor).availableExporterTypes()); + dialog->filterWidget()->setEditable(false); + + if (dialog->exec() == QDialog::Rejected) { + return; + } + + try { + Serialization(mTutorialEditor).exportTutorial(tutorial, + dialog->currentFilter(), + dialog->selectedUrl()); + } catch (IOException e) { + QString text = i18nc("@label", "There was a problem when trying to " +"save the exported tutorial:<nl/>%1", e.message()); + QString caption = i18nc("@title:window", "Exported tutorial could not " +"be saved"); + KMessageBox::error(mTutorialEditor, text, caption); + return; + } +} Property changes on: trunk/ktutorial/ktutorial-editor/src/FileActions.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/FileActions.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/FileActions.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/FileActions.h 2010-03-31 06:55:32 UTC (rev 223) @@ -0,0 +1,182 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef FILEACTIONS_H +#define FILEACTIONS_H + +#include <QObject> + +#include <KUrl> + +class KActionCollection; +class KRecentFilesAction; +class KTutorialEditor; + +/** + * File related actions. + * FileActions provide the actions that create a new tutorial, open an existing + * tutorial, open one of the recently opened tutorials, save the tutorial or + * export the tutorial. + * + * Note, however, that it does not provide a quit action (as it has more to do + * with the application as a whole than with the files). + * + * FileActions provides also the URL of the current tutorial, and a way to check + * whether it can be closed or not, warning the user if needed. + * + * FileActions works closely with KTutorialEditor. KTutorialEditor is used to + * know the tutorial and whether it is clean or not. FileActions provides the + * tutorial URL and methods to create a new tutorial, load a tutorial from an + * URL and check whether the current tutorial was modified after the last time + * it was saved or not. + * + * The KTutorialEditor window is also used as the parent for every dialog shown + * by the actions. + */ +class FileActions: public QObject { +Q_OBJECT +public: + + /** + * Creates a new FileActions for the given KTutorialEditor. + * All the actions are set up and added to the KTutorialEditor. + * + * @param tutorialEditor The KTutorialEditor to work with. + */ + explicit FileActions(KTutorialEditor* tutorialEditor); + + /** + * Destroys this FileActions. + * The entries in the recent files action are saved in the configuration. + */ + ~FileActions(); + + /** + * Returns the tutorial URL. + * + * @return The tutorial URL. + */ + const KUrl& tutorialUrl() const; + + /** + * Checks whether the current tutorial can be closed or not. + * If the tutorial is not clean, the user is asked if it has to be saved or + * not, or if the close operation should be cancelled. + * + * @return True if the tutorial can be closed, false otherwise. + */ + bool queryCloseTutorial(); + +public Q_SLOTS: + + /** + * Loads the tutorial to be edited from the given URL. + * The tutorial URL is updated and added to the recent files action, and a + * clean state is forced. + * An error message is shown if the tutorial could not be opened. + * + * Nothing is done if the current tutorial, if any, should not be closed. + * + * @param url The URL to load the tutorial from. + */ + void loadTutorialFromUrl(KUrl url); + + /** + * Creates a new empty tutorial replacing the current one, if any. + * The tutorial URL is cleared. + * + * Nothing is done if the current tutorial, if any, should not be closed. + */ + void newTutorial(); + + /** + * Enables or disables Save action based on the clean state of the stack. + * When the stack is clean and the tutorial has an associated URL, the Save + * action is disabled. Otherwise, it is enabled, so if there is no + * associated URL the Save action is always kept enabled, even if the stack + * is clean. + * + * @param clean Whether the undo stack entered clean state or not. + */ + void handleUndoStackCleanChanged(bool clean); + +private: + + /** + * The KTutorialEditor to work with. + */ + KTutorialEditor* mTutorialEditor; + + /** + * The URL to save the tutorial to. + */ + KUrl mTutorialUrl; + + /** + * True if the tutorial was not modified since the last time it was saved, + * false otherwise. + */ + bool mClean; + + /** + * The "Open Recent" action. + */ + KRecentFilesAction* mRecentFilesAction; + + /** + * Sets up all the file related actions. + */ + void setupActions(); + +private Q_SLOTS: + + /** + * Shows a KFileDialog to select the file to open the tutorial from. + * The tutorial is loaded from the URL selected by the user. + */ + void openTutorial(); + + /** + * Saves the tutorial to the tutorial URL. + * A clean state is set. If there is no tutorial URL it behaves like + * saveTutorialAs(). + * An error message is shown if the tutorial could not be saved. + * + * @return True if the tutorial was successfully saved, false otherwise. + */ + bool saveTutorial(); + + /** + * Shows a KFileDialog to select the file to save the tutorial to. + * The tutorial URL is updated and added to the recent files action, and a + * clean state is forced. + * An error message is shown if the tutorial could not be saved. + * + * @return True if the tutorial was successfully saved, false otherwise. + */ + bool saveTutorialAs(); + + /** + * Shows a KFileDialog to select the file to save the exported tutorial in. + * An error message is shown if the tutorial could not be saved. + */ + void exportTutorial(); + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/FileActions.h ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp 2010-03-31 05:33:29 UTC (rev 222) +++ trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp 2010-03-31 06:55:32 UTC (rev 223) @@ -24,20 +24,15 @@ #include <KAction> #include <KActionCollection> #include <KApplication> -#include <KFileDialog> -#include <KFileFilterCombo> #include <KLocalizedString> -#include <KMessageBox> -#include <KRecentFilesAction> #include <KUndoStack> -#include <KIO/NetAccess> +#include "FileActions.h" #include "commands/StepCommands.h" #include "commands/TutorialCommands.h" #include "data/Reaction.h" #include "data/Step.h" #include "data/Tutorial.h" -#include "serialization/Serialization.h" #include "view/ActionListWidget.h" #include "view/AutoExpandableTreeView.h" #include "view/EditionDialog.h" @@ -64,100 +59,55 @@ mUndoStack = new KUndoStack(this); connect(mUndoStack, SIGNAL(cleanChanged(bool)), + this, SIGNAL(cleanChanged(bool))); + connect(this, SIGNAL(cleanChanged(bool)), this, SLOT(handleUndoStackCleanChanged(bool))); setupDocks(); setupActions(); - newTutorial(); + mFileActions->newTutorial(); setupGUI(); } -KTutorialEditor::~KTutorialEditor() { - mRecentFilesAction->saveEntries(KGlobal::config()->group("RecentFiles")); +Tutorial* KTutorialEditor::tutorial() { + return mTutorial; } -//public slots: - -//Don't use a reference to the URL, as if it is the argument in -//urlSelected(KUrl) signal emitted by mRecentFilesAction, it is removed in -//mRecentFilesAction->addUrl(KUrl), which leads to a crash -void KTutorialEditor::loadTutorialFromUrl(KUrl url) { - if (!queryCloseTutorial()) { - return; - } - - Tutorial* tutorial; - try { - tutorial = Serialization(this).loadTutorial(url); - } catch (IOException e) { - QString text = i18nc("@label", "There was a problem when trying to " -"open the file:<nl/>%1", e.message()); - QString caption = i18nc("@title:window", "File could not be read"); - KMessageBox::error(this, text, caption); - return; - } catch (DeserializationException e) { - QString text = i18nc("@label", "There was a problem when trying to " -"load the tutorial:<nl/>%1", e.message()); - QString caption = i18nc("@title:window", "Tutorial could not be " -"loaded"); - KMessageBox::error(this, text, caption); - return; - } - - setTutorialToBeEdited(tutorial); - mRecentFilesAction->addUrl(url); - mTutorialUrl = url; +void KTutorialEditor::setClean() { mUndoStack->setClean(); + //Force clean state, as setting an empty stack as clean would not emit //cleanChanged() handleUndoStackCleanChanged(true); + mFileActions->handleUndoStackCleanChanged(true); } +void KTutorialEditor::loadTutorialFromUrl(const KUrl& url) { + mFileActions->loadTutorialFromUrl(url); +} + //protected: bool KTutorialEditor::queryClose() { - return queryCloseTutorial(); + return mFileActions->queryCloseTutorial(); } void KTutorialEditor::readProperties(const KConfigGroup& configGroup) { KUrl url = configGroup.readEntry("TutorialUrl"); if (!url.isEmpty()) { - loadTutorialFromUrl(url); + mFileActions->loadTutorialFromUrl(url); } } void KTutorialEditor::saveProperties(KConfigGroup& configGroup) { - configGroup.writeEntry("TutorialUrl", mTutorialUrl); + configGroup.writeEntry("TutorialUrl", mFileActions->tutorialUrl()); } //private: -bool KTutorialEditor::queryCloseTutorial() { - if (mUndoStack->isClean()) { - return true; - } - - QString text = i18nc("@label", "The tutorial has been modified.<nl/>" -"Do you want to save your changes or discard them?"); - QString caption = i18nc("@title:window", "Close tutorial"); - int button = KMessageBox::warningYesNoCancel(this, text, caption, - KStandardGuiItem::save(), - KStandardGuiItem::discard()); - - if (button == KMessageBox::Cancel) { - return false; - } - - if (button == KMessageBox::Yes) { - return saveTutorial(); - } - - return true; -} - void KTutorialEditor::setTutorialToBeEdited(Tutorial* tutorial) { if (!tutorial) { tutorial = new Tutorial(this); @@ -214,26 +164,8 @@ } void KTutorialEditor::setupActions() { - KStandardAction::openNew(this, SLOT(newTutorial()), actionCollection()); + mFileActions = new FileActions(this); - KStandardAction::open(this, SLOT(openTutorial()), actionCollection()); - - mRecentFilesAction = KStandardAction::openRecent( - this, SLOT(loadTutorialFromUrl(KUrl)), actionCollection()); - mRecentFilesAction->loadEntries(KGlobal::config()->group("RecentFiles")); - - KStandardAction::save(this, SLOT(saveTutorial()), actionCollection()); - - KStandardAction::saveAs(this, SLOT(saveTutorialAs()), actionCollection()); - - KAction* action = new KAction(this); - action->setText(i18nc("@action", "Export...")); - action->setStatusTip(i18nc("@info:status", "Exports the tutorial to a " -"script.")); - action->setIcon(KIcon("document-export")); - actionCollection()->addAction("exportTutorial", action); - connect(action, SIGNAL(triggered(bool)), this, SLOT(exportTutorial())); - KStandardAction::quit(this, SLOT(close()), actionCollection()); mUndoStack->createUndoAction(actionCollection()); @@ -243,7 +175,7 @@ ActionListWidget* actionListWidget = new ActionListWidget(mTutorialActionDock); - action = new KAction(this); + KAction* action = new KAction(this); action->setText(i18nc("@action", "Set information...")); action->setStatusTip(i18nc("@info:status", "Set the name and description " "of the tutorial.")); @@ -377,12 +309,12 @@ } QString KTutorialEditor::captionFromTutorialUrl() { - if (mTutorialUrl.isEmpty()) { + if (mFileActions->tutorialUrl().isEmpty()) { return i18nc("@title:window Window title for KTutorial editor when the \ tutorial has no associated URL", "New file"); } - QString caption = mTutorialUrl.prettyUrl(); + QString caption = mFileActions->tutorialUrl().prettyUrl(); if (caption.length() > 64) { caption = "..." + caption.right(64); } @@ -441,126 +373,8 @@ setCaption(i18nc("@title:window Wrapper for the window title when the \ tutorial was modified but not saved yet", "%1 [not saved]", caption)); } - - if (clean && !mTutorialUrl.isEmpty()) { - actionCollection()->action("file_save")->setEnabled(false); - } else { - actionCollection()->action("file_save")->setEnabled(true); - } } -void KTutorialEditor::newTutorial() { - if (!queryCloseTutorial()) { - return; - } - - setTutorialToBeEdited(); - mTutorialUrl = KUrl(); - //Force clean state, as clearing an empty stack would not emit - //cleanChanged() - handleUndoStackCleanChanged(true); -} - -void KTutorialEditor::openTutorial() { - KUrl url = mTutorialUrl; - QPointer<KFileDialog> dialog = new KFileDialog(url, QString(), this); - - dialog->setCaption(i18nc("@title", "Open Tutorial")); - dialog->setOperationMode(KFileDialog::Opening); - dialog->setFilter(i18nc("@item:inlistbox A KFileDialog filter", - "*.xml|XML file")); - - if (dialog->exec() == QDialog::Rejected) { - return; - } - - loadTutorialFromUrl(dialog->selectedUrl()); -} - -bool KTutorialEditor::saveTutorial() { - if (mTutorialUrl.isEmpty()) { - return saveTutorialAs(); - } - - try { - Serialization(this).saveTutorial(mTutorial, mTutorialUrl); - } catch (IOException e) { - QString text = i18nc("@label", "There was a problem when trying to " -"save the tutorial:<nl/>%1", e.message()); - QString caption = i18nc("@title:window", "Tutorial could not be saved"); - KMessageBox::error(this, text, caption); - return false; - } - - mUndoStack->setClean(); - - return true; -} - -bool KTutorialEditor::saveTutorialAs() { - KUrl url = mTutorialUrl; - QPointer<KFileDialog> dialog = new KFileDialog(url, QString(), this); - - dialog->setSelection(mTutorial->id()); - dialog->setCaption(i18nc("@title", "Save Tutorial")); - dialog->setOperationMode(KFileDialog::Saving); - dialog->setConfirmOverwrite(true); - dialog->setFilter(i18nc("@item:inlistbox A KFileDialog filter", - "*.xml|XML file")); - dialog->filterWidget()->setEditable(false); - - if (dialog->exec() == QDialog::Rejected) { - return false; - } - - try { - Serialization(this).saveTutorial(mTutorial, dialog->selectedUrl()); - } catch (IOException e) { - QString text = i18nc("@label", "There was a problem when trying to " -"save the tutorial:<nl/>%1", e.message()); - QString caption = i18nc("@title:window", "Tutorial could not be saved"); - KMessageBox::error(this, text, caption); - return false; - } - - mRecentFilesAction->addUrl(dialog->selectedUrl()); - mTutorialUrl = dialog->selectedUrl(); - mUndoStack->setClean(); - //Force clean state, as setting an empty stack as clean would not emit - //cleanChanged() - handleUndoStackCleanChanged(true); - - return true; -} - -void KTutorialEditor::exportTutorial() { - KUrl url; - QPointer<KFileDialog> dialog = new KFileDialog(url, QString(), this); - - dialog->setSelection(mTutorial->id()); - dialog->setCaption(i18nc("@title", "Export Tutorial")); - dialog->setOperationMode(KFileDialog::Saving); - dialog->setConfirmOverwrite(true); - dialog->setFilter(Serialization(this).availableExporterTypes()); - dialog->filterWidget()->setEditable(false); - - if (dialog->exec() == QDialog::Rejected) { - return; - } - - try { - Serialization(this).exportTutorial(mTutorial, dialog->currentFilter(), - dialog->selectedUrl()); - } catch (IOException e) { - QString text = i18nc("@label", "There was a problem when trying to " -"save the exported tutorial:<nl/>%1", e.message()); - QString caption = i18nc("@title:window", "Exported tutorial could not " -"be saved"); - KMessageBox::error(this, text, caption); - return; - } -} - void KTutorialEditor::setTutorialInformation() { showEditionDialog(new TutorialInformationWidget(mTutorial)); } Modified: trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h 2010-03-31 05:33:29 UTC (rev 222) +++ trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h 2010-03-31 06:55:32 UTC (rev 223) @@ -24,7 +24,7 @@ class CommandWidget; class EditionWidget; -class KRecentFilesAction; +class FileActions; class KUndoStack; class QTreeView; class Reaction; @@ -45,25 +45,46 @@ KTutorialEditor(); /** - * Destroys this KTutorialEditor. - * The entries in the recent files action are saved in the configuration. + * Returns the tutorial being edited. + * + * @return The tutorial being edited. */ - virtual ~KTutorialEditor(); + Tutorial* tutorial(); -public Q_SLOTS: + /** + * Sets the tutorial as clean (not modified after the last time it was + * saved). + */ + void setClean(); /** * Loads the tutorial to be edited from the given URL. - * The tutorial URL is updated and added to the recent files action, and a - * clean state is forced. - * An error message is shown if the tutorial couldn't be opened. * - * Nothing is done if the current tutorial, if any, should not be closed. - * * @param url The URL to load the tutorial from. + * @see FileActions::loadTutorialFromUrl(KUrl) */ - void loadTutorialFromUrl(KUrl url); + void loadTutorialFromUrl(const KUrl& url); + /** + * Sets the tutorial to be edited. + * It creates a new tutorial, prepares the tree view to represent it and + * handles the selection of items. + * + * If the tutorial is null, a new empty tutorial is set. + * + * @param tutorial The tutorial to set. + */ + void setTutorialToBeEdited(Tutorial* tutorial = 0); + +Q_SIGNALS: + + /** + * Emitted when the clean state changes. + * + * @param clean True if the tutorial is clean, false otherwise. + */ + void cleanChanged(bool clean); + protected: /** @@ -120,9 +141,9 @@ QDockWidget* mReactionActionDock; /** - * The "Open Recent" action. + * The file related actions and data. */ - KRecentFilesAction* mRecentFilesAction; + FileActions* mFileActions; /** * The stack of undoable commands. @@ -135,11 +156,6 @@ Tutorial* mTutorial; /** - * The URL to save the tutorial to. - */ - KUrl mTutorialUrl; - - /** * The currently selected step. */ Step* mCurrentStep; @@ -150,26 +166,6 @@ Reaction* mCurrentReaction; /** - * Checks whether the tutorial can be closed or not. - * If the tutorial is not clean, the user is asked if it has to be saved or - * not, or if the close operation should be cancelled. - * - * @return True if the tutorial can be closed, false otherwise. - */ - bool queryCloseTutorial(); - - /** - * Sets the tutorial to be edited. - * It creates a new tutorial, prepares the tree view to represent it and - * handles the selection of items. - * - * If the tutorial is null, a new empty tutorial is set. - * - * @param tutorial The tutorial to set. - */ - void setTutorialToBeEdited(Tutorial* tutorial = 0); - - /** * Sets up the dock widgets. */ void setupDocks(); @@ -218,62 +214,16 @@ void selectReaction(Reaction* reaction); /** - * Modifies the caption and enables or disables Save action based on the - * clean state of the stack. + * Modifies the caption based on the clean state of the stack. * When the stack is not clean, "[not saved]" is added after the caption * (the URL or "New file", depending on the case). Otherwise, the caption is * the URL associated to the tutorial. * - * When the stack is clean and the tutorial has an associated URL, the Save - * action is disabled. Otherwise, it is enabled, so if there is no - * associated URL the Save action is always kept enabled, even if the stack - * is clean. - * * @param clean Whether the undo stack entered clean state or not. */ void handleUndoStackCleanChanged(bool clean); /** - * Creates a new empty tutorial replacing the current one, if any. - * The tutorial URL is cleared. - * - * Nothing is done if the current tutorial, if any, should not be closed. - */ - void newTutorial(); - - /** - * Shows a KFileDialog to select the file to open the tutorial from. - * The tutorial is loaded from the URL selected by the user. - */ - void openTutorial(); - - /** - * Saves the tutorial to the tutorial URL. - * A clean state is set. If there is no tutorial URL it behaves like - * saveTutorialAs(). - * An error message is shown if the tutorial couldn't be saved. - * - * @return True if the tutorial was successfully saved, false otherwise. - */ - bool saveTutorial(); - - /** - * Shows a KFileDialog to select the file to save the tutorial to. - * The tutorial URL is updated and added to the recent files action, and a - * clean state is forced. - * An error message is shown if the tutorial couldn't be saved. - * - * @return True if the tutorial was successfully saved, false otherwise. - */ - bool saveTutorialAs(); - - /** - * Shows a KFileDialog to select the file to save the exported tutorial in. - * An error message is shown if the tutorial couldn't be saved. - */ - void exportTutorial(); - - /** * Shows a TutorialInformationWidget for the tutorial. */ void setTutorialInformation(); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-31 05:33:36
|
Revision: 222 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=222&view=rev Author: danxuliu Date: 2010-03-31 05:33:29 +0000 (Wed, 31 Mar 2010) Log Message: ----------- Tutorial argument should be const. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.cpp trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.h Modified: trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.cpp 2010-03-30 19:50:23 UTC (rev 221) +++ trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.cpp 2010-03-31 05:33:29 UTC (rev 222) @@ -60,7 +60,7 @@ return TutorialReader().readTutorial(data); } -void Serialization::saveTutorial(Tutorial* tutorial, const KUrl& url) +void Serialization::saveTutorial(const Tutorial* tutorial, const KUrl& url) throw (IOException) { Q_ASSERT(tutorial); Q_ASSERT(url.isValid()); Modified: trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.h 2010-03-30 19:50:23 UTC (rev 221) +++ trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.h 2010-03-31 05:33:29 UTC (rev 222) @@ -75,7 +75,8 @@ * file. * @see TutorialWriter */ - void saveTutorial(Tutorial* tutorial, const KUrl& url) throw (IOException); + void saveTutorial(const Tutorial* tutorial, const KUrl& url) + throw (IOException); /** * Returns the available exporter types. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-30 19:50:30
|
Revision: 221 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=221&view=rev Author: danxuliu Date: 2010-03-30 19:50:23 +0000 (Tue, 30 Mar 2010) Log Message: ----------- Add AutoExpandableTreeView that expands the items when they are added or modified in the model Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.ui trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt Added Paths: ----------- trunk/ktutorial/ktutorial-editor/src/view/AutoExpandableTreeView.cpp trunk/ktutorial/ktutorial-editor/src/view/AutoExpandableTreeView.h trunk/ktutorial/ktutorial-editor/tests/unit/view/AutoExpandableTreeViewTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp 2010-03-30 07:25:48 UTC (rev 220) +++ trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp 2010-03-30 19:50:23 UTC (rev 221) @@ -39,6 +39,7 @@ #include "data/Tutorial.h" #include "serialization/Serialization.h" #include "view/ActionListWidget.h" +#include "view/AutoExpandableTreeView.h" #include "view/EditionDialog.h" #include "view/LicenseWidget.h" #include "view/ReactionWidget.h" @@ -57,7 +58,7 @@ mCurrentStep(0), mCurrentReaction(0) { - mTreeView = new QTreeView(); + mTreeView = new AutoExpandableTreeView(); mTreeView->setObjectName("centralTreeView"); setCentralWidget(mTreeView); Added: trunk/ktutorial/ktutorial-editor/src/view/AutoExpandableTreeView.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/AutoExpandableTreeView.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/AutoExpandableTreeView.cpp 2010-03-30 19:50:23 UTC (rev 221) @@ -0,0 +1,64 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "AutoExpandableTreeView.h" + +//public: + +AutoExpandableTreeView::AutoExpandableTreeView(QWidget* parent): + QTreeView(parent) { +} + +//protected: + +void AutoExpandableTreeView::dataChanged(const QModelIndex& topLeft, + const QModelIndex& bottomRight) { + QTreeView::dataChanged(topLeft, bottomRight); + + expandParents(topLeft); +} + +void AutoExpandableTreeView::rowsInserted(const QModelIndex& parent, int start, + int end) { + QTreeView::rowsInserted(parent, start, end); + + expand(parent); + expandParents(parent); + + for (int i=start; i<=end; ++i) { + expandRecursive(model()->index(i, 0, parent)); + } +} + +//private: + +void AutoExpandableTreeView::expandParents(const QModelIndex& index) { + QModelIndex parent = index.parent(); + while (parent.isValid()) { + expand(parent); + parent = parent.parent(); + } +} + +void AutoExpandableTreeView::expandRecursive(const QModelIndex& index) { + expand(index); + + for (int i=0; i<model()->rowCount(index); ++i) { + expandRecursive(model()->index(i, 0, index)); + } +} Property changes on: trunk/ktutorial/ktutorial-editor/src/view/AutoExpandableTreeView.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/AutoExpandableTreeView.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/AutoExpandableTreeView.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/AutoExpandableTreeView.h 2010-03-30 19:50:23 UTC (rev 221) @@ -0,0 +1,92 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef AUTOEXPANDABLETREEVIEW_H +#define AUTOEXPANDABLETREEVIEW_H + +#include <QTreeView> + +/** + * Special QTreeView that expands its item when are inserted or changed. + * When an item is inserted, that item, all its children and all its parents are + * expanded. + * When an item is changed, the parents to that item are expanded. Note that + * neither the item nor its children are expanded. + * + * Siblings of parent items are not expanded in any case. Only the parent + * leading to the item to be expanded are expanded. + */ +class AutoExpandableTreeView: public QTreeView { +Q_OBJECT +public: + + /** + * Creates a new AutoExpandableTreeView with the given parent. + * + * @param parent The parent widget. + */ + AutoExpandableTreeView(QWidget* parent = 0); + +protected: + + /** + * This slot is called when items are changed in the model. + * After executing QTreeView default behavior, all the parents of the + * changed items are expanded. All the items should belong to the same + * parent. + * + * Reimplemented from QTreeView::dataChanged(QModelIndex, QModelIndex). + * + * @param topLeft The top left item changed, inclusive. + * @param bottomRight The bottom right item changed, inclusiev. + */ + virtual void dataChanged(const QModelIndex& topLeft, + const QModelIndex& bottomRight); + + /** + * This slot is called when rows are inserted. + * After executing QTreeView default behavior, all the items inserted, all + * their children and their parent are expanded. + * + * Reimplemented from QTreeView::rowsInserted(QModelIndex, int, int). + * + * @param parent The parent index where the children were added. + * @param start The first row inserted, inclusive. + * @param end The last row inserted, inclusive. + */ + virtual void rowsInserted(const QModelIndex& parent, int start, int end); + +private: + + /** + * Expands all the parents of the given index. + * + * @param index The index to expand its parents. + */ + void expandParents(const QModelIndex& index); + + /** + * Expands an index and all its children. + * + * @param index The index to expand. + */ + void expandRecursive(const QModelIndex& index); + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/view/AutoExpandableTreeView.h ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2010-03-30 07:25:48 UTC (rev 220) +++ trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2010-03-30 19:50:23 UTC (rev 221) @@ -1,5 +1,6 @@ set(ktutorial_editor_view_SRCS ActionListWidget.cpp + AutoExpandableTreeView.cpp CommandWidget.cpp EditionDialog.cpp EditionWidget.cpp Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.ui =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.ui 2010-03-30 07:25:48 UTC (rev 220) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.ui 2010-03-30 19:50:23 UTC (rev 221) @@ -19,7 +19,7 @@ </property> <layout class="QVBoxLayout" name="waitForWidgetVerticalLayout"> <item> - <widget class="QTreeView" name="waitForTreeView"/> + <widget class="AutoExpandableTreeView" name="waitForTreeView"/> </item> <item> <layout class="QHBoxLayout" name="horizontalLayout"> @@ -74,6 +74,11 @@ <extends>QPushButton</extends> <header>kpushbutton.h</header> </customwidget> + <customwidget> + <class>AutoExpandableTreeView</class> + <extends>QTreeView</extends> + <header>AutoExpandableTreeView.h</header> + </customwidget> </customwidgets> <resources/> <connections/> Added: trunk/ktutorial/ktutorial-editor/tests/unit/view/AutoExpandableTreeViewTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/AutoExpandableTreeViewTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/AutoExpandableTreeViewTest.cpp 2010-03-30 19:50:23 UTC (rev 221) @@ -0,0 +1,223 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include <QtTest> + +#include "AutoExpandableTreeView.h" + +#include "TextTreeItem.h" +#include "TreeModel.h" + +class AutoExpandableTreeViewTest: public QObject { +Q_OBJECT + +private slots: + + void testConstructor(); + + void testInsertRootItemChild(); + void testInsertDeepNestedChildParentExpanded(); + void testInsertDeepNestedChildParentNotExpanded(); + + void testChangeDeepNestedChild(); + +}; + +void AutoExpandableTreeViewTest::testConstructor() { + QWidget parent; + AutoExpandableTreeView* view = new AutoExpandableTreeView(&parent); + + QCOMPARE(view->parentWidget(), &parent); +} + +void AutoExpandableTreeViewTest::testInsertRootItemChild() { + AutoExpandableTreeView view; + TextTreeItem* rootItem = new TextTreeItem(); + TreeModel model(rootItem); + view.setModel(&model); + + TextTreeItem* item1 = new TextTreeItem(rootItem); + TextTreeItem* item1_1 = new TextTreeItem(item1); + TextTreeItem* item1_1_1 = new TextTreeItem(item1_1); + item1_1->appendChild(item1_1_1); + item1->appendChild(item1_1); + TextTreeItem* item1_2 = new TextTreeItem(item1); + TextTreeItem* item1_2_1 = new TextTreeItem(item1_2); + item1_2->appendChild(item1_2_1); + TextTreeItem* item1_2_2 = new TextTreeItem(item1_2); + TextTreeItem* item1_2_2_1 = new TextTreeItem(item1_2_2); + item1_2_2->appendChild(item1_2_2_1); + TextTreeItem* item1_2_2_2 = new TextTreeItem(item1_2_2); + item1_2_2->appendChild(item1_2_2_2); + item1_2->appendChild(item1_2_2); + item1->appendChild(item1_2); + + rootItem->appendChild(item1); + + QModelIndex index1 = model.index(0, 0); + QVERIFY(view.isExpanded(index1)); + QModelIndex index1_1 = model.index(0, 0, index1); + QVERIFY(view.isExpanded(index1_1)); + QModelIndex index1_2 = model.index(1, 0, index1); + QVERIFY(view.isExpanded(index1_2)); + QModelIndex index1_2_2 = model.index(1, 0, index1_2); + QVERIFY(view.isExpanded(index1_2_2)); +} + +void AutoExpandableTreeViewTest::testInsertDeepNestedChildParentExpanded() { + AutoExpandableTreeView view; + TextTreeItem* rootItem = new TextTreeItem(); + TreeModel model(rootItem); + view.setModel(&model); + + TextTreeItem* item1 = new TextTreeItem(rootItem); + TextTreeItem* item1_1 = new TextTreeItem(item1); + TextTreeItem* item1_1_1 = new TextTreeItem(item1_1); + item1_1->appendChild(item1_1_1); + item1->appendChild(item1_1); + TextTreeItem* item1_2 = new TextTreeItem(item1); + TextTreeItem* item1_2_1 = new TextTreeItem(item1_2); + item1_2->appendChild(item1_2_1); + item1->appendChild(item1_2); + rootItem->appendChild(item1); + + QModelIndex index1 = model.index(0, 0); + view.setExpanded(index1, true); + //Collapse sibling of parent to check that it is not expanded again + QModelIndex index1_1 = model.index(0, 0, index1); + view.setExpanded(index1_1, false); + QModelIndex index1_2 = model.index(1, 0, index1); + view.setExpanded(index1_2, true); + + TextTreeItem* item1_2_2 = new TextTreeItem(item1_2); + TextTreeItem* item1_2_2_1 = new TextTreeItem(item1_2_2); + TextTreeItem* item1_2_2_1_1 = new TextTreeItem(item1_2_2_1); + item1_2_2_1->appendChild(item1_2_2_1_1); + TextTreeItem* item1_2_2_1_2 = new TextTreeItem(item1_2_2_1); + item1_2_2_1->appendChild(item1_2_2_1_2); + item1_2_2->appendChild(item1_2_2_1); + TextTreeItem* item1_2_2_2 = new TextTreeItem(item1_2_2); + item1_2_2->appendChild(item1_2_2_2); + item1_2->appendChild(item1_2_2); + + QVERIFY(view.isExpanded(index1)); + QVERIFY(!view.isExpanded(index1_1)); + QVERIFY(view.isExpanded(index1_2)); + QModelIndex index1_2_2 = model.index(1, 0, index1_2); + QVERIFY(view.isExpanded(index1_2_2)); + QModelIndex index1_2_2_1 = model.index(0, 0, index1_2_2); + QVERIFY(view.isExpanded(index1_2_2_1)); +} + +void AutoExpandableTreeViewTest::testInsertDeepNestedChildParentNotExpanded() { + AutoExpandableTreeView view; + TextTreeItem* rootItem = new TextTreeItem(); + TreeModel model(rootItem); + view.setModel(&model); + + TextTreeItem* item1 = new TextTreeItem(rootItem); + TextTreeItem* item1_1 = new TextTreeItem(item1); + TextTreeItem* item1_1_1 = new TextTreeItem(item1_1); + item1_1->appendChild(item1_1_1); + item1->appendChild(item1_1); + TextTreeItem* item1_2 = new TextTreeItem(item1); + TextTreeItem* item1_2_1 = new TextTreeItem(item1_2); + item1_2->appendChild(item1_2_1); + item1->appendChild(item1_2); + rootItem->appendChild(item1); + + QModelIndex index1 = model.index(0, 0); + view.setExpanded(index1, false); + //Collapse sibling of parent to check that it is not expanded again + QModelIndex index1_1 = model.index(0, 0, index1); + view.setExpanded(index1_1, false); + QModelIndex index1_2 = model.index(1, 0, index1); + view.setExpanded(index1_2, false); + + TextTreeItem* item1_2_2 = new TextTreeItem(item1_2); + TextTreeItem* item1_2_2_1 = new TextTreeItem(item1_2_2); + TextTreeItem* item1_2_2_1_1 = new TextTreeItem(item1_2_2_1); + item1_2_2_1->appendChild(item1_2_2_1_1); + TextTreeItem* item1_2_2_1_2 = new TextTreeItem(item1_2_2_1); + item1_2_2_1->appendChild(item1_2_2_1_2); + item1_2_2->appendChild(item1_2_2_1); + TextTreeItem* item1_2_2_2 = new TextTreeItem(item1_2_2); + item1_2_2->appendChild(item1_2_2_2); + + item1_2->appendChild(item1_2_2); + + QVERIFY(view.isExpanded(index1)); + QVERIFY(!view.isExpanded(index1_1)); + QVERIFY(view.isExpanded(index1_2)); + QModelIndex index1_2_2 = model.index(1, 0, index1_2); + QVERIFY(view.isExpanded(index1_2_2)); + QModelIndex index1_2_2_1 = model.index(0, 0, index1_2_2); + QVERIFY(view.isExpanded(index1_2_2_1)); +} + +void AutoExpandableTreeViewTest::testChangeDeepNestedChild() { + AutoExpandableTreeView view; + TextTreeItem* rootItem = new TextTreeItem(); + TreeModel model(rootItem); + view.setModel(&model); + + TextTreeItem* item1 = new TextTreeItem(rootItem); + TextTreeItem* item1_1 = new TextTreeItem(item1); + TextTreeItem* item1_1_1 = new TextTreeItem(item1_1); + item1_1->appendChild(item1_1_1); + item1->appendChild(item1_1); + TextTreeItem* item1_2 = new TextTreeItem(item1); + TextTreeItem* item1_2_1 = new TextTreeItem(item1_2); + item1_2->appendChild(item1_2_1); + TextTreeItem* item1_2_2 = new TextTreeItem(item1_2); + TextTreeItem* item1_2_2_1 = new TextTreeItem(item1_2_2); + TextTreeItem* item1_2_2_1_1 = new TextTreeItem(item1_2_2_1); + item1_2_2_1->appendChild(item1_2_2_1_1); + TextTreeItem* item1_2_2_1_2 = new TextTreeItem(item1_2_2_1); + item1_2_2_1->appendChild(item1_2_2_1_2); + item1_2_2->appendChild(item1_2_2_1); + TextTreeItem* item1_2_2_2 = new TextTreeItem(item1_2_2); + item1_2_2->appendChild(item1_2_2_2); + item1_2->appendChild(item1_2_2); + item1->appendChild(item1_2); + rootItem->appendChild(item1); + + QModelIndex index1 = model.index(0, 0); + view.setExpanded(index1, false); + //Collapse sibling of parent to check that it is not expanded again + QModelIndex index1_1 = model.index(0, 0, index1); + view.setExpanded(index1_1, false); + QModelIndex index1_2 = model.index(1, 0, index1); + view.setExpanded(index1_2, false); + QModelIndex index1_2_2 = model.index(1, 0, index1_2); + view.setExpanded(index1_2_2, false); + QModelIndex index1_2_2_1 = model.index(0, 0, index1_2_2); + view.setExpanded(index1_2_2_1, false); + + item1_2_2_1->setText("New text"); + + QVERIFY(view.isExpanded(index1)); + QVERIFY(!view.isExpanded(index1_1)); + QVERIFY(view.isExpanded(index1_2)); + QVERIFY(view.isExpanded(index1_2_2)); + QVERIFY(!view.isExpanded(index1_2_2_1)); +} + +QTEST_MAIN(AutoExpandableTreeViewTest) + +#include "AutoExpandableTreeViewTest.moc" Property changes on: trunk/ktutorial/ktutorial-editor/tests/unit/view/AutoExpandableTreeViewTest.cpp ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt 2010-03-30 07:25:48 UTC (rev 220) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt 2010-03-30 19:50:23 UTC (rev 221) @@ -18,6 +18,7 @@ unit_tests( ActionListWidget + AutoExpandableTreeView CommandWidget EditionDialog LicenseWidget @@ -53,6 +54,7 @@ mem_tests( ActionListWidget + AutoExpandableTreeView CommandWidget EditionDialog LicenseWidget This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-30 07:25:54
|
Revision: 220 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=220&view=rev Author: danxuliu Date: 2010-03-30 07:25:48 +0000 (Tue, 30 Mar 2010) Log Message: ----------- Fix keeping the tutorial but changing the tutorial URL when the current tutorial was tried to be closed and the user cancelled the operation. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h Modified: trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp 2010-03-30 07:12:38 UTC (rev 219) +++ trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp 2010-03-30 07:25:48 UTC (rev 220) @@ -84,6 +84,10 @@ //urlSelected(KUrl) signal emitted by mRecentFilesAction, it is removed in //mRecentFilesAction->addUrl(KUrl), which leads to a crash void KTutorialEditor::loadTutorialFromUrl(KUrl url) { + if (!queryCloseTutorial()) { + return; + } + Tutorial* tutorial; try { tutorial = Serialization(this).loadTutorial(url); @@ -154,10 +158,6 @@ } void KTutorialEditor::setTutorialToBeEdited(Tutorial* tutorial) { - if (!queryCloseTutorial()) { - return; - } - if (!tutorial) { tutorial = new Tutorial(this); } @@ -449,6 +449,10 @@ } void KTutorialEditor::newTutorial() { + if (!queryCloseTutorial()) { + return; + } + setTutorialToBeEdited(); mTutorialUrl = KUrl(); //Force clean state, as clearing an empty stack would not emit Modified: trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h 2010-03-30 07:12:38 UTC (rev 219) +++ trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h 2010-03-30 07:25:48 UTC (rev 220) @@ -58,6 +58,8 @@ * clean state is forced. * An error message is shown if the tutorial couldn't be opened. * + * Nothing is done if the current tutorial, if any, should not be closed. + * * @param url The URL to load the tutorial from. */ void loadTutorialFromUrl(KUrl url); @@ -163,8 +165,6 @@ * * If the tutorial is null, a new empty tutorial is set. * - * Nothing is done if the previous tutorial should not be closed. - * * @param tutorial The tutorial to set. */ void setTutorialToBeEdited(Tutorial* tutorial = 0); @@ -236,6 +236,8 @@ /** * Creates a new empty tutorial replacing the current one, if any. * The tutorial URL is cleared. + * + * Nothing is done if the current tutorial, if any, should not be closed. */ void newTutorial(); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-30 07:12:49
|
Revision: 219 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=219&view=rev Author: danxuliu Date: 2010-03-30 07:12:38 +0000 (Tue, 30 Mar 2010) Log Message: ----------- Add "Open Recent" action Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h Modified: trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp 2010-03-30 05:03:47 UTC (rev 218) +++ trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp 2010-03-30 07:12:38 UTC (rev 219) @@ -28,6 +28,7 @@ #include <KFileFilterCombo> #include <KLocalizedString> #include <KMessageBox> +#include <KRecentFilesAction> #include <KUndoStack> #include <KIO/NetAccess> @@ -73,7 +74,16 @@ setupGUI(); } -void KTutorialEditor::loadTutorialFromUrl(const KUrl& url) { +KTutorialEditor::~KTutorialEditor() { + mRecentFilesAction->saveEntries(KGlobal::config()->group("RecentFiles")); +} + +//public slots: + +//Don't use a reference to the URL, as if it is the argument in +//urlSelected(KUrl) signal emitted by mRecentFilesAction, it is removed in +//mRecentFilesAction->addUrl(KUrl), which leads to a crash +void KTutorialEditor::loadTutorialFromUrl(KUrl url) { Tutorial* tutorial; try { tutorial = Serialization(this).loadTutorial(url); @@ -93,6 +103,7 @@ } setTutorialToBeEdited(tutorial); + mRecentFilesAction->addUrl(url); mTutorialUrl = url; mUndoStack->setClean(); //Force clean state, as setting an empty stack as clean would not emit @@ -206,6 +217,10 @@ KStandardAction::open(this, SLOT(openTutorial()), actionCollection()); + mRecentFilesAction = KStandardAction::openRecent( + this, SLOT(loadTutorialFromUrl(KUrl)), actionCollection()); + mRecentFilesAction->loadEntries(KGlobal::config()->group("RecentFiles")); + KStandardAction::save(this, SLOT(saveTutorial()), actionCollection()); KStandardAction::saveAs(this, SLOT(saveTutorialAs()), actionCollection()); @@ -503,6 +518,7 @@ return false; } + mRecentFilesAction->addUrl(dialog->selectedUrl()); mTutorialUrl = dialog->selectedUrl(); mUndoStack->setClean(); //Force clean state, as setting an empty stack as clean would not emit Modified: trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h 2010-03-30 05:03:47 UTC (rev 218) +++ trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h 2010-03-30 07:12:38 UTC (rev 219) @@ -24,6 +24,7 @@ class CommandWidget; class EditionWidget; +class KRecentFilesAction; class KUndoStack; class QTreeView; class Reaction; @@ -44,13 +45,22 @@ KTutorialEditor(); /** + * Destroys this KTutorialEditor. + * The entries in the recent files action are saved in the configuration. + */ + virtual ~KTutorialEditor(); + +public Q_SLOTS: + + /** * Loads the tutorial to be edited from the given URL. - * The tutorial URL is updated and a clean state is forced. + * The tutorial URL is updated and added to the recent files action, and a + * clean state is forced. * An error message is shown if the tutorial couldn't be opened. * * @param url The URL to load the tutorial from. */ - void loadTutorialFromUrl(const KUrl& url); + void loadTutorialFromUrl(KUrl url); protected: @@ -108,6 +118,11 @@ QDockWidget* mReactionActionDock; /** + * The "Open Recent" action. + */ + KRecentFilesAction* mRecentFilesAction; + + /** * The stack of undoable commands. */ KUndoStack* mUndoStack; @@ -242,7 +257,8 @@ /** * Shows a KFileDialog to select the file to save the tutorial to. - * The tutorial URL is updated and a clean state is forced. + * The tutorial URL is updated and added to the recent files action, and a + * clean state is forced. * An error message is shown if the tutorial couldn't be saved. * * @return True if the tutorial was successfully saved, false otherwise. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-30 05:03:53
|
Revision: 218 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=218&view=rev Author: danxuliu Date: 2010-03-30 05:03:47 +0000 (Tue, 30 Mar 2010) Log Message: ----------- Add support to save and restore sessions. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h trunk/ktutorial/ktutorial-editor/src/main.cpp Modified: trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp 2010-03-30 03:16:07 UTC (rev 217) +++ trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp 2010-03-30 05:03:47 UTC (rev 218) @@ -106,6 +106,17 @@ return queryCloseTutorial(); } +void KTutorialEditor::readProperties(const KConfigGroup& configGroup) { + KUrl url = configGroup.readEntry("TutorialUrl"); + if (!url.isEmpty()) { + loadTutorialFromUrl(url); + } +} + +void KTutorialEditor::saveProperties(KConfigGroup& configGroup) { + configGroup.writeEntry("TutorialUrl", mTutorialUrl); +} + //private: bool KTutorialEditor::queryCloseTutorial() { Modified: trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h 2010-03-30 03:16:07 UTC (rev 217) +++ trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h 2010-03-30 05:03:47 UTC (rev 218) @@ -65,6 +65,26 @@ */ virtual bool queryClose(); + /** + * Restores the session based on the saved state. + * If "TutorialURL" is not empty, the tutorial is loaded from that URL. + * + * Reimplemented from KMainWindow::readProperties(const KConfigGroup&). + * + * @param configGroup The KConfigGroup to read the state from. + */ + virtual void readProperties(const KConfigGroup& configGroup); + + /** + * Saves the state to restore the session. + * The tutorial URL is saved as "TutorialURL". + * + * Reimplemented from KMainWindow::saveProperties(KConfigGroup&). + * + * @param configGroup The KConfigGroup to save the state to. + */ + virtual void saveProperties(KConfigGroup& configGroup); + private: /** Modified: trunk/ktutorial/ktutorial-editor/src/main.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/main.cpp 2010-03-30 03:16:07 UTC (rev 217) +++ trunk/ktutorial/ktutorial-editor/src/main.cpp 2010-03-30 05:03:47 UTC (rev 218) @@ -41,6 +41,10 @@ KCmdLineArgs::addCmdLineOptions(options); KApplication app; + if (app.isSessionRestored()) { + kRestoreMainWindows<KTutorialEditor>(); + return app.exec(); + } KTutorialEditor* window = new KTutorialEditor(); window->show(); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-30 03:16:13
|
Revision: 217 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=217&view=rev Author: danxuliu Date: 2010-03-30 03:16:07 +0000 (Tue, 30 Mar 2010) Log Message: ----------- Provide the main window to Serialization to be used in KIO::NetAccess operations. Serialization methods were changed from class methods to instance methods. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.cpp trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.h trunk/ktutorial/ktutorial-editor/tests/unit/serialization/SerializationTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp 2010-03-30 02:32:32 UTC (rev 216) +++ trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp 2010-03-30 03:16:07 UTC (rev 217) @@ -76,7 +76,7 @@ void KTutorialEditor::loadTutorialFromUrl(const KUrl& url) { Tutorial* tutorial; try { - tutorial = Serialization::loadTutorial(url); + tutorial = Serialization(this).loadTutorial(url); } catch (IOException e) { QString text = i18nc("@label", "There was a problem when trying to " "open the file:<nl/>%1", e.message()); @@ -452,7 +452,7 @@ } try { - Serialization::saveTutorial(mTutorial, mTutorialUrl); + Serialization(this).saveTutorial(mTutorial, mTutorialUrl); } catch (IOException e) { QString text = i18nc("@label", "There was a problem when trying to " "save the tutorial:<nl/>%1", e.message()); @@ -483,7 +483,7 @@ } try { - Serialization::saveTutorial(mTutorial, dialog->selectedUrl()); + Serialization(this).saveTutorial(mTutorial, dialog->selectedUrl()); } catch (IOException e) { QString text = i18nc("@label", "There was a problem when trying to " "save the tutorial:<nl/>%1", e.message()); @@ -509,7 +509,7 @@ dialog->setCaption(i18nc("@title", "Export Tutorial")); dialog->setOperationMode(KFileDialog::Saving); dialog->setConfirmOverwrite(true); - dialog->setFilter(Serialization::availableExporterTypes()); + dialog->setFilter(Serialization(this).availableExporterTypes()); dialog->filterWidget()->setEditable(false); if (dialog->exec() == QDialog::Rejected) { @@ -517,8 +517,8 @@ } try { - Serialization::exportTutorial(mTutorial, dialog->currentFilter(), - dialog->selectedUrl()); + Serialization(this).exportTutorial(mTutorial, dialog->currentFilter(), + dialog->selectedUrl()); } catch (IOException e) { QString text = i18nc("@label", "There was a problem when trying to " "save the exported tutorial:<nl/>%1", e.message()); Modified: trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.cpp 2010-03-30 02:32:32 UTC (rev 216) +++ trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.cpp 2010-03-30 03:16:07 UTC (rev 217) @@ -29,6 +29,10 @@ //public: +Serialization::Serialization(QWidget* window): + mWindow(window) { +} + Tutorial* Serialization::loadTutorial(const KUrl& url) throw (DeserializationException, IOException) { Q_ASSERT(url.isValid()); @@ -39,7 +43,7 @@ } QString temporaryFileName; - if (!KIO::NetAccess::download(url, temporaryFileName, 0)) { + if (!KIO::NetAccess::download(url, temporaryFileName, mWindow)) { throw IOException(KIO::NetAccess::lastErrorString()); } @@ -111,7 +115,7 @@ out.flush(); temporaryFile.close(); - if (!KIO::NetAccess::upload(temporaryFile.fileName(), url, 0)) { + if (!KIO::NetAccess::upload(temporaryFile.fileName(), url, mWindow)) { throw IOException(KIO::NetAccess::lastErrorString()); } } Modified: trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.h 2010-03-30 02:32:32 UTC (rev 216) +++ trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.h 2010-03-30 03:16:07 UTC (rev 217) @@ -25,6 +25,7 @@ #include "IOException.h" class KUrl; +class QWidget; class Tutorial; /** @@ -37,6 +38,17 @@ public: /** + * Creates a new Serialization. + * The given window will be used as the parent window if any dialog is shown + * to request some information (for example, the user password when saving a + * file in a remote computer). It will be also used to automatically cache + * and discard that information. + * + * @param window The window associated with the input/ouput jobs, if any. + */ + explicit Serialization(QWidget* window = 0); + + /** * Loads a tutorial from the file specified by the given url. * The file must be a XML file that validates against the W3C Schema in * Tutorial.xsd. The url can be local or remote. @@ -49,8 +61,8 @@ * file. * @see TutorialReader */ - static Tutorial* loadTutorial(const KUrl& url) - throw (DeserializationException, IOException); + Tutorial* loadTutorial(const KUrl& url) throw (DeserializationException, + IOException); /** * Saves the tutorial to the file specified by the given url. @@ -63,8 +75,7 @@ * file. * @see TutorialWriter */ - static void saveTutorial(Tutorial* tutorial, const KUrl& url) - throw (IOException); + void saveTutorial(Tutorial* tutorial, const KUrl& url) throw (IOException); /** * Returns the available exporter types. @@ -75,7 +86,7 @@ * * @return The available exporter types. */ - static QString availableExporterTypes(); + QString availableExporterTypes(); /** * Exports the tutorial to the file specified by the url using the given @@ -91,17 +102,19 @@ * @throw IOException If there was a problem writing the contents to the * file. */ - static void exportTutorial(const Tutorial* tutorial, const QString& type, - const KUrl& url) throw (IOException); + void exportTutorial(const Tutorial* tutorial, const QString& type, + const KUrl& url) throw (IOException); private: + QWidget* mWindow; + /** * Returns a list of strings with the available exporter types. * * @return A list with the available exporter types. */ - static QStringList availableExporterTypeList(); + QStringList availableExporterTypeList(); /** * Writes the data to the file specified by the given url. @@ -112,8 +125,7 @@ * @throw IOException If there was a problem writing the contents to the * file. */ - static void writeFile(const QString& data, const KUrl& url) - throw (IOException); + void writeFile(const QString& data, const KUrl& url) throw (IOException); }; Modified: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/SerializationTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/serialization/SerializationTest.cpp 2010-03-30 02:32:32 UTC (rev 216) +++ trunk/ktutorial/ktutorial-editor/tests/unit/serialization/SerializationTest.cpp 2010-03-30 03:16:07 UTC (rev 217) @@ -94,8 +94,8 @@ KUrl url = KGlobal::dirs()->saveLocation("tmp") + "/SerializationTest.xml"; - Serialization::saveTutorial(&tutorial, url); - QScopedPointer<Tutorial> loadedTutorial(Serialization::loadTutorial(url)); + Serialization().saveTutorial(&tutorial, url); + QScopedPointer<Tutorial> loadedTutorial(Serialization().loadTutorial(url)); QVERIFY(loadedTutorial); QCOMPARE(loadedTutorial->name(), tutorial.name()); @@ -109,13 +109,13 @@ writeFile(mFile, "<tutorial name=\"The name\"></tutorial>"); QVERIFY(QFile::setPermissions(mFile->fileName(), 0)); - EXPECT_EXCEPTION(Serialization::loadTutorial(url), IOException); + EXPECT_EXCEPTION(Serialization().loadTutorial(url), IOException); } void SerializationTest::testLoadFromDirectory() { KUrl url = KGlobal::dirs()->saveLocation("tmp"); - EXPECT_EXCEPTION(Serialization::loadTutorial(url), IOException); + EXPECT_EXCEPTION(Serialization().loadTutorial(url), IOException); } void SerializationTest::testLoadNotAnXmlFile() { @@ -124,7 +124,7 @@ mFile->open(QIODevice::WriteOnly | QIODevice::Text); writeFile(mFile, "Not an XML file"); - EXPECT_EXCEPTION(Serialization::loadTutorial(url), + EXPECT_EXCEPTION(Serialization().loadTutorial(url), DeserializationException); } @@ -134,7 +134,7 @@ mFile->open(QIODevice::WriteOnly | QIODevice::Text); writeFile(mFile, "<tutorial><step></invalidEndElement></tutorial>"); - EXPECT_EXCEPTION(Serialization::loadTutorial(url), + EXPECT_EXCEPTION(Serialization().loadTutorial(url), DeserializationException); } @@ -144,7 +144,7 @@ mFile->open(QIODevice::WriteOnly | QIODevice::Text); writeFile(mFile, "<unknownRootElement></unknownRootElement>"); - EXPECT_EXCEPTION(Serialization::loadTutorial(url), + EXPECT_EXCEPTION(Serialization().loadTutorial(url), DeserializationException); } @@ -158,7 +158,7 @@ mFile->open(QIODevice::WriteOnly | QIODevice::Text); writeFile(mFile, "Hello world!"); - Serialization::saveTutorial(&tutorial, url); + Serialization().saveTutorial(&tutorial, url); QVERIFY(mFile->exists()); QVERIFY(mFile->open(QIODevice::ReadOnly | QIODevice::Text)); @@ -184,7 +184,7 @@ writeFile(mFile, "Hello world!"); QVERIFY(QFile::setPermissions(mFile->fileName(), 0)); - EXPECT_EXCEPTION(Serialization::saveTutorial(&tutorial, url), IOException); + EXPECT_EXCEPTION(Serialization().saveTutorial(&tutorial, url), IOException); } void SerializationTest::testSaveToDirectory() { @@ -194,11 +194,11 @@ KUrl url = KGlobal::dirs()->saveLocation("tmp"); - EXPECT_EXCEPTION(Serialization::saveTutorial(&tutorial, url), IOException); + EXPECT_EXCEPTION(Serialization().saveTutorial(&tutorial, url), IOException); } void SerializationTest::testAvailableExporterTypes() { - QString types = Serialization::availableExporterTypes(); + QString types = Serialization().availableExporterTypes(); QCOMPARE(types, i18nc("@item:combobox A KFileDialog filter", "*.js|Javascript file")); @@ -211,7 +211,7 @@ KUrl url = KGlobal::dirs()->saveLocation("tmp") + "/SerializationTest.js"; - Serialization::exportTutorial(&tutorial, "*.js", url); + Serialization().exportTutorial(&tutorial, "*.js", url); mFile = new QFile(url.toLocalFile()); QVERIFY(mFile->exists()); @@ -239,7 +239,7 @@ mFile->open(QIODevice::WriteOnly | QIODevice::Text); writeFile(mFile, "Hello world!"); - Serialization::exportTutorial(&tutorial, "*.js", url); + Serialization().exportTutorial(&tutorial, "*.js", url); QVERIFY(mFile->exists()); QVERIFY(mFile->open(QIODevice::ReadOnly | QIODevice::Text)); @@ -267,7 +267,7 @@ writeFile(mFile, "Hello world!"); QVERIFY(QFile::setPermissions(mFile->fileName(), 0)); - EXPECT_EXCEPTION(Serialization::exportTutorial(&tutorial, "*.js", url), + EXPECT_EXCEPTION(Serialization().exportTutorial(&tutorial, "*.js", url), IOException); } @@ -278,7 +278,7 @@ KUrl url = KGlobal::dirs()->saveLocation("tmp"); - EXPECT_EXCEPTION(Serialization::exportTutorial(&tutorial, "*.js", url), + EXPECT_EXCEPTION(Serialization().exportTutorial(&tutorial, "*.js", url), IOException); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-30 02:32:39
|
Revision: 216 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=216&view=rev Author: danxuliu Date: 2010-03-30 02:32:32 +0000 (Tue, 30 Mar 2010) Log Message: ----------- Ensure that IOExceptions are thrown when loading, saving and exporting to a directory instead of a file. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.cpp trunk/ktutorial/ktutorial-editor/tests/unit/serialization/SerializationTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.cpp 2010-03-29 23:58:59 UTC (rev 215) +++ trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.cpp 2010-03-30 02:32:32 UTC (rev 216) @@ -33,6 +33,11 @@ throw (DeserializationException, IOException) { Q_ASSERT(url.isValid()); + if (url.fileName(KUrl::ObeyTrailingSlash).isEmpty()) { + throw IOException(i18n("A file was expected, but '%1' is a folder", + url.prettyUrl())); + } + QString temporaryFileName; if (!KIO::NetAccess::download(url, temporaryFileName, 0)) { throw IOException(KIO::NetAccess::lastErrorString()); Modified: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/SerializationTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/serialization/SerializationTest.cpp 2010-03-29 23:58:59 UTC (rev 215) +++ trunk/ktutorial/ktutorial-editor/tests/unit/serialization/SerializationTest.cpp 2010-03-30 02:32:32 UTC (rev 216) @@ -50,12 +50,14 @@ void testSaveAndLoad(); void testLoadFromUnreadableUrl(); + void testLoadFromDirectory(); void testLoadNotAnXmlFile(); void testLoadXmlNotWellFormed(); void testLoadXmlWithoutRootTutorialElement(); void testSaveToExistingUrl(); void testSaveToUnwritableUrl(); + void testSaveToDirectory(); void testAvailableExporterTypes(); @@ -63,6 +65,7 @@ void testExportToExistingUrl(); void testExportToUnwritableUrl(); + void testExportToDirectory(); private: @@ -109,6 +112,12 @@ EXPECT_EXCEPTION(Serialization::loadTutorial(url), IOException); } +void SerializationTest::testLoadFromDirectory() { + KUrl url = KGlobal::dirs()->saveLocation("tmp"); + + EXPECT_EXCEPTION(Serialization::loadTutorial(url), IOException); +} + void SerializationTest::testLoadNotAnXmlFile() { KUrl url = KGlobal::dirs()->saveLocation("tmp") + "/SerializationTest.txt"; mFile = new QFile(url.toLocalFile()); @@ -178,6 +187,16 @@ EXPECT_EXCEPTION(Serialization::saveTutorial(&tutorial, url), IOException); } +void SerializationTest::testSaveToDirectory() { + Tutorial tutorial; + tutorial.setName("The name"); + tutorial.setDescription("The description"); + + KUrl url = KGlobal::dirs()->saveLocation("tmp"); + + EXPECT_EXCEPTION(Serialization::saveTutorial(&tutorial, url), IOException); +} + void SerializationTest::testAvailableExporterTypes() { QString types = Serialization::availableExporterTypes(); @@ -252,6 +271,17 @@ IOException); } +void SerializationTest::testExportToDirectory() { + Tutorial tutorial; + tutorial.setName("The name"); + tutorial.setDescription("The description"); + + KUrl url = KGlobal::dirs()->saveLocation("tmp"); + + EXPECT_EXCEPTION(Serialization::exportTutorial(&tutorial, "*.js", url), + IOException); +} + /////////////////////////////////// Helpers //////////////////////////////////// QString SerializationTest::readFile(QFile* file) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-29 23:59:07
|
Revision: 215 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=215&view=rev Author: danxuliu Date: 2010-03-29 23:58:59 +0000 (Mon, 29 Mar 2010) Log Message: ----------- Add a command line option to load a tutorial Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h trunk/ktutorial/ktutorial-editor/src/main.cpp Modified: trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp 2010-03-29 23:40:17 UTC (rev 214) +++ trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp 2010-03-29 23:58:59 UTC (rev 215) @@ -73,6 +73,33 @@ setupGUI(); } +void KTutorialEditor::loadTutorialFromUrl(const KUrl& url) { + Tutorial* tutorial; + try { + tutorial = Serialization::loadTutorial(url); + } catch (IOException e) { + QString text = i18nc("@label", "There was a problem when trying to " +"open the file:<nl/>%1", e.message()); + QString caption = i18nc("@title:window", "File could not be read"); + KMessageBox::error(this, text, caption); + return; + } catch (DeserializationException e) { + QString text = i18nc("@label", "There was a problem when trying to " +"load the tutorial:<nl/>%1", e.message()); + QString caption = i18nc("@title:window", "Tutorial could not be " +"loaded"); + KMessageBox::error(this, text, caption); + return; + } + + setTutorialToBeEdited(tutorial); + mTutorialUrl = url; + mUndoStack->setClean(); + //Force clean state, as setting an empty stack as clean would not emit + //cleanChanged() + handleUndoStackCleanChanged(true); +} + //protected: bool KTutorialEditor::queryClose() { @@ -416,30 +443,7 @@ return; } - Tutorial* tutorial; - try { - tutorial = Serialization::loadTutorial(dialog->selectedUrl()); - } catch (IOException e) { - QString text = i18nc("@label", "There was a problem when trying to " -"open the file:<nl/>%1", e.message()); - QString caption = i18nc("@title:window", "File could not be read"); - KMessageBox::error(this, text, caption); - return; - } catch (DeserializationException e) { - QString text = i18nc("@label", "There was a problem when trying to " -"load the tutorial:<nl/>%1", e.message()); - QString caption = i18nc("@title:window", "Tutorial could not be " -"loaded"); - KMessageBox::error(this, text, caption); - return; - } - - setTutorialToBeEdited(tutorial); - mTutorialUrl = dialog->selectedUrl(); - mUndoStack->setClean(); - //Force clean state, as setting an empty stack as clean would not emit - //cleanChanged() - handleUndoStackCleanChanged(true); + loadTutorialFromUrl(dialog->selectedUrl()); } bool KTutorialEditor::saveTutorial() { Modified: trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h 2010-03-29 23:40:17 UTC (rev 214) +++ trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h 2010-03-29 23:58:59 UTC (rev 215) @@ -43,6 +43,15 @@ */ KTutorialEditor(); + /** + * Loads the tutorial to be edited from the given URL. + * The tutorial URL is updated and a clean state is forced. + * An error message is shown if the tutorial couldn't be opened. + * + * @param url The URL to load the tutorial from. + */ + void loadTutorialFromUrl(const KUrl& url); + protected: /** @@ -197,8 +206,7 @@ /** * Shows a KFileDialog to select the file to open the tutorial from. - * The tutorial URL is updated and a clean state is forced. - * An error message is shown if the tutorial couldn't be opened. + * The tutorial is loaded from the URL selected by the user. */ void openTutorial(); Modified: trunk/ktutorial/ktutorial-editor/src/main.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/main.cpp 2010-03-29 23:40:17 UTC (rev 214) +++ trunk/ktutorial/ktutorial-editor/src/main.cpp 2010-03-29 23:58:59 UTC (rev 215) @@ -35,10 +35,20 @@ "dan...@gm..."); KCmdLineArgs::init(argc, argv, &aboutData); + KCmdLineOptions options; + options.add("+[URL]", ki18nc("@info:shell", "The tutorial to open")); + + KCmdLineArgs::addCmdLineOptions(options); + KApplication app; KTutorialEditor* window = new KTutorialEditor(); window->show(); + KCmdLineArgs* args = KCmdLineArgs::parsedArgs(); + if (args->count() == 1) { + window->loadTutorialFromUrl(args->url(0)); + } + return app.exec(); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-29 23:40:23
|
Revision: 214 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=214&view=rev Author: danxuliu Date: 2010-03-29 23:40:17 +0000 (Mon, 29 Mar 2010) Log Message: ----------- Fix comment (copy-pasting is bad, I know) Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp Modified: trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp 2010-03-29 23:35:50 UTC (rev 213) +++ trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp 2010-03-29 23:40:17 UTC (rev 214) @@ -398,7 +398,7 @@ void KTutorialEditor::newTutorial() { setTutorialToBeEdited(); mTutorialUrl = KUrl(); - //Force clean state, as setting an empty stack as clean would not emit + //Force clean state, as clearing an empty stack would not emit //cleanChanged() handleUndoStackCleanChanged(true); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |