Parcourir la source

Insert subtitle: use QUndoStack

Kandrashin Denis il y a 13 ans
Parent
commit
f39400bf6a
7 fichiers modifiés avec 125 ajouts et 65 suppressions
  1. 6 0
      source/fb2html.cpp
  2. 1 0
      source/fb2html.h
  3. 2 2
      source/fb2main.cpp
  4. 1 1
      source/fb2tree.cpp
  5. 100 50
      source/fb2view.cpp
  6. 11 6
      source/fb2view.hpp
  7. 4 6
      source/js/get_location.js

+ 6 - 0
source/fb2html.cpp

@@ -5,6 +5,12 @@
 //  Fb2TextElement
 //---------------------------------------------------------------------------
 
+QString Fb2TextElement::location()
+{
+    static const QString javascript = FB2::read(":/js/get_location.js").prepend("var element=this;");
+    return evaluateJavaScript(javascript).toString();
+}
+
 void Fb2TextElement::select()
 {
     static const QString javascript = FB2::read(":/js/set_cursor.js");

+ 1 - 0
source/fb2html.h

@@ -9,6 +9,7 @@ public:
     Fb2TextElement() {}
     Fb2TextElement(const QWebElement &x) : QWebElement(x) {}
     Fb2TextElement &operator=(const QWebElement &x) { QWebElement::operator=(x); return *this; }
+    QString location();
     bool isSection() const;
     bool isTitle() const;
 

+ 2 - 2
source/fb2main.cpp

@@ -464,7 +464,7 @@ void Fb2MainWindow::selectionChanged()
     actionTextSub->setChecked(textFrame->view.SubChecked());
     actionTextSup->setChecked(textFrame->view.SupChecked());
 
-    statusBar()->showMessage(textFrame->view.status());
+    statusBar()->showMessage(textFrame->view.page()->status());
 }
 
 void Fb2MainWindow::canUndoChanged(bool canUndo)
@@ -693,7 +693,7 @@ void Fb2MainWindow::viewText()
     connect(actionNote, SIGNAL(triggered()), textEdit, SLOT(insertNote()));
     connect(actionLink, SIGNAL(triggered()), textEdit, SLOT(insertLink()));
     connect(actionTitle, SIGNAL(triggered()), textEdit, SLOT(insertTitle()));
-    connect(actionSubtitle, SIGNAL(triggered()), textEdit, SLOT(insertSubtitle()));
+    connect(actionSubtitle, SIGNAL(triggered()), textEdit->page(), SLOT(insertSubtitle()));
     connect(actionBody, SIGNAL(triggered()), textEdit->page(), SLOT(insertBody()));
 
     connect(actionZoomIn, SIGNAL(triggered()), textEdit, SLOT(zoomIn()));

+ 1 - 1
source/fb2tree.cpp

@@ -463,7 +463,7 @@ void Fb2TreeView::selectTree()
 {
     if (qApp->focusWidget() == this) return;
     if (Fb2TreeModel * m = model()) {
-        QString location = m->view().location();
+        QString location = m->view().page()->location();
         QModelIndex index = m->index(location);
         if (!index.isValid()) return;
         setCurrentIndex(index);

+ 100 - 50
source/fb2view.cpp

@@ -94,12 +94,12 @@ bool Fb2TextPage::acceptNavigationRequest(QWebFrame *frame, const QNetworkReques
     return QWebPage::acceptNavigationRequest(frame, request, type);
 }
 
-QWebElement Fb2TextPage::body()
+Fb2TextElement Fb2TextPage::body()
 {
     return doc().findFirst("body");
 }
 
-QWebElement Fb2TextPage::doc()
+Fb2TextElement Fb2TextPage::doc()
 {
     return mainFrame()->documentElement();
 }
@@ -134,6 +134,99 @@ void Fb2TextPage::insertBody()
     emit contentsChanged();
 }
 
+class Fb2InsertSubtitleCmd : public QUndoCommand
+{
+public:
+    explicit Fb2InsertSubtitleCmd(Fb2TextPage &page, const QString &location, QUndoCommand *parent = 0)
+        : QUndoCommand(parent), m_page(page), m_location(location) {}
+    virtual void undo();
+    virtual void redo();
+private:
+    Fb2TextElement m_element;
+    Fb2TextPage & m_page;
+    QString m_location;
+    QString m_position;
+};
+
+void Fb2InsertSubtitleCmd::redo()
+{
+    QString html = "<div class=subtitle><p><br/></p></div>";
+    Fb2TextElement element = m_page.element(m_location);
+    if (m_element.isNull()) {
+        element.appendOutside(html);
+    } else {
+        element.appendOutside(m_element);
+    }
+    element = element.nextSibling();
+    m_position = element.location();
+    element.select();
+    QMetaObject::invokeMethod(&m_page, "selectionChanged");
+    QMetaObject::invokeMethod(&m_page, "contentsChanged");
+}
+
+void Fb2InsertSubtitleCmd::undo()
+{
+    Fb2TextElement element = m_page.element(m_position);
+    Fb2TextElement parent = element.parent();
+    m_element = element.takeFromDocument();
+    parent.select();
+    QMetaObject::invokeMethod(&m_page, "selectionChanged");
+    QMetaObject::invokeMethod(&m_page, "contentsChanged");
+}
+
+void Fb2TextPage::insertSubtitle()
+{
+    Fb2TextElement element = current();
+    while (!element.isNull()) {
+        Fb2TextElement parent = element.parent();
+        if (parent.isSection()) {
+            Fb2TextElement previous = element.previousSibling();
+            if (!previous.isNull()) element = previous;
+            undoStack()->beginMacro("Insert subtitle");
+            undoStack()->push(new Fb2InsertSubtitleCmd(*this, element.location()));
+            undoStack()->endMacro();
+            emit contentsChanged();
+            break;
+        }
+        element = parent;
+    }
+}
+
+Fb2TextElement Fb2TextPage::current()
+{
+    return element(location());
+}
+
+Fb2TextElement Fb2TextPage::element(const QString &location)
+{
+    QStringList list = location.split(",");
+    QStringListIterator iterator(list);
+    QWebElement result = doc();
+    while (iterator.hasNext()) {
+        QString str = iterator.next();
+        int pos = str.indexOf("=");
+        QString tag = str.left(pos);
+        int key = str.mid(pos + 1).toInt();
+        if (key < 0) break;
+        result = result.firstChild();
+        while (0 < key--) result = result.nextSibling();
+        if (tag == "P") break;
+    }
+    return result;
+}
+
+QString Fb2TextPage::location()
+{
+    static const QString javascript = FB2::read(":/js/get_location.js").prepend("var element=document.getSelection().anchorNode;");
+    return mainFrame()->evaluateJavaScript(javascript).toString();
+}
+
+QString Fb2TextPage::status()
+{
+    static const QString javascript = FB2::read(":/js/get_status.js");
+    return mainFrame()->evaluateJavaScript(javascript).toString();
+}
+
 //---------------------------------------------------------------------------
 //  Fb2TextEdit
 //---------------------------------------------------------------------------
@@ -156,6 +249,11 @@ Fb2TextEdit::~Fb2TextEdit()
     FB2DELETE(m_noteView);
 }
 
+Fb2TextPage * Fb2TextEdit::page()
+{
+    return qobject_cast<Fb2TextPage*>(Fb2TextBase::page());
+}
+
 Fb2NoteView & Fb2TextEdit::noteView()
 {
     if (m_noteView) return *m_noteView;
@@ -370,36 +468,6 @@ void Fb2TextEdit::execCommand(const QString &cmd, const QString &arg)
     page()->mainFrame()->evaluateJavaScript(javascript);
 }
 
-QWebElement Fb2TextEdit::current()
-{
-    QStringList list = location().split(",");
-    QStringListIterator iterator(list);
-    QWebElement result = doc();
-    while (iterator.hasNext()) {
-        QString str = iterator.next();
-        int pos = str.indexOf("=");
-        QString tag = str.left(pos);
-        int key = str.mid(pos + 1).toInt();
-        if (key < 0) break;
-        result = result.firstChild();
-        while (0 < key--) result = result.nextSibling();
-        if (tag == "P") break;
-    }
-    return result;
-}
-
-QString Fb2TextEdit::location()
-{
-    static const QString javascript = FB2::read(":/js/get_location.js");
-    return page()->mainFrame()->evaluateJavaScript(javascript).toString();
-}
-
-QString Fb2TextEdit::status()
-{
-    static const QString javascript = FB2::read(":/js/get_status.js");
-    return page()->mainFrame()->evaluateJavaScript(javascript).toString();
-}
-
 void Fb2TextEdit::loadFinished()
 {
     Fb2TextElement element = body().findFirst("div.body");
@@ -415,24 +483,6 @@ void Fb2TextEdit::insertTitle()
     page()->undoStack()->endMacro();
 }
 
-void Fb2TextEdit::insertSubtitle()
-{
-    Fb2TextElement element = current();
-    while (!element.isNull()) {
-        Fb2TextElement parent = element.parent();
-        if (parent.isSection()) {
-            Fb2TextElement previous = element.previousSibling();
-            if (!previous.isNull()) element = previous;
-            QString html = "<div class=subtitle><p><br/></p></div>";
-            element.appendOutside(html);
-            Fb2TextElement subtitle = element.nextSibling();
-            subtitle.select();
-            break;
-        }
-        element = parent;
-    }
-}
-
 //---------------------------------------------------------------------------
 //  Fb2TextFrame
 //---------------------------------------------------------------------------

+ 11 - 6
source/fb2view.hpp

@@ -16,6 +16,7 @@ class QDockWidget;
 QT_END_NAMESPACE
 
 class Fb2NoteView;
+class Fb2TextElement;
 
 class Fb2TextBase : public QWebView
 {
@@ -54,11 +55,18 @@ class Fb2TextPage : public QWebPage
 
 public:
     explicit Fb2TextPage(QObject *parent = 0);
-    QWebElement body();
-    QWebElement doc();
+
+    Fb2TextElement element(const QString &location);
+    Fb2TextElement current();
+    QString location();
+    QString status();
+
+    Fb2TextElement body();
+    Fb2TextElement doc();
 
 public slots:
     void insertBody();
+    void insertSubtitle();
 
 protected:
     virtual bool acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, NavigationType type);
@@ -72,14 +80,12 @@ public:
     explicit Fb2TextEdit(QWidget *parent = 0);
     virtual ~Fb2TextEdit();
 
+    Fb2TextPage * page();
     Fb2TemporaryList & files() { return m_files; }
     void load(const QString &filename, const QString &xml = QString());
     bool save(QIODevice *device, const QString &codec = QString());
     bool save(QByteArray *array);
     bool save(QString *string);
-    QWebElement current();
-    QString location();
-    QString status();
 
     bool UndoEnabled();
     bool RedoEnabled();
@@ -102,7 +108,6 @@ public slots:
     void insertNote();
     void insertLink();
     void insertTitle();
-    void insertSubtitle();
     void zoomIn();
     void zoomOut();
     void zoomReset();

+ 4 - 6
source/js/get_location.js

@@ -1,11 +1,9 @@
-var startNode = document.getSelection().anchorNode;
 // create a reverse function for jQuery
 $.fn.reverse = [].reverse; 
-var hierarchy = $( startNode ).parents().reverse().add( $( startNode ) ) ;
+var hierarchy = $(element).parents().reverse().add($(element));
 hierarchy.map(function () { 
-    if ( undefined !== $( this ).parent().get( 0 ).tagName )
-	{
-        var first_part = $( this ).parent().get( 0 ).tagName + "=";
-        return first_part + $( this ).parent().children().index( this );
+    var parent = $(this).parent();
+    if (undefined !== parent.get( 0 ).tagName) {
+        return parent.get(0).tagName + "=" + parent.children().index(this);
     }
 }).get().join(",");