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 "© 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