浏览代码

FB2: <poem>, <stanza>, <v>

Kandrashin Denis 13 年之前
父节点
当前提交
28adac5752
共有 4 个文件被更改,包括 274 次插入135 次删除
  1. 113 91
      source/fb2main.cpp
  2. 9 3
      source/fb2main.h
  3. 107 36
      source/fb2read.cpp
  4. 45 5
      source/fb2read.h

+ 113 - 91
source/fb2main.cpp

@@ -10,18 +10,39 @@
 MainWindow::MainWindow()
 {
     init();
+    createText();
     setCurrentFile("");
 }
 
-MainWindow::MainWindow(const QString &filename, QTextDocument * document)
+MainWindow::MainWindow(const QString &filename)
 {
     init();
+    createQsci();
+    loadXML(filename);
+    setCurrentFile(filename);
+}
 
-    if (!document) document = LoadDocument(filename);
+MainWindow::MainWindow(const QString &filename, QTextDocument * document)
+{
+    init();
+    createText();
+    if (!document) document = loadFB2(filename);
     setCurrentFile(filename, document);
 }
 
-QTextDocument * MainWindow::LoadDocument(const QString &filename)
+bool MainWindow::loadXML(const QString &filename)
+{
+    if (!filename.isEmpty()) {
+        QFile file(filename);
+        if (file.open(QFile::ReadOnly | QFile::Text)) {
+            qsciEdit->clear();
+            return qsciEdit->read(&file);
+        }
+    }
+    return false;
+}
+
+QTextDocument * MainWindow::loadFB2(const QString &filename)
 {
     if (filename.isEmpty()) return NULL;
 
@@ -77,16 +98,29 @@ void MainWindow::open()
         return;
     }
 
-    QTextDocument * document = LoadDocument(filename);
-    if (!document) return;
+    if (textEdit) {
+        QTextDocument * document = loadFB2(filename);
+        if (!document) return;
+
+        if (isUntitled && textEdit->document()->isEmpty() && !isWindowModified()) {
+            setCurrentFile(filename, document);
+        } else {
+            MainWindow * other = new MainWindow(filename, document);
+            other->move(x() + 40, y() + 40);
+            other->show();
+        }
+    } else if (qsciEdit) {
+        if (isUntitled && !isWindowModified()) {
+            loadXML(filename);
+            setCurrentFile(filename);
+        } else {
+            MainWindow * other = new MainWindow(filename);
+            other->move(x() + 40, y() + 40);
+            other->show();
+        }
 
-    if (isUntitled && textEdit->document()->isEmpty() && !isWindowModified()) {
-        setCurrentFile(filename, document);
-    } else {
-        MainWindow * other = new MainWindow(filename, document);
-        other->move(x() + 40, y() + 40);
-        other->show();
     }
+
 }
 
 bool MainWindow::save()
@@ -127,11 +161,6 @@ void MainWindow::init()
 
     isUntitled = true;
 
-    textEdit = new QTextEdit;
-    textEdit->setAcceptRichText(true);
-    setCentralWidget(textEdit);
-    connect(textEdit->document(), SIGNAL(contentsChanged()), this, SLOT(documentWasModified()));
-
     createActions();
     createMenus();
     createToolBars();
@@ -142,6 +171,66 @@ void MainWindow::init()
     setUnifiedTitleAndToolBarOnMac(true);
 }
 
+void MainWindow::createText()
+{
+    textEdit = new QTextEdit;
+    textEdit->setAcceptRichText(true);
+    setCentralWidget(textEdit);
+
+    connect(cutAct, SIGNAL(triggered()), textEdit, SLOT(cut()));
+    connect(copyAct, SIGNAL(triggered()), textEdit, SLOT(copy()));
+    connect(pasteAct, SIGNAL(triggered()), textEdit, SLOT(paste()));
+
+    connect(textEdit->document(), SIGNAL(contentsChanged()), this, SLOT(documentWasModified()));
+    connect(textEdit, SIGNAL(copyAvailable(bool)), cutAct, SLOT(setEnabled(bool)));
+    connect(textEdit, SIGNAL(copyAvailable(bool)), copyAct, SLOT(setEnabled(bool)));
+}
+
+void MainWindow::createQsci()
+{
+    //  http://qtcoder.blogspot.com/2010/10/qscintills.html
+    //  http://www.riverbankcomputing.co.uk/static/Docs/QScintilla2/classQsciScintilla.html
+
+    qsciEdit = new QsciScintilla;
+    qsciEdit->setUtf8(true);
+    qsciEdit->setCaretLineVisible(true);
+    qsciEdit->setCaretLineBackgroundColor(QColor("gainsboro"));
+    qsciEdit->setWrapMode(QsciScintilla::WrapWord);
+
+    qsciEdit->setEolMode(QsciScintilla::EolWindows);
+
+    qsciEdit->setAutoIndent(true);
+    qsciEdit->setIndentationGuides(true);
+
+    qsciEdit->setAutoCompletionSource(QsciScintilla::AcsAll);
+    qsciEdit->setAutoCompletionCaseSensitivity(true);
+    qsciEdit->setAutoCompletionReplaceWord(true);
+    qsciEdit->setAutoCompletionShowSingle(true);
+    qsciEdit->setAutoCompletionThreshold(2);
+
+    qsciEdit->setMarginsBackgroundColor(QColor("gainsboro"));
+    qsciEdit->setMarginWidth(0, 0);
+    qsciEdit->setMarginLineNumbers(1, true);
+    qsciEdit->setMarginWidth(1, QString("1000"));
+    qsciEdit->setFolding(QsciScintilla::BoxedFoldStyle, 2);
+
+    qsciEdit->setBraceMatching(QsciScintilla::SloppyBraceMatch);
+    qsciEdit->setMatchedBraceBackgroundColor(Qt::yellow);
+    qsciEdit->setUnmatchedBraceForegroundColor(Qt::blue);
+
+    QFont font("Monospace", 10);
+    font.setStyleHint(QFont::TypeWriter);
+    qsciEdit->setFont(font);
+    qsciEdit->setBraceMatching(QsciScintilla::SloppyBraceMatch);
+    qsciEdit->setLexer(new QsciLexerXML);
+
+    setCentralWidget(qsciEdit);
+    qsciEdit->setFocus();
+
+    //    connect(qsciEdit, SIGNAL(textChanged()), this, SLOT(documentWasModified()));
+    //    connect(qsciEdit, SIGNAL(cursorPositionChanged(int, int)), this, SLOT(cursorMoved(int, int)));
+}
+
 void MainWindow::createActions()
 {
     newAct = new QAction(QIcon(":/images/new.png"), tr("&New"), this);
@@ -177,17 +266,14 @@ void MainWindow::createActions()
     cutAct = new QAction(QIcon(":/images/cut.png"), tr("Cu&t"), this);
     cutAct->setShortcuts(QKeySequence::Cut);
     cutAct->setStatusTip(tr("Cut the current selection's contents to the clipboard"));
-    connect(cutAct, SIGNAL(triggered()), textEdit, SLOT(cut()));
 
     copyAct = new QAction(QIcon(":/images/copy.png"), tr("&Copy"), this);
     copyAct->setShortcuts(QKeySequence::Copy);
     copyAct->setStatusTip(tr("Copy the current selection's contents to the clipboard"));
-    connect(copyAct, SIGNAL(triggered()), textEdit, SLOT(copy()));
 
     pasteAct = new QAction(QIcon(":/images/paste.png"), tr("&Paste"), this);
     pasteAct->setShortcuts(QKeySequence::Paste);
     pasteAct->setStatusTip(tr("Paste the clipboard's contents into the current selection"));
-    connect(pasteAct, SIGNAL(triggered()), textEdit, SLOT(paste()));
 
     textAct = new QAction(tr("&Text"), this);
     textAct->setCheckable(true);
@@ -212,15 +298,11 @@ void MainWindow::createActions()
 
     cutAct->setEnabled(false);
     copyAct->setEnabled(false);
-    connect(textEdit, SIGNAL(copyAvailable(bool)), cutAct, SLOT(setEnabled(bool)));
-    connect(textEdit, SIGNAL(copyAvailable(bool)), copyAct, SLOT(setEnabled(bool)));
 }
 
-//! [implicit tr context]
 void MainWindow::createMenus()
 {
     fileMenu = menuBar()->addMenu(tr("&File"));
-//! [implicit tr context]
     fileMenu->addAction(newAct);
     fileMenu->addAction(openAct);
     fileMenu->addAction(saveAct);
@@ -247,11 +329,9 @@ void MainWindow::createMenus()
 
 void MainWindow::createToolBars()
 {
-//! [0]
     fileToolBar = addToolBar(tr("File"));
     fileToolBar->addAction(newAct);
     fileToolBar->addAction(openAct);
-//! [0]
     fileToolBar->addAction(saveAct);
 
     editToolBar = addToolBar(tr("Edit"));
@@ -337,18 +417,15 @@ void MainWindow::setCurrentFile(const QString &filename, QTextDocument * documen
     }
     title += QString(" - ") += qApp->applicationName();
 
-    if (document) textEdit->setDocument(document); else textEdit->clear();
-    textEdit->document()->setModified(false);
+    if (document) {
+        textEdit->setDocument(document);
+        textEdit->document()->setModified(false);
+        connect(textEdit->document(), SIGNAL(contentsChanged()), this, SLOT(documentWasModified()));
+    }
+
     setWindowModified(false);
     setWindowFilePath(curFile);
     setWindowTitle(title);
-
-    connect(textEdit->document(), SIGNAL(contentsChanged()), this, SLOT(documentWasModified()));
-}
-
-QString MainWindow::strippedName(const QString &fullFileName)
-{
-    return QFileInfo(fullFileName).fileName();
 }
 
 MainWindow *MainWindow::findMainWindow(const QString &fileName)
@@ -367,67 +444,12 @@ void MainWindow::viewQsci()
 {
     if (centralWidget() == qsciEdit) return;
     if (textEdit) { delete textEdit; textEdit = NULL; }
-
-//  http://qtcoder.blogspot.com/2010/10/qscintills.html
-//  http://www.riverbankcomputing.co.uk/static/Docs/QScintilla2/classQsciScintilla.html
-
-    qsciEdit = new QsciScintilla;
-    qsciEdit->setUtf8(true);
-    qsciEdit->setCaretLineVisible(true);
-    qsciEdit->setCaretLineBackgroundColor(QColor("gainsboro"));
-    qsciEdit->setWrapMode(QsciScintilla::WrapWord);
-
-    qsciEdit->setEolMode(QsciScintilla::EolWindows);
-
-    qsciEdit->setAutoIndent(true);
-    qsciEdit->setIndentationGuides(true);
-
-    qsciEdit->setAutoCompletionSource(QsciScintilla::AcsAll);
-    qsciEdit->setAutoCompletionCaseSensitivity(true);
-    qsciEdit->setAutoCompletionReplaceWord(true);
-    qsciEdit->setAutoCompletionShowSingle(true);
-    qsciEdit->setAutoCompletionThreshold(2);
-
-    qsciEdit->setMarginsBackgroundColor(QColor("gainsboro"));
-    qsciEdit->setMarginWidth(0, QString("1000"));
-    qsciEdit->setMarginWidth(1, 0);
-    qsciEdit->setMarginLineNumbers(0, true);
-
-    qsciEdit->setBraceMatching(QsciScintilla::SloppyBraceMatch);
-    qsciEdit->setMatchedBraceBackgroundColor(Qt::yellow);
-    qsciEdit->setUnmatchedBraceForegroundColor(Qt::blue);
-
-    QFont font("Monospace", 10);
-    font.setStyleHint(QFont::TypeWriter);
-    qsciEdit->setFont(font);
-    qsciEdit->setBraceMatching(QsciScintilla::SloppyBraceMatch);
-    qsciEdit->setLexer(new QsciLexerXML);
-
-    setCentralWidget(qsciEdit);
-    qsciEdit->setFocus();
-
-    QString filename = windowFilePath();
-    if (!filename.isEmpty()) {
-        QFile file(filename);
-        if (file.open(QFile::ReadOnly | QFile::Text)) {
-            qsciEdit->clear();
-            qsciEdit->read(&file);
-        }
-    }
-
-//    connect(qsciEdit, SIGNAL(textChanged()), this, SLOT(documentWasModified()));
-//    connect(qsciEdit, SIGNAL(cursorPositionChanged(int, int)), this, SLOT(cursorMoved(int, int)));
-
+    createQsci();
 }
 
 void MainWindow::viewText()
 {
     if (centralWidget() == textEdit) return;
     if (qsciEdit) { delete qsciEdit; qsciEdit = NULL; }
-
-    textEdit = new QTextEdit;
-    textEdit->setAcceptRichText(true);
-    setCentralWidget(textEdit);
-    textEdit->setFocus();
-    connect(textEdit->document(), SIGNAL(contentsChanged()), this, SLOT(documentWasModified()));
+    createText();
 }

+ 9 - 3
source/fb2main.h

@@ -6,6 +6,7 @@
 QT_BEGIN_NAMESPACE
 class QAction;
 class QMenu;
+class QFile;
 class QTextEdit;
 class QTextDocument;
 QT_END_NAMESPACE
@@ -18,8 +19,8 @@ class MainWindow : public QMainWindow
 
 public:
     MainWindow();
-    MainWindow(const QString &filename, QTextDocument * document = NULL);
-    static QTextDocument * LoadDocument(const QString &filename);
+    MainWindow(const QString &filename);
+    MainWindow(const QString &filename, QTextDocument * document);
 
 protected:
     void closeEvent(QCloseEvent *event);
@@ -34,8 +35,14 @@ private slots:
     void viewQsci();
     void viewText();
 
+private:
+    static QTextDocument * loadFB2(const QString &filename);
+    bool loadXML(const QString &filename);
+
 private:
     void init();
+    void createText();
+    void createQsci();
     void createActions();
     void createMenus();
     void createToolBars();
@@ -45,7 +52,6 @@ private:
     bool maybeSave();
     bool saveFile(const QString &fileName);
     void setCurrentFile(const QString &fileName, QTextDocument * document = NULL);
-    QString strippedName(const QString &fullFileName);
     MainWindow *findMainWindow(const QString &fileName);
 
     QTextEdit *textEdit;

+ 107 - 36
source/fb2read.cpp

@@ -174,28 +174,23 @@ bool Fb2Handler::BodyHandler::doStart(const QString &name, const QXmlAttributes
     return true;
 }
 
-bool Fb2Handler::BodyHandler::doText(const QString &text)
-{
-    if (m_handler) return m_handler->doText(text);
-    cursor().insertText(text);
-    return true;
-}
-
 //---------------------------------------------------------------------------
 //  Fb2Handler::SectionHandler
 //---------------------------------------------------------------------------
 
 Fb2Handler::SectionHandler::KeywordHash::KeywordHash()
 {
+    insert("title",      Title);
+    insert("epigraph",   Epigraph);
     insert("image",      Image);
+    insert("annotation", Annotation);
     insert("section",    Section);
-    insert("title",      Title);
-
     insert("p",          Paragraph);
-    insert("empty-line", Emptyline);
     insert("poem",       Poem);
-    insert("stanza",     Stanza);
-    insert("v",          Verse);
+    insert("subtitle",   Subtitle);
+    insert("cite",       Cite);
+    insert("empty-line", Emptyline);
+    insert("table",      Table);
 }
 
 Fb2Handler::SectionHandler::SectionHandler(ContentHandler &parent, const QString &name, const QXmlAttributes &attributes)
@@ -209,23 +204,8 @@ Fb2Handler::SectionHandler::SectionHandler(ContentHandler &parent, const QString
     frameFormat.setPadding(8);
     frameFormat.setTopMargin(4);
     frameFormat.setBottomMargin(4);
-    if (name == "title") {
-        frameFormat.setWidth(QTextLength(QTextLength::PercentageLength, 80));
-    }
-
-//    if (name == "stanza") {
-//        frameFormat.setLeftMargin(20);
-//        frameFormat.setWidth(QTextLength(QTextLength::PercentageLength, 80));
-//        frameFormat.setPosition(QTextFrameFormat::FloatRight);
-
-    if (name == "stanza") {
-        QTextTableFormat format;
-        format.setCellPadding(5);
-        format.setCellSpacing(5);
-        QTextTable * table = cursor().insertTable(1, 1, format);
-    } else {
-        cursor().insertFrame(frameFormat);
-    }
+    if (name == "title") frameFormat.setWidth(QTextLength(QTextLength::PercentageLength, 80));
+    cursor().insertFrame(frameFormat);
 
     QTextBlockFormat blockFormat;
     blockFormat.setTopMargin(4);
@@ -251,7 +231,6 @@ bool Fb2Handler::SectionHandler::doStart(const QString &name, const QXmlAttribut
         case Paragraph:
         case Emptyline:
         case Image:
-        case Verse:
             if (m_feed) cursor().insertBlock();
             m_feed = true;
             break;
@@ -262,11 +241,9 @@ bool Fb2Handler::SectionHandler::doStart(const QString &name, const QXmlAttribut
     switch (keyword) {
         case Emptyline : m_handler = new ContentHandler(*this); break;
         case Paragraph : m_handler = new TextHandler(*this, name); break;
-        case Verse     : m_handler = new TextHandler(*this, name); break;
         case Section   : m_handler = new SectionHandler(*this, name, attributes); break;
         case Title     : m_handler = new SectionHandler(*this, name, attributes); break;
-        case Poem      : m_handler = new SectionHandler(*this, name, attributes); break;
-        case Stanza    : m_handler = new SectionHandler(*this, name, attributes); break;
+        case Poem      : m_handler = new PoemHandler(*this, attributes); break;
         case Image     : m_handler = new ImageHandler(*this, attributes); break;
         default        : m_handler = new TextHandler(*this, name); break;
     }
@@ -274,10 +251,104 @@ bool Fb2Handler::SectionHandler::doStart(const QString &name, const QXmlAttribut
     return true;
 }
 
-bool Fb2Handler::SectionHandler::doText(const QString &text)
+//---------------------------------------------------------------------------
+//  Fb2Handler::PoemHandler
+//---------------------------------------------------------------------------
+
+Fb2Handler::PoemHandler::KeywordHash::KeywordHash()
+{
+    insert("title",      Title);
+    insert("epigraph",   Epigraph);
+    insert("stanza",     Stanza);
+    insert("author",     Author);
+    insert("date",       Date);
+}
+
+Fb2Handler::PoemHandler::Keyword Fb2Handler::PoemHandler::toKeyword(const QString &name)
 {
-    if (m_handler) return m_handler->doText(text);
-    cursor().insertText(text);
+    static KeywordHash map;
+    KeywordHash::const_iterator i = map.find(name);
+    return i == map.end() ? None : i.value();
+}
+
+Fb2Handler::PoemHandler::PoemHandler(ContentHandler &parent, const QXmlAttributes &attributes)
+    : ContentHandler(parent)
+    , m_feed(false)
+{
+    m_frame = cursor().currentFrame();
+    QTextTableFormat format;
+    format.setBorder(1);
+    format.setCellPadding(8);
+    format.setCellSpacing(0);
+    format.setBorderStyle(QTextFrameFormat::BorderStyle_Solid);
+    m_table = cursor().insertTable(1, 1, format);
+}
+
+bool Fb2Handler::PoemHandler::doStart(const QString &name, const QXmlAttributes &attributes)
+{
+    if (m_handler) return m_handler->doStart(name, attributes);
+
+    Keyword keyword = toKeyword(name);
+
+    switch (keyword) {
+        case Title:
+        case Epigraph:
+        case Stanza:
+        case Author:
+            if (m_feed) m_table->appendRows(1);
+            m_feed = true;
+            m_handler = new StanzaHandler(*this, attributes);
+            break;
+        default:
+            break;
+    }
+
+    return true;
+}
+
+//---------------------------------------------------------------------------
+//  Fb2Handler::StanzaHandler
+//---------------------------------------------------------------------------
+
+Fb2Handler::StanzaHandler::KeywordHash::KeywordHash()
+{
+    insert("title",      Title);
+    insert("subtitle",   Subtitle);
+    insert("v",          Verse);
+}
+
+Fb2Handler::StanzaHandler::Keyword Fb2Handler::StanzaHandler::toKeyword(const QString &name)
+{
+    static KeywordHash map;
+    KeywordHash::const_iterator i = map.find(name);
+    return i == map.end() ? None : i.value();
+}
+
+Fb2Handler::StanzaHandler::StanzaHandler(ContentHandler &parent, const QXmlAttributes &attributes)
+    : ContentHandler(parent)
+    , m_feed(false)
+{
+}
+
+bool Fb2Handler::StanzaHandler::doStart(const QString &name, const QXmlAttributes &attributes)
+{
+    if (m_handler) return m_handler->doStart(name, attributes);
+
+    Keyword keyword = toKeyword(name);
+
+    switch (keyword) {
+//        case Title:
+//        case Subtitle:
+        case Verse:
+            if (m_feed) cursor().insertBlock();
+            m_feed = true;
+            m_handler = new TextHandler(*this, name); break;
+            break;
+        default:
+            break;
+    }
+
+
     return true;
 }
 

+ 45 - 5
source/fb2read.h

@@ -72,7 +72,6 @@ private:
     public:
         BodyHandler(ContentHandler &parent);
         virtual bool doStart(const QString &name, const QXmlAttributes &attributes);
-        virtual bool doText(const QString &text);
     private:
         enum Keyword {
             None = 0,
@@ -129,23 +128,64 @@ private:
     public:
         SectionHandler(ContentHandler &parent, const QString &name, const QXmlAttributes &attributes);
         virtual bool doStart(const QString &name, const QXmlAttributes &attributes);
-        virtual bool doText(const QString &text);
     private:
         enum Keyword {
             None = 0,
+            Title,
+            Epigraph,
             Image,
+            Annotation,
+            Section,
             Paragraph,
+            Poem,
+            Subtitle,
+            Cite,
             Emptyline,
-            Section,
+            Table,
+        };
+        class KeywordHash : public QHash<QString, Keyword> { public: KeywordHash(); };
+        static Keyword toKeyword(const QString &name);
+    private:
+        QString m_name;
+        bool m_feed;
+    };
+
+    class PoemHandler : public ContentHandler
+    {
+    public:
+        PoemHandler(ContentHandler &parent, const QXmlAttributes &attributes);
+        virtual bool doStart(const QString &name, const QXmlAttributes &attributes);
+    private:
+        enum Keyword {
+            None = 0,
             Title,
-            Poem,
+            Epigraph,
             Stanza,
+            Author,
+            Date,
+        };
+        class KeywordHash : public QHash<QString, Keyword> { public: KeywordHash(); };
+        static Keyword toKeyword(const QString &name);
+    private:
+        QTextTable * m_table;
+        bool m_feed;
+    };
+
+    class StanzaHandler : public ContentHandler
+    {
+    public:
+        StanzaHandler(ContentHandler &parent, const QXmlAttributes &attributes);
+        virtual bool doStart(const QString &name, const QXmlAttributes &attributes);
+    private:
+        enum Keyword {
+            None = 0,
+            Title,
+            Subtitle,
             Verse,
         };
         class KeywordHash : public QHash<QString, Keyword> { public: KeywordHash(); };
         static Keyword toKeyword(const QString &name);
     private:
-        QString m_name;
         bool m_feed;
     };