1 /****************************************************************************
2 **
3 ** This file is part of the LibreCAD project, a 2D CAD program
4 **
5 ** Copyright (C) 2019 Shawn Curry (noneyabiz@mail.wasent.cz)
6 ** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
7 ** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
8 **
9 **
10 ** This file may be distributed and/or modified under the terms of the
11 ** GNU General Public License version 2 as published by the Free Software
12 ** Foundation and appearing in the file gpl-2.0.txt included in the
13 ** packaging of this file.
14 **
15 ** This program is distributed in the hope that it will be useful,
16 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ** GNU General Public License for more details.
19 **
20 ** You should have received a copy of the GNU General Public License
21 ** along with this program; if not, write to the Free Software
22 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 **
24 ** This copyright notice MUST APPEAR in all copies of the script!
25 **
26 **********************************************************************/
27 #include<iostream>
28 #include "qc_mdiwindow.h"
29
30 #include <QtPrintSupport/QPrinter>
31 #include <QtPrintSupport/QPrintDialog>
32
33 #include <QApplication>
34 #include <QCloseEvent>
35 #include <QCursor>
36 #include <QMessageBox>
37 #include <QFileInfo>
38 #include <QMdiArea>
39 #include <QPainter>
40
41 #include "rs_graphic.h"
42 #include "rs_settings.h"
43 #include "qg_exitdialog.h"
44 #include "qg_filedialog.h"
45 #include "rs_insert.h"
46 #include "rs_mtext.h"
47 #include "rs_pen.h"
48 #include "qg_graphicview.h"
49 #include "rs_debug.h"
50
51 int QC_MDIWindow::idCounter = 0;
52
53 /**
54 * Constructor.
55 *
56 * @param doc Pointer to an existing document of NULL if a new
57 * document shall be created for this window.
58 * @param parent An instance of QMdiArea.
59 */
QC_MDIWindow(RS_Document * doc,QWidget * parent,Qt::WindowFlags wflags)60 QC_MDIWindow::QC_MDIWindow(RS_Document* doc, QWidget* parent, Qt::WindowFlags wflags)
61 : QMdiSubWindow(parent, wflags)
62 {
63 setAttribute(Qt::WA_DeleteOnClose);
64 cadMdiArea=qobject_cast<QMdiArea*>(parent);
65
66 if (doc==nullptr) {
67 document = new RS_Graphic();
68 document->newDoc();
69 owner = true;
70 } else {
71 document = doc;
72 owner = false;
73 }
74
75 graphicView = new QG_GraphicView(this, 0, document);
76 graphicView->setObjectName("graphicview");
77
78 connect(graphicView, SIGNAL(previous_zoom_state(bool)),
79 parent->window(), SLOT(setPreviousZoomEnable(bool)));
80
81 setWidget(graphicView);
82
83 id = idCounter++;
84 setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Preferred);
85 if (document) {
86 if (document->getLayerList()) {
87 // Link the graphic view to the layer widget
88 document->getLayerList()->addListener(graphicView);
89 // Link this window to the layer widget
90 document->getLayerList()->addListener(this);
91 }
92 if (document->getBlockList()) {
93 // Link the graphic view to the block widget
94 document->getBlockList()->addListener(graphicView);
95 // Link this window to the block widget
96 document->getBlockList()->addListener(this);
97 }
98 }
99 }
100
101 /**
102 * Destructor.
103 *
104 * Deletes the document associated with this window.
105 */
~QC_MDIWindow()106 QC_MDIWindow::~QC_MDIWindow()
107 {
108 RS_DEBUG->print("~QC_MDIWindow");
109 if(!(graphicView && graphicView->isCleanUp())){
110
111 //do not clear layer/block lists, if application is being closed
112
113 if (document->getLayerList()) {
114 document->getLayerList()->removeListener(graphicView);
115 document->getLayerList()->removeListener(this);
116 }
117
118 if (document->getBlockList()) {
119 document->getBlockList()->removeListener(graphicView);
120 document->getBlockList()->removeListener(this);
121 }
122
123 if (owner==true && document) {
124 delete document;
125 }
126 document = nullptr;
127 }
128 }
129
getGraphicView() const130 QG_GraphicView* QC_MDIWindow::getGraphicView() const
131 {
132 return (graphicView) ? graphicView : nullptr;
133 }
134
135 /** @return Pointer to document */
getDocument() const136 RS_Document* QC_MDIWindow::getDocument() const{
137 return document;
138 }
139
getId() const140 int QC_MDIWindow::getId() const{
141 return id;
142 }
143
getEventHandler() const144 RS_EventHandler* QC_MDIWindow::getEventHandler() const{
145 if (graphicView) {
146 return graphicView->getEventHandler();
147 }
148 else {
149 return nullptr;
150 }
151 }
152
setParentWindow(QC_MDIWindow * p)153 void QC_MDIWindow::setParentWindow(QC_MDIWindow* p) {
154 RS_DEBUG->print("QC_MDIWindow::setParentWindow");
155 parentWindow = p;
156 }
157
getParentWindow() const158 QC_MDIWindow* QC_MDIWindow::getParentWindow() const {
159 RS_DEBUG->print("QC_MDIWindow::getParentWindow");
160 return parentWindow;
161 }
162
getGraphic() const163 RS_Graphic* QC_MDIWindow::getGraphic() const {
164 return document->getGraphic();
165 }
166
167 /**
168 * Adds another MDI window to the list of known windows that
169 * depend on this one. This can be another view or a view for
170 * a particular block.
171 */
addChildWindow(QC_MDIWindow * w)172 void QC_MDIWindow::addChildWindow(QC_MDIWindow* w) {
173 RS_DEBUG->print("RS_MDIWindow::addChildWindow()");
174
175 childWindows.append(w);
176 w->setParentWindow(this);
177
178 RS_DEBUG->print("children: %d", childWindows.count());
179 }
180
181
182
183 /**
184 * Removes a child window.
185 *
186 * @see addChildWindow
187 */
removeChildWindow(QC_MDIWindow * w)188 void QC_MDIWindow::removeChildWindow(QC_MDIWindow* w) {
189 // RS_DEBUG->print("%s %s()", __FILE__, __func__);
190 if(childWindows.size()>0 ){
191 if(childWindows.contains(w)){
192 childWindows.removeAll(w);
193 // suc=true;
194 }
195 }
196
197 // bool suc = childWindows.removeAll(w);
198 // RS_DEBUG->print("successfully removed child window: %d", (int)suc);
199
200 // RS_DEBUG->print("children: %d", childWindows.count());
201
202 }
203
getChildWindows()204 QList<QC_MDIWindow*>& QC_MDIWindow::getChildWindows()
205 {
206 return childWindows;
207 }
208
209
210
211 /**
212 * @return pointer to the print preview of this drawing or NULL.
213 */
getPrintPreview()214 QC_MDIWindow* QC_MDIWindow::getPrintPreview() {
215 for(auto w: childWindows){
216 if(w->getGraphicView()->isPrintPreview()){
217 return w;
218 }
219 }
220 return nullptr;
221 }
222
223
224 /**
225 * Called by Qt when the user closes this MDI window.
226 */
closeEvent(QCloseEvent * ce)227 void QC_MDIWindow::closeEvent(QCloseEvent* ce) {
228 RS_DEBUG->print("QC_MDIWindow::closeEvent begin");
229
230 emit(signalClosing(this));
231 ce->accept(); // handling delegated to QApplication
232
233 RS_DEBUG->print("QC_MDIWindow::closeEvent end");
234 }
235
236
237 /**
238 * Called when the current pen (color, style, width) has changed.
239 * Sets the active pen for the document in this MDI window.
240 */
slotPenChanged(const RS_Pen & pen)241 void QC_MDIWindow::slotPenChanged(const RS_Pen& pen) {
242 RS_DEBUG->print("QC_MDIWindow::slotPenChanged() begin");
243 if (document) {
244 document->setActivePen(pen);
245 }
246 RS_DEBUG->print("QC_MDIWindow::slotPenChanged() end");
247 }
248
249
250 /**
251 * Creates a new empty document in this MDI window.
252 */
slotFileNew()253 void QC_MDIWindow::slotFileNew() {
254 RS_DEBUG->print("QC_MDIWindow::slotFileNew begin");
255 if (document && graphicView) {
256 document->newDoc();
257 graphicView->redraw();
258 }
259 RS_DEBUG->print("QC_MDIWindow::slotFileNew end");
260 }
261
262
263 /**
264 * Creates a new document, loading template, in this MDI window.
265 */
slotFileNewTemplate(const QString & fileName,RS2::FormatType type)266 bool QC_MDIWindow::slotFileNewTemplate(const QString& fileName, RS2::FormatType type) {
267 RS_DEBUG->print("QC_MDIWindow::slotFileNewTemplate begin");
268
269 bool ret = false;
270
271 if (document==NULL || fileName.isEmpty())
272 return ret;
273
274 document->newDoc();
275 ret = document->loadTemplate(fileName, type);
276 if (ret) {
277 RS_DEBUG->print("QC_MDIWindow::slotFileNewTemplate: autoZoom");
278 graphicView->zoomAuto(false);
279 } else
280 RS_DEBUG->print("QC_MDIWindow::slotFileNewTemplate: failed");
281
282 RS_DEBUG->print("QC_MDIWindow::slotFileNewTemplate end");
283 return ret;
284 }
285
286 /**
287 * Opens the given file in this MDI window.
288 */
slotFileOpen(const QString & fileName,RS2::FormatType type)289 bool QC_MDIWindow::slotFileOpen(const QString& fileName, RS2::FormatType type) {
290
291 RS_DEBUG->print("QC_MDIWindow::slotFileOpen");
292 bool ret = false;
293
294 if (document && !fileName.isEmpty()) {
295 document->newDoc();
296
297 // cosmetics..
298 // RVT_PORT qApp->processEvents(1000);
299 qApp->processEvents(QEventLoop::AllEvents, 1000);
300
301 ret = document->open(fileName, type);
302
303 if (ret) {
304 //QString message=tr("Loaded document: ")+fileName;
305 //statusBar()->showMessage(message, 2000);
306
307 if (fileName.endsWith(".lff") || fileName.endsWith(".cxf")) {
308 drawChars();
309
310 RS_DEBUG->print("QC_MDIWindow::slotFileOpen: autoZoom");
311 graphicView->zoomAuto(false);
312 RS_DEBUG->print("QC_MDIWindow::slotFileOpen: autoZoom: OK");
313 } else
314 graphicView->redraw();
315 } else {
316 RS_DEBUG->print("QC_MDIWindow::slotFileOpen: failed");
317 }
318 } else {
319 RS_DEBUG->print("QC_MDIWindow::slotFileOpen: cancelled");
320 //statusBar()->showMessage(tr("Opening aborted"), 2000);
321 }
322
323 RS_DEBUG->print("QC_MDIWindow::slotFileOpen: OK");
324
325 return ret;
326 }
327
slotZoomAuto()328 void QC_MDIWindow::slotZoomAuto() {
329 if(graphicView){
330 if(graphicView->isPrintPreview()){
331 graphicView->zoomPage();
332 }else{
333 graphicView->zoomAuto();
334 }
335 }
336 }
337
drawChars()338 void QC_MDIWindow::drawChars() {
339
340 RS_BlockList* bl = document->getBlockList();
341 double sep = document->getGraphic()->getVariableDouble("LetterSpacing", 3.0);
342 double h = sep/3;
343 sep = sep*3;
344 for (int i=0; i<bl->count(); ++i) {
345 RS_Block* ch = bl->at(i);
346 RS_InsertData data(ch->getName(), RS_Vector(i*sep,0), RS_Vector(1,1), 0, 1, 1, RS_Vector(0,0));
347 RS_Insert* in = new RS_Insert(document, data);
348 document->addEntity(in);
349 QFileInfo info(document->getFilename() );
350 QString uCode = (ch->getName()).mid(1,4);
351 RS_MTextData datatx(RS_Vector(i*sep,-h), h, 4*h, RS_MTextData::VATop,
352 RS_MTextData::HALeft, RS_MTextData::ByStyle, RS_MTextData::AtLeast,
353 1, uCode, "standard", 0);
354 /* RS_MTextData datatx(RS_Vector(i*sep,-h), h, 4*h, RS2::VAlignTop,
355 RS2::HAlignLeft, RS2::ByStyle, RS2::AtLeast,
356 1, uCode, info.baseName(), 0);*/
357 RS_MText *tx = new RS_MText(document, datatx);
358 document->addEntity(tx);
359 }
360
361 }
362
363
364 /**
365 * Saves the current file.
366 *
367 * @param isAutoSave true if this is an "autosave" operation.
368 * false if this is "Save" operation requested
369 * by the user.
370 * @return true if the file was saved successfully.
371 * false if the file could not be saved or the document
372 * is invalid.
373 */
slotFileSave(bool & cancelled,bool isAutoSave)374 bool QC_MDIWindow::slotFileSave(bool &cancelled, bool isAutoSave) {
375 RS_DEBUG->print("QC_MDIWindow::slotFileSave()");
376 bool ret = false;
377 cancelled = false;
378
379 if (document) {
380 document->setGraphicView(graphicView);
381 if (isAutoSave) {
382 // Autosave filename is always supposed to be present.
383 // Autosave does not change the cursor.
384 ret = document->save(true);
385 } else {
386 if (document->getFilename().isEmpty()) {
387 ret = slotFileSaveAs(cancelled);
388 } else {
389 QFileInfo info(document->getFilename());
390 if (!info.isWritable())
391 return false;
392 QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) );
393 ret = document->save();
394 QApplication::restoreOverrideCursor();
395 }
396 }
397 }
398
399 return ret;
400 }
401
402
403
404 /**
405 * Saves the current file. The user is asked for a new filename
406 * and format.
407 *
408 * @return true if the file was saved successfully or the user cancelled.
409 * false if the file could not be saved or the document
410 * is invalid.
411 */
slotFileSaveAs(bool & cancelled)412 bool QC_MDIWindow::slotFileSaveAs(bool &cancelled) {
413 RS_DEBUG->print("QC_MDIWindow::slotFileSaveAs");
414 bool ret = false;
415 cancelled = false;
416 RS2::FormatType t = RS2::FormatDXFRW;
417
418 QG_FileDialog dlg(this);
419 QString fn = dlg.getSaveFile(&t);
420 if (document && !fn.isEmpty()) {
421 QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) );
422 document->setGraphicView(graphicView);
423 ret = document->saveAs(fn, t, true);
424 QApplication::restoreOverrideCursor();
425 } else {
426 // cancel is not an error - returns true
427 ret = true;
428 cancelled = true;
429 }
430
431 return ret;
432 }
433
434
slotFilePrint()435 void QC_MDIWindow::slotFilePrint() {
436
437 RS_DEBUG->print("QC_MDIWindow::slotFilePrint");
438
439 //statusBar()->showMessage(tr("Printing..."));
440 QPrinter printer;
441 QPrintDialog dialog(&printer, this);
442 if (dialog.exec()) {
443 QPainter painter;
444 painter.begin(&printer);
445
446 ///////////////////////////////////////////////////////////////////
447 // TODO: Define printing by using the QPainter methods here
448
449 painter.end();
450 };
451
452 //statusBar()->showMessage(tr("Ready."));
453 }
454
455
456
457 /**
458 * Streams some info about an MDI window to stdout.
459 */
operator <<(std::ostream & os,QC_MDIWindow & w)460 std::ostream& operator << (std::ostream& os, QC_MDIWindow& w) {
461 os << "QC_MDIWindow[" << w.getId() << "]:\n";
462 if (w.parentWindow) {
463 os << " parentWindow: " << w.parentWindow->getId() << "\n";
464 } else {
465 os << " parentWindow: NULL\n";
466 }
467 int i=0;
468 for(auto p: w.childWindows){
469 os << " childWindow[" << i++ << "]: "
470 << p->getId() << "\n";
471 }
472
473 return os;
474 }
475
476 /**
477 * Return true if this window has children (QC_MDIWindow).
478 */
has_children()479 bool QC_MDIWindow::has_children()
480 {
481 return !childWindows.isEmpty();
482 }
483