From a38dea92898064a1fd6d2d97b0bb7647cd929ecf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Strahinja=20Markovi=C4=87?= Date: Sun, 2 Aug 2009 00:34:14 +0200 Subject: [PATCH] Initial upload --- .hgignore | 63 + CMakeLists.txt | 12 + COPYING.txt | 674 +++ src/Sigil/About.cpp | 51 + src/Sigil/About.h | 44 + src/Sigil/AddMetadata.cpp | 64 + src/Sigil/AddMetadata.h | 66 + src/Sigil/Book.cpp | 42 + src/Sigil/Book.h | 63 + src/Sigil/BookNormalization.cpp | 82 + src/Sigil/BookNormalization.h | 48 + src/Sigil/CleanSource.cpp | 455 ++ src/Sigil/CleanSource.h | 97 + src/Sigil/ExportEPUB.cpp | 408 ++ src/Sigil/ExportEPUB.h | 108 + src/Sigil/ExportSGF.cpp | 58 + src/Sigil/ExportSGF.h | 50 + src/Sigil/Exporter.h | 37 + src/Sigil/ExporterFactory.cpp | 74 + src/Sigil/ExporterFactory.h | 51 + src/Sigil/FolderKeeper.cpp | 369 ++ src/Sigil/FolderKeeper.h | 134 + src/Sigil/Form_Files/About.ui | 275 + src/Sigil/Form_Files/AddMetadata.ui | 89 + src/Sigil/Form_Files/MetaEditor.ui | 269 + src/Sigil/Form_Files/TOCEditor.ui | 102 + src/Sigil/Form_Files/main.ui | 651 +++ src/Sigil/Headings.cpp | 316 ++ src/Sigil/Headings.h | 119 + src/Sigil/ImportEPUB.cpp | 417 ++ src/Sigil/ImportEPUB.h | 118 + src/Sigil/ImportHTML.cpp | 233 + src/Sigil/ImportHTML.h | 65 + src/Sigil/ImportSGF.cpp | 59 + src/Sigil/ImportSGF.h | 44 + src/Sigil/ImportTXT.cpp | 124 + src/Sigil/ImportTXT.h | 70 + src/Sigil/Importer.h | 39 + src/Sigil/ImporterFactory.cpp | 87 + src/Sigil/ImporterFactory.h | 45 + src/Sigil/MainWindow.cpp | 1255 +++++ src/Sigil/MainWindow.h | 294 ++ src/Sigil/MetaEditor.cpp | 391 ++ src/Sigil/MetaEditor.h | 144 + src/Sigil/Metadata.cpp | 209 + src/Sigil/Metadata.h | 95 + src/Sigil/NCXWriter.cpp | 282 ++ src/Sigil/NCXWriter.h | 88 + src/Sigil/OPFWriter.cpp | 308 ++ src/Sigil/OPFWriter.h | 90 + src/Sigil/Resource_Files/About/About.qrc | 5 + src/Sigil/Resource_Files/About/Sigil_logo.png | Bin 0 -> 18007 bytes src/Sigil/Resource_Files/icon/Sigil.icns | Bin 0 -> 220719 bytes src/Sigil/Resource_Files/icon/app.ico | Bin 0 -> 334913 bytes src/Sigil/Resource_Files/icon/icon.rc | 1 + .../Resource_Files/main/document-new.png | Bin 0 -> 692 bytes .../Resource_Files/main/document-open.png | Bin 0 -> 1001 bytes .../Resource_Files/main/document-save-as.png | Bin 0 -> 1097 bytes .../Resource_Files/main/document-save.png | Bin 0 -> 1150 bytes src/Sigil/Resource_Files/main/edit-clear.png | Bin 0 -> 1237 bytes src/Sigil/Resource_Files/main/edit-copy.png | Bin 0 -> 725 bytes src/Sigil/Resource_Files/main/edit-cut.png | Bin 0 -> 1177 bytes src/Sigil/Resource_Files/main/edit-delete.png | Bin 0 -> 1211 bytes .../Resource_Files/main/edit-find-replace.png | Bin 0 -> 1088 bytes src/Sigil/Resource_Files/main/edit-find.png | Bin 0 -> 1090 bytes src/Sigil/Resource_Files/main/edit-paste.png | Bin 0 -> 773 bytes src/Sigil/Resource_Files/main/edit-redo.png | Bin 0 -> 810 bytes .../Resource_Files/main/edit-select-all.png | Bin 0 -> 645 bytes src/Sigil/Resource_Files/main/edit-undo.png | Bin 0 -> 1011 bytes .../main/format-indent-less.png | Bin 0 -> 683 bytes .../main/format-indent-more.png | Bin 0 -> 698 bytes .../main/format-justify-center.png | Bin 0 -> 506 bytes .../main/format-justify-fill.png | Bin 0 -> 495 bytes .../main/format-justify-left.png | Bin 0 -> 494 bytes .../main/format-justify-right.png | Bin 0 -> 506 bytes .../Resource_Files/main/format-text-bold.png | Bin 0 -> 939 bytes .../main/format-text-italic.png | Bin 0 -> 784 bytes .../main/format-text-strikethrough.png | Bin 0 -> 797 bytes .../main/format-text-underline.png | Bin 0 -> 869 bytes .../Resource_Files/main/help-browser.png | Bin 0 -> 1359 bytes .../main/insert-bullet-list.png | Bin 0 -> 640 bytes .../main/insert-chapter-break.png | Bin 0 -> 1194 bytes src/Sigil/Resource_Files/main/insert-font.png | Bin 0 -> 3564 bytes .../Resource_Files/main/insert-image.png | Bin 0 -> 900 bytes .../main/insert-numbered-list.png | Bin 0 -> 681 bytes src/Sigil/Resource_Files/main/main.qrc | 32 + .../Resource_Files/main/process-stop.png | Bin 0 -> 1272 bytes src/Sigil/Resource_Files/main/view-book.png | Bin 0 -> 1155 bytes src/Sigil/Resource_Files/main/view-code.png | Bin 0 -> 964 bytes .../Resource_Files/main/view-fullscreen.png | Bin 0 -> 834 bytes .../Resource_Files/main/view-refresh.png | Bin 0 -> 1364 bytes src/Sigil/Resource_Files/main/view-split.png | Bin 0 -> 1221 bytes src/Sigil/Sigil.pro | 103 + src/Sigil/SigilMarkup.cpp | 58 + src/Sigil/SigilMarkup.h | 43 + src/Sigil/TOCEditor.cpp | 320 ++ src/Sigil/TOCEditor.h | 100 + src/Sigil/Utility.cpp | 165 + src/Sigil/Utility.h | 60 + src/Sigil/XHTMLHighlighter.cpp | 430 ++ src/Sigil/XHTMLHighlighter.h | 100 + src/Sigil/XMLWriter.cpp | 49 + src/Sigil/XMLWriter.h | 61 + src/Sigil/constants.h | 32 + src/Sigil/debug/data/basicmeta.csv | 15 + src/Sigil/debug/data/languages.csv | 184 + src/Sigil/debug/data/relator.csv | 212 + src/Sigil/mac_postbuild.sh | 8 + src/Sigil/main.cpp | 43 + src/Sigil/release/data/basicmeta.csv | 15 + src/Sigil/release/data/languages.csv | 184 + src/Sigil/release/data/relator.csv | 212 + src/Sigil/stdafx.cpp | 22 + src/Sigil/stdafx.h | 24 + src/ZipArchive/Aes.cpp | 18 + src/ZipArchive/Aes.h | 14 + src/ZipArchive/Appnote.txt | 3217 ++++++++++++ src/ZipArchive/BaseLibCompressor.cpp | 44 + src/ZipArchive/BaseLibCompressor.h | 196 + src/ZipArchive/BitFlag.h | 211 + src/ZipArchive/BytesWriter.h | 180 + src/ZipArchive/Bzip2Compressor.cpp | 16 + src/ZipArchive/Bzip2Compressor.h | 14 + src/ZipArchive/DeflateCompressor.cpp | 248 + src/ZipArchive/DeflateCompressor.h | 148 + src/ZipArchive/DirEnumerator.cpp | 186 + src/ZipArchive/DirEnumerator.h | 198 + src/ZipArchive/FileFilter.cpp | 61 + src/ZipArchive/FileFilter.h | 657 +++ src/ZipArchive/FileInfo.h | 69 + src/ZipArchive/Hmac.cpp | 16 + src/ZipArchive/Hmac.h | 14 + src/ZipArchive/License.txt | 284 ++ src/ZipArchive/Makefile | 188 + src/ZipArchive/RandomPool.cpp | 16 + src/ZipArchive/RandomPool.h | 14 + src/ZipArchive/Sha1.cpp | 16 + src/ZipArchive/Sha1.h | 14 + src/ZipArchive/Wildcard.cpp | 401 ++ src/ZipArchive/Wildcard.h | 195 + src/ZipArchive/ZipAbstractFile.h | 74 + src/ZipArchive/ZipAesCryptograph.cpp | 16 + src/ZipArchive/ZipAesCryptograph.h | 14 + src/ZipArchive/ZipArchive.cpp | 3311 +++++++++++++ src/ZipArchive/ZipArchive.h | 3446 +++++++++++++ src/ZipArchive/ZipArchive.rc | 103 + src/ZipArchive/ZipAutoBuffer.cpp | 95 + src/ZipArchive/ZipAutoBuffer.h | 67 + src/ZipArchive/ZipBaseException.h | 30 + src/ZipArchive/ZipCallback.h | 731 +++ src/ZipArchive/ZipCallbackProvider.h | 84 + src/ZipArchive/ZipCentralDir.cpp | 1053 ++++ src/ZipArchive/ZipCentralDir.h | 844 ++++ src/ZipArchive/ZipCollections.h | 41 + src/ZipArchive/ZipCollections_mfc.h | 91 + src/ZipArchive/ZipCollections_stl.h | 227 + src/ZipArchive/ZipCompatibility.cpp | 265 + src/ZipArchive/ZipCompatibility.h | 197 + src/ZipArchive/ZipCompressor.cpp | 104 + src/ZipArchive/ZipCompressor.h | 482 ++ src/ZipArchive/ZipCrc32Cryptograph.cpp | 81 + src/ZipArchive/ZipCrc32Cryptograph.h | 120 + src/ZipArchive/ZipCryptograph.cpp | 57 + src/ZipArchive/ZipCryptograph.h | 231 + src/ZipArchive/ZipException.cpp | 291 ++ src/ZipArchive/ZipException.h | 230 + src/ZipArchive/ZipExport.h | 35 + src/ZipArchive/ZipExtraData.cpp | 57 + src/ZipArchive/ZipExtraData.h | 169 + src/ZipArchive/ZipExtraField.cpp | 116 + src/ZipArchive/ZipExtraField.h | 330 ++ src/ZipArchive/ZipFile.h | 40 + src/ZipArchive/ZipFileHeader.cpp | 1114 +++++ src/ZipArchive/ZipFileHeader.h | 905 ++++ src/ZipArchive/ZipFileMapping.h | 37 + src/ZipArchive/ZipFileMapping_lnx.h | 62 + src/ZipArchive/ZipFileMapping_win.h | 68 + src/ZipArchive/ZipFile_mfc.cpp | 37 + src/ZipArchive/ZipFile_mfc.h | 87 + src/ZipArchive/ZipFile_stl.cpp | 214 + src/ZipArchive/ZipFile_stl.h | 93 + src/ZipArchive/ZipFile_win.cpp | 276 ++ src/ZipArchive/ZipFile_win.h | 66 + src/ZipArchive/ZipMemFile.cpp | 110 + src/ZipArchive/ZipMemFile.h | 130 + src/ZipArchive/ZipMutex.h | 38 + src/ZipArchive/ZipMutex_lnx.h | 84 + src/ZipArchive/ZipMutex_win.h | 81 + src/ZipArchive/ZipPathComponent.h | 300 ++ src/ZipArchive/ZipPathComponent_lnx.cpp | 93 + src/ZipArchive/ZipPathComponent_win.cpp | 88 + src/ZipArchive/ZipPlatform.h | 255 + src/ZipArchive/ZipPlatformComm.cpp | 83 + src/ZipArchive/ZipPlatform_lnx.cpp | 277 ++ src/ZipArchive/ZipPlatform_win.cpp | 468 ++ src/ZipArchive/ZipSplitNamesHandler.h | 206 + src/ZipArchive/ZipStorage.cpp | 783 +++ src/ZipArchive/ZipStorage.h | 754 +++ src/ZipArchive/ZipString.cpp | 37 + src/ZipArchive/ZipString.h | 42 + src/ZipArchive/ZipStringStoreSettings.h | 196 + src/ZipArchive/ZipString_mfc.h | 34 + src/ZipArchive/ZipString_stl.h | 330 ++ src/ZipArchive/_features.h | 174 + src/ZipArchive/_platform.h | 66 + src/ZipArchive/_readme.txt | 2 + src/ZipArchive/bzip2/blocksort.c | 1097 ++++ src/ZipArchive/bzip2/bzcompress.c | 675 +++ src/ZipArchive/bzip2/bzlib.c | 1574 ++++++ src/ZipArchive/bzip2/bzlib.h | 379 ++ src/ZipArchive/bzip2/bzlib_private.h | 513 ++ src/ZipArchive/bzip2/crctable.c | 107 + src/ZipArchive/bzip2/decompress.c | 628 +++ src/ZipArchive/bzip2/huffman.c | 208 + src/ZipArchive/bzip2/randtable.c | 86 + src/ZipArchive/resource.h | 15 + src/ZipArchive/std_mfc.h | 56 + src/ZipArchive/std_stl.h | 141 + src/ZipArchive/stdafx.h | 104 + src/ZipArchive/zlib/adler32.c | 149 + src/ZipArchive/zlib/compress.c | 79 + src/ZipArchive/zlib/crc32.c | 423 ++ src/ZipArchive/zlib/crc32.h | 441 ++ src/ZipArchive/zlib/deflate.c | 1736 +++++++ src/ZipArchive/zlib/deflate.h | 331 ++ src/ZipArchive/zlib/infback.c | 623 +++ src/ZipArchive/zlib/inffast.c | 318 ++ src/ZipArchive/zlib/inffast.h | 11 + src/ZipArchive/zlib/inffixed.h | 94 + src/ZipArchive/zlib/inflate.c | 1368 +++++ src/ZipArchive/zlib/inflate.h | 115 + src/ZipArchive/zlib/inftrees.c | 329 ++ src/ZipArchive/zlib/inftrees.h | 55 + src/ZipArchive/zlib/trees.c | 1219 +++++ src/ZipArchive/zlib/trees.h | 128 + src/ZipArchive/zlib/uncompr.c | 61 + src/ZipArchive/zlib/zconf.h | 385 ++ src/ZipArchive/zlib/zlib.h | 1363 +++++ src/ZipArchive/zlib/zutil.c | 318 ++ src/ZipArchive/zlib/zutil.h | 273 + src/tidyLib/CMakeLists.txt | 59 + src/tidyLib/Makefile | 839 ++++ src/tidyLib/access.c | 3310 +++++++++++++ src/tidyLib/access.h | 279 ++ src/tidyLib/alloc.c | 107 + src/tidyLib/attrask.c | 209 + src/tidyLib/attrdict.c | 2398 +++++++++ src/tidyLib/attrdict.h | 122 + src/tidyLib/attrget.c | 213 + src/tidyLib/attrs.c | 1911 +++++++ src/tidyLib/attrs.h | 374 ++ src/tidyLib/buffio.c | 232 + src/tidyLib/buffio.h | 118 + src/tidyLib/charsets.c | 1032 ++++ src/tidyLib/charsets.h | 14 + src/tidyLib/clean.c | 2674 ++++++++++ src/tidyLib/clean.h | 87 + src/tidyLib/config.c | 1750 +++++++ src/tidyLib/config.h | 153 + src/tidyLib/entities.c | 419 ++ src/tidyLib/entities.h | 24 + src/tidyLib/fileio.c | 106 + src/tidyLib/fileio.h | 46 + src/tidyLib/forward.h | 69 + src/tidyLib/iconvtc.c | 105 + src/tidyLib/iconvtc.h | 15 + src/tidyLib/istack.c | 373 ++ src/tidyLib/lexer.c | 3825 ++++++++++++++ src/tidyLib/lexer.h | 617 +++ src/tidyLib/localize.c | 1882 +++++++ src/tidyLib/mappedio.c | 329 ++ src/tidyLib/mappedio.h | 16 + src/tidyLib/message.h | 207 + src/tidyLib/parser.c | 4405 +++++++++++++++++ src/tidyLib/parser.h | 76 + src/tidyLib/platform.h | 636 +++ src/tidyLib/pprint.c | 2276 +++++++++ src/tidyLib/pprint.h | 93 + src/tidyLib/streamio.c | 1407 ++++++ src/tidyLib/streamio.h | 222 + src/tidyLib/tagask.c | 286 ++ src/tidyLib/tags.c | 955 ++++ src/tidyLib/tags.h | 235 + src/tidyLib/tidy-int.h | 129 + src/tidyLib/tidy.h | 1097 ++++ src/tidyLib/tidyenum.h | 623 +++ src/tidyLib/tidylib.c | 1754 +++++++ src/tidyLib/tmbstr.c | 306 ++ src/tidyLib/tmbstr.h | 92 + src/tidyLib/utf8.c | 539 ++ src/tidyLib/utf8.h | 52 + src/tidyLib/version.h | 14 + src/tidyLib/win32tc.c | 795 +++ src/tidyLib/win32tc.h | 19 + 294 files changed, 94390 insertions(+) create mode 100644 .hgignore create mode 100644 CMakeLists.txt create mode 100644 COPYING.txt create mode 100644 src/Sigil/About.cpp create mode 100644 src/Sigil/About.h create mode 100644 src/Sigil/AddMetadata.cpp create mode 100644 src/Sigil/AddMetadata.h create mode 100644 src/Sigil/Book.cpp create mode 100644 src/Sigil/Book.h create mode 100644 src/Sigil/BookNormalization.cpp create mode 100644 src/Sigil/BookNormalization.h create mode 100644 src/Sigil/CleanSource.cpp create mode 100644 src/Sigil/CleanSource.h create mode 100644 src/Sigil/ExportEPUB.cpp create mode 100644 src/Sigil/ExportEPUB.h create mode 100644 src/Sigil/ExportSGF.cpp create mode 100644 src/Sigil/ExportSGF.h create mode 100644 src/Sigil/Exporter.h create mode 100644 src/Sigil/ExporterFactory.cpp create mode 100644 src/Sigil/ExporterFactory.h create mode 100644 src/Sigil/FolderKeeper.cpp create mode 100644 src/Sigil/FolderKeeper.h create mode 100644 src/Sigil/Form_Files/About.ui create mode 100644 src/Sigil/Form_Files/AddMetadata.ui create mode 100644 src/Sigil/Form_Files/MetaEditor.ui create mode 100644 src/Sigil/Form_Files/TOCEditor.ui create mode 100644 src/Sigil/Form_Files/main.ui create mode 100644 src/Sigil/Headings.cpp create mode 100644 src/Sigil/Headings.h create mode 100644 src/Sigil/ImportEPUB.cpp create mode 100644 src/Sigil/ImportEPUB.h create mode 100644 src/Sigil/ImportHTML.cpp create mode 100644 src/Sigil/ImportHTML.h create mode 100644 src/Sigil/ImportSGF.cpp create mode 100644 src/Sigil/ImportSGF.h create mode 100644 src/Sigil/ImportTXT.cpp create mode 100644 src/Sigil/ImportTXT.h create mode 100644 src/Sigil/Importer.h create mode 100644 src/Sigil/ImporterFactory.cpp create mode 100644 src/Sigil/ImporterFactory.h create mode 100644 src/Sigil/MainWindow.cpp create mode 100644 src/Sigil/MainWindow.h create mode 100644 src/Sigil/MetaEditor.cpp create mode 100644 src/Sigil/MetaEditor.h create mode 100644 src/Sigil/Metadata.cpp create mode 100644 src/Sigil/Metadata.h create mode 100644 src/Sigil/NCXWriter.cpp create mode 100644 src/Sigil/NCXWriter.h create mode 100644 src/Sigil/OPFWriter.cpp create mode 100644 src/Sigil/OPFWriter.h create mode 100644 src/Sigil/Resource_Files/About/About.qrc create mode 100644 src/Sigil/Resource_Files/About/Sigil_logo.png create mode 100644 src/Sigil/Resource_Files/icon/Sigil.icns create mode 100644 src/Sigil/Resource_Files/icon/app.ico create mode 100644 src/Sigil/Resource_Files/icon/icon.rc create mode 100644 src/Sigil/Resource_Files/main/document-new.png create mode 100644 src/Sigil/Resource_Files/main/document-open.png create mode 100644 src/Sigil/Resource_Files/main/document-save-as.png create mode 100644 src/Sigil/Resource_Files/main/document-save.png create mode 100644 src/Sigil/Resource_Files/main/edit-clear.png create mode 100644 src/Sigil/Resource_Files/main/edit-copy.png create mode 100644 src/Sigil/Resource_Files/main/edit-cut.png create mode 100644 src/Sigil/Resource_Files/main/edit-delete.png create mode 100644 src/Sigil/Resource_Files/main/edit-find-replace.png create mode 100644 src/Sigil/Resource_Files/main/edit-find.png create mode 100644 src/Sigil/Resource_Files/main/edit-paste.png create mode 100644 src/Sigil/Resource_Files/main/edit-redo.png create mode 100644 src/Sigil/Resource_Files/main/edit-select-all.png create mode 100644 src/Sigil/Resource_Files/main/edit-undo.png create mode 100644 src/Sigil/Resource_Files/main/format-indent-less.png create mode 100644 src/Sigil/Resource_Files/main/format-indent-more.png create mode 100644 src/Sigil/Resource_Files/main/format-justify-center.png create mode 100644 src/Sigil/Resource_Files/main/format-justify-fill.png create mode 100644 src/Sigil/Resource_Files/main/format-justify-left.png create mode 100644 src/Sigil/Resource_Files/main/format-justify-right.png create mode 100644 src/Sigil/Resource_Files/main/format-text-bold.png create mode 100644 src/Sigil/Resource_Files/main/format-text-italic.png create mode 100644 src/Sigil/Resource_Files/main/format-text-strikethrough.png create mode 100644 src/Sigil/Resource_Files/main/format-text-underline.png create mode 100644 src/Sigil/Resource_Files/main/help-browser.png create mode 100644 src/Sigil/Resource_Files/main/insert-bullet-list.png create mode 100644 src/Sigil/Resource_Files/main/insert-chapter-break.png create mode 100644 src/Sigil/Resource_Files/main/insert-font.png create mode 100644 src/Sigil/Resource_Files/main/insert-image.png create mode 100644 src/Sigil/Resource_Files/main/insert-numbered-list.png create mode 100644 src/Sigil/Resource_Files/main/main.qrc create mode 100644 src/Sigil/Resource_Files/main/process-stop.png create mode 100644 src/Sigil/Resource_Files/main/view-book.png create mode 100644 src/Sigil/Resource_Files/main/view-code.png create mode 100644 src/Sigil/Resource_Files/main/view-fullscreen.png create mode 100644 src/Sigil/Resource_Files/main/view-refresh.png create mode 100644 src/Sigil/Resource_Files/main/view-split.png create mode 100644 src/Sigil/Sigil.pro create mode 100644 src/Sigil/SigilMarkup.cpp create mode 100644 src/Sigil/SigilMarkup.h create mode 100644 src/Sigil/TOCEditor.cpp create mode 100644 src/Sigil/TOCEditor.h create mode 100644 src/Sigil/Utility.cpp create mode 100644 src/Sigil/Utility.h create mode 100644 src/Sigil/XHTMLHighlighter.cpp create mode 100644 src/Sigil/XHTMLHighlighter.h create mode 100644 src/Sigil/XMLWriter.cpp create mode 100644 src/Sigil/XMLWriter.h create mode 100644 src/Sigil/constants.h create mode 100644 src/Sigil/debug/data/basicmeta.csv create mode 100644 src/Sigil/debug/data/languages.csv create mode 100644 src/Sigil/debug/data/relator.csv create mode 100644 src/Sigil/mac_postbuild.sh create mode 100644 src/Sigil/main.cpp create mode 100644 src/Sigil/release/data/basicmeta.csv create mode 100644 src/Sigil/release/data/languages.csv create mode 100644 src/Sigil/release/data/relator.csv create mode 100644 src/Sigil/stdafx.cpp create mode 100644 src/Sigil/stdafx.h create mode 100644 src/ZipArchive/Aes.cpp create mode 100644 src/ZipArchive/Aes.h create mode 100644 src/ZipArchive/Appnote.txt create mode 100644 src/ZipArchive/BaseLibCompressor.cpp create mode 100644 src/ZipArchive/BaseLibCompressor.h create mode 100644 src/ZipArchive/BitFlag.h create mode 100644 src/ZipArchive/BytesWriter.h create mode 100644 src/ZipArchive/Bzip2Compressor.cpp create mode 100644 src/ZipArchive/Bzip2Compressor.h create mode 100644 src/ZipArchive/DeflateCompressor.cpp create mode 100644 src/ZipArchive/DeflateCompressor.h create mode 100644 src/ZipArchive/DirEnumerator.cpp create mode 100644 src/ZipArchive/DirEnumerator.h create mode 100644 src/ZipArchive/FileFilter.cpp create mode 100644 src/ZipArchive/FileFilter.h create mode 100644 src/ZipArchive/FileInfo.h create mode 100644 src/ZipArchive/Hmac.cpp create mode 100644 src/ZipArchive/Hmac.h create mode 100644 src/ZipArchive/License.txt create mode 100644 src/ZipArchive/Makefile create mode 100644 src/ZipArchive/RandomPool.cpp create mode 100644 src/ZipArchive/RandomPool.h create mode 100644 src/ZipArchive/Sha1.cpp create mode 100644 src/ZipArchive/Sha1.h create mode 100644 src/ZipArchive/Wildcard.cpp create mode 100644 src/ZipArchive/Wildcard.h create mode 100644 src/ZipArchive/ZipAbstractFile.h create mode 100644 src/ZipArchive/ZipAesCryptograph.cpp create mode 100644 src/ZipArchive/ZipAesCryptograph.h create mode 100644 src/ZipArchive/ZipArchive.cpp create mode 100644 src/ZipArchive/ZipArchive.h create mode 100644 src/ZipArchive/ZipArchive.rc create mode 100644 src/ZipArchive/ZipAutoBuffer.cpp create mode 100644 src/ZipArchive/ZipAutoBuffer.h create mode 100644 src/ZipArchive/ZipBaseException.h create mode 100644 src/ZipArchive/ZipCallback.h create mode 100644 src/ZipArchive/ZipCallbackProvider.h create mode 100644 src/ZipArchive/ZipCentralDir.cpp create mode 100644 src/ZipArchive/ZipCentralDir.h create mode 100644 src/ZipArchive/ZipCollections.h create mode 100644 src/ZipArchive/ZipCollections_mfc.h create mode 100644 src/ZipArchive/ZipCollections_stl.h create mode 100644 src/ZipArchive/ZipCompatibility.cpp create mode 100644 src/ZipArchive/ZipCompatibility.h create mode 100644 src/ZipArchive/ZipCompressor.cpp create mode 100644 src/ZipArchive/ZipCompressor.h create mode 100644 src/ZipArchive/ZipCrc32Cryptograph.cpp create mode 100644 src/ZipArchive/ZipCrc32Cryptograph.h create mode 100644 src/ZipArchive/ZipCryptograph.cpp create mode 100644 src/ZipArchive/ZipCryptograph.h create mode 100644 src/ZipArchive/ZipException.cpp create mode 100644 src/ZipArchive/ZipException.h create mode 100644 src/ZipArchive/ZipExport.h create mode 100644 src/ZipArchive/ZipExtraData.cpp create mode 100644 src/ZipArchive/ZipExtraData.h create mode 100644 src/ZipArchive/ZipExtraField.cpp create mode 100644 src/ZipArchive/ZipExtraField.h create mode 100644 src/ZipArchive/ZipFile.h create mode 100644 src/ZipArchive/ZipFileHeader.cpp create mode 100644 src/ZipArchive/ZipFileHeader.h create mode 100644 src/ZipArchive/ZipFileMapping.h create mode 100644 src/ZipArchive/ZipFileMapping_lnx.h create mode 100644 src/ZipArchive/ZipFileMapping_win.h create mode 100644 src/ZipArchive/ZipFile_mfc.cpp create mode 100644 src/ZipArchive/ZipFile_mfc.h create mode 100644 src/ZipArchive/ZipFile_stl.cpp create mode 100644 src/ZipArchive/ZipFile_stl.h create mode 100644 src/ZipArchive/ZipFile_win.cpp create mode 100644 src/ZipArchive/ZipFile_win.h create mode 100644 src/ZipArchive/ZipMemFile.cpp create mode 100644 src/ZipArchive/ZipMemFile.h create mode 100644 src/ZipArchive/ZipMutex.h create mode 100644 src/ZipArchive/ZipMutex_lnx.h create mode 100644 src/ZipArchive/ZipMutex_win.h create mode 100644 src/ZipArchive/ZipPathComponent.h create mode 100644 src/ZipArchive/ZipPathComponent_lnx.cpp create mode 100644 src/ZipArchive/ZipPathComponent_win.cpp create mode 100644 src/ZipArchive/ZipPlatform.h create mode 100644 src/ZipArchive/ZipPlatformComm.cpp create mode 100644 src/ZipArchive/ZipPlatform_lnx.cpp create mode 100644 src/ZipArchive/ZipPlatform_win.cpp create mode 100644 src/ZipArchive/ZipSplitNamesHandler.h create mode 100644 src/ZipArchive/ZipStorage.cpp create mode 100644 src/ZipArchive/ZipStorage.h create mode 100644 src/ZipArchive/ZipString.cpp create mode 100644 src/ZipArchive/ZipString.h create mode 100644 src/ZipArchive/ZipStringStoreSettings.h create mode 100644 src/ZipArchive/ZipString_mfc.h create mode 100644 src/ZipArchive/ZipString_stl.h create mode 100644 src/ZipArchive/_features.h create mode 100644 src/ZipArchive/_platform.h create mode 100644 src/ZipArchive/_readme.txt create mode 100644 src/ZipArchive/bzip2/blocksort.c create mode 100644 src/ZipArchive/bzip2/bzcompress.c create mode 100644 src/ZipArchive/bzip2/bzlib.c create mode 100644 src/ZipArchive/bzip2/bzlib.h create mode 100644 src/ZipArchive/bzip2/bzlib_private.h create mode 100644 src/ZipArchive/bzip2/crctable.c create mode 100644 src/ZipArchive/bzip2/decompress.c create mode 100644 src/ZipArchive/bzip2/huffman.c create mode 100644 src/ZipArchive/bzip2/randtable.c create mode 100644 src/ZipArchive/resource.h create mode 100644 src/ZipArchive/std_mfc.h create mode 100644 src/ZipArchive/std_stl.h create mode 100644 src/ZipArchive/stdafx.h create mode 100644 src/ZipArchive/zlib/adler32.c create mode 100644 src/ZipArchive/zlib/compress.c create mode 100644 src/ZipArchive/zlib/crc32.c create mode 100644 src/ZipArchive/zlib/crc32.h create mode 100644 src/ZipArchive/zlib/deflate.c create mode 100644 src/ZipArchive/zlib/deflate.h create mode 100644 src/ZipArchive/zlib/infback.c create mode 100644 src/ZipArchive/zlib/inffast.c create mode 100644 src/ZipArchive/zlib/inffast.h create mode 100644 src/ZipArchive/zlib/inffixed.h create mode 100644 src/ZipArchive/zlib/inflate.c create mode 100644 src/ZipArchive/zlib/inflate.h create mode 100644 src/ZipArchive/zlib/inftrees.c create mode 100644 src/ZipArchive/zlib/inftrees.h create mode 100644 src/ZipArchive/zlib/trees.c create mode 100644 src/ZipArchive/zlib/trees.h create mode 100644 src/ZipArchive/zlib/uncompr.c create mode 100644 src/ZipArchive/zlib/zconf.h create mode 100644 src/ZipArchive/zlib/zlib.h create mode 100644 src/ZipArchive/zlib/zutil.c create mode 100644 src/ZipArchive/zlib/zutil.h create mode 100644 src/tidyLib/CMakeLists.txt create mode 100644 src/tidyLib/Makefile create mode 100644 src/tidyLib/access.c create mode 100644 src/tidyLib/access.h create mode 100644 src/tidyLib/alloc.c create mode 100644 src/tidyLib/attrask.c create mode 100644 src/tidyLib/attrdict.c create mode 100644 src/tidyLib/attrdict.h create mode 100644 src/tidyLib/attrget.c create mode 100644 src/tidyLib/attrs.c create mode 100644 src/tidyLib/attrs.h create mode 100644 src/tidyLib/buffio.c create mode 100644 src/tidyLib/buffio.h create mode 100644 src/tidyLib/charsets.c create mode 100644 src/tidyLib/charsets.h create mode 100644 src/tidyLib/clean.c create mode 100644 src/tidyLib/clean.h create mode 100644 src/tidyLib/config.c create mode 100644 src/tidyLib/config.h create mode 100644 src/tidyLib/entities.c create mode 100644 src/tidyLib/entities.h create mode 100644 src/tidyLib/fileio.c create mode 100644 src/tidyLib/fileio.h create mode 100644 src/tidyLib/forward.h create mode 100644 src/tidyLib/iconvtc.c create mode 100644 src/tidyLib/iconvtc.h create mode 100644 src/tidyLib/istack.c create mode 100644 src/tidyLib/lexer.c create mode 100644 src/tidyLib/lexer.h create mode 100644 src/tidyLib/localize.c create mode 100644 src/tidyLib/mappedio.c create mode 100644 src/tidyLib/mappedio.h create mode 100644 src/tidyLib/message.h create mode 100644 src/tidyLib/parser.c create mode 100644 src/tidyLib/parser.h create mode 100644 src/tidyLib/platform.h create mode 100644 src/tidyLib/pprint.c create mode 100644 src/tidyLib/pprint.h create mode 100644 src/tidyLib/streamio.c create mode 100644 src/tidyLib/streamio.h create mode 100644 src/tidyLib/tagask.c create mode 100644 src/tidyLib/tags.c create mode 100644 src/tidyLib/tags.h create mode 100644 src/tidyLib/tidy-int.h create mode 100644 src/tidyLib/tidy.h create mode 100644 src/tidyLib/tidyenum.h create mode 100644 src/tidyLib/tidylib.c create mode 100644 src/tidyLib/tmbstr.c create mode 100644 src/tidyLib/tmbstr.h create mode 100644 src/tidyLib/utf8.c create mode 100644 src/tidyLib/utf8.h create mode 100644 src/tidyLib/version.h create mode 100644 src/tidyLib/win32tc.c create mode 100644 src/tidyLib/win32tc.h diff --git a/.hgignore b/.hgignore new file mode 100644 index 0000000000..aa60d1404b --- /dev/null +++ b/.hgignore @@ -0,0 +1,63 @@ +syntax: glob +# Backup files left behind by the Emacs editor. +*~ + +# Lock files used by the Emacs editor. +.\#* + +# Temporary files used by the vim editor. +.*.swp + +# A hidden file created by the Mac OS X Finder. +.DS_Store + +# Image thumbnail database created by windows +Thumbs.db + +# Various files created by Visual Studio +*.sln +*.suo +*.vcproj +*.user +#*.rc +*.ncb +*.pch +*.dep +*.idb +*.exp +*.res +*.manifest +*.ilk +*.pdb +*.def +BuildLog.htm + +# Various files and folders created by CMake +CMakeFiles +CMakeScripts +CMakeCache.txt +*.cmake +*.dir +ALL_BUILD* + +# Various Qt files +ui_* +moc_* +qrc_* + +# Misc files +*.svn +*.a +*.o +*.obj +*.lib +*.exe +*.dll +*.a +*.app +*.plist +*.xcodeproj +*.pbxbtree +*.pbxindex +*.build +*.smp diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..18425570f6 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,12 @@ + +cmake_minimum_required( VERSION 2.6 ) + +project( Sigil ) + +set( CMAKE_DEBUG_POSTFIX "d" ) +set( EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin ) +set( LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib ) + +add_subdirectory( src/tidyLib ) + +#TODO: Switch sigil and ziparchive to cmake and then add them here. \ No newline at end of file diff --git a/COPYING.txt b/COPYING.txt new file mode 100644 index 0000000000..818433ecc0 --- /dev/null +++ b/COPYING.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/src/Sigil/About.cpp b/src/Sigil/About.cpp new file mode 100644 index 0000000000..4ebc1ed09e --- /dev/null +++ b/src/Sigil/About.cpp @@ -0,0 +1,51 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see . +** +*************************************************************************/ + +#include "stdafx.h" +#include "About.h" + +static const QDateTime BUILD_TIME = QDateTime::currentDateTime(); + + +// Constructor +About::About( QWidget *parent ) + : QDialog( parent ) +{ + ui.setupUi( this ); + + ui.lbBuildTimeDisplay->setText( BUILD_TIME.toString( "yyyy.MM.dd HH:mm:ss" ) ); + ui.lbLoadedQtDisplay->setText( QString( qVersion() ) ); + + // The individual numbers that make up the build version string + // always take up 3 spaces; we want to display them + // in exactly the number of spaces needed + // (regex used in case we change the number of digits) + QRegExp version_number( "(\\d+)\\.(\\d+)\\.(\\d+)" ); + + QString( SIGIL_VERSION ).indexOf( version_number ); + + QString version_text = QString( "%1.%2.%3" ) + .arg( version_number.cap( 1 ).toInt() ) + .arg( version_number.cap( 2 ).toInt() ) + .arg( version_number.cap( 3 ).toInt() ); + + ui.lbVersionDisplay->setText( version_text ); +} diff --git a/src/Sigil/About.h b/src/Sigil/About.h new file mode 100644 index 0000000000..f2e571c225 --- /dev/null +++ b/src/Sigil/About.h @@ -0,0 +1,44 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see . +** +*************************************************************************/ + +#pragma once +#ifndef ABOUT_H +#define ABOUT_H + +#include +#include "ui_About.h" + +class About : public QDialog +{ + Q_OBJECT + +public: + + // Constructor + About( QWidget *parent = 0 ); + +private: + + // Holds all the widgets Qt Designer created for us + Ui::About ui; +}; + +#endif // ABOUT_H diff --git a/src/Sigil/AddMetadata.cpp b/src/Sigil/AddMetadata.cpp new file mode 100644 index 0000000000..11f24e9dbf --- /dev/null +++ b/src/Sigil/AddMetadata.cpp @@ -0,0 +1,64 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see . +** +*************************************************************************/ + +#include "stdafx.h" +#include "AddMetadata.h" +#include "Metadata.h" + + +// Constructor +AddMetadata::AddMetadata( const QMap< QString, Metadata::MetaInfo > &metadata, QWidget *parent ) + : QDialog( parent ), m_Metadata( metadata ) +{ + ui.setupUi( this ); + + connect( ui.lwProperties, SIGNAL( currentItemChanged( QListWidgetItem*, QListWidgetItem* ) ), + this, SLOT( UpdateDescription( QListWidgetItem* ) ) ); + + connect( this, SIGNAL( accepted() ), this, SLOT( EmitSelection() ) ); + + // Filling the dialog with metadata names + foreach( QString name, m_Metadata.keys() ) + { + ui.lwProperties->addItem( name ); + } +} + + +// Updates the description of the currently selected item +// whenever the user selects a new item +void AddMetadata::UpdateDescription( QListWidgetItem *current ) +{ + QString text = m_Metadata.value( current->text() ).description; + + if ( text.isNull() != true ) + + ui.lbDescription->setText( text ); +} + + +// Emits the name of the metadata that +// should be added to the metadata table; +// should be called on accept signal +void AddMetadata::EmitSelection() +{ + emit MetadataToAdd( ui.lwProperties->currentItem()->text() ); +} \ No newline at end of file diff --git a/src/Sigil/AddMetadata.h b/src/Sigil/AddMetadata.h new file mode 100644 index 0000000000..8196604e55 --- /dev/null +++ b/src/Sigil/AddMetadata.h @@ -0,0 +1,66 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see . +** +*************************************************************************/ + +#pragma once +#ifndef ADDMETADATA_H +#define ADDMETADATA_H + +#include +#include "ui_AddMetadata.h" +#include "Metadata.h" + +class AddMetadata : public QDialog +{ + Q_OBJECT + +public: + + // Constructor + AddMetadata( const QMap< QString, Metadata::MetaInfo > &elements, QWidget *parent = 0 ); + +signals: + + // The name of the metadata the user + // wants inserted into the table + void MetadataToAdd( QString name ); + +private slots: + + // Updates the description of the currently selected item + // whenever the user selects a new item + void UpdateDescription( QListWidgetItem *current ); + + // Emits the name of the metadata that + // should be added to the metadata table; + // should be called on accept signal + void EmitSelection(); + +private: + + // Represents the metadata list that this dialog displays + // For description of the stored types, see Metadata.h + const QMap< QString, Metadata::MetaInfo > &m_Metadata; + + // Holds all the widgets Qt Designer created for us + Ui::AddMetadata ui; +}; + +#endif // ADDMETADATA_H diff --git a/src/Sigil/Book.cpp b/src/Sigil/Book.cpp new file mode 100644 index 0000000000..90edf21e09 --- /dev/null +++ b/src/Sigil/Book.cpp @@ -0,0 +1,42 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see . +** +*************************************************************************/ + +#include "stdafx.h" +#include "Book.h" +#include "Utility.h" + +static const int BOOK_IDENTIFIER_LENGTH = 30; + +// Constructor +Book::Book() + : PublicationIdentifier( Utility::GetRandomString( BOOK_IDENTIFIER_LENGTH ) ) +{ + +} + + +// Returns the base url of the book, +// that is the location to the text folder +// within the main folder +QUrl Book::GetBaseUrl() +{ + return QUrl::fromLocalFile( mainfolder.GetFullPathToTextFolder() + "/" ); +} \ No newline at end of file diff --git a/src/Sigil/Book.h b/src/Sigil/Book.h new file mode 100644 index 0000000000..1dd27735bb --- /dev/null +++ b/src/Sigil/Book.h @@ -0,0 +1,63 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see . +** +*************************************************************************/ + +#pragma once +#ifndef BOOK_H +#define BOOK_H + +#include "FolderKeeper.h" + +#include +#include +#include + +class Book +{ + // These are all public because + // this class is basically a glorified struct +public: + + // Constructor + Book(); + + // Returns the base url of the book, + // that is the location to the text folder + // within the main folder + QUrl GetBaseUrl(); + + // Stores the full XHTML source code of the book + QString source; + + // Stores all the metadata for the book; + // the key is the metadata name, the values + // are the lists of metadata values + QHash< QString, QList< QVariant > > metadata; + + // The 30 character random identifier + // that uniquely represents this book + QString PublicationIdentifier; + + // The FolderKeeper object that represents + // this books presence on the hard drive + FolderKeeper mainfolder; +}; + +#endif // BOOK_H diff --git a/src/Sigil/BookNormalization.cpp b/src/Sigil/BookNormalization.cpp new file mode 100644 index 0000000000..e3d0c92943 --- /dev/null +++ b/src/Sigil/BookNormalization.cpp @@ -0,0 +1,82 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see . +** +*************************************************************************/ + +#include "stdafx.h" +#include +#include "Book.h" +#include "BookNormalization.h" +#include "CleanSource.h" + + +// Performs all the operations necessary +// on the Book before it is exported, +// like adding ID's to all headings etc. +Book BookNormalization::Normalize( const Book &book ) +{ + Book newbook = book; + + newbook.source = GiveIDsToHeadings( newbook.source ); + newbook.source = RemoveXMLCarriageReturns( newbook.source ); + newbook.source = CleanSource::Clean( newbook.source ); + + return newbook; +} + +// Gives ID's to all headings that don't have them +QString BookNormalization::GiveIDsToHeadings( const QString &source ) +{ + QDomDocument document; + + document.setContent( source ); + + int heading_id = 1; + + for ( int level = 1; level < 7; level++ ) + { + QString tag = "h" + QString::number( level ); + + QDomNodeList headings = document.elementsByTagName( tag ); + + for ( int index = 0; index < headings.count(); index++ ) + { + QDomElement element = headings.at( index ).toElement(); + + if ( !element.hasAttribute( "id" ) ) + { + element.setAttribute( "id", "heading_id_" + QString::number( heading_id ) ); + + heading_id++; + } + } + } + + return document.toString(); +} + + +// Removes the XML carriage returns (" " sequences ) +// that .toString() kindly left for us +QString BookNormalization::RemoveXMLCarriageReturns( const QString &source ) +{ + QString newsource = source; + + return newsource.replace( " ", "" ); +} \ No newline at end of file diff --git a/src/Sigil/BookNormalization.h b/src/Sigil/BookNormalization.h new file mode 100644 index 0000000000..1b958f06b6 --- /dev/null +++ b/src/Sigil/BookNormalization.h @@ -0,0 +1,48 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see . +** +*************************************************************************/ + +#pragma once +#ifndef BOOKNORMALIZATION_H +#define BOOKNORMALIZATION_H + +class Book; + +class BookNormalization +{ + +public: + + // Performs all the operations necessary + // on the Book before it is exported, + // like adding ID's to all headings etc. + static Book Normalize( const Book &book ); + +private: + + // Gives ID's to all headings that don't have them + static QString GiveIDsToHeadings( const QString &source ); + + // Removes the XML carriage returns (" " sequences ) + // that .toString() kindly left for us + static QString RemoveXMLCarriageReturns( const QString &source ); +}; + +#endif // BOOKNORMALIZATION_H \ No newline at end of file diff --git a/src/Sigil/CleanSource.cpp b/src/Sigil/CleanSource.cpp new file mode 100644 index 0000000000..04d5016b1a --- /dev/null +++ b/src/Sigil/CleanSource.cpp @@ -0,0 +1,455 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see . +** +*************************************************************************/ + +#include "stdafx.h" +#include "Utility.h" +#include "CleanSource.h" +#include +#include + +static const QString SIGIL_CLASS_NAME = "sgc"; +static const QString SIGIL_CLASS_NAME_REG = SIGIL_CLASS_NAME + "-(\\d+)"; + +// Use with .setMinimal( true ) +static const QString STYLE_TAG_CSS_ONLY = "<\\s*style\\s*type\\s*=\\s*\"text/css\"[^>]*>.*]*>"; + +static const QString CLASS_REMOVE_START = "<[^>]*class\\s*=\\s*\"[^\"]*"; +static const QString CLASS_REMOVE_END = "[^\"]*\"[^>]*>"; + +// Use with .setMinimal( true ) +static const QString CLASS_DEFINITION = "\\{.*\\}"; + +// The value was picked arbitrarily +static const int TAG_SIZE_THRESHOLD = 1000; + + +// Performs general cleaning (and improving) +// of provided book XHTML source code +QString CleanSource::Clean( const QString &source ) +{ + QString newsource = source; + + // We store the number of CSS style tags before + // running Tidy so CleanCSS can remove redundant classes + // if tidy added a new style tag + int old_num_styles = CSSStyleTags( newsource ).count(); + + newsource = HTMLTidy( newsource ); + newsource = CleanCSS( newsource, old_num_styles ); + + // Once more, so we get the nice pretty-printed + // output of our CSS code too + newsource = HTMLTidy( newsource ); + + return newsource; +} + + +// Cleans CSS; currently it removes the redundant CSS classes +// that Tidy sometimes adds because it doesn't parse existing +// CSS classes, it only adds new ones; this also merges smaller +// style tags into larger ones +QString CleanSource::CleanCSS( const QString &source, int old_num_styles ) +{ + QString newsource = source; + QStringList css_style_tags = CSSStyleTags( newsource ); + + // If Tidy added a new tag, we remove the redundant ones + if ( css_style_tags.count() > old_num_styles ) + { + SourceAndStyles cleaned = RemoveRedundantClasses( newsource, css_style_tags ); + + newsource = cleaned.source; + css_style_tags = cleaned.css_style_tags; + } + + css_style_tags = RemoveCDATAComments( css_style_tags ); + css_style_tags = MergeSmallerStyles( css_style_tags ); + css_style_tags = AddCDATAComments( css_style_tags ); + + newsource = WriteNewCSSStyleTags( newsource, css_style_tags ); + + return newsource; +} + + +// Returns the content of all CSS style tags in a list, +// where each element is a QString representing the content +// of a single CSS style tag +QStringList CleanSource::CSSStyleTags( const QString &source ) +{ + QRegExp body_start_tag( BODY_START ); + + int body_begin = source.indexOf( body_start_tag, 0 ); + + QString header = Utility::Substring( 0, body_begin, source ); + + QRegExp style_tag( STYLE_TAG ); + + // Non-greedy quantifiers, so we get + // only one style tag per pass + style_tag.setMinimal( true ); + + QStringList css_style_tags; + int main_index = 0; + + while ( true ) + { + int css_index = header.indexOf( style_tag, main_index ); + + if ( css_index == -1 ) + + break; + + main_index = css_index + style_tag.matchedLength(); + + // We only read from CSS style tags and ignore other types + if ( style_tag.cap( 1 ) != "text/css" ) + + continue; + + css_style_tags.append( style_tag.cap( 2 ) ); + } + + return css_style_tags; +} + +// Removes the CDATA comments from the style tag contents +QStringList CleanSource::RemoveCDATAComments( const QStringList &css_style_tags ) +{ + QStringList new_tags = css_style_tags; + + for ( int i = 0; i < new_tags.count(); i++ ) + { + new_tags[ i ].replace( "/**/", "" ); + + new_tags[ i ] = new_tags[ i ].trimmed(); + } + + return new_tags; +} + + +// Adds back the CDATA comments to the style tag contents +QStringList CleanSource::AddCDATAComments( const QStringList &css_style_tags ) +{ + QStringList new_tags = css_style_tags; + + for ( int i = 0; i < new_tags.count(); i++ ) + { + new_tags[ i ].prepend( "/**/" ); + } + + return new_tags; +} + + +// Merges smaller styles into bigger ones +QStringList CleanSource::MergeSmallerStyles( const QStringList &css_style_tags ) +{ + if ( css_style_tags.count() < 2 ) + + return css_style_tags; + + QStringList new_tags = css_style_tags; + + int index = 1; + + while ( index < new_tags.count() ) + { + if ( new_tags[ index ].length() < TAG_SIZE_THRESHOLD ) + { + new_tags[ index - 1 ].append( "\n\n" + new_tags[ index ] ); + + new_tags.removeAt( index ); + } + + else + { + index++; + } + } + + return new_tags; +} + + +// Returns the largest index of all the Sigil CSS classes +int CleanSource::MaxSigilCSSClassIndex( const QStringList &css_style_tags ) +{ + int max_class_index = 0; + + foreach( QString style_tag, css_style_tags ) + { + QRegExp sigil_class( SIGIL_CLASS_NAME_REG ); + + int main_index = 0; + + while ( true ) + { + main_index = style_tag.indexOf( sigil_class, main_index ); + + if ( main_index == -1 ) + + break; + + main_index += sigil_class.matchedLength(); + + int class_index = sigil_class.cap( 1 ).toInt(); + + if ( class_index > max_class_index ) + + max_class_index = class_index; + } + } + + return max_class_index; +} + + +// Runs HTML Tidy on the provided XHTML source code +QString CleanSource::HTMLTidy( const QString &source ) +{ + TidyDoc tidy_document = tidyCreate(); + + TidyBuffer output = { 0 }; + TidyBuffer errbuf = { 0 }; + + // For more information on Tidy configuration + // options, see http://tidy.sourceforge.net/docs/quickref.html + + // "output-xhtml" + tidyOptSetBool( tidy_document, TidyXhtmlOut, yes ); + + // "add-xml-decl" + tidyOptSetBool( tidy_document, TidyXmlDecl, yes ); + + // "clean" + tidyOptSetBool( tidy_document, TidyMakeClean, yes ); + + // Turning these two options on produces ugly markup + // from WYSIWYG actions... for now, it's better we turn it off. + + // "merge-divs" + //tidyOptSetInt( tidy_document, TidyMergeDivs, no ); + + // "merge-spans" + //tidyOptSetInt( tidy_document, TidyMergeSpans, no ); + + // "doctype" + tidyOptSetValue( tidy_document, TidyDoctype, "strict" ); + + // "drop-empty-paras" + tidyOptSetBool( tidy_document, TidyDropEmptyParas, yes ); + + // "enclose-text" + tidyOptSetBool( tidy_document, TidyEncloseBodyText, yes ); + + // "wrap" + tidyOptSetInt( tidy_document, TidyWrapLen, 100 ); + + // "css-prefix" + tidyOptSetValue( tidy_document, TidyCSSPrefix, SIGIL_CLASS_NAME.toUtf8().data() ); + + // This option doesn't exist in "normal" Tidy. It has been hacked on + // and enables us to direct Tidy to start numbering new CSS classes + // from an index we provide it, and not always from 1 (which causes clashes). + tidyOptSetInt( tidy_document, TidyClassStartID, MaxSigilCSSClassIndex( CSSStyleTags( source ) ) ); + + // "indent" + tidyOptSetInt( tidy_document, TidyIndentContent, TidyAutoState ); + + // "tidy-mark" + tidyOptSetBool( tidy_document, TidyMark, no ); + + // UTF-8 for input and output + tidySetCharEncoding( tidy_document, "utf8" ); + + // Force output + tidyOptSetBool( tidy_document, TidyForceOutput, yes); + + // Write all errors to error buffer + tidySetErrorBuffer( tidy_document, &errbuf ); + + // Set the input + tidyParseString( tidy_document, source.toUtf8().data() ); + + // GO BABY GO! + tidyCleanAndRepair( tidy_document ); + + // Run diagnostics + tidyRunDiagnostics( tidy_document ); + + // TODO: read and report any possible errors + // from the error buffer + + // Store the cleaned up XHTML + tidySaveBuffer( tidy_document, &output ); + + QString clean = QString::fromUtf8( (const char*) output.bp ); + + // Free memory + tidyBufFree( &output ); + tidyBufFree( &errbuf ); + tidyRelease( tidy_document ); + + return clean; +} + + +// Writes the new CSS style tags to the source, replacing the old ones +QString CleanSource::WriteNewCSSStyleTags( const QString &source, const QStringList &css_style_tags ) +{ + QRegExp body_start_tag( BODY_START ); + + int body_begin = source.indexOf( body_start_tag, 0 ); + + QString header = Utility::Substring( 0, body_begin, source ); + + QRegExp css_styles_reg( STYLE_TAG_CSS_ONLY ); + css_styles_reg.setMinimal( true ); + + // We delete the old CSS style tags + header.remove( css_styles_reg ); + + // For each new style tag, create it + // and add it to the end of the section + foreach( QString styles, css_style_tags ) + { + QString style_tag = "\n"; + + header.insert( header.indexOf( "" ), style_tag ); + } + + return header + Utility::Substring( body_begin, source.length(), source ); +} + + +// Removes redundant classes from the style tags and source code; +// Calls more specific version. +CleanSource::SourceAndStyles CleanSource::RemoveRedundantClasses( const QString &source, const QStringList &css_style_tags ) +{ + QHash< QString, QString > redundant_classes = GetRedundantClasses( css_style_tags ); + + SourceAndStyles cleaned; + cleaned.source = RemoveRedundantClassesSource( source, redundant_classes ); + cleaned.css_style_tags = RemoveRedundantClassesTags( css_style_tags, redundant_classes ); + + return cleaned; +} + +// Removes redundant CSS classes from the provided CSS style tags +QStringList CleanSource::RemoveRedundantClassesTags( const QStringList &css_style_tags, const QHash< QString, QString > redundant_classes ) +{ + QStringList new_css_style_tags = css_style_tags; + QStringList last_tag_styles = new_css_style_tags.last().split( QChar( '\n' ) ); + + // Searches for the old class in every line; + // Tidy always creates class definitions as one line + foreach( QString key, redundant_classes.keys() ) + { + QRegExp remove_old( "^.*" + key + ".*$" ); + remove_old.setMinimal( true ); + + last_tag_styles.replaceInStrings( remove_old, "" ); + } + + new_css_style_tags[ new_css_style_tags.count() - 1 ] = last_tag_styles.join( QChar( '\n' ) ); + + return new_css_style_tags; +} + +// Removes redundant CSS classes from the provided XHTML source code; +// Updates references to older classes that do the same thing +QString CleanSource::RemoveRedundantClassesSource( const QString &source, const QHash< QString, QString > redundant_classes ) +{ + QString newsource = source; + + foreach( QString key, redundant_classes.keys() ) + { + QRegExp remove_old( CLASS_REMOVE_START + key + CLASS_REMOVE_END ); + + while ( newsource.indexOf( remove_old ) != -1 ) + { + QString matched = remove_old.cap( 0 ); + + matched.replace( key, redundant_classes[ key ] ); + + newsource.replace( remove_old.cap( 0 ), matched ); + } + } + + return newsource; +} + + +// Returns a QHash with keys being the new redundant CSS classes, +// and the values the old classes that already do the job of the new ones. +QHash< QString, QString > CleanSource::GetRedundantClasses( const QStringList &css_style_tags ) +{ + QHash< QString, QString > redundant_classes; + + // Tidy always create ONE style tag for its new classes, + // and it is always the last one + QString last_style_tag = css_style_tags.last(); + + QStringList last_tag_styles = last_style_tag.split( QChar( '\n' ) ); + + // We search through all the tags that come before this new one + for ( int i = 0; i < css_style_tags.count() - 1; i++ ) + { + QStringList old_lines = css_style_tags[ i ].split( QChar( '\n' ) ); + + foreach( QString new_line, last_tag_styles ) + { + QRegExp class_definition( CLASS_DEFINITION ); + class_definition.setMinimal( true ); + + if ( new_line.indexOf( class_definition ) != -1 ) + { + // There should always be just one that matches + QStringList matching_lines = old_lines.filter( class_definition.cap( 0 ) ); + + if ( matching_lines.count() != 0 ) + { + QRegExp sgc_class( SIGIL_CLASS_NAME_REG ); + + matching_lines[ 0 ].indexOf( sgc_class ); + QString oldclass = sgc_class.cap( 0 ); + + new_line.indexOf( sgc_class ); + QString newclass = sgc_class.cap( 0 ); + + redundant_classes[ newclass ] = oldclass; + } + + else + { + continue; + } + } + } + } + + return redundant_classes; +} diff --git a/src/Sigil/CleanSource.h b/src/Sigil/CleanSource.h new file mode 100644 index 0000000000..8fa52264b1 --- /dev/null +++ b/src/Sigil/CleanSource.h @@ -0,0 +1,97 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see . +** +*************************************************************************/ + +#pragma once +#ifndef CLEANSOURCE_H +#define CLEANSOURCE_H + +#include + +class CleanSource +{ + +public: + + // Performs general cleaning (and improving) + // of provided book XHTML source code + static QString Clean( const QString &source ); + +private: + + // Cleans CSS; currently it removes the redundant CSS classes + // that Tidy sometimes adds because it doesn't parse existing + // CSS classes, it only adds new ones; this also merges smaller + // style tags into larger ones + static QString CleanCSS( const QString &source, int old_num_styles ); + + // Returns the content of all CSS style tags in a list, + // where each element is a QString representing the content + // of a single CSS style tag + static QStringList CSSStyleTags( const QString &source ); + + // Removes the CDATA comments from the style tag contents + static QStringList RemoveCDATAComments( const QStringList &css_style_tags ); + + // Adds back the CDATA comments to the style tag contents + static QStringList AddCDATAComments( const QStringList &css_style_tags ); + + // Merges smaller styles into bigger ones + static QStringList MergeSmallerStyles( const QStringList &css_style_tags ); + + // Returns the largest index of all the Sigil CSS classes + static int MaxSigilCSSClassIndex( const QStringList &css_style_tags ); + + // Runs HTML Tidy on the provided XHTML source code + static QString HTMLTidy( const QString &source ); + + // Writes the new CSS style tags to the source, replacing the old ones + static QString WriteNewCSSStyleTags( const QString &source, const QStringList &css_style_tags ); + + // Used for the return value of RemoveRedundantClasses + // because C++ doens't have tuples (TR-1 and Boost don't count). + // Using non-const references would be rather ugly here. + struct SourceAndStyles + { + QString source; + QStringList css_style_tags; + }; + + // Removes redundant CSS classes from the style tags and source code; + // Calls more specific version. + static SourceAndStyles RemoveRedundantClasses( const QString &source, const QStringList &css_style_tags ); + + // Removes redundant CSS classes from the provided CSS style tags + static QStringList RemoveRedundantClassesTags( const QStringList &css_style_tags, + const QHash< QString, QString > redundant_classes ); + + // Removes redundant CSS classes from the provided XHTML source code; + // Updates references to older classes that do the same thing + static QString RemoveRedundantClassesSource( const QString &source, + const QHash< QString, QString > redundant_classes ); + + // Returns a QHash with keys being the new redundant CSS classes, + // and the values the old classes that already do the job of the new ones. + static QHash< QString, QString > GetRedundantClasses( const QStringList &css_style_tags ); + +}; + + +#endif // CLEANSOURCE_H diff --git a/src/Sigil/ExportEPUB.cpp b/src/Sigil/ExportEPUB.cpp new file mode 100644 index 0000000000..d7b7dcf667 --- /dev/null +++ b/src/Sigil/ExportEPUB.cpp @@ -0,0 +1,408 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see . +** +*************************************************************************/ + +#include "stdafx.h" +#include "ExportSGF.h" +#include "FolderKeeper.h" +#include "OPFWriter.h" +#include "NCXWriter.h" +#include +#include "CleanSource.h" +#include "Utility.h" + +const QString BODY_START = "<\\s*body[^>]*>"; +const QString BODY_END = ""; +const QString BREAK_TAG = ""; + +// Use with .setMinimal( true ) +const QString STYLE_TAG = "<\\s*style\\s*type\\s*=\\s*\"([^\"]+)\"[^>]*>(.*)]*>"; + + +// Constructor; +// the first parameter is the location where the book +// should be save to, and the second is the book to be saved +ExportEPUB::ExportEPUB( const QString &fullfilepath, const Book &book ) + : m_FullFilePath( fullfilepath ), m_Book( book ), fkFolder( book.mainfolder ) +{ + +} + + +// Destructor +ExportEPUB::~ExportEPUB() +{ + +} + + +// Writes the book to the path +// specified in the constructor +void ExportEPUB::WriteBook() +{ + CreatePublication(); + + SaveTo( m_FullFilePath ); +} + + +// Creates the publication from the Book +// (creates XHTML, CSS, OPF, NCX files etc.) +void ExportEPUB::CreatePublication() +{ + QStringList css_files = CreateStyleFiles(); + QString header = CreateHeader( css_files ); + + CreateXHTMLFiles( header ); + + CreateContainerXML(); + CreateContentOPF(); + CreateTocNCX(); +} + + +// Saves the publication to the specified path +void ExportEPUB::SaveTo( const QString &fullfilepath ) +{ + QTemporaryFile mimetype; + + if ( mimetype.open() ) + { + QTextStream out( &mimetype ); + + // We ALWAYS output in UTF-8 + out.setCodec( "UTF-8" ); + + out << "application/epub+zip"; + + // Write to disk immediately + out.flush(); + mimetype.flush(); + } + + CZipArchive zip; + + // FIXME: check for return true on zip.open + +#ifdef Q_WS_WIN + // The location where the epub file will be written to + zip.Open( fullfilepath.utf16(), CZipArchive::zipCreate ); + + // Add the uncompressed mimetype file as per OPF spec + zip.AddNewFile( mimetype.fileName().utf16(), QString( "mimetype" ).utf16(), 0 ); + + // Add all the files and folders in the publication structure + zip.AddNewFiles( QDir::toNativeSeparators( fkFolder.GetFullPathToMainFolder() ).utf16() ); + +#else + // The location where the epub file will be written to + zip.Open( fullfilepath.toUtf8().data(), CZipArchive::zipCreate ); + + // Add the uncompressed mimetype file as per OPF spec + zip.AddNewFile( mimetype.fileName().toUtf8().data(), QString( "mimetype" ).toUtf8().data(), 0 ); + + // Add all the files and folders in the publication structure + zip.AddNewFiles( QDir::toNativeSeparators( fkFolder.GetFullPathToMainFolder() ).toUtf8().data() ); +#endif + + zip.Close(); +} + + +// Creates style files from the style tags in the source +// and returns a list of their file paths relative +// to the OEBPS folder in the FolderKeeper +QStringList ExportEPUB::CreateStyleFiles() +{ + QRegExp body_start_tag( BODY_START ); + + int body_begin = m_Book.source.indexOf( body_start_tag, 0 ); + + QString header = Utility::Substring( 0, body_begin, m_Book.source ); + + QRegExp style_tag( STYLE_TAG ); + + // Non-greedy quantifiers, so we get + // only one style tag per pass + style_tag.setMinimal( true ); + + QStringList style_files; + + int main_index = 0; + + while ( true ) + { + int css_index = header.indexOf( style_tag, main_index ); + + if ( css_index == -1 ) + + break; + + QString extension = ""; + + // What type of stylesheet should we create? + if ( style_tag.cap( 1 ) == "text/css" ) + + extension = "css"; + + else // This is an XPGT stylesheet + + extension = "xpgt"; + + QString style_text = style_tag.cap( 2 ); + style_text = RemoveSigilStyles( style_text ); + style_text = StripCDATA( style_text ); + style_text = style_text.trimmed(); + + if ( !style_text.isEmpty() ) + + style_files << "../" + CreateOneTextFile( style_text, extension ); + + main_index = css_index + style_tag.matchedLength(); + } + + return style_files; +} + + +// Takes a list of style sheet file names +// and returns the header for XHTML files +QString ExportEPUB::CreateHeader( const QStringList &cssfiles ) +{ + QString header = "\n" + "\n\n" + "\n" + "\n"; + + foreach( QString file, cssfiles ) + { + header += " \n"; + } + + header += "\n"; + + return header; +} + + +// Creates XHTML files from the book source; +// the provided header is used as the header of the created files +void ExportEPUB::CreateXHTMLFiles( const QString &header ) +{ + QRegExp body_start_tag( BODY_START ); + QRegExp body_end_tag( BODY_END ); + + int body_begin = m_Book.source.indexOf( body_start_tag, 0 ) + body_start_tag.matchedLength(); + int body_end = m_Book.source.indexOf( body_end_tag, 0 ); + + int main_index = body_begin; + + while ( main_index != body_end ) + { + QRegExp break_tag( BREAK_TAG ); + + // We search for our HR break tag + int break_index = m_Book.source.indexOf( break_tag, main_index ); + + QString body; + + // We break up the remainder of the file on the HR tag index if it's found + if ( break_index > -1 ) + { + body = Utility::Substring( main_index, break_index, m_Book.source ); + + main_index = break_index + break_tag.matchedLength(); + } + + // Otherwise, we take the rest of the file + else + { + body = Utility::Substring( main_index, body_end, m_Book.source ); + + main_index = body_end; + } + + // FIXME: the tag should be created with chapter name + // and added to the header + + QString wholefile = header + "<body>\n" + body + "</body> </html>"; + + wholefile = CleanSource::Clean( wholefile ); + + CreateOneTextFile( wholefile, "xhtml" ); + } +} + + +// Creates one text file from the provided source +// and adds it to the FolderKeeper object with +// the provided extension; returns the file path +// relative to the OEBPS folder +QString ExportEPUB::CreateOneTextFile( const QString &source, const QString &extension ) +{ + QTemporaryFile file; + + if ( file.open() ) + { + QTextStream out( &file ); + + // We ALWAYS output in UTF-8 + out.setCodec( "UTF-8" ); + + out << source; + + // Write to disk immediately + out.flush(); + file.flush(); + + return fkFolder.AddContentFileToFolder( file.fileName(), extension ); + } + + else + { + // FIXME: throw exception + + return ""; + } +} + + +// Strips CDATA declarations from the provided source +QString ExportEPUB::StripCDATA( const QString &style_source ) +{ + QString newsource = style_source; + + newsource.replace( "/*<![CDATA[*/", "" ); + newsource.replace( "/*]]>*/", "" ); + + newsource.replace( "<![CDATA[", "" ); + newsource.replace( "]]>", "" ); + + return newsource; +} + + +// Removes Sigil styles from the provided source +QString ExportEPUB::RemoveSigilStyles( const QString &style_source ) +{ + // TODO: move this functionality to BookNormalization + + QString newsource = style_source; + + QRegExp chapter_break_style( "hr\\.sigilChapterBreak[^\\}]+\\}" ); + QRegExp sigil_comment( "/\\*SG.*SG\\*/" ); + + sigil_comment.setMinimal( true ); + + newsource.remove( chapter_break_style ); + newsource.remove( sigil_comment ); + + return newsource; +} + + +// Creates the publication's container.xml file +void ExportEPUB::CreateContainerXML() +{ + QString xml = "<?xml version=\"1.0\"?>\n" + "<container version=\"1.0\" xmlns=\"urn:oasis:names:tc:opendocument:xmlns:container\">\n" + " <rootfiles>\n" + " <rootfile full-path=\"OEBPS/content.opf\" media-type=\"application/oebps-package+xml\"/>\n" + " </rootfiles>\n" + "</container>\n"; + + QTemporaryFile file; + + if ( file.open() ) + { + QTextStream out( &file ); + + // We ALWAYS output in UTF-8 + out.setCodec( "UTF-8" ); + + out << xml; + + // Write to disk immediately + out.flush(); + file.flush(); + + fkFolder.AddInfraFileToFolder( file.fileName(), "container.xml" ); + } + + // FIXME: throw exception if not open +} + + +// Creates the publication's content.opf file +void ExportEPUB::CreateContentOPF() +{ + QTemporaryFile file; + + if ( file.open() ) + { + QTextStream out( &file ); + + // We ALWAYS output in UTF-8 + out.setCodec( "UTF-8" ); + + OPFWriter opf( m_Book, fkFolder.GetContentFilesList() ); + + out << opf.GetXML(); + + // Write to disk immediately + out.flush(); + file.flush(); + + fkFolder.AddInfraFileToFolder( file.fileName(), "content.opf" ); + } + + // FIXME: throw exception if not open +} + + +// Creates the publication's toc.ncx file +void ExportEPUB::CreateTocNCX() +{ + QTemporaryFile file; + + if ( file.open() ) + { + QTextStream out( &file ); + + // We ALWAYS output in UTF-8 + out.setCodec( "UTF-8" ); + + NCXWriter ncx( m_Book, fkFolder ); + + out << ncx.GetXML(); + + // Write to disk immediately + out.flush(); + file.flush(); + + fkFolder.AddInfraFileToFolder( file.fileName(), "toc.ncx" ); + } + + // FIXME: throw exception if not open +} + + + diff --git a/src/Sigil/ExportEPUB.h b/src/Sigil/ExportEPUB.h new file mode 100644 index 0000000000..a0310ae29a --- /dev/null +++ b/src/Sigil/ExportEPUB.h @@ -0,0 +1,108 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see <http://www.gnu.org/licenses/>. +** +*************************************************************************/ + +#pragma once +#ifndef EXPORTEPUB_H +#define EXPORTEPUB_H + +#include "Exporter.h" +#include "FolderKeeper.h" +#include "Book.h" + +class ExportEPUB : public Exporter +{ + +public: + + // Constructor; + // the first parameter is the location where the book + // should be save to, and the second is the book to be saved + ExportEPUB( const QString &fullfilepath, const Book &book ); + + // Destructor + virtual ~ExportEPUB(); + + // Writes the book to the path + // specified in the constructor + virtual void WriteBook(); + +protected: + + // Creates the publication from the Book + // (creates XHTML, CSS, OPF, NCX files etc.) + void virtual CreatePublication(); + + // Saves the publication to the specified path + void SaveTo( const QString &fullfilepath ); + + // Creates style files from the style tags in the source + // and returns a list of their file paths relative + // to the OEBPS folder in the FolderKeeper + QStringList CreateStyleFiles(); + + // Takes a list of style sheet file names + // and returns the header for XHTML files + QString CreateHeader( const QStringList &cssfiles ); + + // Creates XHTML files from the book source; + // the provided header is used as the header of the created files + void CreateXHTMLFiles( const QString &header ); + + // Creates one text file from the provided source + // and adds it to the FolderKeeper object with + // the provided extension; returns the file path + // relative to the OEBPS folder + QString CreateOneTextFile( const QString &source, const QString &extension ); + + // Strips CDATA declarations from the provided source + QString StripCDATA( const QString &style_source ); + + // Removes Sigil styles from the provided source + QString RemoveSigilStyles( const QString &style_source ); + + // Creates the publication's container.xml file + void CreateContainerXML(); + + // Creates the publication's content.opf file + void CreateContentOPF(); + + // Creates the publication's toc.ncx file + void CreateTocNCX(); + + + /////////////////////////////// + // PROTECTED MEMBER VARIABLES + /////////////////////////////// + + // The location where the publication + // should be exported to + QString m_FullFilePath; + + // The book being exported + Book m_Book; + + // The folder which contains all the files + // that will end up in the final exported file + FolderKeeper fkFolder; + +}; + +#endif // EXPORTEPUB_H \ No newline at end of file diff --git a/src/Sigil/ExportSGF.cpp b/src/Sigil/ExportSGF.cpp new file mode 100644 index 0000000000..40e8a8173b --- /dev/null +++ b/src/Sigil/ExportSGF.cpp @@ -0,0 +1,58 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see <http://www.gnu.org/licenses/>. +** +*************************************************************************/ + +#include "stdafx.h" +#include "ExportSGF.h" +#include "FolderKeeper.h" +#include "Book.h" + + +// Constructor; +// the first parameter is the location where the book +// should be save to, and the second is the book to be saved +ExportSGF::ExportSGF( const QString &fullfilepath, const Book &book ) + : ExportEPUB( fullfilepath, book ) +{ + +} + + +// Writes the book to the path +// specified in the constructor +void ExportSGF::WriteBook() +{ + CreatePublication(); + + SaveTo( m_FullFilePath ); +} + + +// Creates the publication from the Book +// (creates XHTML, OPF, NCX files etc.) +void ExportSGF::CreatePublication() +{ + //CreateXHTMLFile(); + CreateOneTextFile( m_Book.source, "xhtml" ); + + CreateContainerXML(); + CreateContentOPF(); + CreateTocNCX(); +} diff --git a/src/Sigil/ExportSGF.h b/src/Sigil/ExportSGF.h new file mode 100644 index 0000000000..f1e99edbed --- /dev/null +++ b/src/Sigil/ExportSGF.h @@ -0,0 +1,50 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see <http://www.gnu.org/licenses/>. +** +*************************************************************************/ + +#pragma once +#ifndef EXPORTSGF_H +#define EXPORTSGF_H + +#include "ExportEPUB.h" + +class ExportSGF : public ExportEPUB +{ + +public: + + // Constructor; + // the first parameter is the location where the book + // should be save to, and the second is the book to be saved + ExportSGF( const QString &fullfilepath, const Book &book ); + + // Writes the book to the path + // specified in the constructor + void WriteBook(); + +private: + + // Creates the publication from the Book + // (creates XHTML, OPF, NCX files etc.) + void CreatePublication(); + +}; + +#endif // EXPORTSGF_H \ No newline at end of file diff --git a/src/Sigil/Exporter.h b/src/Sigil/Exporter.h new file mode 100644 index 0000000000..ac22063536 --- /dev/null +++ b/src/Sigil/Exporter.h @@ -0,0 +1,37 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see <http://www.gnu.org/licenses/>. +** +*************************************************************************/ + +#pragma once +#ifndef EXPORTER_H +#define EXPORTER_H + +// An interface class for all Exporters +class Exporter +{ + +public: + + virtual ~Exporter() {} + + virtual void WriteBook() = 0; +}; + +#endif // EXPORTER_H diff --git a/src/Sigil/ExporterFactory.cpp b/src/Sigil/ExporterFactory.cpp new file mode 100644 index 0000000000..38bc186119 --- /dev/null +++ b/src/Sigil/ExporterFactory.cpp @@ -0,0 +1,74 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see <http://www.gnu.org/licenses/>. +** +*************************************************************************/ + +#include "stdafx.h" +#include "ExporterFactory.h" +#include "ExportSGF.h" +#include "ExportEPUB.h" + + +// Constructor +ExporterFactory::ExporterFactory() + : m_Exporter( NULL ) +{ + +} + +// Destructor +ExporterFactory::~ExporterFactory() +{ + delete m_Exporter; +} + + +// Returns a reference to the exporter +// appropriate for the given filename +Exporter& ExporterFactory::GetExporter( const QString &filename, const Book &book ) +{ + QString extension = QFileInfo( filename ).suffix().toLower(); + +// if ( ( extension == "xhtml" ) || +// ( extension == "html" ) || +// ( extension == "htm" ) +// ) +// { +// exExporter = new ExportHTML( filename ); +// +// return *m_Exporter; +// } + + if ( ( extension == "sgf" ) ) + { + m_Exporter = new ExportSGF( filename, book ); + + return *m_Exporter; + } + + if ( ( extension == "epub" ) ) + { + m_Exporter = new ExportEPUB( filename, book ); + + return *m_Exporter; + } + + return *m_Exporter; +} + diff --git a/src/Sigil/ExporterFactory.h b/src/Sigil/ExporterFactory.h new file mode 100644 index 0000000000..4b3f8862b5 --- /dev/null +++ b/src/Sigil/ExporterFactory.h @@ -0,0 +1,51 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see <http://www.gnu.org/licenses/>. +** +*************************************************************************/ + +#pragma once +#ifndef EXPORTERFACTORY_H +#define EXPORTERFACTORY_H + +#include "Exporter.h" +#include "Book.h" + +class ExporterFactory +{ + +public: + + // Constructor + ExporterFactory(); + + // Destructor + ~ExporterFactory(); + + // Returns a reference to the exporter + // appropriate for the given filename + Exporter& GetExporter( const QString &filename, const Book &book ); + +private: + + // The exporter created + Exporter* m_Exporter; + +}; + +#endif // EXPORTERFACTORY_H \ No newline at end of file diff --git a/src/Sigil/FolderKeeper.cpp b/src/Sigil/FolderKeeper.cpp new file mode 100644 index 0000000000..fc862983e8 --- /dev/null +++ b/src/Sigil/FolderKeeper.cpp @@ -0,0 +1,369 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see <http://www.gnu.org/licenses/>. +** +*************************************************************************/ + +#include "stdafx.h" +#include "FolderKeeper.h" +#include "Utility.h" + +// Constructor +FolderKeeper::FolderKeeper() +{ + Initialize(); +} + + +// Copy constructor +FolderKeeper::FolderKeeper( const FolderKeeper& other ) +{ + Initialize(); + + Utility::CopyFiles( other.FullPathToMainFolder, FullPathToMainFolder ); +} + + +// Assignment operator +FolderKeeper& FolderKeeper::operator = ( const FolderKeeper& other ) +{ + // Protect against invalid self-assignment + if ( this != &other ) + { + QString path_to_old = FullPathToMainFolder; + + Initialize(); + + Utility::DeleteFolderAndFiles( path_to_old ); + + Utility::CopyFiles( other.FullPathToMainFolder, FullPathToMainFolder ); + } + + // By convention, always return *this + return *this; +} + + +// Destructor +FolderKeeper::~FolderKeeper() +{ + if ( FullPathToMainFolder.isEmpty() == false ) + + Utility::DeleteFolderAndFiles( FullPathToMainFolder ); +} + +// A dispatcher function that routes the given *infrastructure* file +// to the appropriate specific folder function +void FolderKeeper::AddInfraFileToFolder( const QString &fullfilepath, const QString &newfilename ) +{ + if ( newfilename == "container.xml" ) + + AddFileToMetaInfFolder( fullfilepath, newfilename ); + + else if ( ( newfilename == "content.opf" ) || ( newfilename == "toc.ncx" ) ) + + AddFileToOEBPSFolder( fullfilepath, newfilename ); + + else + { + // FIXME: throw exception + } +} + +// A dispatcher function that routes the given *content* file +// to the appropriate specific folder function; +// the file is recognized according to its extension: use force_extension +// to override the recognition and force an extension; +// the function returns the new file's path relative to the OEBPS folder +QString FolderKeeper::AddContentFileToFolder( const QString &fullfilepath, const QString &force_extension ) +{ + QList< QString > images; + images << "jpg" << "jpeg" << "png" + << "gif" << "tif" << "tiff" + << "bm" << "bmp" << "svg"; + + QList< QString > fonts; + fonts << "ttf" << "otf"; + + QList< QString > texts; + texts << "xhtml" << "html" << "htm"; + + QList< QString > styles; + styles << "css" << "xpgt"; + + QString extension = ""; + + if ( force_extension.isNull() ) + { + extension = QFileInfo( fullfilepath ).suffix().toLower(); + } + + else + { + // If the user specified for instance ".txt", + // it is converted to "txt" (we remove the dot) + if ( force_extension[ 0 ] == QChar( '.' ) ) + + extension = Utility::Substring( 1, force_extension.length(), force_extension ).toLower(); + + else + + extension = force_extension.toLower();; + } + + if ( images.contains( extension ) ) + + return "images/" + AddFileToImagesFolder( fullfilepath, extension ); + + if ( fonts.contains( extension ) ) + + return "fonts/" + AddFileToFontsFolder( fullfilepath, extension ); + + if ( texts.contains( extension ) ) + + return "text/" + AddFileToTextFolder( fullfilepath, extension ); + + if ( styles.contains( extension ) ) + + return "styles/" + AddFileToStylesFolder( fullfilepath, extension ); + + // Fallback mechanism + return "misc/" + AddFileToMiscFolder( fullfilepath, extension ); +} + + +// Returns a list of all the content files in the directory +// with a path relative to the OEBPS directory +QStringList FolderKeeper::GetContentFilesList() const +{ + QStringList filelist; + + QDir images( FullPathToImagesFolder ); + QDir fonts( FullPathToFontsFolder ); + QDir texts( FullPathToTextFolder ); + QDir styles( FullPathToStylesFolder ); + QDir misc( FullPathToMiscFolder ); + + foreach( QString file, images.entryList() ) + { + if ( ( file != "." ) && ( file != ".." ) ) + + filelist.append( "images/" + file ); + } + + foreach( QString file, fonts.entryList() ) + { + if ( ( file != "." ) && ( file != ".." ) ) + + filelist.append( "fonts/" + file ); + } + + foreach( QString file, texts.entryList() ) + { + if ( ( file != "." ) && ( file != ".." ) ) + + filelist.append( "text/" + file ); + } + + foreach( QString file, styles.entryList() ) + { + if ( ( file != "." ) && ( file != ".." ) ) + + filelist.append( "styles/" + file ); + } + + foreach( QString file, misc.entryList() ) + { + if ( ( file != "." ) && ( file != ".." ) ) + + filelist.append( "misc/" + file ); + } + + return filelist; +} + + +// Returns the full path to the main folder of the publication +QString FolderKeeper::GetFullPathToMainFolder() const +{ + return FullPathToMainFolder; +} + + +// Returns the full path to the OEBPS folder of the publication +QString FolderKeeper::GetFullPathToOEBPSFolder() const +{ + return FullPathToOEBPSFolder; +} + + +// Returns the full path to the OEBPS/text folder of the publication +QString FolderKeeper::GetFullPathToTextFolder() const +{ + return FullPathToTextFolder; +} + + +// Copies the file specified with fullfilepath +// to the META-INF folder with the name newfilename +void FolderKeeper::AddFileToMetaInfFolder( const QString &fullfilepath, const QString &newfilename ) +{ + QFile::copy( fullfilepath, FullPathToMetaInfFolder + "/" + newfilename ); +} + + +// Copies the file specified with fullfilepath +// to the OEBPS folder with the name newfilename +void FolderKeeper::AddFileToOEBPSFolder( const QString &fullfilepath, const QString &newfilename ) +{ + QFile::copy( fullfilepath, FullPathToOEBPSFolder + "/" + newfilename ); +} + + +// Copies the file specified with fullfilepath +// to the OEBPS/images folder with a generated name; +// the generated name is returned +QString FolderKeeper::AddFileToImagesFolder( const QString &fullfilepath, const QString &extension ) +{ + // Count - 2 because we don't care for the "." and ".." folders + // + 1 because we are adding a file + int index = QDir( FullPathToImagesFolder ).count() - 2 + 1; + + // We add a number to the file, so e.g. we get "img0001.png", "img0035.jpg" etc. + QString newfile = QString( "img" ) + QString( "%1" ).arg( index, 4, 10, QChar( '0' ) ) + "." + extension; + + QFile::copy( fullfilepath, FullPathToImagesFolder + "/" + newfile ); + + return newfile; +} + + +// Copies the file specified with fullfilepath +// to the OEBPS/images folder with a generated name; +// the generated name is returned +QString FolderKeeper::AddFileToFontsFolder( const QString &fullfilepath, const QString &extension ) +{ + // Count - 2 because we don't care for the "." and ".." folders + // + 1 because we are adding a file + int index = QDir( FullPathToFontsFolder ).count() - 2 + 1; + + // We add a number to the file, so e.g. we get "font001.otf", "font035.ttf" etc. + QString newfile = QString( "font" ) + QString( "%1" ).arg( index, 3, 10, QChar( '0' ) ) + "." + extension; + + QFile::copy( fullfilepath, FullPathToFontsFolder + "/" + newfile ); + + return newfile; +} + + +// Copies the file specified with fullfilepath +// to the OEBPS/text folder with a generated name; +// the generated name is returned +QString FolderKeeper::AddFileToTextFolder( const QString &fullfilepath, const QString &extension ) +{ + // Count - 2 because we don't care for the "." and ".." folders + // + 1 because we are adding a file + int index = QDir( FullPathToTextFolder ).count() - 2 + 1; + + // We add a number to the file, so e.g. we get "content001.xhtml", "content035.xhtml" etc. + QString newfile = QString( "content" ) + QString( "%1" ).arg( index, 3, 10, QChar( '0' ) ) + "." + extension; + + QFile::copy( fullfilepath, FullPathToTextFolder + "/" + newfile ); + + return newfile; +} + +// Copies the file specified with fullfilepath +// to the OEBPS/styles folder with a generated name; +// the generated name is returned +QString FolderKeeper::AddFileToStylesFolder( const QString &fullfilepath, const QString &extension ) +{ + // Count - 2 because we don't care for the "." and ".." folders + // + 1 because we are adding a file + int index = QDir( FullPathToStylesFolder ).count() - 2 + 1; + + // We add a number to the file, so e.g. we get "style001.css", "style035.css" etc. + QString newfile = QString( "style" ) + QString( "%1" ).arg( index, 3, 10, QChar( '0' ) ) + "." + extension; + + QFile::copy( fullfilepath, FullPathToStylesFolder + "/" + newfile ); + + return newfile; +} + +// Copies the file specified with fullfilepath +// to the OEBPS/misc folder with a generated name; +// the generated name is returned +QString FolderKeeper::AddFileToMiscFolder( const QString &fullfilepath, const QString &extension ) +{ + // Count - 2 because we don't care for the "." and ".." folders + // + 1 because we are adding a file + int index = QDir( FullPathToMiscFolder ).count() - 2 + 1; + + // We add a number to the file, so e.g. we get "misc001.xxx", "misc035.xxx" etc. + QString newfile = QString( "misc" ) + QString( "%1" ).arg( index, 3, 10, QChar( '0' ) ) + "." + extension; + + QFile::copy( fullfilepath, FullPathToMiscFolder + "/" + newfile ); + + return newfile; +} + + +// Performs common constructor duties +// for all constructors +void FolderKeeper::Initialize() +{ + QDir folder( Utility::GetNewTempFolderPath() ); + + folder.mkpath( folder.absolutePath() ); + + FullPathToMainFolder = folder.absolutePath(); + + CreateFolderStructure(); +} + + +// Creates the required folder structure: +// META-INF +// OEBPS +// images +// fonts +// text +// styles +// misc +void FolderKeeper::CreateFolderStructure() +{ + QDir folder( FullPathToMainFolder ); + + folder.mkdir( "META-INF" ); + folder.mkdir( "OEBPS" ); + + folder.mkpath( "OEBPS/fonts" ); + folder.mkpath( "OEBPS/images" ); + folder.mkpath( "OEBPS/text" ); + folder.mkpath( "OEBPS/styles" ); + folder.mkpath( "OEBPS/misc" ); + + FullPathToMetaInfFolder = FullPathToMainFolder + "/META-INF"; + FullPathToOEBPSFolder = FullPathToMainFolder + "/OEBPS"; + + FullPathToImagesFolder = FullPathToOEBPSFolder + "/images"; + FullPathToFontsFolder = FullPathToOEBPSFolder + "/fonts"; + FullPathToTextFolder = FullPathToOEBPSFolder + "/text"; + FullPathToStylesFolder = FullPathToOEBPSFolder + "/styles"; + FullPathToMiscFolder = FullPathToOEBPSFolder + "/misc"; +} diff --git a/src/Sigil/FolderKeeper.h b/src/Sigil/FolderKeeper.h new file mode 100644 index 0000000000..2360102d2f --- /dev/null +++ b/src/Sigil/FolderKeeper.h @@ -0,0 +1,134 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see <http://www.gnu.org/licenses/>. +** +*************************************************************************/ + +#pragma once +#ifndef FOLDERKEEPER_H +#define FOLDERKEEPER_H + +#include <QString> + + +class FolderKeeper +{ + +public: + + // Constructor + FolderKeeper(); + + // Copy constructor + FolderKeeper( const FolderKeeper& other ); + + // Assignment operator + FolderKeeper& operator = ( const FolderKeeper& other ); + + // Destructor + ~FolderKeeper(); + + // A dispatcher function that routes the given *infrastructure* file + // to the appropriate specific folder function; the name of the new file + // needs to be specified + void AddInfraFileToFolder( const QString &fullfilepath, const QString &newfilename ); + + // A dispatcher function that routes the given *content* file + // to the appropriate specific folder function + QString AddContentFileToFolder( const QString &fullfilepath, const QString &force_extension = NULL ); + + // Returns a list of all the content files in the directory + // with a path relative to the OEBPS directory + QStringList GetContentFilesList() const; + + // Returns the full path to the main folder of the publication + QString GetFullPathToMainFolder() const; + + // Returns the full path to the OEBPS folder of the publication + QString GetFullPathToOEBPSFolder() const; + + // Returns the full path to the OEBPS folder of the publication + QString GetFullPathToTextFolder() const; + +private: + + // Copies the file specified with fullfilepath + // to the META-INF folder with the name newfilename + void AddFileToMetaInfFolder( const QString &fullfilepath, const QString &newfilename ); + + // Copies the file specified with fullfilepath + // to the OEBPS folder with the name newfilename + void AddFileToOEBPSFolder( const QString &fullfilepath, const QString &newfilename ); + + // Copies the file specified with fullfilepath + // to the OEBPS/images folder with a generated name; + // the generated name is returned + QString AddFileToImagesFolder( const QString &fullfilepath, const QString &extension ); + + // Copies the file specified with fullfilepath + // to the OEBPS/fonts folder with a generated name; + // the generated name is returned + QString AddFileToFontsFolder( const QString &fullfilepath, const QString &extension ); + + // Copies the file specified with fullfilepath + // to the OEBPS/text folder with a generated name; + // the generated name is returned + QString AddFileToTextFolder( const QString &fullfilepath, const QString &extension ); + + // Copies the file specified with fullfilepath + // to the OEBPS/styles folder with a generated name; + // the generated name is returned + QString AddFileToStylesFolder( const QString &fullfilepath, const QString &extension ); + + // Copies the file specified with fullfilepath + // to the OEBPS/misc folder with a generated name; + // the generated name is returned + QString AddFileToMiscFolder( const QString &fullfilepath, const QString &extension ); + + // Performs common constructor duties + // for all constructors + void Initialize(); + + // Creates the required folder structure: + // META-INF + // OEBPS + // images + // fonts + // text + // styles + // misc + void CreateFolderStructure(); + + + /////////////////////////////// + // PRIVATE MEMBER VARIABLES + /////////////////////////////// + + // Full paths to all the folders in the publication + QString FullPathToMainFolder; + QString FullPathToMetaInfFolder; + QString FullPathToOEBPSFolder; + + QString FullPathToImagesFolder; + QString FullPathToFontsFolder; + QString FullPathToTextFolder; + QString FullPathToStylesFolder; + QString FullPathToMiscFolder; +}; + +#endif // FOLDERKEEPER_H diff --git a/src/Sigil/Form_Files/About.ui b/src/Sigil/Form_Files/About.ui new file mode 100644 index 0000000000..3f3400165b --- /dev/null +++ b/src/Sigil/Form_Files/About.ui @@ -0,0 +1,275 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>About</class> + <widget class="QDialog" name="About"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>292</width> + <height>284</height> + </rect> + </property> + <property name="windowTitle"> + <string>About</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="sizeConstraint"> + <enum>QLayout::SetFixedSize</enum> + </property> + <item> + <widget class="QLabel" name="logo"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>80</height> + </size> + </property> + <property name="text"> + <string/> + </property> + <property name="pixmap"> + <pixmap resource="../Resource_Files/About/About.qrc">:/newPrefix/Sigil_logo.png</pixmap> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="subtitle"> + <property name="minimumSize"> + <size> + <width>0</width> + <height>32</height> + </size> + </property> + <property name="font"> + <font> + <pointsize>14</pointsize> + </font> + </property> + <property name="text"> + <string>the ePub editor</string> + </property> + <property name="alignment"> + <set>Qt::AlignHCenter|Qt::AlignTop</set> + </property> + </widget> + </item> + <item> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="lbAuthor"> + <property name="font"> + <font> + <pointsize>10</pointsize> + </font> + </property> + <property name="text"> + <string>Author:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLabel" name="lbAuthorDisplay"> + <property name="font"> + <font> + <pointsize>10</pointsize> + </font> + </property> + <property name="text"> + <string>Strahinja Marković</string> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="indent"> + <number>5</number> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="lbHomepage"> + <property name="font"> + <font> + <pointsize>10</pointsize> + </font> + </property> + <property name="text"> + <string>Homepage:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLabel" name="lbHomepageDisplay"> + <property name="font"> + <font> + <pointsize>10</pointsize> + </font> + </property> + <property name="text"> + <string><a href="http://code.google.com/p/sigil/">http://code.google.com/p/sigil/</a></string> + </property> + <property name="textFormat"> + <enum>Qt::AutoText</enum> + </property> + <property name="indent"> + <number>5</number> + </property> + <property name="openExternalLinks"> + <bool>true</bool> + </property> + <property name="textInteractionFlags"> + <set>Qt::TextBrowserInteraction</set> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="lbVersion"> + <property name="font"> + <font> + <pointsize>10</pointsize> + </font> + </property> + <property name="text"> + <string>Version:</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLabel" name="lbVersionDisplay"> + <property name="font"> + <font> + <pointsize>10</pointsize> + </font> + </property> + <property name="text"> + <string>VERSION HERE</string> + </property> + <property name="indent"> + <number>5</number> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="lbBuildTime"> + <property name="font"> + <font> + <pointsize>10</pointsize> + </font> + </property> + <property name="text"> + <string>Build time:</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QLabel" name="lbBuildTimeDisplay"> + <property name="font"> + <font> + <pointsize>10</pointsize> + </font> + </property> + <property name="text"> + <string>BUILD TIME HERE</string> + </property> + <property name="indent"> + <number>5</number> + </property> + </widget> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="lbLoadedQt"> + <property name="font"> + <font> + <pointsize>10</pointsize> + </font> + </property> + <property name="text"> + <string>Loaded Qt:</string> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="QLabel" name="lbLoadedQtDisplay"> + <property name="font"> + <font> + <pointsize>10</pointsize> + </font> + </property> + <property name="cursor"> + <cursorShape>ArrowCursor</cursorShape> + </property> + <property name="text"> + <string>LOADED QT VERSION HERE</string> + </property> + <property name="indent"> + <number>5</number> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Close</set> + </property> + <property name="centerButtons"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + <resources> + <include location="../Resource_Files/About/About.qrc"/> + <include location="../Resource_Files/About/About.qrc"/> + <include location="../Resource_Files/About/About.qrc"/> + <include location="../Resource_Files/About/About.qrc"/> + </resources> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>About</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>About</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/src/Sigil/Form_Files/AddMetadata.ui b/src/Sigil/Form_Files/AddMetadata.ui new file mode 100644 index 0000000000..b27afc096e --- /dev/null +++ b/src/Sigil/Form_Files/AddMetadata.ui @@ -0,0 +1,89 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>AddMetadata</class> + <widget class="QDialog" name="AddMetadata"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>354</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle"> + <string>Add metadata property</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QSplitter" name="splitter"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="childrenCollapsible"> + <bool>false</bool> + </property> + <widget class="QListWidget" name="lwProperties"/> + <widget class="QLabel" name="lbDescription"> + <property name="text"> + <string>Metadata description</string> + </property> + <property name="scaledContents"> + <bool>false</bool> + </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>AddMetadata</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>257</x> + <y>290</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>AddMetadata</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>325</x> + <y>290</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/src/Sigil/Form_Files/MetaEditor.ui b/src/Sigil/Form_Files/MetaEditor.ui new file mode 100644 index 0000000000..12576115f5 --- /dev/null +++ b/src/Sigil/Form_Files/MetaEditor.ui @@ -0,0 +1,269 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MetaEditor</class> + <widget class="QDialog" name="MetaEditor"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>450</width> + <height>304</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="windowTitle"> + <string>Meta Editor</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <property name="sizeConstraint"> + <enum>QLayout::SetMaximumSize</enum> + </property> + <item row="0" column="0"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <layout class="QFormLayout" name="formLayout"> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::AllNonFixedFieldsGrow</enum> + </property> + <property name="verticalSpacing"> + <number>13</number> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Title:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="leTitle"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Author:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="leAuthor"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Language:</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QComboBox" name="cbLanguages"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>56</height> + </size> + </property> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btMore"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Ignored" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>25</height> + </size> + </property> + <property name="sizeIncrement"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>More</string> + </property> + <property name="checkable"> + <bool>false</bool> + </property> + <property name="default"> + <bool>false</bool> + </property> + <property name="flat"> + <bool>false</bool> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </item> + <item row="1" column="0"> + <widget class="QWidget" name="wgExtension" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <property name="margin"> + <number>0</number> + </property> + <item> + <widget class="QTableView" name="tvMetaTable"> + <property name="minimumSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="alternatingRowColors"> + <bool>false</bool> + </property> + </widget> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout_5"> + <item> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QPushButton" name="btAddBasic"> + <property name="text"> + <string>Add Basic</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btAddAdvanced"> + <property name="text"> + <string>Add Adv.</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btRemove"> + <property name="text"> + <string>Remove</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <tabstops> + <tabstop>leTitle</tabstop> + <tabstop>leAuthor</tabstop> + <tabstop>buttonBox</tabstop> + <tabstop>btMore</tabstop> + <tabstop>btAddBasic</tabstop> + <tabstop>btAddAdvanced</tabstop> + <tabstop>btRemove</tabstop> + <tabstop>tvMetaTable</tabstop> + <tabstop>cbLanguages</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>MetaEditor</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>438</x> + <y>66</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>MetaEditor</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>438</x> + <y>66</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/src/Sigil/Form_Files/TOCEditor.ui b/src/Sigil/Form_Files/TOCEditor.ui new file mode 100644 index 0000000000..2154c74eda --- /dev/null +++ b/src/Sigil/Form_Files/TOCEditor.ui @@ -0,0 +1,102 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>TOCEditor</class> + <widget class="QDialog" name="TOCEditor"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>408</width> + <height>328</height> + </rect> + </property> + <property name="windowTitle"> + <string>Table Of Contents Editor</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QTreeView" name="tvTOCDisplay"> + <property name="editTriggers"> + <set>QAbstractItemView::NoEditTriggers</set> + </property> + <property name="tabKeyNavigation"> + <bool>false</bool> + </property> + <property name="alternatingRowColors"> + <bool>true</bool> + </property> + <property name="indentation"> + <number>15</number> + </property> + <property name="uniformRowHeights"> + <bool>true</bool> + </property> + <property name="animated"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="cbTOCItemsOnly"> + <property name="toolTip"> + <string>If this is checked, only the items that will end up in the Table Of Contents are displayed in the list</string> + </property> + <property name="text"> + <string>TOC items only</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + <property name="centerButtons"> + <bool>false</bool> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>TOCEditor</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>TOCEditor</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/src/Sigil/Form_Files/main.ui b/src/Sigil/Form_Files/main.ui new file mode 100644 index 0000000000..1c2e5e1eca --- /dev/null +++ b/src/Sigil/Form_Files/main.ui @@ -0,0 +1,651 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MainWindow</class> + <widget class="QMainWindow" name="MainWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>945</width> + <height>721</height> + </rect> + </property> + <property name="windowTitle"> + <string>untitled.sgf[*] - Sigil</string> + </property> + <property name="toolButtonStyle"> + <enum>Qt::ToolButtonIconOnly</enum> + </property> + <widget class="QWidget" name="centralwidget"> + <property name="layoutDirection"> + <enum>Qt::LeftToRight</enum> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="spacing"> + <number>0</number> + </property> + <property name="margin"> + <number>0</number> + </property> + <item> + <widget class="QSplitter" name="splitter"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="handleWidth"> + <number>4</number> + </property> + <widget class="QWebView" name="wBookView"> + <property name="url"> + <url> + <string>about:blank</string> + </url> + </property> + </widget> + <widget class="QPlainTextEdit" name="wCodeView"/> + </widget> + </item> + </layout> + </widget> + <widget class="QMenuBar" name="menubar"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>945</width> + <height>22</height> + </rect> + </property> + <widget class="QMenu" name="menuFile"> + <property name="title"> + <string>&File</string> + </property> + <addaction name="actionNew"/> + <addaction name="actionOpen"/> + <addaction name="separator"/> + <addaction name="actionSave"/> + <addaction name="actionSaveAs"/> + <addaction name="separator"/> + <addaction name="separator"/> + <addaction name="actionExit"/> + </widget> + <widget class="QMenu" name="menuEdit"> + <property name="title"> + <string>&Edit</string> + </property> + <addaction name="actionUndo"/> + <addaction name="actionRedo"/> + <addaction name="separator"/> + <addaction name="actionCut"/> + <addaction name="actionCopy"/> + <addaction name="actionPaste"/> + </widget> + <widget class="QMenu" name="menuHelp"> + <property name="title"> + <string>&Help</string> + </property> + <addaction name="actionAbout"/> + </widget> + <widget class="QMenu" name="menuFormat"> + <property name="title"> + <string>For&mat</string> + </property> + <addaction name="actionBold"/> + <addaction name="actionItalic"/> + <addaction name="actionUnderline"/> + <addaction name="actionStrikethrough"/> + <addaction name="separator"/> + <addaction name="actionAlignLeft"/> + <addaction name="actionCenter"/> + <addaction name="actionAlignRight"/> + <addaction name="actionJustify"/> + <addaction name="separator"/> + <addaction name="actionInsertBulletedList"/> + <addaction name="actionInsertNumberedList"/> + </widget> + <widget class="QMenu" name="menuView"> + <property name="title"> + <string>&View</string> + </property> + <addaction name="actionBookView"/> + <addaction name="actionSplitView"/> + <addaction name="actionCodeView"/> + </widget> + <widget class="QMenu" name="menuTools"> + <property name="title"> + <string>&Tools</string> + </property> + <addaction name="actionMetaEditor"/> + <addaction name="actionTOCEditor"/> + </widget> + <widget class="QMenu" name="menuInsert"> + <property name="title"> + <string>&Insert</string> + </property> + <addaction name="actionInsertChapterBreak"/> + <addaction name="actionInsertImage"/> + </widget> + <addaction name="menuFile"/> + <addaction name="menuEdit"/> + <addaction name="menuFormat"/> + <addaction name="menuInsert"/> + <addaction name="menuView"/> + <addaction name="menuTools"/> + <addaction name="menuHelp"/> + </widget> + <widget class="QStatusBar" name="statusbar"/> + <widget class="QToolBar" name="toolBarFileActions"> + <property name="windowTitle"> + <string>toolBar</string> + </property> + <attribute name="toolBarArea"> + <enum>TopToolBarArea</enum> + </attribute> + <attribute name="toolBarBreak"> + <bool>false</bool> + </attribute> + <addaction name="actionNew"/> + <addaction name="actionOpen"/> + <addaction name="actionSave"/> + <addaction name="actionSaveAs"/> + </widget> + <widget class="QToolBar" name="toolBarTextManip"> + <property name="windowTitle"> + <string>toolBar_2</string> + </property> + <attribute name="toolBarArea"> + <enum>TopToolBarArea</enum> + </attribute> + <attribute name="toolBarBreak"> + <bool>false</bool> + </attribute> + <addaction name="actionUndo"/> + <addaction name="actionRedo"/> + <addaction name="separator"/> + <addaction name="actionCut"/> + <addaction name="actionCopy"/> + <addaction name="actionPaste"/> + </widget> + <widget class="QToolBar" name="toolBarViews"> + <property name="windowTitle"> + <string>toolBar_5</string> + </property> + <attribute name="toolBarArea"> + <enum>TopToolBarArea</enum> + </attribute> + <attribute name="toolBarBreak"> + <bool>false</bool> + </attribute> + <addaction name="actionBookView"/> + <addaction name="actionSplitView"/> + <addaction name="actionCodeView"/> + </widget> + <widget class="QToolBar" name="toolBarInsertions"> + <property name="windowTitle"> + <string>toolBar_6</string> + </property> + <attribute name="toolBarArea"> + <enum>TopToolBarArea</enum> + </attribute> + <attribute name="toolBarBreak"> + <bool>false</bool> + </attribute> + <addaction name="actionInsertChapterBreak"/> + <addaction name="actionInsertImage"/> + </widget> + <widget class="QToolBar" name="toolBarHeadings"> + <property name="windowTitle"> + <string>toolBar</string> + </property> + <attribute name="toolBarArea"> + <enum>TopToolBarArea</enum> + </attribute> + <attribute name="toolBarBreak"> + <bool>true</bool> + </attribute> + </widget> + <widget class="QToolBar" name="toolBarTextFormats"> + <property name="windowTitle"> + <string>toolBar_3</string> + </property> + <attribute name="toolBarArea"> + <enum>TopToolBarArea</enum> + </attribute> + <attribute name="toolBarBreak"> + <bool>false</bool> + </attribute> + <addaction name="actionBold"/> + <addaction name="actionItalic"/> + <addaction name="actionUnderline"/> + <addaction name="actionStrikethrough"/> + </widget> + <widget class="QToolBar" name="toolBarTextAlign"> + <property name="windowTitle"> + <string>toolBar_4</string> + </property> + <attribute name="toolBarArea"> + <enum>TopToolBarArea</enum> + </attribute> + <attribute name="toolBarBreak"> + <bool>false</bool> + </attribute> + <addaction name="actionAlignLeft"/> + <addaction name="actionCenter"/> + <addaction name="actionAlignRight"/> + <addaction name="actionJustify"/> + </widget> + <widget class="QToolBar" name="toolBarLists"> + <property name="windowTitle"> + <string>toolBar_7</string> + </property> + <attribute name="toolBarArea"> + <enum>TopToolBarArea</enum> + </attribute> + <attribute name="toolBarBreak"> + <bool>false</bool> + </attribute> + <addaction name="actionInsertBulletedList"/> + <addaction name="actionInsertNumberedList"/> + </widget> + <action name="actionNew"> + <property name="icon"> + <iconset resource="../Resource_Files/main/main.qrc"> + <normaloff>:/newPrefix/document-new.png</normaloff>:/newPrefix/document-new.png</iconset> + </property> + <property name="text"> + <string>&New</string> + </property> + <property name="shortcut"> + <string>Ctrl+N</string> + </property> + </action> + <action name="actionSave"> + <property name="icon"> + <iconset resource="../Resource_Files/main/main.qrc"> + <normaloff>:/newPrefix/document-save.png</normaloff>:/newPrefix/document-save.png</iconset> + </property> + <property name="text"> + <string>&Save</string> + </property> + <property name="shortcut"> + <string>Ctrl+S</string> + </property> + </action> + <action name="actionSaveAs"> + <property name="icon"> + <iconset resource="../Resource_Files/main/main.qrc"> + <normaloff>:/newPrefix/document-save-as.png</normaloff>:/newPrefix/document-save-as.png</iconset> + </property> + <property name="text"> + <string>Save &As...</string> + </property> + <property name="shortcut"> + <string>F12</string> + </property> + </action> + <action name="actionCut"> + <property name="icon"> + <iconset resource="../Resource_Files/main/main.qrc"> + <normaloff>:/newPrefix/edit-cut.png</normaloff>:/newPrefix/edit-cut.png</iconset> + </property> + <property name="text"> + <string>&Cut</string> + </property> + <property name="shortcut"> + <string>Ctrl+X</string> + </property> + </action> + <action name="actionPaste"> + <property name="icon"> + <iconset resource="../Resource_Files/main/main.qrc"> + <normaloff>:/newPrefix/edit-paste.png</normaloff>:/newPrefix/edit-paste.png</iconset> + </property> + <property name="text"> + <string>&Paste</string> + </property> + <property name="shortcut"> + <string>Ctrl+V</string> + </property> + </action> + <action name="actionUndo"> + <property name="icon"> + <iconset resource="../Resource_Files/main/main.qrc"> + <normaloff>:/newPrefix/edit-undo.png</normaloff>:/newPrefix/edit-undo.png</iconset> + </property> + <property name="text"> + <string>&Undo</string> + </property> + <property name="shortcut"> + <string>Ctrl+Z</string> + </property> + </action> + <action name="actionRedo"> + <property name="icon"> + <iconset resource="../Resource_Files/main/main.qrc"> + <normaloff>:/newPrefix/edit-redo.png</normaloff>:/newPrefix/edit-redo.png</iconset> + </property> + <property name="text"> + <string>&Redo</string> + </property> + <property name="shortcut"> + <string>Ctrl+Y</string> + </property> + </action> + <action name="actionCopy"> + <property name="icon"> + <iconset resource="../Resource_Files/main/main.qrc"> + <normaloff>:/newPrefix/edit-copy.png</normaloff>:/newPrefix/edit-copy.png</iconset> + </property> + <property name="text"> + <string>&Copy</string> + </property> + <property name="shortcut"> + <string>Ctrl+C</string> + </property> + </action> + <action name="actionAlignLeft"> + <property name="icon"> + <iconset resource="../Resource_Files/main/main.qrc"> + <normaloff>:/newPrefix/format-justify-left.png</normaloff>:/newPrefix/format-justify-left.png</iconset> + </property> + <property name="text"> + <string>Align &Left</string> + </property> + <property name="shortcut"> + <string>Ctrl+L</string> + </property> + </action> + <action name="actionAlignRight"> + <property name="icon"> + <iconset resource="../Resource_Files/main/main.qrc"> + <normaloff>:/newPrefix/format-justify-right.png</normaloff>:/newPrefix/format-justify-right.png</iconset> + </property> + <property name="text"> + <string>Align &Right</string> + </property> + <property name="shortcut"> + <string>Ctrl+R</string> + </property> + </action> + <action name="actionCenter"> + <property name="icon"> + <iconset resource="../Resource_Files/main/main.qrc"> + <normaloff>:/newPrefix/format-justify-center.png</normaloff>:/newPrefix/format-justify-center.png</iconset> + </property> + <property name="text"> + <string>&Center</string> + </property> + <property name="shortcut"> + <string>Ctrl+E</string> + </property> + </action> + <action name="actionJustify"> + <property name="icon"> + <iconset resource="../Resource_Files/main/main.qrc"> + <normaloff>:/newPrefix/format-justify-fill.png</normaloff>:/newPrefix/format-justify-fill.png</iconset> + </property> + <property name="text"> + <string>&Justify</string> + </property> + <property name="shortcut"> + <string>Ctrl+J</string> + </property> + </action> + <action name="actionBold"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="icon"> + <iconset resource="../Resource_Files/main/main.qrc"> + <normaloff>:/newPrefix/format-text-bold.png</normaloff>:/newPrefix/format-text-bold.png</iconset> + </property> + <property name="text"> + <string>&Bold</string> + </property> + <property name="shortcut"> + <string>Ctrl+B</string> + </property> + </action> + <action name="actionItalic"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="icon"> + <iconset resource="../Resource_Files/main/main.qrc"> + <normaloff>:/newPrefix/format-text-italic.png</normaloff>:/newPrefix/format-text-italic.png</iconset> + </property> + <property name="text"> + <string>&Italic</string> + </property> + <property name="shortcut"> + <string>Ctrl+I</string> + </property> + </action> + <action name="actionOpen"> + <property name="icon"> + <iconset resource="../Resource_Files/main/main.qrc"> + <normaloff>:/newPrefix/document-open.png</normaloff>:/newPrefix/document-open.png</iconset> + </property> + <property name="text"> + <string>&Open...</string> + </property> + <property name="shortcut"> + <string>Ctrl+O</string> + </property> + </action> + <action name="actionUnderline"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="icon"> + <iconset resource="../Resource_Files/main/main.qrc"> + <normaloff>:/newPrefix/format-text-underline.png</normaloff>:/newPrefix/format-text-underline.png</iconset> + </property> + <property name="text"> + <string>&Underline</string> + </property> + <property name="shortcut"> + <string>Ctrl+U</string> + </property> + </action> + <action name="actionExit"> + <property name="icon"> + <iconset resource="../Resource_Files/main/main.qrc"> + <normaloff>:/newPrefix/process-stop.png</normaloff>:/newPrefix/process-stop.png</iconset> + </property> + <property name="text"> + <string>&Exit</string> + </property> + <property name="toolTip"> + <string>Exit</string> + </property> + <property name="shortcut"> + <string>Ctrl+Q</string> + </property> + </action> + <action name="actionAbout"> + <property name="icon"> + <iconset resource="../Resource_Files/main/main.qrc"> + <normaloff>:/newPrefix/help-browser.png</normaloff>:/newPrefix/help-browser.png</iconset> + </property> + <property name="text"> + <string>&About...</string> + </property> + <property name="toolTip"> + <string>About</string> + </property> + </action> + <action name="actionMetaEditor"> + <property name="text"> + <string>&Meta Editor...</string> + </property> + <property name="toolTip"> + <string>Meta information editor</string> + </property> + <property name="shortcut"> + <string>F8</string> + </property> + </action> + <action name="actionBookView"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="icon"> + <iconset resource="../Resource_Files/main/main.qrc"> + <normaloff>:/newPrefix/view-book.png</normaloff>:/newPrefix/view-book.png</iconset> + </property> + <property name="text"> + <string>&Book View</string> + </property> + <property name="toolTip"> + <string>Book View</string> + </property> + <property name="shortcut"> + <string>F9</string> + </property> + </action> + <action name="actionSplitView"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="icon"> + <iconset resource="../Resource_Files/main/main.qrc"> + <normaloff>:/newPrefix/view-split.png</normaloff>:/newPrefix/view-split.png</iconset> + </property> + <property name="text"> + <string>&Split View</string> + </property> + <property name="toolTip"> + <string>Split View</string> + </property> + <property name="shortcut"> + <string>F10</string> + </property> + </action> + <action name="actionCodeView"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="icon"> + <iconset resource="../Resource_Files/main/main.qrc"> + <normaloff>:/newPrefix/view-code.png</normaloff>:/newPrefix/view-code.png</iconset> + </property> + <property name="text"> + <string>&Code View</string> + </property> + <property name="toolTip"> + <string>Code View</string> + </property> + <property name="shortcut"> + <string>F11</string> + </property> + </action> + <action name="actionInsertChapterBreak"> + <property name="icon"> + <iconset resource="../Resource_Files/main/main.qrc"> + <normaloff>:/newPrefix/insert-chapter-break.png</normaloff>:/newPrefix/insert-chapter-break.png</iconset> + </property> + <property name="text"> + <string>&Chapter Break</string> + </property> + <property name="toolTip"> + <string>Insert Chapter Break + +Chapter breaks split your document into +multiple XHTML documents (where supported). +Use them often and where appropriate.</string> + </property> + <property name="shortcut"> + <string>Ctrl+Return</string> + </property> + </action> + <action name="actionInsertImage"> + <property name="icon"> + <iconset resource="../Resource_Files/main/main.qrc"> + <normaloff>:/newPrefix/insert-image.png</normaloff>:/newPrefix/insert-image.png</iconset> + </property> + <property name="text"> + <string>&Image...</string> + </property> + <property name="toolTip"> + <string>Insert Image</string> + </property> + <property name="shortcut"> + <string>Ctrl+Shift+I</string> + </property> + </action> + <action name="actionInsertNumberedList"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="icon"> + <iconset resource="../Resource_Files/main/main.qrc"> + <normaloff>:/newPrefix/insert-numbered-list.png</normaloff>:/newPrefix/insert-numbered-list.png</iconset> + </property> + <property name="text"> + <string>&Numbered List</string> + </property> + <property name="toolTip"> + <string>Insert Numbered List</string> + </property> + <property name="shortcut"> + <string>Ctrl+Alt+L</string> + </property> + </action> + <action name="actionInsertBulletedList"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="icon"> + <iconset resource="../Resource_Files/main/main.qrc"> + <normaloff>:/newPrefix/insert-bullet-list.png</normaloff>:/newPrefix/insert-bullet-list.png</iconset> + </property> + <property name="text"> + <string>Bulle&ted List</string> + </property> + <property name="toolTip"> + <string>Insert Bulleted List</string> + </property> + <property name="shortcut"> + <string>Ctrl+Shift+L</string> + </property> + </action> + <action name="actionTOCEditor"> + <property name="text"> + <string>&TOC Editor...</string> + </property> + <property name="shortcut"> + <string>F7</string> + </property> + </action> + <action name="actionStrikethrough"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="icon"> + <iconset resource="../Resource_Files/main/main.qrc"> + <normaloff>:/newPrefix/format-text-strikethrough.png</normaloff>:/newPrefix/format-text-strikethrough.png</iconset> + </property> + <property name="text"> + <string>Strike&through</string> + </property> + <property name="toolTip"> + <string>Strikethrough</string> + </property> + <property name="shortcut"> + <string>Ctrl+T</string> + </property> + </action> + </widget> + <customwidgets> + <customwidget> + <class>QWebView</class> + <extends>QWidget</extends> + <header>QtWebKit/QWebView</header> + </customwidget> + </customwidgets> + <resources> + <include location="../Resource_Files/main/main.qrc"/> + </resources> + <connections/> +</ui> diff --git a/src/Sigil/Headings.cpp b/src/Sigil/Headings.cpp new file mode 100644 index 0000000000..c03ed9c705 --- /dev/null +++ b/src/Sigil/Headings.cpp @@ -0,0 +1,316 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see <http://www.gnu.org/licenses/>. +** +*************************************************************************/ + +#include "stdafx.h" +#include "Headings.h" + +// The maximum allowed distance (in characters) that a heading +// can be located from a chapter break (or body tag) and still +// be detected as the "name" for that chapter; +// The value was picked arbitrarily +static const int CHAPTER_TO_HEADING_DIST = 1000; + +// Use with <QRegExp>.setMinimal( true ) +const QString HEADING = "<\\s*(?:h|H)\\d[^>]*>(.*)</\\s*(?:h|H)\\d[^>]*>"; + +static const QString NOT_IN_TOC_CLASS = "sigilNotInTOC"; +static const QString TOC_CLASS_PRESENT = "(<[^>]*)" + NOT_IN_TOC_CLASS + "([^>]*>)"; +static const QString CLASS_ATTRIBUTE = "<[^>]*class\\s*=\\s*\"([^\"]+)\"[^>]*>"; +static const QString ID_ATTRIBUTE = "<[^>]*id\\s*=\\s*\"([^\"]+)\"[^>]*>"; +static const QString ELEMENT_BODY = "<([^/>]+)>"; +static const QString HEADING_LEVEL = "(?:h|H)(\\d)"; + + +// Constructs the new heading element source +// created from the provided heading struct +QString Headings::GetNewHeadingSource( const Heading &heading ) +{ + QString source = heading.element_source; + + // We first remove our TOC class if it's present + QRegExp sigil_class( TOC_CLASS_PRESENT ); + source.replace( sigil_class, "\\1\\2" ); + + // If the heading should be included, + // that's it, return what we have + if ( heading.include_in_toc == true ) + + return source; + + // Otherwise add our not-in-TOC CSS class + + QRegExp class_reg( CLASS_ATTRIBUTE ); + + // If the element already has a class attribute, + // we add our TOC class to the list of classes + if ( source.indexOf( class_reg ) != -1 ) + { + QString new_class_value = class_reg.cap( 1 ) + " " + NOT_IN_TOC_CLASS; + QString new_class = class_reg.cap( 0 ).replace( class_reg.cap( 1 ), new_class_value ); + + source.replace( class_reg, new_class ); + } + + // Otherwise we create the class attribute too + else + { + QRegExp element( ELEMENT_BODY ); + + source.indexOf( element ); + + QString new_element_body = element.cap( 1 ) + " class=\"" + NOT_IN_TOC_CLASS + "\""; + QString new_element = element.cap( 0 ).replace( element.cap( 1 ), new_element_body ); + + source.replace( element, new_element ); + } + + return source; +} + + +// Returns a list of headings from the provided XHTML source; +// the list is flat, the headings are *not* in a hierarchy tree +QList< Headings::Heading > Headings::GetHeadingList( const QString &source ) +{ + QList< Heading > heading_list; + + QRegExp heading_regex( HEADING ); + heading_regex.setMinimal( true ); + + int main_index = 0; + + while ( true ) + { + main_index = source.indexOf( heading_regex, main_index ); + + if ( main_index == -1 ) + + break; + + Heading heading; + + heading.element_source = heading_regex.cap( 0 ); + heading.text = heading_regex.cap( 1 ); + heading.after_chapter_break = IsAfterChapterBreak( source, main_index ); + + QRegExp level( HEADING_LEVEL ); + heading_regex.cap( 0 ).indexOf( level ); + + heading.level = level.cap( 1 ).toInt(); + + QRegExp id( ID_ATTRIBUTE ); + heading_regex.cap( 0 ).indexOf( id ); + + heading.id = id.cap( 1 ); + + QRegExp sigil_class( TOC_CLASS_PRESENT ); + + if ( heading_regex.cap( 0 ).indexOf( sigil_class ) != -1 ) + + heading.include_in_toc = false; + + else + + heading.include_in_toc = true; + + heading_list.append( heading ); + + main_index += heading_regex.matchedLength(); + } + + return heading_list; +} + + +// Takes a flat list of headings and returns a list with those +// headings sorted into a hierarchy +QList< Headings::Heading > Headings::MakeHeadingHeirarchy( const QList< Heading > &headings ) +{ + QList< Heading > ordered_headings = ExcludeHeadingsAboveRoot( headings, GetRootHeadingLevel( headings ) ); + + for ( int i = 0; i < ordered_headings.size(); i++ ) + { + // As long as the headings after this one are + // higher in level (smaller in size), we continue + // adding them as this heading's children + while ( true ) + { + if ( ( i == ordered_headings.size() - 1 ) || + ( ordered_headings[ i + 1 ].level <= ordered_headings[ i ].level ) + ) + { + break; + } + + AddChildHeading( ordered_headings[ i ], ordered_headings[ i + 1 ] ); + + // The removeAt function will "push down" the rest + // of the elements in the list by one after + // it removes this element + ordered_headings.removeAt( i + 1 ); + } + } + + return ordered_headings; +} + + +// Takes a hierarchical list of headings and returns a flat list of them +QList< Headings::Heading > Headings::GetFlattenedHeadings( const QList< Heading > &headings ) +{ + QList< Heading > flat_headings; + + foreach( Heading heading, headings ) + { + flat_headings.append( FlattenHeadingNode( heading ) ); + } + + return flat_headings; +} + + +// Flattens the provided heading node and its children +// into a list and returns it +QList< Headings::Heading > Headings::FlattenHeadingNode( Heading heading ) +{ + QList< Heading > my_headings; + + my_headings.append( heading ); + + foreach( Heading child_heading, heading.children ) + { + my_headings.append( FlattenHeadingNode( child_heading ) ); + } + + return my_headings; +} + + +// Returns true if the provided heading location +// appears within 1000 chars after a chapter break +bool Headings::IsAfterChapterBreak( const QString &source, int heading_location ) +{ + // Our search is between search_start and heading_location + int search_start = heading_location - CHAPTER_TO_HEADING_DIST; + + if ( search_start < 0 ) + + search_start = 0; + + QRegExp chapter_break_tag( BREAK_TAG ); + int chapter_location = source.lastIndexOf( chapter_break_tag, heading_location - 1 ); + + // We look for a heading that appears before "this one" + // because we need to make sure we don't "assign" + // a chapter break that is already "taken" + QRegExp heading_regex( HEADING ); + heading_regex.setMinimal( true ); + int previous_heading_location = source.lastIndexOf( heading_regex, heading_location - 1 ); + + QRegExp body_tag( BODY_START ); + int body_tag_location = source.lastIndexOf( body_tag, heading_location - 1 ); + + // The tags are considered "found" if they appear within our search interval + bool chapter_tag_found = ( chapter_location != -1 ) && ( chapter_location > search_start ); + bool body_tag_found = ( body_tag_location != -1 ) && ( body_tag_location > search_start ); + + // There is no need to check that chapter_location and body_tag_location + // are greater than -1 because if they're both aren't, the next IF is false anyway + bool previous_heading_found = ( previous_heading_location != -1 ) && ( previous_heading_location > search_start ) && + ( previous_heading_location > chapter_location ) && ( previous_heading_location > body_tag_location ); + + if ( ( chapter_tag_found || body_tag_found ) && !previous_heading_found ) + + return true; + + else + + return false; +} + + +// Adds the new_child heading to the parent heading; +// the new_child is propagated down the tree if necessary +void Headings::AddChildHeading( Heading &parent, Heading new_child ) +{ + if ( ( !parent.children.isEmpty() ) && + ( parent.children.last().level < new_child.level ) + ) + { + AddChildHeading( parent.children.last(), new_child ); + } + + else + { + parent.children.append( new_child ); + } +} + + +// Returns the root heading level; the root level is +// considered to be the level with the max number of +// headings that appear after a chapter break +int Headings::GetRootHeadingLevel( const QList< Heading > &headings ) +{ + // Used to count the number of + // chapter breaks per level; + // the keys are levels, the values + // are the number of chapter breaks per that level + QHash< int, int > chapters_per_level; + + foreach( Heading heading, headings ) + { + if ( heading.after_chapter_break == true ) + + chapters_per_level[ heading.level ] = chapters_per_level.value( heading.level, 0 ) + 1 ; + } + + int maxvalue = 0; + int maxvalue_key = 0; + + foreach( int key, chapters_per_level.keys() ) + { + if ( chapters_per_level[ key ] > maxvalue ) + { + maxvalue = chapters_per_level[ key ]; + maxvalue_key = key; + } + } + + return maxvalue_key; +} + + +// Sets include_in_toc to false to those +// headings that appear above the root +QList< Headings::Heading > Headings::ExcludeHeadingsAboveRoot( const QList< Heading > &headings, int root_level ) +{ + QList< Heading > included_headings = headings; + + for ( int i = 0; i < included_headings.count(); i++ ) + { + if ( included_headings[ i ].level < root_level ) + + included_headings[ i ].include_in_toc = false; + } + + return included_headings; +} diff --git a/src/Sigil/Headings.h b/src/Sigil/Headings.h new file mode 100644 index 0000000000..46d610ba7f --- /dev/null +++ b/src/Sigil/Headings.h @@ -0,0 +1,119 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see <http://www.gnu.org/licenses/>. +** +*************************************************************************/ + +#pragma once +#ifndef HEADINGS_H +#define HEADINGS_H + +#include <QString> + +class Headings +{ + +public: + + // Describes a heading element found + // in the XHTML source code + struct Heading + { + // The whole source of the element; for instance: + // <h1 class="something">I'm a heading!</h1> + QString element_source; + + // The value of the ID attribute of the heading; + // NULL if heading doesn't have the attribute set + QString id; + + // The text value of the heading; for instance: + // I'm a heading! + QString text; + + // The level of the heading, from 1 to 6 + // (lower number means 'bigger' heading ) + int level; + + // True if the heading appears within + // 1000 chars after a chapter break + bool after_chapter_break; + + // Should the heading be included in the TOC or not + bool include_in_toc; + + // The headings 'below' this one + // (appear after it in the source and + // are of higher level/smaller size) + QList< Heading > children; + }; + + // A wrapper struct for the pointer + // because of restrictions on what + // can be stored inside a QVariant + struct HeadingPointer + { + Heading *heading; + }; + + // Constructs the new heading element source + // created from the provided heading struct + static QString GetNewHeadingSource( const Heading &heading ); + + // Returns a list of headings from the provided XHTML source; + // the list is flat, the headings are *not* in a hierarchy tree + static QList< Heading > GetHeadingList( const QString &source ); + + // Takes a flat list of headings and returns a list with those + // headings sorted into a hierarchy + static QList< Heading > MakeHeadingHeirarchy( const QList< Heading > &headings ); + + // Takes a hierarchical list of headings and returns a flat list of them + static QList< Heading > GetFlattenedHeadings( const QList< Heading > &headings ); + +private: + + // Flattens the provided heading node and its children + // into a list and returns it + static QList< Heading > FlattenHeadingNode( Heading heading ); + + // Returns true if the provided heading location + // appears within 1000 chars after a chapter break + static bool IsAfterChapterBreak( const QString &source, int heading_location ); + + // Adds the new_child heading to the parent heading; + // the new_child is propagated down the tree if necessary + static void AddChildHeading( Heading &parent, Heading new_child ); + + // Returns the root heading level; the root level is + // considered to be the level with the max number of + // headings that appear after a chapter break + static int GetRootHeadingLevel( const QList< Heading > &headings ); + + // Sets include_in_toc to false to those + // headings that appear above the root + static QList< Heading > ExcludeHeadingsAboveRoot( const QList< Heading > &headings, int root_level ); +}; + + +// Enables us to store instances of the +// HeadingPointer struct inside of QVariants +Q_DECLARE_METATYPE( Headings::HeadingPointer ); + + +#endif // HEADINGS_H diff --git a/src/Sigil/ImportEPUB.cpp b/src/Sigil/ImportEPUB.cpp new file mode 100644 index 0000000000..dcb4524ad5 --- /dev/null +++ b/src/Sigil/ImportEPUB.cpp @@ -0,0 +1,417 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see <http://www.gnu.org/licenses/>. +** +*************************************************************************/ + +#include "ImportEPUB.h" +#include "CleanSource.h" +#include "Utility.h" +#include "Metadata.h" +#include <ZipArchive.h> +#include "stdafx.h" + + +// Constructor; +// The parameter is the file to be imported +ImportEPUB::ImportEPUB( const QString &fullfilepath ) + : ImportHTML( fullfilepath ) +{ + +} + + +// Destructor +ImportEPUB::~ImportEPUB() +{ + if ( !m_ExtractedFolderPath.isEmpty() ) + + Utility::DeleteFolderAndFiles( m_ExtractedFolderPath ); +} + + +// Reads and parses the file +// and returns the created Book +Book ImportEPUB::GetBook() +{ + if ( !IsFileReadable() ) + + return Book(); + + // These read the EPUB file + ExtractContainer(); + LocateOPF(); + ReadOPF(); + + // These mutate the bkBook object + LoadMetadata(); + LoadSource(); + AddHeaderToSource(); + LoadFolderStructure(); + + m_Book.source = CleanSource::Clean( m_Book.source ); + + return m_Book; +} + + +// Extracts the EPUB file to a temporary folder; +// the path to this folder is stored in m_ExtractedFolderPath +void ImportEPUB::ExtractContainer() +{ + QDir folder( Utility::GetNewTempFolderPath() ); + + m_ExtractedFolderPath = folder.absolutePath(); + + folder.mkpath( m_ExtractedFolderPath ); + + CZipArchive zip; + +#ifdef Q_WS_WIN + zip.Open( m_FullFilePath.utf16(), CZipArchive::zipOpenReadOnly ); +#else + zip.Open( m_FullFilePath.toUtf8().data(), CZipArchive::zipOpenReadOnly ); +#endif + + int file_count = (int) zip.GetCount(); + + for ( int i = 0; i < file_count; i++ ) + { + #ifdef Q_WS_WIN + zip.ExtractFile( i, folder.absolutePath().utf16() ); + #else + zip.ExtractFile( i, folder.absolutePath().toUtf8().data() ); + #endif + } + + zip.Close(); +} + + +// Locates the OPF file in the extracted folder; +// the path to the OPF is stored in m_OPFFilePath +void ImportEPUB::LocateOPF() +{ + QDir folder( m_ExtractedFolderPath ); + + folder.cd( "META-INF" ); + + QString fullpath = folder.absoluteFilePath( "container.xml" ); + + QFile file( fullpath ); + + // Check if we can open the file + if ( !file.open( QFile::ReadOnly | QFile::Text ) ) + { + QMessageBox::warning( 0, + QObject::tr( "Sigil" ), + QObject::tr("Cannot read file %1:\n%2.") + .arg( fullpath ) + .arg( file.errorString() ) + ); + return; + } + + QTextStream in( &file ); + + // Input should be UTF-8 + in.setCodec( "UTF-8" ); + + QString container_xml = in.readAll(); + + QRegExp opf_search( "\"([^\">]+\\.opf)\"" ); + + container_xml.indexOf( opf_search ); + + m_OPFFilePath = m_ExtractedFolderPath + "/" + opf_search.cap( 1 ); +} + + +// Parses the OPF file and stores the parsed information +// inside m_MetaElements, m_Files and m_ReadingOrderIds +void ImportEPUB::ReadOPF() +{ + QFile file( m_OPFFilePath ); + + // Check if we can open the file + if ( !file.open( QFile::ReadOnly | QFile::Text ) ) + { + QMessageBox::warning( 0, + QObject::tr( "Sigil" ), + QObject::tr("Cannot read file %1:\n%2.") + .arg( m_OPFFilePath ) + .arg( file.errorString() ) + ); + return; + } + + QXmlStreamReader opf( &file ); + + while ( !opf.atEnd() ) + { + // Get the next token from the stream + QXmlStreamReader::TokenType type = opf.readNext(); + + if ( type == QXmlStreamReader::StartElement ) + { + // Parse and store Dublin Core metadata elements + if ( opf.qualifiedName().toString().startsWith( "dc:" ) == true ) + { + MetaElement meta; + + // We create a copy of the attributes because + // the QXmlStreamAttributes die out after we + // move away from the token + foreach( QXmlStreamAttribute attribute, opf.attributes() ) + { + meta.attributes[ attribute.name().toString() ] = attribute.value().toString(); + } + + meta.name = opf.name().toString(); + meta.value = opf.readElementText(); + + m_MetaElements.append( meta ); + } + + // Get the list of content files that + // make up the publication + else if ( opf.name() == "item" ) + { + QString id = opf.attributes().value( "", "id" ).toString(); + QString href = opf.attributes().value( "", "href" ).toString(); + + if ( !href.contains( ".ncx" ) ) + + m_Files[ id ] = href; + } + + // Get the list of XHTML files that + // represent the reading order + else if ( opf.name() == "itemref" ) + { + m_ReadingOrderIds.append( opf.attributes().value( "", "idref" ).toString() ); + } + } + } + + if ( opf.hasError() ) + { + // TODO: error handling + } + +} + +// Loads the metadata from the m_MetaElements list +// (filled by reading the OPF) into the book +void ImportEPUB::LoadMetadata() +{ + foreach( MetaElement meta, m_MetaElements ) + { + QString name = meta.name; + QVariant value = meta.value; + + if ( ( name == "creator" ) || ( name == "contributor" ) ) + { + QString role = meta.attributes.value( "role", "aut" ); + + // We convert the role into the new metadata name (e.g. aut -> Author) + name = Metadata::Instance().GetFullRelatorNameHash()[ role ]; + + // If a "file-as" attribute is provided, we use that as the value + QString file_as = meta.attributes.value( "file-as" ); + + if ( !file_as.isEmpty() ) + + value = file_as; + } + + else if ( name == "date" ) + { + QString date_event = meta.attributes.value( "event" ); + + if ( ( date_event == "creation" ) || + ( date_event == "publication" ) || + ( date_event == "modification" ) ) + { + name = date_event; + } + + else + { + name = "publication"; + } + + // Dates are in YYYY[-MM[-DD]] format + QStringList date_parts = meta.value.split( "-", QString::SkipEmptyParts ); + + if ( date_parts.count() < 3 ) + { + if ( date_parts.count() < 2 ) + { + date_parts.append( "01" ); + } + + date_parts.append( "01" ); + } + + value = QDate( date_parts[ 0 ].toInt(), date_parts[ 1 ].toInt(), date_parts[ 2 ].toInt() ); + } + + else if ( name == "identifier" ) + { + QString scheme = meta.attributes.value( "scheme" ); + + if ( ( scheme == "ISBN" ) || + ( scheme == "ISSN" ) || + ( scheme == "DOI" ) ) + { + name = scheme; + } + + else + { + // We don't store identifier elements without + // a recognizable scheme; such an identifier + // is arbitrary, so we might as well make our own + continue; + } + } + + else if ( name == "language" ) + { + // We convert the ISO 639-1 language code into the full language name + // (e.g. en -> English) + value = Metadata::Instance().GetFullLanguageNameHash()[ meta.value ]; + } + + QString capitalized_name = name[ 0 ].toUpper() + Utility::Substring( 1, name.length(), name ); + + m_Book.metadata[ capitalized_name ].append( value ); + } +} + + +// Loads the source code into the Book +void ImportEPUB::LoadSource() +{ + bool is_first_text_file = true; + + foreach( QString id, m_ReadingOrderIds ) + { + QString fullpath = QFileInfo( m_OPFFilePath ).absolutePath() + "/" + m_Files[ id ]; + + QFile file( fullpath ); + + // Check if we can open the file + if ( !file.open( QFile::ReadOnly | QFile::Text ) ) + { + QMessageBox::warning( 0, + QObject::tr( "Sigil" ), + QObject::tr( "Cannot read file %1:\n%2." ) + .arg( fullpath ) + .arg( file.errorString() ) + ); + return; + } + + QTextStream in( &file ); + + // Input should be UTF-8 + in.setCodec( "UTF-8" ); + + QString text = ResolveCustomEntities( in.readAll() ); + + // We extract the content of the files + // that is within the <body> tag + QRegExp body_start_tag( BODY_START ); + QRegExp body_end_tag( BODY_END ); + + int body_begin = text.indexOf( body_start_tag, 0 ) + body_start_tag.matchedLength(); + int body_end = text.indexOf( body_end_tag, 0 ); + + QString content = Utility::Substring( body_begin, body_end, text ); + + // We don't add the our chapter break tag + // for the first text file + if ( is_first_text_file == false ) + { + m_Book.source += "<hr class=\"sigilChapterBreak\" />\n" + content; + } + + else + { + m_Book.source += content; + + is_first_text_file = false; + } + } + + m_Book.source += "</body> </html>"; +} + + +// Adds the header to the Book source code +void ImportEPUB::AddHeaderToSource() +{ + // TODO: add title tag from metadata info + + QString header = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n" + " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\n" + "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" + "<head>\n"; + + // Creates <style> tags from CSS files + foreach( QString path, m_Files.values() ) + { + if ( path.contains( ".css" ) || path.contains( ".xpgt" ) ) + { + QString style_tag = CreateStyleTag( QFileInfo( m_OPFFilePath ).absolutePath() + "/" + path ); + + header += style_tag; + } + } + + header += "</head>\n<body>\n"; + + m_Book.source = header + m_Book.source; +} + +// Loads the referenced files into the main folder of the book; +// as the files get a new name, the references are updated +void ImportEPUB::LoadFolderStructure() +{ + foreach( QString key, m_Files.keys() ) + { + QString path = m_Files[ key ]; + + // We skip over the book text and style files + if ( ( !m_ReadingOrderIds.contains( key ) ) && + ( !path.contains( ".css" ) ) && + ( !path.contains( ".xpgt" ) ) + ) + { + QString fullfilepath = QFileInfo( m_OPFFilePath ).absolutePath() + "/" + path; + + QString newpath = m_Book.mainfolder.AddContentFileToFolder( fullfilepath ); + newpath = "../" + newpath; + + UpdateReferences( path, newpath ); + } + } +} diff --git a/src/Sigil/ImportEPUB.h b/src/Sigil/ImportEPUB.h new file mode 100644 index 0000000000..218e5253c4 --- /dev/null +++ b/src/Sigil/ImportEPUB.h @@ -0,0 +1,118 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see <http://www.gnu.org/licenses/>. +** +*************************************************************************/ + +#pragma once +#ifndef IMPORTEPUB_H +#define IMPORTEPUB_H + +#include "ImportHTML.h" +#include "FolderKeeper.h" + +#include <QHash> +#include <QStringList> + +class ImportEPUB : public ImportHTML +{ + +public: + + // Constructor; + // The parameter is the file to be imported + ImportEPUB( const QString &fullfilepath ); + + // Destructor + virtual ~ImportEPUB(); + + // Reads and parses the file + // and returns the created Book + virtual Book GetBook(); + +protected: + + // Extracts the EPUB file to a temporary folder; + // the path to this folder is stored in m_ExtractedFolderPath + void ExtractContainer(); + + // Locates the OPF file in the extracted folder; + // the path to the OPF is stored in m_OPFFilePath + void LocateOPF(); + + // Parses the OPF file and stores the parsed information + // inside m_MetaElements, m_Files and m_ReadingOrderIds + void ReadOPF(); + + // Loads the metadata from the m_MetaElements list + // (filled by reading the OPF) into the book + void LoadMetadata(); + + // Loads the source code into the Book + void virtual LoadSource(); + + // Adds the header to the Book source code + void AddHeaderToSource(); + + // Loads the referenced files into the main folder of the book; + // as the files get a new name, the references are updated + void LoadFolderStructure(); + + + /////////////////////////////// + // PROTECTED MEMBER VARIABLES + /////////////////////////////// + + // The full path to the folder where the + // EPUB was extracted to + QString m_ExtractedFolderPath; + + // The full path to the OPF file + // of the publication + QString m_OPFFilePath; + + // The map of all the files in the publication's + // manifest; The keys are the element ID's, + // the values are stored paths to the files + QMap< QString, QString > m_Files; + + // The list of ID's to the files in the manifest + // that represent the reading order of the publication + QStringList m_ReadingOrderIds; + + // Defines the metadata elements in the OPF + struct MetaElement + { + // The name of the element + QString name; + + // The value of the element + QString value; + + // The attributes of the element; + // the keys are the attribute names, + // the values are the attribute values + QHash< QString, QString > attributes; + }; + + // The list of metadata elements in the OPF + QList< MetaElement > m_MetaElements; + +}; + +#endif // IMPORTEPUB_H \ No newline at end of file diff --git a/src/Sigil/ImportHTML.cpp b/src/Sigil/ImportHTML.cpp new file mode 100644 index 0000000000..2d1273f1d0 --- /dev/null +++ b/src/Sigil/ImportHTML.cpp @@ -0,0 +1,233 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see <http://www.gnu.org/licenses/>. +** +*************************************************************************/ + +#include "ImportHTML.h" +#include "Utility.h" +#include "CleanSource.h" +#include "stdafx.h" + + +// Constructor; +// The parameter is the file to be imported +ImportHTML::ImportHTML( const QString &fullfilepath ) + : ImportTXT( fullfilepath ) +{ + +} + +// Reads and parses the file +// and returns the created Book +Book ImportHTML::GetBook() +{ + if ( !IsFileReadable() ) + + return Book(); + + LoadSource(); + LoadFolderStructure(); + + m_Book.source = CleanSource::Clean( m_Book.source ); + + return m_Book; +} + + +// Returns a style tag created +// from the provided path to a CSS file +QString ImportHTML::CreateStyleTag( const QString &fullfilepath ) +{ + QFile file( fullfilepath ); + + // Check if we can open the file + if ( !file.open( QFile::ReadOnly | QFile::Text ) ) + { + QMessageBox::warning( 0, + QObject::tr( "Sigil" ), + QObject::tr( "Cannot read file %1:\n%2." ) + .arg( fullfilepath ) + .arg( file.errorString() ) + ); + return ""; + } + + QTextStream in( &file ); + + // Input should be UTF-8 + in.setCodec( "UTF-8" ); + + QString style_tag = ""; + + if ( QFileInfo( fullfilepath ).suffix() == "css" ) + { + style_tag = "<style type=\"text/css\">\n" + in.readAll() + "\n</style>\n"; + } + + else // XPGT stylesheet + { + style_tag = "<style type=\"application/vnd.adobe-page-template+xml\">\n" + in.readAll() + "\n</style>\n"; + } + + return style_tag; +} + + +// Updates all references to the resource specified with oldpath +// to the path of the new resource specified with newpath +void ImportHTML::UpdateReferences( const QString &oldpath, const QString &newpath ) +{ + QString filename = QFileInfo( oldpath ).fileName(); + + QRegExp reference; + + // Fonts get searched for differently than the other resources + if ( ( filename.contains( ".ttf" ) ) || ( filename.contains( ".otf" ) ) ) + + reference = QRegExp( "src:\\s*\\w+\\(([^\\)]*" + filename + ")\\)" ); + + else + + reference = QRegExp( "<[^>]*\"([^\">]*" + filename + ")\"[^>]*>" ); + + int index = -1; + + while ( true ) + { + int newindex = m_Book.source.indexOf( reference ); + + // We need to make sure we don't end up + // replacing the same thing over and over again + if ( ( index == newindex ) || ( newindex == -1 ) ) + + break; + + m_Book.source.replace( reference.cap( 1 ), newpath ); + + index = newindex; + } +} + + +// Resolves custom ENTITY declarations +QString ImportHTML::ResolveCustomEntities( const QString &html_source ) +{ + QString source = html_source; + + QRegExp entity_search( "<!ENTITY\\s+(\\w+)\\s+\"([^\"]+)\">" ); + + QHash< QString, QString > entities; + + int main_index = 0; + + // Catch all custom entity declarations... + while ( true ) + { + main_index = source.indexOf( entity_search, main_index ); + + if ( main_index == -1 ) + + break; + + entities[ "&" + entity_search.cap( 1 ) + ";" ] = entity_search.cap( 2 ); + + // Erase the entity declaration + source.replace( entity_search.cap( 0 ), "" ); + } + + // ...and now replace all occurrences + foreach( QString key, entities.keys() ) + { + source.replace( key, entities[ key ] ); + } + + // Clean up what's left of the custom entity declaration field + source.replace( QRegExp( "\\[\\s*\\]>" ), "" ); + + return source; +} + +// Loads the source code into the Book +void ImportHTML::LoadSource() +{ + QFile file( m_FullFilePath ); + + // Check if we can open the file + if ( !file.open( QFile::ReadOnly | QFile::Text ) ) + { + QMessageBox::warning( 0, + QObject::tr( "Sigil" ), + QObject::tr("Cannot read file %1:\n%2.") + .arg( m_FullFilePath ) + .arg( file.errorString() ) + ); + return; + } + + QByteArray data = file.readAll(); + + // Qt docs say Qt will take care of deleting + // any QTextCodec objects on application exit + m_Book.source = QTextCodec::codecForHtml( data, QTextCodec::codecForName( "UTF-8" ) )->toUnicode( data ); + m_Book.source = ResolveCustomEntities( m_Book.source ); +} + + +// Loads the referenced files into the main folder of the book; +// as the files get a new name, the references are updated +void ImportHTML::LoadFolderStructure() +{ + int index = 0; + + QString image = "<\\s*img[^>]*src\\s*=\\s*"; + QString linkel = "<\\s*link[^>]*href\\s*=\\s*"; + QString theurl = "\"([^\">]+)\""; + QString tail = "[^>]*>"; + + while ( true ) + { + QRegExp fileurl( "(?:" + image + "|" + linkel + ")" + theurl + tail ); + + index = m_Book.source.indexOf( fileurl, index ) + fileurl.matchedLength(); + + if ( index < 0 ) + + break; + + QDir folder( QFileInfo( m_FullFilePath ).absoluteDir() ); + + QString fullfilepath = QFileInfo( folder, fileurl.cap( 1 ) ).absoluteFilePath(); + + if ( !fullfilepath.contains( ".css" ) ) + { + QString newpath = "../" + m_Book.mainfolder.AddContentFileToFolder( fullfilepath ); + + UpdateReferences( fileurl.cap( 1 ), newpath ); + } + + else + { + QString style_tag = CreateStyleTag( fullfilepath ); + + m_Book.source.replace( fileurl.cap( 0 ), style_tag ); + } + } +} + + diff --git a/src/Sigil/ImportHTML.h b/src/Sigil/ImportHTML.h new file mode 100644 index 0000000000..d3d47364a7 --- /dev/null +++ b/src/Sigil/ImportHTML.h @@ -0,0 +1,65 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see <http://www.gnu.org/licenses/>. +** +*************************************************************************/ + +#pragma once +#ifndef IMPORTHTML_H +#define IMPORTHTML_H + +#include "ImportTXT.h" +#include "FolderKeeper.h" + +class ImportHTML : public ImportTXT +{ + +public: + + // Constructor; + // The parameter is the file to be imported + ImportHTML( const QString &fullfilepath ); + + // Reads and parses the file + // and returns the created Book + virtual Book GetBook(); + +protected: + + // Returns a style tag created + // from the provided path to a CSS file + QString CreateStyleTag( const QString &fullfilepath ); + + // Updates all references to the resource specified with oldpath + // to the path of the new resource specified with newpath + void UpdateReferences( const QString &oldpath, const QString &newpath ); + + // Resolves custom ENTITY declarations + QString ResolveCustomEntities( const QString &html_source ); + +private: + + // Loads the source code into the Book + void LoadSource(); + + // Loads the referenced files into the main folder of the book; + // as the files get a new name, the references are updated + void LoadFolderStructure(); +}; + +#endif // IMPORTHTML_H \ No newline at end of file diff --git a/src/Sigil/ImportSGF.cpp b/src/Sigil/ImportSGF.cpp new file mode 100644 index 0000000000..f91bdba729 --- /dev/null +++ b/src/Sigil/ImportSGF.cpp @@ -0,0 +1,59 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see <http://www.gnu.org/licenses/>. +** +*************************************************************************/ + +#include "stdafx.h" +#include "ImportSGF.h" + + +// Constructor; +// The parameter is the file to be imported +ImportSGF::ImportSGF( const QString &fullfilepath ) + : ImportEPUB( fullfilepath ) +{ + +} + +// Loads the source code into the Book +void ImportSGF::LoadSource() +{ + QString fullpath = QFileInfo( m_OPFFilePath ).absolutePath() + "/" + m_Files.values().first(); + + QFile file( fullpath ); + + // Check if we can open the file + if ( !file.open( QFile::ReadOnly | QFile::Text ) ) + { + QMessageBox::warning( 0, + QObject::tr( "Sigil" ), + QObject::tr("Cannot read file %1:\n%2.") + .arg( fullpath ) + .arg( file.errorString() ) + ); + return; + } + + QTextStream in( &file ); + + // Input should be UTF-8 + in.setCodec( "UTF-8" ); + + m_Book.source = in.readAll(); +} diff --git a/src/Sigil/ImportSGF.h b/src/Sigil/ImportSGF.h new file mode 100644 index 0000000000..24fe7a8f46 --- /dev/null +++ b/src/Sigil/ImportSGF.h @@ -0,0 +1,44 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see <http://www.gnu.org/licenses/>. +** +*************************************************************************/ + +#pragma once +#ifndef IMPORTSGF_H +#define IMPORTSGF_H + +#include "ImportEPUB.h" + +class ImportSGF : public ImportEPUB +{ + +public: + + // Constructor; + // The parameter is the file to be imported + ImportSGF( const QString &fullfilepath ); + +private: + + // Loads the source code into the Book + void LoadSource(); + +}; + +#endif // IMPORTSGF_H \ No newline at end of file diff --git a/src/Sigil/ImportTXT.cpp b/src/Sigil/ImportTXT.cpp new file mode 100644 index 0000000000..3d61a8eba4 --- /dev/null +++ b/src/Sigil/ImportTXT.cpp @@ -0,0 +1,124 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see <http://www.gnu.org/licenses/>. +** +*************************************************************************/ + +#include "ImportTXT.h" +#include "CleanSource.h" +#include "Utility.h" +#include "stdafx.h" + + +// Constructor; +// The parameter is the file to be imported +ImportTXT::ImportTXT( const QString &fullfilepath ) + : m_FullFilePath( fullfilepath ) +{ + +} + +// Reads and parses the file +// and returns the created Book +Book ImportTXT::GetBook() +{ + if ( !IsFileReadable() ) + + return Book(); + + LoadSource(); + + m_Book.source = CreateParagraphs( m_Book.source.split( QChar( '\n' ) ) ); + m_Book.source = CleanSource::Clean( m_Book.source ); + + return m_Book; +} + + +// Returns true if the file +// to be imported can be read +bool ImportTXT::IsFileReadable() +{ + QFile file( m_FullFilePath ); + + // Check if we can open the file + if ( !file.open( QFile::ReadOnly ) ) + { + QMessageBox::warning( 0, + QObject::tr( "Sigil" ), + QObject::tr( "Cannot read file %1:\n%2." ) + .arg( m_FullFilePath ) + .arg( file.errorString() ) + ); + return false; + } + + file.close(); + + return true; +} + + +// Loads the source code into the Book +void ImportTXT::LoadSource() +{ + QFile file( m_FullFilePath ); + + // Check if we can open the file + if ( !file.open( QFile::ReadOnly | QFile::Text ) ) + { + QMessageBox::warning( 0, + QObject::tr( "Sigil" ), + QObject::tr("Cannot read file %1:\n%2.") + .arg( m_FullFilePath ) + .arg( file.errorString() ) + ); + return; + } + + QTextStream in( &file ); + + // Input should be UTF-8 + in.setCodec( "UTF-8" ); + + m_Book.source = in.readAll(); +} + + +// Accepts a list of text lines and returns +// a string with paragraphs wrapped into <p> tags +QString ImportTXT::CreateParagraphs( const QStringList &lines ) +{ + QString text = ""; + + QString paragraph = "<p>"; + + foreach( QString line, lines ) + { + if ( ( line.isEmpty() ) || ( line[ 0 ].isSpace() ) ) + { + text += paragraph + "</p>\n"; + + paragraph = "<p>"; + } + + paragraph += line; + } + + return text; +} diff --git a/src/Sigil/ImportTXT.h b/src/Sigil/ImportTXT.h new file mode 100644 index 0000000000..9b7a86b789 --- /dev/null +++ b/src/Sigil/ImportTXT.h @@ -0,0 +1,70 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see <http://www.gnu.org/licenses/>. +** +*************************************************************************/ + +#pragma once +#ifndef IMPORTTXT_H +#define IMPORTTXT_H + +#include "Importer.h" +#include <QUrl> + +class ImportTXT : public Importer +{ + +public: + + // Constructor; + // The parameter is the file to be imported + ImportTXT( const QString &fullfilepath ); + + // Reads and parses the file + // and returns the created Book + virtual Book GetBook(); + +protected: + + // Returns true if the file + // to be imported can be read + bool IsFileReadable(); + + // Loads the source code into the Book + virtual void LoadSource(); + + + /////////////////////////////// + // PROTECTED MEMBER VARIABLES + /////////////////////////////// + + // The full path to the file to be imported + const QString &m_FullFilePath; + + // The Book that will be created + // by the importing process + Book m_Book; + +private: + + // Accepts a list of text lines and returns + // a string with paragraphs wrapped into <p> tags + QString CreateParagraphs( const QStringList &lines ); +}; + +#endif // IMPORTTXT_H \ No newline at end of file diff --git a/src/Sigil/Importer.h b/src/Sigil/Importer.h new file mode 100644 index 0000000000..73dbe0e9ac --- /dev/null +++ b/src/Sigil/Importer.h @@ -0,0 +1,39 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see <http://www.gnu.org/licenses/>. +** +*************************************************************************/ + +#pragma once +#ifndef IMPORTER_H +#define IMPORTER_H + +#include "Book.h" + +// Interface for Importers +class Importer +{ + +public: + + virtual ~Importer() {} + + virtual Book GetBook() = 0; +}; + +#endif // IMPORTER_H diff --git a/src/Sigil/ImporterFactory.cpp b/src/Sigil/ImporterFactory.cpp new file mode 100644 index 0000000000..de7d70d7d2 --- /dev/null +++ b/src/Sigil/ImporterFactory.cpp @@ -0,0 +1,87 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see <http://www.gnu.org/licenses/>. +** +*************************************************************************/ + +#include "stdafx.h" +#include "ImporterFactory.h" +#include "ImportTXT.h" +#include "ImportHTML.h" +#include "ImportEPUB.h" +#include "ImportSGF.h" + + +ImporterFactory::ImporterFactory() + : imImporter( NULL ) +{ + +} + + +ImporterFactory::~ImporterFactory() +{ + delete imImporter; +} + + +Importer& ImporterFactory::GetImporter( const QString &filename ) +{ + QString extension = QFileInfo( filename ).suffix(); + + if ( ( extension == "xhtml" ) || + ( extension == "html" ) || + ( extension == "htm" ) + ) + { + imImporter = new ImportHTML( filename ); + + return *imImporter; + } + + if ( ( extension == "txt" ) ) + { + imImporter = new ImportTXT( filename ); + + return *imImporter; + } + + if ( ( extension == "epub" ) ) + { + imImporter = new ImportEPUB( filename ); + + return *imImporter; + } + + if ( ( extension == "sgf" ) ) + { + imImporter = new ImportSGF( filename ); + + return *imImporter; + } + + // FIXME: Tell the user that the extension wasn't + // recognized and then offer a default method + // of loading (or maybe a list of methods?) + + // FIXME: should probably just be a TXT importer + imImporter = new ImportHTML( filename ); + + return *imImporter; +} + diff --git a/src/Sigil/ImporterFactory.h b/src/Sigil/ImporterFactory.h new file mode 100644 index 0000000000..97447f2579 --- /dev/null +++ b/src/Sigil/ImporterFactory.h @@ -0,0 +1,45 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see <http://www.gnu.org/licenses/>. +** +*************************************************************************/ + +#pragma once +#ifndef IMPORTERFACTORY_H +#define IMPORTERFACTORY_H + +#include "Importer.h" + +class ImporterFactory +{ + +public: + + ImporterFactory(); + + ~ImporterFactory(); + + Importer& GetImporter( const QString &filename ); + +private: + + Importer* imImporter; + +}; + +#endif // IMPORTERFACTORY_H \ No newline at end of file diff --git a/src/Sigil/MainWindow.cpp b/src/Sigil/MainWindow.cpp new file mode 100644 index 0000000000..356239c66b --- /dev/null +++ b/src/Sigil/MainWindow.cpp @@ -0,0 +1,1255 @@ +/************************************************************************ +** +** Copyright (C) 2009 Strahinja Markovic +** +** This file is part of Sigil. +** +** Sigil 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. +** +** Sigil 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 Sigil. If not, see <http://www.gnu.org/licenses/>. +** +*************************************************************************/ + +#include "stdafx.h" +#include "MainWindow.h" +#include "CleanSource.h" +#include "FolderKeeper.h" +#include "ExportEPUB.h" +#include "ExportSGF.h" +#include "XHTMLHighlighter.h" +#include "MetaEditor.h" +#include "About.h" +#include "TOCEditor.h" +#include "ImporterFactory.h" +#include "ExporterFactory.h" +#include "BookNormalization.h" +#include "SigilMarkup.h" + +static const int STATUSBAR_MSG_DISPLAY_TIME = 2000; +static const int TAB_SPACES_WIDTH = 4; +static const int TEXT_ELIDE_WIDTH = 300; + +static const QString CHAPTER_BREAK_TAG = "<hr class=\"sigilChapterBreak\" />"; + +// Constructor +MainWindow::MainWindow( QWidget *parent, Qt::WFlags flags ) + : QMainWindow( parent, flags ) +{ + ui.setupUi( this ); + + ExtendUI(); + + ConnectSignalsToSlots(); + + ReadSettings(); + + CreateRecentFilesActions(); + UpdateRecentFileActions(); + + SetUpCodeView(); + + ui.actionBookView->trigger(); + + m_isLastViewBook = true; + + New(); +} + + +// Overrides the closeEvent handler so we can check +// for saved status before actually closing +void MainWindow::closeEvent( QCloseEvent *event ) +{ + if ( MaybeSave() ) + { + WriteSettings(); + + event->accept(); + } + + else + { + event->ignore(); + } +} + + +// Implements New action functionality +void MainWindow::New() +{ + if ( MaybeSave() ) + { + m_Book = Book(); + + m_Book.source = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n" + " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\n" + "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" + "<head>\n" + "<title>\n" + "\n" + "\n" + + // The "nbsp" is here so that the user starts writing + // inside the

element; if it's not here, webkit + // inserts text _outside_ the

element + "

 

\n" + "\n" + ""; + + // Add Sigil-specific markup + m_Book.source = SigilMarkup::AddSigilMarkup( m_Book.source ); + + ui.wBookView->setHtml( m_Book.source, m_Book.GetBaseUrl() ); + ui.wBookView->page()->setContentEditable( true ); + ui.wBookView->page()->setLinkDelegationPolicy( QWebPage::DelegateAllLinks ); + + ui.wCodeView->setPlainText( m_Book.source ); + + SetCurrentFile( "" ); + } +} + + +// Implements Open action functionality +void MainWindow::Open() +{ + if ( MaybeSave() ) + { + QString filters = tr( "Sigil Format files (*.sgf);;" + "EPUB files (*.epub);;" + "HTML files (*.htm, *.html, *.xhtml);;" + "Text files (*.txt);;" + "All files (*.*)" + ); + + QString default_filter = tr( "All files (*.*)" ); + + QString filename = QFileDialog::getOpenFileName( this, + tr( "Open File" ), + m_LastFolderOpen, + filters, + &default_filter + ); + + if ( !filename.isEmpty() ) + { + // Store the folder the user opened from + m_LastFolderOpen = QFileInfo( filename ).absolutePath(); + + LoadFile( filename ); + } + } +} + + +// Implements Open recent file action functionality +void MainWindow::OpenRecentFile() +{ + QAction *action = qobject_cast< QAction *>( sender() ); + + if( action != NULL ) + + LoadFile( action->data().toString() ); +} + + +// Implements Save action functionality +bool MainWindow::Save() +{ + if ( m_CurrentFile.isEmpty() ) + { + return SaveAs(); + } + + else + { + return SaveFile( m_CurrentFile ); + } +} + + +// Implements Save As action functionality +bool MainWindow::SaveAs() +{ + QString filters = tr( "Sigil Format file (*.sgf);;EPUB file (*.epub)" ); + + QString default_filter = tr( "Sigil Format file (*.sgf)" ); + + QString filename = QFileDialog::getSaveFileName( this, + tr( "Save File" ), + m_LastFolderSave, + filters, + &default_filter + ); + + if ( filename.isEmpty() ) + + return false; + + // Store the folder the user saved to + m_LastFolderSave = QFileInfo( filename ).absolutePath(); + + return SaveFile( filename ); +} + + +// Implements Undo action functionality +void MainWindow::Undo() +{ + if ( ui.wBookView->hasFocus() ) + { + ui.wBookView->page()->triggerAction( QWebPage::Undo ); + + RemoveAppleClasses(); + } + + else if ( ui.wCodeView->hasFocus() ) + { + ui.wCodeView->undo(); + } +} + + +// Implements Redo action functionality +void MainWindow::Redo() +{ + if ( ui.wBookView->hasFocus() ) + { + ui.wBookView->page()->triggerAction( QWebPage::Redo ); + + RemoveAppleClasses(); + } + + else if ( ui.wCodeView->hasFocus() ) + { + ui.wCodeView->redo(); + } +} + + +// Implements Cut action functionality +void MainWindow::Cut() +{ + if ( ui.wBookView->hasFocus() ) + { + ui.wBookView->page()->triggerAction( QWebPage::Cut ); + + RemoveAppleClasses(); + } + + else if ( ui.wCodeView->hasFocus() ) + { + ui.wCodeView->cut(); + } +} + + +// Implements Copy action functionality +void MainWindow::Copy() +{ + if ( ui.wBookView->hasFocus() ) + { + ui.wBookView->page()->triggerAction( QWebPage::Copy ); + + RemoveAppleClasses(); + } + + else if ( ui.wCodeView->hasFocus() ) + { + ui.wCodeView->copy(); + } +} + + +// Implements Paste action functionality +void MainWindow::Paste() +{ + if ( ui.wBookView->hasFocus() ) + { + ui.wBookView->page()->triggerAction( QWebPage::Paste ); + + RemoveAppleClasses(); + } + + else if ( ui.wCodeView->hasFocus() ) + { + ui.wCodeView->paste(); + } +} + + +// Implements Bold action functionality +void MainWindow::Bold() +{ + if ( ui.wBookView->hasFocus() ) + { + ui.wBookView->page()->triggerAction( QWebPage::ToggleBold ); + + RemoveAppleClasses(); + } + + // TODO: insert required HTML for Code View +} + + +// Implements Italic action functionality +void MainWindow::Italic() +{ + if ( ui.wBookView->hasFocus() ) + { + ui.wBookView->page()->triggerAction( QWebPage::ToggleItalic ); + + RemoveAppleClasses(); + } + + // TODO: insert required HTML for Code View +} + + +// Implements Underline action functionality +void MainWindow::Underline() +{ + if ( ui.wBookView->hasFocus() ) + { + ui.wBookView->page()->triggerAction( QWebPage::ToggleUnderline ); + + RemoveAppleClasses(); + } + + // TODO: insert required HTML for Code View +} + + +// Implements Strikethrough action functionality +void MainWindow::Strikethrough() +{ + if ( ui.wBookView->hasFocus() ) + { + ExecCommand( "strikeThrough" ); + + RemoveAppleClasses(); + } + + // TODO: insert required HTML for Code View +} + + +// Implements Align Left action functionality +void MainWindow::AlignLeft() +{ + if ( ui.wBookView->hasFocus() ) + { + ExecCommand( "justifyLeft" ); + + RemoveAppleClasses(); + } + + // TODO: insert required HTML for Code View +} + + +// Implements Center action functionality +void MainWindow::Center() +{ + if ( ui.wBookView->hasFocus() ) + { + ExecCommand( "justifyCenter" ); + + RemoveAppleClasses(); + } + + // TODO: insert required HTML for Code View +} + + +// Implements Align Right action functionality +void MainWindow::AlignRight() +{ + if ( ui.wBookView->hasFocus() ) + { + ExecCommand( "justifyRight" ); + + RemoveAppleClasses(); + } + + // TODO: insert required HTML for Code View +} + + +// Implements Justify action functionality +void MainWindow::Justify() +{ + if ( ui.wBookView->hasFocus() ) + { + ExecCommand( "justifyFull" ); + + RemoveAppleClasses(); + } + + // TODO: insert required HTML for Code View +} + + +// Implements Book View action functionality +void MainWindow::BookView() +{ + QApplication::setOverrideCursor( Qt::WaitCursor ); + + // Update the book view if we just edited + // in the code view + if ( !m_isLastViewBook ) + + UpdateBookViewFromSource(); + + ui.wBookView->show(); + ui.wCodeView->hide(); + + // Update the "toggle" button states + ui.actionBookView->setChecked( true ); + ui.actionSplitView->setChecked( false ); + ui.actionCodeView->setChecked( false ); + + m_isLastViewBook = true; + + QApplication::restoreOverrideCursor(); +} + + +// Implements Split View action functionality +void MainWindow::SplitView() +{ + QApplication::setOverrideCursor( Qt::WaitCursor ); + + // Update the required view + if ( !m_isLastViewBook ) + + UpdateBookViewFromSource(); + + else + + UpdateCodeViewFromSource(); + + ui.wBookView->show(); + ui.wCodeView->show(); + + // Update the "toggle" button states + ui.actionBookView->setChecked( false ); + ui.actionSplitView->setChecked( true ); + ui.actionCodeView->setChecked( false ); + + QApplication::restoreOverrideCursor(); +} + + +// Implements Code View action functionality +void MainWindow::CodeView() +{ + QApplication::setOverrideCursor( Qt::WaitCursor ); + + // Update the code view if we just edited + // in the book view + if ( m_isLastViewBook ) + + UpdateCodeViewFromSource(); + + ui.wBookView->hide(); + ui.wCodeView->show(); + + // Update the "toggle" button states + ui.actionBookView->setChecked( false ); + ui.actionSplitView->setChecked( false ); + ui.actionCodeView->setChecked( true ); + + m_isLastViewBook = false; + + QApplication::restoreOverrideCursor(); +} + + +// Implements Insert chapter break action functionality +void MainWindow::InsertChapterBreak() +{ + ExecCommand( "insertHTML", CHAPTER_BREAK_TAG ); + + RemoveAppleClasses(); +} + + +// Implements Insert image action functionality +void MainWindow::InsertImage() +{ + // TODO: remember last folder from which we loaded an image + QString filename = QFileDialog::getOpenFileName( this, + tr( "Insert Image" ), + "", + tr( "Images (*.png *.jpg *.jpeg *.gif *.svg)") + ); + + if ( filename.isEmpty() ) + + return; + + QString relative_path = "../" + m_Book.mainfolder.AddContentFileToFolder( filename ); + + ExecCommand( "insertImage", relative_path ); + + RemoveAppleClasses(); +} + + +// Implements Insert bulleted list action functionality +void MainWindow::InsertBulletedList() +{ + ExecCommand( "insertUnorderedList" ); + + RemoveAppleClasses(); +} + + +// Implements Insert numbered list action functionality +void MainWindow::InsertNumberedList() +{ + ExecCommand( "insertOrderedList" ); + + RemoveAppleClasses(); +} + + +// Implements the heading combo box functionality +void MainWindow::HeadingStyle( const QString& heading_type ) +{ + QChar last_char = heading_type[ heading_type.count() - 1 ]; + + // For heading_type == "Heading #" + if ( last_char.isDigit() ) + + ExecCommand( "formatBlock", "H" + QString( last_char ) ); + + else if ( heading_type == "Normal" ) + + ExecCommand( "formatBlock", "P" ); + + // else is ""; + } + + m_cbHeadings->setCurrentIndex( m_cbHeadings->findText( select ) ); +} + + +// Initializes the code view +void MainWindow::SetUpCodeView() +{ + // Let's try to use Consolas as our font + QFont font( "Consolas", 10 ); + + // But just in case, say we want a fixed width font + // if Consolas is not on the system + font.setStyleHint( QFont::TypeWriter ); + + ui.wCodeView->setFont( font ); + ui.wCodeView->setTabStopWidth( TAB_SPACES_WIDTH * QFontMetrics( font ).width( ' ' ) ); + + m_Highlighter = new XHTMLHighlighter( ui.wCodeView->document() ); +} + + +// Creates and adds the recent files actions +// to the File menu +void MainWindow::CreateRecentFilesActions() +{ + for ( int i = 0; i < MAX_RECENT_FILES; ++i ) + { + m_RecentFileActions[ i ] = new QAction( this ); + + // The actions are not visible until we put a filename in them + m_RecentFileActions[ i ]->setVisible( false ); + + QList actlist = ui.menuFile->actions(); + + // Add the new action just below the Quit action + // and the separator behind it + ui.menuFile->insertAction( actlist[ actlist.size() - 2 ], m_RecentFileActions[ i ] ); + + connect( m_RecentFileActions[ i ], SIGNAL( triggered() ), this, SLOT( OpenRecentFile() ) ); + } +} + + +// Updates the recent files actions when the +// list of files to be listed has changed +void MainWindow::UpdateRecentFileActions() +{ + int num_recent_files = qMin( m_RecentFiles.size(), MAX_RECENT_FILES ); + + // Store the filenames to the actions and display those actions + for ( int i = 0; i < num_recent_files; ++i ) + { + QString text = tr( "&%1 %2" ).arg( i + 1 ).arg( QFileInfo( m_RecentFiles[ i ] ).fileName() ); + + m_RecentFileActions[ i ]->setText( fontMetrics().elidedText( text, Qt::ElideRight, TEXT_ELIDE_WIDTH ) ); + m_RecentFileActions[ i ]->setData( m_RecentFiles[ i ] ); + m_RecentFileActions[ i ]->setVisible( true ); + } + + // If we have fewer files than actions, hide the other actions + for ( int j = num_recent_files; j < MAX_RECENT_FILES; ++j ) + { + m_RecentFileActions[ j ]->setVisible( false ); + } + + QAction *separator = ui.menuFile->actions()[ ui.menuFile->actions().size() - 2 ]; + + // If we have any actions with files shown, + // display the separator; otherwise, don't + if ( num_recent_files > 0 ) + + separator->setVisible( true ); + + else + + separator->setVisible( false ); +} + + +// Qt Designer is not able to create all the widgets +// we want in the MainWindow, so we use this function +// to extend the UI created by the Designer +void MainWindow::ExtendUI() +{ + m_cbHeadings = new QComboBox(); + + QStringList headings; + + headings << " and ... */ + /* this doesn't handle which browsers treat as */ + /* 'foo"/' nor which browser treat as 'foo"' */ + + c = TY_(ReadChar)(doc->docIn); + if (c == '>') + { + TY_(AddCharToLexer)(lexer, q); + TY_(UngetChar)(c, doc->docIn); + break; + } + else + { + TY_(UngetChar)(c, doc->docIn); + c = q; + } + } + + if (c == '<') + { + TY_(UngetChar)(c, doc->docIn); + c = '>'; + TY_(UngetChar)(c, doc->docIn); + TY_(ReportAttrError)( doc, lexer->token, NULL, UNEXPECTED_GT ); + break; + } + + /* + For cases like
need to avoid treating /> as + part of the attribute value, however care is needed to avoid + so treating
in this way, which + would map the tag to + */ + if (c == '/') + { + /* peek ahead in case of /> */ + c = TY_(ReadChar)(doc->docIn); + + if ( c == '>' && !TY_(IsUrl)(doc, name) ) + { + *isempty = yes; + TY_(UngetChar)(c, doc->docIn); + break; + } + + /* unget peeked character */ + TY_(UngetChar)(c, doc->docIn); + c = '/'; + } + } + else /* delim is '\'' or '"' */ + { + if (c == delim) + break; + + if (c == '\n' || c == '<' || c == '>') + ++quotewarning; + + if (c == '>') + seen_gt = yes; + } + + if (c == '&') + { + TY_(AddCharToLexer)(lexer, c); + ParseEntity( doc, IgnoreWhitespace ); + if (lexer->lexbuf[lexer->lexsize - 1] == '\n' && munge) + ChangeChar(lexer, ' '); + continue; + } + + /* + kludge for JavaScript attribute values + with line continuations in string literals + */ + if (c == '\\') + { + c = TY_(ReadChar)(doc->docIn); + + if (c != '\n') + { + TY_(UngetChar)(c, doc->docIn); + c = '\\'; + } + } + + if (TY_(IsWhite)(c)) + { + if ( delim == 0 ) + break; + + if (munge) + { + /* discard line breaks in quoted URLs */ + /* #438650 - fix by Randy Waki */ + if ( c == '\n' && TY_(IsUrl)(doc, name) ) + { + /* warn that we discard this newline */ + TY_(ReportAttrError)( doc, lexer->token, NULL, NEWLINE_IN_URI); + continue; + } + + c = ' '; + + if (lastc == ' ') + { + if (TY_(IsUrl)(doc, name) ) + TY_(ReportAttrError)( doc, lexer->token, NULL, WHITE_IN_URI); + continue; + } + } + } + else if (foldCase && TY_(IsUpper)(c)) + c = TY_(ToLower)(c); + + TY_(AddCharToLexer)(lexer, c); + } + + if (quotewarning > 10 && seen_gt && munge) + { + /* + there is almost certainly a missing trailing quote mark + as we have see too many newlines, < or > characters. + + an exception is made for Javascript attributes and the + javascript URL scheme which may legitimately include < and >, + and for attributes starting with "lexbuf+start, "javascript:", 11) == 0) && + !(TY_(tmbstrncmp)(lexer->lexbuf+start, "lexsize - start; + lexer->lexsize = start; + + + if (len > 0 || delim) + { + /* ignore leading and trailing white space for all but title, alt, value */ + /* and prompts attributes unless --literal-attributes is set to yes */ + /* #994841 - Whitespace is removed from value attributes */ + + if (munge && + TY_(tmbstrcasecmp)(name, "alt") && + TY_(tmbstrcasecmp)(name, "title") && + TY_(tmbstrcasecmp)(name, "value") && + TY_(tmbstrcasecmp)(name, "prompt")) + { + while (TY_(IsWhite)(lexer->lexbuf[start+len-1])) + --len; + + while (TY_(IsWhite)(lexer->lexbuf[start]) && start < len) + { + ++start; + --len; + } + } + + value = TY_(tmbstrndup)(doc->allocator, lexer->lexbuf + start, len); + } + else + value = NULL; + + /* note delimiter if given */ + *pdelim = (delim ? delim : '"'); + + return value; +} + +/* attr must be non-NULL */ +static Bool IsValidAttrName( ctmbstr attr ) +{ + uint i, c = attr[0]; + + /* first character should be a letter */ + if (!TY_(IsLetter)(c)) + return no; + + /* remaining characters should be namechars */ + for( i = 1; i < TY_(tmbstrlen)(attr); i++) + { + c = attr[i]; + + if (TY_(IsNamechar)(c)) + continue; + + return no; + } + + return yes; +} + +/* create a new attribute */ +AttVal *TY_(NewAttribute)( TidyDocImpl* doc ) +{ + AttVal *av = (AttVal*) TidyDocAlloc( doc, sizeof(AttVal) ); + TidyClearMemory( av, sizeof(AttVal) ); + return av; +} + +/* create a new attribute with given name and value */ +AttVal* TY_(NewAttributeEx)( TidyDocImpl* doc, ctmbstr name, ctmbstr value, + int delim ) +{ + AttVal *av = TY_(NewAttribute)(doc); + av->attribute = TY_(tmbstrdup)(doc->allocator, name); + av->value = TY_(tmbstrdup)(doc->allocator, value); + av->delim = delim; + av->dict = TY_(FindAttribute)( doc, av ); + return av; +} + +static void AddAttrToList( AttVal** list, AttVal* av ) +{ + if ( *list == NULL ) + *list = av; + else + { + AttVal* here = *list; + while ( here->next ) + here = here->next; + here->next = av; + } +} + +void TY_(InsertAttributeAtEnd)( Node *node, AttVal *av ) +{ + AddAttrToList(&node->attributes, av); +} + +void TY_(InsertAttributeAtStart)( Node *node, AttVal *av ) +{ + av->next = node->attributes; + node->attributes = av; +} + +/* swallows closing '>' */ + +static AttVal* ParseAttrs( TidyDocImpl* doc, Bool *isempty ) +{ + Lexer* lexer = doc->lexer; + AttVal *av, *list; + tmbstr value; + int delim; + Node *asp, *php; + + list = NULL; + + while ( !EndOfInput(doc) ) + { + tmbstr attribute = ParseAttribute( doc, isempty, &asp, &php ); + + if (attribute == NULL) + { + /* check if attributes are created by ASP markup */ + if (asp) + { + av = TY_(NewAttribute)(doc); + av->asp = asp; + AddAttrToList( &list, av ); + continue; + } + + /* check if attributes are created by PHP markup */ + if (php) + { + av = TY_(NewAttribute)(doc); + av->php = php; + AddAttrToList( &list, av ); + continue; + } + + break; + } + + value = ParseValue( doc, attribute, no, isempty, &delim ); + + if (attribute && (IsValidAttrName(attribute) || + (cfgBool(doc, TidyXmlTags) && IsValidXMLAttrName(attribute)))) + { + av = TY_(NewAttribute)(doc); + av->delim = delim; + av->attribute = attribute; + av->value = value; + av->dict = TY_(FindAttribute)( doc, av ); + AddAttrToList( &list, av ); + } + else + { + av = TY_(NewAttribute)(doc); + av->attribute = attribute; + av->value = value; + + if (LastChar(attribute) == '"') + TY_(ReportAttrError)( doc, lexer->token, av, MISSING_QUOTEMARK); + else if (value == NULL) + TY_(ReportAttrError)(doc, lexer->token, av, MISSING_ATTR_VALUE); + else + TY_(ReportAttrError)(doc, lexer->token, av, INVALID_ATTRIBUTE); + + TY_(FreeAttribute)( doc, av ); + } + } + + return list; +} + +/* + Returns document type declarations like + + + + ]> + + as + + + + <!ENTITY ouml "&#246"> +*/ +static Node *ParseDocTypeDecl(TidyDocImpl* doc) +{ + Lexer *lexer = doc->lexer; + int start = lexer->lexsize; + ParseDocTypeDeclState state = DT_DOCTYPENAME; + uint c; + uint delim = 0; + Bool hasfpi = yes; + + Node* node = TY_(NewNode)(lexer->allocator, lexer); + node->type = DocTypeTag; + node->start = lexer->txtstart; + node->end = lexer->txtend; + + lexer->waswhite = no; + + /* todo: reset lexer->lexsize when appropriate to avoid wasting memory */ + + while ((c = TY_(ReadChar)(doc->docIn)) != EndOfStream) + { + /* convert newlines to spaces */ + if (state != DT_INTSUBSET) + c = c == '\n' ? ' ' : c; + + /* convert white-space sequences to single space character */ + if (TY_(IsWhite)(c) && state != DT_INTSUBSET) + { + if (!lexer->waswhite) + { + TY_(AddCharToLexer)(lexer, c); + lexer->waswhite = yes; + } + else + { + /* discard space */ + continue; + } + } + else + { + TY_(AddCharToLexer)(lexer, c); + lexer->waswhite = no; + } + + switch(state) + { + case DT_INTERMEDIATE: + /* determine what's next */ + if (TY_(ToUpper)(c) == 'P' || TY_(ToUpper)(c) == 'S') + { + start = lexer->lexsize - 1; + state = DT_PUBLICSYSTEM; + continue; + } + else if (c == '[') + { + start = lexer->lexsize; + state = DT_INTSUBSET; + continue; + } + else if (c == '\'' || c == '"') + { + start = lexer->lexsize; + delim = c; + state = DT_QUOTEDSTRING; + continue; + } + else if (c == '>') + { + AttVal* si; + + node->end = --(lexer->lexsize); + + si = TY_(GetAttrByName)(node, "SYSTEM"); + if (si) + TY_(CheckUrl)(doc, node, si); + + if (!node->element || !IsValidXMLElemName(node->element)) + { + TY_(ReportError)(doc, NULL, NULL, MALFORMED_DOCTYPE); + TY_(FreeNode)(doc, node); + return NULL; + } +#ifdef TIDY_STORE_ORIGINAL_TEXT + StoreOriginalTextInToken(doc, node, 0); +#endif + return node; + } + else + { + /* error */ + } + break; + case DT_DOCTYPENAME: + /* read document type name */ + if (TY_(IsWhite)(c) || c == '>' || c == '[') + { + node->element = TY_(tmbstrndup)(doc->allocator, + lexer->lexbuf + start, + lexer->lexsize - start - 1); + if (c == '>' || c == '[') + { + --(lexer->lexsize); + TY_(UngetChar)(c, doc->docIn); + } + + state = DT_INTERMEDIATE; + continue; + } + break; + case DT_PUBLICSYSTEM: + /* read PUBLIC/SYSTEM */ + if (TY_(IsWhite)(c) || c == '>') + { + char *attname = TY_(tmbstrndup)(doc->allocator, + lexer->lexbuf + start, + lexer->lexsize - start - 1); + hasfpi = !(TY_(tmbstrcasecmp)(attname, "SYSTEM") == 0); + + TidyDocFree(doc, attname); + + /* todo: report an error if SYSTEM/PUBLIC not uppercase */ + + if (c == '>') + { + --(lexer->lexsize); + TY_(UngetChar)(c, doc->docIn); + } + + state = DT_INTERMEDIATE; + continue; + } + break; + case DT_QUOTEDSTRING: + /* read quoted string */ + if (c == delim) + { + char *value = TY_(tmbstrndup)(doc->allocator, + lexer->lexbuf + start, + lexer->lexsize - start - 1); + AttVal* att = TY_(AddAttribute)(doc, node, hasfpi ? "PUBLIC" : "SYSTEM", value); + TidyDocFree(doc, value); + att->delim = delim; + hasfpi = no; + state = DT_INTERMEDIATE; + delim = 0; + continue; + } + break; + case DT_INTSUBSET: + /* read internal subset */ + if (c == ']') + { + Node* subset; + lexer->txtstart = start; + lexer->txtend = lexer->lexsize - 1; + subset = TY_(TextToken)(lexer); + TY_(InsertNodeAtEnd)(node, subset); + state = DT_INTERMEDIATE; + } + break; + } + } + + /* document type declaration not finished */ + TY_(ReportError)(doc, NULL, NULL, MALFORMED_DOCTYPE); + TY_(FreeNode)(doc, node); + return NULL; +} + +/* + * local variables: + * mode: c + * indent-tabs-mode: nil + * c-basic-offset: 4 + * eval: (c-set-offset 'substatement-open 0) + * end: + */ diff --git a/src/tidyLib/lexer.h b/src/tidyLib/lexer.h new file mode 100644 index 0000000000..6ac19df917 --- /dev/null +++ b/src/tidyLib/lexer.h @@ -0,0 +1,617 @@ +#ifndef __LEXER_H__ +#define __LEXER_H__ + +/* lexer.h -- Lexer for html parser + + (c) 1998-2008 (W3C) MIT, ERCIM, Keio University + See tidy.h for the copyright notice. + + CVS Info: + $Author: arnaud02 $ + $Date: 2008/03/22 21:06:11 $ + $Revision: 1.41 $ + +*/ + +/* + Given an input source, it returns a sequence of tokens. + + GetToken(source) gets the next token + UngetToken(source) provides one level undo + + The tags include an attribute list: + + - linked list of attribute/value nodes + - each node has 2 NULL-terminated strings. + - entities are replaced in attribute values + + white space is compacted if not in preformatted mode + If not in preformatted mode then leading white space + is discarded and subsequent white space sequences + compacted to single space characters. + + If XmlTags is no then Tag names are folded to upper + case and attribute names to lower case. + + Not yet done: + - Doctype subset and marked sections +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "forward.h" + +/* lexer character types +*/ +#define digit 1u +#define letter 2u +#define namechar 4u +#define white 8u +#define newline 16u +#define lowercase 32u +#define uppercase 64u +#define digithex 128u + + +/* node->type is one of these values +*/ +typedef enum +{ + RootNode, + DocTypeTag, + CommentTag, + ProcInsTag, + TextNode, + StartTag, + EndTag, + StartEndTag, + CDATATag, + SectionTag, + AspTag, + JsteTag, + PhpTag, + XmlDecl +} NodeType; + + + +/* lexer GetToken states +*/ +typedef enum +{ + LEX_CONTENT, + LEX_GT, + LEX_ENDTAG, + LEX_STARTTAG, + LEX_COMMENT, + LEX_DOCTYPE, + LEX_PROCINSTR, + LEX_CDATA, + LEX_SECTION, + LEX_ASP, + LEX_JSTE, + LEX_PHP, + LEX_XMLDECL +} LexerState; + +/* ParseDocTypeDecl state constants */ +typedef enum +{ + DT_INTERMEDIATE, + DT_DOCTYPENAME, + DT_PUBLICSYSTEM, + DT_QUOTEDSTRING, + DT_INTSUBSET +} ParseDocTypeDeclState; + +/* content model shortcut encoding + + Descriptions are tentative. +*/ +#define CM_UNKNOWN 0 +/* Elements with no content. Map to HTML specification. */ +#define CM_EMPTY (1 << 0) +/* Elements that appear outside of "BODY". */ +#define CM_HTML (1 << 1) +/* Elements that can appear within HEAD. */ +#define CM_HEAD (1 << 2) +/* HTML "block" elements. */ +#define CM_BLOCK (1 << 3) +/* HTML "inline" elements. */ +#define CM_INLINE (1 << 4) +/* Elements that mark list item ("LI"). */ +#define CM_LIST (1 << 5) +/* Elements that mark definition list item ("DL", "DT"). */ +#define CM_DEFLIST (1 << 6) +/* Elements that can appear inside TABLE. */ +#define CM_TABLE (1 << 7) +/* Used for "THEAD", "TFOOT" or "TBODY". */ +#define CM_ROWGRP (1 << 8) +/* Used for "TD", "TH" */ +#define CM_ROW (1 << 9) +/* Elements whose content must be protected against white space movement. + Includes some elements that can found in forms. */ +#define CM_FIELD (1 << 10) +/* Used to avoid propagating inline emphasis inside some elements + such as OBJECT or APPLET. */ +#define CM_OBJECT (1 << 11) +/* Elements that allows "PARAM". */ +#define CM_PARAM (1 << 12) +/* "FRAME", "FRAMESET", "NOFRAMES". Used in ParseFrameSet. */ +#define CM_FRAMES (1 << 13) +/* Heading elements (h1, h2, ...). */ +#define CM_HEADING (1 << 14) +/* Elements with an optional end tag. */ +#define CM_OPT (1 << 15) +/* Elements that use "align" attribute for vertical position. */ +#define CM_IMG (1 << 16) +/* Elements with inline and block model. Used to avoid calling InlineDup. */ +#define CM_MIXED (1 << 17) +/* Elements whose content needs to be indented only if containing one + CM_BLOCK element. */ +#define CM_NO_INDENT (1 << 18) +/* Elements that are obsolete (such as "dir", "menu"). */ +#define CM_OBSOLETE (1 << 19) +/* User defined elements. Used to determine how attributes wihout value + should be printed. */ +#define CM_NEW (1 << 20) +/* Elements that cannot be omitted. */ +#define CM_OMITST (1 << 21) + +/* If the document uses just HTML 2.0 tags and attributes described +** it as HTML 2.0 Similarly for HTML 3.2 and the 3 flavors of HTML 4.0. +** If there are proprietary tags and attributes then describe it as +** HTML Proprietary. If it includes the xml-lang or xmlns attributes +** but is otherwise HTML 2.0, 3.2 or 4.0 then describe it as one of the +** flavors of Voyager (strict, loose or frameset). +*/ + +/* unknown */ +#define xxxx 0u + +/* W3C defined HTML/XHTML family document types */ +#define HT20 1u +#define HT32 2u +#define H40S 4u +#define H40T 8u +#define H40F 16u +#define H41S 32u +#define H41T 64u +#define H41F 128u +#define X10S 256u +#define X10T 512u +#define X10F 1024u +#define XH11 2048u +#define XB10 4096u + +/* proprietary stuff */ +#define VERS_SUN 8192u +#define VERS_NETSCAPE 16384u +#define VERS_MICROSOFT 32768u + +/* special flag */ +#define VERS_XML 65536u + +/* compatibility symbols */ +#define VERS_UNKNOWN (xxxx) +#define VERS_HTML20 (HT20) +#define VERS_HTML32 (HT32) +#define VERS_HTML40_STRICT (H40S|H41S|X10S) +#define VERS_HTML40_LOOSE (H40T|H41T|X10T) +#define VERS_FRAMESET (H40F|H41F|X10F) +#define VERS_XHTML11 (XH11) +#define VERS_BASIC (XB10) + +/* meta symbols */ +#define VERS_HTML40 (VERS_HTML40_STRICT|VERS_HTML40_LOOSE|VERS_FRAMESET) +#define VERS_IFRAME (VERS_HTML40_LOOSE|VERS_FRAMESET) +#define VERS_LOOSE (VERS_HTML20|VERS_HTML32|VERS_IFRAME) +#define VERS_EVENTS (VERS_HTML40|VERS_XHTML11) +#define VERS_FROM32 (VERS_HTML32|VERS_HTML40) +#define VERS_FROM40 (VERS_HTML40|VERS_XHTML11|VERS_BASIC) +#define VERS_XHTML (X10S|X10T|X10F|XH11|XB10) + +/* all W3C defined document types */ +#define VERS_ALL (VERS_HTML20|VERS_HTML32|VERS_FROM40) + +/* all proprietary types */ +#define VERS_PROPRIETARY (VERS_NETSCAPE|VERS_MICROSOFT|VERS_SUN) + +/* Linked list of class names and styles +*/ +struct _Style; +typedef struct _Style TagStyle; + +struct _Style +{ + tmbstr tag; + tmbstr tag_class; + tmbstr properties; + TagStyle *next; +}; + + +/* Linked list of style properties +*/ +struct _StyleProp; +typedef struct _StyleProp StyleProp; + +struct _StyleProp +{ + tmbstr name; + tmbstr value; + StyleProp *next; +}; + + + + +/* Attribute/Value linked list node +*/ + +struct _AttVal +{ + AttVal* next; + const Attribute* dict; + Node* asp; + Node* php; + int delim; + tmbstr attribute; + tmbstr value; +}; + + + +/* + Mosaic handles inlines via a separate stack from other elements + We duplicate this to recover from inline markup errors such as: + + italic text +

more italic text normal text + + which for compatibility with Mosaic is mapped to: + + italic text +

more italic text normal text + + Note that any inline end tag pop's the effect of the current + inline start tag, so that pop's in the above example. +*/ +struct _IStack +{ + IStack* next; + const Dict* tag; /* tag's dictionary definition */ + tmbstr element; /* name (NULL for text nodes) */ + AttVal* attributes; +}; + + +/* HTML/XHTML/XML Element, Comment, PI, DOCTYPE, XML Decl, +** etc. etc. +*/ + +struct _Node +{ + Node* parent; /* tree structure */ + Node* prev; + Node* next; + Node* content; + Node* last; + + AttVal* attributes; + const Dict* was; /* old tag when it was changed */ + const Dict* tag; /* tag's dictionary definition */ + + tmbstr element; /* name (NULL for text nodes) */ + + uint start; /* start of span onto text array */ + uint end; /* end of span onto text array */ + NodeType type; /* TextNode, StartTag, EndTag etc. */ + + uint line; /* current line of document */ + uint column; /* current column of document */ + + Bool closed; /* true if closed by explicit end tag */ + Bool implicit; /* true if inferred */ + Bool linebreak; /* true if followed by a line break */ + +#ifdef TIDY_STORE_ORIGINAL_TEXT + tmbstr otext; +#endif +}; + + +/* + The following are private to the lexer + Use NewLexer() to create a lexer, and + FreeLexer() to free it. +*/ + +struct _Lexer +{ +#if 0 /* Move to TidyDocImpl */ + StreamIn* in; /* document content input */ + StreamOut* errout; /* error output stream */ + + uint badAccess; /* for accessibility errors */ + uint badLayout; /* for bad style errors */ + uint badChars; /* for bad character encodings */ + uint badForm; /* for mismatched/mispositioned form tags */ + uint warnings; /* count of warnings in this document */ + uint errors; /* count of errors */ +#endif + + uint lines; /* lines seen */ + uint columns; /* at start of current token */ + Bool waswhite; /* used to collapse contiguous white space */ + Bool pushed; /* true after token has been pushed back */ + Bool insertspace; /* when space is moved after end tag */ + Bool excludeBlocks; /* Netscape compatibility */ + Bool exiled; /* true if moved out of table */ + Bool isvoyager; /* true if xmlns attribute on html element */ + uint versions; /* bit vector of HTML versions */ + uint doctype; /* version as given by doctype (if any) */ + uint versionEmitted; /* version of doctype emitted */ + Bool bad_doctype; /* e.g. if html or PUBLIC is missing */ + uint txtstart; /* start of current node */ + uint txtend; /* end of current node */ + LexerState state; /* state of lexer's finite state machine */ + + Node* token; /* last token returned by GetToken() */ + Node* itoken; /* last duplicate inline returned by GetToken() */ + Node* root; /* remember root node of the document */ + Node* parent; /* remember parent node for CDATA elements */ + + Bool seenEndBody; /* true if a tag has been encountered */ + Bool seenEndHtml; /* true if a tag has been encountered */ + + /* + Lexer character buffer + + Parse tree nodes span onto this buffer + which contains the concatenated text + contents of all of the elements. + + lexsize must be reset for each file. + */ + tmbstr lexbuf; /* MB character buffer */ + uint lexlength; /* allocated */ + uint lexsize; /* used */ + + /* Inline stack for compatibility with Mosaic */ + Node* inode; /* for deferring text node */ + IStack* insert; /* for inferring inline tags */ + IStack* istack; + uint istacklength; /* allocated */ + uint istacksize; /* used */ + uint istackbase; /* start of frame */ + + TagStyle *styles; /* used for cleaning up presentation markup */ + + TidyAllocator* allocator; /* allocator */ + +#if 0 + TidyDocImpl* doc; /* Pointer back to doc for error reporting */ +#endif +}; + + +/* Lexer Functions +*/ + +/* choose what version to use for new doctype */ +int TY_(HTMLVersion)( TidyDocImpl* doc ); + +/* everything is allowed in proprietary version of HTML */ +/* this is handled here rather than in the tag/attr dicts */ + +void TY_(ConstrainVersion)( TidyDocImpl* doc, uint vers ); + +Bool TY_(IsWhite)(uint c); +Bool TY_(IsDigit)(uint c); +Bool TY_(IsLetter)(uint c); +Bool TY_(IsNewline)(uint c); +Bool TY_(IsNamechar)(uint c); +Bool TY_(IsXMLLetter)(uint c); +Bool TY_(IsXMLNamechar)(uint c); + +/* Bool IsLower(uint c); */ +Bool TY_(IsUpper)(uint c); +uint TY_(ToLower)(uint c); +uint TY_(ToUpper)(uint c); + +Lexer* TY_(NewLexer)( TidyDocImpl* doc ); +void TY_(FreeLexer)( TidyDocImpl* doc ); + +/* store character c as UTF-8 encoded byte stream */ +void TY_(AddCharToLexer)( Lexer *lexer, uint c ); + +/* + Used for elements and text nodes + element name is NULL for text nodes + start and end are offsets into lexbuf + which contains the textual content of + all elements in the parse tree. + + parent and content allow traversal + of the parse tree in any direction. + attributes are represented as a linked + list of AttVal nodes which hold the + strings for attribute/value pairs. +*/ +Node* TY_(NewNode)( TidyAllocator* allocator, Lexer* lexer ); + + +/* used to clone heading nodes when split by an


*/ +Node* TY_(CloneNode)( TidyDocImpl* doc, Node *element ); + +/* free node's attributes */ +void TY_(FreeAttrs)( TidyDocImpl* doc, Node *node ); + +/* doesn't repair attribute list linkage */ +void TY_(FreeAttribute)( TidyDocImpl* doc, AttVal *av ); + +/* detach attribute from node */ +void TY_(DetachAttribute)( Node *node, AttVal *attr ); + +/* detach attribute from node then free it +*/ +void TY_(RemoveAttribute)( TidyDocImpl* doc, Node *node, AttVal *attr ); + +/* + Free document nodes by iterating through peers and recursing + through children. Set next to NULL before calling FreeNode() + to avoid freeing peer nodes. Doesn't patch up prev/next links. + */ +void TY_(FreeNode)( TidyDocImpl* doc, Node *node ); + +Node* TY_(TextToken)( Lexer *lexer ); + +/* used for creating preformatted text from Word2000 */ +Node* TY_(NewLineNode)( Lexer *lexer ); + +/* used for adding a   for Word2000 */ +Node* TY_(NewLiteralTextNode)(Lexer *lexer, ctmbstr txt ); + +void TY_(AddStringLiteral)( Lexer* lexer, ctmbstr str ); +/* void AddStringLiteralLen( Lexer* lexer, ctmbstr str, int len ); */ + +/* find element */ +Node* TY_(FindDocType)( TidyDocImpl* doc ); +Node* TY_(FindHTML)( TidyDocImpl* doc ); +Node* TY_(FindHEAD)( TidyDocImpl* doc ); +Node* TY_(FindTITLE)(TidyDocImpl* doc); +Node* TY_(FindBody)( TidyDocImpl* doc ); +Node* TY_(FindXmlDecl)(TidyDocImpl* doc); + +/* Returns containing block element, if any */ +Node* TY_(FindContainer)( Node* node ); + +/* add meta element for Tidy */ +Bool TY_(AddGenerator)( TidyDocImpl* doc ); + +uint TY_(ApparentVersion)( TidyDocImpl* doc ); + +ctmbstr TY_(HTMLVersionNameFromCode)( uint vers, Bool isXhtml ); + +Bool TY_(WarnMissingSIInEmittedDocType)( TidyDocImpl* doc ); + +Bool TY_(SetXHTMLDocType)( TidyDocImpl* doc ); + + +/* fixup doctype if missing */ +Bool TY_(FixDocType)( TidyDocImpl* doc ); + +/* ensure XML document starts with */ +/* add encoding attribute if not using ASCII or UTF-8 output */ +Bool TY_(FixXmlDecl)( TidyDocImpl* doc ); + +Node* TY_(InferredTag)(TidyDocImpl* doc, TidyTagId id); + +void TY_(UngetToken)( TidyDocImpl* doc ); + + +/* + modes for GetToken() + + MixedContent -- for elements which don't accept PCDATA + Preformatted -- white space preserved as is + IgnoreMarkup -- for CDATA elements such as script, style +*/ +typedef enum +{ + IgnoreWhitespace, + MixedContent, + Preformatted, + IgnoreMarkup, + CdataContent +} GetTokenMode; + +Node* TY_(GetToken)( TidyDocImpl* doc, GetTokenMode mode ); + +void TY_(InitMap)(void); + + +/* create a new attribute */ +AttVal* TY_(NewAttribute)( TidyDocImpl* doc ); + +/* create a new attribute with given name and value */ +AttVal* TY_(NewAttributeEx)( TidyDocImpl* doc, ctmbstr name, ctmbstr value, + int delim ); + +/* insert attribute at the end of attribute list of a node */ +void TY_(InsertAttributeAtEnd)( Node *node, AttVal *av ); + +/* insert attribute at the start of attribute list of a node */ +void TY_(InsertAttributeAtStart)( Node *node, AttVal *av ); + +/************************************* + In-line Stack functions +*************************************/ + + +/* duplicate attributes */ +AttVal* TY_(DupAttrs)( TidyDocImpl* doc, AttVal* attrs ); + +/* + push a copy of an inline node onto stack + but don't push if implicit or OBJECT or APPLET + (implicit tags are ones generated from the istack) + + One issue arises with pushing inlines when + the tag is already pushed. For instance: + +

text +

more text + + Shouldn't be mapped to + +

text

+

more text +*/ +void TY_(PushInline)( TidyDocImpl* doc, Node* node ); + +/* pop inline stack */ +void TY_(PopInline)( TidyDocImpl* doc, Node* node ); + +Bool TY_(IsPushed)( TidyDocImpl* doc, Node* node ); +Bool TY_(IsPushedLast)( TidyDocImpl* doc, Node *element, Node *node ); + +/* + This has the effect of inserting "missing" inline + elements around the contents of blocklevel elements + such as P, TD, TH, DIV, PRE etc. This procedure is + called at the start of ParseBlock. when the inline + stack is not empty, as will be the case in: + +

italic heading

+ + which is then treated as equivalent to + +

italic heading

+ + This is implemented by setting the lexer into a mode + where it gets tokens from the inline stack rather than + from the input stream. +*/ +int TY_(InlineDup)( TidyDocImpl* doc, Node *node ); + +/* + defer duplicates when entering a table or other + element where the inlines shouldn't be duplicated +*/ +void TY_(DeferDup)( TidyDocImpl* doc ); +Node* TY_(InsertedToken)( TidyDocImpl* doc ); + +/* stack manipulation for inline elements */ +Bool TY_(SwitchInline)( TidyDocImpl* doc, Node* element, Node* node ); +Bool TY_(InlineDup1)( TidyDocImpl* doc, Node* node, Node* element ); + +#ifdef __cplusplus +} +#endif + + +#endif /* __LEXER_H__ */ diff --git a/src/tidyLib/localize.c b/src/tidyLib/localize.c new file mode 100644 index 0000000000..c924798e91 --- /dev/null +++ b/src/tidyLib/localize.c @@ -0,0 +1,1882 @@ +/* localize.c -- text strings and routines to handle errors and general messages + + (c) 1998-2008 (W3C) MIT, ERCIM, Keio University + Portions Copyright University of Toronto + See tidy.h and access.h for the copyright notice. + + You should only need to edit this file and tidy.c + to localize HTML tidy. *** This needs checking *** + + CVS Info : + + $Author: arnaud02 $ + $Date: 2008/06/18 20:18:54 $ + $Revision: 1.178 $ + +*/ + +#include "tidy-int.h" +#include "lexer.h" +#include "streamio.h" +#include "message.h" +#include "tmbstr.h" +#include "utf8.h" + +/* used to point to Web Accessibility Guidelines */ +#define ACCESS_URL "http://www.w3.org/WAI/GL" + +/* points to the Adaptive Technology Resource Centre at the +** University of Toronto +*/ +#define ATRC_ACCESS_URL "http://www.aprompt.ca/Tidy/accessibilitychecks.html" + +#include "version.h" + +ctmbstr TY_(ReleaseDate)(void) +{ + return TY_(release_date); +} + +static struct _msgfmt +{ + uint code; + ctmbstr fmt; +} const msgFormat[] = +{ +/* ReportEncodingWarning */ + { ENCODING_MISMATCH, "specified input encoding (%s) does not match actual input encoding (%s)" }, /* Warning */ + +/* ReportEncodingError */ + { VENDOR_SPECIFIC_CHARS, "%s invalid character code %s" }, /* Error */ + { INVALID_SGML_CHARS, "%s invalid character code %s" }, /* Error */ + { INVALID_UTF8, "%s invalid UTF-8 bytes (char. code %s)" }, /* Error */ + { INVALID_UTF16, "%s invalid UTF-16 surrogate pair (char. code %s)" }, /* Error */ + { INVALID_NCR, "%s invalid numeric character reference %s" }, /* Error */ + +/* ReportEntityError */ + { MISSING_SEMICOLON, "entity \"%s\" doesn't end in ';'" }, /* Warning in HTML, Error in XML/XHTML */ + { MISSING_SEMICOLON_NCR, "numeric character reference \"%s\" doesn't end in ';'" }, /* Warning in HTML, Error in XML/XHTML */ + { UNESCAPED_AMPERSAND, "unescaped & which should be written as &" }, /* Warning in HTML, Error in XHTML */ + { UNKNOWN_ENTITY, "unescaped & or unknown entity \"%s\"" }, /* Error */ + { APOS_UNDEFINED, "named entity ' only defined in XML/XHTML" }, /* Error in HTML (should only occur for HTML input) */ + +/* ReportAttrError */ + + /* attribute name */ + { INSERTING_ATTRIBUTE, "%s inserting \"%s\" attribute" }, /* Warning in CheckLINK, Error otherwise */ + { MISSING_ATTR_VALUE, "%s attribute \"%s\" lacks value" }, /* Warning in CheckUrl, Error otherwise */ + { UNKNOWN_ATTRIBUTE, "%s unknown attribute \"%s\"" }, /* Error */ + { PROPRIETARY_ATTRIBUTE, "%s proprietary attribute \"%s\"" }, /* Error */ + { JOINING_ATTRIBUTE, "%s joining values of repeated attribute \"%s\"" }, /* Error */ + { XML_ATTRIBUTE_VALUE, "%s has XML attribute \"%s\"" }, /* Error (but deprecated) */ + + /* attribute value */ + { XML_ID_SYNTAX, "%s ID \"%s\" uses XML ID syntax" }, /* Warning if XHTML, Error if HTML */ + { ATTR_VALUE_NOT_LCASE, "%s attribute value \"%s\" must be lower case for XHTML" }, /* Error if XHTML input, Notice if HTML input and XHTML outout */ + { PROPRIETARY_ATTR_VALUE, "%s proprietary attribute value \"%s\"" }, /* Error */ + { ANCHOR_NOT_UNIQUE, "%s anchor \"%s\" already defined" }, /* Error */ + + /* attribute name, attribute value */ + { BAD_ATTRIBUTE_VALUE, "%s attribute \"%s\" has invalid value \"%s\"" }, /* Error */ + { BAD_ATTRIBUTE_VALUE_REPLACED, "%s attribute \"%s\" had invalid value \"%s\" and has been replaced" }, /* Error */ + { INVALID_ATTRIBUTE, "%s attribute name \"%s\" (value=\"%s\") is invalid" }, /* Error */ + + /* attribute value, attribute name */ + { REPEATED_ATTRIBUTE, "%s dropping value \"%s\" for repeated attribute \"%s\"" }, /* Error */ + + /* no arguments */ + { INVALID_XML_ID, "%s cannot copy name attribute to id" }, /* Warning */ + { UNEXPECTED_GT, "%s missing '>' for end of tag" }, /* Warning if HTML, Error if XML/XHTML */ + { UNEXPECTED_QUOTEMARK, "%s unexpected or duplicate quote mark" }, /* Error */ + { MISSING_QUOTEMARK, "%s attribute with missing trailing quote mark" }, /* Error */ + { UNEXPECTED_END_OF_FILE_ATTR, "%s end of file while parsing attributes" }, /* Error */ + { ID_NAME_MISMATCH, "%s id and name attribute value mismatch" }, /* Error */ + { BACKSLASH_IN_URI, "%s URI reference contains backslash. Typo?" }, /* Error */ + { FIXED_BACKSLASH, "%s converting backslash in URI to slash" }, /* Error */ + { ILLEGAL_URI_REFERENCE, "%s improperly escaped URI reference" }, /* Error */ + { ESCAPED_ILLEGAL_URI, "%s escaping malformed URI reference" }, /* Error */ + { NEWLINE_IN_URI, "%s discarding newline in URI reference" }, /* Error */ + { WHITE_IN_URI, "%s discarding whitespace in URI reference" }, /* Error */ + { UNEXPECTED_EQUALSIGN, "%s unexpected '=', expected attribute name" }, /* Error */ + { MISSING_IMAGEMAP, "%s should use client-side image map" }, /* Warning (but deprecated) */ + +/* ReportMissingAttr */ + { MISSING_ATTRIBUTE, "%s lacks \"%s\" attribute" }, /* Error */ +/* ReportWarning */ + { NESTED_EMPHASIS, "nested emphasis %s" }, /* Warning */ + { NESTED_QUOTATION, "nested q elements, possible typo." }, /* Warning */ + { OBSOLETE_ELEMENT, "replacing obsolete element %s by %s" }, /* Warning */ + { COERCE_TO_ENDTAG_WARN, "<%s> is probably intended as " }, /* Warning */ + +/* ReportNotice */ + { TRIM_EMPTY_ELEMENT, "trimming empty %s" }, /* Notice */ + { REPLACING_ELEMENT, "replacing %s by %s" }, /* Notice */ + +/* ReportError */ + { COERCE_TO_ENDTAG, "<%s> is probably intended as " }, /* Error */ + { REPLACING_UNEX_ELEMENT, "replacing unexpected %s by %s" }, /* Error */ + { MISSING_ENDTAG_FOR, "missing " }, /* Error */ + { MISSING_ENDTAG_BEFORE, "missing before %s" }, /* Error */ + { DISCARDING_UNEXPECTED, "discarding unexpected %s" }, /* Error */ + { NON_MATCHING_ENDTAG, "replacing unexpected %s by " }, /* Error */ + { TAG_NOT_ALLOWED_IN, "%s isn't allowed in <%s> elements" }, /* Error */ + { MISSING_STARTTAG, "missing <%s>" }, /* Error */ + { UNEXPECTED_ENDTAG, "unexpected " }, /* Error */ + { TOO_MANY_ELEMENTS, "too many %s elements" }, /* Error */ + { USING_BR_INPLACE_OF, "using
in place of %s" }, /* Error */ + { INSERTING_TAG, "inserting implicit <%s>" }, /* Error */ + { CANT_BE_NESTED, "%s can't be nested" }, /* Error */ + { PROPRIETARY_ELEMENT, "%s is not approved by W3C" }, /* Error */ + { ILLEGAL_NESTING, "%s shouldn't be nested" }, /* Error */ + { NOFRAMES_CONTENT, "%s not inside 'noframes' element" }, /* Error */ + { UNEXPECTED_END_OF_FILE, "unexpected end of file %s" }, /* Error */ + { ELEMENT_NOT_EMPTY, "%s element not empty or not closed" }, /* Error */ + { UNEXPECTED_ENDTAG_IN, "unexpected in <%s>" }, /* Error */ + { TOO_MANY_ELEMENTS_IN, "too many %s elements in <%s>" }, /* Error */ + { UNESCAPED_ELEMENT, "unescaped %s in pre content" }, /* Error (but deprecated) */ + + /* no arguments */ + { DOCTYPE_AFTER_TAGS, " isn't allowed after elements" }, /* Error */ + { MISSING_TITLE_ELEMENT, "inserting missing 'title' element" }, /* Error */ + { INCONSISTENT_VERSION, "HTML DOCTYPE doesn't match content" }, /* Error */ + { MISSING_DOCTYPE, "missing declaration" }, /* Error */ + { CONTENT_AFTER_BODY, "content occurs after end of body" }, /* Error */ + { MALFORMED_COMMENT, "adjacent hyphens within comment" }, /* Error */ + { BAD_COMMENT_CHARS, "expecting -- or >" }, /* Error */ + { BAD_CDATA_CONTENT, "'<' + '/' + letter not allowed here" }, /* Error */ + { INCONSISTENT_NAMESPACE, "HTML namespace doesn't match content" }, /* Error */ + { SPACE_PRECEDING_XMLDECL, "removing whitespace preceding XML Declaration" }, /* Error */ + { MALFORMED_DOCTYPE, "discarding malformed " }, /* Error */ + { BAD_XML_COMMENT, "XML comments can't contain --" }, /* Error (but deprecated) */ + { DTYPE_NOT_UPPER_CASE, "SYSTEM, PUBLIC, W3C, DTD, EN must be upper case" }, /* Error (but deprecated) */ + { ENCODING_IO_CONFLICT, "Output encoding does not work with standard output" }, /* Error (but deprecated) */ + +/* ReportFatal */ + { SUSPECTED_MISSING_QUOTE, "missing quote mark for attribute value" }, /* Error? (not really sometimes) */ + { DUPLICATE_FRAMESET, "repeated FRAMESET element" }, /* Error */ + { UNKNOWN_ELEMENT, "%s is not recognized!" }, /* Error */ + { UNEXPECTED_ENDTAG, "unexpected " }, /* Error */ + +/* */ + { PREVIOUS_LOCATION, "<%s> previously mentioned" }, /* Info */ + +#if SUPPORT_ACCESSIBILITY_CHECKS + +/* ReportAccess */ +/* + List of error/warning messages. The error code corresponds to + the check that is listed in the AERT (HTML specifications). +*/ + { IMG_MISSING_ALT, "[1.1.1.1]: missing 'alt' text." }, /* Access */ + { IMG_ALT_SUSPICIOUS_FILENAME, "[1.1.1.2]: suspicious 'alt' text (filename)." }, /* Access */ + { IMG_ALT_SUSPICIOUS_FILE_SIZE, "[1.1.1.3]: suspicious 'alt' text (file size)." }, /* Access */ + { IMG_ALT_SUSPICIOUS_PLACEHOLDER, "[1.1.1.4]: suspicious 'alt' text (placeholder)." }, /* Access */ + { IMG_ALT_SUSPICIOUS_TOO_LONG, "[1.1.1.10]: suspicious 'alt' text (too long)." }, /* Access */ + { IMG_MISSING_LONGDESC_DLINK, "[1.1.2.1]: missing 'longdesc' and d-link." }, /* Access */ + { IMG_MISSING_DLINK, "[1.1.2.2]: missing d-link." }, /* Access */ + { IMG_MISSING_LONGDESC, "[1.1.2.3]: missing 'longdesc'." }, /* Access */ + { IMG_BUTTON_MISSING_ALT, "[1.1.3.1]: (button) missing 'alt' text." }, /* Access */ + { APPLET_MISSING_ALT, "[1.1.4.1]: missing alternate content." }, /* Access */ + { OBJECT_MISSING_ALT, "[1.1.5.1]: missing alternate content." }, /* Access */ + { AUDIO_MISSING_TEXT_WAV, "[1.1.6.1]: audio missing text transcript (wav)." }, /* Access */ + { AUDIO_MISSING_TEXT_AU, "[1.1.6.2]: audio missing text transcript (au)." }, /* Access */ + { AUDIO_MISSING_TEXT_AIFF, "[1.1.6.3]: audio missing text transcript (aiff)." }, /* Access */ + { AUDIO_MISSING_TEXT_SND, "[1.1.6.4]: audio missing text transcript (snd)." }, /* Access */ + { AUDIO_MISSING_TEXT_RA, "[1.1.6.5]: audio missing text transcript (ra)." }, /* Access */ + { AUDIO_MISSING_TEXT_RM, "[1.1.6.6]: audio missing text transcript (rm)." }, /* Access */ + { FRAME_MISSING_LONGDESC, "[1.1.8.1]: may require 'longdesc'." }, /* Access */ + { AREA_MISSING_ALT, "[1.1.9.1]: missing 'alt' text." }, /* Access */ + { SCRIPT_MISSING_NOSCRIPT, "[1.1.10.1]: