1 /* 2 Scan Tailor - Interactive post-processing tool for scanned pages. 3 Copyright (C) Joseph Artsimovich <joseph.artsimovich@gmail.com> 4 5 This program is free software: you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation, either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #ifndef PROJECT_PAGES_H_ 20 #define PROJECT_PAGES_H_ 21 22 #include <QMutex> 23 #include <QObject> 24 #include <QString> 25 #include <Qt> 26 #include <cstddef> 27 #include <set> 28 #include <vector> 29 #include "BeforeOrAfter.h" 30 #include "ImageId.h" 31 #include "ImageMetadata.h" 32 #include "NonCopyable.h" 33 #include "PageId.h" 34 #include "PageInfo.h" 35 #include "PageView.h" 36 #include "VirtualFunction.h" 37 #include "ref_countable.h" 38 39 class ImageFileInfo; 40 class ImageInfo; 41 class OrthogonalRotation; 42 class PageSequence; 43 class RelinkablePath; 44 class AbstractRelinker; 45 class QDomElement; 46 47 class ProjectPages : public QObject, public ref_countable { 48 Q_OBJECT 49 DECLARE_NON_COPYABLE(ProjectPages) 50 51 public: 52 enum Pages { ONE_PAGE, TWO_PAGES, AUTO_PAGES }; 53 54 enum LayoutType { ONE_PAGE_LAYOUT, TWO_PAGE_LAYOUT }; 55 56 explicit ProjectPages(Qt::LayoutDirection layout_direction = Qt::LeftToRight); 57 58 ProjectPages(const std::vector<ImageInfo>& images, Qt::LayoutDirection layout_direction); 59 60 ProjectPages(const std::vector<ImageFileInfo>& files, Pages pages, Qt::LayoutDirection layout_direction); 61 62 ~ProjectPages() override; 63 64 Qt::LayoutDirection layoutDirection() const; 65 66 PageSequence toPageSequence(PageView view) const; 67 68 void listRelinkablePaths(const VirtualFunction<void, const RelinkablePath&>& sink) const; 69 70 /** 71 * \note It's up to the caller to make sure different paths aren't collapsed into one. 72 * Having the same page more the once in a project is not supported by Scan Tailor. 73 */ 74 void performRelinking(const AbstractRelinker& relinker); 75 76 void setLayoutTypeFor(const ImageId& image_id, LayoutType layout); 77 78 void setLayoutTypeForAllPages(LayoutType layout); 79 80 void autoSetLayoutTypeFor(const ImageId& image_id, OrthogonalRotation rotation); 81 82 void updateImageMetadata(const ImageId& image_id, const ImageMetadata& metadata); 83 84 static int adviseNumberOfLogicalPages(const ImageMetadata& metadata, OrthogonalRotation rotation); 85 86 int numImages() const; 87 88 /** 89 * \brief Insert an image before or after the existing one. 90 * 91 * The caller has to make sure he is not inserting an image that already 92 * exists in this ProjectPages. Requesting to insert a new image 93 * BEFORE the null one is legal and means inserting it at the end. 94 * 95 * \param new_image The image to insert. 96 * \param before_or_after Whether to insert before or after another image. 97 * \param existing The image we are inserting before or after. 98 * \param view This one only affects what is returned. 99 * \return One or two (or zero, if existing image wasn't found) logical 100 * page descriptors. If two are returned, they will be returned 101 * in the order dependent on the layout direction specified 102 * at construction time. 103 */ 104 std::vector<PageInfo> insertImage(const ImageInfo& new_image, 105 BeforeOrAfter before_or_after, 106 const ImageId& existing, 107 PageView view); 108 109 void removePages(const std::set<PageId>& pages); 110 111 /** 112 * \brief Unremoves half-a-page, if the other half is still present. 113 * 114 * \param page_id Left or right sub-page to restore. 115 * \return A PageInfo corresponding to the page restored or 116 * a null PageInfo if restoring failed. 117 */ 118 PageInfo unremovePage(const PageId& page_id); 119 120 /** 121 * \brief Check if all DPIs are OK, in terms of ImageMetadata::isDpiOK() 122 * 123 * \return true if all DPIs are OK, false if not. 124 */ 125 bool validateDpis() const; 126 127 std::vector<ImageFileInfo> toImageFileInfo() const; 128 129 void updateMetadataFrom(const std::vector<ImageFileInfo>& files); 130 131 signals: 132 133 void modified(); 134 135 private: 136 struct ImageDesc { 137 ImageId id; 138 ImageMetadata metadata; 139 int numLogicalPages; // 1 or 2 140 bool leftHalfRemoved; // Both can't be true, and if one is true, 141 bool rightHalfRemoved; // then numLogicalPages is 1. 142 143 explicit ImageDesc(const ImageInfo& image_info); 144 145 ImageDesc(const ImageId& id, const ImageMetadata& metadata, Pages pages); 146 147 PageId::SubPage logicalPageToSubPage(int logical_page, const PageId::SubPage* sub_pages_in_order) const; 148 }; 149 150 void initSubPagesInOrder(Qt::LayoutDirection layout_direction); 151 152 void setLayoutTypeForImpl(const ImageId& image_id, LayoutType layout, bool* modified); 153 154 void setLayoutTypeForAllPagesImpl(LayoutType layout, bool* modified); 155 156 void autoSetLayoutTypeForImpl(const ImageId& image_id, OrthogonalRotation rotation, bool* modified); 157 158 void updateImageMetadataImpl(const ImageId& image_id, const ImageMetadata& metadata, bool* modified); 159 160 std::vector<PageInfo> insertImageImpl(const ImageInfo& new_image, 161 BeforeOrAfter before_or_after, 162 const ImageId& existing, 163 PageView view, 164 bool& modified); 165 166 void removePagesImpl(const std::set<PageId>& pages, bool& modified); 167 168 PageInfo unremovePageImpl(const PageId& page_id, bool& modified); 169 170 mutable QMutex m_mutex; 171 std::vector<ImageDesc> m_images; 172 PageId::SubPage m_subPagesInOrder[2]; 173 }; 174 175 176 #endif // ifndef PROJECT_PAGES_H_ 177