Engauge Digitizer  2
DlgImportCroppingPdf.cpp
1 /******************************************************************************************************
2  * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released *
3  * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file *
4  * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. *
5  ******************************************************************************************************/
6 
7 #include "DlgImportCroppingPdf.h"
8 #include "EngaugeAssert.h"
9 #include "Logger.h"
10 #include "MainWindow.h"
11 #include "PdfCropping.h"
12 #include "poppler-qt5.h"
13 #include <QApplication>
14 #include <QGraphicsPixmapItem>
15 #include <QGraphicsScene>
16 #include <QImage>
17 #include <QLabel>
18 #include <QLayout>
19 #include <QPushButton>
20 #include <QSettings>
21 #include <QSpinBox>
22 #include <QTimer>
23 #include "Settings.h"
24 #include "ViewPreview.h"
25 
26 using namespace Poppler;
27 
28 int DlgImportCroppingPdf::MINIMUM_DIALOG_WIDTH = 350;
29 int DlgImportCroppingPdf::MINIMUM_PREVIEW_HEIGHT = 200;
30 const int X_TOP_LEFT = 0, Y_TOP_LEFT = 0;
31 const int WIDTH = -1, HEIGHT = -1; // Negative values give full page
32 const int FIRST_PAGE_1_BASED = 1;
33 const int SMALLEST_DELAY_MS = 500; // Below 500 triggers "double jump" bug in linux
34 
35 DlgImportCroppingPdf::DlgImportCroppingPdf(const Poppler::Document &document,
36  int resolution) :
37  m_document (document),
38  m_resolution (resolution),
39  m_pixmap (0)
40 {
41  LOG4CPP_INFO_S ((*mainCat)) << "DlgImportCroppingPdf::DlgImportCroppingPdf";
42 
43  setWindowTitle (tr ("PDF File Import Cropping"));
44  setModal (true);
45 
46  QWidget *subPanel = new QWidget ();
47  QGridLayout *layout = new QGridLayout (subPanel);
48  subPanel->setLayout (layout);
49 
50  int row = 0;
51 
52  createTimer ();
53  createPageSpinner (layout, row);
54  createPreview (layout, row);
55  finishPanel (subPanel);
56  updatePreview ();
57 
58  // Bring the two middle columns together
59  layout->setColumnStretch (0, 1);
60  layout->setColumnStretch (1, 0);
61  layout->setColumnStretch (2, 0);
62  layout->setColumnStretch (3, 1);
63 }
64 
65 DlgImportCroppingPdf::~DlgImportCroppingPdf()
66 {
67  LOG4CPP_INFO_S ((*mainCat)) << "DlgImportCroppingPdf::~DlgImportCroppingPdf";
68 }
69 
70 void DlgImportCroppingPdf::createPageSpinner (QGridLayout *layout,
71  int &row)
72 {
73  LOG4CPP_INFO_S ((*mainCat)) << "DlgImportCroppingPdf::createPageSpinner";
74 
75  const int MIN_WIDTH_SPINNER = 90;
76 
77  QLabel *labelPage = new QLabel (tr ("Page:"));
78  layout->addWidget (labelPage, row, 1, 1, 1);
79 
80  m_spinPage = new QSpinBox;
81  m_spinPage->setMinimumWidth (MIN_WIDTH_SPINNER);
82  m_spinPage->setWhatsThis (tr ("Page number that will be imported"));
83  m_spinPage->setRange (1, m_document.numPages());
84  layout->addWidget (m_spinPage, row++, 2, 1, 1);
85  connect (m_spinPage, SIGNAL (valueChanged (int)), this, SLOT (slotPage (int)));
86 }
87 
88 void DlgImportCroppingPdf::createPdfCropping ()
89 {
90  // Create frame that shows what will be included, and what will be excluded, during the import
91  m_pdfCropping = new PdfCropping (*m_scenePreview,
92  *m_viewPreview);
93 }
94 
95 void DlgImportCroppingPdf::createPreview (QGridLayout *layout,
96  int &row)
97 {
98  LOG4CPP_INFO_S ((*mainCat)) << "DlgImportCroppingPdf::createPreview";
99 
100  QLabel *labelPreview = new QLabel (tr ("Preview"));
101  layout->addWidget (labelPreview, row++, 0, 1, 1, Qt::AlignLeft);
102 
103  m_scenePreview = new QGraphicsScene (this);
104  m_viewPreview = new ViewPreview (m_scenePreview,
105  ViewPreview::VIEW_ASPECT_RATIO_ONE_TO_ONE,
106  this);
107  m_viewPreview->setWhatsThis (tr ("Preview window that shows what part of the image will be imported. "
108  "The image portion inside the rectangular frame will be imported from the currently selected page. "
109  "The frame can be moved and resized by dragging the corner handles."));
110  m_viewPreview->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
111  m_viewPreview->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
112  m_viewPreview->setMinimumHeight (MINIMUM_PREVIEW_HEIGHT);
113  layout->addWidget (m_viewPreview, row++, 0, 1, 4);
114 
115  // More preview initialization
116  initializeFrameGeometryAndPixmap (); // Before first call to updatePreview
117  createPdfCropping ();
118 }
119 
120 void DlgImportCroppingPdf::createTimer ()
121 {
122  m_timer = new QTimer;
123  m_timer->setSingleShot (true);
124  connect (m_timer, SIGNAL (timeout ()), this, SLOT (slotTimeout ()));
125 }
126 
127 void DlgImportCroppingPdf::finishPanel (QWidget *subPanel)
128 {
129  const int STRETCH_OFF = 0, STRETCH_ON = 1;
130 
131  QVBoxLayout *panelLayout = new QVBoxLayout (this);
132 
133  setMinimumWidth (MINIMUM_DIALOG_WIDTH);
134  setLayout (panelLayout);
135 
136  panelLayout->addWidget (subPanel);
137  panelLayout->setStretch (panelLayout->count () - 1, STRETCH_ON);
138 
139  QWidget *panelButtons = new QWidget (this);
140  QHBoxLayout *buttonLayout = new QHBoxLayout (panelButtons);
141 
142  QHBoxLayout *layoutRightSide = new QHBoxLayout;
143 
144  QWidget *widgetRightSide = new QWidget;
145  widgetRightSide->setLayout (layoutRightSide);
146  buttonLayout->addWidget (widgetRightSide);
147 
148  QSpacerItem *spacerExpanding = new QSpacerItem (40, 5, QSizePolicy::Expanding, QSizePolicy::Expanding);
149  layoutRightSide->addItem (spacerExpanding);
150 
151  m_btnOk = new QPushButton (tr ("Ok"));
152  layoutRightSide->addWidget (m_btnOk, 0, Qt::AlignRight);
153  connect (m_btnOk, SIGNAL (released ()), this, SLOT (slotOk ()));
154 
155  QSpacerItem *spacerFixed = new QSpacerItem (40, 5, QSizePolicy::Fixed, QSizePolicy::Fixed);
156  layoutRightSide->addItem (spacerFixed);
157 
158  m_btnCancel = new QPushButton (tr ("Cancel"));
159  layoutRightSide->addWidget (m_btnCancel, 0, Qt::AlignRight);
160  connect (m_btnCancel, SIGNAL (released ()), this, SLOT (slotCancel ()));
161 
162  panelLayout->addWidget (panelButtons, STRETCH_ON);
163  panelLayout->setStretch (panelLayout->count () - 1, STRETCH_OFF);
164 }
165 
167 {
168  // If the entire page was to be returned, then this method would simply return m_image. However, only the framed
169  // portion is to be returned
170  ENGAUGE_ASSERT (m_pdfCropping != 0);
171  QRectF rectFramePixels = m_pdfCropping->frameRect ();
172 
173  return m_image.copy (rectFramePixels.toRect ());
174 }
175 
176 void DlgImportCroppingPdf::initializeFrameGeometryAndPixmap ()
177 {
178  m_image = loadImage (FIRST_PAGE_1_BASED);
179  QGraphicsPixmapItem *pixmap = new QGraphicsPixmapItem (QPixmap::fromImage (m_image));
180  m_scenePreview->addItem (pixmap);
181 
182  // Force resize so image fills preview area. We do this only once initially for speed
183  m_viewPreview->setSceneRect (pixmap->boundingRect ());
184 }
185 
186 QImage DlgImportCroppingPdf::loadImage (int page1Based) const
187 {
188  QImage image;
189 
190  int page0Based = page1Based - 1;
191  Page *page = m_document.page (page0Based);
192  if (page != 0) {
193 
194  image = page->renderToImage (m_resolution,
195  m_resolution,
196  X_TOP_LEFT,
197  Y_TOP_LEFT,
198  WIDTH,
199  HEIGHT);
200 
201  delete page;
202  }
203 
204  return image;
205 }
206 
207 void DlgImportCroppingPdf::saveGeometryToSettings()
208 {
209  // Store the settings for use by showEvent
210  QSettings settings;
211  settings.beginGroup (SETTINGS_GROUP_IMPORT_CROPPING);
212  settings.setValue (SETTINGS_IMPORT_CROPPING_POS, saveGeometry ());
213  settings.endGroup();
214 }
215 
216 void DlgImportCroppingPdf::showEvent (QShowEvent * /* event */)
217 {
218  QSettings settings;
219  settings.beginGroup (SETTINGS_GROUP_IMPORT_CROPPING);
220  if (settings.contains (SETTINGS_IMPORT_CROPPING_POS)) {
221 
222  // Restore the settings that were stored by the last call to saveGeometryToSettings
223  restoreGeometry (settings.value (SETTINGS_IMPORT_CROPPING_POS).toByteArray ());
224  }
225 }
226 
227 void DlgImportCroppingPdf::slotCancel ()
228 {
229  LOG4CPP_INFO_S ((*mainCat)) << "DlgImportCroppingPdf::slotCancel";
230 
231  // Restore cursor in case updatePreview has not already completed and then restored it
232  QApplication::restoreOverrideCursor ();
233 
234  setResult (QDialog::Rejected);
235  saveGeometryToSettings();
236  hide();
237 }
238 
239 void DlgImportCroppingPdf::slotOk ()
240 {
241  LOG4CPP_INFO_S ((*mainCat)) << "DlgImportCroppingPdf::slotOk";
242 
243  // Restore cursor in case updatePreview has not already completed and then restored it
244  QApplication::restoreOverrideCursor ();
245 
246  setResult (QDialog::Accepted);
247  saveGeometryToSettings();
248  hide();
249 }
250 
251 void DlgImportCroppingPdf::slotPage (int page)
252 {
253  LOG4CPP_INFO_S ((*mainCat)) << "DlgImportCroppingPdf::slotPage"
254  << " page=" << page
255  << " stepBy=" << m_spinPage->singleStep ();
256 
257  // Show wait cursor until slow calculations are over
258  QApplication::setOverrideCursor (Qt::WaitCursor);
259 
260  m_timer->start (SMALLEST_DELAY_MS);
261 }
262 
263 void DlgImportCroppingPdf::slotTimeout ()
264 {
265  LOG4CPP_INFO_S ((*mainCat)) << "DlgImportCroppingPdf::slotTimeout";
266 
267  updatePreview ();
268 }
269 
270 void DlgImportCroppingPdf::updatePreview ()
271 {
272  LOG4CPP_INFO_S ((*mainCat)) << "DlgImportCroppingPdf::updatePreview";
273 
274  if (m_pixmap != 0) {
275  m_scenePreview->removeItem (m_pixmap);
276  }
277 
278  m_image = loadImage (m_spinPage->value ());
279  m_pixmap = new QGraphicsPixmapItem (QPixmap::fromImage (m_image));
280  m_scenePreview->addItem (m_pixmap);
281 
282  // Calculations for preview updating are now over
283  QApplication::restoreOverrideCursor ();
284 }
DlgImportCroppingPdf(const Poppler::Document &document, int resolution)
Single constructor.
QRectF frameRect() const
Frame rectangle selected by user.
Definition: PdfCropping.cpp:68
Class that modifies QGraphicsView to automatically expand/shrink the view to fit the window...
Definition: ViewPreview.h:14
This class shows a frame around the selected portion of the pdf import preview window.
Definition: PdfCropping.h:24
QImage image() const
Image that was selected. Value is null if loading failed.
virtual void showEvent(QShowEvent *event)
Do preparation before dialog is displayed.