1
/*******************************************************************
3
Part of the Fritzing project - http://fritzing.org
4
Copyright (c) 2007-2012 Fachhochschule Potsdam - http://fh-potsdam.de
6
Fritzing is free software: you can redistribute it and/or modify
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.
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.
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/>.
20
********************************************************************
23
$Author: irascibl@gmail.com $:
24
$Date: 2012-10-16 05:51:14 +0200 (Tue, 16 Oct 2012) $
26
********************************************************************/
32
#include <QStringList>
33
#include <QFileInfoList>
39
#include <QPaintDevice>
42
#include <QStackedWidget>
43
#include <QXmlStreamReader>
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"
92
///////////////////////////////////////////////
94
#define ZIP_PART QString("part.")
95
#define ZIP_SVG QString("svg.")
97
///////////////////////////////////////////////
99
// SwapTimer explained: http://code.google.com/p/fritzing/issues/detail?id=1431
101
SwapTimer::SwapTimer() : QTimer()
105
void SwapTimer::setAll(const QString & family, const QString & prop, QMap<QString, QString> & propsMap, ItemBase * itemBase)
109
m_propsMap = propsMap;
110
m_itemBase = itemBase;
113
const QString & SwapTimer::family()
118
const QString & SwapTimer::prop()
123
QMap<QString, QString> SwapTimer::propsMap()
128
ItemBase * SwapTimer::itemBase()
133
///////////////////////////////////////////////
135
const QString MainWindow::UntitledSketchName = "Untitled Sketch";
136
int MainWindow::UntitledSketchIndex = 1;
137
int MainWindow::CascadeFactorX = 21;
138
int MainWindow::CascadeFactorY = 19;
140
static const int MainWindowDefaultWidth = 840;
141
static const int MainWindowDefaultHeight = 600;
143
int MainWindow::AutosaveTimeoutMinutes = 10; // in minutes
144
bool MainWindow::AutosaveEnabled = true;
145
QString MainWindow::BackupFolder;
147
/////////////////////////////////////////////
149
MainWindow::MainWindow(ReferenceModel *referenceModel, QWidget * parent) :
150
FritzingWindow(untitledFileName(), untitledFileCount(), fileExtension(), parent)
152
setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
153
setDockOptions(QMainWindow::AnimatedDocks);
154
m_sizeGrip = new FSizeGrip(this);
158
m_dontKeepMargins = true;
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;
165
m_addedToTemp = false;
166
setAcceptDrops(true);
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()));
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;
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);
192
resize(MainWindowDefaultWidth, MainWindowDefaultHeight);
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)));
200
m_dotIcon = QIcon(":/resources/images/dot.png");
201
m_emptyIcon = QIcon();
203
m_currentWidget = NULL;
206
m_statusBar = new QStatusBar(this);
207
setStatusBar(m_statusBar);
208
m_statusBar->setSizeGripEnabled(false);
211
m_locationLabelUnits = settings.value("LocationInches", "in").toString();
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();
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);
221
m_zoomSlider = new ZoomSlider(m_statusBar);
222
connect(m_zoomSlider, SIGNAL(zoomChanged(double)), this, SLOT(updateViewZoom(double)));
223
m_statusBar->addPermanentWidget(m_zoomSlider);
226
setAttribute(Qt::WA_DeleteOnClose, true);
229
//setAttribute(Qt::WA_QuitOnClose, false); // restoring this temporarily (2008.12.19)
231
m_dontClose = m_closing = false;
233
m_referenceModel = referenceModel;
234
m_sketchModel = new SketchModel(true);
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()));
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()));
251
shortcut = new QShortcut(QKeySequence(tr("Shift+Ctrl+Tab", "Toggle Active Layer")), this);
252
connect(shortcut, SIGNAL(activated()), this, SLOT(toggleActiveLayer()));
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);
262
QWidget * MainWindow::createTabWidget() {
263
return new QStackedWidget(this);
266
void MainWindow::addTab(QWidget * widget, const QString & label) {
268
qobject_cast<QStackedWidget *>(m_tabWidget)->addWidget(widget);
271
int MainWindow::currentTabIndex() {
272
return qobject_cast<QStackedWidget *>(m_tabWidget)->currentIndex();
275
void MainWindow::setCurrentTabIndex(int index) {
276
qobject_cast<QStackedWidget *>(m_tabWidget)->setCurrentIndex(index);
279
QWidget * MainWindow::currentTabWidget() {
280
return qobject_cast<QStackedWidget *>(m_tabWidget)->currentWidget();
283
void MainWindow::init(ReferenceModel *referenceModel, bool lockFiles) {
285
m_tabWidget = createTabWidget(); // FTabWidget(this);
286
m_tabWidget->setObjectName("sketch_tabs");
287
setCentralWidget(m_tabWidget);
289
m_referenceModel = referenceModel;
290
m_restarting = false;
292
if (m_fileProgressDialog) {
293
m_fileProgressDialog->setValue(2);
296
initLockedFiles(lockFiles);
300
m_undoView = new QUndoView();
301
m_undoGroup = new QUndoGroup(this);
302
m_undoView->setGroup(m_undoGroup);
303
m_undoGroup->setActiveStack(m_undoStack);
309
createZoomOptions(m_breadboardWidget);
310
createZoomOptions(m_schematicWidget);
311
createZoomOptions(m_pcbWidget);
313
m_breadboardWidget->setToolbarWidgets(getButtonsForView(ViewLayer::BreadboardView));
314
m_schematicWidget->setToolbarWidgets(getButtonsForView(ViewLayer::SchematicView));
315
m_pcbWidget->setToolbarWidgets(getButtonsForView(ViewLayer::PCBView));
319
m_breadboardGraphicsView->setItemMenu(breadboardItemMenu());
320
m_breadboardGraphicsView->setWireMenu(breadboardWireMenu());
322
m_pcbGraphicsView->setWireMenu(pcbWireMenu());
323
m_pcbGraphicsView->setItemMenu(pcbItemMenu());
325
m_schematicGraphicsView->setItemMenu(schematicItemMenu());
326
m_schematicGraphicsView->setWireMenu(schematicWireMenu());
329
m_breadboardGraphicsView->setInfoView(m_infoView);
330
m_pcbGraphicsView->setInfoView(m_infoView);
331
m_schematicGraphicsView->setInfoView(m_infoView);
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 )));
341
// do this the first time, since the current_changed signal wasn't sent
343
if (m_navigators.count() > 0) {
344
currentNavigatorChanged(m_navigators[tab]);
346
tabWidget_currentChanged(tab+1);
347
tabWidget_currentChanged(tab);
349
this->installEventFilter(this);
351
if (m_fileProgressDialog) {
352
m_fileProgressDialog->setValue(95);
356
if (m_viewSwitcherDock) {
357
m_viewSwitcherDock->prestorePreference();
359
if(!settings.value(m_settingsPrefix + "state").isNull()) {
360
restoreState(settings.value(m_settingsPrefix + "state").toByteArray());
361
restoreGeometry(settings.value(m_settingsPrefix + "geometry").toByteArray());
363
if (m_viewSwitcherDock) {
364
m_viewSwitcherDock->restorePreference();
365
m_viewSwitcherDock->setViewSwitcher(m_viewSwitcher);
369
m_tabWidget->setMinimumWidth(500);
370
m_tabWidget->setMinimumWidth(0);
372
if (m_miniViewContainerBreadboard) {
373
m_miniViewContainerBreadboard->setView(m_breadboardGraphicsView);
374
m_miniViewContainerSchematic->setView(m_schematicGraphicsView);
375
m_miniViewContainerPCB->setView(m_pcbGraphicsView);
378
connect(this, SIGNAL(readOnlyChanged(bool)), this, SLOT(applyReadOnlyChange(bool)));
380
m_setUpDockManagerTimer.setSingleShot(true);
381
connect(&m_setUpDockManagerTimer, SIGNAL(timeout()), this, SLOT(keepMargins()));
382
m_setUpDockManagerTimer.start(1000);
384
if (m_fileProgressDialog) {
385
m_fileProgressDialog->setValue(98);
390
MainWindow::~MainWindow()
392
// Delete backup of this sketch if one exists.
393
QFile::remove(m_backupFileNameAndPath);
395
delete m_sketchModel;
398
m_setUpDockManagerTimer.stop();
400
foreach (LinkedFile * linkedFile, m_linkedProgramFiles) {
403
m_linkedProgramFiles.clear();
405
if (!m_fzzFolder.isEmpty()) {
406
LockManager::releaseLockedFiles(m_fzzFolder, m_fzzFiles);
407
FolderUtils::rmdir(m_fzzFolder);
411
void MainWindow::initHelper() {
412
m_helper = new Helper(this, true);
415
void MainWindow::initLockedFiles(bool lockFiles) {
416
LockManager::initLockedFiles("fzz", m_fzzFolder, m_fzzFiles, lockFiles ? LockManager::SlowTime : 0);
418
QFileInfoList backupList;
419
LockManager::checkLockedFiles("fzz", backupList, m_fzzFiles, true, LockManager::SlowTime);
423
void MainWindow::initSketchWidgets() {
424
//DebugDialog::debug("init sketch widgets");
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"));
432
if (m_fileProgressDialog) {
433
m_fileProgressDialog->setValue(11);
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"));
441
if (m_fileProgressDialog) {
442
m_fileProgressDialog->setValue(20);
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"));
450
if (m_fileProgressDialog) {
451
m_fileProgressDialog->setValue(29);
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");
464
//DebugDialog::debug("create menus");
469
//DebugDialog::debug("create toolbars");
473
//DebugDialog::debug("after creating status bar");
475
if (m_fileProgressDialog) {
476
m_fileProgressDialog->setValue(91);
483
void MainWindow::showNavigator() {
484
m_navigatorDock->setFloating(false);
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();
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);
504
connect(m_pcbGraphicsView, SIGNAL(groundFillSignal()), this, SLOT(groundFill()));
505
connect(m_pcbGraphicsView, SIGNAL(copperFillSignal()), this, SLOT(copperFill()));
507
connect(m_pcbGraphicsView, SIGNAL(swapBoardImageSignal(SketchWidget *, ItemBase *, const QString &, const QString &, bool)),
508
this, SLOT(swapBoardImageSlot(SketchWidget *, ItemBase *, const QString &, const QString &, bool)));
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 *)));
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 *)));
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 &)));
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 *)));
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 *)));
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);
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()));
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 )));
551
succeeded = succeeded && connect(m_pcbGraphicsView, SIGNAL(boardDeletedSignal()), this, SLOT(boardDeletedSlot()));
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)));
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)));
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);
566
DebugDialog::debug("connectPair failed");
570
void MainWindow::connectPair(SketchWidget * signaller, SketchWidget * slotter)
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 *)));
576
succeeded = succeeded && connect(signaller, SIGNAL(itemDeletedSignal(long)),
577
slotter, SLOT(itemDeletedSlot(long)),
578
Qt::DirectConnection);
580
succeeded = succeeded && connect(signaller, SIGNAL(clearSelectionSignal()),
581
slotter, SLOT(clearSelectionSlot()));
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);
597
succeeded = succeeded && connect(signaller, SIGNAL(cleanUpWiresSignal(CleanUpWiresCommand *)),
598
slotter, SLOT(cleanUpWiresSlot(CleanUpWiresCommand *)) );
600
succeeded = succeeded && connect(signaller, SIGNAL(checkStickySignal(long, bool, bool, CheckStickyCommand *)),
601
slotter, SLOT(checkSticky(long, bool, bool, CheckStickyCommand *)) );
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 * )));
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)));
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 )));
619
succeeded = succeeded && connect(signaller, SIGNAL(setVoltageSignal(double, bool )),
620
slotter, SLOT(setVoltage(double, bool )));
622
succeeded = succeeded && connect(signaller, SIGNAL(showLabelFirstTimeSignal(long, bool, bool )),
623
slotter, SLOT(showLabelFirstTime(long, bool, bool )));
625
succeeded = succeeded && connect(signaller, SIGNAL(changeBoardLayersSignal(int, bool )),
626
slotter, SLOT(changeBoardLayers(int, bool )));
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);
632
succeeded = succeeded && connect(signaller, SIGNAL(ratsnestConnectSignal(long, const QString &, bool, bool)),
633
slotter, SLOT(ratsnestConnect(long, const QString &, bool, bool )),
634
Qt::DirectConnection);
637
succeeded = succeeded && connect(signaller, SIGNAL(updatePartLabelInstanceTitleSignal(long)),
638
slotter, SLOT(updatePartLabelInstanceTitleSlot(long)));
640
succeeded = succeeded && connect(signaller, SIGNAL(changePinLabelsSignal(ItemBase *, bool)),
641
slotter, SLOT(changePinLabelsSlot(ItemBase *, bool)));
643
succeeded = succeeded && connect(signaller, SIGNAL(collectRatsnestSignal(QList<SketchWidget *> &)),
644
slotter, SLOT(collectRatsnestSlot(QList<SketchWidget *> &)),
645
Qt::DirectConnection);
647
succeeded = succeeded && connect(signaller, SIGNAL(removeRatsnestSignal(QList<struct ConnectorEdge *> &, QUndoCommand *)),
648
slotter, SLOT(removeRatsnestSlot(QList<struct ConnectorEdge *> &, QUndoCommand *)),
649
Qt::DirectConnection);
651
succeeded = succeeded && connect(signaller, SIGNAL(canConnectSignal(Wire *, ItemBase *, bool &)),
652
slotter, SLOT(canConnect(Wire *, ItemBase *, bool &)),
653
Qt::DirectConnection);
655
succeeded = succeeded && connect(signaller, SIGNAL(swapStartSignal(SwapThing &, bool)),
656
slotter, SLOT(swapStart(SwapThing &, bool)),
657
Qt::DirectConnection);
660
DebugDialog::debug("connectPair failed");
665
void MainWindow::setCurrentFile(const QString &filename, bool addToRecent, bool setAsLastOpened) {
666
setFileName(filename);
668
if(setAsLastOpened) {
670
settings.setValue("lastOpenSketch",filename);
673
updateRaiseWindowAction();
678
QStringList files = settings.value("recentFileList").toStringList();
679
files.removeAll(filename);
680
files.prepend(filename);
681
while (files.size() > MaxRecentFiles)
684
settings.setValue("recentFileList", files);
687
foreach (QWidget *widget, QApplication::topLevelWidgets()) {
688
MainWindow *mainWin = qobject_cast<MainWindow *>(widget);
690
mainWin->updateRecentFileActions();
695
void MainWindow::createZoomOptions(SketchAreaWidget* parent) {
697
connect(parent->contentView(), SIGNAL(zoomChanged(double)), this, SLOT(updateZoomSlider(double)));
698
connect(parent->contentView(), SIGNAL(zoomOutOfRange(double)), this, SLOT(updateZoomOptionsNoMatterWhat(double)));
701
ExpandingLabel * MainWindow::createRoutingStatusLabel(SketchAreaWidget * parent) {
702
ExpandingLabel * routingStatusLabel = new ExpandingLabel(m_pcbWidget);
704
connect(routingStatusLabel, SIGNAL(mousePressSignal(QMouseEvent*)), this, SLOT(routingStatusLabelMousePress(QMouseEvent*)));
705
connect(routingStatusLabel, SIGNAL(mouseReleaseSignal(QMouseEvent*)), this, SLOT(routingStatusLabelMouseRelease(QMouseEvent*)));
707
routingStatusLabel->setTextInteractionFlags(Qt::NoTextInteraction);
708
routingStatusLabel->setCursor(Qt::WhatsThisCursor);
709
routingStatusLabel->viewport()->setCursor(Qt::WhatsThisCursor);
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;
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"));
726
m_rotateButtons << rotateButton;
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
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"));
743
m_flipButtons << flipButton;
747
SketchToolButton *MainWindow::createAutorouteButton(SketchAreaWidget *parent) {
748
SketchToolButton *autorouteButton = new SketchToolButton("Autoroute",parent, m_autorouteAct);
749
autorouteButton->setText(tr("Autoroute"));
751
return autorouteButton;
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
759
return orderFabButton;
762
QWidget *MainWindow::createActiveLayerButton(SketchAreaWidget *parent)
764
QList<QAction *> actions;
765
actions << m_activeLayerBothAct << m_activeLayerBottomAct << m_activeLayerTopAct;
767
m_activeLayerButtonWidget = new QStackedWidget;
768
m_activeLayerButtonWidget->setMaximumWidth(90);
770
SketchToolButton * button = new SketchToolButton("ActiveLayer", parent, actions);
771
button->setDefaultAction(m_activeLayerBottomAct);
772
button->setText(tr("Both Layers"));
773
m_activeLayerButtonWidget->addWidget(button);
775
button = new SketchToolButton("ActiveLayerB", parent, actions);
776
button->setDefaultAction(m_activeLayerTopAct);
777
button->setText(tr("Bottom Layer"));
778
m_activeLayerButtonWidget->addWidget(button);
780
button = new SketchToolButton("ActiveLayerT", parent, actions);
781
button->setDefaultAction(m_activeLayerBothAct);
782
button->setText(tr("Top Layer"));
783
m_activeLayerButtonWidget->addWidget(button);
785
return m_activeLayerButtonWidget;
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
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;
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));
810
return toolbarSpacer;
813
QList<QWidget*> MainWindow::getButtonsForView(ViewLayer::ViewIdentifier viewId) {
814
QList<QWidget*> retval;
815
SketchAreaWidget *parent;
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;
822
retval << createShareButton(parent);
825
case ViewLayer::BreadboardView:
826
case ViewLayer::SchematicView:
827
retval << createNoteButton(parent);
832
retval << createRotateButton(parent);
834
case ViewLayer::BreadboardView:
835
retval << createFlipButton(parent);
837
case ViewLayer::SchematicView:
838
retval << createFlipButton(parent) << createToolbarSpacer(parent) << createAutorouteButton(parent);
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);
853
retval << createRoutingStatusLabel(parent);
857
void MainWindow::updateZoomSlider(double zoom) {
858
m_zoomSlider->setValue(zoom);
861
SketchAreaWidget *MainWindow::currentSketchArea() {
862
return dynamic_cast<SketchAreaWidget*>(m_currentGraphicsView->parent());
865
void MainWindow::updateZoomOptionsNoMatterWhat(double zoom) {
866
m_zoomSlider->setValue(zoom);
869
void MainWindow::updateViewZoom(double newZoom) {
870
m_comboboxChanged = true;
871
if(m_currentGraphicsView) m_currentGraphicsView->absoluteZoom(newZoom);
875
void MainWindow::createStatusBar()
877
m_statusBar->showMessage(tr("Ready"));
880
void MainWindow::tabWidget_currentChanged(int index) {
881
SketchAreaWidget * widgetParent = dynamic_cast<SketchAreaWidget *>(currentTabWidget());
882
if (widgetParent == NULL) return;
884
m_currentWidget = widgetParent;
886
if (m_locationLabel) {
887
m_locationLabel->setText("");
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();
895
if (m_breadboardGraphicsView) m_breadboardGraphicsView->setCurrent(false);
896
if (m_schematicGraphicsView) m_schematicGraphicsView->setCurrent(false);
897
if (m_pcbGraphicsView) m_pcbGraphicsView->setCurrent(false);
899
SketchWidget *widget = qobject_cast<SketchWidget *>(widgetParent->contentView());
901
if(m_currentGraphicsView) {
902
m_currentGraphicsView->saveZoom(m_zoomSlider->value());
904
m_currentGraphicsView,
905
SIGNAL(selectionChangedSignal()),
907
SLOT(updateTransformationActions())
910
m_currentGraphicsView = widget;
911
if (widget == NULL) return;
913
m_zoomSlider->setValue(m_currentGraphicsView->retrieveZoom());
916
m_currentGraphicsView, // don't connect directly to the scene here, connect to the widget's signal
917
SIGNAL(selectionChangedSignal()),
919
SLOT(updateTransformationActions())
922
updateActiveLayerButtons();
924
m_currentGraphicsView->setCurrent(true);
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()) {
934
updateLayerMenu(true);
935
if (m_showBreadboardAct) {
936
QList<QAction *> actions;
937
actions << m_showBreadboardAct << m_showSchematicAct << m_showPCBAct;
938
setActionsIcons(index, actions);
943
updateTransformationActions();
947
// triggers a signal to the navigator widget
948
if (m_navigators.count() > index) {
949
m_navigators[index]->miniViewMousePressedSlot();
951
emit viewSwitched(index);
953
if (m_showInViewHelpAct) {
954
if (m_helper == NULL) {
955
m_showInViewHelpAct->setChecked(false);
958
m_showInViewHelpAct->setChecked(m_helper->helpVisible(currentTabIndex()));
963
m_currentGraphicsView->updateInfoView();
966
// update issue with 4.5.1?: is this still valid (4.6.x?)
967
m_currentGraphicsView->updateConnectors();
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);
977
void MainWindow::closeEvent(QCloseEvent *event) {
983
if (m_programWindow) {
984
m_programWindow->close();
985
if (m_programWindow->isVisible()) {
991
if (!m_closeSilently) {
992
bool whatWithAliens = whatToDoWithAlienFiles();
994
if(!beforeClosing(true, discard) || !whatWithAliens ||!m_binManager->beforeClosing()) {
999
if(whatWithAliens && m_binManager->hasAlienParts()) {
1000
m_binManager->createIfMyPartsNotExists();
1004
//DebugDialog::debug(QString("top level windows: %1").arg(QApplication::topLevelWidgets().size()));
1006
foreach (QWidget * widget, QApplication::topLevelWidgets()) {
1007
QMenu * menu = qobject_cast<QMenu *>(widget);
1009
continue; // QMenus are always top level widgets, even if they have parents...
1011
DebugDialog::debug(QString("top level widget %1 %2 %3")
1012
.arg(widget->metaObject()->className())
1013
.arg(widget->windowTitle())
1014
.arg(widget->toolTip())
1022
foreach (QWidget *widget, QApplication::topLevelWidgets()) {
1023
if (widget == this) continue;
1024
if (qobject_cast<QMainWindow *>(widget) == NULL) continue;
1030
DebugDialog::closeDebug();
1034
settings.setValue(m_settingsPrefix + "state",saveState());
1035
settings.setValue(m_settingsPrefix + "geometry",saveGeometry());
1037
QMainWindow::closeEvent(event);
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()),
1045
.arg(QFileInfo(m_fwFilename).baseName()),
1046
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
1047
// TODO: translate button text
1048
if (reply == QMessageBox::Yes) {
1050
} else if (reply == QMessageBox::No) {
1051
foreach(QString pathToRemove, m_alienFiles) {
1052
QFile::remove(pathToRemove);
1054
m_alienFiles.clear();
1055
recoverBackupedFiles();
1057
emit alienPartsDismissed();
1068
void MainWindow::acceptAlienFiles() {
1069
m_alienFiles.clear();
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))
1078
//DebugDialog::debug(QString("event filter %1").arg(event->type()) );
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();
1089
return QMainWindow::eventFilter(object, event);
1092
const QString MainWindow::untitledFileName() {
1093
return UntitledSketchName;
1096
int &MainWindow::untitledFileCount() {
1097
return UntitledSketchIndex;
1100
const QString MainWindow::fileExtension() {
1101
return FritzingBundleExtension;
1104
const QString MainWindow::defaultSaveFolder() {
1105
return FolderUtils::openSaveFolder();
1108
bool MainWindow::undoStackIsEmpty() {
1109
return m_undoStack->count() == 0;
1112
void MainWindow::setInfoViewOnHover(bool infoViewOnHover) {
1113
m_breadboardGraphicsView->setInfoViewOnHover(infoViewOnHover);
1114
m_schematicGraphicsView->setInfoViewOnHover(infoViewOnHover);
1115
m_pcbGraphicsView->setInfoViewOnHover(infoViewOnHover);
1117
m_binManager->setInfoViewOnHover(infoViewOnHover);
1120
void MainWindow::loadBundledSketch(const QString &fileName, bool addToRecent, bool setAsLastOpened) {
1122
if(!FolderUtils::unzipTo(fileName, m_fzzFolder)) {
1123
QMessageBox::warning(
1126
tr("Unable to open '%1'").arg(fileName)
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);
1137
QStringList namefilters;
1138
namefilters << "*"+FritzingSketchExtension;
1139
QFileInfoList entryInfoList = dir.entryInfoList(namefilters);
1140
if (entryInfoList.count() == 0) {
1141
QMessageBox::warning(
1144
tr("No Sketch found in '%1'").arg(fileName)
1150
QFileInfo sketchInfo = entryInfoList[0];
1152
QString sketchName = dir.absoluteFilePath(sketchInfo.fileName());
1154
namefilters.clear();
1155
namefilters << "*" + FritzingPartExtension;
1156
entryInfoList = dir.entryInfoList(namefilters);
1157
QRegExp moduleIDFinder("moduleId=\"([^\"]+)");
1159
namefilters.clear();
1160
namefilters << "*.svg";
1161
QFileInfoList svgEntryInfoList = dir.entryInfoList(namefilters);
1163
m_addedToTemp = false;
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()));
1173
// TODO: could be more efficient by using a streamreader
1174
QString fzp = file.readAll();
1176
int ix = fzp.indexOf(moduleIDFinder);
1178
DebugDialog::debug(QString("unable to find module id in %1: %2").arg(file.fileName()).arg(fzp));
1182
QString moduleID = moduleIDFinder.cap(1);
1183
ModelPart * mp = m_referenceModel->retrieveModelPart(moduleID);
1186
if (!doc.setContent(fzp)) {
1187
DebugDialog::debug(QString("unable to parse fzp in %1: %2").arg(file.fileName()).arg(fzp));
1192
mp = copyToPartsFolder(fzpInfo, false, false, PartFactory::folderPath(), "contrib");
1194
DebugDialog::debug(QString("unable to create model part in %1: %2").arg(file.fileName()).arg(fzp));
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);
1215
view = view.nextSiblingElement();
1221
m_binManager->addToTempPartsBin(mp);
1222
m_addedToTemp = true;
1225
if (!m_addedToTemp) {
1226
m_binManager->hideTempPartsBin();
1229
// the bundled itself
1230
this->mainLoad(sketchName, "");
1231
setCurrentFile(fileName, addToRecent, setAsLastOpened);
1234
void MainWindow::loadBundledNonAtomicEntity(const QString &fileName, Bundler* bundler, bool addToBin, bool dontAsk) {
1235
QDir destFolder = QDir::temp();
1237
FolderUtils::createFolderAnCdIntoIt(destFolder, FolderUtils::getRandText());
1238
QString unzipDirPath = destFolder.path();
1240
if(!FolderUtils::unzipTo(fileName, unzipDirPath)) {
1241
QMessageBox::warning(
1244
tr("Unable to open shareable %1").arg(fileName)
1247
// gotta return now, or loadBundledSketchAux will crash
1251
QDir unzipDir(unzipDirPath);
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);
1259
FolderUtils::rmdir(unzipDirPath);
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));
1274
ModelPart* MainWindow::loadBundledPart(const QString &fileName, bool addToBin) {
1275
QDir destFolder = QDir::temp();
1277
FolderUtils::createFolderAnCdIntoIt(destFolder, FolderUtils::getRandText());
1278
QString unzipDirPath = destFolder.path();
1280
if(!FolderUtils::unzipTo(fileName, unzipDirPath)) {
1281
QMessageBox::warning(
1284
tr("Unable to open shareable part %1").arg(fileName)
1289
QDir unzipDir(unzipDirPath);
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(
1297
tr("Unable to read shareable part %1").arg(fileName)
1302
FolderUtils::rmdir(unzipDirPath);
1307
void MainWindow::saveBundledPart(const QString &moduleId) {
1308
QString modIdToExport;
1311
if(moduleId.isEmpty()) {
1312
if (m_currentGraphicsView == NULL) return;
1313
PaletteItem *selectedPart = m_currentGraphicsView->getSelectedPart();
1314
mp = selectedPart->modelPart();
1315
modIdToExport = mp->moduleID();
1317
modIdToExport = moduleId;
1318
mp = m_referenceModel->retrieveModelPart(moduleId);
1320
QString partTitle = mp->title();
1323
QString path = defaultSaveFolder()+"/"+partTitle+FritzingBundledPartExtension;
1324
QString bundledFileName = FolderUtils::getSaveFileName(
1326
tr("Specify a file name"),
1328
tr("Fritzing Part (*%1)").arg(FritzingBundledPartExtension),
1332
if (bundledFileName.isEmpty()) return; // Cancel pressed
1334
if(!alreadyHasExtension(bundledFileName, FritzingBundledPartExtension)) {
1335
bundledFileName += FritzingBundledPartExtension;
1338
QDir destFolder = QDir::temp();
1340
FolderUtils::createFolderAnCdIntoIt(destFolder, FolderUtils::getRandText());
1341
QString dirToRemove = destFolder.path();
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);
1348
//bool wasModified = isWindowModified();
1349
//QString prevFileName = m_fileName;
1350
//saveAsAux(destPartPath);
1351
//m_fileName = prevFileName;
1352
//setWindowModified(wasModified);
1355
saveBundledAux(mp, destFolder);
1357
QStringList skipSuffixes;
1358
if(!FolderUtils::createZipAndSaveTo(destFolder, bundledFileName, skipSuffixes)) {
1359
QMessageBox::warning(
1362
tr("Unable to export %1 to shareable sketch").arg(bundledFileName)
1366
FolderUtils::rmdir(dirToRemove);
1369
QStringList MainWindow::saveBundledAux(ModelPart *mp, const QDir &destFolder) {
1371
QString partPath = mp->path();
1372
QFile file(partPath);
1373
QString fn = ZIP_PART + QFileInfo(partPath).fileName();
1375
file.copy(destFolder.path()+"/"+fn);
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;
1383
QString filename = ItemBase::getSvgFilename(mp, basename);
1384
if (filename.isEmpty()) continue;
1386
QFile file(filename);
1387
basename.replace("/", ".");
1388
QString fn = ZIP_SVG + basename;
1390
file.copy(destFolder.path()+"/"+fn);
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;
1401
throw "MainWindow::moveToPartsFolder mainwindow missing";
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);
1411
namefilters.clear();
1412
namefilters << ZIP_PART+"*";
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);
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);
1430
QString destFilePath =
1431
prefixFolder+"/svg/"+destFolder+"/"+viewFolder+"/"+fileName;
1433
backupExistingFileIfExists(destFilePath);
1434
if(svgfile.copy(destFilePath)) {
1436
m_alienFiles << destFilePath;
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));
1447
backupExistingFileIfExists(destFilePath);
1448
if(partfile.copy(destFilePath)) {
1450
m_alienFiles << destFilePath;
1451
m_alienPartsMsg = tr("Do you want to keep the imported parts?");
1454
ModelPart *mp = m_referenceModel->loadPart(destFilePath, true);
1458
m_binManager->addToContrib(mp);
1464
void MainWindow::binSaved(bool hasPartsFromBundled) {
1465
if(hasPartsFromBundled) {
1466
// the bin will need those parts, so just keep them
1467
m_alienFiles.clear();
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());
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);
1491
file.remove(destFilePath);
1496
void MainWindow::recoverBackupedFiles() {
1497
foreach(QString originalFilePath, m_filesReplacedByAlienOnes) {
1498
QFile file(m_tempDir.path()+"/"+QFileInfo(originalFilePath).fileName());
1499
if(file.exists(originalFilePath)) {
1502
file.copy(originalFilePath);
1507
void MainWindow::resetTempFolder() {
1508
if(m_tempDir.path() != ".") {
1509
FolderUtils::rmdir(m_tempDir);
1510
m_tempDir = QDir::temp();
1512
m_filesReplacedByAlienOnes.clear();
1515
void MainWindow::routingStatusSlot(SketchWidget * sketchWidget, const RoutingStatus & routingStatus) {
1516
m_routingStatus = routingStatus;
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");
1525
theText = tr("Routing completed using %n jumper part(s)", "", routingStatus.m_jumperItemCount);
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);
1533
dynamic_cast<SketchAreaWidget *>(sketchWidget->parent())->routingStatusLabel()->setLabelText(theText);
1538
void MainWindow::applyReadOnlyChange(bool isReadOnly) {
1539
Q_UNUSED(isReadOnly);
1540
//m_saveAct->setDisabled(isReadOnly);
1543
void MainWindow::currentNavigatorChanged(MiniViewContainer * miniView)
1545
int index = m_navigators.indexOf(miniView);
1546
if (index < 0) return;
1548
int oldIndex = currentTabIndex();
1549
if (oldIndex == index) return;
1551
setCurrentTabIndex(index);
1554
void MainWindow::viewSwitchedTo(int viewIndex) {
1555
setCurrentTabIndex(viewIndex);
1558
const QString MainWindow::fritzingTitle() {
1559
if (m_currentGraphicsView == NULL) {
1560
return FritzingWindow::fritzingTitle();
1563
QString fritzing = FritzingWindow::fritzingTitle();
1564
return tr("%1 - [%2]").arg(fritzing).arg(m_currentGraphicsView->viewName());
1567
QAction *MainWindow::raiseWindowAction() {
1568
return m_raiseWindowAct;
1571
void MainWindow::raiseAndActivate() {
1576
QTimer::singleShot(20, this, SLOT(activateWindowAux()));
1579
void MainWindow::activateWindowAux() {
1583
void MainWindow::updateRaiseWindowAction() {
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);
1592
actionText = m_fwFilename;
1594
m_raiseWindowAct->setText(actionText);
1595
m_raiseWindowAct->setToolTip(m_fwFilename);
1596
m_raiseWindowAct->setStatusTip("raise \""+m_fwFilename+"\" window");
1599
QSizeGrip *MainWindow::sizeGrip() {
1603
QStatusBar *MainWindow::realStatusBar() {
1607
void MainWindow::moveEvent(QMoveEvent * event) {
1608
FritzingWindow::moveEvent(event);
1609
emit mainWindowMoved(this);
1612
bool MainWindow::event(QEvent * e) {
1613
switch (e->type()) {
1614
case QEvent::WindowActivate:
1615
emit changeActivationSignal(true, this);
1617
case QEvent::WindowDeactivate:
1618
emit changeActivationSignal(false, this);
1623
return FritzingWindow::event(e);
1626
void MainWindow::resizeEvent(QResizeEvent * event) {
1628
m_sizeGrip->rearrange();
1630
FritzingWindow::resizeEvent(event);
1633
void MainWindow::showInViewHelp() {
1635
if (m_helper == NULL) {
1636
m_helper = new Helper(this, true);
1640
bool toggle = !m_helper->helpVisible(currentTabIndex());
1641
showAllFirstTimeHelp(toggle);
1644
m_helper->toggleHelpVisibility(currentTabIndex());
1647
m_showInViewHelpAct->setChecked(m_helper->helpVisible(currentTabIndex()));
1651
void MainWindow::showAllFirstTimeHelp(bool show) {
1653
for (int i = 0; i < 3; i++) {
1654
m_helper->setHelpVisibility(i, show);
1657
m_showInViewHelpAct->setChecked(show);
1660
void MainWindow::enableCheckUpdates(bool enabled)
1662
if (m_checkForUpdatesAct != NULL) {
1663
m_checkForUpdatesAct->setEnabled(enabled);
1668
void MainWindow::swapSelectedDelay(const QString & family, const QString & prop, QMap<QString, QString> & currPropsMap, ItemBase * itemBase)
1671
m_swapTimer.setAll(family, prop, currPropsMap, itemBase);
1672
m_swapTimer.start();
1675
void MainWindow::swapSelectedTimeout()
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());
1683
void MainWindow::swapSelectedMap(const QString & family, const QString & prop, QMap<QString, QString> & currPropsMap, ItemBase * itemBase)
1685
if (itemBase == NULL) return;
1687
QString generatedModuleID = currPropsMap.value("moduleID");
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(
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.")
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);
1711
else if (type.compare("stripboard", Qt::CaseInsensitive) == 0) {
1712
generatedModuleID = Stripboard::genModuleID(currPropsMap);
1718
if (!generatedModuleID.isEmpty()) {
1719
ModelPart * modelPart = m_referenceModel->retrieveModelPart(generatedModuleID);
1720
if (modelPart == NULL) {
1721
if (!m_referenceModel->genFZP(generatedModuleID, m_referenceModel)) {
1726
swapSelectedAux(itemBase->layerKinChief(), generatedModuleID, false, ViewLayer::UnknownSpec);
1730
if ((prop.compare("package", Qt::CaseSensitive) != 0) && swapSpecial(prop, currPropsMap)) {
1734
foreach (QString key, currPropsMap.keys()) {
1735
QString value = currPropsMap.value(key);
1736
m_referenceModel->recordProperty(key, value);
1739
QString moduleID = m_referenceModel->retrieveModuleIdWith(family, prop, true);
1740
bool exactMatch = m_referenceModel->lastWasExactMatch();
1742
if(moduleID.isEmpty()) {
1743
if (prop.compare("layer") == 0 && itemBase->modelPart()->flippedSMD()) {
1744
ItemBase * viewItem = itemBase->modelPart()->viewItem(ViewLayer::PCBView);
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);
1755
QMessageBox::information(
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")
1767
itemBase = itemBase->layerKinChief();
1770
AutoCloseMessageBox::showMessage(this, tr("No exactly matching part found; Fritzing chose the closest match."));
1773
swapSelectedAux(itemBase, moduleID, false, ViewLayer::UnknownSpec);
1776
bool MainWindow::swapSpecial(const QString & theProp, QMap<QString, QString> & currPropsMap) {
1777
ItemBase * itemBase = m_infoView->currentItem();
1778
QString pinSpacing, resistance;
1781
foreach (QString key, currPropsMap.keys()) {
1782
if (key.compare("layers", Qt::CaseInsensitive) == 0) {
1783
if (!Board::isBoard(itemBase)) continue;
1785
QString value = currPropsMap.value(key, "");
1786
if (value.compare(Board::OneLayerTranslated) == 0) {
1789
else if (value.compare(Board::TwoLayersTranslated) == 0) {
1794
if (key.compare("resistance", Qt::CaseInsensitive) == 0) {
1795
resistance = currPropsMap.value(key);
1798
if (key.compare("pin spacing", Qt::CaseInsensitive) == 0) {
1799
pinSpacing = currPropsMap.value(key);
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);
1813
if (!resistance.isEmpty() || !pinSpacing.isEmpty()) {
1814
if (theProp.contains("band", Qt::CaseInsensitive)) {
1815
// swap 4band for 5band or vice versa.
1819
Resistor * resistor = qobject_cast<Resistor *>(itemBase);
1820
if (resistor != NULL) {
1821
m_currentGraphicsView->setResistance(resistance, pinSpacing);
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);
1837
void MainWindow::swapSelectedAux(ItemBase * itemBase, const QString & moduleID, bool useViewLayerSpec, ViewLayer::ViewLayerSpec overrideViewLayerSpec) {
1839
QUndoCommand* parentCommand = new QUndoCommand(tr("Swapped %1 with module %2").arg(itemBase->instanceTitle()).arg(moduleID));
1840
new CleanUpWiresCommand(m_breadboardGraphicsView, CleanUpWiresCommand::UndoOnly, parentCommand);
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;
1851
swapSelectedAuxAux(itemBase, moduleID, viewLayerSpec, parentCommand);
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);
1858
void MainWindow::swapBoardImageSlot(SketchWidget * sketchWidget, ItemBase * itemBase, const QString & filename, const QString & moduleID, bool addName) {
1860
QUndoCommand* parentCommand = new QUndoCommand(tr("Change image to %2").arg(filename));
1861
long newID = swapSelectedAuxAux(itemBase, moduleID, itemBase->viewLayerSpec(), parentCommand);
1863
LoadLogoImageCommand * cmd = new LoadLogoImageCommand(sketchWidget, newID, "", QSizeF(0,0), filename, filename, addName, parentCommand);
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);
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);
1876
long MainWindow::swapSelectedAuxAux(ItemBase * itemBase, const QString & moduleID, ViewLayer::ViewLayerSpec viewLayerSpec, QUndoCommand * parentCommand)
1878
long modelIndex = ModelPart::nextIndex();
1880
QList<SketchWidget *> sketchWidgets;
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;
1887
case ViewLayer::PCBView:
1888
sketchWidgets << m_schematicGraphicsView << m_breadboardGraphicsView << m_pcbGraphicsView;
1891
sketchWidgets << m_schematicGraphicsView << m_pcbGraphicsView << m_breadboardGraphicsView;
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;
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;
1914
void MainWindow::svgMissingLayer(const QString & layername, const QString & path) {
1915
QMessageBox::warning(
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>.")
1926
void MainWindow::addDefaultParts() {
1927
if (m_pcbGraphicsView == NULL) return;
1929
m_pcbGraphicsView->addDefaultParts();
1930
m_breadboardGraphicsView->addDefaultParts();
1931
m_schematicGraphicsView->addDefaultParts();
1934
MainWindow * MainWindow::newMainWindow(ReferenceModel *referenceModel, const QString & displayPath, bool showProgress, bool lockFiles) {
1935
MainWindow * mw = new MainWindow(referenceModel, NULL);
1937
mw->showFileProgressDialog(displayPath);
1940
mw->init(referenceModel, lockFiles);
1945
void MainWindow::clearFileProgressDialog() {
1946
if (m_fileProgressDialog) {
1947
m_fileProgressDialog->close();
1948
delete m_fileProgressDialog;
1949
m_fileProgressDialog = NULL;
1953
void MainWindow::setFileProgressPath(const QString & path)
1955
if (m_fileProgressDialog) m_fileProgressDialog->setMessage(tr("loading %1").arg(path));
1958
FileProgressDialog * MainWindow::fileProgressDialog()
1960
return m_fileProgressDialog;
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());
1970
setFileProgressPath(tr("new sketch"));
1974
const QString &MainWindow::selectedModuleID() {
1975
if(m_currentGraphicsView) {
1976
return m_currentGraphicsView->selectedModuleID();
1978
return ___emptyString___;
1982
void MainWindow::redrawSketch() {
1983
foreach (QGraphicsItem * item, m_currentGraphicsView->scene()->items()) {
1985
ConnectorItem * c = dynamic_cast<ConnectorItem *>(item);
1987
c->restoreColor(false, 0, true);
1992
void MainWindow::statusMessage(QString message, int timeout) {
1993
QStatusBar * sb = realStatusBar();
1995
sb->showMessage(message, timeout);
1999
void MainWindow::dropPaste(SketchWidget * sketchWidget) {
2000
Q_UNUSED(sketchWidget);
2004
void MainWindow::updateLayerMenuSlot() {
2005
updateLayerMenu(true);
2008
bool MainWindow::save() {
2009
bool result = FritzingWindow::save();
2012
settings.setValue("lastOpenSketch", m_fwFilename);
2017
bool MainWindow::saveAs() {
2018
bool result = false;
2019
if (m_fwFilename.endsWith(FritzingSketchExtension)) {
2020
result = FritzingWindow::saveAs(m_fwFilename + 'z', false);
2023
result = FritzingWindow::saveAs();
2027
settings.setValue("lastOpenSketch", m_fwFilename);
2032
void MainWindow::changeBoardLayers(int layers, bool doEmit) {
2035
updateActiveLayerButtons();
2036
m_currentGraphicsView->updateConnectors();
2039
void MainWindow::updateActiveLayerButtons() {
2040
if (m_activeLayerButtonWidget == NULL) return;
2042
int index = activeLayerIndex();
2043
bool enabled = index >= 0;
2045
m_activeLayerButtonWidget->setCurrentIndex(index);
2046
m_activeLayerButtonWidget->setVisible(enabled);
2048
m_activeLayerBothAct->setEnabled(enabled);
2049
m_activeLayerBottomAct->setEnabled(enabled);
2050
m_activeLayerTopAct->setEnabled(enabled);
2052
QList<QAction *> actions;
2053
actions << m_activeLayerBothAct << m_activeLayerBottomAct << m_activeLayerTopAct;
2054
setActionsIcons(index, actions);
2058
int MainWindow::activeLayerIndex()
2060
if (m_currentGraphicsView == NULL) return -1;
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) {
2068
else if (copper1Visible) {
2071
else if (copper0Visible) {
2079
bool MainWindow::activeLayerWidgetAlwaysOn() {
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.
2090
void MainWindow::backupSketch() {
2091
if (ProcessEventBlocker::isProcessing()) {
2092
// don't want to autosave during autorouting, for example
2096
if (m_autosaveNeeded && !m_undoStack->isClean()) {
2097
m_autosaveNeeded = false; // clear this now in case the save takes a really long time
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();
2103
connectStartSave(true);
2104
m_sketchModel->save(m_backupFileNameAndPath, false);
2105
connectStartSave(false);
2106
m_backingUp = false;
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.
2117
void MainWindow::autosaveNeeded(int index) {
2119
//DebugDialog::debug(QString("Triggering autosave"));
2120
m_autosaveNeeded = true;
2124
* delete the backup file when the undostack is clean.
2126
void MainWindow::undoStackCleanChanged(bool isClean) {
2127
DebugDialog::debug(QString("Clean status changed to %1").arg(isClean));
2129
QFile::remove(m_backupFileNameAndPath);
2133
void MainWindow::setAutosavePeriod(int minutes) {
2134
setAutosave(minutes, AutosaveEnabled);
2137
void MainWindow::setAutosaveEnabled(bool enabled) {
2138
setAutosave(AutosaveTimeoutMinutes, enabled);
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;
2148
mainWindow->m_autosaveTimer.stop();
2149
if (qobject_cast<PEMainWindow *>(widget)) {
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);
2161
bool MainWindow::hasLinkedProgramFiles(const QString & filename, QStringList & linkedProgramFiles)
2163
QFile file(filename);
2164
file.open(QFile::ReadOnly);
2165
QXmlStreamReader xml(&file);
2166
xml.setNamespaceProcessing(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());
2176
if (xml.name().toString().compare("views") == 0) {
2180
if (xml.name().toString().compare("instances") == 0) {
2191
return linkedProgramFiles.count() > 0;
2194
QString MainWindow::getExtensionString() {
2195
return tr("Fritzing (*%1)").arg(fileExtension());
2198
QStringList MainWindow::getExtensions() {
2199
QStringList extensions;
2200
extensions.append(fileExtension());
2204
void MainWindow::firstTimeHelpHidden() {
2205
m_showInViewHelpAct->setChecked(false);
2208
void MainWindow::routingStatusLabelMousePress(QMouseEvent* event) {
2209
routingStatusLabelMouse(event, true);
2212
void MainWindow::routingStatusLabelMouseRelease(QMouseEvent* event) {
2213
routingStatusLabelMouse(event, false);
2216
void MainWindow::routingStatusLabelMouse(QMouseEvent*, bool show) {
2217
if (show) DebugDialog::debug("-------");
2219
QSet<ConnectorItem *> toShow;
2220
foreach (QGraphicsItem * item, m_currentGraphicsView->scene()->items()) {
2221
VirtualWire * vw = dynamic_cast<VirtualWire *>(item);
2222
if (vw == NULL) continue;
2224
foreach (ConnectorItem * connectorItem, vw->connector0()->connectedToItems()) {
2225
toShow.insert(connectorItem);
2227
foreach (ConnectorItem * connectorItem, vw->connector1()->connectedToItems()) {
2228
toShow.insert(connectorItem);
2231
foreach (ConnectorItem * connectorItem, toShow) {
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()));
2240
if (connectorItem->isActive() && connectorItem->isVisible() && !connectorItem->hidden()) {
2241
connectorItem->showEqualPotential(show);
2244
connectorItem = connectorItem->getCrossLayerConnectorItem();
2245
if (connectorItem) connectorItem->showEqualPotential(show);
2249
if (!show && toShow.count() == 0) {
2250
QMessageBox::information(this, tr("Unrouted connections"),
2251
tr("There are no unrouted connections in this view."));
2255
void MainWindow::setReportMissingModules(bool b) {
2256
if (m_sketchModel) {
2257
m_sketchModel->setReportMissingModules(b);
2263
void MainWindow::boardDeletedSlot()
2265
activeLayerBottom();
2268
void MainWindow::cursorLocationSlot(double xinches, double yinches)
2270
if (m_locationLabel) {
2274
m_locationLabel->setProperty("location", QSizeF(xinches, xinches));
2276
if (m_locationLabelUnits.compare("mm") == 0) {
2281
else if (m_locationLabelUnits.compare("px") == 0) {
2283
x = xinches * GraphicsUtils::SVGDPI;
2284
y = yinches * GraphicsUtils::SVGDPI;
2292
m_locationLabel->setText(tr("%1 %2 %3")
2299
void MainWindow::locationLabelClicked()
2301
if (m_locationLabelUnits.compare("mm") == 0) {
2302
m_locationLabelUnits = "px";
2304
else if (m_locationLabelUnits.compare("px") == 0) {
2305
m_locationLabelUnits = "in";
2307
else if (m_locationLabelUnits.compare("in") == 0) {
2308
m_locationLabelUnits = "mm";
2311
m_locationLabelUnits = "in";
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());
2321
cursorLocationSlot(0, 0);
2326
settings.setValue("LocationInches", QVariant(m_locationLabelUnits));
2329
void MainWindow::filenameIfSlot(QString & filename)
2331
filename = QFileInfo(fileName()).fileName();
2334
QList<SketchWidget *> MainWindow::sketchWidgets()
2336
QList<SketchWidget *> list;
2337
list << m_breadboardGraphicsView << m_schematicGraphicsView << m_pcbGraphicsView;
2341
void MainWindow::setCloseSilently(bool cs)
2343
m_closeSilently = cs;
2346
PCBSketchWidget * MainWindow::pcbView() {
2347
return m_pcbGraphicsView;
2350
void MainWindow::noBackup()
2352
m_autosaveTimer.stop();
2355
void MainWindow::hideTempPartsBin() {
2356
if (m_binManager) m_binManager->hideTempPartsBin();
2359
void MainWindow::setActiveWire(Wire * wire) {
2360
m_activeWire = wire;
2363
void MainWindow::setActiveConnectorItem(ConnectorItem * connectorItem) {
2364
m_activeConnectorItem = connectorItem;
2367
const QString & MainWindow::fritzingVersion() {
2368
if (m_sketchModel) return m_sketchModel->fritzingVersion();
2370
return ___emptyString___;
2374
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
2376
const QMimeData* mimeData = event->mimeData();
2378
if (mimeData->hasUrls()) {
2379
QStringList pathList;
2380
QList<QUrl> urlList = mimeData->urls();
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();
2395
void MainWindow::dropEvent(QDropEvent *event)
2397
const QMimeData* mimeData = event->mimeData();
2399
if (mimeData->hasUrls()) {
2400
QStringList pathList;
2401
QList<QUrl> urlList = mimeData->urls();
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());
2410
bool MainWindow::hasAnyAlien() {
2411
return m_addedToTemp;
2414
void MainWindow::initStyleSheet()
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));
2421
QString platformDependantStyle = "";
2422
QString platformDependantStylePath;
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();
2430
platformDependantStylePath = QString(":/resources/styles/linux-%1.qss").arg(suffix);
2434
platformDependantStylePath = QString(":/resources/styles/mac-%1.qss").arg(suffix);
2438
platformDependantStylePath = QString(":/resources/styles/win-%1.qss").arg(suffix);
2441
QFile platformDependantStyleSheet(platformDependantStylePath);
2442
if(platformDependantStyleSheet.open(QIODevice::ReadOnly)) {
2443
platformDependantStyle += platformDependantStyleSheet.readAll();
2445
setStyleSheet(styleSheet.readAll()+platformDependantStyle);
2449
QString MainWindow::getStyleSheetSuffix() {
2453
void MainWindow::addToMyParts(ModelPart * modelPart)
2455
if (modelPart != NULL) m_binManager->addToMyParts(modelPart);
2458
bool MainWindow::usesPart(const QString & moduleID) {
2459
if (m_currentGraphicsView == NULL) return false;
2461
foreach (QGraphicsItem * item, m_currentGraphicsView->scene()->items()) {
2462
ItemBase * itemBase = dynamic_cast<ItemBase *>(item);
2463
if (itemBase != NULL && itemBase->moduleID().compare(moduleID) == 0) {
2471
bool MainWindow::updateParts(const QString & moduleID, QUndoCommand * parentCommand) {
2472
if (m_currentGraphicsView == NULL) return false;
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;
2480
itemBases.insert(itemBase->layerKinChief());
2483
foreach (ItemBase * itemBase, itemBases) {
2484
swapSelectedAuxAux(itemBase, moduleID, itemBase->viewLayerSpec(), parentCommand);
2490
void MainWindow::showStatusMessage(const QString & message)
2492
if (sender() == m_statusBar) {
2496
if (message == m_statusBar->currentMessage()) {
2500
//DebugDialog::debug("show message " + message);
2501
m_statusBar->blockSignals(true);
2502
m_statusBar->showMessage(message);
2503
m_statusBar->blockSignals(false);
2506
void MainWindow::updatePartsBin(const QString & moduleID) {
2507
m_binManager->reloadPart(moduleID);
2510
bool MainWindow::hasCustomBoardShape() {
2511
if (m_pcbGraphicsView == NULL) return false;
2513
return m_pcbGraphicsView->hasCustomBoardShape();