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: cohen@irascible.com $:
24
$Date: 2012-08-08 04:07:28 +0200 (Wed, 08 Aug 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 "navigator/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 "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 "dockmanager.h"
78
#include "partsbinpalette/binmanager/binmanager.h"
80
#include "fsvgrenderer.h"
81
#include "utils/fsizegrip.h"
82
#include "utils/expandinglabel.h"
83
#include "viewswitcher/viewswitcher.h"
84
#include "viewswitcher/viewswitcherdockwidget.h"
86
#include "utils/autoclosemessagebox.h"
87
#include "utils/fileprogressdialog.h"
88
#include "utils/clickablelabel.h"
89
#include "items/resizableboard.h"
90
#include "items/resistor.h"
91
#include "items/symbolpaletteitem.h"
92
#include "utils/zoomslider.h"
95
///////////////////////////////////////////////
97
#define ZIP_PART QString("part.")
98
#define ZIP_SVG QString("svg.")
100
///////////////////////////////////////////////
102
// SwapTimer explained: http://code.google.com/p/fritzing/issues/detail?id=1431
104
SwapTimer::SwapTimer() : QTimer()
108
void SwapTimer::setAll(const QString & family, const QString & prop, QMap<QString, QString> & propsMap, ItemBase * itemBase)
112
m_propsMap = propsMap;
113
m_itemBase = itemBase;
116
const QString & SwapTimer::family()
121
const QString & SwapTimer::prop()
126
QMap<QString, QString> SwapTimer::propsMap()
131
ItemBase * SwapTimer::itemBase()
136
///////////////////////////////////////////////
138
const QString MainWindow::UntitledSketchName = "Untitled Sketch";
139
int MainWindow::UntitledSketchIndex = 1;
140
int MainWindow::CascadeFactorX = 21;
141
int MainWindow::CascadeFactorY = 19;
142
int MainWindow::RestartNeeded = 0;
144
static const int MainWindowDefaultWidth = 840;
145
static const int MainWindowDefaultHeight = 600;
147
int MainWindow::AutosaveTimeoutMinutes = 10; // in minutes
148
bool MainWindow::AutosaveEnabled = true;
149
QString MainWindow::BackupFolder;
151
/////////////////////////////////////////////
153
MainWindow::MainWindow(PaletteModel * paletteModel, ReferenceModel *refModel, QWidget * parent) :
154
FritzingWindow(untitledFileName(), untitledFileCount(), fileExtension(), parent)
156
setAcceptDrops(true);
158
m_activeConnectorItem = NULL;
159
m_swapTimer.setInterval(30);
160
m_swapTimer.setParent(this);
161
m_swapTimer.setSingleShot(true);
162
connect(&m_swapTimer, SIGNAL(timeout()), this, SLOT(swapSelectedTimeout()));
164
m_closeSilently = false;
165
m_orderFabAct = NULL;
166
m_activeLayerButtonWidget = NULL;
167
m_programWindow = NULL;
168
m_windowMenuSeparator = NULL;
169
m_wireColorMenu = NULL;
170
m_viewSwitcherDock = NULL;
171
m_checkForUpdatesAct = NULL;
172
m_fileProgressDialog = NULL;
173
m_currentGraphicsView = NULL;
174
m_comboboxChanged = false;
176
m_smdOneSideWarningGiven = false;
178
// Add a timer for autosaving
179
m_backingUp = m_autosaveNeeded = false;
180
connect(&m_autosaveTimer, SIGNAL(timeout()), this, SLOT(backupSketch()));
181
m_autosaveTimer.start(AutosaveTimeoutMinutes * 60 * 1000);
183
resize(MainWindowDefaultWidth, MainWindowDefaultHeight);
185
m_backupFileNameAndPath = MainWindow::BackupFolder + "/" + FolderUtils::getRandText() + FritzingSketchExtension;
186
// Connect the undoStack to our autosave stuff
187
connect(m_undoStack, SIGNAL(indexChanged(int)), this, SLOT(autosaveNeeded(int)));
188
connect(m_undoStack, SIGNAL(cleanChanged(bool)), this, SLOT(undoStackCleanChanged(bool)));
191
m_dotIcon = QIcon(":/resources/images/dot.png");
192
m_emptyIcon = QIcon();
194
m_currentWidget = NULL;
197
m_statusBar = new QStatusBar(this);
198
setStatusBar(m_statusBar);
199
m_statusBar->setSizeGripEnabled(false);
202
m_locationLabelUnits = settings.value("LocationInches", "in").toString();
204
// leave the m_orderFabEnabled check in case we turn off the fab button in the future
205
m_orderFabEnabled = true; // settings.value(ORDERFABENABLED, QVariant(false)).toBool();
207
m_locationLabel = new ClickableLabel("", this);
208
m_locationLabel->setObjectName("LocationLabel");
209
connect(m_locationLabel, SIGNAL(clicked()), this, SLOT(locationLabelClicked()));
210
m_statusBar->addPermanentWidget(m_locationLabel);
212
m_zoomSlider = new ZoomSlider(m_statusBar);
213
connect(m_zoomSlider, SIGNAL(zoomChanged(double)), this, SLOT(updateViewZoom(double)));
214
m_statusBar->addPermanentWidget(m_zoomSlider);
217
setAttribute(Qt::WA_DeleteOnClose, true);
220
//setAttribute(Qt::WA_QuitOnClose, false); // restoring this temporarily (2008.12.19)
222
m_dontClose = m_closing = false;
224
m_paletteModel = paletteModel;
225
m_refModel = refModel;
226
m_sketchModel = new SketchModel(true);
228
m_tabWidget = new QStackedWidget(this); // FTabWidget(this);
229
m_tabWidget->setObjectName("sketch_tabs");
231
setCentralWidget(m_tabWidget);
233
QShortcut * shortcut = new QShortcut(QKeySequence(tr("Ctrl+R", "Rotate Clockwise")), this);
234
connect(shortcut, SIGNAL(activated()), this, SLOT(rotateIncCW()));
235
shortcut = new QShortcut(QKeySequence(tr("Alt+Ctrl+R", "Rotate Clockwise")), this);
236
connect(shortcut, SIGNAL(activated()), this, SLOT(rotateIncCWRubberBand()));
237
shortcut = new QShortcut(QKeySequence(tr("Meta+Ctrl+R", "Rotate Clockwise")), this);
238
connect(shortcut, SIGNAL(activated()), this, SLOT(rotateIncCWRubberBand()));
240
shortcut = new QShortcut(QKeySequence(tr("Shift+Ctrl+R", "Rotate Counterclockwise")), this);
241
connect(shortcut, SIGNAL(activated()), this, SLOT(rotateIncCCW()));
242
shortcut = new QShortcut(QKeySequence(tr("Alt+Shift+Ctrl+R", "Rotate Counterclockwise")), this);
243
connect(shortcut, SIGNAL(activated()), this, SLOT(rotateIncCCWRubberBand()));
244
shortcut = new QShortcut(QKeySequence(tr("Meta+Shift+Ctrl+R", "Rotate Counterclockwise")), this);
245
connect(shortcut, SIGNAL(activated()), this, SLOT(rotateIncCCWRubberBand()));
247
shortcut = new QShortcut(QKeySequence(tr("Shift+Ctrl+Tab", "Toggle Active Layer")), this);
248
connect(shortcut, SIGNAL(activated()), this, SLOT(toggleActiveLayer()));
251
connect(this, SIGNAL(changeActivationSignal(bool, QWidget *)), qApp, SLOT(changeActivation(bool, QWidget *)), Qt::DirectConnection);
252
connect(this, SIGNAL(destroyed(QObject *)), qApp, SLOT(topLevelWidgetDestroyed(QObject *)));
253
connect(this, SIGNAL(externalProcessSignal(QString &, QString &, QStringList &)),
254
qApp, SLOT(externalProcessSlot(QString &, QString &, QStringList &)),
255
Qt::DirectConnection);
258
void MainWindow::init(PaletteModel * paletteModel, ReferenceModel *refModel, bool lockFiles) {
259
m_paletteModel = paletteModel;
260
m_refModel = refModel;
261
m_restarting = false;
263
if (m_fileProgressDialog) {
264
m_fileProgressDialog->setValue(2);
267
LockManager::initLockedFiles("fzz", m_fzzFolder, m_fzzFiles, lockFiles ? LockManager::SlowTime : 0);
269
QFileInfoList backupList;
270
LockManager::checkLockedFiles("fzz", backupList, m_fzzFiles, true, LockManager::SlowTime);
273
DebugDialog::debug("init sketch widgets");
275
// all this belongs in viewLayer.xml
276
m_breadboardGraphicsView = new BreadboardSketchWidget(ViewIdentifierClass::BreadboardView, this);
277
initSketchWidget(m_breadboardGraphicsView);
278
m_breadboardWidget = new SketchAreaWidget(m_breadboardGraphicsView,this);
279
m_tabWidget->addWidget(m_breadboardWidget);
281
if (m_fileProgressDialog) {
282
m_fileProgressDialog->setValue(11);
286
m_schematicGraphicsView = new SchematicSketchWidget(ViewIdentifierClass::SchematicView, this);
287
initSketchWidget(m_schematicGraphicsView);
288
m_schematicWidget = new SketchAreaWidget(m_schematicGraphicsView, this);
289
m_tabWidget->addWidget(m_schematicWidget);
291
if (m_fileProgressDialog) {
292
m_fileProgressDialog->setValue(20);
295
m_pcbGraphicsView = new PCBSketchWidget(ViewIdentifierClass::PCBView, this);
296
initSketchWidget(m_pcbGraphicsView);
297
m_pcbWidget = new SketchAreaWidget(m_pcbGraphicsView, this);
298
m_tabWidget->addWidget(m_pcbWidget);
300
if (m_fileProgressDialog) {
301
m_fileProgressDialog->setValue(29);
304
m_undoView = new QUndoView();
305
m_undoGroup = new QUndoGroup(this);
306
m_undoView->setGroup(m_undoGroup);
307
m_undoGroup->setActiveStack(m_undoStack);
309
m_layerPalette = new LayerPalette(this);
311
DebugDialog::debug("before creating dock");
313
m_dockManager = new DockManager(this);
314
DebugDialog::debug("before creating bins");
316
m_dockManager->createBinAndInfoViewDocks();
318
DebugDialog::debug("after creating bins");
319
if (m_fileProgressDialog) {
320
m_fileProgressDialog->setValue(89);
325
// This is the magic translation that changes all the shortcut text on the menu items
326
// to the native language instead of "Ctrl", so the German menu items will now read "Strg"
327
// You don't actually have to translate every menu item in the .ts file, you can just leave it as "Ctrl".
328
QShortcut::tr("Ctrl", "for naming shortcut keys on menu items");
329
QShortcut::tr("Alt", "for naming shortcut keys on menu items");
330
QShortcut::tr("Shift", "for naming shortcut keys on menu items");
331
QShortcut::tr("Meta", "for naming shortcut keys on menu items");
333
DebugDialog::debug("create menus");
338
DebugDialog::debug("create toolbars");
343
DebugDialog::debug("after creating status bar");
345
if (m_fileProgressDialog) {
346
m_fileProgressDialog->setValue(91);
349
DebugDialog::debug("create view switcher");
351
m_layerPalette->setShowAllLayersAction(m_showAllLayersAct);
352
m_layerPalette->setHideAllLayersAction(m_hideAllLayersAct);
354
m_viewSwitcher = new ViewSwitcher();
355
connect(m_viewSwitcher, SIGNAL(viewSwitched(int)), this, SLOT(viewSwitchedTo(int)));
356
connect(this, SIGNAL(viewSwitched(int)), m_viewSwitcher, SLOT(viewSwitchedTo(int)));
357
m_viewSwitcher->viewSwitchedTo(0);
359
m_dockManager->createDockWindows();
361
if (m_fileProgressDialog) {
362
m_fileProgressDialog->setValue(93);
365
createZoomOptions(m_breadboardWidget);
366
createZoomOptions(m_schematicWidget);
367
createZoomOptions(m_pcbWidget);
369
m_breadboardWidget->setToolbarWidgets(getButtonsForView(m_breadboardWidget->viewIdentifier()));
370
m_schematicWidget->setToolbarWidgets(getButtonsForView(m_schematicWidget->viewIdentifier()));
371
m_pcbWidget->setToolbarWidgets(getButtonsForView(m_pcbWidget->viewIdentifier()));
373
QFile styleSheet(":/resources/styles/fritzing.qss");
374
if (!styleSheet.open(QIODevice::ReadOnly)) {
375
qWarning("Unable to open :/resources/styles/fritzing.qss");
377
QString platformDependantStyle = "";
378
QString platformDependantStylePath;
380
if(style()->metaObject()->className()==QString("OxygenStyle")) {
381
QFile oxygenStyleSheet(":/resources/styles/linux-kde-oxygen.qss");
382
if(oxygenStyleSheet.open(QIODevice::ReadOnly)) {
383
platformDependantStyle += oxygenStyleSheet.readAll();
386
platformDependantStylePath = ":/resources/styles/linux.qss";
390
platformDependantStylePath = ":/resources/styles/mac.qss";
394
platformDependantStylePath = ":/resources/styles/win.qss";
397
QFile platformDependantStyleSheet(platformDependantStylePath);
398
if(platformDependantStyleSheet.open(QIODevice::ReadOnly)) {
399
platformDependantStyle += platformDependantStyleSheet.readAll();
401
setStyleSheet(styleSheet.readAll()+platformDependantStyle);
404
m_breadboardGraphicsView->setItemMenu(breadboardItemMenu());
405
m_breadboardGraphicsView->setWireMenu(breadboardWireMenu());
407
m_pcbGraphicsView->setWireMenu(pcbWireMenu());
408
m_pcbGraphicsView->setItemMenu(pcbItemMenu());
410
m_schematicGraphicsView->setItemMenu(schematicItemMenu());
411
m_schematicGraphicsView->setWireMenu(schematicWireMenu());
413
m_breadboardGraphicsView->setInfoView(m_infoView);
414
m_pcbGraphicsView->setInfoView(m_infoView);
415
m_schematicGraphicsView->setInfoView(m_infoView);
417
// make sure to set the connections after the views have been created
418
connect(m_tabWidget, SIGNAL(currentChanged ( int )), this, SLOT(tabWidget_currentChanged( int )));
422
m_helper = new Helper(this, true);
424
// do this the first time, since the current_changed signal wasn't sent
426
currentNavigatorChanged(m_navigators[tab]);
427
tabWidget_currentChanged(tab+1);
428
tabWidget_currentChanged(tab);
430
this->installEventFilter(this);
432
if (m_fileProgressDialog) {
433
m_fileProgressDialog->setValue(95);
437
m_viewSwitcherDock->prestorePreference();
438
if(!settings.value("main/state").isNull()) {
439
restoreState(settings.value("main/state").toByteArray());
440
restoreGeometry(settings.value("main/geometry").toByteArray());
442
m_viewSwitcherDock->restorePreference();
443
m_viewSwitcherDock->setViewSwitcher(m_viewSwitcher);
446
m_tabWidget->setMinimumWidth(500);
447
m_tabWidget->setMinimumWidth(0);
449
m_miniViewContainerBreadboard->setView(m_breadboardGraphicsView);
450
m_miniViewContainerSchematic->setView(m_schematicGraphicsView);
451
m_miniViewContainerPCB->setView(m_pcbGraphicsView);
453
connect(this, SIGNAL(readOnlyChanged(bool)), this, SLOT(applyReadOnlyChange(bool)));
455
m_setUpDockManagerTimer.setSingleShot(true);
456
connect(&m_setUpDockManagerTimer, SIGNAL(timeout()), m_dockManager, SLOT(keepMargins()));
457
m_setUpDockManagerTimer.start(1000);
459
if (m_fileProgressDialog) {
460
m_fileProgressDialog->setValue(98);
465
MainWindow::~MainWindow()
467
// Delete backup of this sketch if one exists.
468
QFile::remove(m_backupFileNameAndPath);
470
delete m_sketchModel;
471
m_dockManager->dontKeepMargins();
472
m_setUpDockManagerTimer.stop();
474
foreach (LinkedFile * linkedFile, m_linkedProgramFiles) {
477
m_linkedProgramFiles.clear();
479
if (!m_fzzFolder.isEmpty()) {
480
LockManager::releaseLockedFiles(m_fzzFolder, m_fzzFiles);
481
FolderUtils::rmdir(m_fzzFolder);
485
void MainWindow::showNavigator() {
486
m_navigatorDock->setFloating(false);
489
void MainWindow::initSketchWidget(SketchWidget * sketchWidget) {
490
sketchWidget->setPaletteModel(m_paletteModel);
491
sketchWidget->setSketchModel(m_sketchModel);
492
sketchWidget->setRefModel(m_refModel);
493
sketchWidget->setUndoStack(m_undoStack);
494
sketchWidget->setChainDrag(true); // enable bend points
495
sketchWidget->initGrid();
496
sketchWidget->addViewLayers();
499
void MainWindow::connectPairs() {
500
connectPair(m_breadboardGraphicsView, m_schematicGraphicsView);
501
connectPair(m_breadboardGraphicsView, m_pcbGraphicsView);
502
connectPair(m_schematicGraphicsView, m_breadboardGraphicsView);
503
connectPair(m_schematicGraphicsView, m_pcbGraphicsView);
504
connectPair(m_pcbGraphicsView, m_breadboardGraphicsView);
505
connectPair(m_pcbGraphicsView, m_schematicGraphicsView);
507
connect(m_pcbGraphicsView, SIGNAL(groundFillSignal()), this, SLOT(groundFill()));
508
connect(m_pcbGraphicsView, SIGNAL(copperFillSignal()), this, SLOT(copperFill()));
510
connect(m_pcbGraphicsView, SIGNAL(swapBoardImageSignal(SketchWidget *, ItemBase *, const QString &, const QString &, bool)),
511
this, SLOT(swapBoardImageSlot(SketchWidget *, ItemBase *, const QString &, const QString &, bool)));
514
connect(m_breadboardGraphicsView, SIGNAL(setActiveWireSignal(Wire *)), this, SLOT(setActiveWire(Wire *)));
515
connect(m_schematicGraphicsView, SIGNAL(setActiveWireSignal(Wire *)), this, SLOT(setActiveWire(Wire *)));
516
connect(m_pcbGraphicsView, SIGNAL(setActiveWireSignal(Wire *)), this, SLOT(setActiveWire(Wire *)));
518
connect(m_breadboardGraphicsView, SIGNAL(setActiveConnectorItemSignal(ConnectorItem *)), this, SLOT(setActiveConnectorItem(ConnectorItem *)));
519
connect(m_schematicGraphicsView, SIGNAL(setActiveConnectorItemSignal(ConnectorItem *)), this, SLOT(setActiveConnectorItem(ConnectorItem *)));
520
connect(m_pcbGraphicsView, SIGNAL(setActiveConnectorItemSignal(ConnectorItem *)), this, SLOT(setActiveConnectorItem(ConnectorItem *)));
522
bool succeeded = connect(m_pcbGraphicsView, SIGNAL(routingStatusSignal(SketchWidget *, const RoutingStatus &)),
523
this, SLOT(routingStatusSlot(SketchWidget *, const RoutingStatus &)));
524
succeeded = succeeded && connect(m_schematicGraphicsView, SIGNAL(routingStatusSignal(SketchWidget *, const RoutingStatus &)),
525
this, SLOT(routingStatusSlot(SketchWidget *, const RoutingStatus &)));
526
succeeded = succeeded && connect(m_breadboardGraphicsView, SIGNAL(routingStatusSignal(SketchWidget *, const RoutingStatus &)),
527
this, SLOT(routingStatusSlot(SketchWidget *, const RoutingStatus &)));
529
succeeded = succeeded && connect(m_breadboardGraphicsView, SIGNAL(swapSignal(const QString &, const QString &, QMap<QString, QString> &, ItemBase *)),
530
this, SLOT(swapSelectedDelay(const QString &, const QString &, QMap<QString, QString> &, ItemBase *)));
531
succeeded = succeeded && connect(m_schematicGraphicsView, SIGNAL(swapSignal(const QString &, const QString &, QMap<QString, QString> &, ItemBase *)),
532
this, SLOT(swapSelectedDelay(const QString &, const QString &, QMap<QString, QString> &, ItemBase *)));
533
succeeded = succeeded && connect(m_pcbGraphicsView, SIGNAL(swapSignal(const QString &, const QString &, QMap<QString, QString> &, ItemBase *)),
534
this, SLOT(swapSelectedDelay(const QString &, const QString &, QMap<QString, QString> &, ItemBase *)));
536
succeeded = succeeded && connect(m_breadboardGraphicsView, SIGNAL(warnSMDSignal(const QString &)), this, SLOT(warnSMD(const QString &)), Qt::QueuedConnection);
537
succeeded = succeeded && connect(m_pcbGraphicsView, SIGNAL(warnSMDSignal(const QString &)), this, SLOT(warnSMD(const QString &)), Qt::QueuedConnection);
538
succeeded = succeeded && connect(m_schematicGraphicsView, SIGNAL(warnSMDSignal(const QString &)), this, SLOT(warnSMD(const QString &)), Qt::QueuedConnection);
541
succeeded = succeeded && connect(m_breadboardGraphicsView, SIGNAL(dropPasteSignal(SketchWidget *)),
542
this, SLOT(dropPaste(SketchWidget *)));
543
succeeded = succeeded && connect(m_schematicGraphicsView, SIGNAL(dropPasteSignal(SketchWidget *)),
544
this, SLOT(dropPaste(SketchWidget *)));
545
succeeded = succeeded && connect(m_pcbGraphicsView, SIGNAL(dropPasteSignal(SketchWidget *)),
546
this, SLOT(dropPaste(SketchWidget *)));
548
succeeded = succeeded && connect(m_pcbGraphicsView, SIGNAL(subSwapSignal(SketchWidget *, ItemBase *, const QString &, ViewLayer::ViewLayerSpec, long &, QUndoCommand *)),
549
this, SLOT(subSwapSlot(SketchWidget *, ItemBase *, const QString &, ViewLayer::ViewLayerSpec, long &, QUndoCommand *)),
550
Qt::DirectConnection);
552
succeeded = succeeded && connect(m_pcbGraphicsView, SIGNAL(firstTimeHelpHidden()), this, SLOT(firstTimeHelpHidden()));
553
succeeded = succeeded && connect(m_schematicGraphicsView, SIGNAL(firstTimeHelpHidden()), this, SLOT(firstTimeHelpHidden()));
554
succeeded = succeeded && connect(m_breadboardGraphicsView, SIGNAL(firstTimeHelpHidden()), this, SLOT(firstTimeHelpHidden()));
556
succeeded = succeeded && connect(m_pcbGraphicsView, SIGNAL(updateLayerMenuSignal()), this, SLOT(updateLayerMenuSlot()));
557
succeeded = succeeded && connect(m_pcbGraphicsView, SIGNAL(changeBoardLayersSignal(int, bool )), this, SLOT(changeBoardLayers(int, bool )));
560
succeeded = succeeded && connect(qApp, SIGNAL(spaceBarIsPressedSignal(bool)), m_breadboardGraphicsView, SLOT(spaceBarIsPressedSlot(bool)));
561
succeeded = succeeded && connect(qApp, SIGNAL(spaceBarIsPressedSignal(bool)), m_schematicGraphicsView, SLOT(spaceBarIsPressedSlot(bool)));
562
succeeded = succeeded && connect(qApp, SIGNAL(spaceBarIsPressedSignal(bool)), m_pcbGraphicsView, SLOT(spaceBarIsPressedSlot(bool)));
564
succeeded = succeeded && connect(m_pcbGraphicsView, SIGNAL(boardDeletedSignal()), this, SLOT(boardDeletedSlot()));
566
succeeded = succeeded && connect(m_pcbGraphicsView, SIGNAL(cursorLocationSignal(double, double)), this, SLOT(cursorLocationSlot(double, double)));
567
succeeded = succeeded && connect(m_breadboardGraphicsView, SIGNAL(cursorLocationSignal(double, double)), this, SLOT(cursorLocationSlot(double, double)));
568
succeeded = succeeded && connect(m_schematicGraphicsView, SIGNAL(cursorLocationSignal(double, double)), this, SLOT(cursorLocationSlot(double, double)));
570
succeeded = succeeded && connect(m_breadboardGraphicsView, SIGNAL(filenameIfSignal(QString &)), this, SLOT(filenameIfSlot(QString &)), Qt::DirectConnection);
571
succeeded = succeeded && connect(m_pcbGraphicsView, SIGNAL(filenameIfSignal(QString &)), this, SLOT(filenameIfSlot(QString &)), Qt::DirectConnection);
572
succeeded = succeeded && connect(m_schematicGraphicsView, SIGNAL(filenameIfSignal(QString &)), this, SLOT(filenameIfSlot(QString &)), Qt::DirectConnection);
575
DebugDialog::debug("connectPair failed");
579
void MainWindow::connectPair(SketchWidget * signaller, SketchWidget * slotter)
582
bool succeeded = connect(signaller, SIGNAL(itemAddedSignal(ModelPart *, ViewLayer::ViewLayerSpec, const ViewGeometry &, long, SketchWidget *)),
583
slotter, SLOT(itemAddedSlot(ModelPart *, ViewLayer::ViewLayerSpec, const ViewGeometry &, long, SketchWidget *)));
585
succeeded = succeeded && connect(signaller, SIGNAL(itemDeletedSignal(long)),
586
slotter, SLOT(itemDeletedSlot(long)),
587
Qt::DirectConnection);
589
succeeded = succeeded && connect(signaller, SIGNAL(clearSelectionSignal()),
590
slotter, SLOT(clearSelectionSlot()));
592
succeeded = succeeded && connect(signaller, SIGNAL(itemSelectedSignal(long, bool)),
593
slotter, SLOT(itemSelectedSlot(long, bool)));
594
succeeded = succeeded && connect(signaller, SIGNAL(selectAllItemsSignal(bool, bool)),
595
slotter, SLOT(selectAllItems(bool, bool)));
596
succeeded = succeeded && connect(signaller, SIGNAL(wireDisconnectedSignal(long, QString)),
597
slotter, SLOT(wireDisconnectedSlot(long, QString)));
598
succeeded = succeeded && connect(signaller, SIGNAL(wireConnectedSignal(long, QString, long, QString)),
599
slotter, SLOT(wireConnectedSlot(long, QString, long, QString)));
600
succeeded = succeeded && connect(signaller, SIGNAL(changeConnectionSignal(long, QString, long, QString, ViewLayer::ViewLayerSpec, bool, bool)),
601
slotter, SLOT(changeConnectionSlot(long, QString, long, QString, ViewLayer::ViewLayerSpec, bool, bool)));
602
succeeded = succeeded && connect(signaller, SIGNAL(copyBoundingRectsSignal(QHash<QString, QRectF> &)),
603
slotter, SLOT(copyBoundingRectsSlot(QHash<QString, QRectF> &)),
604
Qt::DirectConnection);
606
succeeded = succeeded && connect(signaller, SIGNAL(cleanUpWiresSignal(CleanUpWiresCommand *)),
607
slotter, SLOT(cleanUpWiresSlot(CleanUpWiresCommand *)) );
609
succeeded = succeeded && connect(signaller, SIGNAL(checkStickySignal(long, bool, bool, CheckStickyCommand *)),
610
slotter, SLOT(checkSticky(long, bool, bool, CheckStickyCommand *)) );
612
succeeded = succeeded && connect(signaller, SIGNAL(disconnectAllSignal(QList<ConnectorItem *>, QHash<ItemBase *, SketchWidget *> &, QUndoCommand *)),
613
slotter, SLOT(disconnectAllSlot(QList<ConnectorItem *>, QHash<ItemBase *, SketchWidget *> &, QUndoCommand *)),
614
Qt::DirectConnection);
615
succeeded = succeeded && connect(signaller, SIGNAL(setResistanceSignal(long, QString, QString, bool)),
616
slotter, SLOT(setResistance(long, QString, QString, bool)));
617
succeeded = succeeded && connect(signaller, SIGNAL(makeDeleteItemCommandPrepSignal(ItemBase *, bool , QUndoCommand * )),
618
slotter, SLOT(makeDeleteItemCommandPrepSlot(ItemBase * , bool , QUndoCommand * )));
619
succeeded = succeeded && connect(signaller, SIGNAL(makeDeleteItemCommandFinalSignal(ItemBase *, bool , QUndoCommand * )),
620
slotter, SLOT(makeDeleteItemCommandFinalSlot(ItemBase * , bool , QUndoCommand * )));
622
succeeded = succeeded && connect(signaller, SIGNAL(setPropSignal(long, const QString &, const QString &, bool, bool)),
623
slotter, SLOT(setProp(long, const QString &, const QString &, bool, bool)));
625
succeeded = succeeded && connect(signaller, SIGNAL(setInstanceTitleSignal(long, const QString &, const QString &, bool, bool )),
626
slotter, SLOT(setInstanceTitle(long, const QString &, const QString &, bool, bool )));
628
succeeded = succeeded && connect(signaller, SIGNAL(setVoltageSignal(double, bool )),
629
slotter, SLOT(setVoltage(double, bool )));
631
succeeded = succeeded && connect(signaller, SIGNAL(showLabelFirstTimeSignal(long, bool, bool )),
632
slotter, SLOT(showLabelFirstTime(long, bool, bool )));
634
succeeded = succeeded && connect(signaller, SIGNAL(changeBoardLayersSignal(int, bool )),
635
slotter, SLOT(changeBoardLayers(int, bool )));
637
succeeded = succeeded && connect(signaller, SIGNAL(deleteTracesSignal(QSet<ItemBase *> &, QHash<ItemBase *, SketchWidget *> &, QList<long> &, bool, QUndoCommand *)),
638
slotter, SLOT(deleteTracesSlot(QSet<ItemBase *> &, QHash<ItemBase *, SketchWidget *> &, QList<long> &, bool, QUndoCommand *)),
639
Qt::DirectConnection);
641
succeeded = succeeded && connect(signaller, SIGNAL(ratsnestConnectSignal(long, const QString &, bool, bool)),
642
slotter, SLOT(ratsnestConnect(long, const QString &, bool, bool )),
643
Qt::DirectConnection);
646
succeeded = succeeded && connect(signaller, SIGNAL(updatePartLabelInstanceTitleSignal(long)),
647
slotter, SLOT(updatePartLabelInstanceTitleSlot(long)));
649
succeeded = succeeded && connect(signaller, SIGNAL(changePinLabelsSignal(ItemBase *, bool)),
650
slotter, SLOT(changePinLabelsSlot(ItemBase *, bool)));
652
succeeded = succeeded && connect(signaller, SIGNAL(collectRatsnestSignal(QList<SketchWidget *> &)),
653
slotter, SLOT(collectRatsnestSlot(QList<SketchWidget *> &)),
654
Qt::DirectConnection);
656
succeeded = succeeded && connect(signaller, SIGNAL(removeRatsnestSignal(QList<struct ConnectorEdge *> &, QUndoCommand *)),
657
slotter, SLOT(removeRatsnestSlot(QList<struct ConnectorEdge *> &, QUndoCommand *)),
658
Qt::DirectConnection);
660
succeeded = succeeded && connect(signaller, SIGNAL(canConnectSignal(Wire *, ItemBase *, bool &)),
661
slotter, SLOT(canConnect(Wire *, ItemBase *, bool &)),
662
Qt::DirectConnection);
664
succeeded = succeeded && connect(signaller, SIGNAL(swapStartSignal(SwapThing &, bool)),
665
slotter, SLOT(swapStart(SwapThing &, bool)),
666
Qt::DirectConnection);
669
DebugDialog::debug("connectPair failed");
674
void MainWindow::setCurrentFile(const QString &filename, bool addToRecent, bool setAsLastOpened) {
675
setFileName(filename);
677
if(setAsLastOpened) {
679
settings.setValue("lastOpenSketch",filename);
682
updateRaiseWindowAction();
687
QStringList files = settings.value("recentFileList").toStringList();
688
files.removeAll(filename);
689
files.prepend(filename);
690
while (files.size() > MaxRecentFiles)
693
settings.setValue("recentFileList", files);
696
foreach (QWidget *widget, QApplication::topLevelWidgets()) {
697
MainWindow *mainWin = qobject_cast<MainWindow *>(widget);
699
mainWin->updateRecentFileActions();
704
void MainWindow::createZoomOptions(SketchAreaWidget* parent) {
706
connect(parent->graphicsView(), SIGNAL(zoomChanged(double)), this, SLOT(updateZoomSlider(double)));
707
connect(parent->graphicsView(), SIGNAL(zoomOutOfRange(double)), this, SLOT(updateZoomOptionsNoMatterWhat(double)));
710
void MainWindow::createToolBars() {
711
/* TODO: Mariano this is too hacky and requires some styling
712
* around here and some else in the qss file
714
/*m_toolbar = new QToolBar(this);
715
m_toolbar->setObjectName("fake_tabbar");
716
m_toolbar->setFloatable(false);
717
m_toolbar->setMovable(false);
718
int height = 0; // m_tabWidget->tabBar()->height();
719
m_toolbar->layout()->setMargin(0);
720
m_toolbar->setFixedHeight(height+10);
721
m_toolbar->setMinimumWidth(400); // connect to tabwidget resize event
722
m_toolbar->toggleViewAction()->setVisible(false);
723
// m_tabWidget->tabBar()->setParent(m_toolbar);
724
addToolBar(m_toolbar);*/
726
/* QToolBar *tb2 = new QToolBar(this);
727
tb2->setFloatable(false);
728
tb2->setMovable(false);
729
QToolButton *dummyButton = new QToolButton();
730
dummyButton->setIcon(QIcon(":/resources/images/toolbar_icons/toolbarExport_pdf_icon.png"));
731
tb2->addWidget(dummyButton);
732
QToolButton *dummyButton2 = new QToolButton();
733
dummyButton2->setIcon(QIcon(":/resources/images/toolbar_icons/toolbarOrder_icon.png"));
734
tb2->addWidget(dummyButton2);
738
m_fileToolBar = addToolBar(tr("File"));
739
m_fileToolBar->setObjectName("fileToolBar");
740
m_fileToolBar->addAction(m_saveAct);
741
m_fileToolBar->addAction(m_printAct);
743
m_editToolBar = addToolBar(tr("Edit"));
744
m_editToolBar->setObjectName("editToolBar");
745
m_editToolBar->addAction(m_undoAct);
746
m_editToolBar->addWidget(m_zoomOptsComboBox);
750
ExpandingLabel * MainWindow::createRoutingStatusLabel(SketchAreaWidget * parent) {
751
ExpandingLabel * routingStatusLabel = new ExpandingLabel(m_pcbWidget);
753
connect(routingStatusLabel, SIGNAL(mousePressSignal(QMouseEvent*)), this, SLOT(routingStatusLabelMousePress(QMouseEvent*)));
754
connect(routingStatusLabel, SIGNAL(mouseReleaseSignal(QMouseEvent*)), this, SLOT(routingStatusLabelMouseRelease(QMouseEvent*)));
756
routingStatusLabel->setTextInteractionFlags(Qt::NoTextInteraction);
757
routingStatusLabel->setCursor(Qt::ArrowCursor);
758
routingStatusLabel->viewport()->setCursor(Qt::ArrowCursor);
760
routingStatusLabel->setObjectName(SketchAreaWidget::RoutingStateLabelName);
761
parent->setRoutingStatusLabel(routingStatusLabel);
762
RoutingStatus routingStatus;
763
routingStatus.zero();
764
routingStatusSlot(parent->graphicsView(), routingStatus);
765
return routingStatusLabel;
768
SketchToolButton *MainWindow::createRotateButton(SketchAreaWidget *parent) {
769
QList<QAction*> rotateMenuActions;
770
rotateMenuActions << m_rotate45ccwAct << m_rotate90ccwAct << m_rotate180Act << m_rotate90cwAct << m_rotate45cwAct;
771
SketchToolButton * rotateButton = new SketchToolButton("Rotate",parent, rotateMenuActions);
772
rotateButton->setDefaultAction(m_rotate90ccwAct);
773
rotateButton->setText(tr("Rotate"));
775
m_rotateButtons << rotateButton;
779
SketchToolButton *MainWindow::createShareButton(SketchAreaWidget *parent) {
780
SketchToolButton *shareButton = new SketchToolButton("Share",parent, m_shareOnlineAct);
781
shareButton->setText(tr("Share"));
782
shareButton->setEnabledIcon(); // seems to need this to display button icon first time
786
SketchToolButton *MainWindow::createFlipButton(SketchAreaWidget *parent) {
787
QList<QAction*> flipMenuActions;
788
flipMenuActions << m_flipHorizontalAct << m_flipVerticalAct;
789
SketchToolButton *flipButton = new SketchToolButton("Flip",parent, flipMenuActions);
790
flipButton->setText(tr("Flip"));
792
m_flipButtons << flipButton;
796
SketchToolButton *MainWindow::createAutorouteButton(SketchAreaWidget *parent) {
797
SketchToolButton *autorouteButton = new SketchToolButton("Autoroute",parent, m_autorouteAct);
798
autorouteButton->setText(tr("Autoroute"));
800
return autorouteButton;
803
SketchToolButton *MainWindow::createOrderFabButton(SketchAreaWidget *parent) {
804
SketchToolButton *orderFabButton = new SketchToolButton("Order",parent, m_orderFabAct);
805
orderFabButton->setText(tr("Order PCB"));
806
orderFabButton->setEnabledIcon(); // seems to need this to display button icon first time
808
return orderFabButton;
811
QWidget *MainWindow::createActiveLayerButton(SketchAreaWidget *parent)
813
QList<QAction *> actions;
814
actions << m_activeLayerBothAct << m_activeLayerBottomAct << m_activeLayerTopAct;
816
m_activeLayerButtonWidget = new QStackedWidget;
817
m_activeLayerButtonWidget->setMaximumWidth(90);
819
SketchToolButton * button = new SketchToolButton("ActiveLayer", parent, actions);
820
button->setDefaultAction(m_activeLayerBottomAct);
821
button->setText(tr("Both Layers"));
822
m_activeLayerButtonWidget->addWidget(button);
824
button = new SketchToolButton("ActiveLayerB", parent, actions);
825
button->setDefaultAction(m_activeLayerTopAct);
826
button->setText(tr("Bottom Layer"));
827
m_activeLayerButtonWidget->addWidget(button);
829
button = new SketchToolButton("ActiveLayerT", parent, actions);
830
button->setDefaultAction(m_activeLayerBothAct);
831
button->setText(tr("Top Layer"));
832
m_activeLayerButtonWidget->addWidget(button);
834
return m_activeLayerButtonWidget;
837
SketchToolButton *MainWindow::createNoteButton(SketchAreaWidget *parent) {
838
SketchToolButton *noteButton = new SketchToolButton("Notes",parent, m_addNoteAct);
839
noteButton->setText(tr("Add a note"));
840
noteButton->setEnabledIcon(); // seems to need this to display button icon first time
844
SketchToolButton *MainWindow::createExportEtchableButton(SketchAreaWidget *parent) {
845
QList<QAction*> actions;
846
actions << m_exportEtchablePdfAct << m_exportEtchableSvgAct << m_exportGerberAct;
847
SketchToolButton *exportEtchableButton = new SketchToolButton("Diy",parent, actions);
848
exportEtchableButton->setDefaultAction(m_exportEtchablePdfAct);
849
exportEtchableButton->setText(tr("Export for PCB"));
850
exportEtchableButton->setEnabledIcon(); // seems to need this to display button icon first time
851
return exportEtchableButton;
854
QWidget *MainWindow::createToolbarSpacer(SketchAreaWidget *parent) {
855
QFrame *toolbarSpacer = new QFrame(parent);
856
QHBoxLayout *spacerLayout = new QHBoxLayout(toolbarSpacer);
857
spacerLayout->addSpacerItem(new QSpacerItem(0,0,QSizePolicy::Expanding));
859
return toolbarSpacer;
862
QList<QWidget*> MainWindow::getButtonsForView(ViewIdentifierClass::ViewIdentifier viewId) {
863
QList<QWidget*> retval;
864
SketchAreaWidget *parent;
866
case ViewIdentifierClass::BreadboardView: parent = m_breadboardWidget; break;
867
case ViewIdentifierClass::SchematicView: parent = m_schematicWidget; break;
868
case ViewIdentifierClass::PCBView: parent = m_pcbWidget; break;
869
default: return retval;
871
retval << createShareButton(parent);
874
case ViewIdentifierClass::BreadboardView:
875
case ViewIdentifierClass::SchematicView:
876
retval << createNoteButton(parent);
881
retval << createRotateButton(parent);
883
case ViewIdentifierClass::BreadboardView:
884
retval << createFlipButton(parent);
886
case ViewIdentifierClass::SchematicView:
887
retval << createFlipButton(parent) << createToolbarSpacer(parent) << createAutorouteButton(parent);
889
case ViewIdentifierClass::PCBView:
890
retval << SketchAreaWidget::separator(parent)
891
<< createActiveLayerButton(parent)
892
<< createAutorouteButton(parent)
893
<< createExportEtchableButton(parent);
894
if (m_orderFabEnabled) {
895
retval << createOrderFabButton(parent);
902
retval << createRoutingStatusLabel(parent);
906
void MainWindow::updateZoomSlider(double zoom) {
907
m_zoomSlider->setValue(zoom);
910
SketchAreaWidget *MainWindow::currentSketchArea() {
911
return dynamic_cast<SketchAreaWidget*>(m_currentGraphicsView->parent());
914
void MainWindow::updateZoomOptionsNoMatterWhat(double zoom) {
915
m_zoomSlider->setValue(zoom);
918
void MainWindow::updateViewZoom(double newZoom) {
919
m_comboboxChanged = true;
920
if(m_currentGraphicsView) m_currentGraphicsView->absoluteZoom(newZoom);
924
void MainWindow::createStatusBar()
926
m_statusBar->showMessage(tr("Ready"));
929
void MainWindow::tabWidget_currentChanged(int index) {
930
SketchAreaWidget * widgetParent = dynamic_cast<SketchAreaWidget *>(m_tabWidget->currentWidget());
931
if (widgetParent == NULL) return;
933
m_currentWidget = widgetParent;
935
if (m_locationLabel) {
936
m_locationLabel->setText("");
939
QStatusBar *sb = statusBar();
940
connect(sb, SIGNAL(messageChanged(const QString &)), m_statusBar, SLOT(showMessage(const QString &)));
941
widgetParent->addStatusBar(m_statusBar);
942
if(sb != m_statusBar) sb->hide();
944
if (m_breadboardGraphicsView) m_breadboardGraphicsView->setCurrent(false);
945
if (m_schematicGraphicsView) m_schematicGraphicsView->setCurrent(false);
946
if (m_pcbGraphicsView) m_pcbGraphicsView->setCurrent(false);
948
SketchWidget *widget = widgetParent->graphicsView();
950
if(m_currentGraphicsView) {
951
m_currentGraphicsView->saveZoom(m_zoomSlider->value());
953
m_currentGraphicsView,
954
SIGNAL(selectionChangedSignal()),
956
SLOT(updateTransformationActions())
959
m_currentGraphicsView = widget;
960
if (widget == NULL) return;
962
m_zoomSlider->setValue(m_currentGraphicsView->retrieveZoom());
965
m_currentGraphicsView, // don't connect directly to the scene here, connect to the widget's signal
966
SIGNAL(selectionChangedSignal()),
968
SLOT(updateTransformationActions())
971
updateActiveLayerButtons();
973
m_currentGraphicsView->setCurrent(true);
975
// !!!!!! hack alert !!!!!!!
976
// this item update loop seems to deal with a qt update bug:
977
// if one view is visible and you change something in another view,
978
// the change might not appear when you switch views until you move the item in question
979
foreach(QGraphicsItem * item, m_currentGraphicsView->items()) {
983
updateLayerMenu(true);
984
QList<QAction *> actions;
985
actions << m_showBreadboardAct << m_showSchematicAct << m_showPCBAct;
986
setActionsIcons(index, actions);
990
updateTransformationActions();
994
// triggers a signal to the navigator widget
995
m_navigators[index]->miniViewMousePressedSlot();
996
emit viewSwitched(index);
998
if (m_helper == NULL) {
999
m_showInViewHelpAct->setChecked(false);
1002
m_showInViewHelpAct->setChecked(m_helper->helpVisible(m_tabWidget->currentIndex()));
1005
m_currentGraphicsView->updateInfoView();
1007
// update issue with 4.5.1?: is this still valid (4.6.x?)
1008
m_currentGraphicsView->updateConnectors();
1012
void MainWindow::setActionsIcons(int index, QList<QAction *> & actions) {
1013
for (int i = 0; i < actions.count(); i++) {
1014
actions[i]->setIcon(index == i ? m_dotIcon : m_emptyIcon);
1018
void MainWindow::closeEvent(QCloseEvent *event) {
1024
if (m_programWindow) {
1025
m_programWindow->close();
1026
if (m_programWindow->isVisible()) {
1032
if (!m_closeSilently) {
1033
bool whatWithAliens = whatToDoWithAlienFiles();
1034
if(!beforeClosing() || !whatWithAliens ||!m_binManager->beforeClosing()) {
1039
if(whatWithAliens && m_binManager->hasAlienParts()) {
1040
m_binManager->createIfMyPartsNotExists();
1044
DebugDialog::debug(QString("top level windows: %1").arg(QApplication::topLevelWidgets().size()));
1046
foreach (QWidget * widget, QApplication::topLevelWidgets()) {
1047
QMenu * menu = qobject_cast<QMenu *>(widget);
1049
continue; // QMenus are always top level widgets, even if they have parents...
1051
DebugDialog::debug(QString("top level widget %1 %2 %3")
1052
.arg(widget->metaObject()->className())
1053
.arg(widget->windowTitle())
1054
.arg(widget->toolTip())
1060
emit aboutToClose();
1063
foreach (QWidget *widget, QApplication::topLevelWidgets()) {
1064
if (widget == this) continue;
1065
if (qobject_cast<QMainWindow *>(widget) == NULL) continue;
1071
DebugDialog::closeDebug();
1075
settings.setValue("main/state",saveState());
1076
settings.setValue("main/geometry",saveGeometry());
1078
QMainWindow::closeEvent(event);
1081
bool MainWindow::whatToDoWithAlienFiles() {
1082
if (m_alienFiles.size() > 0) {
1083
QMessageBox::StandardButton reply;
1084
reply = QMessageBox::question(this, tr("Save %1").arg(QFileInfo(m_fwFilename).baseName()),
1086
.arg(QFileInfo(m_fwFilename).baseName()),
1087
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
1088
// TODO: translate button text
1089
if (reply == QMessageBox::Yes) {
1091
} else if (reply == QMessageBox::No) {
1092
foreach(QString pathToRemove, m_alienFiles) {
1093
QFile::remove(pathToRemove);
1095
m_alienFiles.clear();
1096
recoverBackupedFiles();
1098
emit alienPartsDismissed();
1109
void MainWindow::acceptAlienFiles() {
1110
m_alienFiles.clear();
1113
void MainWindow::saveDocks()
1115
for (int i = 0; i < children().count(); i++) {
1116
FDockWidget * dock = qobject_cast<FDockWidget *>(children()[i]);
1117
if (dock == NULL) continue;
1119
//DebugDialog::debug(QString("saving dock %1").arg(dock->windowTitle()));
1122
if (dock->isFloating() && dock->isVisible()) {
1123
//DebugDialog::debug(QString("hiding dock %1").arg(dock->windowTitle()));
1129
void MainWindow::restoreDocks() {
1130
for (int i = 0; i < children().count(); i++) {
1131
FDockWidget * dock = qobject_cast<FDockWidget *>(children()[i]);
1132
if (dock == NULL) continue;
1134
// DebugDialog::debug(QString("restoring dock %1").arg(dock->windowTitle()));
1135
dock->restoreState();
1140
ModelPart *MainWindow::loadPartFromFile(const QString& newPartPath, bool connectorsChanged) {
1141
if(connectorsChanged && wannaRestart()) {
1142
QApplication::exit(RestartNeeded);
1145
ModelPart* mp = m_refModel->addPart(newPartPath, true, true);
1146
m_refModel->addPart(mp,true);
1151
bool MainWindow::wannaRestart() {
1152
QMessageBox::StandardButton btn = QMessageBox::question(this,
1153
tr("Updating existing part"),
1154
tr("Some connectors have changed.\n"
1155
"In order to see the changes, you have to restart fritzing.\n"
1156
"Do you want to restart now?"
1158
QMessageBox::Yes|QMessageBox::No
1160
bool result = (btn == QMessageBox::Yes);
1162
m_restarting = true;
1164
m_restarting = false;
1169
void MainWindow::loadPart(const QString &newPartPath, long partsEditorId, bool connectorsChanged) {
1170
ModelPart * modelPart = loadPartFromFile(newPartPath, connectorsChanged);
1171
if(modelPart && modelPart->hasViewIdentifier(ViewIdentifierClass::IconView)) {
1172
if(m_binsWithPartsEditorRequests.contains(partsEditorId)
1173
&& !m_binsWithPartsEditorRequests[partsEditorId]->currentBinIsCore() ) {
1174
m_binManager->addPartTo(m_binsWithPartsEditorRequests[partsEditorId],modelPart, true);
1176
m_binManager->addNewPart(modelPart);
1178
m_infoView->reloadContent(m_currentGraphicsView);
1182
bool MainWindow::eventFilter(QObject *object, QEvent *event) {
1183
if (object == this &&
1184
(event->type() == QEvent::KeyPress
1185
// || event->type() == QEvent::KeyRelease
1186
|| event->type() == QEvent::ShortcutOverride))
1188
//DebugDialog::debug(QString("event filter %1").arg(event->type()) );
1192
// On the mac, the first time the delete key is pressed, to be used as a shortcut for QAction m_deleteAct,
1193
// for some reason, the enabling of the m_deleteAct in UpdateEditMenu doesn't "take" until the next time the event loop is processed
1194
// Thereafter, the delete key works as it should.
1195
// So this call to processEvents() makes sure m_deleteAct is enabled.
1196
ProcessEventBlocker::processEvents();
1199
return QMainWindow::eventFilter(object, event);
1202
const QString MainWindow::untitledFileName() {
1203
return UntitledSketchName;
1206
int &MainWindow::untitledFileCount() {
1207
return UntitledSketchIndex;
1210
const QString MainWindow::fileExtension() {
1211
return FritzingBundleExtension;
1214
const QString MainWindow::defaultSaveFolder() {
1215
return FolderUtils::openSaveFolder();
1218
bool MainWindow::undoStackIsEmpty() {
1219
return m_undoStack->count() == 0;
1222
void MainWindow::setInfoViewOnHover(bool infoViewOnHover) {
1223
m_breadboardGraphicsView->setInfoViewOnHover(infoViewOnHover);
1224
m_schematicGraphicsView->setInfoViewOnHover(infoViewOnHover);
1225
m_pcbGraphicsView->setInfoViewOnHover(infoViewOnHover);
1227
m_binManager->setInfoViewOnHover(infoViewOnHover);
1230
void MainWindow::loadBundledSketch(const QString &fileName, bool addToRecent, bool setAsLastOpened) {
1232
if(!FolderUtils::unzipTo(fileName, m_fzzFolder)) {
1233
QMessageBox::warning(
1236
tr("Unable to open '%1'").arg(fileName)
1242
QDir dir(m_fzzFolder);
1243
QString binFileName = dir.absoluteFilePath(QFileInfo(BinManager::TempPartsBinTemplateLocation).fileName());
1244
m_binManager->setTempPartsBinLocation(binFileName);
1245
FolderUtils::copyBin(binFileName, BinManager::TempPartsBinTemplateLocation);
1247
QStringList namefilters;
1248
namefilters << "*"+FritzingSketchExtension;
1249
QFileInfoList entryInfoList = dir.entryInfoList(namefilters);
1250
if (entryInfoList.count() == 0) {
1251
QMessageBox::warning(
1254
tr("No Sketch found in '%1'").arg(fileName)
1260
QFileInfo sketchInfo = entryInfoList[0];
1262
QString sketchName = dir.absoluteFilePath(sketchInfo.fileName());
1264
namefilters.clear();
1265
namefilters << "*" + FritzingPartExtension;
1266
entryInfoList = dir.entryInfoList(namefilters);
1267
QRegExp moduleIDFinder("moduleId=\"([^\"]+)");
1269
namefilters.clear();
1270
namefilters << "*.svg";
1271
QFileInfoList svgEntryInfoList = dir.entryInfoList(namefilters);
1273
bool addedToTemp = false;
1275
foreach (QFileInfo fzpInfo, entryInfoList) {
1276
QFile file(dir.absoluteFilePath(fzpInfo.fileName()));
1277
if (!file.open(QFile::ReadOnly)) {
1278
DebugDialog::debug(QString("unable to open %1: %2").arg(file.fileName()));
1283
// TODO: could be more efficient by using a streamreader
1284
QString fzp = file.readAll();
1286
int ix = fzp.indexOf(moduleIDFinder);
1288
DebugDialog::debug(QString("unable to find module id in %1: %2").arg(file.fileName()).arg(fzp));
1292
QString moduleID = moduleIDFinder.cap(1);
1293
ModelPart * mp = m_paletteModel->retrieveModelPart(moduleID);
1296
if (!doc.setContent(fzp)) {
1297
DebugDialog::debug(QString("unable to parse fzp in %1: %2").arg(file.fileName()).arg(fzp));
1302
mp = copyToPartsFolder(fzpInfo, false, false, PartFactory::folderPath(), "contrib");
1304
DebugDialog::debug(QString("unable to create model part in %1: %2").arg(file.fileName()).arg(fzp));
1308
QDomElement root = doc.documentElement();
1309
QDomElement views = root.firstChildElement("views");
1310
QDomElement view = views.firstChildElement();
1311
while (!view.isNull()) {
1312
QDomElement layers = view.firstChildElement("layers");
1313
QString path = layers.attribute("image", "");
1314
if (!path.isEmpty()) {
1315
int ix = path.indexOf("/");
1316
path = path.mid(ix + 1);
1317
for (int jx = svgEntryInfoList.count() - 1; jx >= 0; jx--) {
1318
QFileInfo svgInfo = svgEntryInfoList.at(jx);
1319
if (svgInfo.fileName().contains(path)) {
1320
copyToSvgFolder(svgInfo, false, PartFactory::folderPath(), "contrib");
1321
svgEntryInfoList.removeAt(jx);
1325
view = view.nextSiblingElement();
1331
m_binManager->addToTempPartsBin(mp);
1336
m_binManager->hideTempPartsBin();
1339
// the bundled itself
1340
this->mainLoad(sketchName, "");
1341
setCurrentFile(fileName, addToRecent, setAsLastOpened);
1344
void MainWindow::loadBundledNonAtomicEntity(const QString &fileName, Bundler* bundler, bool addToBin, bool dontAsk) {
1345
QDir destFolder = QDir::temp();
1347
FolderUtils::createFolderAnCdIntoIt(destFolder, FolderUtils::getRandText());
1348
QString unzipDirPath = destFolder.path();
1350
if(!FolderUtils::unzipTo(fileName, unzipDirPath)) {
1351
QMessageBox::warning(
1354
tr("Unable to open shareable %1").arg(fileName)
1357
// gotta return now, or loadBundledSketchAux will crash
1361
QDir unzipDir(unzipDirPath);
1363
if (bundler->preloadBundledAux(unzipDir, dontAsk)) {
1364
QList<ModelPart*> mps = moveToPartsFolder(unzipDir,this,addToBin,true,FolderUtils::getUserDataStorePath("parts"),"contrib");
1365
// the bundled itself
1366
bundler->loadBundledAux(unzipDir,mps);
1369
FolderUtils::rmdir(unzipDirPath);
1373
void MainWindow::loadBundledPartFromWeb() {
1374
QMainWindow *mw = new QMainWindow();
1375
QString url = "http://localhost:8081/parts_gen/choose";
1376
QWebView *view = new QWebView(mw);
1377
mw->setCentralWidget(view);
1378
view->setUrl(QUrl(url));
1384
ModelPart* MainWindow::loadBundledPart(const QString &fileName, bool addToBin) {
1385
QDir destFolder = QDir::temp();
1387
FolderUtils::createFolderAnCdIntoIt(destFolder, FolderUtils::getRandText());
1388
QString unzipDirPath = destFolder.path();
1390
if(!FolderUtils::unzipTo(fileName, unzipDirPath)) {
1391
QMessageBox::warning(
1394
tr("Unable to open shareable part %1").arg(fileName)
1399
QDir unzipDir(unzipDirPath);
1401
QList<ModelPart*> mps = moveToPartsFolder(unzipDir, this, addToBin, true, FolderUtils::getUserDataStorePath("parts"), "contrib");
1402
if (mps.count()!=1) {
1403
// if this fails, that means that the bundled was wrong
1404
QMessageBox::warning(
1407
tr("Unable to read shareable part %1").arg(fileName)
1412
FolderUtils::rmdir(unzipDirPath);
1417
void MainWindow::saveBundledPart(const QString &moduleId) {
1418
QString modIdToExport;
1421
if(moduleId.isEmpty()) {
1422
if (m_currentGraphicsView == NULL) return;
1423
PaletteItem *selectedPart = m_currentGraphicsView->getSelectedPart();
1424
mp = selectedPart->modelPart();
1425
modIdToExport = mp->moduleID();
1427
modIdToExport = moduleId;
1428
mp = m_refModel->retrieveModelPart(moduleId);
1430
QString partTitle = mp->title();
1433
QString path = defaultSaveFolder()+"/"+partTitle+FritzingBundledPartExtension;
1434
QString bundledFileName = FolderUtils::getSaveFileName(
1436
tr("Specify a file name"),
1438
tr("Fritzing Part (*%1)").arg(FritzingBundledPartExtension),
1442
if (bundledFileName.isEmpty()) return; // Cancel pressed
1444
if(!alreadyHasExtension(bundledFileName, FritzingBundledPartExtension)) {
1445
bundledFileName += FritzingBundledPartExtension;
1448
QDir destFolder = QDir::temp();
1450
FolderUtils::createFolderAnCdIntoIt(destFolder, FolderUtils::getRandText());
1451
QString dirToRemove = destFolder.path();
1453
QString aux = QFileInfo(bundledFileName).fileName();
1454
QString destPartPath = // remove the last "z" from the extension
1455
destFolder.path()+"/"+aux.left(aux.size()-1);
1456
DebugDialog::debug("saving part temporarily to "+destPartPath);
1458
//bool wasModified = isWindowModified();
1459
//QString prevFileName = m_fileName;
1460
//saveAsAux(destPartPath);
1461
//m_fileName = prevFileName;
1462
//setWindowModified(wasModified);
1465
saveBundledAux(mp, destFolder);
1467
QStringList skipSuffixes;
1468
if(!FolderUtils::createZipAndSaveTo(destFolder, bundledFileName, skipSuffixes)) {
1469
QMessageBox::warning(
1472
tr("Unable to export %1 to shareable sketch").arg(bundledFileName)
1476
FolderUtils::rmdir(dirToRemove);
1479
QStringList MainWindow::saveBundledAux(ModelPart *mp, const QDir &destFolder) {
1481
QString partPath = mp->modelPartShared()->path();
1482
QFile file(partPath);
1483
QString fn = ZIP_PART + QFileInfo(partPath).fileName();
1485
file.copy(destFolder.path()+"/"+fn);
1487
QList<ViewIdentifierClass::ViewIdentifier> identifiers;
1488
identifiers << ViewIdentifierClass::IconView << ViewIdentifierClass::BreadboardView << ViewIdentifierClass::SchematicView << ViewIdentifierClass::PCBView;
1489
foreach (ViewIdentifierClass::ViewIdentifier viewIdentifier, identifiers) {
1490
QString basename = mp->hasBaseNameFor(viewIdentifier);
1491
if (basename.isEmpty()) continue;
1493
QString filename = ItemBase::getSvgFilename(mp, basename);
1494
if (filename.isEmpty()) continue;
1496
QFile file(filename);
1497
basename.replace("/", ".");
1498
QString fn = ZIP_SVG + basename;
1500
file.copy(destFolder.path()+"/"+fn);
1506
QList<ModelPart*> MainWindow::moveToPartsFolder(QDir &unzipDir, MainWindow* mw, bool addToBin, bool addToAlien, const QString & prefixFolder, const QString &destFolder) {
1507
QStringList namefilters;
1508
QList<ModelPart*> retval;
1511
throw "MainWindow::moveToPartsFolder mainwindow missing";
1515
namefilters << ZIP_SVG+"*";
1516
foreach(QFileInfo file, unzipDir.entryInfoList(namefilters)) { // svg files
1517
//DebugDialog::debug("unzip svg " + file.absoluteFilePath());
1518
mw->copyToSvgFolder(file, addToAlien, prefixFolder, destFolder);
1521
namefilters.clear();
1522
namefilters << ZIP_PART+"*";
1524
foreach(QFileInfo file, unzipDir.entryInfoList(namefilters)) { // part files
1525
//DebugDialog::debug("unzip part " + file.absoluteFilePath());
1526
retval << mw->copyToPartsFolder(file, addToBin, addToAlien, prefixFolder, destFolder);
1533
void MainWindow::copyToSvgFolder(const QFileInfo& file, bool addToAlien, const QString & prefixFolder, const QString &destFolder) {
1534
QFile svgfile(file.filePath());
1535
// let's make sure that we remove just the suffix
1536
QString fileName = file.fileName().remove(QRegExp("^"+ZIP_SVG));
1537
QString viewFolder = fileName.left(fileName.indexOf("."));
1538
fileName.remove(0, viewFolder.length() + 1);
1540
QString destFilePath =
1541
prefixFolder+"/svg/"+destFolder+"/"+viewFolder+"/"+fileName;
1543
backupExistingFileIfExists(destFilePath);
1544
if(svgfile.copy(destFilePath)) {
1546
m_alienFiles << destFilePath;
1551
ModelPart* MainWindow::copyToPartsFolder(const QFileInfo& file, bool addToBin, bool addToAlien, const QString & prefixFolder, const QString &destFolder) {
1552
QFile partfile(file.filePath());
1553
// let's make sure that we remove just the suffix
1554
QString destFilePath =
1555
prefixFolder+"/"+destFolder+"/"+file.fileName().remove(QRegExp("^"+ZIP_PART));
1557
backupExistingFileIfExists(destFilePath);
1558
if(partfile.copy(destFilePath)) {
1560
m_alienFiles << destFilePath;
1561
m_alienPartsMsg = tr("Do you want to keep the imported parts?");
1564
ModelPart *mp = m_refModel->loadPart(destFilePath, true, false);
1568
m_binManager->addToContrib(mp);
1574
void MainWindow::binSaved(bool hasPartsFromBundled) {
1575
if(hasPartsFromBundled) {
1576
// the bin will need those parts, so just keep them
1577
m_alienFiles.clear();
1586
void MainWindow::backupExistingFileIfExists(const QString &destFilePath) {
1587
if(QFileInfo(destFilePath).exists()) {
1588
if(m_tempDir.path() == ".") {
1589
m_tempDir = QDir::temp();
1590
FolderUtils::createFolderAnCdIntoIt(m_tempDir, FolderUtils::getRandText());
1591
DebugDialog::debug("debug folder for overwritten files: "+m_tempDir.path());
1594
QString fileBackupName = QFileInfo(destFilePath).fileName();
1595
m_filesReplacedByAlienOnes << destFilePath;
1596
QFile file(destFilePath);
1597
bool alreadyExists = file.exists();
1598
file.copy(m_tempDir.path()+"/"+fileBackupName);
1601
file.remove(destFilePath);
1606
void MainWindow::recoverBackupedFiles() {
1607
foreach(QString originalFilePath, m_filesReplacedByAlienOnes) {
1608
QFile file(m_tempDir.path()+"/"+QFileInfo(originalFilePath).fileName());
1609
if(file.exists(originalFilePath)) {
1612
file.copy(originalFilePath);
1617
void MainWindow::resetTempFolder() {
1618
if(m_tempDir.path() != ".") {
1619
FolderUtils::rmdir(m_tempDir);
1620
m_tempDir = QDir::temp();
1622
m_filesReplacedByAlienOnes.clear();
1625
void MainWindow::routingStatusSlot(SketchWidget * sketchWidget, const RoutingStatus & routingStatus) {
1626
m_routingStatus = routingStatus;
1628
if (routingStatus.m_netCount == 0) {
1629
theText = tr("No connections to route");
1630
} else if (routingStatus.m_netCount == routingStatus.m_netRoutedCount) {
1631
if (routingStatus.m_jumperItemCount == 0) {
1632
theText = tr("Routing completed");
1635
theText = tr("Routing completed using %n jumper part(s)", "", routingStatus.m_jumperItemCount);
1638
theText = tr("%1 of %2 nets routed - %n connector(s) still to be routed", "", routingStatus.m_connectorsLeftToRoute)
1639
.arg(routingStatus.m_netRoutedCount)
1640
.arg(routingStatus.m_netCount);
1643
dynamic_cast<SketchAreaWidget *>(sketchWidget->parent())->routingStatusLabel()->setLabelText(theText);
1648
void MainWindow::applyReadOnlyChange(bool isReadOnly) {
1649
Q_UNUSED(isReadOnly);
1650
//m_saveAct->setDisabled(isReadOnly);
1653
void MainWindow::currentNavigatorChanged(MiniViewContainer * miniView)
1655
int index = m_navigators.indexOf(miniView);
1656
if (index < 0) return;
1658
int oldIndex = m_tabWidget->currentIndex();
1659
if (oldIndex == index) return;
1661
this->m_tabWidget->setCurrentIndex(index);
1664
void MainWindow::viewSwitchedTo(int viewIndex) {
1665
m_tabWidget->setCurrentIndex(viewIndex);
1668
const QString MainWindow::fritzingTitle() {
1669
if (m_currentGraphicsView == NULL) {
1670
return FritzingWindow::fritzingTitle();
1673
QString fritzing = FritzingWindow::fritzingTitle();
1674
return tr("%1 - [%2]").arg(fritzing).arg(m_currentGraphicsView->viewName());
1677
QAction *MainWindow::raiseWindowAction() {
1678
return m_raiseWindowAct;
1681
void MainWindow::raiseAndActivate() {
1686
QTimer::singleShot(20, this, SLOT(activateWindowAux()));
1689
void MainWindow::activateWindowAux() {
1693
void MainWindow::updateRaiseWindowAction() {
1695
QFileInfo fileInfo(m_fwFilename);
1696
if(fileInfo.exists()) {
1697
int lastSlashIdx = m_fwFilename.lastIndexOf("/");
1698
int beforeLastSlashIdx = m_fwFilename.left(lastSlashIdx).lastIndexOf("/");
1699
actionText = beforeLastSlashIdx > -1 && lastSlashIdx > -1 ? "..." : "";
1700
actionText += m_fwFilename.right(m_fwFilename.size()-beforeLastSlashIdx-1);
1702
actionText = m_fwFilename;
1704
m_raiseWindowAct->setText(actionText);
1705
m_raiseWindowAct->setToolTip(m_fwFilename);
1706
m_raiseWindowAct->setStatusTip("raise \""+m_fwFilename+"\" window");
1709
QSizeGrip *MainWindow::sizeGrip() {
1713
QStatusBar *MainWindow::realStatusBar() {
1717
void MainWindow::moveEvent(QMoveEvent * event) {
1718
FritzingWindow::moveEvent(event);
1719
emit mainWindowMoved(this);
1722
bool MainWindow::event(QEvent * e) {
1723
switch (e->type()) {
1724
case QEvent::WindowActivate:
1725
emit changeActivationSignal(true, this);
1727
case QEvent::WindowDeactivate:
1728
emit changeActivationSignal(false, this);
1733
return FritzingWindow::event(e);
1736
void MainWindow::resizeEvent(QResizeEvent * event) {
1737
m_sizeGrip->rearrange();
1738
FritzingWindow::resizeEvent(event);
1741
void MainWindow::showInViewHelp() {
1743
if (m_helper == NULL) {
1744
m_helper = new Helper(this, true);
1748
bool toggle = !m_helper->helpVisible(m_tabWidget->currentIndex());
1749
showAllFirstTimeHelp(toggle);
1752
m_helper->toggleHelpVisibility(m_tabWidget->currentIndex());
1755
m_showInViewHelpAct->setChecked(m_helper->helpVisible(m_tabWidget->currentIndex()));
1759
void MainWindow::showAllFirstTimeHelp(bool show) {
1761
for (int i = 0; i < 3; i++) {
1762
m_helper->setHelpVisibility(i, show);
1765
m_showInViewHelpAct->setChecked(show);
1768
void MainWindow::enableCheckUpdates(bool enabled)
1770
if (m_checkForUpdatesAct != NULL) {
1771
m_checkForUpdatesAct->setEnabled(enabled);
1776
void MainWindow::swapSelectedDelay(const QString & family, const QString & prop, QMap<QString, QString> & currPropsMap, ItemBase * itemBase)
1779
m_swapTimer.setAll(family, prop, currPropsMap, itemBase);
1780
m_swapTimer.start();
1783
void MainWindow::swapSelectedTimeout()
1785
if (sender() == &m_swapTimer) {
1786
QMap<QString, QString> map = m_swapTimer.propsMap();
1787
swapSelectedMap(m_swapTimer.family(), m_swapTimer.prop(), map, m_swapTimer.itemBase());
1791
void MainWindow::swapSelectedMap(const QString & family, const QString & prop, QMap<QString, QString> & currPropsMap, ItemBase * itemBase)
1793
if (itemBase == NULL) return;
1795
QString generatedModuleID = currPropsMap.value("moduleID");
1797
if (generatedModuleID.isEmpty()) {
1798
if ((family.compare("logo") == 0 || family.compare("pad") == 0) && prop.compare("layer") == 0) {
1799
QString value = currPropsMap.value(prop);
1800
if (value.contains("1") && m_currentGraphicsView->boardLayers() == 1) {
1801
QMessageBox::warning(
1803
tr("No copper top layer"),
1804
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.")
1811
if (generatedModuleID.isEmpty()) {
1812
if (family.compare("Prototyping Board", Qt::CaseInsensitive) == 0) {
1813
if (prop.compare("size", Qt::CaseInsensitive) == 0 || prop.compare("type", Qt::CaseInsensitive) == 0) {
1814
QString size = currPropsMap.value("size");
1815
QString type = currPropsMap.value("type");
1816
if (type.compare("perfboard", Qt::CaseInsensitive) == 0) {
1817
generatedModuleID = Perfboard::genModuleID(currPropsMap);
1819
else if (type.compare("stripboard", Qt::CaseInsensitive) == 0) {
1820
generatedModuleID = Stripboard::genModuleID(currPropsMap);
1826
if (!generatedModuleID.isEmpty()) {
1827
ModelPart * modelPart = m_refModel->retrieveModelPart(generatedModuleID);
1828
if (modelPart == NULL) {
1829
if (!m_refModel->genFZP(generatedModuleID, m_refModel)) {
1834
swapSelectedAux(itemBase->layerKinChief(), generatedModuleID);
1838
if ((prop.compare("package", Qt::CaseSensitive) != 0) && swapSpecial(prop, currPropsMap)) {
1842
foreach (QString key, currPropsMap.keys()) {
1843
QString value = currPropsMap.value(key);
1844
m_refModel->recordProperty(key, value);
1847
QString moduleID = m_refModel->retrieveModuleIdWith(family, prop, true);
1848
bool exactMatch = m_refModel->lastWasExactMatch();
1850
if(moduleID.isEmpty()) {
1851
QMessageBox::information(
1855
"No part with those characteristics.\n"
1856
"We're working to avoid this message, and only let you choose between properties that do exist")
1863
itemBase = itemBase->layerKinChief();
1866
AutoCloseMessageBox::showMessage(this, tr("No exactly matching part found; Fritzing chose the closest match."));
1869
swapSelectedAux(itemBase, moduleID);
1872
bool MainWindow::swapSpecial(const QString & theProp, QMap<QString, QString> & currPropsMap) {
1873
ItemBase * itemBase = m_infoView->currentItem();
1874
QString pinSpacing, resistance;
1877
foreach (QString key, currPropsMap.keys()) {
1878
if (key.compare("layers", Qt::CaseInsensitive) == 0) {
1879
if (!Board::isBoard(itemBase)) continue;
1881
QString value = currPropsMap.value(key, "");
1882
if (value.compare(Board::OneLayerTranslated) == 0) {
1885
else if (value.compare(Board::TwoLayersTranslated) == 0) {
1890
if (key.compare("resistance", Qt::CaseInsensitive) == 0) {
1891
resistance = currPropsMap.value(key);
1894
if (key.compare("pin spacing", Qt::CaseInsensitive) == 0) {
1895
pinSpacing = currPropsMap.value(key);
1901
currPropsMap.insert("layers", QString::number(layers));
1902
if (theProp.compare("layers") == 0) {
1903
QString msg = (layers == 1) ? tr("Change to single layer pcb") : tr("Change to two layer pcb");
1904
swapLayers(itemBase, layers, msg, true, SketchWidget::PropChangeDelay);
1910
if (!resistance.isEmpty() || !pinSpacing.isEmpty()) {
1911
if (theProp.contains("band", Qt::CaseInsensitive)) {
1912
// swap 4band for 5band or vice versa.
1916
Resistor * resistor = qobject_cast<Resistor *>(itemBase);
1917
if (resistor != NULL) {
1918
m_currentGraphicsView->setResistance(resistance, pinSpacing);
1926
void MainWindow::swapLayers(ItemBase * itemBase, int layers, const QString & msg, bool flip, int delay) {
1927
QUndoCommand* parentCommand = new QUndoCommand(msg);
1928
new CleanUpWiresCommand(m_breadboardGraphicsView, CleanUpWiresCommand::UndoOnly, parentCommand);
1929
m_pcbGraphicsView->swapLayers(itemBase, layers, flip, parentCommand);
1930
// need to defer execution so the content of the info view doesn't change during an event that started in the info view
1931
m_undoStack->waitPush(parentCommand, delay);
1934
void MainWindow::swapSelectedAux(ItemBase * itemBase, const QString & moduleID) {
1936
QUndoCommand* parentCommand = new QUndoCommand(tr("Swapped %1 with module %2").arg(itemBase->instanceTitle()).arg(moduleID));
1937
new CleanUpWiresCommand(m_breadboardGraphicsView, CleanUpWiresCommand::UndoOnly, parentCommand);
1938
swapSelectedAuxAux(itemBase, moduleID, itemBase->viewLayerSpec(), parentCommand);
1940
// need to defer execution so the content of the info view doesn't change during an event that started in the info view
1941
m_undoStack->waitPush(parentCommand, SketchWidget::PropChangeDelay);
1946
void MainWindow::swapBoardImageSlot(SketchWidget * sketchWidget, ItemBase * itemBase, const QString & filename, const QString & moduleID, bool addName) {
1948
QUndoCommand* parentCommand = new QUndoCommand(tr("Change image to %2").arg(filename));
1949
long newID = swapSelectedAuxAux(itemBase, moduleID, itemBase->viewLayerSpec(), parentCommand);
1951
LoadLogoImageCommand * cmd = new LoadLogoImageCommand(sketchWidget, newID, "", QSizeF(0,0), filename, filename, addName, parentCommand);
1954
// need to defer execution so the content of the info view doesn't change during an event that started in the info view
1955
m_undoStack->waitPush(parentCommand, SketchWidget::PropChangeDelay);
1959
void MainWindow::subSwapSlot(SketchWidget * sketchWidget, ItemBase * itemBase, const QString & newModuleID, ViewLayer::ViewLayerSpec viewLayerSpec, long & newID, QUndoCommand * parentCommand) {
1960
Q_UNUSED(sketchWidget);
1961
newID = swapSelectedAuxAux(itemBase, newModuleID, viewLayerSpec, parentCommand);
1964
long MainWindow::swapSelectedAuxAux(ItemBase * itemBase, const QString & moduleID, ViewLayer::ViewLayerSpec viewLayerSpec, QUndoCommand * parentCommand)
1966
long modelIndex = ModelPart::nextIndex();
1968
QList<SketchWidget *> sketchWidgets;
1970
// master view must go last, since it creates the delete command, and possibly has all the local props
1971
switch (itemBase->viewIdentifier()) {
1972
case ViewIdentifierClass::SchematicView:
1973
sketchWidgets << m_pcbGraphicsView << m_breadboardGraphicsView << m_schematicGraphicsView;
1975
case ViewIdentifierClass::PCBView:
1976
sketchWidgets << m_schematicGraphicsView << m_breadboardGraphicsView << m_pcbGraphicsView;
1979
sketchWidgets << m_schematicGraphicsView << m_pcbGraphicsView << m_breadboardGraphicsView;
1983
SwapThing swapThing;
1984
swapThing.firstTime = true;
1985
swapThing.itemBase = itemBase;
1986
swapThing.newModelIndex = modelIndex;
1987
swapThing.newModuleID = moduleID;
1988
swapThing.viewLayerSpec = viewLayerSpec;
1989
swapThing.parentCommand = parentCommand;
1992
for (int i = 0; i < 3; i++) {
1993
long tempID = sketchWidgets[i]->setUpSwap(swapThing, i == 2);
1994
if (newID == 0 && tempID != 0) newID = tempID;
2002
void MainWindow::svgMissingLayer(const QString & layername, const QString & path) {
2003
QMessageBox::warning(
2006
tr("Svg %1 is missing a '%2' layer. "
2007
"For more information on how to create a custom board shape, "
2008
"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>.")
2014
void MainWindow::addDefaultParts() {
2015
if (m_pcbGraphicsView == NULL) return;
2017
m_pcbGraphicsView->addDefaultParts();
2018
m_breadboardGraphicsView->addDefaultParts();
2019
m_schematicGraphicsView->addDefaultParts();
2022
MainWindow * MainWindow::newMainWindow(PaletteModel * paletteModel, ReferenceModel *refModel, const QString & displayPath, bool showProgress, bool lockFiles) {
2023
MainWindow * mw = new MainWindow(paletteModel, refModel, NULL);
2025
mw->showFileProgressDialog(displayPath);
2028
mw->init(paletteModel, refModel, lockFiles);
2033
void MainWindow::clearFileProgressDialog() {
2034
if (m_fileProgressDialog) {
2035
m_fileProgressDialog->close();
2036
delete m_fileProgressDialog;
2037
m_fileProgressDialog = NULL;
2041
void MainWindow::setFileProgressPath(const QString & path)
2043
if (m_fileProgressDialog) m_fileProgressDialog->setMessage(tr("loading %1").arg(path));
2046
FileProgressDialog * MainWindow::fileProgressDialog()
2048
return m_fileProgressDialog;
2051
void MainWindow::showFileProgressDialog(const QString & path) {
2052
m_fileProgressDialog = new FileProgressDialog(tr("Loading..."), 200, this);
2053
m_fileProgressDialog->setBinLoadingChunk(50);
2054
if (!path.isEmpty()) {
2055
setFileProgressPath(QFileInfo(path).fileName());
2058
setFileProgressPath(tr("new sketch"));
2062
const QString &MainWindow::selectedModuleID() {
2063
if(m_currentGraphicsView) {
2064
return m_currentGraphicsView->selectedModuleID();
2066
return ___emptyString___;
2070
void MainWindow::redrawSketch() {
2071
foreach (QGraphicsItem * item, m_currentGraphicsView->scene()->items()) {
2073
ConnectorItem * c = dynamic_cast<ConnectorItem *>(item);
2075
c->restoreColor(false, 0, true);
2080
void MainWindow::statusMessage(QString message, int timeout) {
2081
QStatusBar * sb = realStatusBar();
2083
sb->showMessage(message, timeout);
2087
void MainWindow::dropPaste(SketchWidget * sketchWidget) {
2088
Q_UNUSED(sketchWidget);
2092
void MainWindow::updateLayerMenuSlot() {
2093
updateLayerMenu(true);
2096
bool MainWindow::save() {
2097
bool result = FritzingWindow::save();
2100
settings.setValue("lastOpenSketch", m_fwFilename);
2105
bool MainWindow::saveAs() {
2106
bool result = false;
2107
if (m_fwFilename.endsWith(FritzingSketchExtension)) {
2108
result = FritzingWindow::saveAs(m_fwFilename + 'z', false);
2111
result = FritzingWindow::saveAs();
2115
settings.setValue("lastOpenSketch", m_fwFilename);
2120
void MainWindow::changeBoardLayers(int layers, bool doEmit) {
2123
updateActiveLayerButtons();
2124
m_currentGraphicsView->updateConnectors();
2127
void MainWindow::updateActiveLayerButtons() {
2128
int index = activeLayerIndex();
2129
bool enabled = index >= 0;
2131
m_activeLayerButtonWidget->setCurrentIndex(index);
2132
m_activeLayerButtonWidget->setVisible(enabled);
2134
m_activeLayerBothAct->setEnabled(enabled);
2135
m_activeLayerBottomAct->setEnabled(enabled);
2136
m_activeLayerTopAct->setEnabled(enabled);
2138
QList<QAction *> actions;
2139
actions << m_activeLayerBothAct << m_activeLayerBottomAct << m_activeLayerTopAct;
2140
setActionsIcons(index, actions);
2144
int MainWindow::activeLayerIndex()
2146
if (m_currentGraphicsView->boardLayers() == 2) {
2147
bool copper0Visible = m_currentGraphicsView->layerIsActive(ViewLayer::Copper0);
2148
bool copper1Visible = m_currentGraphicsView->layerIsActive(ViewLayer::Copper1);
2149
if (copper0Visible && copper1Visible) {
2152
else if (copper1Visible) {
2155
else if (copper0Visible) {
2164
* A slot for saving a copy of the current sketch to a temp location.
2165
* This should be called every X minutes as well as just before certain
2166
* events, such as saves, part imports, file export/printing. This relies
2167
* on the m_autosaveNeeded variable and the undoStack being dirty for
2168
* an autosave to be attempted.
2170
void MainWindow::backupSketch() {
2171
if (ProcessEventBlocker::isProcessing()) {
2172
// don't want to autosave during autorouting, for example
2176
if (m_autosaveNeeded && !m_undoStack->isClean()) {
2177
m_autosaveNeeded = false; // clear this now in case the save takes a really long time
2179
DebugDialog::debug(QString("%1 autosaved as %2").arg(m_fwFilename).arg(m_backupFileNameAndPath));
2180
statusBar()->showMessage(tr("Backing up '%1'").arg(m_fwFilename), 2000);
2181
ProcessEventBlocker::processEvents();
2183
connectStartSave(true);
2184
m_sketchModel->save(m_backupFileNameAndPath, false);
2185
connectStartSave(false);
2186
m_backingUp = false;
2191
* This function is used to trigger an autosave at the next autosave
2192
* timer event. It is connected to the QUndoStack::indexChanged(int)
2193
* signal so that any change to the undo stack triggers autosaves.
2194
* This function can be called independent of this signal and
2195
* still work properly.
2197
void MainWindow::autosaveNeeded(int index) {
2199
//DebugDialog::debug(QString("Triggering autosave"));
2200
m_autosaveNeeded = true;
2204
* delete the backup file when the undostack is clean.
2206
void MainWindow::undoStackCleanChanged(bool isClean) {
2207
DebugDialog::debug(QString("Clean status changed to %1").arg(isClean));
2209
QFile::remove(m_backupFileNameAndPath);
2213
void MainWindow::setAutosavePeriod(int minutes) {
2214
setAutosave(minutes, AutosaveEnabled);
2217
void MainWindow::setAutosaveEnabled(bool enabled) {
2218
setAutosave(AutosaveTimeoutMinutes, enabled);
2221
void MainWindow::setAutosave(int minutes, bool enabled) {
2222
AutosaveTimeoutMinutes = minutes;
2223
AutosaveEnabled = enabled;
2224
foreach (QWidget * widget, QApplication::topLevelWidgets()) {
2225
MainWindow * mainWindow = qobject_cast<MainWindow *>(widget);
2226
if (mainWindow == NULL) continue;
2228
mainWindow->m_autosaveTimer.stop();
2229
if (AutosaveEnabled) {
2230
// is there a way to get the current timer offset so that all the timers aren't running in sync?
2231
// or just add some random time...
2232
mainWindow->m_autosaveTimer.start(AutosaveTimeoutMinutes * 60 * 1000);
2237
bool MainWindow::hasLinkedProgramFiles(const QString & filename, QStringList & linkedProgramFiles)
2239
QFile file(filename);
2240
file.open(QFile::ReadOnly);
2241
QXmlStreamReader xml(&file);
2242
xml.setNamespaceProcessing(false);
2245
while (!xml.atEnd()) {
2246
switch (xml.readNext()) {
2247
case QXmlStreamReader::StartElement:
2248
if (xml.name().toString().compare("program") == 0) {
2249
linkedProgramFiles.append(xml.readElementText());
2252
if (xml.name().toString().compare("views") == 0) {
2256
if (xml.name().toString().compare("instances") == 0) {
2267
return linkedProgramFiles.count() > 0;
2270
QString MainWindow::getExtensionString() {
2271
return tr("Fritzing (*%1)").arg(fileExtension());
2274
QStringList MainWindow::getExtensions() {
2275
QStringList extensions;
2276
extensions.append(fileExtension());
2280
void MainWindow::firstTimeHelpHidden() {
2281
m_showInViewHelpAct->setChecked(false);
2284
void MainWindow::routingStatusLabelMousePress(QMouseEvent* event) {
2285
routingStatusLabelMouse(event, true);
2288
void MainWindow::routingStatusLabelMouseRelease(QMouseEvent* event) {
2289
routingStatusLabelMouse(event, false);
2292
void MainWindow::routingStatusLabelMouse(QMouseEvent*, bool show) {
2293
if (show) DebugDialog::debug("-------");
2295
QSet<ConnectorItem *> toShow;
2296
foreach (QGraphicsItem * item, m_currentGraphicsView->scene()->items()) {
2297
VirtualWire * vw = dynamic_cast<VirtualWire *>(item);
2298
if (vw == NULL) continue;
2300
foreach (ConnectorItem * connectorItem, vw->connector0()->connectedToItems()) {
2301
toShow.insert(connectorItem);
2303
foreach (ConnectorItem * connectorItem, vw->connector1()->connectedToItems()) {
2304
toShow.insert(connectorItem);
2307
foreach (ConnectorItem * connectorItem, toShow) {
2309
DebugDialog::debug(QString("unrouted %1 %2 %3 %4")
2310
.arg(connectorItem->attachedToInstanceTitle())
2311
.arg(connectorItem->attachedToID())
2312
.arg(connectorItem->attachedTo()->title())
2313
.arg(connectorItem->connectorSharedName()));
2316
if (connectorItem->isActive() && connectorItem->isVisible() && !connectorItem->hidden()) {
2317
connectorItem->showEqualPotential(show);
2320
connectorItem = connectorItem->getCrossLayerConnectorItem();
2321
if (connectorItem) connectorItem->showEqualPotential(show);
2326
void MainWindow::setReportMissingModules(bool b) {
2327
if (m_sketchModel) {
2328
m_sketchModel->setReportMissingModules(b);
2332
void MainWindow::warnSMD(const QString & moduleID) {
2334
ModelPart * mp = m_refModel->retrieveModelPart(moduleID);
2335
if (mp == NULL) return;
2337
if (!mp->flippedSMD()) return;
2339
if (m_pcbGraphicsView->routeBothSides()) {
2340
if (!m_pcbGraphicsView->layerIsActive(ViewLayer::Copper1)) {
2346
if (m_smdOneSideWarningGiven) return;
2349
ItemBase * board = m_pcbGraphicsView->findSelectedBoard(boardCount);
2350
if (board == NULL) return;
2352
m_smdOneSideWarningGiven = true;
2353
// don't want to trigger the message box and subsequent swap from within the original event
2354
QTimer::singleShot(15, this, SLOT(warnSMDReally()));
2357
void MainWindow::warnSMDReally()
2359
QMessageBox messageBox(this);
2360
messageBox.setWindowTitle(tr("Using SMD parts"));
2361
messageBox.setInformativeText(tr("When using SMD parts, a double-sided board is usually desired. "
2362
"On the default single-sided board, SMD parts will end up on the back of the board."));
2363
messageBox.setText(tr("Do you want to swap to a double-sided board now?"));
2364
messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
2365
messageBox.setDefaultButton(QMessageBox::Yes);
2366
messageBox.setIcon(QMessageBox::Information);
2367
messageBox.setWindowModality(Qt::WindowModal);
2368
messageBox.setButtonText(QMessageBox::Yes, tr("Swap"));
2369
messageBox.setButtonText(QMessageBox::No, tr("Don't Swap"));
2370
messageBox.button(QMessageBox::No)->setShortcut(tr("Ctrl+D"));
2372
int ret = messageBox.exec();
2374
case QMessageBox::Yes:
2381
ItemBase * board = m_pcbGraphicsView->findSelectedBoard(boardCount);
2382
swapLayers(board, 2, tr("Change to two layer pcb"), true, SketchWidget::PropChangeDelay);
2386
void MainWindow::boardDeletedSlot()
2388
activeLayerBottom();
2391
void MainWindow::cursorLocationSlot(double xinches, double yinches)
2393
if (m_locationLabel) {
2397
m_locationLabel->setProperty("location", QSizeF(xinches, xinches));
2399
if (m_locationLabelUnits.compare("mm") == 0) {
2404
else if (m_locationLabelUnits.compare("px") == 0) {
2406
x = xinches * GraphicsUtils::SVGDPI;
2407
y = yinches * GraphicsUtils::SVGDPI;
2415
m_locationLabel->setText(tr("%1 %2 %3")
2422
void MainWindow::locationLabelClicked()
2424
if (m_locationLabelUnits.compare("mm") == 0) {
2425
m_locationLabelUnits = "px";
2427
else if (m_locationLabelUnits.compare("px") == 0) {
2428
m_locationLabelUnits = "in";
2430
else if (m_locationLabelUnits.compare("in") == 0) {
2431
m_locationLabelUnits = "mm";
2434
m_locationLabelUnits = "in";
2437
if (m_locationLabel) {
2438
QVariant variant = m_locationLabel->property("location");
2439
if (variant.isValid()) {
2440
QSizeF size = variant.toSizeF();
2441
cursorLocationSlot(size.width(), size.height());
2444
cursorLocationSlot(0, 0);
2449
settings.setValue("LocationInches", QVariant(m_locationLabelUnits));
2452
void MainWindow::filenameIfSlot(QString & filename)
2454
filename = QFileInfo(fileName()).fileName();
2457
QList<SketchWidget *> MainWindow::sketchWidgets()
2459
QList<SketchWidget *> list;
2460
list << m_breadboardGraphicsView << m_schematicGraphicsView << m_pcbGraphicsView;
2464
void MainWindow::setCloseSilently(bool cs)
2466
m_closeSilently = cs;
2469
PCBSketchWidget * MainWindow::pcbView() {
2470
return m_pcbGraphicsView;
2473
void MainWindow::noBackup()
2475
m_autosaveTimer.stop();
2478
void MainWindow::hideTempPartsBin() {
2479
if (m_binManager) m_binManager->hideTempPartsBin();
2482
void MainWindow::setActiveWire(Wire * wire) {
2483
m_activeWire = wire;
2486
void MainWindow::setActiveConnectorItem(ConnectorItem * connectorItem) {
2487
m_activeConnectorItem = connectorItem;
2490
const QString & MainWindow::fritzingVersion() {
2491
if (m_sketchModel) return m_sketchModel->fritzingVersion();
2493
return ___emptyString___;
2497
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
2499
const QMimeData* mimeData = event->mimeData();
2501
if (mimeData->hasUrls()) {
2502
QStringList pathList;
2503
QList<QUrl> urlList = mimeData->urls();
2505
// extract the local paths of the files
2506
for (int i = 0; i < urlList.size() && i < 32; ++i) {
2507
QString fn = urlList.at(i).toLocalFile();
2508
foreach (QString ext, fritzingExtensions()) {
2509
if (fn.endsWith(ext)) {
2510
event->acceptProposedAction();
2518
void MainWindow::dropEvent(QDropEvent *event)
2520
const QMimeData* mimeData = event->mimeData();
2522
if (mimeData->hasUrls()) {
2523
QStringList pathList;
2524
QList<QUrl> urlList = mimeData->urls();
2526
// extract the local paths of the files
2527
for (int i = 0; i < urlList.size() && i < 32; ++i) {
2528
mainLoadAux(urlList.at(i).toLocalFile());