瀏覽代碼

Insert <body> element: undo, redo

Kandrashin Denis 13 年之前
父節點
當前提交
2c97b4ae83
共有 8 個文件被更改,包括 186 次插入39 次删除
  1. 89 6
      source/fb2html.cpp
  2. 54 7
      source/fb2html.h
  3. 1 1
      source/fb2main.cpp
  4. 15 8
      source/fb2text.cpp
  5. 1 1
      source/fb2text.hpp
  6. 20 15
      source/fb2tree.cpp
  7. 1 1
      source/fb2tree.hpp
  8. 5 0
      source/res/style.css

+ 89 - 6
source/fb2html.cpp

@@ -35,31 +35,114 @@ void Fb2TextElement::select()
     evaluateJavaScript(javascript);
 }
 
+bool Fb2TextElement::isBody() const
+{
+    return tagName() == "DIV" && attribute("class").toLower() == "body";
+}
+
 bool Fb2TextElement::isSection() const
 {
     return tagName() == "DIV" && attribute("class").toLower() == "section";
 }
 
+bool Fb2TextElement::hasTitle() const
+{
+    return Fb2TextElement(firstChild()).isTitle();
+}
+
 bool Fb2TextElement::isTitle() const
 {
     return tagName() == "DIV" && attribute("class").toLower() == "title";
 }
 
+//---------------------------------------------------------------------------
+//  Fb2UndoCommand
+//---------------------------------------------------------------------------
+
+QString Fb2UndoCommand::div(const QString &style, const QString &text)
+{
+    return QString("<div class=%1>%2</div>").arg(style).arg(text);
+}
+
+QString Fb2UndoCommand::p(const QString &text)
+{
+    return QString("<p>%1</p>").arg(text);
+}
+
 //---------------------------------------------------------------------------
 //  Fb2AddBodyCmd
 //---------------------------------------------------------------------------
 
 void Fb2AddBodyCmd::undo()
 {
-    m_page.body().lastChild().removeFromDocument();
-    Fb2TextElement(m_page.body().lastChild()).select();
+    m_body.takeFromDocument();
     m_page.update();
 }
 
 void Fb2AddBodyCmd::redo()
 {
-    m_page.body().appendInside("<div class=body><div class=section><p>text</p></div></div>");
-    Fb2TextElement(m_page.body().lastChild()).select();
+    Fb2TextElement parent = m_page.body();
+    if (m_body.isNull()) {
+        QString html = div("body", div("title", p()) + div("section", div("title", p()) + p()));
+        parent.appendInside(html);
+        m_body = parent.lastChild();
+    } else {
+        parent.appendInside(m_body);
+    }
+    m_body.select();
+    m_page.update();
+}
+
+//---------------------------------------------------------------------------
+//  Fb2SectionCmd
+//---------------------------------------------------------------------------
+
+void Fb2SectionCmd::redo()
+{
+    if (m_child.isNull()) {
+        QString html = div("section", div("title", p()) + p());
+        m_parent.appendInside(html);
+        m_child = m_parent.lastChild();
+    } else {
+        m_parent.appendInside(m_child);
+    }
+    m_child.select();
+    m_page.update();
+}
+
+void Fb2SectionCmd::undo()
+{
+    m_child.takeFromDocument();
+    Fb2TextElement last = m_parent.lastChild();
+    if (last.isNull()) {
+        m_parent.select();
+    } else {
+        last.select();
+    }
+    m_page.update();
+}
+
+//---------------------------------------------------------------------------
+//  Fb2TitleCmd
+//---------------------------------------------------------------------------
+
+void Fb2TitleCmd::redo()
+{
+    if (m_title.isNull()) {
+        QString html = div("title", p());
+        m_section.prependInside(html);
+        m_title = m_section.firstChild();
+    } else {
+        m_section.prependInside(m_title);
+    }
+    m_section.select();
+    m_page.update();
+}
+
+void Fb2TitleCmd::undo()
+{
+    m_title.takeFromDocument();
+    m_section.select();
     m_page.update();
 }
 
@@ -95,8 +178,8 @@ void Fb2SubtitleCmd::undo()
 //  Fb2DeleteCmd
 //---------------------------------------------------------------------------
 
-Fb2DeleteCmd::Fb2DeleteCmd(Fb2TextPage &page, const Fb2TextElement &element, QUndoCommand *parent)
-    : QUndoCommand(parent)
+Fb2DeleteCmd::Fb2DeleteCmd(Fb2TextPage &page, const Fb2TextElement &element, Fb2UndoCommand *parent)
+    : Fb2UndoCommand(parent)
     , m_element(element)
     , m_page(page)
     , m_inner(false)

+ 54 - 7
source/fb2html.h

@@ -18,28 +18,75 @@ public:
     Fb2TextElement &operator=(const QWebElement &x) { QWebElement::operator=(x); return *this; }
     void getChildren(Fb2ElementList &list);
     QString location();
+    bool hasTitle() const;
+    bool isBody() const;
     bool isSection() const;
     bool isTitle() const;
 
+public:
+    Fb2TextElement findFirst(const QString &selectorQuery) const { return QWebElement::findFirst(selectorQuery); }
+    Fb2TextElement parent() const { return QWebElement::parent(); }
+    Fb2TextElement firstChild() const { return QWebElement::firstChild(); }
+    Fb2TextElement lastChild() const { return QWebElement::lastChild(); }
+    Fb2TextElement nextSibling() const { return QWebElement::nextSibling(); }
+    Fb2TextElement previousSibling() const { return QWebElement::previousSibling(); }
+    Fb2TextElement document() const { return QWebElement::document(); }
+
 public:
     void select();
 };
 
-class Fb2AddBodyCmd : public QUndoCommand
+class Fb2UndoCommand : public QUndoCommand
+{
+public:
+    explicit Fb2UndoCommand(QUndoCommand *parent = 0) : QUndoCommand(parent) {}
+protected:
+    static QString div(const QString &style, const QString &text);
+    static QString p(const QString &text = "<br/>");
+};
+
+class Fb2AddBodyCmd : public Fb2UndoCommand
+{
+public:
+    explicit Fb2AddBodyCmd(Fb2TextPage &page, Fb2UndoCommand *parent = 0) : Fb2UndoCommand(parent), m_page(page) {}
+    virtual void undo();
+    virtual void redo();
+private:
+    Fb2TextPage & m_page;
+    Fb2TextElement m_body;
+};
+
+class Fb2SectionCmd : public Fb2UndoCommand
+{
+public:
+    explicit Fb2SectionCmd(Fb2TextPage &page, const Fb2TextElement &element, Fb2UndoCommand *parent = 0)
+        : Fb2UndoCommand(parent), m_page(page), m_parent(element) {}
+    virtual void undo();
+    virtual void redo();
+private:
+    Fb2TextPage & m_page;
+    Fb2TextElement m_parent;
+    Fb2TextElement m_child;
+};
+
+class Fb2TitleCmd : public Fb2UndoCommand
 {
 public:
-    explicit Fb2AddBodyCmd(Fb2TextPage &page, QUndoCommand *parent = 0) : QUndoCommand(parent), m_page(page) {}
+    explicit Fb2TitleCmd(Fb2TextPage &page, const Fb2TextElement &element, Fb2UndoCommand *parent = 0)
+        : Fb2UndoCommand(parent), m_page(page), m_section(element) {}
     virtual void undo();
     virtual void redo();
 private:
     Fb2TextPage & m_page;
+    Fb2TextElement m_section;
+    Fb2TextElement m_title;
 };
 
-class Fb2SubtitleCmd : public QUndoCommand
+class Fb2SubtitleCmd : public Fb2UndoCommand
 {
 public:
-    explicit Fb2SubtitleCmd(Fb2TextPage &page, const QString &location, QUndoCommand *parent = 0)
-        : QUndoCommand(parent), m_page(page), m_location(location) {}
+    explicit Fb2SubtitleCmd(Fb2TextPage &page, const QString &location, Fb2UndoCommand *parent = 0)
+        : Fb2UndoCommand(parent), m_page(page), m_location(location) {}
     virtual void undo();
     virtual void redo();
 private:
@@ -49,10 +96,10 @@ private:
     QString m_position;
 };
 
-class Fb2DeleteCmd : public QUndoCommand
+class Fb2DeleteCmd : public Fb2UndoCommand
 {
 public:
-    explicit Fb2DeleteCmd(Fb2TextPage &page, const Fb2TextElement &element, QUndoCommand *parent = 0);
+    explicit Fb2DeleteCmd(Fb2TextPage &page, const Fb2TextElement &element, Fb2UndoCommand *parent = 0);
     virtual void undo();
     virtual void redo();
 private:

+ 1 - 1
source/fb2main.cpp

@@ -695,7 +695,7 @@ void Fb2MainWindow::viewText()
     connect(actionImage, SIGNAL(triggered()), textEdit, SLOT(insertImage()));
     connect(actionNote, SIGNAL(triggered()), textEdit, SLOT(insertNote()));
     connect(actionLink, SIGNAL(triggered()), textEdit, SLOT(insertLink()));
-    connect(actionTitle, SIGNAL(triggered()), textEdit, SLOT(insertTitle()));
+    connect(actionTitle, SIGNAL(triggered()), textEdit->page(), SLOT(insertTitle()));
     connect(actionSubtitle, SIGNAL(triggered()), textEdit->page(), SLOT(insertSubtitle()));
     connect(actionBody, SIGNAL(triggered()), textEdit->page(), SLOT(insertBody()));
 

+ 15 - 8
source/fb2text.cpp

@@ -117,6 +117,21 @@ void Fb2TextPage::update()
     emit selectionChanged();
 }
 
+void Fb2TextPage::insertTitle()
+{
+    Fb2TextElement element = current();
+    while (!element.isNull()) {
+        Fb2TextElement parent = element.parent();
+        if (parent.isSection() && !parent.hasTitle()) {
+            undoStack()->beginMacro("Insert title");
+            undoStack()->push(new Fb2TitleCmd(*this, parent));
+            undoStack()->endMacro();
+            break;
+        }
+        element = parent;
+    }
+}
+
 void Fb2TextPage::insertSubtitle()
 {
     Fb2TextElement element = current();
@@ -416,14 +431,6 @@ void Fb2TextEdit::loadFinished()
     element.select();
 }
 
-void Fb2TextEdit::insertTitle()
-{
-    page()->undoStack()->beginMacro("Insert title");
-    static const QString javascript = FB2::read(":/js/insert_title.js");
-    page()->mainFrame()->evaluateJavaScript(javascript);
-    page()->undoStack()->endMacro();
-}
-
 //---------------------------------------------------------------------------
 //  Fb2TextFrame
 //---------------------------------------------------------------------------

+ 1 - 1
source/fb2text.hpp

@@ -67,6 +67,7 @@ public:
 
 public slots:
     void insertBody();
+    void insertTitle();
     void insertSubtitle();
 
 protected:
@@ -108,7 +109,6 @@ public slots:
     void insertImage();
     void insertNote();
     void insertLink();
-    void insertTitle();
     void zoomIn();
     void zoomOut();
     void zoomReset();

+ 20 - 15
source/fb2tree.cpp

@@ -532,13 +532,11 @@ void Fb2TreeView::updateTree()
     selectTree();
 }
 
-QModelIndex Fb2TreeModel::append(const QModelIndex &parent)
+QModelIndex Fb2TreeModel::append(const QModelIndex &parent, Fb2TextElement element)
 {
     Fb2TreeItem * owner = item(parent);
     if (!owner || owner == m_root) return QModelIndex();
     int row = owner->count();
-    owner->element().appendInside("<div class=section><div class=title><p><br/></p></div><p><br/></p></div>");
-    QWebElement element = owner->element().lastChild();
     Fb2TreeItem * child = new Fb2TreeItem(element);
     beginInsertRows(parent, row, row);
     owner->insert(child, row);
@@ -553,20 +551,27 @@ void Fb2TreeView::insertNode()
         Fb2TreeItem * item = m->item(index);
         if (!item) return;
 
-        QString n = item->name();
-        if (n != "section" && n != "body") {
+        Fb2TextElement element = item->element();
+        while (!element.isNull()) {
+            if (element.isSection() || element.isBody())
+            {
+                QUndoStack * undoStack = m_view.page()->undoStack();
+                undoStack->beginMacro("Insert section");
+                undoStack->push(new Fb2SectionCmd(*m_view.page(), element));
+                undoStack->endMacro();
+
+                QModelIndex result = m->append(index, element.lastChild());
+                if (!result.isValid()) return;
+                setCurrentIndex(result);
+                emit QTreeView::currentChanged(result, index);
+                emit QTreeView::activated(result);
+                scrollTo(result);
+
+                break;
+            }
+            element = element.parent();
             index = m->parent(index);
-            item = item->parent();
-            n = item->name();
-            if (n != "section" && n != "body") return;
         }
-
-        QModelIndex result = m->append(index);
-        if (!result.isValid()) return;
-        setCurrentIndex(result);
-        emit QTreeView::currentChanged(result, index);
-        emit QTreeView::activated(result);
-        scrollTo(result);
     }
 }
 

+ 1 - 1
source/fb2tree.hpp

@@ -105,7 +105,7 @@ public:
     Fb2TextEdit & view() { return m_view; }
     void selectText(const QModelIndex &index);
     QModelIndex move(const QModelIndex &index, int dx, int dy);
-    QModelIndex append(const QModelIndex &parent);
+    QModelIndex append(const QModelIndex &parent, Fb2TextElement element);
     Fb2TreeItem * item(const QModelIndex &index) const;
     void update();
 

+ 5 - 0
source/res/style.css

@@ -104,6 +104,11 @@ div.title {
   background: green;
   text-align: center;
   font-family: sans-serif;
+  font-size: 120%;
+}
+
+div.section div.title {
+  font-size: 100%;
 }
 
 div.subtitle {