~ubuntu-branches/ubuntu/trusty/fritzing/trusty-proposed

« back to all changes in this revision

Viewing changes to src/mainwindow/mainwindow.cpp

  • Committer: Package Import Robot
  • Author(s): Enrique Hernández Bello
  • Date: 2012-11-11 21:38:56 UTC
  • mfrom: (1.1.5)
  • Revision ID: package-import@ubuntu.com-20121111213856-0825ywdrtdcshl91
Tags: 0.7.10b-1
* New upstream version. Closes: #661495, #692998
* Removed useless patches.
* Removed SetupAPI.lib from sourceless files.
* Skip dfsg tarball creation if there are no sourceless files.
* Added libqt4-sql-sqlite to dependencies. Thanks to Tom Hummel <tom@bluespice.org>.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*******************************************************************
 
2
 
 
3
Part of the Fritzing project - http://fritzing.org
 
4
Copyright (c) 2007-2012 Fachhochschule Potsdam - http://fh-potsdam.de
 
5
 
 
6
Fritzing is free software: you can redistribute it and/or modify
 
7
 
 
8
it under the terms of the GNU General Public License as published by
 
9
the Free Software Foundation, either version 3 of the License, or
 
10
(at your option) any later version.
 
11
 
 
12
Fritzing is distributed in the hope that it will be useful,
 
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
GNU General Public License for more details.
 
16
 
 
17
You should have received a copy of the GNU General Public License
 
18
along with Fritzing.  If not, see <http://www.gnu.org/licenses/>.
 
19
 
 
20
********************************************************************
 
21
 
 
22
$Revision: 6569 $:
 
23
$Author: irascibl@gmail.com $:
 
24
$Date: 2012-10-16 05:51:14 +0200 (Tue, 16 Oct 2012) $
 
25
 
 
26
********************************************************************/
 
27
 
 
28
#include <QtGui>
 
29
#include <QtXml>
 
30
#include <QList>
 
31
#include <QFileInfo>
 
32
#include <QStringList>
 
33
#include <QFileInfoList>
 
34
#include <QDir>
 
35
#include <QLabel>
 
36
#include <QTime>
 
37
#include <QSettings>
 
38
#include <QRegExp>
 
39
#include <QPaintDevice>
 
40
#include <QPixmap>
 
41
#include <QTimer>
 
42
#include <QStackedWidget>
 
43
#include <QXmlStreamReader>
 
44
#include <QShortcut>
 
45
 
 
46
#include "mainwindow.h"
 
47
#include "../debugdialog.h"
 
48
#include "../connectors/connector.h"
 
49
#include "../partsbinpalette/partsbinpalettewidget.h"
 
50
#include "fdockwidget.h"
 
51
#include "../infoview/htmlinfoview.h"
 
52
#include "../waitpushundostack.h"
 
53
#include "../layerattributes.h"
 
54
#include "../dock/triplenavigator.h"
 
55
#include "../sketch/breadboardsketchwidget.h"
 
56
#include "../sketch/schematicsketchwidget.h"
 
57
#include "../sketch/pcbsketchwidget.h"
 
58
#include "../svg/svgfilesplitter.h"
 
59
#include "../utils/folderutils.h"
 
60
#include "../utils/lockmanager.h"
 
61
#include "../utils/textutils.h"
 
62
#include "../utils/graphicsutils.h"
 
63
#include "../items/mysterypart.h"
 
64
#include "../items/moduleidnames.h"
 
65
#include "../items/pinheader.h"
 
66
#include "../items/perfboard.h"
 
67
#include "../items/stripboard.h"
 
68
#include "../items/partfactory.h"
 
69
#include "../dock/layerpalette.h"
 
70
#include "../items/paletteitem.h"
 
71
#include "../items/virtualwire.h"
 
72
#include "../items/screwterminal.h"
 
73
#include "../items/dip.h"
 
74
#include "../processeventblocker.h"
 
75
#include "../help/helper.h"
 
76
#include "../sketchtoolbutton.h"
 
77
#include "../partsbinpalette/binmanager/binmanager.h"
 
78
#include "../fsvgrenderer.h"
 
79
#include "../utils/fsizegrip.h"
 
80
#include "../utils/expandinglabel.h"
 
81
#include "../dock/viewswitcher.h"
 
82
#include "../dock/viewswitcherdockwidget.h"
 
83
#include "../utils/autoclosemessagebox.h"
 
84
#include "../utils/fileprogressdialog.h"
 
85
#include "../utils/clickablelabel.h"
 
86
#include "../items/resizableboard.h"
 
87
#include "../items/resistor.h"
 
88
#include "../utils/zoomslider.h"
 
89
#include "../partseditor/pemainwindow.h"
 
90
 
 
91
 
 
92
///////////////////////////////////////////////
 
93
 
 
94
#define ZIP_PART QString("part.")
 
95
#define ZIP_SVG  QString("svg.")
 
96
 
 
97
///////////////////////////////////////////////
 
98
 
 
99
// SwapTimer explained: http://code.google.com/p/fritzing/issues/detail?id=1431
 
100
 
 
101
SwapTimer::SwapTimer() : QTimer() 
 
102
{
 
103
}
 
104
 
 
105
void SwapTimer::setAll(const QString & family, const QString & prop, QMap<QString, QString> & propsMap, ItemBase * itemBase)
 
106
{
 
107
        m_family = family;
 
108
        m_prop = prop;
 
109
        m_propsMap = propsMap;
 
110
        m_itemBase = itemBase;
 
111
}
 
112
 
 
113
const QString & SwapTimer::family()
 
114
{
 
115
        return  m_family;
 
116
}
 
117
 
 
118
const QString & SwapTimer::prop()
 
119
{
 
120
        return m_prop;
 
121
}
 
122
 
 
123
QMap<QString, QString> SwapTimer::propsMap()
 
124
{
 
125
        return m_propsMap;
 
126
}
 
127
 
 
128
ItemBase * SwapTimer::itemBase()
 
129
{
 
130
        return m_itemBase;
 
131
}
 
132
 
 
133
///////////////////////////////////////////////
 
134
 
 
135
const QString MainWindow::UntitledSketchName = "Untitled Sketch";
 
136
int MainWindow::UntitledSketchIndex = 1;
 
137
int MainWindow::CascadeFactorX = 21;
 
138
int MainWindow::CascadeFactorY = 19;
 
139
 
 
140
static const int MainWindowDefaultWidth = 840;
 
141
static const int MainWindowDefaultHeight = 600;
 
142
 
 
143
int MainWindow::AutosaveTimeoutMinutes = 10;   // in minutes
 
144
bool MainWindow::AutosaveEnabled = true;
 
145
QString MainWindow::BackupFolder;
 
146
 
 
147
/////////////////////////////////////////////
 
148
 
 
149
MainWindow::MainWindow(ReferenceModel *referenceModel, QWidget * parent) :
 
150
    FritzingWindow(untitledFileName(), untitledFileCount(), fileExtension(), parent)
 
151
{
 
152
        setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
 
153
        setDockOptions(QMainWindow::AnimatedDocks);
 
154
        m_sizeGrip = new FSizeGrip(this);
 
155
 
 
156
        m_topDock = NULL;
 
157
        m_bottomDock = NULL;
 
158
        m_dontKeepMargins = true;
 
159
 
 
160
    m_settingsPrefix = "main/";
 
161
    m_raiseWindowAct = m_showPartsBinIconViewAct = m_showAllLayersAct = m_hideAllLayersAct = m_showInViewHelpAct = m_rotate90cwAct = m_showBreadboardAct = m_showSchematicAct = m_showPCBAct = NULL;
 
162
    m_partMenu = m_windowMenu = m_pcbTraceMenu = m_schematicTraceMenu = m_breadboardTraceMenu = m_viewMenu = NULL;
 
163
    m_miniViewContainerBreadboard = NULL;
 
164
    m_infoView = NULL;
 
165
    m_addedToTemp = false;
 
166
    setAcceptDrops(true);
 
167
        m_activeWire = NULL;
 
168
        m_activeConnectorItem = NULL;
 
169
        m_swapTimer.setInterval(30);
 
170
        m_swapTimer.setParent(this);
 
171
        m_swapTimer.setSingleShot(true);
 
172
        connect(&m_swapTimer, SIGNAL(timeout()), this, SLOT(swapSelectedTimeout()));
 
173
 
 
174
        m_closeSilently = false;
 
175
        m_orderFabAct = NULL;
 
176
        m_activeLayerButtonWidget = NULL;
 
177
        m_programWindow = NULL;
 
178
        m_windowMenuSeparator = NULL;
 
179
        m_wireColorMenu = NULL;
 
180
        m_viewSwitcherDock = NULL;
 
181
        m_checkForUpdatesAct = NULL;
 
182
        m_fileProgressDialog = NULL;
 
183
        m_currentGraphicsView = NULL;
 
184
        m_comboboxChanged = false;
 
185
        m_helper = NULL;
 
186
 
 
187
    // Add a timer for autosaving
 
188
        m_backingUp = m_autosaveNeeded = false;
 
189
    connect(&m_autosaveTimer, SIGNAL(timeout()), this, SLOT(backupSketch()));
 
190
    m_autosaveTimer.start(AutosaveTimeoutMinutes * 60 * 1000);
 
191
 
 
192
        resize(MainWindowDefaultWidth, MainWindowDefaultHeight);
 
193
 
 
194
        m_backupFileNameAndPath = MainWindow::BackupFolder + "/" + FolderUtils::getRandText() + FritzingSketchExtension;
 
195
    // Connect the undoStack to our autosave stuff
 
196
    connect(m_undoStack, SIGNAL(indexChanged(int)), this, SLOT(autosaveNeeded(int)));
 
197
    connect(m_undoStack, SIGNAL(cleanChanged(bool)), this, SLOT(undoStackCleanChanged(bool)));
 
198
 
 
199
        // Create dot icons
 
200
        m_dotIcon = QIcon(":/resources/images/dot.png");
 
201
        m_emptyIcon = QIcon();
 
202
 
 
203
        m_currentWidget = NULL;
 
204
        m_firstOpen = true;
 
205
 
 
206
        m_statusBar = new QStatusBar(this);
 
207
        setStatusBar(m_statusBar);
 
208
        m_statusBar->setSizeGripEnabled(false);
 
209
 
 
210
        QSettings settings;
 
211
        m_locationLabelUnits = settings.value("LocationInches", "in").toString();
 
212
 
 
213
        // leave the m_orderFabEnabled check in case we turn off the fab button in the future
 
214
        m_orderFabEnabled = true; // settings.value(ORDERFABENABLED, QVariant(false)).toBool();
 
215
 
 
216
        m_locationLabel = new ClickableLabel("", this);
 
217
        m_locationLabel->setObjectName("LocationLabel");
 
218
        connect(m_locationLabel, SIGNAL(clicked()), this, SLOT(locationLabelClicked()));
 
219
        m_statusBar->addPermanentWidget(m_locationLabel);
 
220
 
 
221
        m_zoomSlider = new ZoomSlider(m_statusBar);
 
222
        connect(m_zoomSlider, SIGNAL(zoomChanged(double)), this, SLOT(updateViewZoom(double)));
 
223
        m_statusBar->addPermanentWidget(m_zoomSlider);
 
224
 
 
225
 
 
226
        setAttribute(Qt::WA_DeleteOnClose, true);
 
227
 
 
228
#ifdef Q_WS_MAC
 
229
        //setAttribute(Qt::WA_QuitOnClose, false);                                      // restoring this temporarily (2008.12.19)
 
230
#endif
 
231
    m_dontClose = m_closing = false;
 
232
 
 
233
        m_referenceModel = referenceModel;
 
234
        m_sketchModel = new SketchModel(true);
 
235
 
 
236
 
 
237
        QShortcut * shortcut = new QShortcut(QKeySequence(tr("Ctrl+R", "Rotate Clockwise")), this);
 
238
        connect(shortcut, SIGNAL(activated()), this, SLOT(rotateIncCW()));
 
239
        shortcut = new QShortcut(QKeySequence(tr("Alt+Ctrl+R", "Rotate Clockwise")), this);
 
240
        connect(shortcut, SIGNAL(activated()), this, SLOT(rotateIncCWRubberBand()));
 
241
        shortcut = new QShortcut(QKeySequence(tr("Meta+Ctrl+R", "Rotate Clockwise")), this);
 
242
        connect(shortcut, SIGNAL(activated()), this, SLOT(rotateIncCWRubberBand()));
 
243
 
 
244
        shortcut = new QShortcut(QKeySequence(tr("Shift+Ctrl+R", "Rotate Counterclockwise")), this);
 
245
        connect(shortcut, SIGNAL(activated()), this, SLOT(rotateIncCCW()));
 
246
        shortcut = new QShortcut(QKeySequence(tr("Alt+Shift+Ctrl+R", "Rotate Counterclockwise")), this);
 
247
        connect(shortcut, SIGNAL(activated()), this, SLOT(rotateIncCCWRubberBand()));
 
248
        shortcut = new QShortcut(QKeySequence(tr("Meta+Shift+Ctrl+R", "Rotate Counterclockwise")), this);
 
249
        connect(shortcut, SIGNAL(activated()), this, SLOT(rotateIncCCWRubberBand()));
 
250
 
 
251
        shortcut = new QShortcut(QKeySequence(tr("Shift+Ctrl+Tab", "Toggle Active Layer")), this);
 
252
        connect(shortcut, SIGNAL(activated()), this, SLOT(toggleActiveLayer()));
 
253
 
 
254
 
 
255
        connect(this, SIGNAL(changeActivationSignal(bool, QWidget *)), qApp, SLOT(changeActivation(bool, QWidget *)), Qt::DirectConnection);
 
256
        connect(this, SIGNAL(destroyed(QObject *)), qApp, SLOT(topLevelWidgetDestroyed(QObject *)));
 
257
        connect(this, SIGNAL(externalProcessSignal(QString &, QString &, QStringList &)),
 
258
                        qApp, SLOT(externalProcessSlot(QString &, QString &, QStringList &)), 
 
259
                        Qt::DirectConnection);
 
260
}
 
261
 
 
262
QWidget * MainWindow::createTabWidget() {
 
263
        return new QStackedWidget(this);
 
264
}
 
265
 
 
266
void MainWindow::addTab(QWidget * widget, const QString & label) {
 
267
        Q_UNUSED(label);
 
268
        qobject_cast<QStackedWidget *>(m_tabWidget)->addWidget(widget);
 
269
}
 
270
 
 
271
int MainWindow::currentTabIndex() {
 
272
        return qobject_cast<QStackedWidget *>(m_tabWidget)->currentIndex();
 
273
}
 
274
 
 
275
void MainWindow::setCurrentTabIndex(int index) {
 
276
        qobject_cast<QStackedWidget *>(m_tabWidget)->setCurrentIndex(index);
 
277
}
 
278
 
 
279
QWidget * MainWindow::currentTabWidget() {
 
280
        return qobject_cast<QStackedWidget *>(m_tabWidget)->currentWidget();
 
281
}
 
282
 
 
283
void MainWindow::init(ReferenceModel *referenceModel, bool lockFiles) {
 
284
 
 
285
        m_tabWidget = createTabWidget(); //   FTabWidget(this);
 
286
        m_tabWidget->setObjectName("sketch_tabs");
 
287
        setCentralWidget(m_tabWidget);
 
288
 
 
289
    m_referenceModel = referenceModel;
 
290
    m_restarting = false;
 
291
 
 
292
        if (m_fileProgressDialog) {
 
293
                m_fileProgressDialog->setValue(2);
 
294
        }
 
295
 
 
296
    initLockedFiles(lockFiles);
 
297
 
 
298
    initSketchWidgets();
 
299
 
 
300
    m_undoView = new QUndoView();
 
301
    m_undoGroup = new QUndoGroup(this);
 
302
    m_undoView->setGroup(m_undoGroup);
 
303
    m_undoGroup->setActiveStack(m_undoStack);
 
304
 
 
305
    initDock();
 
306
    initMenus();
 
307
    moreInitDock();
 
308
 
 
309
        createZoomOptions(m_breadboardWidget);
 
310
        createZoomOptions(m_schematicWidget);
 
311
        createZoomOptions(m_pcbWidget);
 
312
 
 
313
    m_breadboardWidget->setToolbarWidgets(getButtonsForView(ViewLayer::BreadboardView));
 
314
    m_schematicWidget->setToolbarWidgets(getButtonsForView(ViewLayer::SchematicView));
 
315
        m_pcbWidget->setToolbarWidgets(getButtonsForView(ViewLayer::PCBView));
 
316
 
 
317
    initStyleSheet();
 
318
 
 
319
    m_breadboardGraphicsView->setItemMenu(breadboardItemMenu());
 
320
    m_breadboardGraphicsView->setWireMenu(breadboardWireMenu());
 
321
 
 
322
    m_pcbGraphicsView->setWireMenu(pcbWireMenu());
 
323
    m_pcbGraphicsView->setItemMenu(pcbItemMenu());
 
324
 
 
325
    m_schematicGraphicsView->setItemMenu(schematicItemMenu());
 
326
    m_schematicGraphicsView->setWireMenu(schematicWireMenu());
 
327
 
 
328
    if (m_infoView) {
 
329
        m_breadboardGraphicsView->setInfoView(m_infoView);
 
330
        m_pcbGraphicsView->setInfoView(m_infoView);
 
331
        m_schematicGraphicsView->setInfoView(m_infoView);
 
332
    }
 
333
 
 
334
        // make sure to set the connections after the views have been created
 
335
        connect(m_tabWidget, SIGNAL(currentChanged ( int )), this, SLOT(tabWidget_currentChanged( int )));
 
336
 
 
337
        connectPairs();
 
338
 
 
339
        initHelper();
 
340
 
 
341
        // do this the first time, since the current_changed signal wasn't sent
 
342
        int tab = 0;
 
343
    if (m_navigators.count() > 0) {
 
344
            currentNavigatorChanged(m_navigators[tab]);
 
345
    }
 
346
        tabWidget_currentChanged(tab+1);
 
347
        tabWidget_currentChanged(tab);
 
348
 
 
349
        this->installEventFilter(this);
 
350
 
 
351
        if (m_fileProgressDialog) {
 
352
                m_fileProgressDialog->setValue(95);
 
353
        }
 
354
 
 
355
        QSettings settings;
 
356
    if (m_viewSwitcherDock) {
 
357
        m_viewSwitcherDock->prestorePreference();
 
358
    }
 
359
        if(!settings.value(m_settingsPrefix + "state").isNull()) {
 
360
                restoreState(settings.value(m_settingsPrefix + "state").toByteArray());
 
361
                restoreGeometry(settings.value(m_settingsPrefix + "geometry").toByteArray());
 
362
        }
 
363
    if (m_viewSwitcherDock) {
 
364
        m_viewSwitcherDock->restorePreference();
 
365
        m_viewSwitcherDock->setViewSwitcher(m_viewSwitcher);
 
366
    }
 
367
 
 
368
        setMinimumSize(0,0);
 
369
        m_tabWidget->setMinimumWidth(500);
 
370
        m_tabWidget->setMinimumWidth(0);
 
371
 
 
372
    if (m_miniViewContainerBreadboard) {
 
373
            m_miniViewContainerBreadboard->setView(m_breadboardGraphicsView);
 
374
            m_miniViewContainerSchematic->setView(m_schematicGraphicsView);
 
375
            m_miniViewContainerPCB->setView(m_pcbGraphicsView);
 
376
    }
 
377
 
 
378
        connect(this, SIGNAL(readOnlyChanged(bool)), this, SLOT(applyReadOnlyChange(bool)));
 
379
 
 
380
        m_setUpDockManagerTimer.setSingleShot(true);
 
381
        connect(&m_setUpDockManagerTimer, SIGNAL(timeout()), this, SLOT(keepMargins()));
 
382
    m_setUpDockManagerTimer.start(1000);
 
383
 
 
384
        if (m_fileProgressDialog) {
 
385
                m_fileProgressDialog->setValue(98);
 
386
        }
 
387
 
 
388
}
 
389
 
 
390
MainWindow::~MainWindow()
 
391
{
 
392
    // Delete backup of this sketch if one exists.
 
393
    QFile::remove(m_backupFileNameAndPath);     
 
394
        
 
395
        delete m_sketchModel;
 
396
 
 
397
        dontKeepMargins();
 
398
        m_setUpDockManagerTimer.stop();
 
399
 
 
400
        foreach (LinkedFile * linkedFile, m_linkedProgramFiles) {
 
401
                delete linkedFile;
 
402
        }
 
403
        m_linkedProgramFiles.clear();
 
404
 
 
405
        if (!m_fzzFolder.isEmpty()) {
 
406
                LockManager::releaseLockedFiles(m_fzzFolder, m_fzzFiles);
 
407
                FolderUtils::rmdir(m_fzzFolder);
 
408
        }
 
409
}       
 
410
 
 
411
void MainWindow::initHelper() {
 
412
    m_helper = new Helper(this, true);
 
413
}
 
414
 
 
415
void MainWindow::initLockedFiles(bool lockFiles) {
 
416
        LockManager::initLockedFiles("fzz", m_fzzFolder, m_fzzFiles, lockFiles ? LockManager::SlowTime : 0);
 
417
        if (lockFiles) {
 
418
                QFileInfoList backupList;
 
419
                LockManager::checkLockedFiles("fzz", backupList, m_fzzFiles, true, LockManager::SlowTime);
 
420
        }
 
421
}
 
422
 
 
423
void MainWindow::initSketchWidgets() {
 
424
        //DebugDialog::debug("init sketch widgets");
 
425
 
 
426
        // all this belongs in viewLayer.xml
 
427
        m_breadboardGraphicsView = new BreadboardSketchWidget(ViewLayer::BreadboardView, this);
 
428
        initSketchWidget(m_breadboardGraphicsView);
 
429
        m_breadboardWidget = new SketchAreaWidget(m_breadboardGraphicsView,this);
 
430
        addTab(m_breadboardWidget, tr("Breadboard"));
 
431
 
 
432
        if (m_fileProgressDialog) {
 
433
                m_fileProgressDialog->setValue(11);
 
434
        }
 
435
 
 
436
        m_schematicGraphicsView = new SchematicSketchWidget(ViewLayer::SchematicView, this);
 
437
        initSketchWidget(m_schematicGraphicsView);
 
438
        m_schematicWidget = new SketchAreaWidget(m_schematicGraphicsView, this);
 
439
        addTab(m_schematicWidget, tr("Schematic"));
 
440
 
 
441
        if (m_fileProgressDialog) {
 
442
                m_fileProgressDialog->setValue(20);
 
443
        }
 
444
 
 
445
        m_pcbGraphicsView = new PCBSketchWidget(ViewLayer::PCBView, this);
 
446
        initSketchWidget(m_pcbGraphicsView);
 
447
        m_pcbWidget = new SketchAreaWidget(m_pcbGraphicsView, this);
 
448
        addTab(m_pcbWidget, tr("PCB"));
 
449
 
 
450
        if (m_fileProgressDialog) {
 
451
                m_fileProgressDialog->setValue(29);
 
452
        }
 
453
}
 
454
 
 
455
void MainWindow::initMenus() {
 
456
        // This is the magic translation that changes all the shortcut text on the menu items
 
457
        // to the native language instead of "Ctrl", so the German menu items will now read "Strg"
 
458
        // You don't actually have to translate every menu item in the .ts file, you can just leave it as "Ctrl".
 
459
        QShortcut::tr("Ctrl", "for naming shortcut keys on menu items");
 
460
        QShortcut::tr("Alt", "for naming shortcut keys on menu items");
 
461
        QShortcut::tr("Shift", "for naming shortcut keys on menu items");
 
462
        QShortcut::tr("Meta", "for naming shortcut keys on menu items");
 
463
 
 
464
        //DebugDialog::debug("create menus");
 
465
 
 
466
    createActions();
 
467
    createMenus();
 
468
 
 
469
        //DebugDialog::debug("create toolbars");
 
470
 
 
471
    createStatusBar();
 
472
 
 
473
        //DebugDialog::debug("after creating status bar");
 
474
 
 
475
        if (m_fileProgressDialog) {
 
476
                m_fileProgressDialog->setValue(91);
 
477
        }
 
478
}
 
479
 
 
480
 
 
481
                                   
 
482
 
 
483
void MainWindow::showNavigator() {
 
484
        m_navigatorDock->setFloating(false);
 
485
}
 
486
 
 
487
void MainWindow::initSketchWidget(SketchWidget * sketchWidget) {
 
488
        sketchWidget->setSketchModel(m_sketchModel);
 
489
        sketchWidget->setReferenceModel(m_referenceModel);
 
490
        sketchWidget->setUndoStack(m_undoStack);
 
491
        sketchWidget->setChainDrag(true);                       // enable bend points
 
492
        sketchWidget->initGrid();
 
493
        sketchWidget->addViewLayers();
 
494
}
 
495
 
 
496
void MainWindow::connectPairs() {
 
497
        connectPair(m_breadboardGraphicsView, m_schematicGraphicsView);
 
498
        connectPair(m_breadboardGraphicsView, m_pcbGraphicsView);
 
499
        connectPair(m_schematicGraphicsView, m_breadboardGraphicsView);
 
500
        connectPair(m_schematicGraphicsView, m_pcbGraphicsView);
 
501
        connectPair(m_pcbGraphicsView, m_breadboardGraphicsView);
 
502
        connectPair(m_pcbGraphicsView, m_schematicGraphicsView);
 
503
 
 
504
        connect(m_pcbGraphicsView, SIGNAL(groundFillSignal()), this, SLOT(groundFill()));
 
505
        connect(m_pcbGraphicsView, SIGNAL(copperFillSignal()), this, SLOT(copperFill()));
 
506
 
 
507
    connect(m_pcbGraphicsView, SIGNAL(swapBoardImageSignal(SketchWidget *, ItemBase *, const QString &, const QString &, bool)),
 
508
                this, SLOT(swapBoardImageSlot(SketchWidget *, ItemBase *, const QString &, const QString &, bool)));
 
509
 
 
510
 
 
511
        connect(m_breadboardGraphicsView, SIGNAL(setActiveWireSignal(Wire *)), this, SLOT(setActiveWire(Wire *)));
 
512
        connect(m_schematicGraphicsView, SIGNAL(setActiveWireSignal(Wire *)), this, SLOT(setActiveWire(Wire *)));
 
513
        connect(m_pcbGraphicsView, SIGNAL(setActiveWireSignal(Wire *)), this, SLOT(setActiveWire(Wire *)));
 
514
 
 
515
        connect(m_breadboardGraphicsView, SIGNAL(setActiveConnectorItemSignal(ConnectorItem *)), this, SLOT(setActiveConnectorItem(ConnectorItem *)));
 
516
        connect(m_schematicGraphicsView, SIGNAL(setActiveConnectorItemSignal(ConnectorItem *)), this, SLOT(setActiveConnectorItem(ConnectorItem *)));
 
517
        connect(m_pcbGraphicsView, SIGNAL(setActiveConnectorItemSignal(ConnectorItem *)), this, SLOT(setActiveConnectorItem(ConnectorItem *)));
 
518
 
 
519
        bool succeeded = connect(m_pcbGraphicsView, SIGNAL(routingStatusSignal(SketchWidget *, const RoutingStatus &)),
 
520
                                                this, SLOT(routingStatusSlot(SketchWidget *, const RoutingStatus &)));
 
521
        succeeded =  succeeded && connect(m_schematicGraphicsView, SIGNAL(routingStatusSignal(SketchWidget *, const RoutingStatus &)),
 
522
                                                this, SLOT(routingStatusSlot(SketchWidget *, const RoutingStatus &)));
 
523
        succeeded =  succeeded && connect(m_breadboardGraphicsView, SIGNAL(routingStatusSignal(SketchWidget *, const RoutingStatus &)),
 
524
                                                this, SLOT(routingStatusSlot(SketchWidget *, const RoutingStatus &)));
 
525
 
 
526
        succeeded =  succeeded && connect(m_breadboardGraphicsView, SIGNAL(swapSignal(const QString &, const QString &, QMap<QString, QString> &, ItemBase *)), 
 
527
                                                this, SLOT(swapSelectedDelay(const QString &, const QString &, QMap<QString, QString> &, ItemBase *)));
 
528
        succeeded =  succeeded && connect(m_schematicGraphicsView, SIGNAL(swapSignal(const QString &, const QString &, QMap<QString, QString> &, ItemBase *)), 
 
529
                                                this, SLOT(swapSelectedDelay(const QString &, const QString &, QMap<QString, QString> &, ItemBase *)));
 
530
        succeeded =  succeeded && connect(m_pcbGraphicsView, SIGNAL(swapSignal(const QString &, const QString &, QMap<QString, QString> &, ItemBase *)), 
 
531
                                                this, SLOT(swapSelectedDelay(const QString &, const QString &, QMap<QString, QString> &, ItemBase *)));
 
532
 
 
533
        succeeded =  succeeded && connect(m_breadboardGraphicsView, SIGNAL(dropPasteSignal(SketchWidget *)), 
 
534
                                                this, SLOT(dropPaste(SketchWidget *)));
 
535
        succeeded =  succeeded && connect(m_schematicGraphicsView, SIGNAL(dropPasteSignal(SketchWidget *)), 
 
536
                                                this, SLOT(dropPaste(SketchWidget *)));
 
537
        succeeded =  succeeded && connect(m_pcbGraphicsView, SIGNAL(dropPasteSignal(SketchWidget *)), 
 
538
                                                this, SLOT(dropPaste(SketchWidget *)));
 
539
        
 
540
        succeeded =  succeeded && connect(m_pcbGraphicsView, SIGNAL(subSwapSignal(SketchWidget *, ItemBase *, const QString &, ViewLayer::ViewLayerSpec, long &, QUndoCommand *)),
 
541
                                                this, SLOT(subSwapSlot(SketchWidget *, ItemBase *, const QString &, ViewLayer::ViewLayerSpec, long &, QUndoCommand *)),
 
542
                                                Qt::DirectConnection);
 
543
 
 
544
        succeeded =  succeeded && connect(m_pcbGraphicsView, SIGNAL(firstTimeHelpHidden()), this, SLOT(firstTimeHelpHidden()));
 
545
        succeeded =  succeeded && connect(m_schematicGraphicsView, SIGNAL(firstTimeHelpHidden()), this, SLOT(firstTimeHelpHidden()));
 
546
        succeeded =  succeeded && connect(m_breadboardGraphicsView, SIGNAL(firstTimeHelpHidden()), this, SLOT(firstTimeHelpHidden()));
 
547
 
 
548
        succeeded =  succeeded && connect(m_pcbGraphicsView, SIGNAL(updateLayerMenuSignal()), this, SLOT(updateLayerMenuSlot()));
 
549
        succeeded =  succeeded && connect(m_pcbGraphicsView, SIGNAL(changeBoardLayersSignal(int, bool )), this, SLOT(changeBoardLayers(int, bool )));
 
550
 
 
551
        succeeded =  succeeded && connect(m_pcbGraphicsView, SIGNAL(boardDeletedSignal()), this, SLOT(boardDeletedSlot()));
 
552
 
 
553
        succeeded =  succeeded && connect(qApp, SIGNAL(spaceBarIsPressedSignal(bool)), m_breadboardGraphicsView, SLOT(spaceBarIsPressedSlot(bool)));
 
554
        succeeded =  succeeded && connect(qApp, SIGNAL(spaceBarIsPressedSignal(bool)), m_schematicGraphicsView, SLOT(spaceBarIsPressedSlot(bool)));
 
555
        succeeded =  succeeded && connect(qApp, SIGNAL(spaceBarIsPressedSignal(bool)), m_pcbGraphicsView, SLOT(spaceBarIsPressedSlot(bool)));
 
556
 
 
557
        succeeded =  succeeded && connect(m_pcbGraphicsView, SIGNAL(cursorLocationSignal(double, double)), this, SLOT(cursorLocationSlot(double, double)));
 
558
        succeeded =  succeeded && connect(m_breadboardGraphicsView, SIGNAL(cursorLocationSignal(double, double)), this, SLOT(cursorLocationSlot(double, double)));
 
559
        succeeded =  succeeded && connect(m_schematicGraphicsView, SIGNAL(cursorLocationSignal(double, double)), this, SLOT(cursorLocationSlot(double, double)));
 
560
 
 
561
        succeeded =  succeeded && connect(m_breadboardGraphicsView, SIGNAL(filenameIfSignal(QString &)), this, SLOT(filenameIfSlot(QString &)), Qt::DirectConnection);
 
562
        succeeded =  succeeded && connect(m_pcbGraphicsView, SIGNAL(filenameIfSignal(QString &)), this, SLOT(filenameIfSlot(QString &)), Qt::DirectConnection);
 
563
        succeeded =  succeeded && connect(m_schematicGraphicsView, SIGNAL(filenameIfSignal(QString &)), this, SLOT(filenameIfSlot(QString &)), Qt::DirectConnection);
 
564
        
 
565
    if (!succeeded) {
 
566
                DebugDialog::debug("connectPair failed");
 
567
        }
 
568
}
 
569
 
 
570
void MainWindow::connectPair(SketchWidget * signaller, SketchWidget * slotter)
 
571
{
 
572
 
 
573
        bool succeeded = connect(signaller, SIGNAL(itemAddedSignal(ModelPart *, ViewLayer::ViewLayerSpec, const ViewGeometry &, long, SketchWidget *)),
 
574
                                                         slotter, SLOT(itemAddedSlot(ModelPart *, ViewLayer::ViewLayerSpec, const ViewGeometry &, long, SketchWidget *)));
 
575
 
 
576
        succeeded = succeeded && connect(signaller, SIGNAL(itemDeletedSignal(long)),
 
577
                                                                         slotter, SLOT(itemDeletedSlot(long)),
 
578
                                                                         Qt::DirectConnection);
 
579
 
 
580
        succeeded = succeeded && connect(signaller, SIGNAL(clearSelectionSignal()),
 
581
                                                                         slotter, SLOT(clearSelectionSlot()));
 
582
 
 
583
        succeeded = succeeded && connect(signaller, SIGNAL(itemSelectedSignal(long, bool)),
 
584
                                                                         slotter, SLOT(itemSelectedSlot(long, bool)));
 
585
        succeeded = succeeded && connect(signaller, SIGNAL(selectAllItemsSignal(bool, bool)),
 
586
                                                                         slotter, SLOT(selectAllItems(bool, bool)));
 
587
        succeeded = succeeded && connect(signaller, SIGNAL(wireDisconnectedSignal(long, QString)),
 
588
                                                                         slotter, SLOT(wireDisconnectedSlot(long,  QString)));
 
589
        succeeded = succeeded && connect(signaller, SIGNAL(wireConnectedSignal(long,  QString, long,  QString)),
 
590
                                                                         slotter, SLOT(wireConnectedSlot(long, QString, long, QString)));
 
591
        succeeded = succeeded && connect(signaller, SIGNAL(changeConnectionSignal(long,  QString, long,  QString, ViewLayer::ViewLayerSpec, bool, bool)),
 
592
                                                                         slotter, SLOT(changeConnectionSlot(long, QString, long, QString, ViewLayer::ViewLayerSpec, bool, bool)));
 
593
        succeeded = succeeded && connect(signaller, SIGNAL(copyBoundingRectsSignal(QHash<QString, QRectF> &)),
 
594
                                                                                                           slotter, SLOT(copyBoundingRectsSlot(QHash<QString, QRectF> &)),
 
595
                                                                         Qt::DirectConnection);
 
596
 
 
597
        succeeded = succeeded && connect(signaller, SIGNAL(cleanUpWiresSignal(CleanUpWiresCommand *)),
 
598
                                                                         slotter, SLOT(cleanUpWiresSlot(CleanUpWiresCommand *)) );
 
599
 
 
600
        succeeded = succeeded && connect(signaller, SIGNAL(checkStickySignal(long, bool, bool, CheckStickyCommand *)),
 
601
                                                                         slotter, SLOT(checkSticky(long, bool, bool, CheckStickyCommand *)) );
 
602
 
 
603
        succeeded = succeeded && connect(signaller, SIGNAL(disconnectAllSignal(QList<ConnectorItem *>, QHash<ItemBase *, SketchWidget *> &, QUndoCommand *)),
 
604
                                                                         slotter, SLOT(disconnectAllSlot(QList<ConnectorItem *>, QHash<ItemBase *, SketchWidget *> &, QUndoCommand *)),
 
605
                                                                         Qt::DirectConnection);
 
606
        succeeded = succeeded && connect(signaller, SIGNAL(setResistanceSignal(long, QString, QString, bool)),
 
607
                                                                         slotter, SLOT(setResistance(long, QString, QString, bool)));
 
608
        succeeded = succeeded && connect(signaller, SIGNAL(makeDeleteItemCommandPrepSignal(ItemBase *, bool , QUndoCommand * )),
 
609
                                                                         slotter, SLOT(makeDeleteItemCommandPrepSlot(ItemBase * , bool , QUndoCommand * )));
 
610
        succeeded = succeeded && connect(signaller, SIGNAL(makeDeleteItemCommandFinalSignal(ItemBase *, bool , QUndoCommand * )),
 
611
                                                                         slotter, SLOT(makeDeleteItemCommandFinalSlot(ItemBase * , bool , QUndoCommand * )));
 
612
 
 
613
        succeeded = succeeded && connect(signaller, SIGNAL(setPropSignal(long,  const QString &,  const QString &, bool, bool)),
 
614
                                                                         slotter, SLOT(setProp(long,  const QString &,  const QString &, bool, bool)));
 
615
 
 
616
        succeeded = succeeded && connect(signaller, SIGNAL(setInstanceTitleSignal(long, const QString &, const QString &, bool, bool )),
 
617
                                                                         slotter, SLOT(setInstanceTitle(long, const QString &, const QString &, bool, bool )));
 
618
 
 
619
        succeeded = succeeded && connect(signaller, SIGNAL(setVoltageSignal(double, bool )),
 
620
                                                                         slotter, SLOT(setVoltage(double, bool )));
 
621
 
 
622
        succeeded = succeeded && connect(signaller, SIGNAL(showLabelFirstTimeSignal(long, bool, bool )),
 
623
                                                                         slotter, SLOT(showLabelFirstTime(long, bool, bool )));
 
624
 
 
625
        succeeded = succeeded && connect(signaller, SIGNAL(changeBoardLayersSignal(int, bool )),
 
626
                                                                         slotter, SLOT(changeBoardLayers(int, bool )));
 
627
 
 
628
        succeeded = succeeded && connect(signaller, SIGNAL(deleteTracesSignal(QSet<ItemBase *> &, QHash<ItemBase *, SketchWidget *> &, QList<long> &, bool, QUndoCommand *)),
 
629
                                                                         slotter, SLOT(deleteTracesSlot(QSet<ItemBase *> &, QHash<ItemBase *, SketchWidget *> &, QList<long> &, bool, QUndoCommand *)),
 
630
                                                                         Qt::DirectConnection);
 
631
 
 
632
        succeeded = succeeded && connect(signaller, SIGNAL(ratsnestConnectSignal(long, const QString &, bool, bool)),
 
633
                                                                         slotter, SLOT(ratsnestConnect(long, const QString &, bool, bool )),
 
634
                                                                         Qt::DirectConnection);
 
635
 
 
636
 
 
637
        succeeded = succeeded && connect(signaller, SIGNAL(updatePartLabelInstanceTitleSignal(long)),
 
638
                                                                         slotter, SLOT(updatePartLabelInstanceTitleSlot(long)));
 
639
 
 
640
        succeeded = succeeded && connect(signaller, SIGNAL(changePinLabelsSignal(ItemBase *, bool)),
 
641
                                                                         slotter, SLOT(changePinLabelsSlot(ItemBase *, bool)));
 
642
 
 
643
        succeeded = succeeded && connect(signaller, SIGNAL(collectRatsnestSignal(QList<SketchWidget *> &)),
 
644
                                                                         slotter, SLOT(collectRatsnestSlot(QList<SketchWidget *> &)),
 
645
                                                                         Qt::DirectConnection);
 
646
 
 
647
        succeeded = succeeded && connect(signaller, SIGNAL(removeRatsnestSignal(QList<struct ConnectorEdge *> &, QUndoCommand *)),
 
648
                                                                         slotter, SLOT(removeRatsnestSlot(QList<struct ConnectorEdge *> &, QUndoCommand *)),
 
649
                                                                         Qt::DirectConnection);
 
650
 
 
651
        succeeded = succeeded && connect(signaller, SIGNAL(canConnectSignal(Wire *, ItemBase *, bool &)),
 
652
                                                                         slotter, SLOT(canConnect(Wire *, ItemBase *, bool &)),
 
653
                                                                         Qt::DirectConnection);
 
654
 
 
655
        succeeded = succeeded && connect(signaller, SIGNAL(swapStartSignal(SwapThing &, bool)),
 
656
                                                                         slotter, SLOT(swapStart(SwapThing &, bool)),
 
657
                                                                         Qt::DirectConnection);
 
658
 
 
659
        if (!succeeded) {
 
660
                DebugDialog::debug("connectPair failed");
 
661
        }
 
662
 
 
663
}
 
664
 
 
665
void MainWindow::setCurrentFile(const QString &filename, bool addToRecent, bool setAsLastOpened) {
 
666
        setFileName(filename);
 
667
 
 
668
        if(setAsLastOpened) {
 
669
                QSettings settings;
 
670
                settings.setValue("lastOpenSketch",filename);
 
671
        }
 
672
 
 
673
        updateRaiseWindowAction();
 
674
        setTitle();
 
675
 
 
676
        if(addToRecent) {
 
677
                QSettings settings;
 
678
                QStringList files = settings.value("recentFileList").toStringList();
 
679
                files.removeAll(filename);
 
680
                files.prepend(filename);
 
681
                while (files.size() > MaxRecentFiles)
 
682
                        files.removeLast();
 
683
 
 
684
                settings.setValue("recentFileList", files);
 
685
        }
 
686
 
 
687
    foreach (QWidget *widget, QApplication::topLevelWidgets()) {
 
688
        MainWindow *mainWin = qobject_cast<MainWindow *>(widget);
 
689
        if (mainWin)
 
690
            mainWin->updateRecentFileActions();
 
691
    }
 
692
}
 
693
 
 
694
 
 
695
void MainWindow::createZoomOptions(SketchAreaWidget* parent) {
 
696
 
 
697
    connect(parent->contentView(), SIGNAL(zoomChanged(double)), this, SLOT(updateZoomSlider(double)));
 
698
    connect(parent->contentView(), SIGNAL(zoomOutOfRange(double)), this, SLOT(updateZoomOptionsNoMatterWhat(double)));
 
699
}
 
700
 
 
701
ExpandingLabel * MainWindow::createRoutingStatusLabel(SketchAreaWidget * parent) {
 
702
        ExpandingLabel * routingStatusLabel = new ExpandingLabel(m_pcbWidget);
 
703
 
 
704
        connect(routingStatusLabel, SIGNAL(mousePressSignal(QMouseEvent*)), this, SLOT(routingStatusLabelMousePress(QMouseEvent*)));
 
705
        connect(routingStatusLabel, SIGNAL(mouseReleaseSignal(QMouseEvent*)), this, SLOT(routingStatusLabelMouseRelease(QMouseEvent*)));
 
706
 
 
707
        routingStatusLabel->setTextInteractionFlags(Qt::NoTextInteraction);
 
708
        routingStatusLabel->setCursor(Qt::WhatsThisCursor);
 
709
        routingStatusLabel->viewport()->setCursor(Qt::WhatsThisCursor);
 
710
 
 
711
        routingStatusLabel->setObjectName(SketchAreaWidget::RoutingStateLabelName);
 
712
        parent->setRoutingStatusLabel(routingStatusLabel);
 
713
        RoutingStatus routingStatus;
 
714
        routingStatus.zero();
 
715
        routingStatusSlot(qobject_cast<SketchWidget *>(parent->contentView()), routingStatus);
 
716
        return routingStatusLabel;
 
717
}
 
718
 
 
719
SketchToolButton *MainWindow::createRotateButton(SketchAreaWidget *parent) {
 
720
        QList<QAction*> rotateMenuActions;
 
721
        rotateMenuActions << m_rotate45ccwAct << m_rotate90ccwAct << m_rotate180Act << m_rotate90cwAct << m_rotate45cwAct;
 
722
        SketchToolButton * rotateButton = new SketchToolButton("Rotate",parent, rotateMenuActions);
 
723
        rotateButton->setDefaultAction(m_rotate90ccwAct);
 
724
        rotateButton->setText(tr("Rotate"));
 
725
 
 
726
        m_rotateButtons << rotateButton;
 
727
        return rotateButton;
 
728
}
 
729
 
 
730
SketchToolButton *MainWindow::createShareButton(SketchAreaWidget *parent) {
 
731
        SketchToolButton *shareButton = new SketchToolButton("Share",parent, m_shareOnlineAct);
 
732
        shareButton->setText(tr("Share"));
 
733
        shareButton->setEnabledIcon();                                  // seems to need this to display button icon first time
 
734
        return shareButton;
 
735
}
 
736
 
 
737
SketchToolButton *MainWindow::createFlipButton(SketchAreaWidget *parent) {
 
738
        QList<QAction*> flipMenuActions;
 
739
        flipMenuActions << m_flipHorizontalAct << m_flipVerticalAct;
 
740
        SketchToolButton *flipButton = new SketchToolButton("Flip",parent, flipMenuActions);
 
741
        flipButton->setText(tr("Flip"));
 
742
 
 
743
        m_flipButtons << flipButton;
 
744
        return flipButton;
 
745
}
 
746
 
 
747
SketchToolButton *MainWindow::createAutorouteButton(SketchAreaWidget *parent) {
 
748
        SketchToolButton *autorouteButton = new SketchToolButton("Autoroute",parent, m_autorouteAct);
 
749
        autorouteButton->setText(tr("Autoroute"));
 
750
 
 
751
        return autorouteButton;
 
752
}
 
753
 
 
754
SketchToolButton *MainWindow::createOrderFabButton(SketchAreaWidget *parent) {
 
755
        SketchToolButton *orderFabButton = new SketchToolButton("Order",parent, m_orderFabAct);
 
756
        orderFabButton->setText(tr("Order PCB"));
 
757
        orderFabButton->setEnabledIcon();                                       // seems to need this to display button icon first time
 
758
 
 
759
        return orderFabButton;
 
760
}
 
761
 
 
762
QWidget *MainWindow::createActiveLayerButton(SketchAreaWidget *parent) 
 
763
{
 
764
        QList<QAction *> actions;
 
765
        actions << m_activeLayerBothAct << m_activeLayerBottomAct << m_activeLayerTopAct;
 
766
 
 
767
        m_activeLayerButtonWidget = new QStackedWidget;
 
768
        m_activeLayerButtonWidget->setMaximumWidth(90);
 
769
 
 
770
        SketchToolButton * button = new SketchToolButton("ActiveLayer", parent, actions);
 
771
        button->setDefaultAction(m_activeLayerBottomAct);
 
772
        button->setText(tr("Both Layers"));
 
773
        m_activeLayerButtonWidget->addWidget(button);
 
774
 
 
775
        button = new SketchToolButton("ActiveLayerB", parent, actions);
 
776
        button->setDefaultAction(m_activeLayerTopAct);
 
777
        button->setText(tr("Bottom Layer"));
 
778
        m_activeLayerButtonWidget->addWidget(button);
 
779
 
 
780
        button = new SketchToolButton("ActiveLayerT", parent, actions);
 
781
        button->setDefaultAction(m_activeLayerBothAct);
 
782
        button->setText(tr("Top Layer"));
 
783
        m_activeLayerButtonWidget->addWidget(button);
 
784
 
 
785
        return m_activeLayerButtonWidget;
 
786
}
 
787
 
 
788
SketchToolButton *MainWindow::createNoteButton(SketchAreaWidget *parent) {
 
789
        SketchToolButton *noteButton = new SketchToolButton("Notes",parent, m_addNoteAct);
 
790
        noteButton->setText(tr("Add a note"));
 
791
        noteButton->setEnabledIcon();                                   // seems to need this to display button icon first time
 
792
        return noteButton;
 
793
}
 
794
 
 
795
SketchToolButton *MainWindow::createExportEtchableButton(SketchAreaWidget *parent) {
 
796
        QList<QAction*> actions;
 
797
        actions << m_exportEtchablePdfAct << m_exportEtchableSvgAct << m_exportGerberAct;
 
798
        SketchToolButton *exportEtchableButton = new SketchToolButton("Diy",parent, actions);
 
799
        exportEtchableButton->setDefaultAction(m_exportEtchablePdfAct);
 
800
        exportEtchableButton->setText(tr("Export for PCB"));
 
801
        exportEtchableButton->setEnabledIcon();                         // seems to need this to display button icon first time
 
802
        return exportEtchableButton;
 
803
}
 
804
 
 
805
QWidget *MainWindow::createToolbarSpacer(SketchAreaWidget *parent) {
 
806
        QFrame *toolbarSpacer = new QFrame(parent);
 
807
        QHBoxLayout *spacerLayout = new QHBoxLayout(toolbarSpacer);
 
808
        spacerLayout->addSpacerItem(new QSpacerItem(0,0,QSizePolicy::Expanding));
 
809
 
 
810
        return toolbarSpacer;
 
811
}
 
812
 
 
813
QList<QWidget*> MainWindow::getButtonsForView(ViewLayer::ViewIdentifier viewId) {
 
814
        QList<QWidget*> retval;
 
815
        SketchAreaWidget *parent;
 
816
        switch(viewId) {
 
817
                case ViewLayer::BreadboardView: parent = m_breadboardWidget; break;
 
818
                case ViewLayer::SchematicView: parent = m_schematicWidget; break;
 
819
                case ViewLayer::PCBView: parent = m_pcbWidget; break;
 
820
                default: return retval;
 
821
        }
 
822
        retval << createShareButton(parent);
 
823
 
 
824
        switch(viewId) {
 
825
                case ViewLayer::BreadboardView:
 
826
                case ViewLayer::SchematicView:
 
827
                        retval << createNoteButton(parent);
 
828
                default: 
 
829
                        break;
 
830
        }
 
831
        
 
832
        retval << createRotateButton(parent);
 
833
        switch (viewId) {
 
834
                case ViewLayer::BreadboardView:
 
835
                        retval << createFlipButton(parent); 
 
836
                        break;
 
837
                case ViewLayer::SchematicView:
 
838
                        retval << createFlipButton(parent) << createToolbarSpacer(parent) << createAutorouteButton(parent);
 
839
                        break;
 
840
                case ViewLayer::PCBView:
 
841
                        retval << SketchAreaWidget::separator(parent) 
 
842
                                << createActiveLayerButton(parent) 
 
843
                                << createAutorouteButton(parent) 
 
844
                                << createExportEtchableButton(parent);
 
845
                        if (m_orderFabEnabled) {
 
846
                                retval << createOrderFabButton(parent);
 
847
                        }
 
848
                        break;
 
849
                default:
 
850
                        break;
 
851
        }
 
852
 
 
853
        retval << createRoutingStatusLabel(parent);
 
854
        return retval;
 
855
}
 
856
 
 
857
void MainWindow::updateZoomSlider(double zoom) {
 
858
        m_zoomSlider->setValue(zoom);
 
859
}
 
860
 
 
861
SketchAreaWidget *MainWindow::currentSketchArea() {
 
862
        return dynamic_cast<SketchAreaWidget*>(m_currentGraphicsView->parent());
 
863
}
 
864
 
 
865
void MainWindow::updateZoomOptionsNoMatterWhat(double zoom) {
 
866
        m_zoomSlider->setValue(zoom);
 
867
}
 
868
 
 
869
void MainWindow::updateViewZoom(double newZoom) {
 
870
        m_comboboxChanged = true;
 
871
        if(m_currentGraphicsView) m_currentGraphicsView->absoluteZoom(newZoom);
 
872
}
 
873
 
 
874
 
 
875
void MainWindow::createStatusBar()
 
876
{
 
877
    m_statusBar->showMessage(tr("Ready"));
 
878
}
 
879
 
 
880
void MainWindow::tabWidget_currentChanged(int index) {
 
881
        SketchAreaWidget * widgetParent = dynamic_cast<SketchAreaWidget *>(currentTabWidget());
 
882
        if (widgetParent == NULL) return;
 
883
 
 
884
        m_currentWidget = widgetParent;
 
885
 
 
886
        if (m_locationLabel) {
 
887
                m_locationLabel->setText("");
 
888
        }
 
889
 
 
890
        QStatusBar *sb = statusBar();
 
891
        connect(sb, SIGNAL(messageChanged(const QString &)), this, SLOT(showStatusMessage(const QString &)));
 
892
        widgetParent->addStatusBar(m_statusBar);
 
893
        if(sb != m_statusBar) sb->hide();
 
894
 
 
895
        if (m_breadboardGraphicsView) m_breadboardGraphicsView->setCurrent(false);
 
896
        if (m_schematicGraphicsView) m_schematicGraphicsView->setCurrent(false);
 
897
        if (m_pcbGraphicsView) m_pcbGraphicsView->setCurrent(false);
 
898
 
 
899
        SketchWidget *widget = qobject_cast<SketchWidget *>(widgetParent->contentView());
 
900
 
 
901
        if(m_currentGraphicsView) {
 
902
                m_currentGraphicsView->saveZoom(m_zoomSlider->value());
 
903
                disconnect(
 
904
                        m_currentGraphicsView,
 
905
                        SIGNAL(selectionChangedSignal()),
 
906
                        this,
 
907
                        SLOT(updateTransformationActions())
 
908
                );
 
909
        }
 
910
        m_currentGraphicsView = widget;
 
911
        if (widget == NULL) return;
 
912
 
 
913
        m_zoomSlider->setValue(m_currentGraphicsView->retrieveZoom());
 
914
 
 
915
        connect(
 
916
                m_currentGraphicsView,                                  // don't connect directly to the scene here, connect to the widget's signal
 
917
                SIGNAL(selectionChangedSignal()),
 
918
                this,
 
919
                SLOT(updateTransformationActions())
 
920
        );
 
921
 
 
922
        updateActiveLayerButtons();
 
923
 
 
924
        m_currentGraphicsView->setCurrent(true);
 
925
 
 
926
        // !!!!!! hack alert  !!!!!!!  
 
927
        // this item update loop seems to deal with a qt update bug:
 
928
        // if one view is visible and you change something in another view, 
 
929
        // the change might not appear when you switch views until you move the item in question
 
930
        foreach(QGraphicsItem * item, m_currentGraphicsView->items()) {
 
931
                item->update();
 
932
        }
 
933
 
 
934
        updateLayerMenu(true);
 
935
    if (m_showBreadboardAct) {
 
936
            QList<QAction *> actions;
 
937
            actions << m_showBreadboardAct << m_showSchematicAct << m_showPCBAct;
 
938
            setActionsIcons(index, actions);
 
939
    }
 
940
 
 
941
        hideShowTraceMenu();
 
942
        updateTraceMenu();
 
943
        updateTransformationActions();
 
944
 
 
945
        setTitle();
 
946
 
 
947
        // triggers a signal to the navigator widget
 
948
    if (m_navigators.count() > index) {
 
949
            m_navigators[index]->miniViewMousePressedSlot();
 
950
    }
 
951
        emit viewSwitched(index);
 
952
 
 
953
    if (m_showInViewHelpAct) {
 
954
            if (m_helper == NULL) {
 
955
                    m_showInViewHelpAct->setChecked(false);
 
956
            }
 
957
            else {
 
958
                    m_showInViewHelpAct->setChecked(m_helper->helpVisible(currentTabIndex()));
 
959
            }
 
960
    }
 
961
 
 
962
    if (m_infoView) {
 
963
            m_currentGraphicsView->updateInfoView();
 
964
    }
 
965
 
 
966
        // update issue with 4.5.1?: is this still valid (4.6.x?)
 
967
        m_currentGraphicsView->updateConnectors();
 
968
 
 
969
}
 
970
 
 
971
void MainWindow::setActionsIcons(int index, QList<QAction *> & actions) {
 
972
        for (int i = 0; i < actions.count(); i++) {
 
973
                actions[i]->setIcon(index == i ? m_dotIcon : m_emptyIcon);
 
974
        }
 
975
}
 
976
 
 
977
void MainWindow::closeEvent(QCloseEvent *event) {
 
978
        if (m_dontClose) {
 
979
                event->ignore();
 
980
                return;
 
981
        }
 
982
 
 
983
        if (m_programWindow) {
 
984
                m_programWindow->close();
 
985
                if (m_programWindow->isVisible()) {
 
986
                        event->ignore();
 
987
                        return;
 
988
                }
 
989
        }
 
990
 
 
991
        if (!m_closeSilently) {
 
992
                bool whatWithAliens = whatToDoWithAlienFiles();
 
993
                bool discard;
 
994
                if(!beforeClosing(true, discard) || !whatWithAliens ||!m_binManager->beforeClosing()) {
 
995
                        event->ignore();
 
996
                        return;
 
997
                }
 
998
 
 
999
                if(whatWithAliens && m_binManager->hasAlienParts()) {
 
1000
                        m_binManager->createIfMyPartsNotExists();
 
1001
                }
 
1002
        }
 
1003
 
 
1004
        //DebugDialog::debug(QString("top level windows: %1").arg(QApplication::topLevelWidgets().size()));
 
1005
        /*
 
1006
        foreach (QWidget * widget, QApplication::topLevelWidgets()) {
 
1007
                QMenu * menu = qobject_cast<QMenu *>(widget);
 
1008
                if (menu != NULL) {
 
1009
                        continue;                               // QMenus are always top level widgets, even if they have parents...
 
1010
                }
 
1011
                DebugDialog::debug(QString("top level widget %1 %2 %3")
 
1012
                        .arg(widget->metaObject()->className())
 
1013
                        .arg(widget->windowTitle())
 
1014
                        .arg(widget->toolTip())
 
1015
                        );
 
1016
        }
 
1017
        */
 
1018
 
 
1019
        m_closing = true;
 
1020
 
 
1021
        int count = 0;
 
1022
        foreach (QWidget *widget, QApplication::topLevelWidgets()) {
 
1023
                if (widget == this) continue;
 
1024
                if (qobject_cast<QMainWindow *>(widget) == NULL) continue;
 
1025
 
 
1026
                count++;
 
1027
        }
 
1028
 
 
1029
        if (count == 0) {
 
1030
                DebugDialog::closeDebug();
 
1031
        }
 
1032
 
 
1033
        QSettings settings;
 
1034
        settings.setValue(m_settingsPrefix + "state",saveState());
 
1035
        settings.setValue(m_settingsPrefix + "geometry",saveGeometry());
 
1036
 
 
1037
        QMainWindow::closeEvent(event);
 
1038
}
 
1039
 
 
1040
bool MainWindow::whatToDoWithAlienFiles() {
 
1041
        if (m_alienFiles.size() > 0) {
 
1042
                QMessageBox::StandardButton reply;
 
1043
                reply = QMessageBox::question(this, tr("Save %1").arg(QFileInfo(m_fwFilename).baseName()),
 
1044
                                                 m_alienPartsMsg
 
1045
                                                 .arg(QFileInfo(m_fwFilename).baseName()),
 
1046
                                                 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
 
1047
                // TODO: translate button text
 
1048
                if (reply == QMessageBox::Yes) {
 
1049
                        return true;
 
1050
                } else if (reply == QMessageBox::No) {
 
1051
                        foreach(QString pathToRemove, m_alienFiles) {
 
1052
                                QFile::remove(pathToRemove);
 
1053
                        }
 
1054
                        m_alienFiles.clear();
 
1055
                        recoverBackupedFiles();
 
1056
 
 
1057
                        emit alienPartsDismissed();
 
1058
                        return true;
 
1059
                }
 
1060
                else {
 
1061
                        return false;
 
1062
                }
 
1063
        } else {
 
1064
                return true;
 
1065
        }
 
1066
}
 
1067
 
 
1068
void MainWindow::acceptAlienFiles() {
 
1069
        m_alienFiles.clear();
 
1070
}
 
1071
 
 
1072
bool MainWindow::eventFilter(QObject *object, QEvent *event) {
 
1073
        if (object == this &&
 
1074
                (event->type() == QEvent::KeyPress
 
1075
                // || event->type() == QEvent::KeyRelease
 
1076
                || event->type() == QEvent::ShortcutOverride))
 
1077
        {
 
1078
                //DebugDialog::debug(QString("event filter %1").arg(event->type()) );
 
1079
                updatePartMenu();
 
1080
                updateTraceMenu();
 
1081
 
 
1082
                // On the mac, the first time the delete key is pressed, to be used as a shortcut for QAction m_deleteAct,
 
1083
                // for some reason, the enabling of the m_deleteAct in UpdateEditMenu doesn't "take" until the next time the event loop is processed
 
1084
                // Thereafter, the delete key works as it should.
 
1085
                // So this call to processEvents() makes sure m_deleteAct is enabled.
 
1086
                ProcessEventBlocker::processEvents();
 
1087
        }
 
1088
 
 
1089
        return QMainWindow::eventFilter(object, event);
 
1090
}
 
1091
 
 
1092
const QString MainWindow::untitledFileName() {
 
1093
        return UntitledSketchName;
 
1094
}
 
1095
 
 
1096
int &MainWindow::untitledFileCount() {
 
1097
        return UntitledSketchIndex;
 
1098
}
 
1099
 
 
1100
const QString MainWindow::fileExtension() {
 
1101
        return FritzingBundleExtension;
 
1102
}
 
1103
 
 
1104
const QString MainWindow::defaultSaveFolder() {
 
1105
        return FolderUtils::openSaveFolder();
 
1106
}
 
1107
 
 
1108
bool MainWindow::undoStackIsEmpty() {
 
1109
        return m_undoStack->count() == 0;
 
1110
}
 
1111
 
 
1112
void MainWindow::setInfoViewOnHover(bool infoViewOnHover) {
 
1113
        m_breadboardGraphicsView->setInfoViewOnHover(infoViewOnHover);
 
1114
        m_schematicGraphicsView->setInfoViewOnHover(infoViewOnHover);
 
1115
        m_pcbGraphicsView->setInfoViewOnHover(infoViewOnHover);
 
1116
 
 
1117
        m_binManager->setInfoViewOnHover(infoViewOnHover);
 
1118
}
 
1119
 
 
1120
void MainWindow::loadBundledSketch(const QString &fileName, bool addToRecent, bool setAsLastOpened) {
 
1121
 
 
1122
        if(!FolderUtils::unzipTo(fileName, m_fzzFolder)) {
 
1123
                QMessageBox::warning(
 
1124
                        this,
 
1125
                        tr("Fritzing"),
 
1126
                        tr("Unable to open '%1'").arg(fileName)
 
1127
                );
 
1128
 
 
1129
                return;
 
1130
        }
 
1131
 
 
1132
        QDir dir(m_fzzFolder);
 
1133
    QString binFileName = dir.absoluteFilePath(QFileInfo(BinManager::TempPartsBinTemplateLocation).fileName());
 
1134
    m_binManager->setTempPartsBinLocation(binFileName);
 
1135
    FolderUtils::copyBin(binFileName, BinManager::TempPartsBinTemplateLocation);
 
1136
 
 
1137
        QStringList namefilters;
 
1138
        namefilters << "*"+FritzingSketchExtension;
 
1139
        QFileInfoList entryInfoList = dir.entryInfoList(namefilters);
 
1140
        if (entryInfoList.count() == 0) {
 
1141
                QMessageBox::warning(
 
1142
                        this,
 
1143
                        tr("Fritzing"),
 
1144
                        tr("No Sketch found in '%1'").arg(fileName)
 
1145
                );
 
1146
 
 
1147
                return;
 
1148
        }
 
1149
 
 
1150
        QFileInfo sketchInfo = entryInfoList[0];
 
1151
 
 
1152
        QString sketchName = dir.absoluteFilePath(sketchInfo.fileName());
 
1153
 
 
1154
    namefilters.clear();
 
1155
    namefilters << "*" + FritzingPartExtension;
 
1156
    entryInfoList = dir.entryInfoList(namefilters);
 
1157
    QRegExp moduleIDFinder("moduleId=\"([^\"]+)");
 
1158
 
 
1159
    namefilters.clear();
 
1160
        namefilters << "*.svg";
 
1161
        QFileInfoList svgEntryInfoList = dir.entryInfoList(namefilters);
 
1162
 
 
1163
    m_addedToTemp = false;
 
1164
 
 
1165
    foreach (QFileInfo fzpInfo, entryInfoList) {
 
1166
        QFile file(dir.absoluteFilePath(fzpInfo.fileName()));
 
1167
        if (!file.open(QFile::ReadOnly)) {
 
1168
            DebugDialog::debug(QString("unable to open %1: %2").arg(file.fileName()));
 
1169
            continue;
 
1170
        }
 
1171
 
 
1172
 
 
1173
        // TODO: could be more efficient by using a streamreader
 
1174
        QString fzp = file.readAll();
 
1175
        file.close();
 
1176
        int ix = fzp.indexOf(moduleIDFinder);
 
1177
        if (ix < 0) {
 
1178
            DebugDialog::debug(QString("unable to find module id in %1: %2").arg(file.fileName()).arg(fzp));
 
1179
            continue;
 
1180
        }
 
1181
 
 
1182
        QString moduleID = moduleIDFinder.cap(1);
 
1183
        ModelPart * mp = m_referenceModel->retrieveModelPart(moduleID);
 
1184
        if (mp == NULL) {
 
1185
            QDomDocument doc;
 
1186
            if (!doc.setContent(fzp)) {
 
1187
                DebugDialog::debug(QString("unable to parse fzp in %1: %2").arg(file.fileName()).arg(fzp));
 
1188
                continue;
 
1189
            }
 
1190
 
 
1191
 
 
1192
            mp = copyToPartsFolder(fzpInfo, false, false, PartFactory::folderPath(), "contrib");
 
1193
            if (mp == NULL) {
 
1194
                DebugDialog::debug(QString("unable to create model part in %1: %2").arg(file.fileName()).arg(fzp));
 
1195
                continue;
 
1196
            }
 
1197
 
 
1198
            QDomElement root = doc.documentElement();
 
1199
                QDomElement views = root.firstChildElement("views");
 
1200
                QDomElement view = views.firstChildElement();
 
1201
            while (!view.isNull()) {
 
1202
                QDomElement layers = view.firstChildElement("layers");
 
1203
                QString path = layers.attribute("image", "");
 
1204
                if (!path.isEmpty()) {
 
1205
                    int ix = path.indexOf("/");
 
1206
                    path = path.mid(ix + 1);
 
1207
                    for (int jx = svgEntryInfoList.count() - 1; jx >= 0; jx--) {
 
1208
                        QFileInfo svgInfo = svgEntryInfoList.at(jx);
 
1209
                        if (svgInfo.fileName().contains(path)) {
 
1210
                            copyToSvgFolder(svgInfo, false, PartFactory::folderPath(), "contrib");
 
1211
                            svgEntryInfoList.removeAt(jx);
 
1212
                        }
 
1213
                    }
 
1214
                }
 
1215
                view = view.nextSiblingElement();
 
1216
            }
 
1217
 
 
1218
                mp->setFzz(true);
 
1219
        }
 
1220
 
 
1221
                m_binManager->addToTempPartsBin(mp);
 
1222
        m_addedToTemp = true;
 
1223
    }
 
1224
 
 
1225
        if (!m_addedToTemp) {
 
1226
                m_binManager->hideTempPartsBin();
 
1227
        }
 
1228
 
 
1229
        // the bundled itself
 
1230
        this->mainLoad(sketchName, "");
 
1231
        setCurrentFile(fileName, addToRecent, setAsLastOpened);
 
1232
}
 
1233
 
 
1234
void MainWindow::loadBundledNonAtomicEntity(const QString &fileName, Bundler* bundler, bool addToBin, bool dontAsk) {
 
1235
        QDir destFolder = QDir::temp();
 
1236
 
 
1237
        FolderUtils::createFolderAnCdIntoIt(destFolder, FolderUtils::getRandText());
 
1238
        QString unzipDirPath = destFolder.path();
 
1239
 
 
1240
        if(!FolderUtils::unzipTo(fileName, unzipDirPath)) {
 
1241
                QMessageBox::warning(
 
1242
                        this,
 
1243
                        tr("Fritzing"),
 
1244
                        tr("Unable to open shareable %1").arg(fileName)
 
1245
                );
 
1246
 
 
1247
                // gotta return now, or loadBundledSketchAux will crash
 
1248
                return;
 
1249
        }
 
1250
 
 
1251
        QDir unzipDir(unzipDirPath);
 
1252
 
 
1253
        if (bundler->preloadBundledAux(unzipDir, dontAsk)) {
 
1254
                QList<ModelPart*> mps = moveToPartsFolder(unzipDir,this,addToBin,true,FolderUtils::getUserDataStorePath("parts"),"contrib");
 
1255
                // the bundled itself
 
1256
                bundler->loadBundledAux(unzipDir,mps);
 
1257
        }
 
1258
 
 
1259
        FolderUtils::rmdir(unzipDirPath);
 
1260
}
 
1261
 
 
1262
/*
 
1263
void MainWindow::loadBundledPartFromWeb() {
 
1264
        QMainWindow *mw = new QMainWindow();
 
1265
        QString url = "http://localhost:8081/parts_gen/choose";
 
1266
        QWebView *view = new QWebView(mw);
 
1267
        mw->setCentralWidget(view);
 
1268
        view->setUrl(QUrl(url));
 
1269
        mw->show();
 
1270
        mw->raise();
 
1271
}
 
1272
*/
 
1273
 
 
1274
ModelPart* MainWindow::loadBundledPart(const QString &fileName, bool addToBin) {
 
1275
        QDir destFolder = QDir::temp();
 
1276
 
 
1277
        FolderUtils::createFolderAnCdIntoIt(destFolder, FolderUtils::getRandText());
 
1278
        QString unzipDirPath = destFolder.path();
 
1279
 
 
1280
        if(!FolderUtils::unzipTo(fileName, unzipDirPath)) {
 
1281
                QMessageBox::warning(
 
1282
                        this,
 
1283
                        tr("Fritzing"),
 
1284
                        tr("Unable to open shareable part %1").arg(fileName)
 
1285
                );
 
1286
                return NULL;
 
1287
        }
 
1288
 
 
1289
        QDir unzipDir(unzipDirPath);
 
1290
 
 
1291
        QList<ModelPart*> mps = moveToPartsFolder(unzipDir, this, addToBin, true, FolderUtils::getUserDataStorePath("parts"), "contrib");
 
1292
        if (mps.count()!=1) {
 
1293
                // if this fails, that means that the bundled was wrong
 
1294
                QMessageBox::warning(
 
1295
                        this,
 
1296
                        tr("Fritzing"),
 
1297
                        tr("Unable to read shareable part %1").arg(fileName)
 
1298
                );
 
1299
                return NULL;
 
1300
        }
 
1301
 
 
1302
        FolderUtils::rmdir(unzipDirPath);
 
1303
 
 
1304
        return mps[0];
 
1305
}
 
1306
 
 
1307
void MainWindow::saveBundledPart(const QString &moduleId) {
 
1308
        QString modIdToExport;
 
1309
        ModelPart* mp;
 
1310
 
 
1311
        if(moduleId.isEmpty()) {
 
1312
                if (m_currentGraphicsView == NULL) return;
 
1313
                PaletteItem *selectedPart = m_currentGraphicsView->getSelectedPart();
 
1314
                mp = selectedPart->modelPart();
 
1315
                modIdToExport = mp->moduleID();
 
1316
        } else {
 
1317
                modIdToExport = moduleId;
 
1318
                mp = m_referenceModel->retrieveModelPart(moduleId);
 
1319
        }
 
1320
        QString partTitle = mp->title();
 
1321
 
 
1322
        QString fileExt;
 
1323
        QString path = defaultSaveFolder()+"/"+partTitle+FritzingBundledPartExtension;
 
1324
        QString bundledFileName = FolderUtils::getSaveFileName(
 
1325
                        this,
 
1326
                        tr("Specify a file name"),
 
1327
                        path,
 
1328
                        tr("Fritzing Part (*%1)").arg(FritzingBundledPartExtension),
 
1329
                        &fileExt
 
1330
                  );
 
1331
 
 
1332
        if (bundledFileName.isEmpty()) return; // Cancel pressed
 
1333
 
 
1334
        if(!alreadyHasExtension(bundledFileName, FritzingBundledPartExtension)) {
 
1335
                bundledFileName += FritzingBundledPartExtension;
 
1336
        }
 
1337
 
 
1338
        QDir destFolder = QDir::temp();
 
1339
 
 
1340
        FolderUtils::createFolderAnCdIntoIt(destFolder, FolderUtils::getRandText());
 
1341
        QString dirToRemove = destFolder.path();
 
1342
 
 
1343
        QString aux = QFileInfo(bundledFileName).fileName();
 
1344
        QString destPartPath = // remove the last "z" from the extension
 
1345
                        destFolder.path()+"/"+aux.left(aux.size()-1);
 
1346
        DebugDialog::debug("saving part temporarily to "+destPartPath);
 
1347
 
 
1348
        //bool wasModified = isWindowModified();
 
1349
        //QString prevFileName = m_fileName;
 
1350
        //saveAsAux(destPartPath);
 
1351
        //m_fileName = prevFileName;
 
1352
        //setWindowModified(wasModified);
 
1353
        setTitle();
 
1354
 
 
1355
        saveBundledAux(mp, destFolder);
 
1356
 
 
1357
    QStringList skipSuffixes;
 
1358
        if(!FolderUtils::createZipAndSaveTo(destFolder, bundledFileName, skipSuffixes)) {
 
1359
                QMessageBox::warning(
 
1360
                        this,
 
1361
                        tr("Fritzing"),
 
1362
                        tr("Unable to export %1 to shareable sketch").arg(bundledFileName)
 
1363
                );
 
1364
        }
 
1365
 
 
1366
        FolderUtils::rmdir(dirToRemove);
 
1367
}
 
1368
 
 
1369
QStringList MainWindow::saveBundledAux(ModelPart *mp, const QDir &destFolder) {
 
1370
        QStringList names;
 
1371
        QString partPath = mp->path();
 
1372
        QFile file(partPath);
 
1373
        QString fn = ZIP_PART + QFileInfo(partPath).fileName();
 
1374
        names << fn;
 
1375
        file.copy(destFolder.path()+"/"+fn);
 
1376
 
 
1377
        QList<ViewLayer::ViewIdentifier> identifiers;
 
1378
        identifiers << ViewLayer::IconView << ViewLayer::BreadboardView << ViewLayer::SchematicView << ViewLayer::PCBView;
 
1379
        foreach (ViewLayer::ViewIdentifier viewIdentifier, identifiers) {
 
1380
                QString basename = mp->hasBaseNameFor(viewIdentifier);
 
1381
                if (basename.isEmpty()) continue;
 
1382
 
 
1383
                QString filename = ItemBase::getSvgFilename(mp, basename);
 
1384
                if (filename.isEmpty()) continue;
 
1385
 
 
1386
                QFile file(filename);
 
1387
                basename.replace("/", ".");
 
1388
                QString fn = ZIP_SVG + basename;
 
1389
                names << fn;
 
1390
                file.copy(destFolder.path()+"/"+fn);
 
1391
        }
 
1392
 
 
1393
        return names;
 
1394
}
 
1395
 
 
1396
QList<ModelPart*> MainWindow::moveToPartsFolder(QDir &unzipDir, MainWindow* mw, bool addToBin, bool addToAlien, const QString & prefixFolder, const QString &destFolder) {
 
1397
        QStringList namefilters;
 
1398
        QList<ModelPart*> retval;
 
1399
 
 
1400
        if (mw == NULL) {
 
1401
                throw "MainWindow::moveToPartsFolder mainwindow missing";
 
1402
        }
 
1403
 
 
1404
        if(mw) {
 
1405
                namefilters << ZIP_SVG+"*";
 
1406
                foreach(QFileInfo file, unzipDir.entryInfoList(namefilters)) { // svg files
 
1407
                        //DebugDialog::debug("unzip svg " + file.absoluteFilePath());
 
1408
                        mw->copyToSvgFolder(file, addToAlien, prefixFolder, destFolder);
 
1409
                }
 
1410
 
 
1411
                namefilters.clear();
 
1412
                namefilters << ZIP_PART+"*"; 
 
1413
 
 
1414
                foreach(QFileInfo file, unzipDir.entryInfoList(namefilters)) { // part files
 
1415
                        //DebugDialog::debug("unzip part " + file.absoluteFilePath());
 
1416
                        retval << mw->copyToPartsFolder(file, addToBin, addToAlien, prefixFolder, destFolder);
 
1417
                }
 
1418
        }
 
1419
 
 
1420
        return retval;
 
1421
}
 
1422
 
 
1423
void MainWindow::copyToSvgFolder(const QFileInfo& file, bool addToAlien, const QString & prefixFolder, const QString &destFolder) {
 
1424
        QFile svgfile(file.filePath());
 
1425
        // let's make sure that we remove just the suffix
 
1426
        QString fileName = file.fileName().remove(QRegExp("^"+ZIP_SVG));
 
1427
        QString viewFolder = fileName.left(fileName.indexOf("."));
 
1428
        fileName.remove(0, viewFolder.length() + 1);
 
1429
 
 
1430
        QString destFilePath =
 
1431
                prefixFolder+"/svg/"+destFolder+"/"+viewFolder+"/"+fileName;
 
1432
 
 
1433
        backupExistingFileIfExists(destFilePath);
 
1434
        if(svgfile.copy(destFilePath)) {
 
1435
                if (addToAlien) {
 
1436
                        m_alienFiles << destFilePath;
 
1437
                }
 
1438
        }
 
1439
}
 
1440
 
 
1441
ModelPart* MainWindow::copyToPartsFolder(const QFileInfo& file, bool addToBin, bool addToAlien, const QString & prefixFolder, const QString &destFolder) {
 
1442
        QFile partfile(file.filePath());
 
1443
        // let's make sure that we remove just the suffix
 
1444
        QString destFilePath =
 
1445
                prefixFolder+"/"+destFolder+"/"+file.fileName().remove(QRegExp("^"+ZIP_PART));
 
1446
 
 
1447
        backupExistingFileIfExists(destFilePath);
 
1448
        if(partfile.copy(destFilePath)) {
 
1449
                if (addToAlien) {
 
1450
                        m_alienFiles << destFilePath;
 
1451
                        m_alienPartsMsg = tr("Do you want to keep the imported parts?");
 
1452
                }
 
1453
        }
 
1454
        ModelPart *mp = m_referenceModel->loadPart(destFilePath, true);
 
1455
        mp->setAlien(true);
 
1456
 
 
1457
        if(addToBin) {
 
1458
                m_binManager->addToContrib(mp);
 
1459
        }
 
1460
 
 
1461
        return mp;
 
1462
}
 
1463
 
 
1464
void MainWindow::binSaved(bool hasPartsFromBundled) {
 
1465
        if(hasPartsFromBundled) {
 
1466
                // the bin will need those parts, so just keep them
 
1467
                m_alienFiles.clear();
 
1468
                resetTempFolder();
 
1469
        }
 
1470
}
 
1471
 
 
1472
#undef ZIP_PART
 
1473
#undef ZIP_SVG
 
1474
 
 
1475
 
 
1476
void MainWindow::backupExistingFileIfExists(const QString &destFilePath) {
 
1477
        if(QFileInfo(destFilePath).exists()) {
 
1478
                if(m_tempDir.path() == ".") {
 
1479
                        m_tempDir = QDir::temp();
 
1480
                        FolderUtils::createFolderAnCdIntoIt(m_tempDir, FolderUtils::getRandText());
 
1481
                        DebugDialog::debug("debug folder for overwritten files: "+m_tempDir.path());
 
1482
                }
 
1483
 
 
1484
                QString fileBackupName = QFileInfo(destFilePath).fileName();
 
1485
                m_filesReplacedByAlienOnes << destFilePath;
 
1486
                QFile file(destFilePath);
 
1487
                bool alreadyExists = file.exists();
 
1488
                file.copy(m_tempDir.path()+"/"+fileBackupName);
 
1489
 
 
1490
                if(alreadyExists) {
 
1491
                        file.remove(destFilePath);
 
1492
                }
 
1493
        }
 
1494
}
 
1495
 
 
1496
void MainWindow::recoverBackupedFiles() {
 
1497
        foreach(QString originalFilePath, m_filesReplacedByAlienOnes) {
 
1498
                QFile file(m_tempDir.path()+"/"+QFileInfo(originalFilePath).fileName());
 
1499
                if(file.exists(originalFilePath)) {
 
1500
                        file.remove();
 
1501
                }
 
1502
                file.copy(originalFilePath);
 
1503
        }
 
1504
        resetTempFolder();
 
1505
}
 
1506
 
 
1507
void MainWindow::resetTempFolder() {
 
1508
        if(m_tempDir.path() != ".") {
 
1509
                FolderUtils::rmdir(m_tempDir);
 
1510
                m_tempDir = QDir::temp();
 
1511
        }
 
1512
        m_filesReplacedByAlienOnes.clear();
 
1513
}
 
1514
 
 
1515
void MainWindow::routingStatusSlot(SketchWidget * sketchWidget, const RoutingStatus & routingStatus) {
 
1516
        m_routingStatus = routingStatus;
 
1517
        QString theText;
 
1518
        if (routingStatus.m_netCount == 0) {
 
1519
                theText = tr("No connections to route");
 
1520
        } else if (routingStatus.m_netCount == routingStatus.m_netRoutedCount) {
 
1521
                if (routingStatus.m_jumperItemCount == 0) {
 
1522
                        theText = tr("Routing completed");
 
1523
                }
 
1524
                else {
 
1525
                        theText = tr("Routing completed using %n jumper part(s)", "", routingStatus.m_jumperItemCount);
 
1526
                }
 
1527
        } else {
 
1528
                theText = tr("%1 of %2 nets routed - %n connector(s) still to be routed", "", routingStatus.m_connectorsLeftToRoute)
 
1529
                        .arg(routingStatus.m_netRoutedCount)
 
1530
                        .arg(routingStatus.m_netCount);
 
1531
        }
 
1532
 
 
1533
        dynamic_cast<SketchAreaWidget *>(sketchWidget->parent())->routingStatusLabel()->setLabelText(theText);
 
1534
 
 
1535
        updateTraceMenu();
 
1536
}
 
1537
 
 
1538
void MainWindow::applyReadOnlyChange(bool isReadOnly) {
 
1539
        Q_UNUSED(isReadOnly);
 
1540
        //m_saveAct->setDisabled(isReadOnly);
 
1541
}
 
1542
 
 
1543
void MainWindow::currentNavigatorChanged(MiniViewContainer * miniView)
 
1544
{
 
1545
        int index = m_navigators.indexOf(miniView);
 
1546
        if (index < 0) return;
 
1547
 
 
1548
        int oldIndex = currentTabIndex();
 
1549
        if (oldIndex == index) return;
 
1550
 
 
1551
        setCurrentTabIndex(index);
 
1552
}
 
1553
 
 
1554
void MainWindow::viewSwitchedTo(int viewIndex) {
 
1555
        setCurrentTabIndex(viewIndex);
 
1556
}
 
1557
 
 
1558
const QString MainWindow::fritzingTitle() {
 
1559
        if (m_currentGraphicsView == NULL) {
 
1560
                return FritzingWindow::fritzingTitle();
 
1561
        }
 
1562
 
 
1563
        QString fritzing = FritzingWindow::fritzingTitle();
 
1564
        return tr("%1 - [%2]").arg(fritzing).arg(m_currentGraphicsView->viewName());
 
1565
}
 
1566
 
 
1567
QAction *MainWindow::raiseWindowAction() {
 
1568
        return m_raiseWindowAct;
 
1569
}
 
1570
 
 
1571
void MainWindow::raiseAndActivate() {
 
1572
        if(isMinimized()) {
 
1573
                showNormal();
 
1574
        }
 
1575
        raise();
 
1576
        QTimer::singleShot(20, this, SLOT(activateWindowAux()));
 
1577
}
 
1578
 
 
1579
void MainWindow::activateWindowAux() {
 
1580
        activateWindow();
 
1581
}
 
1582
 
 
1583
void MainWindow::updateRaiseWindowAction() {
 
1584
        QString actionText;
 
1585
        QFileInfo fileInfo(m_fwFilename);
 
1586
        if(fileInfo.exists()) {
 
1587
                int lastSlashIdx = m_fwFilename.lastIndexOf("/");
 
1588
                int beforeLastSlashIdx = m_fwFilename.left(lastSlashIdx).lastIndexOf("/");
 
1589
                actionText = beforeLastSlashIdx > -1 && lastSlashIdx > -1 ? "..." : "";
 
1590
                actionText += m_fwFilename.right(m_fwFilename.size()-beforeLastSlashIdx-1);
 
1591
        } else {
 
1592
                actionText = m_fwFilename;
 
1593
        }
 
1594
        m_raiseWindowAct->setText(actionText);
 
1595
        m_raiseWindowAct->setToolTip(m_fwFilename);
 
1596
        m_raiseWindowAct->setStatusTip("raise \""+m_fwFilename+"\" window");
 
1597
}
 
1598
 
 
1599
QSizeGrip *MainWindow::sizeGrip() {
 
1600
        return m_sizeGrip;
 
1601
}
 
1602
 
 
1603
QStatusBar *MainWindow::realStatusBar() {
 
1604
        return m_statusBar;
 
1605
}
 
1606
 
 
1607
void MainWindow::moveEvent(QMoveEvent * event) {
 
1608
        FritzingWindow::moveEvent(event);
 
1609
        emit mainWindowMoved(this);
 
1610
}
 
1611
 
 
1612
bool MainWindow::event(QEvent * e) {
 
1613
        switch (e->type()) {
 
1614
                case QEvent::WindowActivate:
 
1615
                        emit changeActivationSignal(true, this);
 
1616
                        break;
 
1617
                case QEvent::WindowDeactivate:
 
1618
                        emit changeActivationSignal(false, this);
 
1619
                        break;
 
1620
                default:
 
1621
                        break;
 
1622
        }
 
1623
        return FritzingWindow::event(e);
 
1624
}
 
1625
 
 
1626
void MainWindow::resizeEvent(QResizeEvent * event) {
 
1627
    if (m_sizeGrip) {
 
1628
            m_sizeGrip->rearrange();
 
1629
    }
 
1630
        FritzingWindow::resizeEvent(event);
 
1631
}
 
1632
 
 
1633
void MainWindow::showInViewHelp() {
 
1634
        //delete m_helper;
 
1635
        if (m_helper == NULL) {
 
1636
                m_helper = new Helper(this, true);
 
1637
                return;
 
1638
        }
 
1639
 
 
1640
        bool toggle = !m_helper->helpVisible(currentTabIndex());
 
1641
        showAllFirstTimeHelp(toggle);
 
1642
 
 
1643
        /*
 
1644
        m_helper->toggleHelpVisibility(currentTabIndex());
 
1645
        */
 
1646
 
 
1647
        m_showInViewHelpAct->setChecked(m_helper->helpVisible(currentTabIndex()));
 
1648
}
 
1649
 
 
1650
 
 
1651
void MainWindow::showAllFirstTimeHelp(bool show) {
 
1652
        if (m_helper) {
 
1653
                for (int i = 0; i < 3; i++) {
 
1654
                        m_helper->setHelpVisibility(i, show);
 
1655
                }
 
1656
        }
 
1657
        m_showInViewHelpAct->setChecked(show);
 
1658
}
 
1659
 
 
1660
void MainWindow::enableCheckUpdates(bool enabled)
 
1661
{
 
1662
        if (m_checkForUpdatesAct != NULL) {
 
1663
                m_checkForUpdatesAct->setEnabled(enabled);
 
1664
        }
 
1665
}
 
1666
 
 
1667
 
 
1668
void MainWindow::swapSelectedDelay(const QString & family, const QString & prop, QMap<QString, QString> & currPropsMap, ItemBase * itemBase) 
 
1669
{
 
1670
        m_swapTimer.stop();
 
1671
        m_swapTimer.setAll(family, prop, currPropsMap, itemBase);
 
1672
        m_swapTimer.start();
 
1673
}
 
1674
 
 
1675
void MainWindow::swapSelectedTimeout()
 
1676
{
 
1677
        if (sender() == &m_swapTimer) {
 
1678
                QMap<QString, QString> map =  m_swapTimer.propsMap();
 
1679
                swapSelectedMap(m_swapTimer.family(), m_swapTimer.prop(), map, m_swapTimer.itemBase());
 
1680
        }
 
1681
}
 
1682
 
 
1683
void MainWindow::swapSelectedMap(const QString & family, const QString & prop, QMap<QString, QString> & currPropsMap, ItemBase * itemBase) 
 
1684
{
 
1685
        if (itemBase == NULL) return;
 
1686
 
 
1687
        QString generatedModuleID = currPropsMap.value("moduleID");
 
1688
 
 
1689
        if (generatedModuleID.isEmpty()) {
 
1690
            if ((family.compare("logo") == 0 || family.compare("pad") == 0) && prop.compare("layer") == 0) {
 
1691
                    QString value = currPropsMap.value(prop);
 
1692
                    if (value.contains("1") && m_currentGraphicsView->boardLayers() == 1) {
 
1693
                            QMessageBox::warning(
 
1694
                                    this,
 
1695
                                    tr("No copper top layer"),
 
1696
                                    tr("The copper top (copper 1) layer is not available on a one-sided board.  Please switch the board to double-sided or choose the copper bottom (copper 0) layer.")
 
1697
                            );
 
1698
                            return;
 
1699
                    }
 
1700
            }
 
1701
    }
 
1702
 
 
1703
        if (generatedModuleID.isEmpty()) {
 
1704
                if (family.compare("Prototyping Board", Qt::CaseInsensitive) == 0) {
 
1705
                        if (prop.compare("size", Qt::CaseInsensitive) == 0 || prop.compare("type", Qt::CaseInsensitive) == 0) {
 
1706
                                QString size = currPropsMap.value("size");
 
1707
                                QString type = currPropsMap.value("type");
 
1708
                                if (type.compare("perfboard", Qt::CaseInsensitive) == 0) {
 
1709
                                        generatedModuleID = Perfboard::genModuleID(currPropsMap);
 
1710
                                }
 
1711
                                else if (type.compare("stripboard", Qt::CaseInsensitive) == 0) {
 
1712
                                        generatedModuleID = Stripboard::genModuleID(currPropsMap);
 
1713
                                }
 
1714
                        }
 
1715
                }
 
1716
        }
 
1717
 
 
1718
        if (!generatedModuleID.isEmpty()) {
 
1719
                ModelPart * modelPart = m_referenceModel->retrieveModelPart(generatedModuleID);
 
1720
                if (modelPart == NULL) {
 
1721
                        if (!m_referenceModel->genFZP(generatedModuleID, m_referenceModel)) {
 
1722
                                return;
 
1723
                        }
 
1724
                }
 
1725
 
 
1726
                swapSelectedAux(itemBase->layerKinChief(), generatedModuleID, false, ViewLayer::UnknownSpec);
 
1727
                return;
 
1728
        }
 
1729
 
 
1730
        if ((prop.compare("package", Qt::CaseSensitive) != 0) && swapSpecial(prop, currPropsMap)) {
 
1731
                return;
 
1732
        }
 
1733
 
 
1734
        foreach (QString key, currPropsMap.keys()) {
 
1735
                QString value = currPropsMap.value(key);
 
1736
                m_referenceModel->recordProperty(key, value);
 
1737
        }
 
1738
 
 
1739
        QString moduleID = m_referenceModel->retrieveModuleIdWith(family, prop, true);
 
1740
        bool exactMatch = m_referenceModel->lastWasExactMatch();
 
1741
 
 
1742
        if(moduleID.isEmpty()) {
 
1743
        if (prop.compare("layer") == 0 && itemBase->modelPart()->flippedSMD()) {
 
1744
            ItemBase * viewItem = itemBase->modelPart()->viewItem(ViewLayer::PCBView);
 
1745
            if (viewItem) {
 
1746
                ViewLayer::ViewLayerID wantViewLayerID = ViewLayer::viewLayerIDFromXmlString(currPropsMap.value(prop));
 
1747
                if (viewItem->viewLayerID() != wantViewLayerID) {
 
1748
                    ViewLayer::ViewLayerSpec viewLayerSpec = (wantViewLayerID == ViewLayer::Copper0) ? ViewLayer::ThroughHoleThroughTop_OneLayer : ViewLayer::ThroughHoleThroughTop_TwoLayers;
 
1749
                    swapSelectedAux(itemBase->layerKinChief(), itemBase->moduleID(), true, viewLayerSpec);
 
1750
                    return;
 
1751
                }
 
1752
            }
 
1753
        }
 
1754
 
 
1755
                QMessageBox::information(
 
1756
                        this,
 
1757
                        tr("Sorry!"),
 
1758
                        tr(
 
1759
                         "No part with those characteristics.\n"
 
1760
                         "We're working to avoid this message, and only let you choose between properties that do exist")
 
1761
                );
 
1762
                return;
 
1763
        }
 
1764
 
 
1765
 
 
1766
 
 
1767
        itemBase = itemBase->layerKinChief();
 
1768
 
 
1769
        if(!exactMatch) {
 
1770
                AutoCloseMessageBox::showMessage(this, tr("No exactly matching part found; Fritzing chose the closest match."));
 
1771
        }
 
1772
 
 
1773
        swapSelectedAux(itemBase, moduleID, false, ViewLayer::UnknownSpec);
 
1774
}
 
1775
 
 
1776
bool MainWindow::swapSpecial(const QString & theProp, QMap<QString, QString> & currPropsMap) {
 
1777
        ItemBase * itemBase = m_infoView->currentItem();
 
1778
        QString pinSpacing, resistance;
 
1779
    int layers = 0;
 
1780
 
 
1781
        foreach (QString key, currPropsMap.keys()) {
 
1782
                if (key.compare("layers", Qt::CaseInsensitive) == 0) {
 
1783
                        if (!Board::isBoard(itemBase)) continue;
 
1784
 
 
1785
                        QString value = currPropsMap.value(key, "");
 
1786
                        if (value.compare(Board::OneLayerTranslated) == 0) {
 
1787
                                layers = 1;
 
1788
                        }
 
1789
                        else if (value.compare(Board::TwoLayersTranslated) == 0) {
 
1790
                                layers = 2;
 
1791
                        }
 
1792
        }
 
1793
 
 
1794
                if (key.compare("resistance", Qt::CaseInsensitive) == 0) {
 
1795
                        resistance = currPropsMap.value(key);
 
1796
                        continue;
 
1797
                }
 
1798
                if (key.compare("pin spacing", Qt::CaseInsensitive) == 0) {
 
1799
                        pinSpacing = currPropsMap.value(key);
 
1800
                        continue;
 
1801
                }
 
1802
        }
 
1803
 
 
1804
    if (layers != 0) {
 
1805
        currPropsMap.insert("layers", QString::number(layers));
 
1806
        if (theProp.compare("layers") == 0) {
 
1807
            QString msg = (layers == 1) ? tr("Change to single layer pcb") : tr("Change to two layer pcb");
 
1808
            swapLayers(itemBase, layers, msg, SketchWidget::PropChangeDelay);
 
1809
            return true;
 
1810
        }
 
1811
        }
 
1812
 
 
1813
        if (!resistance.isEmpty() || !pinSpacing.isEmpty()) {
 
1814
                if (theProp.contains("band", Qt::CaseInsensitive)) {
 
1815
                        // swap 4band for 5band or vice versa.
 
1816
                        return false;
 
1817
                }
 
1818
 
 
1819
                Resistor * resistor = qobject_cast<Resistor *>(itemBase);
 
1820
                if (resistor != NULL) {
 
1821
                        m_currentGraphicsView->setResistance(resistance, pinSpacing);
 
1822
                        return true;
 
1823
                }
 
1824
        }
 
1825
 
 
1826
        return false;
 
1827
}
 
1828
 
 
1829
void MainWindow::swapLayers(ItemBase * itemBase, int layers, const QString & msg, int delay) {
 
1830
    QUndoCommand* parentCommand = new QUndoCommand(msg);
 
1831
        new CleanUpWiresCommand(m_breadboardGraphicsView, CleanUpWiresCommand::UndoOnly, parentCommand);
 
1832
    m_pcbGraphicsView->swapLayers(itemBase, layers, parentCommand);
 
1833
        // need to defer execution so the content of the info view doesn't change during an event that started in the info view
 
1834
        m_undoStack->waitPush(parentCommand, delay);
 
1835
}
 
1836
 
 
1837
void MainWindow::swapSelectedAux(ItemBase * itemBase, const QString & moduleID, bool useViewLayerSpec, ViewLayer::ViewLayerSpec overrideViewLayerSpec) {
 
1838
 
 
1839
        QUndoCommand* parentCommand = new QUndoCommand(tr("Swapped %1 with module %2").arg(itemBase->instanceTitle()).arg(moduleID));
 
1840
        new CleanUpWiresCommand(m_breadboardGraphicsView, CleanUpWiresCommand::UndoOnly, parentCommand);
 
1841
 
 
1842
    ViewLayer::ViewLayerSpec viewLayerSpec = itemBase->viewLayerSpec();
 
1843
    if (m_pcbGraphicsView->boardLayers() == 2) {
 
1844
        ModelPart * modelPart = m_referenceModel->retrieveModelPart(moduleID);
 
1845
        if (modelPart->flippedSMD()) {
 
1846
            viewLayerSpec = m_pcbGraphicsView->layerIsActive(ViewLayer::Copper1) ? ViewLayer::ThroughHoleThroughTop_TwoLayers : ViewLayer::ThroughHoleThroughTop_OneLayer;
 
1847
            if (useViewLayerSpec) viewLayerSpec = overrideViewLayerSpec;
 
1848
        }
 
1849
    }
 
1850
 
 
1851
        swapSelectedAuxAux(itemBase, moduleID, viewLayerSpec, parentCommand);
 
1852
    
 
1853
        // need to defer execution so the content of the info view doesn't change during an event that started in the info view
 
1854
        m_undoStack->waitPush(parentCommand, SketchWidget::PropChangeDelay);
 
1855
 
 
1856
}
 
1857
 
 
1858
void MainWindow::swapBoardImageSlot(SketchWidget * sketchWidget, ItemBase * itemBase, const QString & filename, const QString & moduleID, bool addName) {
 
1859
 
 
1860
        QUndoCommand* parentCommand = new QUndoCommand(tr("Change image to %2").arg(filename));
 
1861
        long newID = swapSelectedAuxAux(itemBase, moduleID, itemBase->viewLayerSpec(), parentCommand);
 
1862
 
 
1863
    LoadLogoImageCommand * cmd = new LoadLogoImageCommand(sketchWidget, newID, "", QSizeF(0,0), filename, filename, addName, parentCommand);
 
1864
    cmd->setRedoOnly();
 
1865
   
 
1866
        // need to defer execution so the content of the info view doesn't change during an event that started in the info view
 
1867
        m_undoStack->waitPush(parentCommand, SketchWidget::PropChangeDelay);
 
1868
}
 
1869
 
 
1870
 
 
1871
void MainWindow::subSwapSlot(SketchWidget * sketchWidget, ItemBase * itemBase, const QString & newModuleID, ViewLayer::ViewLayerSpec viewLayerSpec, long & newID, QUndoCommand * parentCommand) {
 
1872
        Q_UNUSED(sketchWidget);
 
1873
        newID = swapSelectedAuxAux(itemBase, newModuleID, viewLayerSpec, parentCommand);
 
1874
}
 
1875
 
 
1876
long MainWindow::swapSelectedAuxAux(ItemBase * itemBase, const QString & moduleID,  ViewLayer::ViewLayerSpec viewLayerSpec, QUndoCommand * parentCommand) 
 
1877
{
 
1878
        long modelIndex = ModelPart::nextIndex();
 
1879
 
 
1880
        QList<SketchWidget *> sketchWidgets;
 
1881
 
 
1882
    // master view must go last, since it creates the delete command, and possibly has all the local props
 
1883
    switch (itemBase->viewIdentifier()) {
 
1884
        case ViewLayer::SchematicView:
 
1885
                    sketchWidgets << m_pcbGraphicsView << m_breadboardGraphicsView << m_schematicGraphicsView;
 
1886
            break;
 
1887
        case ViewLayer::PCBView:
 
1888
            sketchWidgets << m_schematicGraphicsView << m_breadboardGraphicsView << m_pcbGraphicsView;
 
1889
            break;
 
1890
        default:
 
1891
            sketchWidgets << m_schematicGraphicsView << m_pcbGraphicsView << m_breadboardGraphicsView;
 
1892
            break;
 
1893
        }
 
1894
 
 
1895
    SwapThing swapThing;
 
1896
    swapThing.firstTime = true;
 
1897
    swapThing.itemBase = itemBase;
 
1898
    swapThing.newModelIndex = modelIndex;
 
1899
    swapThing.newModuleID = moduleID;
 
1900
    swapThing.viewLayerSpec = viewLayerSpec;
 
1901
    swapThing.parentCommand = parentCommand;
 
1902
 
 
1903
    long newID = 0;
 
1904
    for (int i = 0; i < 3; i++) {
 
1905
        long tempID = sketchWidgets[i]->setUpSwap(swapThing, i == 2);
 
1906
        if (newID == 0 && tempID != 0) newID = tempID;
 
1907
    }
 
1908
 
 
1909
        // TODO:  z-order?
 
1910
 
 
1911
        return newID;
 
1912
}
 
1913
 
 
1914
void MainWindow::svgMissingLayer(const QString & layername, const QString & path) {
 
1915
        QMessageBox::warning(
 
1916
                this,
 
1917
                tr("Fritzing"),
 
1918
                tr("Svg %1 is missing a '%2' layer. "
 
1919
                        "For more information on how to create a custom board shape, "
 
1920
                        "see the tutorial at <a href='http://fritzing.org/learning/tutorials/designing-pcb/pcb-custom-shape/'>http://fritzing.org/learning/tutorials/designing-pcb/pcb-custom-shape/</a>.")
 
1921
                .arg(path)
 
1922
                .arg(layername)
 
1923
        );
 
1924
}
 
1925
 
 
1926
void MainWindow::addDefaultParts() {
 
1927
        if (m_pcbGraphicsView == NULL) return;
 
1928
 
 
1929
        m_pcbGraphicsView->addDefaultParts();
 
1930
        m_breadboardGraphicsView->addDefaultParts();
 
1931
        m_schematicGraphicsView->addDefaultParts();
 
1932
}
 
1933
 
 
1934
MainWindow * MainWindow::newMainWindow(ReferenceModel *referenceModel, const QString & displayPath, bool showProgress, bool lockFiles) {
 
1935
    MainWindow * mw = new MainWindow(referenceModel, NULL);
 
1936
        if (showProgress) {
 
1937
                mw->showFileProgressDialog(displayPath);
 
1938
        }
 
1939
 
 
1940
    mw->init(referenceModel, lockFiles);
 
1941
 
 
1942
        return mw;
 
1943
}
 
1944
 
 
1945
void  MainWindow::clearFileProgressDialog() {
 
1946
        if (m_fileProgressDialog) {
 
1947
                m_fileProgressDialog->close();
 
1948
                delete m_fileProgressDialog;
 
1949
                m_fileProgressDialog = NULL;
 
1950
        }
 
1951
}
 
1952
 
 
1953
void MainWindow::setFileProgressPath(const QString & path)
 
1954
{
 
1955
        if (m_fileProgressDialog) m_fileProgressDialog->setMessage(tr("loading %1").arg(path));
 
1956
}
 
1957
 
 
1958
FileProgressDialog * MainWindow::fileProgressDialog()
 
1959
{
 
1960
        return m_fileProgressDialog;
 
1961
}
 
1962
 
 
1963
void MainWindow::showFileProgressDialog(const QString & path) {
 
1964
    m_fileProgressDialog = new FileProgressDialog(tr("Loading..."), 200, this);
 
1965
        m_fileProgressDialog->setBinLoadingChunk(50);
 
1966
        if (!path.isEmpty()) {
 
1967
                setFileProgressPath(QFileInfo(path).fileName());
 
1968
        }
 
1969
        else {
 
1970
                setFileProgressPath(tr("new sketch"));
 
1971
        }
 
1972
}
 
1973
 
 
1974
const QString &MainWindow::selectedModuleID() {
 
1975
        if(m_currentGraphicsView) {
 
1976
                return m_currentGraphicsView->selectedModuleID();
 
1977
        } else {
 
1978
                return ___emptyString___;
 
1979
        }
 
1980
}
 
1981
 
 
1982
void MainWindow::redrawSketch() {
 
1983
        foreach (QGraphicsItem * item, m_currentGraphicsView->scene()->items()) {
 
1984
                item->update();
 
1985
                ConnectorItem * c = dynamic_cast<ConnectorItem *>(item);
 
1986
                if (c != NULL) {
 
1987
                        c->restoreColor(false, 0, true);
 
1988
                }
 
1989
        }
 
1990
}
 
1991
 
 
1992
void MainWindow::statusMessage(QString message, int timeout) {
 
1993
        QStatusBar * sb = realStatusBar();
 
1994
        if (sb != NULL) {
 
1995
                sb->showMessage(message, timeout);
 
1996
        }
 
1997
}
 
1998
 
 
1999
void MainWindow::dropPaste(SketchWidget * sketchWidget) {
 
2000
        Q_UNUSED(sketchWidget);
 
2001
        pasteInPlace();
 
2002
}
 
2003
 
 
2004
void MainWindow::updateLayerMenuSlot() {
 
2005
        updateLayerMenu(true);
 
2006
}
 
2007
 
 
2008
bool MainWindow::save() {
 
2009
        bool result = FritzingWindow::save();
 
2010
        if (result) {
 
2011
                QSettings settings;
 
2012
                settings.setValue("lastOpenSketch", m_fwFilename);
 
2013
        }
 
2014
        return result;
 
2015
}
 
2016
 
 
2017
bool MainWindow::saveAs() {
 
2018
        bool result = false;
 
2019
        if (m_fwFilename.endsWith(FritzingSketchExtension)) {
 
2020
                result = FritzingWindow::saveAs(m_fwFilename + 'z', false);
 
2021
        }
 
2022
        else {
 
2023
                result = FritzingWindow::saveAs();
 
2024
        }
 
2025
        if (result) {
 
2026
                QSettings settings;
 
2027
                settings.setValue("lastOpenSketch", m_fwFilename);
 
2028
        }
 
2029
        return result;
 
2030
}
 
2031
 
 
2032
void MainWindow::changeBoardLayers(int layers, bool doEmit) {
 
2033
        Q_UNUSED(doEmit);
 
2034
        Q_UNUSED(layers);
 
2035
        updateActiveLayerButtons();
 
2036
        m_currentGraphicsView->updateConnectors();
 
2037
}
 
2038
 
 
2039
void MainWindow::updateActiveLayerButtons() {
 
2040
    if (m_activeLayerButtonWidget == NULL) return;
 
2041
 
 
2042
        int index = activeLayerIndex();
 
2043
        bool enabled = index >= 0;
 
2044
 
 
2045
        m_activeLayerButtonWidget->setCurrentIndex(index);
 
2046
        m_activeLayerButtonWidget->setVisible(enabled);
 
2047
 
 
2048
        m_activeLayerBothAct->setEnabled(enabled);
 
2049
        m_activeLayerBottomAct->setEnabled(enabled);
 
2050
        m_activeLayerTopAct->setEnabled(enabled);
 
2051
 
 
2052
        QList<QAction *> actions;
 
2053
        actions << m_activeLayerBothAct << m_activeLayerBottomAct << m_activeLayerTopAct;
 
2054
        setActionsIcons(index, actions);
 
2055
}
 
2056
 
 
2057
 
 
2058
int MainWindow::activeLayerIndex() 
 
2059
{
 
2060
        if (m_currentGraphicsView == NULL) return -1;
 
2061
 
 
2062
        if (m_currentGraphicsView->boardLayers() == 2 || activeLayerWidgetAlwaysOn()) {
 
2063
                bool copper0Visible = m_currentGraphicsView->layerIsActive(ViewLayer::Copper0);
 
2064
                bool copper1Visible = m_currentGraphicsView->layerIsActive(ViewLayer::Copper1);
 
2065
                if (copper0Visible && copper1Visible) {
 
2066
                        return 0;
 
2067
                }
 
2068
                else if (copper1Visible) {
 
2069
                        return 2;
 
2070
                }
 
2071
                else if (copper0Visible) {
 
2072
                        return 1;
 
2073
                }
 
2074
        }
 
2075
 
 
2076
        return -1;
 
2077
}
 
2078
 
 
2079
bool MainWindow::activeLayerWidgetAlwaysOn() {
 
2080
        return false;
 
2081
}
 
2082
 
 
2083
/**
 
2084
 * A slot for saving a copy of the current sketch to a temp location.
 
2085
 * This should be called every X minutes as well as just before certain
 
2086
 * events, such as saves, part imports, file export/printing. This relies
 
2087
 * on the m_autosaveNeeded variable and the undoStack being dirty for
 
2088
 * an autosave to be attempted.
 
2089
 */
 
2090
void  MainWindow::backupSketch() {
 
2091
        if (ProcessEventBlocker::isProcessing()) {
 
2092
                // don't want to autosave during autorouting, for example
 
2093
                return;
 
2094
        }
 
2095
 
 
2096
    if (m_autosaveNeeded && !m_undoStack->isClean()) {
 
2097
        m_autosaveNeeded = false;                       // clear this now in case the save takes a really long time
 
2098
 
 
2099
        DebugDialog::debug(QString("%1 autosaved as %2").arg(m_fwFilename).arg(m_backupFileNameAndPath));
 
2100
        statusBar()->showMessage(tr("Backing up '%1'").arg(m_fwFilename), 2000);
 
2101
                ProcessEventBlocker::processEvents();
 
2102
                m_backingUp = true;
 
2103
                connectStartSave(true);
 
2104
                m_sketchModel->save(m_backupFileNameAndPath, false);
 
2105
                connectStartSave(false);
 
2106
                m_backingUp = false;
 
2107
    }
 
2108
}
 
2109
 
 
2110
/**
 
2111
 * This function is used to trigger an autosave at the next autosave
 
2112
 * timer event. It is connected to the QUndoStack::indexChanged(int)
 
2113
 * signal so that any change to the undo stack triggers autosaves.
 
2114
 * This function can be called independent of this signal and
 
2115
 * still work properly.
 
2116
 */
 
2117
void MainWindow::autosaveNeeded(int index) {
 
2118
    Q_UNUSED(index);
 
2119
    //DebugDialog::debug(QString("Triggering autosave"));
 
2120
    m_autosaveNeeded = true;
 
2121
}
 
2122
 
 
2123
/**
 
2124
 * delete the backup file when the undostack is clean.
 
2125
 */
 
2126
void MainWindow::undoStackCleanChanged(bool isClean) {
 
2127
    DebugDialog::debug(QString("Clean status changed to %1").arg(isClean));
 
2128
    if (isClean) {
 
2129
        QFile::remove(m_backupFileNameAndPath);
 
2130
    }
 
2131
}
 
2132
 
 
2133
void MainWindow::setAutosavePeriod(int minutes) {
 
2134
        setAutosave(minutes, AutosaveEnabled);
 
2135
}
 
2136
 
 
2137
void MainWindow::setAutosaveEnabled(bool enabled) {
 
2138
        setAutosave(AutosaveTimeoutMinutes, enabled);
 
2139
}
 
2140
 
 
2141
void MainWindow::setAutosave(int minutes, bool enabled) {
 
2142
        AutosaveTimeoutMinutes = minutes;
 
2143
        AutosaveEnabled = enabled;
 
2144
        foreach (QWidget * widget, QApplication::topLevelWidgets()) {
 
2145
                MainWindow * mainWindow = qobject_cast<MainWindow *>(widget);
 
2146
                if (mainWindow == NULL) continue;
 
2147
 
 
2148
                mainWindow->m_autosaveTimer.stop();
 
2149
                if (qobject_cast<PEMainWindow *>(widget)) {
 
2150
                        continue;
 
2151
                }
 
2152
 
 
2153
                if (AutosaveEnabled) {
 
2154
                        // is there a way to get the current timer offset so that all the timers aren't running in sync?
 
2155
                        // or just add some random time...
 
2156
                        mainWindow->m_autosaveTimer.start(AutosaveTimeoutMinutes * 60 * 1000);
 
2157
                }
 
2158
        }
 
2159
}
 
2160
 
 
2161
bool MainWindow::hasLinkedProgramFiles(const QString & filename, QStringList & linkedProgramFiles) 
 
2162
{
 
2163
        QFile file(filename);
 
2164
        file.open(QFile::ReadOnly);
 
2165
        QXmlStreamReader xml(&file);
 
2166
    xml.setNamespaceProcessing(false);
 
2167
 
 
2168
        bool done = false;
 
2169
        while (!xml.atEnd()) {
 
2170
        switch (xml.readNext()) {
 
2171
        case QXmlStreamReader::StartElement:
 
2172
                        if (xml.name().toString().compare("program") == 0) {
 
2173
                                linkedProgramFiles.append(xml.readElementText());
 
2174
                                break;
 
2175
                        }
 
2176
                        if (xml.name().toString().compare("views") == 0) {
 
2177
                                done = true;
 
2178
                                break;
 
2179
                        }
 
2180
                        if (xml.name().toString().compare("instances") == 0) {
 
2181
                                done = true;
 
2182
                                break;
 
2183
                        }
 
2184
                default:
 
2185
                        break;
 
2186
                }
 
2187
 
 
2188
                if (done) break;
 
2189
        }
 
2190
 
 
2191
        return linkedProgramFiles.count() > 0;
 
2192
}
 
2193
 
 
2194
QString MainWindow::getExtensionString() {
 
2195
        return tr("Fritzing (*%1)").arg(fileExtension());
 
2196
}
 
2197
 
 
2198
QStringList MainWindow::getExtensions() {
 
2199
        QStringList extensions;
 
2200
        extensions.append(fileExtension());
 
2201
        return extensions;
 
2202
}
 
2203
 
 
2204
void MainWindow::firstTimeHelpHidden() {
 
2205
        m_showInViewHelpAct->setChecked(false);
 
2206
}
 
2207
 
 
2208
void MainWindow::routingStatusLabelMousePress(QMouseEvent* event) {
 
2209
        routingStatusLabelMouse(event, true);
 
2210
}
 
2211
 
 
2212
void MainWindow::routingStatusLabelMouseRelease(QMouseEvent* event) {
 
2213
        routingStatusLabelMouse(event, false);
 
2214
}
 
2215
 
 
2216
void MainWindow::routingStatusLabelMouse(QMouseEvent*, bool show) {
 
2217
        if (show) DebugDialog::debug("-------");
 
2218
 
 
2219
        QSet<ConnectorItem *> toShow;
 
2220
        foreach (QGraphicsItem * item, m_currentGraphicsView->scene()->items()) {
 
2221
                VirtualWire * vw = dynamic_cast<VirtualWire *>(item);
 
2222
                if (vw == NULL) continue;
 
2223
 
 
2224
                foreach (ConnectorItem * connectorItem, vw->connector0()->connectedToItems()) {
 
2225
                        toShow.insert(connectorItem);
 
2226
                }
 
2227
                foreach (ConnectorItem * connectorItem, vw->connector1()->connectedToItems()) {
 
2228
                        toShow.insert(connectorItem);
 
2229
                }
 
2230
        }
 
2231
        foreach (ConnectorItem * connectorItem, toShow) {
 
2232
                if (show) {
 
2233
                        DebugDialog::debug(QString("unrouted %1 %2 %3 %4")
 
2234
                                .arg(connectorItem->attachedToInstanceTitle())
 
2235
                                .arg(connectorItem->attachedToID())
 
2236
                                .arg(connectorItem->attachedTo()->title())
 
2237
                                .arg(connectorItem->connectorSharedName()));
 
2238
                }
 
2239
 
 
2240
                if (connectorItem->isActive() && connectorItem->isVisible() && !connectorItem->hidden()) {
 
2241
                        connectorItem->showEqualPotential(show);
 
2242
                }
 
2243
                else {
 
2244
                        connectorItem = connectorItem->getCrossLayerConnectorItem();
 
2245
                        if (connectorItem) connectorItem->showEqualPotential(show);
 
2246
                }
 
2247
        }
 
2248
 
 
2249
    if (!show && toShow.count() == 0) {
 
2250
            QMessageBox::information(this, tr("Unrouted connections"), 
 
2251
            tr("There are no unrouted connections in this view."));
 
2252
    }
 
2253
}
 
2254
 
 
2255
void MainWindow::setReportMissingModules(bool b) {
 
2256
        if (m_sketchModel) {
 
2257
                m_sketchModel->setReportMissingModules(b);
 
2258
        }
 
2259
}
 
2260
 
 
2261
 
 
2262
 
 
2263
void MainWindow::boardDeletedSlot() 
 
2264
{
 
2265
        activeLayerBottom();
 
2266
}
 
2267
 
 
2268
void MainWindow::cursorLocationSlot(double xinches, double yinches)
 
2269
{
 
2270
        if (m_locationLabel) {
 
2271
                QString units;
 
2272
                double x, y;
 
2273
 
 
2274
                m_locationLabel->setProperty("location", QSizeF(xinches, xinches));
 
2275
 
 
2276
                if (m_locationLabelUnits.compare("mm") == 0) {
 
2277
                        units = "mm";
 
2278
                        x = xinches * 25.4;
 
2279
                        y = yinches * 25.4;
 
2280
                }
 
2281
                else if (m_locationLabelUnits.compare("px") == 0) {
 
2282
                        units = "px";
 
2283
                        x = xinches * GraphicsUtils::SVGDPI;
 
2284
                        y = yinches * GraphicsUtils::SVGDPI;
 
2285
                }
 
2286
                else {
 
2287
                        units = "in";
 
2288
                        x = xinches;
 
2289
                        y = yinches;
 
2290
                }
 
2291
 
 
2292
                m_locationLabel->setText(tr("%1 %2 %3")
 
2293
                        .arg(x, 0, 'f', 3)
 
2294
                        .arg(y, 0, 'f', 3)
 
2295
                        .arg(units) );
 
2296
        }
 
2297
}
 
2298
 
 
2299
void MainWindow::locationLabelClicked()
 
2300
{
 
2301
        if (m_locationLabelUnits.compare("mm") == 0) {
 
2302
                m_locationLabelUnits = "px";
 
2303
        }
 
2304
        else if (m_locationLabelUnits.compare("px") == 0) {
 
2305
                m_locationLabelUnits = "in";
 
2306
        }
 
2307
        else if (m_locationLabelUnits.compare("in") == 0) {
 
2308
                m_locationLabelUnits = "mm";
 
2309
        }
 
2310
        else {
 
2311
                m_locationLabelUnits = "in";
 
2312
        }
 
2313
 
 
2314
        if (m_locationLabel) {
 
2315
                QVariant variant =  m_locationLabel->property("location");
 
2316
                if (variant.isValid()) {
 
2317
                        QSizeF size = variant.toSizeF();
 
2318
                        cursorLocationSlot(size.width(), size.height());
 
2319
                }
 
2320
                else {
 
2321
                        cursorLocationSlot(0, 0);
 
2322
                }
 
2323
        }
 
2324
                
 
2325
        QSettings settings;
 
2326
        settings.setValue("LocationInches", QVariant(m_locationLabelUnits));
 
2327
}
 
2328
 
 
2329
void MainWindow::filenameIfSlot(QString & filename)
 
2330
{
 
2331
        filename = QFileInfo(fileName()).fileName();
 
2332
}
 
2333
 
 
2334
QList<SketchWidget *> MainWindow::sketchWidgets() 
 
2335
{
 
2336
        QList<SketchWidget *> list;
 
2337
        list << m_breadboardGraphicsView << m_schematicGraphicsView << m_pcbGraphicsView;
 
2338
        return list;
 
2339
}
 
2340
 
 
2341
void MainWindow::setCloseSilently(bool cs)
 
2342
{
 
2343
        m_closeSilently = cs;
 
2344
}
 
2345
 
 
2346
PCBSketchWidget * MainWindow::pcbView() {
 
2347
        return m_pcbGraphicsView;
 
2348
}
 
2349
 
 
2350
void MainWindow::noBackup()
 
2351
{
 
2352
        m_autosaveTimer.stop();
 
2353
}
 
2354
 
 
2355
void MainWindow::hideTempPartsBin() {
 
2356
        if (m_binManager) m_binManager->hideTempPartsBin();
 
2357
}
 
2358
 
 
2359
void MainWindow::setActiveWire(Wire * wire) {
 
2360
        m_activeWire = wire;
 
2361
}
 
2362
 
 
2363
void MainWindow::setActiveConnectorItem(ConnectorItem * connectorItem) {
 
2364
        m_activeConnectorItem = connectorItem;
 
2365
}
 
2366
 
 
2367
const QString & MainWindow::fritzingVersion() {
 
2368
        if (m_sketchModel) return m_sketchModel->fritzingVersion();
 
2369
 
 
2370
        return ___emptyString___;
 
2371
}
 
2372
 
 
2373
 
 
2374
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
 
2375
{
 
2376
    const QMimeData* mimeData = event->mimeData();
 
2377
 
 
2378
    if (mimeData->hasUrls()) {
 
2379
        QStringList pathList;
 
2380
        QList<QUrl> urlList = mimeData->urls();
 
2381
 
 
2382
        // extract the local paths of the files
 
2383
        for (int i = 0; i < urlList.size() && i < 32; ++i) {
 
2384
            QString fn = urlList.at(i).toLocalFile();
 
2385
            foreach (QString ext, fritzingExtensions()) {
 
2386
                if (fn.endsWith(ext)) {
 
2387
                    event->acceptProposedAction();
 
2388
                    return;
 
2389
                }
 
2390
            }
 
2391
        }
 
2392
    }
 
2393
}
 
2394
 
 
2395
void MainWindow::dropEvent(QDropEvent *event)
 
2396
{
 
2397
    const QMimeData* mimeData = event->mimeData();
 
2398
 
 
2399
    if (mimeData->hasUrls()) {
 
2400
        QStringList pathList;
 
2401
        QList<QUrl> urlList = mimeData->urls();
 
2402
 
 
2403
        // extract the local paths of the files
 
2404
        for (int i = 0; i < urlList.size() && i < 32; ++i) {
 
2405
            mainLoadAux(urlList.at(i).toLocalFile());
 
2406
        }
 
2407
    }
 
2408
}
 
2409
 
 
2410
bool MainWindow::hasAnyAlien() {
 
2411
    return m_addedToTemp;
 
2412
}
 
2413
 
 
2414
void MainWindow::initStyleSheet() 
 
2415
{
 
2416
    QString suffix = getStyleSheetSuffix();
 
2417
        QFile styleSheet(QString(":/resources/styles/%1.qss").arg(suffix));
 
2418
    if (!styleSheet.open(QIODevice::ReadOnly)) {
 
2419
                DebugDialog::debug(QString("Unable to open :/resources/styles/%1.qss").arg(suffix));
 
2420
        } else {
 
2421
                QString platformDependantStyle = "";
 
2422
                QString platformDependantStylePath;
 
2423
#ifdef Q_WS_X11
 
2424
                if(style()->metaObject()->className()==QString("OxygenStyle")) {
 
2425
                        QFile oxygenStyleSheet(QString(":/resources/styles/linux-kde-oxygen-%1.qss").arg(suffix));
 
2426
                        if(oxygenStyleSheet.open(QIODevice::ReadOnly)) {
 
2427
                                platformDependantStyle += oxygenStyleSheet.readAll();
 
2428
                        }
 
2429
                }
 
2430
                platformDependantStylePath = QString(":/resources/styles/linux-%1.qss").arg(suffix);
 
2431
#endif
 
2432
 
 
2433
#ifdef Q_WS_MAC
 
2434
                platformDependantStylePath = QString(":/resources/styles/mac-%1.qss").arg(suffix);
 
2435
#endif
 
2436
 
 
2437
#ifdef Q_WS_WIN
 
2438
                platformDependantStylePath = QString(":/resources/styles/win-%1.qss").arg(suffix);
 
2439
#endif
 
2440
 
 
2441
                QFile platformDependantStyleSheet(platformDependantStylePath);
 
2442
                if(platformDependantStyleSheet.open(QIODevice::ReadOnly)) {
 
2443
                        platformDependantStyle += platformDependantStyleSheet.readAll();
 
2444
                }
 
2445
                setStyleSheet(styleSheet.readAll()+platformDependantStyle);
 
2446
        }
 
2447
}
 
2448
 
 
2449
QString MainWindow::getStyleSheetSuffix() {
 
2450
    return "fritzing";
 
2451
}
 
2452
 
 
2453
void MainWindow::addToMyParts(ModelPart * modelPart)
 
2454
{
 
2455
    if (modelPart != NULL) m_binManager->addToMyParts(modelPart);
 
2456
}
 
2457
 
 
2458
bool MainWindow::usesPart(const QString & moduleID) {
 
2459
    if (m_currentGraphicsView == NULL) return false;
 
2460
 
 
2461
    foreach (QGraphicsItem * item, m_currentGraphicsView->scene()->items()) {
 
2462
        ItemBase * itemBase = dynamic_cast<ItemBase *>(item);
 
2463
        if (itemBase != NULL && itemBase->moduleID().compare(moduleID) == 0) {
 
2464
            return true;
 
2465
        }
 
2466
    }
 
2467
 
 
2468
    return false;
 
2469
}
 
2470
 
 
2471
bool MainWindow::updateParts(const QString & moduleID, QUndoCommand * parentCommand) {
 
2472
    if (m_currentGraphicsView == NULL) return false;
 
2473
 
 
2474
    QSet<ItemBase *> itemBases;
 
2475
    foreach (QGraphicsItem * item, m_currentGraphicsView->scene()->items()) {
 
2476
        ItemBase * itemBase = dynamic_cast<ItemBase *>(item);
 
2477
        if (itemBase == NULL) continue;       
 
2478
        if (itemBase->moduleID().compare(moduleID) != 0) continue;
 
2479
 
 
2480
        itemBases.insert(itemBase->layerKinChief());
 
2481
    }
 
2482
 
 
2483
    foreach (ItemBase * itemBase, itemBases) {
 
2484
        swapSelectedAuxAux(itemBase, moduleID, itemBase->viewLayerSpec(), parentCommand);
 
2485
    }
 
2486
 
 
2487
    return true;
 
2488
}
 
2489
 
 
2490
void MainWindow::showStatusMessage(const QString & message)
 
2491
{
 
2492
    if (sender() == m_statusBar) {
 
2493
        return;
 
2494
    }
 
2495
 
 
2496
    if (message == m_statusBar->currentMessage()) {
 
2497
        return;
 
2498
    }
 
2499
 
 
2500
    //DebugDialog::debug("show message " + message);
 
2501
    m_statusBar->blockSignals(true);
 
2502
    m_statusBar->showMessage(message);
 
2503
    m_statusBar->blockSignals(false);
 
2504
}
 
2505
 
 
2506
void MainWindow::updatePartsBin(const QString & moduleID) {
 
2507
        m_binManager->reloadPart(moduleID);
 
2508
}
 
2509
 
 
2510
bool MainWindow::hasCustomBoardShape() {
 
2511
        if (m_pcbGraphicsView == NULL) return false;
 
2512
 
 
2513
        return m_pcbGraphicsView->hasCustomBoardShape();
 
2514
}
 
2515