[Ktutorial-commits] SF.net SVN: ktutorial:[301] trunk/ktutorial/ktutorial-editor
Status: Alpha
Brought to you by:
danxuliu
|
From: <dan...@us...> - 2011-05-05 14:39:24
|
Revision: 301
http://ktutorial.svn.sourceforge.net/ktutorial/?rev=301&view=rev
Author: danxuliu
Date: 2011-05-05 14:39:15 +0000 (Thu, 05 May 2011)
Log Message:
-----------
Add a basic helper to edit KUIT semantic markup in the text of a step.
Modified Paths:
--------------
trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt
trunk/ktutorial/ktutorial-editor/src/view/StepDataWidget.cpp
trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt
Added Paths:
-----------
trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupEdition.cpp
trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupEdition.h
trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupLinkWidget.cpp
trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupLinkWidget.h
trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupLinkWidget.ui
trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupParser.cpp
trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupParser.h
trunk/ktutorial/ktutorial-editor/tests/unit/view/SemanticMarkupEditionTest.cpp
trunk/ktutorial/ktutorial-editor/tests/unit/view/SemanticMarkupLinkWidgetTest.cpp
trunk/ktutorial/ktutorial-editor/tests/unit/view/SemanticMarkupParserTest.cpp
Modified: trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt
===================================================================
--- trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2011-04-30 17:31:13 UTC (rev 300)
+++ trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2011-05-05 14:39:15 UTC (rev 301)
@@ -9,6 +9,9 @@
NewWaitForWidget.cpp
ReactionTreeItem.cpp
ReactionWidget.cpp
+ SemanticMarkupEdition.cpp
+ SemanticMarkupLinkWidget.cpp
+ SemanticMarkupParser.cpp
StepCustomCodeWidget.cpp
StepDataWidget.cpp
StepTreeItem.cpp
@@ -53,6 +56,7 @@
NewWaitForWidget.ui
ReactionWidget.ui
RemoteObjectNameWidget.ui
+ SemanticMarkupLinkWidget.ui
StepDataWidget.ui
TutorialInformationWidget.ui
WaitForEventWidget.ui
Added: trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupEdition.cpp
===================================================================
--- trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupEdition.cpp (rev 0)
+++ trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupEdition.cpp 2011-05-05 14:39:15 UTC (rev 301)
@@ -0,0 +1,418 @@
+/***************************************************************************
+ * Copyright (C) 2011 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 "SemanticMarkupEdition.h"
+
+#include <QRegExp>
+#include <QTextEdit>
+
+#include <KAction>
+#include <KActionCollection>
+#include <KDialog>
+#include <KLocalizedString>
+#include <KPushButton>
+
+#include "DialogRunner.h"
+#include "SemanticMarkupLinkWidget.h"
+#include "SemanticMarkupParser.h"
+
+//public:
+
+SemanticMarkupEdition::SemanticMarkupEdition(QTextEdit* textEdit):
+ QObject(textEdit),
+ mTextEdit(textEdit) {
+ Q_ASSERT(textEdit);
+
+ connect(mTextEdit, SIGNAL(cursorPositionChanged()),
+ this, SLOT(updateActionStates()));
+ //TODO Needed to update the action states when the user deletes a character;
+ //look how to do that without updating twice in any other text change.
+ connect(mTextEdit, SIGNAL(textChanged()),
+ this, SLOT(updateActionStates()));
+}
+
+void SemanticMarkupEdition::createActions(KActionCollection* actionCollection) {
+ Q_ASSERT(actionCollection);
+
+ mEmphasisAction = new KAction("emphasis", actionCollection);
+ mEmphasisAction->setCheckable(true);
+ mEmphasisAction->setToolTip(i18nc("@info:tooltip", "Emphasized text"));
+ mEmphasisAction->setWhatsThis(i18nc("@info:whatsthis",
+ "Phrase tag to emphasize a word or phrase in the text.<nl/>"
+ "Example: <emphasis>emphasized text</emphasis>"));
+ actionCollection->addAction("kuit-edition-phrase-emphasis",
+ mEmphasisAction);
+ connect(mEmphasisAction, SIGNAL(triggered()), this, SLOT(emphasis()));
+ mActions.append(mEmphasisAction);
+
+ mEmphasisStrongAction = new KAction("emphasis (strong)", actionCollection);
+ mEmphasisStrongAction->setCheckable(true);
+ mEmphasisStrongAction->setToolTip(i18nc("@info:tooltip",
+ "Strongly emphasized text"));
+ mEmphasisStrongAction->setWhatsThis(i18nc("@info:whatsthis",
+ "Phrase tag to strongly emphasize a word or phrase in the text.<nl/>"
+ "Example: <emphasis strong=\"1\">strongly emphasized text</emphasis>"));
+ actionCollection->addAction("kuit-edition-phrase-emphasis-strong",
+ mEmphasisStrongAction);
+ connect(mEmphasisStrongAction, SIGNAL(triggered()),
+ this, SLOT(emphasisStrong()));
+ mActions.append(mEmphasisStrongAction);
+
+ mFilenameAction = new KAction("filename", actionCollection);
+ mFilenameAction->setCheckable(true);
+ mFilenameAction->setToolTip(i18nc("@info:tooltip", "Filename or path"));
+ mFilenameAction->setWhatsThis(i18nc("@info:whatsthis",
+ "Phrase tag for file or folder name or path.<nl/>"
+ "The path separators will be transformed into what is native to the "
+ "platform.<nl/>"
+ "Example: <filename>/home/user/Music/song.ogg</filename>"));
+ actionCollection->addAction("kuit-edition-phrase-filename",
+ mFilenameAction);
+ connect(mFilenameAction, SIGNAL(triggered()), this, SLOT(filename()));
+ mActions.append(mFilenameAction);
+
+ mInterfaceAction = new KAction("interface", actionCollection);
+ mInterfaceAction->setCheckable(true);
+ mInterfaceAction->setToolTip(i18nc("@info:tooltip",
+ "GUI interface element"));
+ mInterfaceAction->setWhatsThis(i18nc("@info:whatsthis",
+ "Phrase tag for paths to GUI interface elements.<nl/>"
+ "If there is more than one element in the path, use \"|\" to delimit "
+ "elements, which will be converted into canonical delimiter.<nl/>"
+ "Example: <interface>File|Open</interface>"));
+ actionCollection->addAction("kuit-edition-phrase-interface",
+ mInterfaceAction);
+ connect(mInterfaceAction, SIGNAL(triggered()), this, SLOT(interface()));
+ mActions.append(mInterfaceAction);
+
+ mLinkAction = new KAction("link", actionCollection);
+ mLinkAction->setCheckable(true);
+ mLinkAction->setToolTip(i18nc("@info:tooltip", "Link to URL or widget"));
+ mLinkAction->setWhatsThis(i18nc("@info:whatsthis",
+ "Phrase tag to link to a URL-addressable resource.<nl/>"
+ "Widgets in the target application interface can be linked using "
+ "<emphasis>widget:theObjectNameOfTheWidget</emphasis><nl/>"
+ "Example: <link url=\"http://www.kde.org\">a link</link>"));
+ actionCollection->addAction("kuit-edition-phrase-link", mLinkAction);
+ connect(mLinkAction, SIGNAL(triggered()), this, SLOT(link()));
+ mActions.append(mLinkAction);
+
+ mNlAction = new KAction("nl", actionCollection);
+ mNlAction->setToolTip(i18nc("@info:tooltip", "Line break"));
+ mNlAction->setWhatsThis(i18nc("@info:whatsthis",
+ "Phrase tag for line breaks.<nl/>"
+ "Example: line<nl/>break"));
+ actionCollection->addAction("kuit-edition-phrase-nl", mNlAction);
+ connect(mNlAction, SIGNAL(triggered()), this, SLOT(nl()));
+ mActions.append(mNlAction);
+
+ mShortcutAction = new KAction("shortcut", actionCollection);
+ mShortcutAction->setCheckable(true);
+ mShortcutAction->setToolTip(i18nc("@info:tooltip",
+ "Combination of keys to press"));
+ mShortcutAction->setWhatsThis(i18nc("@info:whatsthis",
+ "Phrase tag for combinations of keys to press.<nl/>"
+ "Separate the keys by \"+\" or \"-\", and the shortcut will be "
+ "converted into canonical form.<nl/>"
+ "Example: <shortcut>Ctrl+N</shortcut>"));
+ actionCollection->addAction("kuit-edition-phrase-shortcut",
+ mShortcutAction);
+ connect(mShortcutAction, SIGNAL(triggered()), this, SLOT(shortcut()));
+ mActions.append(mShortcutAction);
+
+ mParaAction = new KAction("para", actionCollection);
+ mParaAction->setCheckable(true);
+ mParaAction->setToolTip(i18nc("@info:tooltip", "Paragraph"));
+ mParaAction->setWhatsThis(i18nc("@info:whatsthis",
+ "<para>Structure tag for text paragraphs.<nl/>"
+ "Example: one paragraph</para><para>Other paragraph</para>"));
+ actionCollection->addAction("kuit-edition-structure-para", mParaAction);
+ connect(mParaAction, SIGNAL(triggered()), this, SLOT(para()));
+ mActions.append(mParaAction);
+
+ mListAction = new KAction("list", actionCollection);
+ mListAction->setCheckable(true);
+ mListAction->setToolTip(i18nc("@info:tooltip", "List of items"));
+ mListAction->setWhatsThis(i18nc("@info:whatsthis",
+ "<para>Structure tag for lists of items.<nl/>"
+ "Can contain only <item> as subtags. List is considered an "
+ "element of the paragraph, so the <list> must be found inside "
+ "<para>.<nl/>"
+ "Example: <list>"
+ " <item>One item</item>"
+ " <item>Other item</item>"
+ " </list></para>"));
+ actionCollection->addAction("kuit-edition-structure-list", mListAction);
+ connect(mListAction, SIGNAL(triggered()), this, SLOT(list()));
+ mActions.append(mListAction);
+
+ mItemAction = new KAction("item", actionCollection);
+ mItemAction->setCheckable(true);
+ mItemAction->setToolTip(i18nc("@info:tooltip", "List items"));
+ mItemAction->setWhatsThis(i18nc("@info:whatsthis",
+ "<para>Structure tag for list items.<nl/>"
+ "Example: <list>"
+ " <item>One item</item>"
+ " <item>Other item</item>"
+ " </list></para>"));
+ actionCollection->addAction("kuit-edition-structure-item", mItemAction);
+ connect(mItemAction, SIGNAL(triggered()), this, SLOT(item()));
+ mActions.append(mItemAction);
+
+ updateActionStates();
+}
+
+//private:
+
+QAction* SemanticMarkupEdition::actionForElement(const StartTag& startTag)
+ const {
+ QAction* action = 0;
+
+ QRegExp emphasisStrongRegExp("strong=\"yes|true|1\"");
+ if (startTag.mName == "emphasis" &&
+ startTag.mAttributes.indexOf(emphasisStrongRegExp) < 0) {
+ action = mEmphasisAction;
+ } else if (startTag.mName == "emphasis" &&
+ startTag.mAttributes.indexOf(emphasisStrongRegExp) >= 0) {
+ action = mEmphasisStrongAction;
+ } else if (startTag.mName == "filename") {
+ action = mFilenameAction;
+ } else if (startTag.mName == "interface") {
+ action = mInterfaceAction;
+ } else if (startTag.mName == "link") {
+ action = mLinkAction;
+ } else if (startTag.mName == "nl") {
+ action = mNlAction;
+ } else if (startTag.mName == "shortcut") {
+ action = mShortcutAction;
+ } else if (startTag.mName == "para") {
+ action = mParaAction;
+ } else if (startTag.mName == "list") {
+ action = mListAction;
+ } else if (startTag.mName == "item") {
+ action = mItemAction;
+ }
+
+ return action;
+}
+
+void SemanticMarkupEdition::writeSimpleTagFor(const QAction* action) {
+ if (action->isChecked()) {
+ mTextEdit->insertPlainText('<' + action->text() + '>');
+ } else {
+ mTextEdit->insertPlainText("</" + action->text() + '>');
+ }
+}
+
+QDialog* SemanticMarkupEdition::newLinkDialog(const QString& url) const {
+ KDialog* dialog = new KDialog(mTextEdit);
+ dialog->setModal(true);
+
+ dialog->setButtons(KDialog::Ok | KDialog::Cancel);
+
+ dialog->button(KDialog::Ok)->setObjectName("okButton");
+ dialog->button(KDialog::Cancel)->setObjectName("cancelButton");
+
+ SemanticMarkupLinkWidget* linkWidget = new SemanticMarkupLinkWidget(dialog);
+ linkWidget->setUrl(url);
+ dialog->setMainWidget(linkWidget);
+ dialog->setWindowTitle(linkWidget->windowTitle());
+
+ return dialog;
+}
+
+//private slots:
+
+void SemanticMarkupEdition::updateActionStates() {
+ Q_ASSERT(!mActions.isEmpty());
+
+ foreach (QAction* action, mActions) {
+ action->setEnabled(true);
+ action->setChecked(false);
+ }
+
+ mLinkElementClosed = false;
+
+ SemanticMarkupParser parser;
+ parser.setCursorIndex(mTextEdit->textCursor().position());
+ parser.parse(mTextEdit->toPlainText());
+
+ if (parser.isCursorInsideTag()) {
+ foreach (QAction* action, mActions) {
+ action->setEnabled(false);
+ }
+
+ return;
+ }
+
+ QList<StartTag> openElementsAtCursor = parser.openElementsAtCursor();
+ if (openElementsAtCursor.isEmpty()) {
+ mListAction->setEnabled(false);
+ mItemAction->setEnabled(false);
+
+ return;
+ }
+
+ QList<QAction*> phraseActions;
+ phraseActions << mEmphasisAction << mEmphasisStrongAction << mFilenameAction
+ << mInterfaceAction << mLinkAction << mNlAction
+ << mShortcutAction;
+
+ foreach (const StartTag& startTag, openElementsAtCursor) {
+ QAction* action = actionForElement(startTag);
+ if (!action) {
+ continue;
+ }
+
+ action->setChecked(true);
+
+ bool elementClosed = parser.isElementClosed(startTag);
+ if (elementClosed && action != mLinkAction) {
+ action->setEnabled(false);
+ } else if (elementClosed && action == mLinkAction) {
+ action->setEnabled(true);
+ mLinkElementClosed = true;
+ }
+
+ if (phraseActions.contains(action)) {
+ foreach (QAction* actionToDisable, mActions) {
+ if (actionToDisable != action) {
+ actionToDisable->setEnabled(false);
+ }
+ }
+ } else if (action == mParaAction) {
+ if (!mListAction->isChecked()) {
+ mItemAction->setEnabled(false);
+ }
+ } else if (action == mListAction) {
+ mParaAction->setEnabled(false);
+ if (!mItemAction->isChecked()) {
+ foreach (QAction* phraseAction, phraseActions) {
+ phraseAction->setEnabled(false);
+ }
+ }
+ } else if (action == mItemAction) {
+ mParaAction->setEnabled(false);
+ mListAction->setEnabled(false);
+ }
+ }
+}
+
+void SemanticMarkupEdition::emphasis() {
+ writeSimpleTagFor(mEmphasisAction);
+}
+
+void SemanticMarkupEdition::emphasisStrong() {
+ if (mEmphasisStrongAction->isChecked()) {
+ mTextEdit->insertPlainText("<emphasis strong=\"yes\">");
+ } else {
+ mTextEdit->insertPlainText("</emphasis>");
+ }
+}
+
+void SemanticMarkupEdition::filename() {
+ writeSimpleTagFor(mFilenameAction);
+}
+
+void SemanticMarkupEdition::interface() {
+ writeSimpleTagFor(mInterfaceAction);
+}
+
+void SemanticMarkupEdition::link() {
+ if (!mLinkAction->isChecked() && !mLinkElementClosed) {
+ mTextEdit->insertPlainText("</link>");
+ return;
+ }
+
+ if (!mLinkElementClosed) {
+ QScopedPointer<QDialog> dialog(newLinkDialog(""));
+ if (DialogRunner(dialog.data()).exec() == QDialog::Rejected) {
+ mLinkAction->setChecked(false);
+ return;
+ }
+
+ QString newUrl = dialog->findChild<SemanticMarkupLinkWidget*>()->url();
+ mTextEdit->insertPlainText(QString("<link url=\"%1\">").arg(newUrl));
+
+ return;
+ }
+
+ mLinkAction->setChecked(true);
+
+ QString text = mTextEdit->toPlainText();
+ int cursorIndex = mTextEdit->textCursor().position();
+ QRegExp linkRegExp("<\\s*link\\s*(\\w+=\"[^\"]*\")*\\s*>");
+ int linkElementIndex = text.lastIndexOf(linkRegExp, cursorIndex);
+
+ QString linkText = linkRegExp.capturedTexts().at(0);
+ QRegExp urlRegExp(" url=\"([^\"]*)\"");
+ int urlAttributeIndex = linkText.indexOf(urlRegExp);
+
+ if (urlAttributeIndex == -1) {
+ urlAttributeIndex = QString("<link").length();
+ }
+
+ int absoluteUrlAttributeIndex = linkElementIndex + urlAttributeIndex;
+ QString oldUrlAttribute = urlRegExp.capturedTexts().at(0);
+ QString oldUrl = urlRegExp.capturedTexts().at(1);
+
+ QScopedPointer<QDialog> dialog(newLinkDialog(oldUrl));
+ if (DialogRunner(dialog.data()).exec() == QDialog::Rejected) {
+ return;
+ }
+
+ QString newUrl = dialog->findChild<SemanticMarkupLinkWidget*>()->url();
+
+ QTextCursor cursor = mTextEdit->textCursor();
+ cursor.setPosition(absoluteUrlAttributeIndex);
+ cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor,
+ oldUrlAttribute.length());
+ cursor.insertText(QString(" url=\"%1\"").arg(newUrl));
+}
+
+void SemanticMarkupEdition::nl() {
+ mTextEdit->insertPlainText("<nl/>\n");
+}
+
+void SemanticMarkupEdition::shortcut() {
+ writeSimpleTagFor(mShortcutAction);
+}
+
+void SemanticMarkupEdition::para() {
+ if (mParaAction->isChecked()) {
+ mTextEdit->insertPlainText("<para>");
+ } else {
+ mTextEdit->insertPlainText("</para>\n\n");
+ }
+}
+
+void SemanticMarkupEdition::list() {
+ if (mListAction->isChecked()) {
+ mTextEdit->insertPlainText("<list>\n");
+ } else {
+ mTextEdit->insertPlainText("</list>\n");
+ }
+}
+
+void SemanticMarkupEdition::item() {
+ if (mItemAction->isChecked()) {
+ mTextEdit->insertPlainText("<item>");
+ } else {
+ mTextEdit->insertPlainText("</item>\n");
+ }
+}
Property changes on: trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupEdition.cpp
___________________________________________________________________
Added: svn:eol-style
+ native
Added: trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupEdition.h
===================================================================
--- trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupEdition.h (rev 0)
+++ trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupEdition.h 2011-05-05 14:39:15 UTC (rev 301)
@@ -0,0 +1,248 @@
+/***************************************************************************
+ * Copyright (C) 2011 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 SEMANTICMARKUPEDITION_H
+#define SEMANTICMARKUPEDITION_H
+
+#include <QObject>
+
+class QAction;
+class QDialog;
+class QTextEdit;
+
+class KActionCollection;
+
+class StartTag;
+
+/**
+ * Helper to edit KUIT semantic markup in a QTextEdit widget.
+ * SemanticMarkupEdition provides several actions that ease the edition of the
+ * most common KUIT semantic markup tags. The actions are added to a
+ * KActionCollection using createActions(KActionCollection*).
+ *
+ * Triggering an action will write its associated start tag in the current
+ * position of the text edit cursor. Triggering the action again will write its
+ * associated end tag. When a tag needs extra information from the user to be
+ * written (for example, the URL of a link element), a dialog will be shown.
+ * Also, triggering the action when the cursor is between two paired start and
+ * end tags will show the dialog and update the attribute.
+ *
+ * The action states will be updated based on the cursor of the QTextEdit.
+ * Depending on its position or the current selection some actions may be
+ * disabled or checked.
+ *
+ * When the cursor is inside any tag all the actions will be disabled. If it is
+ * between two paired start and end tags they will also be disabled (except the
+ * ones that show a dialog), although the action for that tag (and its paired
+ * parent elements) will be checked. If the cursor is after a start tag, the
+ * action for that tag will be enabled and checked (and triggering it will write
+ * the end tag).
+ *
+ * The actions may also be disabled when their element can not be written at the
+ * current position of the cursor. For example, the list action will be disabled
+ * unless the cursor is after a para tag. It will be disabled too if after the
+ * para tag there is a phrase element tag, as list elements can be child only of
+ * para elements.
+ *
+ * Only the cursor position is used to update the state of the actions.
+ * Selections are not taken into account.
+ */
+class SemanticMarkupEdition: public QObject {
+Q_OBJECT
+public:
+
+ /**
+ * Creates a new SemanticMarkupEdition.
+ * The QTextEdit will also act as parent of the SemanticMarkupEdition.
+ *
+ * @param textEdit The QTextEdit used for the edition of the text.
+ */
+ SemanticMarkupEdition(QTextEdit* textEdit);
+
+ /**
+ * Creates the actions for markup edition and adds them to the given
+ * collection.
+ * The collection is made parent of the actions.
+ *
+ * @param actionCollection The collection to add the actions to.
+ */
+ void createActions(KActionCollection* actionCollection);
+
+private:
+
+ /**
+ * All the edition actions.
+ */
+ QList<QAction*> mActions;
+
+ /**
+ * Action for "emphasis" phrase tag.
+ */
+ QAction* mEmphasisAction;
+
+ /**
+ * Action for "emphasis" phrase tag with "strong" attribute.
+ */
+ QAction* mEmphasisStrongAction;
+
+ /**
+ * Action for "filename" phrase tag.
+ */
+ QAction* mFilenameAction;
+
+ /**
+ * Action for "interface" phrase tag.
+ */
+ QAction* mInterfaceAction;
+
+ /**
+ * Action for "link" phrase tag.
+ */
+ QAction* mLinkAction;
+
+ /**
+ * Action for "nl" phrase tag.
+ */
+ QAction* mNlAction;
+
+ /**
+ * Action for "shortcut" phrase tag.
+ */
+ QAction* mShortcutAction;
+
+ /**
+ * Action for "para" structure tag.
+ */
+ QAction* mParaAction;
+
+ /**
+ * Action for "list" structure tag.
+ */
+ QAction* mListAction;
+
+ /**
+ * Action for "item" structure tag.
+ */
+ QAction* mItemAction;
+
+ /**
+ * The QTextEdit used for the edition of the text.
+ */
+ QTextEdit* mTextEdit;
+
+ /**
+ * Whether the cursor is between two paired start and end link elements or
+ * not.
+ */
+ bool mLinkElementClosed;
+
+ /**
+ * Returns the action that represents the given start tag.
+ *
+ * @param startTag The start tag to get its action.
+ * @return The action for the tag.
+ */
+ QAction* actionForElement(const StartTag& startTag) const;
+
+ /**
+ * Writes a simple tag for the given action.
+ * If the action is checked, a start tag for the element of the action is
+ * inserted in the text edit. If the action is not checked, an end tag is
+ * inserted.
+ *
+ * @param action The action to write its tag.
+ */
+ void writeSimpleTagFor(const QAction* action);
+
+ /**
+ * Creates a new dialog for link elements.
+ * The dialog contains a SemanticMarkupLinkWidget and two dialog buttons: Ok
+ * and Cancel.
+ *
+ * @param url The URL to show in the link widget of the dialog.
+ * @return The new dialog.
+ */
+ QDialog* newLinkDialog(const QString& url) const;
+
+private Q_SLOTS:
+
+ /**
+ * Updates the state of the edition actions based on the cursor position.
+ */
+ void updateActionStates();
+
+ /**
+ * Behavior for "emphasis" phrase tag edition.
+ */
+ void emphasis();
+
+ /**
+ * Behavior for "emphasis" phrase tag with "strong" attribute edition.
+ */
+ void emphasisStrong();
+
+ /**
+ * Behavior for "filename" phrase tag edition.
+ */
+ void filename();
+
+ /**
+ * Behavior for "interface" phrase tag edition.
+ */
+ void interface();
+
+ /**
+ * Behavior for "link" phrase tag edition.
+ * Unlike other tags, to write the start link" element the user has to
+ * provide some information. A dialog is shown to the user to set the URL of
+ * the link.
+ *
+ * Moreover, the URL can be modified even on a closed "link" element. The
+ * "link" action can be triggered even on a closed element, and when the
+ * action is triggered, the dialog is shown to modify the URL.
+ */
+ void link();
+
+ /**
+ * Behavior for "nl" phrase tag edition.
+ */
+ void nl();
+
+ /**
+ * Behavior for "shortcut" phrase tag edition.
+ */
+ void shortcut();
+
+ /**
+ * Behavior for "para" structure tag edition.
+ */
+ void para();
+
+ /**
+ * Behavior for "list" structure tag edition.
+ */
+ void list();
+
+ /**
+ * Behavior for "item" structure tag edition.
+ */
+ void item();
+
+};
+
+#endif
Property changes on: trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupEdition.h
___________________________________________________________________
Added: svn:eol-style
+ native
Added: trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupLinkWidget.cpp
===================================================================
--- trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupLinkWidget.cpp (rev 0)
+++ trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupLinkWidget.cpp 2011-05-05 14:39:15 UTC (rev 301)
@@ -0,0 +1,93 @@
+/***************************************************************************
+ * Copyright (C) 2011 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 "SemanticMarkupLinkWidget.h"
+
+#include "ui_SemanticMarkupLinkWidget.h"
+
+#ifdef QT_QTDBUS_FOUND
+#include "RemoteObjectNameWidget.h"
+#endif
+
+//public:
+
+SemanticMarkupLinkWidget::SemanticMarkupLinkWidget(QWidget* parent):
+ QWidget(parent) {
+
+ ui = new Ui::SemanticMarkupLinkWidget();
+ ui->setupUi(this);
+
+#ifdef QT_QTDBUS_FOUND
+ mRemoteObjectNameWidget = new RemoteObjectNameWidget(this);
+
+ //Replace ui->widgetLinkLineEdit with mRemoteObjectNameWidget
+ ui->valueVerticalLayout->removeWidget(ui->widgetLinkLineEdit);
+ delete ui->widgetLinkLineEdit;
+
+ ui->valueVerticalLayout->insertWidget(1, mRemoteObjectNameWidget);
+#endif
+
+ ui->genericLinkRadioButton->setChecked(true);
+
+ connect(ui->genericLinkRadioButton, SIGNAL(toggled(bool)),
+ ui->genericLinkLineEdit, SLOT(setEnabled(bool)));
+
+#ifdef QT_QTDBUS_FOUND
+ mRemoteObjectNameWidget->setEnabled(false);
+
+ connect(ui->widgetLinkRadioButton, SIGNAL(toggled(bool)),
+ mRemoteObjectNameWidget, SLOT(setEnabled(bool)));
+#else
+ ui->widgetLinkLineEdit->setEnabled(false);
+
+ connect(ui->widgetLinkRadioButton, SIGNAL(toggled(bool)),
+ ui->widgetLinkLineEdit, SLOT(setEnabled(bool)));
+#endif
+}
+
+SemanticMarkupLinkWidget::~SemanticMarkupLinkWidget() {
+ delete ui;
+}
+
+QString SemanticMarkupLinkWidget::url() const {
+ if (ui->genericLinkRadioButton->isChecked()) {
+ return ui->genericLinkLineEdit->text();
+ }
+
+#ifdef QT_QTDBUS_FOUND
+ return "widget:" + mRemoteObjectNameWidget->name();
+#else
+ return "widget:" + ui->widgetLinkLineEdit->text();
+#endif
+}
+
+void SemanticMarkupLinkWidget::setUrl(const QString& url) {
+ if (!url.startsWith(QLatin1String("widget:"))) {
+ ui->genericLinkRadioButton->setChecked(true);
+ ui->genericLinkLineEdit->setText(url);
+ return;
+ }
+
+ ui->widgetLinkRadioButton->setChecked(true);
+ QString widgetName = url.mid(QString("widget:").length());
+#ifdef QT_QTDBUS_FOUND
+ mRemoteObjectNameWidget->setName(widgetName);
+#else
+ ui->widgetLinkLineEdit->setText(widgetName);
+#endif
+}
Property changes on: trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupLinkWidget.cpp
___________________________________________________________________
Added: svn:eol-style
+ native
Added: trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupLinkWidget.h
===================================================================
--- trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupLinkWidget.h (rev 0)
+++ trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupLinkWidget.h 2011-05-05 14:39:15 UTC (rev 301)
@@ -0,0 +1,96 @@
+/***************************************************************************
+ * Copyright (C) 2011 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 SEMANTICMARKUPLINKWIDGET_H
+#define SEMANTICMARKUPLINKWIDGET_H
+
+#include <QWidget>
+
+#ifdef QT_QTDBUS_FOUND
+class RemoteObjectNameWidget;
+#endif
+
+namespace Ui {
+class SemanticMarkupLinkWidget;
+}
+
+/**
+ * Helper widget for the semantic markup edition to input the URL of a link.
+ * The widget contains a line edit where any URL can be written. However, it
+ * also offers support for a specific type of URLs: widget URLs. There are two
+ * radio buttons to select between a generic URL and a widget URL.
+ *
+ * Widget URLs represent a widget in the target application. When DBus module is
+ * enabled, the widget to link to can be selected using a RemoteObjectChooser.
+ *
+ * When the URL is got, the URL returned depends on the current type of URL
+ * selected. Widget URLs also contain the "widget:" protocol. When the URL is
+ * set, the line edit filled and radio button checked depend on the type of URL
+ * set.
+ */
+class SemanticMarkupLinkWidget: public QWidget {
+Q_OBJECT
+public:
+
+ /**
+ * Creates a new SemanticMarkupLinkWidget.
+ *
+ * @param parent The parent QWidget.
+ */
+ explicit SemanticMarkupLinkWidget(QWidget* parent = 0);
+
+ /**
+ * Destroys this widget.
+ */
+ virtual ~SemanticMarkupLinkWidget();
+
+ /**
+ * Returns the URL.
+ * If the URL is a widget URL, the returned URL contains the "widget:"
+ * protocol.
+ *
+ * @return The URL.
+ */
+ QString url() const;
+
+ /**
+ * Sets the URL.
+ * If the URL is a widget URL, the "widget:" protocol is not shown in its
+ * line edit.
+ *
+ * @param url The URL to set.
+ */
+ void setUrl(const QString& url);
+
+private:
+
+ /**
+ * The Ui Designer generated class.
+ */
+ Ui::SemanticMarkupLinkWidget* ui;
+
+#ifdef QT_QTDBUS_FOUND
+ /**
+ * The widget to get the name of a remote object.
+ */
+ RemoteObjectNameWidget* mRemoteObjectNameWidget;
+#endif
+
+};
+
+#endif
Property changes on: trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupLinkWidget.h
___________________________________________________________________
Added: svn:eol-style
+ native
Added: trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupLinkWidget.ui
===================================================================
--- trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupLinkWidget.ui (rev 0)
+++ trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupLinkWidget.ui 2011-05-05 14:39:15 UTC (rev 301)
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SemanticMarkupLinkWidget</class>
+ <widget class="QWidget" name="SemanticMarkupLinkWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="windowTitle">
+ <string comment="@title">URL for <emphasis>link</emphasis> element</string>
+ </property>
+ <property name="whatsThis">
+ <string comment="@info:whatsthis"><para>Set the <emphasis>url</emphasis> attribute for the <emphasis>link</emphasis> semantic element.</para>
+
+<para>Any URL can be set in the <interface>Generic</interface> field. For example, the URL of a webpage or the URL to link to a widget.</para>
+
+<para>However, to link to a widget it is better to just write the object name of the desired widget in the <interface>Widget</interface> field. Moreover, that field provides also text completion for the names and a dialog to choose the widget from a running target application.</para>
+
+<para>These advanced features, though, are not available in every system; if <application>KTutorial editor</application> was not built with <application>QtDBus</application> support only a plain text line will be shown. Again, only the name has to be written in the text line for the widget; <emphasis>widget:</emphasis> is automatically added to the URL when the dialog is accepted.</para></string>
+ </property>
+ <layout class="QVBoxLayout" name="SemanticMarkupLinkWidgetLayout">
+ <item>
+ <layout class="QHBoxLayout" name="semanticMarkupLinkWidgetHorizontalLayout">
+ <item>
+ <layout class="QVBoxLayout" name="radioButtonVerticalLayout">
+ <item>
+ <widget class="QRadioButton" name="genericLinkRadioButton">
+ <property name="text">
+ <string comment="@option:radio Generic link URL">Generic</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="widgetLinkRadioButton">
+ <property name="text">
+ <string comment="@option:radio Widget link URL">Widget</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="valueVerticalLayout">
+ <item>
+ <widget class="KLineEdit" name="genericLinkLineEdit"/>
+ </item>
+ <item>
+ <widget class="KLineEdit" name="widgetLinkLineEdit"/>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="semanticMarkupLinkWidgetSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::MinimumExpanding</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>KLineEdit</class>
+ <extends>QLineEdit</extends>
+ <header>klineedit.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
Added: trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupParser.cpp
===================================================================
--- trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupParser.cpp (rev 0)
+++ trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupParser.cpp 2011-05-05 14:39:15 UTC (rev 301)
@@ -0,0 +1,137 @@
+/***************************************************************************
+ * Copyright (C) 2011 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 "SemanticMarkupParser.h"
+
+#include <QRegExp>
+#include <QStringList>
+
+//public:
+
+SemanticMarkupParser::SemanticMarkupParser():
+ mCursorIndex(-1),
+ mCursorInsideTag(false) {
+}
+
+void SemanticMarkupParser::setCursorIndex(int cursorIndex) {
+ mCursorIndex = cursorIndex;
+}
+
+void SemanticMarkupParser::parse(const QString& text) {
+ mCursorInsideTag = false;
+ mOpenElements.clear();
+ mOpenElementsAtCursor.clear();
+ mNotClosedChildElements.clear();
+
+ QRegExp startTagRegExp("<\\s*(\\w+)\\s*((\\w+=\"[^\"]*\"\\s*)*)>");
+ QRegExp endTagRegExp("</\\s*(\\w+)\\s*>");
+ QRegExp emptyTagRegExp("<\\s*(\\w+)\\s*((\\w+=\"[^\"]*\"\\s*)*)/>");
+ QRegExp tagRegExp(startTagRegExp.pattern() + '|' +
+ endTagRegExp.pattern() + '|' +
+ emptyTagRegExp.pattern());
+
+ bool parsingReachedCursor = false;
+
+ int parsingIndex = tagRegExp.indexIn(text);
+ while (parsingIndex >= 0) {
+ QString tag = tagRegExp.capturedTexts().at(0);
+
+ if (mCursorIndex > parsingIndex &&
+ mCursorIndex < parsingIndex + tagRegExp.matchedLength()) {
+ mCursorInsideTag = true;
+ mOpenElementsAtCursor.clear();
+ return;
+ }
+
+ if (!parsingReachedCursor && parsingIndex >= mCursorIndex) {
+ parsingReachedCursor = true;
+ mOpenElementsAtCursor = mOpenElements;
+ }
+
+ if (startTagRegExp.exactMatch(tag)) {
+ StartTag startTag;
+ startTag.mName = startTagRegExp.capturedTexts().at(1);
+ startTag.mAttributes = startTagRegExp.capturedTexts().at(2);
+ startTag.mIndex = parsingIndex;
+ mOpenElements.insert(0, startTag);
+ } else if (endTagRegExp.exactMatch(tag)) {
+ QString endTagName = endTagRegExp.capturedTexts().at(1);
+
+ int endElementIndex = indexOf(mOpenElements, endTagName);
+ if (endElementIndex >= 0) {
+ int index = 0;
+ while (index < endElementIndex) {
+ mNotClosedChildElements.append(mOpenElements.first());
+ mOpenElements.removeFirst();
+ index++;
+ }
+ mOpenElements.removeFirst();
+ }
+ }
+
+ parsingIndex = parsingIndex + tagRegExp.matchedLength();
+ parsingIndex = tagRegExp.indexIn(text, parsingIndex);
+ }
+
+ if (!parsingReachedCursor) {
+ mOpenElementsAtCursor = mOpenElements;
+ }
+}
+
+bool SemanticMarkupParser::isElementClosed(const StartTag& startTag) const {
+ if (indexOf(mOpenElements, startTag) > -1 ||
+ indexOf(mNotClosedChildElements, startTag) > -1) {
+ return false;
+ }
+
+ return true;
+}
+
+bool SemanticMarkupParser::isCursorInsideTag() const {
+ return mCursorInsideTag;
+}
+
+QList<StartTag> SemanticMarkupParser::openElementsAtCursor() const {
+ return mOpenElementsAtCursor;
+}
+
+//private:
+
+int SemanticMarkupParser::indexOf(const QList<StartTag>& startTags,
+ const QString& tagName) const {
+ for (int i=0; i<startTags.count(); ++i) {
+ if (startTags[i].mName == tagName) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+int SemanticMarkupParser::indexOf(const QList<StartTag>& startTags,
+ const StartTag& startTag) const {
+ for (int i=0; i<startTags.count(); ++i) {
+ if (startTags[i].mName == startTag.mName &&
+ startTags[i].mAttributes == startTag.mAttributes &&
+ startTags[i].mIndex == startTag.mIndex) {
+ return i;
+ }
+ }
+
+ return -1;
+}
Property changes on: trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupParser.cpp
___________________________________________________________________
Added: svn:eol-style
+ native
Added: trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupParser.h
===================================================================
--- trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupParser.h (rev 0)
+++ trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupParser.h 2011-05-05 14:39:15 UTC (rev 301)
@@ -0,0 +1,182 @@
+/***************************************************************************
+ * Copyright (C) 2011 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 SEMANTICMARKUPPARSER_H
+#define SEMANTICMARKUPPARSER_H
+
+#include <QList>
+#include <QString>
+
+/**
+ * Structure to store the data of a XML start tag.
+ */
+struct StartTag {
+
+ /**
+ * The tag name.
+ */
+ QString mName;
+
+ /**
+ * The attributes, if any.
+ */
+ QString mAttributes;
+
+ /**
+ * The index of the tag in the text (the position of the '<' character).
+ */
+ int mIndex;
+
+ /**
+ * Creates a new StartTag.
+ */
+ StartTag():
+ mName(""),
+ mAttributes(""),
+ mIndex(-1) {
+ }
+
+};
+
+/**
+ * Simple parser for texts containing KUIT semantic markup.
+ * The parser is meant to provide SemanticMarkupEdition with information about
+ * the markup in the text. Thus, it is designed just for that purpose; it is not
+ * a general purpose parser.
+ *
+ * The parser supports XML where not all the elements have been closed. For
+ * example, it can parse a text with just a start tag, or a text where there
+ * is an unpaired start tag inside a valid element (one with paired start and
+ * end tags).
+ *
+ * The parser stores which elements have been opened, and when it reaches an end
+ * tag it regardes as closed the newest element that matches the end tag. For
+ * example, in <a><a><b></a></b>, when </a>
+ * is reached the second "a" element is regarded as closed. The </b> will
+ * be ignored, as the "b" element is no longer taken into account since its
+ * parent element was closed. Note, however, that the "b" element is not closed,
+ * and isElementClosed(StartTag) with that "b" element would return false.
+ * Passing the first "a" element would also return false; true would be returned
+ * only for the second "a" element.
+ *
+ * Before parsing a text, the cursor index has to be set using
+ * setCursorIndex(int). Then the text can be parsed using parse(QString).
+ *
+ * Once parsed, the SemanticMarkupParser object provides information about the
+ * parsed text regarding the cursor position. To update the information provided
+ * the text must be parsed again; that is, even if the only change is in the
+ * cursor index, parse(QString) has to be called again.
+ */
+class SemanticMarkupParser {
+public:
+
+ /**
+ * Creates a new SemanticMarkupParser.
+ */
+ SemanticMarkupParser();
+
+ /**
+ * Sets the index of the cursor.
+ *
+ * @param cursorIndex The index to set.
+ */
+ void setCursorIndex(int cursorIndex);
+
+ /**
+ * Parses the given text, updating the state of this parser.
+ *
+ * @param text The text to parse.
+ */
+ void parse(const QString& text);
+
+ /**
+ * Returns whether the cursor is inside a tag or not.
+ *
+ * @return True if the cursor is inside a tag, false otherwise.
+ */
+ bool isCursorInsideTag() const;
+
+ /**
+ * Returns whether the given start tag was closed or not.
+ *
+ * @param startTag The tag to check.
+ * @return True if the start tag was closed, false otherwise.
+ */
+ bool isElementClosed(const StartTag& startTag) const;
+
+ /**
+ * Returns a list with all the start tags that were open at the cursor
+ * position.
+ * The order of the tags goes from the deepest one to the more general one.
+ * That is, for <a><b>, the first tag is "b" and the second one
+ * is "a".
+ *
+ * @return The start tags open at the cursor.
+ */
+ QList<StartTag> openElementsAtCursor() const;
+
+private:
+
+ /**
+ * The position of the cursor in the text.
+ */
+ int mCursorIndex;
+
+ /**
+ * Whether the cursor was inside a tag or not in the last parsed text.
+ */
+ bool mCursorInsideTag;
+
+ /**
+ * A list with all the open elements at the end of the last parsed text.
+ */
+ QList<StartTag> mOpenElements;
+
+ /**
+ * A list with all the open elements at the cursor of the last parsed text.
+ */
+ QList<StartTag> mOpenElementsAtCursor;
+
+ /**
+ * A list with all the elements that were not closed but some ancestor
+ * element was at the end of the last parsed text.
+ */
+ QList<StartTag> mNotClosedChildElements;
+
+ /**
+ * The position in the given list of a tag with the given name.
+ *
+ * @param startTags The list to check.
+ * @param tagName The name of the tag to find.
+ * @return The position of the tag name, or -1 if it is not found.
+ */
+ int indexOf(const QList<StartTag>& startTags, const QString& tagName) const;
+
+ /**
+ * The position in the given list of the given tag.
+ *
+ * @param startTags The list to check.
+ * @param startTag The tag to find.
+ * @return The position of the tag, or -1 if it is not found.
+ */
+ int indexOf(const QList<StartTag>& startTags,
+ const StartTag& startTag) const;
+
+};
+
+#endif
Property changes on: trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupParser.h
___________________________________________________________________
Added: svn:eol-style
+ native
Modified: trunk/ktutorial/ktutorial-editor/src/view/StepDataWidget.cpp
===================================================================
--- trunk/ktutorial/ktutorial-editor/src/view/StepDataWidget.cpp 2011-04-30 17:31:13 UTC (rev 300)
+++ trunk/ktutorial/ktutorial-editor/src/view/StepDataWidget.cpp 2011-05-05 14:39:15 UTC (rev 301)
@@ -1,5 +1,5 @@
/***************************************************************************
- * Copyright (C) 2010 by Daniel Calviño Sánchez *
+ * Copyright (C) 2010-2011 by Daniel Calviño Sánchez *
* dan...@gm... *
* *
* This program is free software; you can redistribute it and/or modify *
@@ -18,7 +18,11 @@
#include "StepDataWidget.h"
+#include <KActionCollection>
+#include <KToolBar>
+
#include "ui_StepDataWidget.h"
+#include "SemanticMarkupEdition.h"
#include "../commands/StepCommands.h"
#include "../data/Step.h"
@@ -30,6 +34,17 @@
ui = new Ui::StepDataWidget();
ui->setupUi(this);
+ KToolBar* toolBar = new KToolBar(this);
+ int textEditIndex = ui->textLayout->indexOf(ui->textTextEdit);
+ ui->textLayout->insertWidget(textEditIndex, toolBar);
+
+ KActionCollection* editionActions = new KActionCollection(this);
+ editionActions->addAssociatedWidget(toolBar);
+
+ SemanticMarkupEdition* semanticMarkupEdition =
+ new SemanticMarkupEdition(ui->textTextEdit);
+ semanticMarkupEdition->createActions(editionActions);
+
ui->idLineEdit->setText(step->id());
ui->textTextEdit->setPlainText(step->text());
}
Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt
===================================================================
--- trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt 2011-04-30 17:31:13 UTC (rev 300)
+++ trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt 2011-05-05 14:39:15 UTC (rev 301)
@@ -26,6 +26,9 @@
NewWaitForWidget
ReactionTreeItem
ReactionWidget
+ SemanticMarkupEdition
+ SemanticMarkupLinkWidget
+ SemanticMarkupParser
StepCustomCodeWidget
StepDataWidget
StepTreeItem
@@ -79,6 +82,9 @@
NewWaitForWidget
ReactionTreeItem
ReactionWidget
+ SemanticMarkupEdition
+ SemanticMarkupLinkWidget
+ SemanticMarkupParser
StepCustomCodeWidget
StepDataWidget
StepTreeItem
Added: trunk/ktutorial/ktutorial-editor/tests/unit/view/SemanticMarkupEditionTest.cpp
===================================================================
--- trunk/ktutorial/ktutorial-editor/tests/unit/view/SemanticMarkupEditionTest.cpp (rev 0)
+++ trunk/ktutorial/ktutorial-editor/tests/unit/view/SemanticMarkupEditionTest.cpp 2011-05-05 14:39:15 UTC (rev 301)
@@ -0,0 +1,842 @@
+/***************************************************************************
+ * Copyright (C) 2011 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 "SemanticMarkupEdition.h"
+
+#include <QAction>
+#include <QTextEdit>
+
+#include <KActionCollection>
+#include <KPushButton>
+
+#include "SemanticMarkupLinkWidget.h"
+
+class SemanticMarkupEditionTest: public QObject {
+Q_OBJECT
+
+private slots:
+
+ void init();
+ void cleanup();
+
+ void testConstructor();
+
+ void testCreateActions();
+
+ void testEmphasis();
+ void testEmphasisStrong();
+ void testFilename();
+ void testInterface();
+ void testLink();
+ void testLinkUpdate();
+ void testLinkUpdateWithoutUrlAttribute();
+ void testNl();
+ void testShortcut();
+ void testPara();
+ void testList();
+ void testItem();
+
+ void testCursorInStartTag();
+ void testCursorInEndTag();
+ void testCursorInEmptyElementTag();
+
+ void testCursorBetweenPhraseTags();
+ void testCursorBetweenLinkTags();
+ void testCursorBetweenLinkTagsWithChildElement();
+ void testCursorBetweenParaTags();
+ void testCursorBetweenParaTagsWithPhraseTagNotClosed();
+ void testCursorBetweenListTags();
+ void testCursorBetweenListTagsWithItemTagNotClosed();
+ void testCursorBetweenItemTags();
+ void testCursorBetweenItemTagsWithPhraseTagNotClosed();
+
+ void testCursorBetweenEndAndStartTags();
+ void testCursorBetweenUnpairedTags();
+ void testCursorBetweenUnpairedTagsClosedLater();
+ void testCursorBetweenTwoStartTags();
+ void testCursorBetweenTwoEndTags();
+
+ void testChangeTextWithoutChangingCursorPosition();
+
+private:
+
+ SemanticMarkupEdition* mSemanticMarkupEdition;
+ KActionCollection* mActionCollection;
+ QTextEdit* mTextEdit;
+
+ QAction* mEmphasisAction;
+ QAction* mEmphasisStrongAction;
+ QAction* mFilenameAction;
+ QAction* mInterfaceAction;
+ QAction* mLinkAction;
+ QAction* mNlAction;
+ QAction* mShortcutAction;
+ QAction* mParaAction;
+ QAction* mListAction;
+ QAction* mItemAction;
+
+ void queueAssertLinkUrl(const QString& url, int timeToWait);
+ void queueSetLinkUrl(const QString& url, int timeToWait);
+ void queueCancelSetLinkUrl(const QString& url, int timeToWait);
+
+ void moveCursorTo(int position) const;
+
+ void assertOnlyEnabled(const QList<QAction*>& enabledActions) const;
+ void assertOnlyDisabled(const QList<QAction*>& disabledActions) const;
+ void assertOnlyChecked(const QList<QAction*>& checkedActions) const;
+
+ void assertTextStartTriggerTextEndTriggerText(QAction* action,
+ const QString& tagName) const;
+
+};
+
+void SemanticMarkupEditionTest::init() {
+ mTextEdit = new QTextEdit();
+ mSemanticMarkupEdition = new SemanticMarkupEdition(mTextEdit);
+ mActionCollection = new KActionCollection(this);
+
+ mSemanticMarkupEdition->createActions(mActionCollection);
+
+ mEmphasisAction = mActionCollection->action("kuit-edition-phrase-emphasis");
+ mEmphasisStrongAction =
+ mActionCollection->action("kuit-edition-phrase-emphasis-strong");
+ mFilenameAction = mActionCollection->action("kuit-edition-phrase-filename");
+ mInterfaceAction =
+ mActionCollection->action("kuit-edition-phrase-interface");
+ mLinkAction = mActionCollection->action("kuit-edition-phrase-link");
+ mNlAction = mActionCollection->action("kuit-edition-phrase-nl");
+ mShortcutAction = mActionCollection->action("kuit-edition-phrase-shortcut");
+ mParaAction = mActionCollection->action("kuit-edition-structure-para");
+ mListAction = mActionCollection->action("kuit-edition-structure-list");
+ mItemAction = mActionCollection->action("kuit-edition-structure-item");
+}
+
+void SemanticMarkupEditionTest::cleanup() {
+ delete mActionCollection;
+ delete mTextEdit;
+}
+
+void SemanticMarkupEditionTest::testConstructor() {
+ QTextEdit textEdit;
+ SemanticMarkupEdition* semanticMarkupEdition =
+ new SemanticMarkupEdition(&textEdit);
+
+ QCOMPARE(semanticMarkupEdition->parent(), &textEdit);
+}
+
+void SemanticMarkupEditionTest::testCreateActions() {
+ QTextEdit textEdit;
+ SemanticMarkupEdition* semanticMarkupEdition =
+ new SemanticMarkupEdition(&textEdit);
+ KActionCollection actionCollection(this);
+
+ semanticMarkupEdition->createActions(&actionCollection);
+
+ QCOMPARE(actionCollection.count(), 10);
+ QVERIFY(actionCollection.action("kuit-edition-phrase-emphasis"));
+ QVERIFY(actionCollectio...
[truncated message content] |