1 /*******************************************************************
2 
3 Part of the Fritzing project - http://fritzing.org
4 Copyright (c) 2007-2014 Fachhochschule Potsdam - http://fh-potsdam.de
5 
6 Fritzing is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10 
11 Fritzing is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with Fritzing.  If not, see <http://www.gnu.org/licenses/>.
18 
19 ********************************************************************
20 
21 $Revision: 6975 $:
22 $Author: irascibl@gmail.com $:
23 $Date: 2013-04-19 12:51:22 +0200 (Fr, 19. Apr 2013) $
24 
25 ********************************************************************/
26 
27 #include "fapplication.h"
28 #include "debugdialog.h"
29 #include "utils/misc.h"
30 #include "mainwindow/mainwindow.h"
31 #include "fsplashscreen.h"
32 #include "version/version.h"
33 #include "dialogs/prefsdialog.h"
34 #include "fsvgrenderer.h"
35 #include "version/versionchecker.h"
36 #include "version/updatedialog.h"
37 #include "itemdrag.h"
38 #include "items/wire.h"
39 #include "partsbinpalette/binmanager/binmanager.h"
40 #include "help/tipsandtricks.h"
41 #include "utils/folderutils.h"
42 #include "utils/lockmanager.h"
43 #include "utils/fmessagebox.h"
44 #include "dialogs/translatorlistmodel.h"
45 #include "partsbinpalette/partsbinview.h"
46 #include "partsbinpalette/svgiconwidget.h"
47 #include "partsbinpalette/partsbinpalettewidget.h"
48 #include "items/moduleidnames.h"
49 #include "partsbinpalette/searchlineedit.h"
50 #include "utils/ratsnestcolors.h"
51 #include "utils/cursormaster.h"
52 #include "utils/textutils.h"
53 #include "utils/graphicsutils.h"
54 #include "infoview/htmlinfoview.h"
55 #include "svg/gedaelement2svg.h"
56 #include "svg/kicadmodule2svg.h"
57 #include "svg/kicadschematic2svg.h"
58 #include "svg/gerbergenerator.h"
59 #include "installedfonts.h"
60 #include "items/pinheader.h"
61 #include "items/partfactory.h"
62 #include "items/propertydef.h"
63 #include "dialogs/recoverydialog.h"
64 #include "processeventblocker.h"
65 #include "autoroute/panelizer.h"
66 #include "sketch/sketchwidget.h"
67 #include "sketch/pcbsketchwidget.h"
68 #include "help/firsttimehelpdialog.h"
69 #include "help/aboutbox.h"
70 
71 // dependency injection :P
72 #include "referencemodel/sqlitereferencemodel.h"
73 #define CurrentReferenceModel SqliteReferenceModel
74 
75 #include <QSettings>
76 #include <QKeyEvent>
77 #include <QFileInfo>
78 #include <QDesktopServices>
79 #include <QLocale>
80 #include <QFileOpenEvent>
81 #include <QThread>
82 #include <QMessageBox>
83 #include <QTextStream>
84 #include <QFontDatabase>
85 #include <QtDebug>
86 #include <QNetworkAccessManager>
87 #include <QNetworkRequest>
88 #include <QMultiHash>
89 
90 #ifdef LINUX_32
91 #define PLATFORM_NAME "linux-32bit"
92 #endif
93 #ifdef LINUX_64
94 #define PLATFORM_NAME "linux-64bit"
95 #endif
96 #ifdef Q_OS_WIN
97 #ifdef WIN64
98 #define PLATFORM_NAME "windows-64bit"
99 #else
100 #define PLATFORM_NAME "windows"
101 #endif
102 #endif
103 #ifdef Q_OS_MAC
104 #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) || defined(QT_MAC_USE_COCOA)
105 #define PLATFORM_NAME "mac-os-x-105"
106 #else
107 #define PLATFORM_NAME "mac-os-x-104"
108 #endif
109 #endif
110 
111 #ifdef Q_OS_WIN
112 #ifndef QT_NO_DEBUG
113 #define WIN_DEBUG
114 #endif
115 #endif
116 
117 static const double LoadProgressStart = 0.085;
118 static const double LoadProgressEnd = 0.6;
119 
120 ////////////////////////////////////////////////////
121 
FServer(QObject * parent)122 FServer::FServer(QObject *parent)
123     : QTcpServer(parent)
124 {
125 }
126 
incomingConnection(int socketDescriptor)127 void FServer::incomingConnection(int socketDescriptor)
128 {
129     emit newConnection(socketDescriptor);
130 }
131 
132 ////////////////////////////////////////////////////
133 
134 QMutex FServerThread::m_busy;
135 
FServerThread(int socketDescriptor,QObject * parent)136 FServerThread::FServerThread(int socketDescriptor, QObject *parent) : QThread(parent), m_socketDescriptor(socketDescriptor)
137 {
138 }
139 
run()140  void FServerThread::run()
141  {
142     QTcpSocket * socket = new QTcpSocket();
143     if (!socket->setSocketDescriptor(m_socketDescriptor)) {
144         emit error(socket->error());
145         DebugDialog::debug(QString("Socket error %1 %2").arg(socket->error()).arg(socket->errorString()));
146         socket->deleteLater();
147         return;
148     }
149 
150     socket->waitForReadyRead();
151     QString header;
152     while (socket->canReadLine()) {
153         header += socket->readLine();
154     }
155 
156     DebugDialog::debug("header " + header);
157 
158     QStringList tokens = header.split(QRegExp("[ \r\n][ \r\n]*"), QString::SkipEmptyParts);
159     if (tokens.count() <= 0) {
160         writeResponse(socket, 400, "Bad Request", "", "");
161         return;
162     }
163 
164     if (tokens[0] != "GET") {
165         writeResponse(socket, 405, "Method Not Allowed", "", "");
166         return;
167     }
168 
169     if (tokens.count() < 2) {
170         writeResponse(socket, 400, "Bad Request", "", "");
171         return;
172     }
173 
174     QStringList params = tokens.at(1).split("/", QString::SkipEmptyParts);
175     QString command = params.takeFirst();
176     if (params.count() == 0) {
177         writeResponse(socket, 400, "Bad Request", "", "");
178         return;
179     }
180 
181     QString subFolder = params.join("/");
182 	bool fixSubFolder = false;
183     QString mimeType;
184     if (command == "svg") {
185 		 mimeType = "image/svg+xml";
186     }
187     else if (command == "gerber") {
188     }
189     else if (command == "svg-tcp") {
190 		fixSubFolder = true;
191     }
192     else if (command == "gerber-tcp") {
193 		fixSubFolder = true;
194     }
195     else {
196         writeResponse(socket, 400, "Bad Request", "", "");
197         return;
198     }
199 
200 	if (fixSubFolder) {
201 		// replace "/" that was removed from "http:/blah" above
202 		int ix = subFolder.indexOf(":/");
203 		if (ix >= 0) {
204 			subFolder.insert(ix + 1, "/");
205 		}
206 	}
207 
208     int waitInterval = 100;     // 100ms to wait
209     int timeoutSeconds = 2 * 60;    // timeout after 2 minutes
210     int attempts = timeoutSeconds * 1000 / waitInterval;  // timeout a
211     bool gotLock = false;
212     for (int i = 0; i < attempts; i++) {
213         if (m_busy.tryLock()) {
214             gotLock = true;
215             break;
216         }
217     }
218 
219     if (!gotLock) {
220         writeResponse(socket, 503, "Service Unavailable", "", "Server busy.");
221         return;
222     }
223 
224     DebugDialog::debug(QString("emitting do command %1 %2").arg(command).arg(subFolder));
225     QString result;
226 	int status;
227     emit doCommand(command, subFolder, result, status);
228 
229     m_busy.unlock();
230 
231 	if (status != 200) {
232 		writeResponse(socket, status, "failed", "", result);
233 	}
234 	else if (command.endsWith("tcp")) {
235 		QString filename = result;
236 		mimeType = "application/zip";
237 		QFile file(filename);
238 		if (file.open(QFile::ReadOnly)) {
239 			QString response = QString("HTTP/1.0 %1 %2\r\n").arg(200).arg("ok");
240 			response += QString("Content-Type: %1; charset=\"utf-8\"\r\n").arg(mimeType);
241 			response += QString("Content-Length: %1\r\n").arg(file.size());
242 			response += QString("\r\n");
243 			socket->write(response.toUtf8());
244 			int buffersize = 8192;
245 			long remaining = file.size();
246 			while (remaining >= buffersize) {
247 				QByteArray bytes = file.read(buffersize);
248 				socket->write(bytes);
249 				remaining -= buffersize;
250 			}
251 			if (remaining > 0) {
252 				QByteArray bytes = file.read(remaining);
253 				socket->write(bytes);
254 			}
255 			socket->disconnectFromHost();
256 			socket->waitForDisconnected();
257 			socket->deleteLater();
258 			file.close();
259 		}
260 		else {
261 			writeResponse(socket, 500, "failed", "", "local zip failure (2)");
262 		}
263 
264 		QFileInfo info(filename);
265 		QDir dir = info.dir();
266 		FolderUtils::rmdir(dir);
267 	}
268 	else {
269 		writeResponse(socket, 200, "Ok", mimeType, result);
270 	}
271 }
272 
writeResponse(QTcpSocket * socket,int code,const QString & codeString,const QString & mimeType,const QString & message)273 void FServerThread::writeResponse(QTcpSocket * socket, int code, const QString & codeString, const QString & mimeType, const QString & message)
274 {
275     QString type = mimeType;
276     if (type.isEmpty()) type = "text/plain";
277     QString response = QString("HTTP/1.0 %1 %2\r\n").arg(code).arg(codeString);
278     response += QString("Content-Type: %1; charset=\"utf-8\"\r\n").arg(type);
279     response += QString("Content-Length: %1\r\n").arg(message.count());
280     response += QString("\r\n%1").arg(message);
281 
282     socket->write(response.toUtf8());
283     socket->disconnectFromHost();
284     socket->waitForDisconnected();
285     socket->deleteLater();
286 }
287 
288 ////////////////////////////////////////////////////
289 
FApplication(int & argc,char ** argv)290 FApplication::FApplication( int & argc, char ** argv) : QApplication(argc, argv)
291 {
292     m_fServer = NULL;
293 	m_spaceBarIsPressed = false;
294 	m_mousePressed = false;
295 	m_referenceModel = NULL;
296 	m_started = false;
297 	m_updateDialog = NULL;
298 	m_lastTopmostWindow = NULL;
299 	m_serviceType = NoService;
300 	m_splash = NULL;
301 
302 	m_arguments = arguments();
303 }
304 
init()305 bool FApplication::init() {
306 
307 	//foreach (QString argument, m_arguments) {
308 		//DebugDialog::debug(QString("argument %1").arg(argument));
309 	//}
310 
311 	m_serviceType = NoService;
312 
313 	QList<int> toRemove;
314 	for (int i = 0; i < m_arguments.length(); i++) {
315 		if ((m_arguments[i].compare("-h", Qt::CaseInsensitive) == 0) ||
316 			(m_arguments[i].compare("-help", Qt::CaseInsensitive) == 0) ||
317 			(m_arguments[i].compare("--help", Qt::CaseInsensitive) == 0))
318 		{
319 			return false;
320 		}
321 
322 		if ((m_arguments[i].compare("-e", Qt::CaseInsensitive) == 0) ||
323 			(m_arguments[i].compare("-examples", Qt::CaseInsensitive) == 0)||
324 			(m_arguments[i].compare("--examples", Qt::CaseInsensitive) == 0)) {
325             DebugDialog::setEnabled(true);
326 			m_serviceType = ExampleService;
327 			m_outputFolder = " ";					// otherwise program will bail out
328 			toRemove << i;
329 		}
330 
331 		if ((m_arguments[i].compare("-d", Qt::CaseInsensitive) == 0) ||
332 			(m_arguments[i].compare("-debug", Qt::CaseInsensitive) == 0)||
333 			(m_arguments[i].compare("--debug", Qt::CaseInsensitive) == 0)) {
334 			DebugDialog::setEnabled(true);
335 			toRemove << i;
336 		}
337 
338 		if (i + 1 >= m_arguments.length()) continue;
339 
340 		if ((m_arguments[i].compare("-f", Qt::CaseInsensitive) == 0) ||
341 			(m_arguments[i].compare("-folder", Qt::CaseInsensitive) == 0)||
342 			(m_arguments[i].compare("--folder", Qt::CaseInsensitive) == 0))
343 		{
344 			FolderUtils::setApplicationPath(m_arguments[i + 1]);
345 			// delete these so we don't try to process them as files later
346 			toRemove << i << i + 1;
347 		}
348 
349 		if ((m_arguments[i].compare("-geda", Qt::CaseInsensitive) == 0) ||
350 			(m_arguments[i].compare("--geda", Qt::CaseInsensitive) == 0)) {
351 			m_serviceType = GedaService;
352 			m_outputFolder = m_arguments[i + 1];
353 			toRemove << i << i + 1;
354 		}
355 
356 		//if ((m_arguments[i].compare("-drc", Qt::CaseInsensitive) == 0) ||
357 		//	(m_arguments[i].compare("--drc", Qt::CaseInsensitive) == 0)) {
358 		//	m_serviceType = DRCService;
359 		//	m_outputFolder = m_arguments[i + 1];
360 		//	toRemove << i << i + 1;
361 		//}
362 
363 		if ((m_arguments[i].compare("-db", Qt::CaseInsensitive) == 0) ||
364             (m_arguments[i].compare("-database", Qt::CaseInsensitive) == 0) ||
365 			(m_arguments[i].compare("--database", Qt::CaseInsensitive) == 0)) {
366 			m_serviceType = DatabaseService;
367 			m_outputFolder = m_arguments[i + 1];
368 			toRemove << i << i + 1;
369 		}
370 
371 		if ((m_arguments[i].compare("-kicad", Qt::CaseInsensitive) == 0) ||
372 			(m_arguments[i].compare("--kicad", Qt::CaseInsensitive) == 0)) {
373 			m_serviceType = KicadFootprintService;
374 			m_outputFolder = m_arguments[i + 1];
375 			toRemove << i << i + 1;
376 		}
377 
378 		if ((m_arguments[i].compare("-kicadschematic", Qt::CaseInsensitive) == 0) ||
379 			(m_arguments[i].compare("--kicadschematic", Qt::CaseInsensitive) == 0)) {
380 			m_serviceType = KicadSchematicService;
381 			m_outputFolder = m_arguments[i + 1];
382 			toRemove << i << i + 1;
383 		}
384 
385 		if ((m_arguments[i].compare("-svg", Qt::CaseInsensitive) == 0) ||
386 			(m_arguments[i].compare("--svg", Qt::CaseInsensitive) == 0)) {
387 			m_serviceType = SvgService;
388             DebugDialog::setEnabled(true);
389 			m_outputFolder = m_arguments[i + 1];
390 			toRemove << i << i + 1;
391 		}
392 
393 		if ((m_arguments[i].compare("-port", Qt::CaseInsensitive) == 0) ||
394 			(m_arguments[i].compare("--port", Qt::CaseInsensitive) == 0)) {
395             DebugDialog::setEnabled(true);
396             bool ok;
397             int p = m_arguments[i + 1].toInt(&ok);
398             if (ok) {
399                 m_portNumber = p;
400             }
401 
402             toRemove << i << i + 1;
403 
404             if (i + 2 < m_arguments.count()) {
405                 if (ok) {
406                     m_portRootFolder = m_arguments[i + 2];
407                     m_serviceType = PortService;
408                 }
409                 toRemove << i + 2;
410             }
411 
412 			m_outputFolder = m_arguments[i + 1];
413 		}
414 
415 
416 
417 		if ((m_arguments[i].compare("-g", Qt::CaseInsensitive) == 0) ||
418 			(m_arguments[i].compare("-gerber", Qt::CaseInsensitive) == 0)||
419 			(m_arguments[i].compare("--gerber", Qt::CaseInsensitive) == 0)) {
420 			m_serviceType = GerberService;
421             DebugDialog::setEnabled(true);
422 			m_outputFolder = m_arguments[i + 1];
423 			toRemove << i << i + 1;
424 		}
425 
426 		if ((m_arguments[i].compare("-p", Qt::CaseInsensitive) == 0) ||
427 			(m_arguments[i].compare("-panel", Qt::CaseInsensitive) == 0)||
428 			(m_arguments[i].compare("--panel", Qt::CaseInsensitive) == 0)) {
429 			m_serviceType = PanelizerService;
430 			m_panelFilename = m_arguments[i + 1];
431 			m_outputFolder = " ";					// otherwise program will bail out
432             m_panelizerCustom = false;
433 			toRemove << i << i + 1;
434 		}
435 
436 		if ((m_arguments[i].compare("-pc", Qt::CaseInsensitive) == 0)) {
437 			m_serviceType = PanelizerService;
438 			m_panelFilename = m_arguments[i + 1];
439 			m_outputFolder = " ";					// otherwise program will bail out
440             m_panelizerCustom = true;
441 			toRemove << i << i + 1;
442 		}
443 
444 		if ((m_arguments[i].compare("-i", Qt::CaseInsensitive) == 0) ||
445 			(m_arguments[i].compare("-inscription", Qt::CaseInsensitive) == 0)||
446 			(m_arguments[i].compare("--inscription", Qt::CaseInsensitive) == 0)) {
447 			m_serviceType = InscriptionService;
448 			m_panelFilename = m_arguments[i + 1];
449 			m_outputFolder = " ";					// otherwise program will bail out
450 			toRemove << i << i + 1;
451 		}
452 
453 		if (m_arguments[i].compare("-ep", Qt::CaseInsensitive) == 0) {
454 			m_externalProcessPath = m_arguments[i + 1];
455 			toRemove << i << i + 1;
456 		}
457 
458 		if (m_arguments[i].compare("-eparg", Qt::CaseInsensitive) == 0) {
459 			m_externalProcessArgs << m_arguments[i + 1];
460 			toRemove << i << i + 1;
461 		}
462 
463 		if (m_arguments[i].compare("-epname", Qt::CaseInsensitive) == 0) {
464 			m_externalProcessName = m_arguments[i + 1];
465 			toRemove << i << i + 1;
466 		}
467 
468 	}
469 
470 	while (toRemove.count() > 0) {
471 		int ix = toRemove.takeLast();
472 		m_arguments.removeAt(ix);
473 	}
474 
475 	m_started = false;
476 	m_updateDialog = NULL;
477 	m_lastTopmostWindow = NULL;
478 
479 	connect(&m_activationTimer, SIGNAL(timeout()), this, SLOT(updateActivation()));
480 	m_activationTimer.setInterval(10);
481 	m_activationTimer.setSingleShot(true);
482 
483 	QCoreApplication::setOrganizationName("Fritzing");
484 	QCoreApplication::setOrganizationDomain("fritzing.org");
485 	QCoreApplication::setApplicationName("Fritzing");
486 
487 	installEventFilter(this);
488 
489 	// tell app where to search for plugins (jpeg export and sql lite)
490 	m_libPath = FolderUtils::getLibraryPath();
491 	QApplication::addLibraryPath(m_libPath);
492 
493 	/*QFile file("libpath.txt");
494 	if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
495 		QTextStream out(&file);
496 		out << m_libPath;
497 		file.close();
498 	}*/
499 
500 	// !!! translator must be installed before any widgets are created !!!
501 	m_translationPath = FolderUtils::getApplicationSubFolderPath("translations");
502 
503 	bool loaded = findTranslator(m_translationPath);
504 	Q_UNUSED(loaded);
505 
506 	Q_INIT_RESOURCE(phoenixresources);
507 
508 	MainWindow::initNames();
509 	FSvgRenderer::initNames();
510 	ViewLayer::initNames();
511 	RatsnestColors::initNames();
512 	Wire::initNames();
513 	ItemBase::initNames();
514 	ViewLayer::initNames();
515 	Connector::initNames();
516 	BinManager::initNames();
517 	PaletteModel::initNames();
518 	SvgIconWidget::initNames();
519 	PinHeader::initNames();
520 	CursorMaster::initCursors();
521 
522 #ifdef Q_OS_MAC
523 #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) || defined(QT_MAC_USE_COCOA)
524 	m_buildType = " Cocoa";
525 #else
526 	m_buildType = " Carbon";
527 #endif
528 #else
529     m_buildType = QString(PLATFORM_NAME).contains("64") ? "64" : "32";
530 #endif
531     AboutBox::initBuildType(m_buildType);
532 
533 	return true;
534 }
535 
~FApplication(void)536 FApplication::~FApplication(void)
537 {
538 	cleanupBackups();
539 
540 	clearModels();
541 
542 	if (m_updateDialog) {
543 		delete m_updateDialog;
544 	}
545 
546 	FSvgRenderer::cleanup();
547 	ViewLayer::cleanup();
548 	ViewLayer::cleanup();
549 	ItemBase::cleanup();
550 	Wire::cleanup();
551 	DebugDialog::cleanup();
552 	ItemDrag::cleanup();
553 	Version::cleanup();
554 	TipsAndTricks::cleanup();
555 	FirstTimeHelpDialog::cleanup();
556 	TranslatorListModel::cleanup();
557 	FolderUtils::cleanup();
558 	SearchLineEdit::cleanup();
559 	RatsnestColors::cleanup();
560 	HtmlInfoView::cleanup();
561 	SvgIconWidget::cleanup();
562 	PartFactory::cleanup();
563     PartsBinView::cleanup();
564     PropertyDefMaster::cleanup();
565     CursorMaster::cleanup();
566     LockManager::cleanup();
567     PartsBinPaletteWidget::cleanup();
568 }
569 
clearModels()570 void FApplication::clearModels() {
571 	if (m_referenceModel) {
572 		m_referenceModel->clearPartHash();
573 		delete m_referenceModel;
574 	}
575 }
576 
spaceBarIsPressed()577 bool FApplication::spaceBarIsPressed() {
578 	return ((FApplication *) qApp)->m_spaceBarIsPressed;
579 }
580 
581 
eventFilter(QObject * obj,QEvent * event)582 bool FApplication::eventFilter(QObject *obj, QEvent *event)
583 {
584 	// check whether the space bar is down.
585     //qDebug() << "event" << event->type();
586 
587 	Q_UNUSED(obj);
588 
589 	switch (event->type()) {
590 		case QEvent::MouseButtonPress:
591             //DebugDialog::debug("button press");
592 			m_mousePressed = true;
593 			break;
594 		case QEvent::MouseButtonRelease:
595             //DebugDialog::debug("button release");
596 			m_mousePressed = false;
597 			break;
598         case QEvent::Drop:
599             // at least under Windows, the MouseButtonRelease event is not triggered if the Drop event is triggered
600             m_mousePressed = false;
601             break;
602 		case QEvent::KeyPress:
603 			{
604                 //DebugDialog::debug(QString("key pressed %1 %2").arg(m_mousePressed).arg(QApplication::mouseButtons()));
605 				if (!m_mousePressed && !m_spaceBarIsPressed) {
606 					QKeyEvent * kevent = static_cast<QKeyEvent *>(event);
607 					if (!kevent->isAutoRepeat() && (kevent->key() == Qt::Key_Space)) {
608 						m_spaceBarIsPressed = true;
609                         //DebugDialog::debug("spacebar pressed");
610                         CursorMaster::instance()->block();
611                         setOverrideCursor(Qt::OpenHandCursor);
612 						emit spaceBarIsPressedSignal(true);
613 					}
614 				}
615 			}
616 			break;
617 		case QEvent::KeyRelease:
618 			{
619                 //DebugDialog::debug(QString("key released %1 %2").arg(m_mousePressed).arg(QApplication::mouseButtons()));
620 				if (m_spaceBarIsPressed) {
621 					QKeyEvent * kevent = static_cast<QKeyEvent *>(event);
622 					if (!kevent->isAutoRepeat() && (kevent->key() == Qt::Key_Space)) {
623 						m_spaceBarIsPressed = false;
624                         //DebugDialog::debug("spacebar pressed");
625                         restoreOverrideCursor();
626                         CursorMaster::instance()->unblock();
627 						emit spaceBarIsPressedSignal(false);
628 					}
629 				}
630 			}
631 			break;
632 		default:
633 			break;
634 	}
635 
636 	return false;
637 }
638 
639 
event(QEvent * event)640 bool FApplication::event(QEvent *event)
641 {
642     switch (event->type()) {
643 		case QEvent::FileOpen:
644 			{
645 				QString path = static_cast<QFileOpenEvent *>(event)->file();
646 				DebugDialog::debug(QString("file open %1").arg(path));
647 				if (m_started) {
648 					loadNew(path);
649 				}
650 				else {
651 					m_filesToLoad.append(path);
652 				}
653 
654 			}
655 			return true;
656 		default:
657 			return QApplication::event(event);
658     }
659 }
660 
findTranslator(const QString & translationsPath)661 bool FApplication::findTranslator(const QString & translationsPath) {
662 	QSettings settings;
663 	QString suffix = settings.value("language").toString();
664 	if (suffix.isEmpty()) {
665 		suffix = QLocale::system().name();	   // Returns the language and country of this locale as a string of the form "language_country", where language is a lowercase, two-letter ISO 639 language code, and country is an uppercase, two-letter ISO 3166 country code.
666 	}
667 	else {
668 		QLocale::setDefault(QLocale(suffix));
669 	}
670 
671     bool loaded = m_translator.load(QString("fritzing_") + suffix.toLower(), translationsPath);
672     DebugDialog::debug(QString("translation %1 loaded %2 from %3").arg(suffix).arg(loaded).arg(translationsPath));
673 	if (loaded) {
674 		QApplication::installTranslator(&m_translator);
675 	}
676 
677 	return loaded;
678 }
679 
registerFonts()680 void FApplication::registerFonts() {
681 	registerFont(":/resources/fonts/DroidSans.ttf", true);
682 	registerFont(":/resources/fonts/DroidSans-Bold.ttf", false);
683 	registerFont(":/resources/fonts/DroidSansMono.ttf", false);
684 	registerFont(":/resources/fonts/OCRA.ttf", true);
685 
686     // "Droid Sans"
687     // "Droid Sans Mono"
688 
689     /*
690 		QFontDatabase database;
691 		QStringList families = database.families (  );
692 		foreach (QString string, families) {
693 			DebugDialog::debug(string);			// should print out the name of the fonts you loaded
694 		}
695 */
696 
697 
698 }
699 
loadReferenceModel(const QString & databaseName,bool fullLoad)700 ReferenceModel * FApplication::loadReferenceModel(const QString & databaseName, bool fullLoad) {
701 	m_referenceModel = new CurrentReferenceModel();
702 	ItemBase::setReferenceModel(m_referenceModel);
703 	connect(m_referenceModel, SIGNAL(loadedPart(int, int)), this, SLOT(loadedPart(int, int)));
704 
705     bool dbExists = false;
706     QDir * dir = FolderUtils::getApplicationSubFolder("parts");
707     QString dbPath;
708     if (dir) {
709         dbPath = dir->absoluteFilePath("parts.db");
710         QFileInfo info(dbPath);
711         dbExists = info.exists();
712     }
713 
714 	bool ok = m_referenceModel->loadAll(databaseName, fullLoad, dbExists);		// loads local parts, resource parts, and any other parts in files not in the db--these part override db parts with the same moduleID
715     if (ok && databaseName.isEmpty()) {
716         if (dir == NULL) {
717         }
718         else {
719             QFile file(dir->absoluteFilePath("parts.db"));
720             if (file.exists()) {
721                 m_referenceModel->loadFromDB(dbPath);
722             }
723         }
724     }
725     delete dir;
726 
727 	return m_referenceModel;
728 }
729 
openWindowForService(bool lockFiles,int initialTab)730 MainWindow * FApplication::openWindowForService(bool lockFiles, int initialTab) {
731 	// our MainWindows use WA_DeleteOnClose so this has to be added to the heap (via new) rather than the stack (for local vars)
732 	MainWindow * mainWindow = MainWindow::newMainWindow(m_referenceModel, "", false, lockFiles, initialTab);   // this is also slow
733 	mainWindow->setReportMissingModules(false);
734     mainWindow->noBackup();
735     mainWindow->noSchematicConversion();
736 
737 	return mainWindow;
738 }
739 
serviceStartup()740 int FApplication::serviceStartup() {
741 
742 	if (m_outputFolder.isEmpty()) {
743 		return -1;
744 	}
745 
746 	switch (m_serviceType) {
747         case PortService:
748             initService();
749             {
750                 MainWindow * sketch = MainWindow::newMainWindow(m_referenceModel, "", true, true, -1);
751                 if (sketch) {
752                     sketch->show();
753                     sketch->clearFileProgressDialog();
754                 }
755             }
756             return 1;
757 
758 		case GedaService:
759 			runGedaService();
760 			return 0;
761 
762 		case DRCService:
763 			runDRCService();
764 			return 0;
765 
766 		case DatabaseService:
767 			runDatabaseService();
768 			return 0;
769 
770 		case KicadFootprintService:
771 			runKicadFootprintService();
772 			return 0;
773 
774 		case KicadSchematicService:
775 			runKicadSchematicService();
776 			return 0;
777 
778 		case GerberService:
779 			runGerberService();
780 			return 0;
781 
782 		case SvgService:
783 			runSvgService();
784 			return 0;
785 
786 		case PanelizerService:
787 			runPanelizerService();
788 			return 0;
789 
790 		case InscriptionService:
791 			runInscriptionService();
792 			return 0;
793 
794 		case ExampleService:
795 			runExampleService();
796 			return 0;
797 
798 		default:
799 			DebugDialog::debug("unknown service");
800 			return -1;
801 	}
802 }
803 
runGerberService()804 void FApplication::runGerberService()
805 {
806 	initService();
807     runGerberServiceAux();
808 }
809 
runGerberServiceAux()810 void FApplication::runGerberServiceAux()
811 {
812 	QDir dir(m_outputFolder);
813 	QString s = dir.absolutePath();
814 	QStringList filters;
815 	filters << "*" + FritzingBundleExtension;
816 	QStringList filenames = dir.entryList(filters, QDir::Files);
817 	foreach (QString filename, filenames) {
818 		QString filepath = dir.absoluteFilePath(filename);
819 		MainWindow * mainWindow = openWindowForService(false, 3);
820 		m_started = true;
821 
822 		FolderUtils::setOpenSaveFolderAux(m_outputFolder);
823 		if (mainWindow->loadWhich(filepath, false, false, false, "")) {
824             QFileInfo info(filepath);
825             GerberGenerator::exportToGerber(info.completeBaseName(), m_outputFolder, NULL, mainWindow->pcbView(), false);
826 		}
827 
828 		mainWindow->setCloseSilently(true);
829 		mainWindow->close();
830 	}
831 }
832 
initService()833 void FApplication::initService()
834 {
835 	createUserDataStoreFolderStructure();
836 	registerFonts();
837 	loadReferenceModel("", false);
838 }
839 
runSvgService()840 void FApplication::runSvgService()
841 {
842     initService();
843     runSvgServiceAux();
844 }
845 
runSvgServiceAux()846 void FApplication::runSvgServiceAux()
847 {
848 	QDir dir(m_outputFolder);
849 	QString s = dir.absolutePath();
850 	QStringList filters;
851 	filters << "*" + FritzingBundleExtension;
852 	QStringList filenames = dir.entryList(filters, QDir::Files);
853 	foreach (QString filename, filenames) {
854 		QString filepath = dir.absoluteFilePath(filename);
855         MainWindow * mainWindow = openWindowForService(false, -1);
856 		m_started = true;
857 
858 		FolderUtils::setOpenSaveFolderAux(m_outputFolder);
859 		if (mainWindow->loadWhich(filepath, false, false, false, "")) {
860             QFileInfo info(filepath);
861             QList<ViewLayer::ViewID> ids;
862             ids << ViewLayer::BreadboardView << ViewLayer::SchematicView << ViewLayer::PCBView;
863             foreach (ViewLayer::ViewID id, ids) {
864                 QString fn = QString("%1_%2.svg").arg(info.completeBaseName()).arg(ViewLayer::viewIDNaturalName(id));
865                 QString svgPath = dir.absoluteFilePath(fn);
866                 mainWindow->setCurrentView(id);
867                 mainWindow->exportSvg(GraphicsUtils::StandardFritzingDPI, false, false, svgPath);
868             }
869 		}
870 
871 		mainWindow->setCloseSilently(true);
872 		mainWindow->close();
873 	}
874 }
875 
runDatabaseService()876 void FApplication::runDatabaseService()
877 {
878 	createUserDataStoreFolderStructure();
879 
880     DebugDialog::setEnabled(true);
881     QDir * parent = FolderUtils::getApplicationSubFolder("pdb");
882     QFileInfoList dirs = parent->entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
883     delete parent;
884 
885     QStringList nameFilters;
886     nameFilters << ("*" + FritzingPartExtension);
887     foreach (QFileInfo dirInfo, dirs) {
888         if (!dirInfo.isDir()) continue;
889 
890         QDir dir(dirInfo.absoluteFilePath());
891         QFileInfoList files = dir.entryInfoList(nameFilters, QDir::Files | QDir::NoSymLinks);
892         foreach (QFileInfo fileInfo, files) {
893             QString path = fileInfo.absoluteFilePath();
894             QString newPath = path;
895             newPath.replace("/pdb/", "/parts/");
896             QFile::rename(path, newPath);
897         }
898     }
899 
900 
901     QFile::remove(m_outputFolder);
902 	loadReferenceModel(m_outputFolder, true);  // m_outputFolder is actually a full path ending in ".db"
903 }
904 
runGedaService()905 void FApplication::runGedaService() {
906 	try {
907 		QDir dir(m_outputFolder);
908 		QStringList filters;
909 		filters << "*.fp";
910 		QStringList filenames = dir.entryList(filters, QDir::Files);
911 		foreach (QString filename, filenames) {
912 			QString filepath = dir.absoluteFilePath(filename);
913 			QString newfilepath = filepath;
914 			newfilepath.replace(".fp", ".svg");
915 			GedaElement2Svg geda;
916 			QString svg = geda.convert(filepath, false);
917             TextUtils::writeUtf8(newfilepath, svg);
918 		}
919 	}
920 	catch (const QString & msg) {
921 		DebugDialog::debug(msg);
922 	}
923 	catch (...) {
924 		DebugDialog::debug("who knows");
925 	}
926 }
927 
928 
runDRCService()929 void FApplication::runDRCService() {
930     m_started = true;
931     initService();
932     DebugDialog::setEnabled(true);
933 
934     try {
935 		QDir dir(m_outputFolder);
936 		QStringList filters;
937 		filters << "*.fzz";
938 		QStringList filenames = dir.entryList(filters, QDir::Files);
939 		foreach (QString filename, filenames) {
940 			QString filepath = dir.absoluteFilePath(filename);
941 	        MainWindow * mainWindow = openWindowForService(false, 3);
942             if (mainWindow == NULL) continue;
943 
944             mainWindow->setCloseSilently(true);
945 
946 	        if (!mainWindow->loadWhich(filepath, false, false, false, "")) {
947 		        DebugDialog::debug(QString("failed to load '%1'").arg(filepath));
948 		        mainWindow->close();
949                 delete mainWindow;
950                 continue;
951 	        }
952 
953 	        mainWindow->showPCBView();
954 
955             int moved = mainWindow->pcbView()->checkLoadedTraces();
956             if (moved > 0) {
957                 QMessageBox::warning(NULL, QObject::tr("Fritzing"), QObject::tr("%1 wires moved from their saved position in %2.").arg(moved).arg(filepath));
958                 DebugDialog::debug(QString("\ncheckloadedtraces %1\n").arg(filepath));
959             }
960 
961 
962             Panelizer::checkDonuts(mainWindow, true);
963             Panelizer::checkText(mainWindow, true);
964 
965             QList<ItemBase *> boards = mainWindow->pcbView()->findBoard();
966 	        foreach (ItemBase * boardItem, boards) {
967                 mainWindow->pcbView()->selectAllItems(false, false);
968                 boardItem->setSelected(true);
969                 mainWindow->newDesignRulesCheck(false);
970             }
971 
972             mainWindow->close();
973             delete mainWindow;
974 		}
975 	}
976 	catch (const QString & msg) {
977 		DebugDialog::debug(msg);
978 	}
979 	catch (...) {
980 		DebugDialog::debug("who knows");
981 	}
982 }
983 
runKicadFootprintService()984 void FApplication::runKicadFootprintService() {
985 	QDir dir(m_outputFolder);
986 	QStringList filters;
987 	filters << "*.mod";
988 	QStringList filenames = dir.entryList(filters, QDir::Files);
989 	foreach (QString filename, filenames) {
990 		QString filepath = dir.absoluteFilePath(filename);
991 		QStringList moduleNames = KicadModule2Svg::listModules(filepath);
992 		foreach (QString moduleName, moduleNames) {
993 			KicadModule2Svg kicad;
994 			try {
995 				QString svg = kicad.convert(filepath, moduleName, false);
996 				if (svg.isEmpty()) {
997 					DebugDialog::debug("svg is empty " + filepath + " " + moduleName);
998 					continue;
999 				}
1000 				foreach (QChar c, QString("<>:\"/\\|?*")) {
1001 					moduleName.remove(c);
1002 				}
1003 
1004 				QString newFilePath = dir.absoluteFilePath(moduleName + "_" + filename);
1005 				newFilePath.replace(".mod", ".svg");
1006 
1007 				if (!TextUtils::writeUtf8(newFilePath, svg)) {
1008 					DebugDialog::debug("unable to open file " + newFilePath);
1009 				}
1010 			}
1011 			catch (const QString & msg) {
1012 				DebugDialog::debug(msg);
1013 			}
1014 			catch (...) {
1015 				DebugDialog::debug("who knows");
1016 			}
1017 		}
1018 	}
1019 }
1020 
runKicadSchematicService()1021 void FApplication::runKicadSchematicService() {
1022 	QDir dir(m_outputFolder);
1023 	QStringList filters;
1024 	filters << "*.lib";
1025 	QStringList filenames = dir.entryList(filters, QDir::Files);
1026 	foreach (QString filename, filenames) {
1027 		QString filepath = dir.absoluteFilePath(filename);
1028 		QStringList defNames = KicadSchematic2Svg::listDefs(filepath);
1029 		foreach (QString defName, defNames) {
1030 			KicadSchematic2Svg kicad;
1031 			try {
1032 				QString svg = kicad.convert(filepath, defName);
1033 				if (svg.isEmpty()) {
1034 					DebugDialog::debug("svg is empty " + filepath + " " + defName);
1035 					continue;
1036 				}
1037 				foreach (QChar c, QString("<>:\"/\\|?*")) {
1038 					defName.remove(c);
1039 				}
1040 
1041 				//DebugDialog::debug(QString("converting %1 %2").arg(defName).arg(filename));
1042 
1043 				QString newFilePath = dir.absoluteFilePath(defName + "_" + filename);
1044 				newFilePath.replace(".lib", ".svg");
1045 
1046 				QFile file(newFilePath);
1047 				if (!TextUtils::writeUtf8(newFilePath, svg)) {
1048 					DebugDialog::debug("unable to open file " + newFilePath);
1049 				}
1050 			}
1051 			catch (const QString & msg) {
1052 				DebugDialog::debug(msg);
1053 			}
1054 			catch (...) {
1055 				DebugDialog::debug("who knows");
1056 			}
1057 		}
1058 	}
1059 }
1060 
startup()1061 int FApplication::startup()
1062 {
1063 	//DebugDialog::setEnabled(true);
1064 
1065 	QString splashName = ":/resources/images/splash/splash_screen_start.png";
1066 	QDateTime now = QDateTime::currentDateTime();
1067 	if (now.date().month() == 4 && now.date().day() == 1) {
1068 		QString aSplashName = ":/resources/images/splash/april1st.png";
1069 		QFileInfo info(aSplashName);
1070 		if (info.exists()) {
1071 			splashName = aSplashName;
1072 		}
1073 	}
1074 
1075 	QPixmap pixmap(splashName);
1076 	FSplashScreen splash(pixmap);
1077 	m_splash = &splash;
1078 	ProcessEventBlocker::processEvents();								// seems to need this (sometimes?) to display the splash screen
1079 
1080 	initSplash(splash);
1081 	ProcessEventBlocker::processEvents();
1082 
1083 	// DebugDialog::debug("Data Location: "+QDesktopServices::storageLocation(QDesktopServices::DataLocation));
1084 
1085 	registerFonts();
1086 
1087 	if (m_progressIndex >= 0) splash.showProgress(m_progressIndex, LoadProgressStart);
1088 	ProcessEventBlocker::processEvents();
1089 
1090 	#ifdef Q_OS_WIN
1091 		// associate .fz file with fritzing app on windows (xp only--vista is different)
1092 		// TODO: don't change settings if they're already set?
1093 		// TODO: only do this at install time?
1094 		QSettings settings1("HKEY_CLASSES_ROOT\\Fritzing", QSettings::NativeFormat);
1095 		settings1.setValue(".", "Fritzing Application");
1096 		foreach (QString extension, fritzingExtensions()) {
1097 			QSettings settings2("HKEY_CLASSES_ROOT\\" + extension, QSettings::NativeFormat);
1098 			settings2.setValue(".", "Fritzing");
1099 		}
1100 		QSettings settings3("HKEY_CLASSES_ROOT\\Fritzing\\shell\\open\\command", QSettings::NativeFormat);
1101 		settings3.setValue(".", QString("\"%1\" \"%2\"")
1102 							.arg(QDir::toNativeSeparators(QApplication::applicationFilePath()))
1103 							.arg("%1") );
1104 	#endif
1105 
1106 	cleanFzzs();
1107 
1108     createUserDataStoreFolderStructure();
1109 
1110 	loadReferenceModel("", false);
1111 
1112 	QString prevVersion;
1113 	{
1114 		// put this in a block so that QSettings is closed
1115 		QSettings settings;
1116 		prevVersion = settings.value("version").toString();
1117 		QString currVersion = Version::versionString();
1118 		if(prevVersion != currVersion) {
1119 			QVariant pid = settings.value("pid");
1120             QVariant language = settings.value("language");
1121 			settings.clear();
1122 			if (!pid.isNull()) {
1123 				settings.setValue("pid", pid);
1124 			}
1125 			if (!language.isNull()) {
1126 				settings.setValue("language", language);
1127 			}
1128 		}
1129 	}
1130 
1131 	//bool fabEnabled = settings.value(ORDERFABENABLED, QVariant(false)).toBool();
1132 	//if (!fabEnabled) {
1133 		QNetworkAccessManager * manager = new QNetworkAccessManager(this);
1134 		connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(gotOrderFab(QNetworkReply *)));
1135 		manager->get(QNetworkRequest(QUrl(QString("http://fab.fritzing.org/launched%1").arg(Version::makeRequestParamsString(true)))));
1136 	//}
1137 
1138 	if (m_progressIndex >= 0) splash.showProgress(m_progressIndex, LoadProgressEnd);
1139 
1140 
1141 
1142 	//DebugDialog::debug("after createUserDataStoreFolderStructure");
1143 
1144 	if (m_progressIndex >= 0) splash.showProgress(m_progressIndex, 0.65);
1145 	ProcessEventBlocker::processEvents();
1146 
1147 	if (m_progressIndex >= 0) splash.showProgress(m_progressIndex, 0.825);
1148 	ProcessEventBlocker::processEvents();
1149 
1150 	m_updateDialog = new UpdateDialog();
1151 	connect(m_updateDialog, SIGNAL(enableAgainSignal(bool)), this, SLOT(enableCheckUpdates(bool)));
1152 	checkForUpdates(false);
1153 
1154 	if (m_progressIndex >= 0) splash.showProgress(m_progressIndex, 0.875);
1155 
1156 	DebugDialog::debug("load something");
1157 	loadSomething(prevVersion);
1158 	m_started = true;
1159 
1160 	if (m_progressIndex >= 0) splash.showProgress(m_progressIndex, 0.99);
1161 	ProcessEventBlocker::processEvents();
1162 
1163 	m_splash = NULL;
1164 	return 0;
1165 }
1166 
registerFont(const QString & fontFile,bool reallyRegister)1167 void FApplication::registerFont(const QString &fontFile, bool reallyRegister) {
1168 	int id = QFontDatabase::addApplicationFont(fontFile);
1169 	if(id > -1 && reallyRegister) {
1170 		QStringList familyNames = QFontDatabase::applicationFontFamilies(id);
1171 		QFileInfo finfo(fontFile);
1172 		foreach (QString family, familyNames) {
1173 			InstalledFonts::InstalledFontsNameMapper.insert(family, finfo.completeBaseName());
1174 			InstalledFonts::InstalledFontsList << family;
1175 			DebugDialog::debug(QString("registering font family: %1 %2").arg(family).arg(finfo.completeBaseName()));
1176 		}
1177 	}
1178 }
1179 
finish()1180 void FApplication::finish()
1181 {
1182 	QString currVersion = Version::versionString();
1183 	QSettings settings;
1184     settings.setValue("version", currVersion);
1185 }
1186 
loadNew(QString path)1187 void FApplication::loadNew(QString path) {
1188 	MainWindow * mw = MainWindow::newMainWindow(m_referenceModel, path, true, true, -1);
1189 	if (!mw->loadWhich(path, false, true, true, "")) {
1190 		mw->close();
1191 	}
1192 	mw->clearFileProgressDialog();
1193 }
1194 
loadOne(MainWindow * mw,QString path,int loaded)1195 void FApplication::loadOne(MainWindow * mw, QString path, int loaded) {
1196 	if (loaded == 0) {
1197 		mw->showFileProgressDialog(path);
1198 		mw->loadWhich(path, true, true, true, "");
1199 	}
1200 	else {
1201 		loadNew(path);
1202 	}
1203 }
1204 
preferences()1205 void FApplication::preferences() {
1206     // delay keeps OS 7 from crashing?
1207 
1208     QTimer::singleShot(30, this, SLOT(preferencesAfter()));
1209 }
1210 
preferencesAfter()1211 void FApplication::preferencesAfter()
1212 {
1213 	QDir dir(m_translationPath);
1214 	QStringList nameFilters;
1215 	nameFilters << "*.qm";
1216     QFileInfoList languages = dir.entryInfoList(nameFilters, QDir::Files | QDir::NoSymLinks);
1217 	QSettings settings;
1218 	QString language = settings.value("language").toString();
1219 	if (language.isEmpty()) {
1220 		language = QLocale::system().name();
1221 	}
1222 
1223 	MainWindow * mainWindow = NULL;
1224 	foreach (MainWindow * mw, orderedTopLevelMainWindows()) {
1225 		mainWindow = mw;
1226 		break;
1227 	}
1228 
1229 	if (mainWindow == NULL) return;			// shouldn't happen (maybe on the mac)
1230 
1231 	PrefsDialog prefsDialog(language, NULL);			// TODO: use the topmost MainWindow as parent
1232 	int ix = 0;
1233 	foreach (SketchWidget * sketchWidget, mainWindow->sketchWidgets()) {
1234 		prefsDialog.initViewInfo(ix++,  sketchWidget->viewName(), sketchWidget->getShortName(),
1235 									sketchWidget->curvyWires());
1236 	}
1237 
1238     QList<Platform *> platforms = mainWindow->programmingWidget()->getAvailablePlatforms();
1239 
1240     prefsDialog.initLayout(languages, platforms);
1241 	if (QDialog::Accepted == prefsDialog.exec()) {
1242 		updatePrefs(prefsDialog);
1243 	}
1244 }
1245 
updatePrefs(PrefsDialog & prefsDialog)1246 void FApplication::updatePrefs(PrefsDialog & prefsDialog)
1247 {
1248 	QSettings settings;
1249 
1250 	if (prefsDialog.cleared()) {
1251 		settings.clear();
1252 		return;
1253 	}
1254 
1255 	QHash<QString, QString> hash = prefsDialog.settings();
1256 	QList<MainWindow *> mainWindows = orderedTopLevelMainWindows();
1257 	foreach (QString key, hash.keys()) {
1258 		settings.setValue(key, hash.value(key));
1259 		if (key.compare("connectedColor") == 0) {
1260 			QColor c(hash.value(key));
1261 			ItemBase::setConnectedColor(c);
1262 			foreach (MainWindow * mainWindow, mainWindows) {
1263 				mainWindow->redrawSketch();
1264 			}
1265 		}
1266 		else if (key.compare("unconnectedColor") == 0) {
1267 			QColor c(hash.value(key));
1268 			ItemBase::setUnconnectedColor(c);
1269 			foreach (MainWindow * mainWindow, mainWindows) {
1270 				mainWindow->redrawSketch();
1271 			}
1272 		}
1273 		else if (key.compare("wheelMapping") == 0) {
1274 			ZoomableGraphicsView::setWheelMapping((ZoomableGraphicsView::WheelMapping) hash.value(key).toInt());
1275 		}
1276 		else if (key.compare("autosavePeriod") == 0) {
1277 			MainWindow::setAutosavePeriod(hash.value(key).toInt());
1278 		}
1279 		else if (key.compare("autosaveEnabled") == 0) {
1280 			MainWindow::setAutosaveEnabled(hash.value(key).toInt());
1281 		}
1282 		else if (key.contains("curvy", Qt::CaseInsensitive)) {
1283 			foreach (MainWindow * mainWindow, mainWindows) {
1284 				foreach (SketchWidget * sketchWidget, mainWindow->sketchWidgets()) {
1285 					if (key.contains(sketchWidget->getShortName())) {
1286 						sketchWidget->setCurvyWires(hash.value(key).compare("1") == 0);
1287 					}
1288 				}
1289 			}
1290 		}
1291 	}
1292 
1293 }
1294 
initSplash(FSplashScreen & splash)1295 void FApplication::initSplash(FSplashScreen & splash) {
1296 	QPixmap logo(":/resources/images/splash/fhp_logo_small.png");
1297 	QPixmap progress(":/resources/images/splash/splash_progressbar.png");
1298 
1299 	m_progressIndex = splash.showPixmap(progress, "progress");
1300 	if (m_progressIndex >= 0) splash.showProgress(m_progressIndex, 0);
1301 
1302 	// put this above the progress indicator
1303 	splash.showPixmap(logo, "fhpLogo");
1304 
1305 	QString msg1 = QObject::tr("<font face='Lucida Grande, Tahoma, Sans Serif' size='2' color='#eaf4ed'>"
1306 							   "&#169; 2007-%1 Fachhochschule Potsdam"
1307 							   "</font>")
1308 							.arg(Version::year());
1309 	splash.showMessage(msg1, "fhpText", Qt::AlignLeft | Qt::AlignTop);
1310 
1311 	QString msg2 = QObject::tr("<font face='Lucida Grande, Tahoma, Sans Serif' size='2' color='#eaf4ed'>"
1312 							   "Version %1.%2.%3 (%4%5) %6"
1313 							   "</font>")
1314 						.arg(Version::majorVersion())
1315 						.arg(Version::minorVersion())
1316 						.arg(Version::minorSubVersion())
1317 						.arg(Version::modifier())
1318 						.arg(Version::shortDate())
1319 						.arg(m_buildType);
1320 	splash.showMessage(msg2, "versionText", Qt::AlignRight | Qt::AlignTop);
1321     splash.show();
1322 }
1323 
1324 struct Thing {
1325         QString moduleID;
1326         ViewLayer::ViewID viewID;
1327         ViewLayer::ViewLayerID viewLayerID;
1328 };
1329 
1330 
checkForUpdates()1331 void FApplication::checkForUpdates() {
1332 	checkForUpdates(true);
1333 }
1334 
checkForUpdates(bool atUserRequest)1335 void FApplication::checkForUpdates(bool atUserRequest)
1336 {
1337 	if (atUserRequest) {
1338 		enableCheckUpdates(false);
1339 	}
1340 
1341 	VersionChecker * versionChecker = new VersionChecker();
1342 
1343 	QSettings settings;
1344 	if (!atUserRequest) {
1345 		// if I've already been notified about these updates, don't bug me again
1346 		QString lastMainVersionChecked = settings.value("lastMainVersionChecked").toString();
1347 		if (!lastMainVersionChecked.isEmpty()) {
1348 			versionChecker->ignore(lastMainVersionChecked, false);
1349 		}
1350 		QString lastInterimVersionChecked = settings.value("lastInterimVersionChecked").toString();
1351 		if (!lastInterimVersionChecked.isEmpty()) {
1352 			versionChecker->ignore(lastInterimVersionChecked, true);
1353 		}
1354 	}
1355 
1356     QString atom = QString("http://fritzing.org/download/feed/atom/%1/%2")
1357 		.arg(PLATFORM_NAME)
1358 		.arg(Version::makeRequestParamsString(true));
1359     DebugDialog::debug(atom);
1360     versionChecker->setUrl(atom);
1361 	m_updateDialog->setAtUserRequest(atUserRequest);
1362 	m_updateDialog->setVersionChecker(versionChecker);
1363 
1364 	if (atUserRequest) {
1365 		m_updateDialog->show();
1366 	}
1367 }
1368 
enableCheckUpdates(bool enabled)1369 void FApplication::enableCheckUpdates(bool enabled)
1370 {
1371 	//DebugDialog::debug("before enable check updates");
1372     foreach (QWidget *widget, QApplication::topLevelWidgets()) {
1373         MainWindow *mainWindow = qobject_cast<MainWindow *>(widget);
1374 		if (mainWindow) {
1375 			mainWindow->enableCheckUpdates(enabled);
1376 		}
1377 	}
1378 	//DebugDialog::debug("after enable check updates");
1379 }
1380 
1381 
createUserDataStoreFolderStructure()1382 void FApplication::createUserDataStoreFolderStructure() {
1383 	// make sure that the folder structure for parts and bins, exists
1384 	QString userDataStorePath = FolderUtils::getUserDataStorePath();
1385 	QDir dataStore(userDataStorePath);
1386 	QStringList dataFolders = FolderUtils::getUserDataStoreFolders();
1387 	foreach(QString folder, dataFolders) {
1388 		if(!QFileInfo(dataStore.absolutePath()+folder).exists()) {
1389 			QString folderaux = folder.startsWith("/")? folder.remove(0,1): folder;
1390 			dataStore.mkpath(folder);
1391 		}
1392 	}
1393 
1394     FolderUtils::copyBin(BinManager::MyPartsBinLocation, BinManager::MyPartsBinTemplateLocation);
1395     FolderUtils::copyBin(BinManager::SearchBinLocation, BinManager::SearchBinTemplateLocation);
1396 	PartFactory::initFolder();
1397 
1398 }
1399 
1400 
changeActivation(bool activate,QWidget * originator)1401 void FApplication::changeActivation(bool activate, QWidget * originator) {
1402 	if (!activate) return;
1403 
1404 	//DebugDialog::debug(QString("change activation %1 %2").arg(activate).arg(originator->metaObject()->className()));
1405 
1406 	FritzingWindow * fritzingWindow = qobject_cast<FritzingWindow *>(originator);
1407 	if (fritzingWindow == NULL) {
1408 		fritzingWindow = qobject_cast<FritzingWindow *>(originator->parent());
1409 	}
1410 	if (fritzingWindow == NULL) return;
1411 
1412 	m_orderedTopLevelWidgets.removeOne(fritzingWindow);
1413 	m_orderedTopLevelWidgets.push_front(fritzingWindow);
1414 
1415 	m_activationTimer.stop();
1416 	m_activationTimer.start();
1417 }
1418 
updateActivation()1419 void FApplication::updateActivation() {
1420 	//DebugDialog::debug("updating activation");
1421 
1422 	FritzingWindow * prior = m_lastTopmostWindow;
1423 	m_lastTopmostWindow = NULL;
1424 	if (m_orderedTopLevelWidgets.count() > 0) {
1425 		m_lastTopmostWindow = qobject_cast<FritzingWindow *>(m_orderedTopLevelWidgets.at(0));
1426 	}
1427 
1428 	if (prior == m_lastTopmostWindow) {
1429 		//DebugDialog::debug("done updating activation");
1430 		return;
1431 	}
1432 
1433 	//DebugDialog::debug(QString("last:%1, new:%2").arg((long) prior, 0, 16).arg((long) m_lastTopmostWindow.data(), 0, 16));
1434 
1435 	MainWindow * priorMainWindow = qobject_cast<MainWindow *>(prior);
1436 	if (priorMainWindow != NULL) {
1437 		priorMainWindow->saveDocks();
1438 	}
1439 
1440 	MainWindow * lastTopmostMainWindow = qobject_cast<MainWindow *>(m_lastTopmostWindow);
1441 	if (lastTopmostMainWindow != NULL) {
1442 		lastTopmostMainWindow->restoreDocks();
1443 		//DebugDialog::debug("restoring active window");
1444 	}
1445 
1446 	//DebugDialog::debug("done 2 updating activation");
1447 
1448 }
1449 
topLevelWidgetDestroyed(QObject * object)1450 void FApplication::topLevelWidgetDestroyed(QObject * object) {
1451 	QWidget * widget = qobject_cast<QWidget *>(object);
1452 	if (widget) {
1453 		m_orderedTopLevelWidgets.removeOne(widget);
1454 	}
1455 }
1456 
closeAllWindows2()1457 void FApplication::closeAllWindows2() {
1458 /*
1459 Ok, near as I can tell, here's what's going on.  When you quit fritzing, the function
1460 QApplication::closeAllWindows() is invoked.  This goes through the top-level window
1461 list in random order and calls close() on each window, until some window says "no".
1462 The QGraphicsProxyWidgets must contain top-level windows, and at least on the mac, their response to close()
1463 seems to be setVisible(false).  The random order explains why different icons
1464 disappear, or sometimes none at all.
1465 
1466 So the hack for now is to call the windows in non-random order.
1467 
1468 Eventually, maybe the SvgIconWidget class could be rewritten so that it's not using QGraphicsProxyWidget,
1469 which is really not intended for hundreds of widgets.
1470 
1471 (SvgIconWidget has been rewritten)
1472 */
1473 
1474 
1475 // this code modified from QApplication::closeAllWindows()
1476 
1477 
1478     bool did_close = true;
1479     QWidget *w;
1480     while((w = QApplication::activeModalWidget()) && did_close) {
1481         if(!w->isVisible())
1482             break;
1483         did_close = w->close();
1484     }
1485 	if (!did_close) return;
1486 
1487     QWidgetList list = QApplication::topLevelWidgets();
1488     for (int i = 0; did_close && i < list.size(); ++i) {
1489         w = list.at(i);
1490         FritzingWindow *fWindow = qobject_cast<FritzingWindow *>(w);
1491 		if (fWindow == NULL) continue;
1492 
1493         if (w->isVisible() && w->windowType() != Qt::Desktop) {
1494             did_close = w->close();
1495             list = QApplication::topLevelWidgets();
1496             i = -1;
1497         }
1498     }
1499 	if (!did_close) return;
1500 
1501     list = QApplication::topLevelWidgets();
1502     for (int i = 0; did_close && i < list.size(); ++i) {
1503         w = list.at(i);
1504         if (w->isVisible() && w->windowType() != Qt::Desktop) {
1505             did_close = w->close();
1506             list = QApplication::topLevelWidgets();
1507             i = -1;
1508         }
1509     }
1510 
1511 }
1512 
runAsService()1513 bool FApplication::runAsService() {
1514     if (m_serviceType == PortService) {
1515         DebugDialog::setEnabled(true);
1516         initServer();
1517         //return false;
1518     }
1519 
1520 	return m_serviceType != NoService;
1521 }
1522 
loadedPart(int loaded,int total)1523 void FApplication::loadedPart(int loaded, int total) {
1524 	if (total == 0) return;
1525 	if (m_splash == NULL) return;
1526 
1527 	//DebugDialog::debug(QString("loaded %1 %2").arg(loaded).arg(total));
1528 	if (m_progressIndex >= 0) m_splash->showProgress(m_progressIndex, LoadProgressStart + ((LoadProgressEnd - LoadProgressStart) * loaded / (double) total));
1529 }
1530 
externalProcessSlot(QString & name,QString & path,QStringList & args)1531 void FApplication::externalProcessSlot(QString &name, QString &path, QStringList &args) {
1532 	name = m_externalProcessName;
1533 	path = m_externalProcessPath;
1534 	args = m_externalProcessArgs;
1535 }
1536 
notify(QObject * receiver,QEvent * e)1537 bool FApplication::notify(QObject *receiver, QEvent *e)
1538 {
1539     try {
1540         //qDebug() << QString("notify %1 %2").arg(receiver->metaObject()->className()).arg(e->type());
1541         return QApplication::notify(receiver, e);
1542     }
1543 	catch (char const *str) {
1544         FMessageBox::critical(NULL, tr("Fritzing failure"), tr("Fritzing caught an exception %1 from %2 in event %3")
1545 			.arg(str).arg(receiver->objectName()).arg(e->type()));
1546 	}
1547     catch (std::exception& exp) {
1548         // suggested in https://code.google.com/p/fritzing/issues/detail?id=2698
1549         qDebug() << QString("notify %1 %2").arg(receiver->metaObject()->className()).arg(e->type());
1550         FMessageBox::critical(NULL, tr("Fritzing failure"), tr("Fritzing caught an exception from %1 in event %2: %3").arg(receiver->objectName()).arg(e->type()).arg(exp.what()));
1551     }
1552     catch (...) {
1553         FMessageBox::critical(NULL, tr("Fritzing failure"), tr("Fritzing caught an exception from %1 in event %2").arg(receiver->objectName()).arg(e->type()));
1554     }
1555 	closeAllWindows2();
1556 	QApplication::exit(-1);
1557 	abort();
1558     return false;
1559 }
1560 
loadSomething(const QString & prevVersion)1561 void FApplication::loadSomething(const QString & prevVersion) {
1562     // At this point we're trying to determine what sketches to load which are from one of the following sources:
1563     // Only one of these sources will actually provide sketches to load and they're listed in order of priority:
1564 
1565     //		We found sketch backups to recover
1566 	//		there's a previous version (open an empty sketch)
1567 	//		files were double-clicked
1568     //		The last opened sketch
1569     //		A new blank sketch
1570 
1571 	initFilesToLoad();   // sets up m_filesToLoad from the command line on PC and Linux; mac uses a FileOpen event instead
1572 
1573 	initBackups();
1574 
1575 	DebugDialog::debug("checking for backups");
1576     QList<MainWindow*> sketchesToLoad = recoverBackups();
1577 
1578 	bool loadPrevious = false;
1579 	if (sketchesToLoad.isEmpty()) {
1580 		loadPrevious = !prevVersion.isEmpty() && Version::greaterThan(prevVersion, Version::FirstVersionWithDetachedUserData);
1581 	}
1582 
1583 	DebugDialog::debug(QString("load previous %1").arg(loadPrevious));
1584 
1585 	if (!loadPrevious && sketchesToLoad.isEmpty()) {
1586 		// Check for double-clicked files to load
1587 		DebugDialog::debug(QString("check files to load %1").arg(m_filesToLoad.count()));
1588 
1589         foreach (QString filename, m_filesToLoad) {
1590             DebugDialog::debug(QString("Loading non-service file %1").arg(filename));
1591             MainWindow *mainWindow = MainWindow::newMainWindow(m_referenceModel, filename, true, true, -1);
1592             mainWindow->loadWhich(filename, true, true, true, "");
1593             if (filename.endsWith(FritzingSketchExtension) || filename.endsWith(FritzingBundleExtension)) {
1594             }
1595             else {
1596                 mainWindow->addDefaultParts();
1597             }
1598             sketchesToLoad << mainWindow;
1599         }
1600 	}
1601 
1602     // Find any previously open sketches to reload
1603     if (!loadPrevious && sketchesToLoad.isEmpty()) {
1604 		DebugDialog::debug(QString("load last open"));
1605         // new logic here, we no longer open the most recent sketch, since it can be reached in one click from the welcome page
1606 		//sketchesToLoad = loadLastOpenSketch();
1607 	}
1608 
1609 	MainWindow * newBlankSketch = NULL;
1610 	if (sketchesToLoad.isEmpty()) {
1611 		DebugDialog::debug(QString("create empty sketch"));
1612 		newBlankSketch = MainWindow::newMainWindow(m_referenceModel, "", true, true, -1);
1613 		if (newBlankSketch) {
1614 			// make sure to start an empty sketch with a board
1615 			newBlankSketch->addDefaultParts();   // do this before call to show()
1616 			sketchesToLoad << newBlankSketch;
1617 		}
1618 	}
1619 
1620 	DebugDialog::debug(QString("finish up sketch loading"));
1621 
1622     // Finish loading the sketches and show them to the user
1623 	foreach (MainWindow* sketch, sketchesToLoad) {
1624 		sketch->show();
1625 		sketch->clearFileProgressDialog();
1626 	}
1627 
1628 	if (loadPrevious) {
1629 		doLoadPrevious(newBlankSketch);
1630 	}
1631 	else if (newBlankSketch) {
1632 		newBlankSketch->hideTempPartsBin();
1633         // new empty sketch defaults to welcome view
1634         newBlankSketch->showWelcomeView();
1635 	}
1636 }
1637 
loadLastOpenSketch()1638 QList<MainWindow *> FApplication::loadLastOpenSketch() {
1639 	QList<MainWindow *> sketches;
1640 	QSettings settings;
1641 	if(settings.value("lastOpenSketch").isNull()) return sketches;
1642 
1643 	QString lastSketchPath = settings.value("lastOpenSketch").toString();
1644 	if(!QFileInfo(lastSketchPath).exists()) {
1645 		settings.remove("lastOpenSketch");
1646 		return sketches;
1647 	}
1648 
1649     DebugDialog::debug(QString("Loading last open sketch %1").arg(lastSketchPath));
1650     settings.remove("lastOpenSketch");				// clear the preference, in case the load crashes
1651     MainWindow *mainWindow = MainWindow::newMainWindow(m_referenceModel, lastSketchPath, true, true, -1);
1652     mainWindow->loadWhich(lastSketchPath, true, true, true, "");
1653     sketches << mainWindow;
1654     settings.setValue("lastOpenSketch", lastSketchPath);	// the load works, so restore the preference
1655 	return sketches;
1656 }
1657 
doLoadPrevious(MainWindow * sketchWindow)1658 void FApplication::doLoadPrevious(MainWindow * sketchWindow) {
1659 	// Here we check if files need to be imported from an earlier version.
1660     // This should be done before any files are loaded as it requires a restart.
1661     // As this can generate UI it should come after the splash screen has closed.
1662 
1663     FMessageBox messageBox(sketchWindow);
1664     messageBox.setWindowTitle(tr("Import files from previous version?"));
1665     messageBox.setText(tr("Do you want to import parts and bins that you have created with earlier versions of Fritzing?\n"));
1666     messageBox.setInformativeText(tr("\nNote: You can import them later using the \"Help\" > \"Import parts and bins "
1667 									"from old version...\" menu action."));
1668     messageBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
1669     messageBox.setDefaultButton(QMessageBox::Cancel);
1670     messageBox.setIcon(QMessageBox::Question);
1671     messageBox.setWindowModality(Qt::WindowModal);
1672     messageBox.setButtonText(QMessageBox::Ok, tr("Import"));
1673     messageBox.setButtonText(QMessageBox::Cancel, tr("Do not import now"));
1674     QMessageBox::StandardButton answer = (QMessageBox::StandardButton) messageBox.exec();
1675 
1676     if(answer == QMessageBox::Ok) {
1677 		 sketchWindow->importFilesFromPrevInstall();
1678     }
1679 }
1680 
recoverBackups()1681 QList<MainWindow *> FApplication::recoverBackups()
1682 {
1683 	QFileInfoList backupList;
1684 	LockManager::checkLockedFiles("backup", backupList, m_lockedFiles, false, LockManager::FastTime);
1685 	for (int i = backupList.size() - 1; i >=0; i--) {
1686 		QFileInfo fileInfo = backupList.at(i);
1687 		if (!fileInfo.fileName().endsWith(FritzingSketchExtension)) {
1688 			backupList.removeAt(i);
1689 		}
1690 	}
1691 
1692 	QList<MainWindow*> recoveredSketches;
1693     if (backupList.size() == 0) return recoveredSketches;
1694 
1695     RecoveryDialog recoveryDialog(backupList);
1696 	int result = (QMessageBox::StandardButton)recoveryDialog.exec();
1697     QList<QTreeWidgetItem*> fileItems = recoveryDialog.getFileList();
1698     DebugDialog::debug(QString("Recovering %1 files from recoveryDialog").arg(fileItems.size()));
1699     foreach (QTreeWidgetItem * item, fileItems) {
1700 		QString backupName = item->data(0, Qt::UserRole).value<QString>();
1701         if (result == QDialog::Accepted && item->isSelected()) {
1702 			QString originalBaseName = item->text(0);
1703             DebugDialog::debug(QString("Loading recovered sketch %1").arg(originalBaseName));
1704 
1705 			QString originalPath = item->data(1, Qt::UserRole).value<QString>();
1706 			QString fileExt;
1707 			QString bundledFileName = FolderUtils::getSaveFileName(NULL, tr("Please specify an .fzz file name to save to (cancel will delete the backup)"), originalPath, tr("Fritzing (*%1)").arg(FritzingBundleExtension), &fileExt);
1708 			if (!bundledFileName.isEmpty()) {
1709 				MainWindow *currentRecoveredSketch = MainWindow::newMainWindow(m_referenceModel, originalBaseName, true, true, -1);
1710     			currentRecoveredSketch->mainLoad(backupName, bundledFileName, true);
1711 				currentRecoveredSketch->saveAsShareable(bundledFileName, true);
1712 				currentRecoveredSketch->setCurrentFile(bundledFileName, true, true);
1713 				recoveredSketches << currentRecoveredSketch;
1714 
1715 				/*
1716 				if (originalPath.startsWith(untitledFileName())) {
1717 					DebugDialog::debug(QString("Comparing untitled documents: %1 %2").arg(filename).arg(untitledFileName()));
1718 					QRegExp regexp("\\d+");
1719 					int ix = regexp.indexIn(filename);
1720 					int untitledSketchNumber = ix >= 0 ? regexp.cap(0).toInt() : 1;
1721 					untitledSketchNumber++;
1722 					DebugDialog::debug(QString("%1 untitled documents open, currently thinking %2").arg(untitledSketchNumber).arg(UntitledSketchIndex));
1723 					UntitledSketchIndex = UntitledSketchIndex >= untitledSketchNumber ? UntitledSketchIndex : untitledSketchNumber;
1724 				}
1725 				*/
1726 
1727 
1728 
1729 			}
1730         }
1731 
1732 		QFile::remove(backupName);
1733     }
1734 
1735 	return recoveredSketches;
1736 }
1737 
initFilesToLoad()1738 void FApplication::initFilesToLoad()
1739 {
1740 	for (int i = 1; i < m_arguments.length(); i++) {
1741 		QFileInfo fileinfo(m_arguments[i]);
1742 		if (fileinfo.exists() && !fileinfo.isDir()) {
1743 			m_filesToLoad << m_arguments[i];
1744 		}
1745 	}
1746 }
1747 
initBackups()1748 void FApplication::initBackups() {
1749 	LockManager::initLockedFiles("backup", MainWindow::BackupFolder, m_lockedFiles, LockManager::FastTime);
1750 }
1751 
cleanupBackups()1752 void FApplication::cleanupBackups() {
1753 	LockManager::releaseLockedFiles(MainWindow::BackupFolder, m_lockedFiles);
1754 }
1755 
gotOrderFab(QNetworkReply * networkReply)1756 void FApplication::gotOrderFab(QNetworkReply * networkReply) {
1757 	int responseCode = networkReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
1758 	if (responseCode == 200) {
1759 		QSettings settings;
1760 		settings.setValue(ORDERFABENABLED, QVariant(true));
1761 	}
1762     networkReply->manager()->deleteLater();
1763     networkReply->deleteLater();
1764 }
1765 
runPanelizerService()1766 void FApplication::runPanelizerService()
1767 {
1768 	m_started = true;
1769 	Panelizer::panelize(this, m_panelFilename, m_panelizerCustom);
1770 }
1771 
runInscriptionService()1772 void FApplication::runInscriptionService()
1773 {
1774 	m_started = true;
1775     bool drc = false;
1776     bool noMessages = false;
1777     foreach (QString arg, m_arguments) {
1778         if (arg.compare("-drc", Qt::CaseInsensitive) == 0) {
1779             drc = true;
1780         }
1781         if (arg.compare("-nm", Qt::CaseInsensitive) == 0) {
1782             noMessages = true;
1783         }
1784     }
1785 	Panelizer::inscribe(this, m_panelFilename, drc, noMessages);
1786 }
1787 
orderedTopLevelMainWindows()1788 QList<MainWindow *> FApplication::orderedTopLevelMainWindows() {
1789 	QList<MainWindow *> mainWindows;
1790 	foreach (QWidget * widget, m_orderedTopLevelWidgets) {
1791 		MainWindow * mainWindow = qobject_cast<MainWindow *>(widget);
1792 		if (mainWindow) mainWindows.append(mainWindow);
1793 	}
1794 	return mainWindows;
1795 }
1796 
runExampleService()1797 void FApplication::runExampleService()
1798 {
1799 	m_started = true;
1800 
1801 	initService();
1802 
1803 	QDir sketchesDir(FolderUtils::getApplicationSubFolderPath("sketches"));
1804 	runExampleService(sketchesDir);
1805 }
1806 
runExampleService(QDir & dir)1807 void FApplication::runExampleService(QDir & dir) {
1808 	QStringList nameFilters;
1809 	nameFilters << ("*" + FritzingBundleExtension);   //  FritzingSketchExtension
1810 	QFileInfoList fileList = dir.entryInfoList(nameFilters, QDir::Files | QDir::NoSymLinks);
1811 	foreach (QFileInfo fileInfo, fileList) {
1812 		QString path = fileInfo.absoluteFilePath();
1813 		DebugDialog::debug("sketch file " + path);
1814 
1815 		MainWindow * mainWindow = openWindowForService(false, -1);
1816 		if (mainWindow == NULL) continue;
1817 
1818 		FolderUtils::setOpenSaveFolderAux(dir.absolutePath());
1819 
1820 		if (!mainWindow->loadWhich(path, false, false, true, "")) {
1821 			DebugDialog::debug(QString("failed to load"));
1822 		}
1823 		else {
1824 			QList<ItemBase *> items = mainWindow->selectAllObsolete(false);
1825 			if (items.count() > 0) {
1826                 mainWindow->swapObsolete(false, items);
1827             }
1828 			mainWindow->saveAsAux(path);    //   path + "z"
1829 			mainWindow->setCloseSilently(true);
1830 			mainWindow->close();
1831 		}
1832 	}
1833 
1834 	QFileInfoList dirList = dir.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot | QDir::Hidden | QDir::NoSymLinks);
1835 	foreach (QFileInfo dirInfo, dirList) {
1836 		QDir dir(dirInfo.filePath());
1837 		runExampleService(dir);
1838 	}
1839 }
1840 
cleanFzzs()1841 void FApplication::cleanFzzs() {
1842 	QHash<QString, LockedFile *> lockedFiles;
1843 	QString folder;
1844 	LockManager::initLockedFiles("fzz", folder, lockedFiles, LockManager::SlowTime);
1845 	QFileInfoList backupList;
1846 	LockManager::checkLockedFiles("fzz", backupList, lockedFiles, true, LockManager::SlowTime);
1847 	LockManager::releaseLockedFiles(folder, lockedFiles);
1848 }
1849 
initServer()1850 void FApplication::initServer() {
1851     FMessageBox::BlockMessages = true;
1852     m_fServer = new FServer(this);
1853     connect(m_fServer, SIGNAL(newConnection(int)), this, SLOT(newConnection(int)));
1854     m_fServer->listen(QHostAddress::Any, m_portNumber);
1855 }
1856 
newConnection(int socketDescription)1857 void FApplication::newConnection(int socketDescription) {
1858      FServerThread *thread = new FServerThread(socketDescription, this);
1859      connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
1860      connect(thread, SIGNAL(doCommand(const QString &, const QString &, QString &, int &)),
1861 			this, SLOT(doCommand(const QString &, const QString &, QString &, int &)), Qt::BlockingQueuedConnection);
1862      thread->start();
1863 }
1864 
1865 
doCommand(const QString & command,const QString & params,QString & result,int & status)1866 void FApplication::doCommand(const QString & command, const QString & params, QString & result, int & status) {
1867 	status = 200;
1868 	result = "";
1869 
1870     QDir dir(m_portRootFolder);
1871 
1872 	QString subfolder = params;
1873 	if (command.endsWith("tcp")) {
1874 		subfolder = TextUtils::getRandText();
1875 		dir.mkdir(subfolder);
1876 	}
1877 
1878     dir.cd(subfolder);
1879     m_outputFolder = dir.absolutePath();
1880 
1881 	if (command.endsWith("tcp")) {
1882 		QEventLoop loop;
1883 		QNetworkAccessManager networkManager;
1884 		QObject::connect(&networkManager, SIGNAL(finished(QNetworkReply*)), &loop, SLOT(quit()));
1885 
1886 		QUrl url = params;
1887 		QNetworkReply* reply = networkManager.get(QNetworkRequest(url));
1888 
1889 		loop.exec();
1890 
1891 		status = 404;
1892 
1893 		if (reply->error() == QNetworkReply::NoError) {
1894 			if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toUInt() == 200) {
1895 				if (reply->isReadable()) {
1896 					int buffersize = 8192;
1897 					QStringList components = params.split("/");
1898 					QString filename = components.last();
1899 					QFile file(dir.absoluteFilePath(filename));
1900 					if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
1901 						status = 200;
1902 						while (reply->bytesAvailable() >= buffersize) {
1903 							QByteArray bytes = reply->read(buffersize);
1904 							file.write(bytes);
1905 						}
1906 						if (reply->bytesAvailable() > 0) {
1907 							file.write(reply->readAll());
1908 						}
1909 						file.close();
1910 					}
1911 					else {
1912 						result = "unable to save to local file";
1913 					}
1914 				}
1915 				else {
1916 					result = "response unreadable";
1917 				}
1918 			}
1919 			else {
1920 				result = QString("bad response from url server %1").arg(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toUInt());
1921 			}
1922 		}
1923 		else {
1924 			result = QString("url get failed %1").arg(reply->error());
1925 		}
1926 
1927 		reply->deleteLater();
1928 	}
1929 
1930 	if (!result.isEmpty()) {
1931 		// network problem
1932 		return;
1933 	}
1934 
1935 	if (command.startsWith("svg")) {
1936         runSvgServiceAux();
1937 	    QStringList nameFilters;
1938 	    nameFilters << ("*.svg");
1939 	    QFileInfoList fileList = dir.entryInfoList(nameFilters, QDir::Files | QDir::NoSymLinks);
1940         if (fileList.count() > 0) {
1941             QFile file(fileList.at(0).absoluteFilePath());
1942             if (file.open(QFile::ReadOnly)) {
1943                 result = file.readAll();
1944             }
1945         }
1946     }
1947     else if (command.startsWith("gerber")) {
1948         runGerberServiceAux();
1949 	    QStringList nameFilters;
1950 	    nameFilters << ("*.txt");
1951 	    QFileInfoList fileList = dir.entryInfoList(nameFilters, QDir::Files | QDir::NoSymLinks);
1952         if (fileList.count() > 0) {
1953             QFile file(fileList.at(0).absoluteFilePath());
1954             if (file.open(QFile::ReadOnly)) {
1955                 result = file.readAll();
1956             }
1957         }
1958     }
1959 
1960 
1961 	if (command.endsWith("tcp")) {
1962 		QStringList skipSuffixes(".zip");
1963 		skipSuffixes << ".fzz";
1964 		QString filename = dir.absoluteFilePath(subfolder + ".zip");
1965 		if (FolderUtils::createZipAndSaveTo(dir, filename, skipSuffixes)) {
1966 			status = 200;
1967 			result = filename;
1968 		}
1969 		else {
1970 			status = 500;
1971 			result = "local zip failure";
1972 		}
1973 	}
1974 }
1975 
1976 
1977