[fritzing] Update to 0.8.3b.
Ed Marshall
logic at fedoraproject.org
Sun Aug 11 06:06:37 UTC 2013
commit bd9d37d0e7c9753dc0f5fdbcc8ea863ca8030d72
Author: Ed Marshall <esm at logic.net>
Date: Sat Aug 10 23:06:17 2013 -0700
Update to 0.8.3b.
fritzing-disable-autoupdate.patch | 8410 ++++++++++++++++++++++++++++++++++++-
fritzing-use-external-libs.patch | 403 --
fritzing.spec | 7 +-
sources | 3 +-
4 files changed, 8279 insertions(+), 544 deletions(-)
---
diff --git a/fritzing-disable-autoupdate.patch b/fritzing-disable-autoupdate.patch
index e06669b..50fd26c 100644
--- a/fritzing-disable-autoupdate.patch
+++ b/fritzing-disable-autoupdate.patch
@@ -1,137 +1,144 @@
-diff -urN fritzing-0.7.12b.source.orig/src/fapplication.cpp fritzing-0.7.12b.source/src/fapplication.cpp
---- fritzing-0.7.12b.source.orig/src/fapplication.cpp 2013-02-25 05:02:58.000000000 -0800
-+++ fritzing-0.7.12b.source/src/fapplication.cpp 2013-02-25 18:30:14.337450882 -0800
-@@ -288,7 +288,6 @@
- m_mousePressed = false;
- m_referenceModel = NULL;
- m_started = false;
-- m_updateDialog = NULL;
- m_lastTopmostWindow = NULL;
- m_serviceType = NoService;
- m_splash = NULL;
-@@ -460,7 +459,6 @@
- }
-
- m_started = false;
-- m_updateDialog = NULL;
- m_lastTopmostWindow = NULL;
-
- connect(&m_activationTimer, SIGNAL(timeout()), this, SLOT(updateActivation()));
-@@ -516,10 +514,6 @@
-
- clearModels();
-
-- if (m_updateDialog) {
-- delete m_updateDialog;
-- }
--
- FSvgRenderer::cleanup();
- ViewLayer::cleanup();
- ViewLayer::cleanup();
-@@ -1037,10 +1031,6 @@
- if (m_progressIndex >= 0) splash.showProgress(m_progressIndex, 0.825);
- ProcessEventBlocker::processEvents();
-
-- m_updateDialog = new UpdateDialog();
-- connect(m_updateDialog, SIGNAL(enableAgainSignal(bool)), this, SLOT(enableCheckUpdates(bool)));
-- checkForUpdates(false);
--
- if (m_progressIndex >= 0) splash.showProgress(m_progressIndex, 0.875);
-
- DebugDialog::debug("load something");
-@@ -1223,59 +1213,6 @@
- ViewLayer::ViewLayerID viewLayerID;
- };
-
--
--
--void FApplication::checkForUpdates() {
-- checkForUpdates(true);
--}
--
--void FApplication::checkForUpdates(bool atUserRequest)
--{
-- if (atUserRequest) {
-- enableCheckUpdates(false);
-- }
--
-- VersionChecker * versionChecker = new VersionChecker();
--
-- QSettings settings;
-- if (!atUserRequest) {
-- // if I've already been notified about these updates, don't bug me again
-- QString lastMainVersionChecked = settings.value("lastMainVersionChecked").toString();
-- if (!lastMainVersionChecked.isEmpty()) {
-- versionChecker->ignore(lastMainVersionChecked, false);
-- }
-- QString lastInterimVersionChecked = settings.value("lastInterimVersionChecked").toString();
-- if (!lastInterimVersionChecked.isEmpty()) {
-- versionChecker->ignore(lastInterimVersionChecked, true);
-- }
-- }
--
-- QString atom = QString("http://fritzing.org/download/feed/atom/%1/%2")
-- .arg(PLATFORM_NAME)
-- .arg(Version::makeRequestParamsString());
-- DebugDialog::debug(atom);
-- versionChecker->setUrl(atom);
-- m_updateDialog->setAtUserRequest(atUserRequest);
-- m_updateDialog->setVersionChecker(versionChecker);
--
-- if (atUserRequest) {
-- m_updateDialog->show();
-- }
--}
--
--void FApplication::enableCheckUpdates(bool enabled)
--{
-- //DebugDialog::debug("before enable check updates");
-- foreach (QWidget *widget, QApplication::topLevelWidgets()) {
-- MainWindow *mainWindow = qobject_cast<MainWindow *>(widget);
-- if (mainWindow) {
-- mainWindow->enableCheckUpdates(enabled);
-- }
-- }
-- //DebugDialog::debug("after enable check updates");
--}
--
--
- void FApplication::createUserDataStoreFolderStructure() {
- // make sure that the folder structure for parts and bins, exists
- QString userDataStorePath = FolderUtils::getUserDataStorePath();
-diff -urN fritzing-0.7.12b.source.orig/src/fapplication.h fritzing-0.7.12b.source/src/fapplication.h
---- fritzing-0.7.12b.source.orig/src/fapplication.h 2013-02-25 05:02:59.000000000 -0800
-+++ fritzing-0.7.12b.source/src/fapplication.h 2013-02-25 18:29:22.841458898 -0800
+diff -urN fritzing-0.8.3b.source.orig/src/fapplication.cpp fritzing-0.8.3b.source/src/fapplication.cpp
+--- fritzing-0.8.3b.source.orig/src/fapplication.cpp 2013-07-27 14:03:38.000000000 -0700
++++ fritzing-0.8.3b.source/src/fapplication.cpp 2013-08-10 22:52:45.541364980 -0700
+@@ -34,7 +34,6 @@
+ #include "help/helper.h"
+ #include "fsvgrenderer.h"
+ #include "version/versionchecker.h"
+-#include "version/updatedialog.h"
+ #include "itemdrag.h"
+ #include "dock/viewswitcher.h"
+ #include "items/wire.h"
+@@ -289,7 +288,6 @@
+ m_mousePressed = false;
+ m_referenceModel = NULL;
+ m_started = false;
+- m_updateDialog = NULL;
+ m_lastTopmostWindow = NULL;
+ m_serviceType = NoService;
+ m_splash = NULL;
+@@ -468,7 +466,6 @@
+ }
+
+ m_started = false;
+- m_updateDialog = NULL;
+ m_lastTopmostWindow = NULL;
+
+ connect(&m_activationTimer, SIGNAL(timeout()), this, SLOT(updateActivation()));
+@@ -524,10 +521,6 @@
+
+ clearModels();
+
+- if (m_updateDialog) {
+- delete m_updateDialog;
+- }
+-
+ FSvgRenderer::cleanup();
+ ViewLayer::cleanup();
+ ViewLayer::cleanup();
+@@ -1115,10 +1108,6 @@
+ if (m_progressIndex >= 0) splash.showProgress(m_progressIndex, 0.825);
+ ProcessEventBlocker::processEvents();
+
+- m_updateDialog = new UpdateDialog();
+- connect(m_updateDialog, SIGNAL(enableAgainSignal(bool)), this, SLOT(enableCheckUpdates(bool)));
+- checkForUpdates(false);
+-
+ if (m_progressIndex >= 0) splash.showProgress(m_progressIndex, 0.875);
+
+ DebugDialog::debug("load something");
+@@ -1302,58 +1291,6 @@
+ };
+
+
+-
+-void FApplication::checkForUpdates() {
+- checkForUpdates(true);
+-}
+-
+-void FApplication::checkForUpdates(bool atUserRequest)
+-{
+- if (atUserRequest) {
+- enableCheckUpdates(false);
+- }
+-
+- VersionChecker * versionChecker = new VersionChecker();
+-
+- QSettings settings;
+- if (!atUserRequest) {
+- // if I've already been notified about these updates, don't bug me again
+- QString lastMainVersionChecked = settings.value("lastMainVersionChecked").toString();
+- if (!lastMainVersionChecked.isEmpty()) {
+- versionChecker->ignore(lastMainVersionChecked, false);
+- }
+- QString lastInterimVersionChecked = settings.value("lastInterimVersionChecked").toString();
+- if (!lastInterimVersionChecked.isEmpty()) {
+- versionChecker->ignore(lastInterimVersionChecked, true);
+- }
+- }
+-
+- QString atom = QString("http://fritzing.org/download/feed/atom/%1/%2")
+- .arg(PLATFORM_NAME)
+- .arg(Version::makeRequestParamsString(true));
+- DebugDialog::debug(atom);
+- versionChecker->setUrl(atom);
+- m_updateDialog->setAtUserRequest(atUserRequest);
+- m_updateDialog->setVersionChecker(versionChecker);
+-
+- if (atUserRequest) {
+- m_updateDialog->show();
+- }
+-}
+-
+-void FApplication::enableCheckUpdates(bool enabled)
+-{
+- //DebugDialog::debug("before enable check updates");
+- foreach (QWidget *widget, QApplication::topLevelWidgets()) {
+- MainWindow *mainWindow = qobject_cast<MainWindow *>(widget);
+- if (mainWindow) {
+- mainWindow->enableCheckUpdates(enabled);
+- }
+- }
+- //DebugDialog::debug("after enable check updates");
+-}
+-
+-
+ void FApplication::createUserDataStoreFolderStructure() {
+ // make sure that the folder structure for parts and bins, exists
+ QString userDataStorePath = FolderUtils::getUserDataStorePath();
+diff -urN fritzing-0.8.3b.source.orig/src/fapplication.h fritzing-0.8.3b.source/src/fapplication.h
+--- fritzing-0.8.3b.source.orig/src/fapplication.h 2013-07-27 14:03:38.000000000 -0700
++++ fritzing-0.8.3b.source/src/fapplication.h 2013-08-10 22:50:50.837249496 -0700
@@ -108,9 +108,6 @@
- public slots:
- void preferences();
- void preferencesAfter();
-- void checkForUpdates();
-- void checkForUpdates(bool atUserRequest);
-- void enableCheckUpdates(bool enabled);
- void createUserDataStoreFolderStructure();
- void changeActivation(bool activate, QWidget * originator);
- void updateActivation();
-@@ -180,7 +177,6 @@
- QStringList m_filesToLoad;
- QString m_libPath;
- QString m_translationPath;
-- class UpdateDialog * m_updateDialog;
- QTimer m_activationTimer;
- QPointer<class FritzingWindow> m_lastTopmostWindow;
- QList<QWidget *> m_orderedTopLevelWidgets;
-diff -urN fritzing-0.7.12b.source.orig/src/mainwindow/mainwindow.cpp fritzing-0.7.12b.source/src/mainwindow/mainwindow.cpp
---- fritzing-0.7.12b.source.orig/src/mainwindow/mainwindow.cpp 2013-02-25 05:02:59.000000000 -0800
-+++ fritzing-0.7.12b.source/src/mainwindow/mainwindow.cpp 2013-02-25 18:29:22.842458995 -0800
-@@ -198,7 +198,6 @@
+ public slots:
+ void preferences();
+ void preferencesAfter();
+- void checkForUpdates();
+- void checkForUpdates(bool atUserRequest);
+- void enableCheckUpdates(bool enabled);
+ void createUserDataStoreFolderStructure();
+ void changeActivation(bool activate, QWidget * originator);
+ void updateActivation();
+@@ -182,7 +179,6 @@
+ QStringList m_filesToLoad;
+ QString m_libPath;
+ QString m_translationPath;
+- class UpdateDialog * m_updateDialog;
+ QTimer m_activationTimer;
+ QPointer<class FritzingWindow> m_lastTopmostWindow;
+ QList<QWidget *> m_orderedTopLevelWidgets;
+diff -urN fritzing-0.8.3b.source.orig/src/mainwindow/mainwindow.cpp fritzing-0.8.3b.source/src/mainwindow/mainwindow.cpp
+--- fritzing-0.8.3b.source.orig/src/mainwindow/mainwindow.cpp 2013-07-27 14:03:38.000000000 -0700
++++ fritzing-0.8.3b.source/src/mainwindow/mainwindow.cpp 2013-08-10 22:49:23.904174341 -0700
+@@ -199,7 +199,6 @@
m_windowMenuSeparator = NULL;
- m_wireColorMenu = NULL;
+ m_schematicWireColorMenu = m_breadboardWireColorMenu = NULL;
m_viewSwitcherDock = NULL;
- m_checkForUpdatesAct = NULL;
m_fileProgressDialog = NULL;
m_currentGraphicsView = NULL;
m_comboboxChanged = false;
-@@ -1852,13 +1851,6 @@
+@@ -1897,13 +1896,6 @@
m_showInViewHelpAct->setChecked(show);
}
@@ -145,10 +152,2898 @@ diff -urN fritzing-0.7.12b.source.orig/src/mainwindow/mainwindow.cpp fritzing-0.
void MainWindow::swapSelectedDelay(const QString & family, const QString & prop, QMap<QString, QString> & currPropsMap, ItemBase * itemBase)
{
-diff -urN fritzing-0.7.12b.source.orig/src/mainwindow/mainwindow.h fritzing-0.7.12b.source/src/mainwindow/mainwindow.h
---- fritzing-0.7.12b.source.orig/src/mainwindow/mainwindow.h 2013-02-25 05:02:59.000000000 -0800
-+++ fritzing-0.7.12b.source/src/mainwindow/mainwindow.h 2013-02-25 18:29:22.842458995 -0800
-@@ -122,7 +122,6 @@
+diff -urN fritzing-0.8.3b.source.orig/src/mainwindow/mainwindow.cpp.orig fritzing-0.8.3b.source/src/mainwindow/mainwindow.cpp.orig
+--- fritzing-0.8.3b.source.orig/src/mainwindow/mainwindow.cpp.orig 1969-12-31 16:00:00.000000000 -0800
++++ fritzing-0.8.3b.source/src/mainwindow/mainwindow.cpp.orig 2013-07-27 14:03:38.000000000 -0700
+@@ -0,0 +1,2884 @@
++/*******************************************************************
++
++Part of the Fritzing project - http://fritzing.org
++Copyright (c) 2007-2013 Fachhochschule Potsdam - http://fh-potsdam.de
++
++Fritzing is free software: you can redistribute it and/or modify
++
++it under the terms of the GNU General Public License as published by
++the Free Software Foundation, either version 3 of the License, or
++(at your option) any later version.
++
++Fritzing is distributed in the hope that it will be useful,
++but WITHOUT ANY WARRANTY; without even the implied warranty of
++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++GNU General Public License for more details.
++
++You should have received a copy of the GNU General Public License
++along with Fritzing. If not, see <http://www.gnu.org/licenses/>.
++
++********************************************************************
++
++$Revision: 6995 $:
++$Author: irascibl at gmail.com $:
++$Date: 2013-04-28 00:56:34 +0200 (So, 28. Apr 2013) $
++
++********************************************************************/
++
++#include <QtGui>
++#include <QtXml>
++#include <QList>
++#include <QFileInfo>
++#include <QStringList>
++#include <QFileInfoList>
++#include <QDir>
++#include <QLabel>
++#include <QTime>
++#include <QSettings>
++#include <QRegExp>
++#include <QPaintDevice>
++#include <QPixmap>
++#include <QTimer>
++#include <QStackedWidget>
++#include <QXmlStreamReader>
++#include <QShortcut>
++
++#include "mainwindow.h"
++#include "../debugdialog.h"
++#include "../connectors/connector.h"
++#include "../partsbinpalette/partsbinpalettewidget.h"
++#include "fdockwidget.h"
++#include "../infoview/htmlinfoview.h"
++#include "../waitpushundostack.h"
++#include "../layerattributes.h"
++#include "../dock/triplenavigator.h"
++#include "../sketch/breadboardsketchwidget.h"
++#include "../sketch/schematicsketchwidget.h"
++#include "../sketch/pcbsketchwidget.h"
++#include "../svg/svgfilesplitter.h"
++#include "../utils/folderutils.h"
++#include "../utils/lockmanager.h"
++#include "../utils/textutils.h"
++#include "../utils/graphicsutils.h"
++#include "../items/mysterypart.h"
++#include "../items/moduleidnames.h"
++#include "../items/pinheader.h"
++#include "../items/perfboard.h"
++#include "../items/stripboard.h"
++#include "../items/partfactory.h"
++#include "../dock/layerpalette.h"
++#include "../items/paletteitem.h"
++#include "../items/virtualwire.h"
++#include "../items/screwterminal.h"
++#include "../items/dip.h"
++#include "../processeventblocker.h"
++#include "../help/helper.h"
++#include "../sketchtoolbutton.h"
++#include "../partsbinpalette/binmanager/binmanager.h"
++#include "../fsvgrenderer.h"
++#include "../utils/fsizegrip.h"
++#include "../utils/expandinglabel.h"
++#include "../dock/viewswitcher.h"
++#include "../dock/viewswitcherdockwidget.h"
++#include "../utils/autoclosemessagebox.h"
++#include "../utils/fileprogressdialog.h"
++#include "../utils/clickablelabel.h"
++#include "../items/resizableboard.h"
++#include "../items/resistor.h"
++#include "../items/logoitem.h"
++#include "../utils/zoomslider.h"
++#include "../partseditor/pemainwindow.h"
++
++///////////////////////////////////////////////
++
++struct MissingSvgInfo {
++ QString requestedPath;
++ QStringList connectorSvgIds;
++ ModelPart * modelPart;
++ bool equal;
++};
++
++bool byConnectorCount(MissingSvgInfo & m1, MissingSvgInfo & m2)
++{
++ if (m1.connectorSvgIds.count() == m2.connectorSvgIds.count() && m1.modelPart != m2.modelPart) {
++ m1.equal = m2.equal = true;
++ }
++
++ return (m1.connectorSvgIds.count() > m2.connectorSvgIds.count());
++}
++
++///////////////////////////////////////////////
++
++#define ZIP_PART QString("part.")
++#define ZIP_SVG QString("svg.")
++
++///////////////////////////////////////////////
++
++// SwapTimer explained: http://code.google.com/p/fritzing/issues/detail?id=1431
++
++SwapTimer::SwapTimer() : QTimer()
++{
++}
++
++void SwapTimer::setAll(const QString & family, const QString & prop, QMap<QString, QString> & propsMap, ItemBase * itemBase)
++{
++ m_family = family;
++ m_prop = prop;
++ m_propsMap = propsMap;
++ m_itemBase = itemBase;
++}
++
++const QString & SwapTimer::family()
++{
++ return m_family;
++}
++
++const QString & SwapTimer::prop()
++{
++ return m_prop;
++}
++
++QMap<QString, QString> SwapTimer::propsMap()
++{
++ return m_propsMap;
++}
++
++ItemBase * SwapTimer::itemBase()
++{
++ return m_itemBase;
++}
++
++///////////////////////////////////////////////
++
++const QString MainWindow::UntitledSketchName = "Untitled Sketch";
++int MainWindow::UntitledSketchIndex = 1;
++int MainWindow::CascadeFactorX = 21;
++int MainWindow::CascadeFactorY = 19;
++
++static const int MainWindowDefaultWidth = 840;
++static const int MainWindowDefaultHeight = 600;
++
++int MainWindow::AutosaveTimeoutMinutes = 10; // in minutes
++bool MainWindow::AutosaveEnabled = true;
++QString MainWindow::BackupFolder;
++
++QRegExp MainWindow::GuidMatcher = QRegExp("[A-Fa-f0-9]{32}");
++
++/////////////////////////////////////////////
++
++MainWindow::MainWindow(ReferenceModel *referenceModel, QWidget * parent) :
++ FritzingWindow(untitledFileName(), untitledFileCount(), fileExtension(), parent)
++{
++ m_rolloverQuoteDialog = NULL;
++ setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
++ setDockOptions(QMainWindow::AnimatedDocks);
++ m_sizeGrip = new FSizeGrip(this);
++
++ m_topDock = NULL;
++ m_bottomDock = NULL;
++ m_dontKeepMargins = true;
++
++ m_settingsPrefix = "main/";
++ m_showProgramAct = m_raiseWindowAct = m_showPartsBinIconViewAct = m_showAllLayersAct = m_hideAllLayersAct = m_showInViewHelpAct = m_rotate90cwAct = m_showBreadboardAct = m_showSchematicAct = m_showPCBAct = NULL;
++ m_fileMenu = m_editMenu = m_partMenu = m_windowMenu = m_pcbTraceMenu = m_schematicTraceMenu = m_breadboardTraceMenu = m_viewMenu = NULL;
++ m_miniViewContainerBreadboard = NULL;
++ m_infoView = NULL;
++ m_addedToTemp = false;
++ setAcceptDrops(true);
++ m_activeWire = NULL;
++ m_activeConnectorItem = NULL;
++ m_swapTimer.setInterval(30);
++ m_swapTimer.setParent(this);
++ m_swapTimer.setSingleShot(true);
++ connect(&m_swapTimer, SIGNAL(timeout()), this, SLOT(swapSelectedTimeout()));
++
++ m_closeSilently = false;
++ m_orderFabAct = NULL;
++ m_viewFromButtonWidget = m_activeLayerButtonWidget = NULL;
++ m_programView = m_programWindow = NULL;
++ m_windowMenuSeparator = NULL;
++ m_schematicWireColorMenu = m_breadboardWireColorMenu = NULL;
++ m_viewSwitcherDock = NULL;
++ m_checkForUpdatesAct = NULL;
++ m_fileProgressDialog = NULL;
++ m_currentGraphicsView = NULL;
++ m_comboboxChanged = false;
++ m_helper = NULL;
++
++ // Add a timer for autosaving
++ m_backingUp = m_autosaveNeeded = false;
++ connect(&m_autosaveTimer, SIGNAL(timeout()), this, SLOT(backupSketch()));
++ m_autosaveTimer.start(AutosaveTimeoutMinutes * 60 * 1000);
++
++ resize(MainWindowDefaultWidth, MainWindowDefaultHeight);
++
++ m_backupFileNameAndPath = MainWindow::BackupFolder + "/" + TextUtils::getRandText() + FritzingSketchExtension;
++ // Connect the undoStack to our autosave stuff
++ connect(m_undoStack, SIGNAL(indexChanged(int)), this, SLOT(autosaveNeeded(int)));
++ connect(m_undoStack, SIGNAL(cleanChanged(bool)), this, SLOT(undoStackCleanChanged(bool)));
++
++ // Create dot icons
++ m_dotIcon = QIcon(":/resources/images/dot.png");
++ m_emptyIcon = QIcon();
++
++ m_currentWidget = NULL;
++ m_firstOpen = true;
++
++ m_statusBar = new QStatusBar(this);
++ setStatusBar(m_statusBar);
++ m_statusBar->setSizeGripEnabled(false);
++
++ QSettings settings;
++ m_locationLabelUnits = settings.value("LocationInches", "in").toString();
++
++ // leave the m_orderFabEnabled check in case we turn off the fab button in the future
++ m_orderFabEnabled = true; // settings.value(ORDERFABENABLED, QVariant(false)).toBool();
++
++ m_locationLabel = new ClickableLabel("", this);
++ m_locationLabel->setObjectName("LocationLabel");
++ connect(m_locationLabel, SIGNAL(clicked()), this, SLOT(locationLabelClicked()));
++ m_locationLabel->setCursor(Qt::PointingHandCursor);
++ m_statusBar->addPermanentWidget(m_locationLabel);
++
++ m_zoomSlider = new ZoomSlider(ZoomableGraphicsView::MaxScaleValue, m_statusBar);
++ connect(m_zoomSlider, SIGNAL(zoomChanged(double)), this, SLOT(updateViewZoom(double)));
++ m_statusBar->addPermanentWidget(m_zoomSlider);
++
++ setAttribute(Qt::WA_DeleteOnClose, true);
++
++#ifdef Q_WS_MAC
++ //setAttribute(Qt::WA_QuitOnClose, false); // restoring this temporarily (2008.12.19)
++#endif
++ m_dontClose = m_closing = false;
++
++ m_referenceModel = referenceModel;
++ m_sketchModel = new SketchModel(true);
++
++
++ QShortcut * shortcut = new QShortcut(QKeySequence(tr("Ctrl+R", "Rotate Clockwise")), this);
++ connect(shortcut, SIGNAL(activated()), this, SLOT(rotateIncCW()));
++ shortcut = new QShortcut(QKeySequence(tr("Alt+Ctrl+R", "Rotate Clockwise")), this);
++ connect(shortcut, SIGNAL(activated()), this, SLOT(rotateIncCWRubberBand()));
++ shortcut = new QShortcut(QKeySequence(tr("Meta+Ctrl+R", "Rotate Clockwise")), this);
++ connect(shortcut, SIGNAL(activated()), this, SLOT(rotateIncCWRubberBand()));
++
++ shortcut = new QShortcut(QKeySequence(tr("Shift+Ctrl+R", "Rotate Counterclockwise")), this);
++ connect(shortcut, SIGNAL(activated()), this, SLOT(rotateIncCCW()));
++ shortcut = new QShortcut(QKeySequence(tr("Alt+Shift+Ctrl+R", "Rotate Counterclockwise")), this);
++ connect(shortcut, SIGNAL(activated()), this, SLOT(rotateIncCCWRubberBand()));
++ shortcut = new QShortcut(QKeySequence(tr("Meta+Shift+Ctrl+R", "Rotate Counterclockwise")), this);
++ connect(shortcut, SIGNAL(activated()), this, SLOT(rotateIncCCWRubberBand()));
++
++ shortcut = new QShortcut(QKeySequence(tr("Shift+Ctrl+Tab", "Toggle Active Layer")), this);
++ connect(shortcut, SIGNAL(activated()), this, SLOT(toggleActiveLayer()));
++
++
++ connect(this, SIGNAL(changeActivationSignal(bool, QWidget *)), qApp, SLOT(changeActivation(bool, QWidget *)), Qt::DirectConnection);
++ connect(this, SIGNAL(destroyed(QObject *)), qApp, SLOT(topLevelWidgetDestroyed(QObject *)));
++ connect(this, SIGNAL(externalProcessSignal(QString &, QString &, QStringList &)),
++ qApp, SLOT(externalProcessSlot(QString &, QString &, QStringList &)),
++ Qt::DirectConnection);
++}
++
++QWidget * MainWindow::createTabWidget() {
++ return new QStackedWidget(this);
++}
++
++void MainWindow::addTab(QWidget * widget, const QString & label) {
++ Q_UNUSED(label);
++ qobject_cast<QStackedWidget *>(m_tabWidget)->addWidget(widget);
++}
++
++int MainWindow::currentTabIndex() {
++ return qobject_cast<QStackedWidget *>(m_tabWidget)->currentIndex();
++}
++
++void MainWindow::setCurrentTabIndex(int index) {
++ qobject_cast<QStackedWidget *>(m_tabWidget)->setCurrentIndex(index);
++}
++
++QWidget * MainWindow::currentTabWidget() {
++ return qobject_cast<QStackedWidget *>(m_tabWidget)->currentWidget();
++}
++
++void MainWindow::init(ReferenceModel *referenceModel, bool lockFiles) {
++
++ m_tabWidget = createTabWidget(); // FTabWidget(this);
++ m_tabWidget->setObjectName("sketch_tabs");
++ setCentralWidget(m_tabWidget);
++
++ m_referenceModel = referenceModel;
++ m_restarting = false;
++
++ if (m_fileProgressDialog) {
++ m_fileProgressDialog->setValue(2);
++ }
++
++ initLockedFiles(lockFiles);
++
++ initSketchWidgets();
++ initProgrammingWidget();
++
++ m_undoView = new QUndoView();
++ m_undoGroup = new QUndoGroup(this);
++ m_undoView->setGroup(m_undoGroup);
++ m_undoGroup->setActiveStack(m_undoStack);
++
++ initDock();
++ initMenus();
++ moreInitDock();
++
++ createZoomOptions(m_breadboardWidget);
++ createZoomOptions(m_schematicWidget);
++ createZoomOptions(m_pcbWidget);
++
++ m_breadboardWidget->setToolbarWidgets(getButtonsForView(ViewLayer::BreadboardView));
++ m_schematicWidget->setToolbarWidgets(getButtonsForView(ViewLayer::SchematicView));
++ m_pcbWidget->setToolbarWidgets(getButtonsForView(ViewLayer::PCBView));
++
++ initStyleSheet();
++
++ m_breadboardGraphicsView->setItemMenu(breadboardItemMenu());
++ m_breadboardGraphicsView->setWireMenu(breadboardWireMenu());
++
++ m_pcbGraphicsView->setWireMenu(pcbWireMenu());
++ m_pcbGraphicsView->setItemMenu(pcbItemMenu());
++
++ m_schematicGraphicsView->setItemMenu(schematicItemMenu());
++ m_schematicGraphicsView->setWireMenu(schematicWireMenu());
++
++ if (m_infoView) {
++ m_breadboardGraphicsView->setInfoView(m_infoView);
++ m_pcbGraphicsView->setInfoView(m_infoView);
++ m_schematicGraphicsView->setInfoView(m_infoView);
++ }
++
++ // make sure to set the connections after the views have been created
++ connect(m_tabWidget, SIGNAL(currentChanged ( int )), this, SLOT(tabWidget_currentChanged( int )));
++
++ connectPairs();
++
++ initHelper();
++
++ // do this the first time, since the current_changed signal wasn't sent
++ int tab = 0;
++ if (m_navigators.count() > 0) {
++ currentNavigatorChanged(m_navigators[tab]);
++ }
++ tabWidget_currentChanged(tab+1);
++ tabWidget_currentChanged(tab);
++
++ this->installEventFilter(this);
++
++ if (m_fileProgressDialog) {
++ m_fileProgressDialog->setValue(95);
++ }
++
++ QSettings settings;
++ if (m_viewSwitcherDock) {
++ m_viewSwitcherDock->prestorePreference();
++ }
++ if(!settings.value(m_settingsPrefix + "state").isNull()) {
++ restoreState(settings.value(m_settingsPrefix + "state").toByteArray());
++ restoreGeometry(settings.value(m_settingsPrefix + "geometry").toByteArray());
++ }
++ if (m_viewSwitcherDock) {
++ m_viewSwitcherDock->restorePreference();
++ m_viewSwitcherDock->setViewSwitcher(m_viewSwitcher);
++ }
++
++ setMinimumSize(0,0);
++ m_tabWidget->setMinimumWidth(500);
++ m_tabWidget->setMinimumWidth(0);
++
++ if (m_miniViewContainerBreadboard) {
++ m_miniViewContainerBreadboard->setView(m_breadboardGraphicsView);
++ m_miniViewContainerSchematic->setView(m_schematicGraphicsView);
++ m_miniViewContainerPCB->setView(m_pcbGraphicsView);
++ }
++
++ connect(this, SIGNAL(readOnlyChanged(bool)), this, SLOT(applyReadOnlyChange(bool)));
++
++ m_setUpDockManagerTimer.setSingleShot(true);
++ connect(&m_setUpDockManagerTimer, SIGNAL(timeout()), this, SLOT(keepMargins()));
++ m_setUpDockManagerTimer.start(1000);
++
++ if (m_fileProgressDialog) {
++ m_fileProgressDialog->setValue(98);
++ }
++
++}
++
++MainWindow::~MainWindow()
++{
++ // Delete backup of this sketch if one exists.
++ QFile::remove(m_backupFileNameAndPath);
++
++ delete m_sketchModel;
++
++ dontKeepMargins();
++ m_setUpDockManagerTimer.stop();
++
++ foreach (LinkedFile * linkedFile, m_linkedProgramFiles) {
++ delete linkedFile;
++ }
++ m_linkedProgramFiles.clear();
++
++ if (!m_fzzFolder.isEmpty()) {
++ LockManager::releaseLockedFiles(m_fzzFolder, m_fzzFiles);
++ FolderUtils::rmdir(m_fzzFolder);
++ }
++}
++
++void MainWindow::initHelper() {
++ m_helper = new Helper(this, true);
++}
++
++void MainWindow::initLockedFiles(bool lockFiles) {
++ LockManager::initLockedFiles("fzz", m_fzzFolder, m_fzzFiles, lockFiles ? LockManager::SlowTime : 0);
++ if (lockFiles) {
++ QFileInfoList backupList;
++ LockManager::checkLockedFiles("fzz", backupList, m_fzzFiles, true, LockManager::SlowTime);
++ }
++}
++
++void MainWindow::initSketchWidgets() {
++ //DebugDialog::debug("init sketch widgets");
++
++ // all this belongs in viewLayer.xml
++ m_breadboardGraphicsView = new BreadboardSketchWidget(ViewLayer::BreadboardView, this);
++ initSketchWidget(m_breadboardGraphicsView);
++ m_breadboardWidget = new SketchAreaWidget(m_breadboardGraphicsView,this);
++ addTab(m_breadboardWidget, tr("Breadboard"));
++
++ if (m_fileProgressDialog) {
++ m_fileProgressDialog->setValue(11);
++ }
++
++ m_schematicGraphicsView = new SchematicSketchWidget(ViewLayer::SchematicView, this);
++ initSketchWidget(m_schematicGraphicsView);
++ m_schematicWidget = new SketchAreaWidget(m_schematicGraphicsView, this);
++ addTab(m_schematicWidget, tr("Schematic"));
++
++ if (m_fileProgressDialog) {
++ m_fileProgressDialog->setValue(20);
++ }
++
++ m_pcbGraphicsView = new PCBSketchWidget(ViewLayer::PCBView, this);
++ initSketchWidget(m_pcbGraphicsView);
++ m_pcbWidget = new SketchAreaWidget(m_pcbGraphicsView, this);
++ addTab(m_pcbWidget, tr("PCB"));
++
++ if (m_fileProgressDialog) {
++ m_fileProgressDialog->setValue(29);
++ }
++}
++
++void MainWindow::initMenus() {
++ // This is the magic translation that changes all the shortcut text on the menu items
++ // to the native language instead of "Ctrl", so the German menu items will now read "Strg"
++ // You don't actually have to translate every menu item in the .ts file, you can just leave it as "Ctrl".
++ QShortcut::tr("Ctrl", "for naming shortcut keys on menu items");
++ QShortcut::tr("Alt", "for naming shortcut keys on menu items");
++ QShortcut::tr("Shift", "for naming shortcut keys on menu items");
++ QShortcut::tr("Meta", "for naming shortcut keys on menu items");
++
++ //DebugDialog::debug("create menus");
++
++ createActions();
++ createMenus();
++
++ //DebugDialog::debug("create toolbars");
++
++ createStatusBar();
++
++ //DebugDialog::debug("after creating status bar");
++
++ if (m_fileProgressDialog) {
++ m_fileProgressDialog->setValue(91);
++ }
++}
++
++
++
++
++void MainWindow::showNavigator() {
++ m_navigatorDock->setFloating(false);
++}
++
++void MainWindow::initSketchWidget(SketchWidget * sketchWidget) {
++ sketchWidget->setSketchModel(m_sketchModel);
++ sketchWidget->setReferenceModel(m_referenceModel);
++ sketchWidget->setUndoStack(m_undoStack);
++ sketchWidget->setChainDrag(true); // enable bend points
++ sketchWidget->initGrid();
++ sketchWidget->addViewLayers();
++}
++
++void MainWindow::connectPairs() {
++ connectPair(m_breadboardGraphicsView, m_schematicGraphicsView);
++ connectPair(m_breadboardGraphicsView, m_pcbGraphicsView);
++ connectPair(m_schematicGraphicsView, m_breadboardGraphicsView);
++ connectPair(m_schematicGraphicsView, m_pcbGraphicsView);
++ connectPair(m_pcbGraphicsView, m_breadboardGraphicsView);
++ connectPair(m_pcbGraphicsView, m_schematicGraphicsView);
++
++ connect(m_pcbGraphicsView, SIGNAL(groundFillSignal()), this, SLOT(groundFill()));
++ connect(m_pcbGraphicsView, SIGNAL(copperFillSignal()), this, SLOT(copperFill()));
++
++ connect(m_pcbGraphicsView, SIGNAL(swapBoardImageSignal(SketchWidget *, ItemBase *, const QString &, const QString &, bool)),
++ this, SLOT(swapBoardImageSlot(SketchWidget *, ItemBase *, const QString &, const QString &, bool)));
++
++
++ connect(m_breadboardGraphicsView, SIGNAL(setActiveWireSignal(Wire *)), this, SLOT(setActiveWire(Wire *)));
++ connect(m_schematicGraphicsView, SIGNAL(setActiveWireSignal(Wire *)), this, SLOT(setActiveWire(Wire *)));
++ connect(m_pcbGraphicsView, SIGNAL(setActiveWireSignal(Wire *)), this, SLOT(setActiveWire(Wire *)));
++
++ connect(m_breadboardGraphicsView, SIGNAL(setActiveConnectorItemSignal(ConnectorItem *)), this, SLOT(setActiveConnectorItem(ConnectorItem *)));
++ connect(m_schematicGraphicsView, SIGNAL(setActiveConnectorItemSignal(ConnectorItem *)), this, SLOT(setActiveConnectorItem(ConnectorItem *)));
++ connect(m_pcbGraphicsView, SIGNAL(setActiveConnectorItemSignal(ConnectorItem *)), this, SLOT(setActiveConnectorItem(ConnectorItem *)));
++
++ bool succeeded = connect(m_pcbGraphicsView, SIGNAL(routingStatusSignal(SketchWidget *, const RoutingStatus &)),
++ this, SLOT(routingStatusSlot(SketchWidget *, const RoutingStatus &)));
++ succeeded = succeeded && connect(m_schematicGraphicsView, SIGNAL(routingStatusSignal(SketchWidget *, const RoutingStatus &)),
++ this, SLOT(routingStatusSlot(SketchWidget *, const RoutingStatus &)));
++ succeeded = succeeded && connect(m_breadboardGraphicsView, SIGNAL(routingStatusSignal(SketchWidget *, const RoutingStatus &)),
++ this, SLOT(routingStatusSlot(SketchWidget *, const RoutingStatus &)));
++
++ succeeded = succeeded && connect(m_breadboardGraphicsView, SIGNAL(swapSignal(const QString &, const QString &, QMap<QString, QString> &, ItemBase *)),
++ this, SLOT(swapSelectedDelay(const QString &, const QString &, QMap<QString, QString> &, ItemBase *)));
++ succeeded = succeeded && connect(m_schematicGraphicsView, SIGNAL(swapSignal(const QString &, const QString &, QMap<QString, QString> &, ItemBase *)),
++ this, SLOT(swapSelectedDelay(const QString &, const QString &, QMap<QString, QString> &, ItemBase *)));
++ succeeded = succeeded && connect(m_pcbGraphicsView, SIGNAL(swapSignal(const QString &, const QString &, QMap<QString, QString> &, ItemBase *)),
++ this, SLOT(swapSelectedDelay(const QString &, const QString &, QMap<QString, QString> &, ItemBase *)));
++
++ succeeded = succeeded && connect(m_breadboardGraphicsView, SIGNAL(dropPasteSignal(SketchWidget *)),
++ this, SLOT(dropPaste(SketchWidget *)));
++ succeeded = succeeded && connect(m_schematicGraphicsView, SIGNAL(dropPasteSignal(SketchWidget *)),
++ this, SLOT(dropPaste(SketchWidget *)));
++ succeeded = succeeded && connect(m_pcbGraphicsView, SIGNAL(dropPasteSignal(SketchWidget *)),
++ this, SLOT(dropPaste(SketchWidget *)));
++
++ succeeded = succeeded && connect(m_pcbGraphicsView, SIGNAL(subSwapSignal(SketchWidget *, ItemBase *, const QString &, ViewLayer::ViewLayerPlacement, long &, QUndoCommand *)),
++ this, SLOT(subSwapSlot(SketchWidget *, ItemBase *, const QString &, ViewLayer::ViewLayerPlacement, long &, QUndoCommand *)),
++ Qt::DirectConnection);
++
++ succeeded = succeeded && connect(m_pcbGraphicsView, SIGNAL(firstTimeHelpHidden()), this, SLOT(firstTimeHelpHidden()));
++ succeeded = succeeded && connect(m_schematicGraphicsView, SIGNAL(firstTimeHelpHidden()), this, SLOT(firstTimeHelpHidden()));
++ succeeded = succeeded && connect(m_breadboardGraphicsView, SIGNAL(firstTimeHelpHidden()), this, SLOT(firstTimeHelpHidden()));
++
++ succeeded = succeeded && connect(m_pcbGraphicsView, SIGNAL(updateLayerMenuSignal()), this, SLOT(updateLayerMenuSlot()));
++ succeeded = succeeded && connect(m_pcbGraphicsView, SIGNAL(changeBoardLayersSignal(int, bool )), this, SLOT(changeBoardLayers(int, bool )));
++
++ succeeded = succeeded && connect(m_pcbGraphicsView, SIGNAL(boardDeletedSignal()), this, SLOT(boardDeletedSlot()));
++
++ succeeded = succeeded && connect(qApp, SIGNAL(spaceBarIsPressedSignal(bool)), m_breadboardGraphicsView, SLOT(spaceBarIsPressedSlot(bool)));
++ succeeded = succeeded && connect(qApp, SIGNAL(spaceBarIsPressedSignal(bool)), m_schematicGraphicsView, SLOT(spaceBarIsPressedSlot(bool)));
++ succeeded = succeeded && connect(qApp, SIGNAL(spaceBarIsPressedSignal(bool)), m_pcbGraphicsView, SLOT(spaceBarIsPressedSlot(bool)));
++
++ succeeded = succeeded && connect(m_pcbGraphicsView, SIGNAL(cursorLocationSignal(double, double)), this, SLOT(cursorLocationSlot(double, double)));
++ succeeded = succeeded && connect(m_breadboardGraphicsView, SIGNAL(cursorLocationSignal(double, double)), this, SLOT(cursorLocationSlot(double, double)));
++ succeeded = succeeded && connect(m_schematicGraphicsView, SIGNAL(cursorLocationSignal(double, double)), this, SLOT(cursorLocationSlot(double, double)));
++
++ succeeded = succeeded && connect(m_breadboardGraphicsView, SIGNAL(filenameIfSignal(QString &)), this, SLOT(filenameIfSlot(QString &)), Qt::DirectConnection);
++ succeeded = succeeded && connect(m_pcbGraphicsView, SIGNAL(filenameIfSignal(QString &)), this, SLOT(filenameIfSlot(QString &)), Qt::DirectConnection);
++ succeeded = succeeded && connect(m_schematicGraphicsView, SIGNAL(filenameIfSignal(QString &)), this, SLOT(filenameIfSlot(QString &)), Qt::DirectConnection);
++
++
++
++ succeeded = succeeded && connect(m_breadboardGraphicsView, SIGNAL(getDroppedItemViewLayerPlacementSignal(ModelPart *, ViewLayer::ViewLayerPlacement &)),
++ m_pcbGraphicsView, SLOT(getDroppedItemViewLayerPlacement(ModelPart *, ViewLayer::ViewLayerPlacement &)),
++ Qt::DirectConnection);
++ succeeded = succeeded && connect(m_schematicGraphicsView, SIGNAL(getDroppedItemViewLayerPlacementSignal(ModelPart *, ViewLayer::ViewLayerPlacement &)),
++ m_pcbGraphicsView, SLOT(getDroppedItemViewLayerPlacement(ModelPart *, ViewLayer::ViewLayerPlacement &)),
++ Qt::DirectConnection);
++
++
++ if (!succeeded) {
++ DebugDialog::debug("connectPair failed");
++ }
++}
++
++void MainWindow::connectPair(SketchWidget * signaller, SketchWidget * slotter)
++{
++
++ bool succeeded = connect(signaller, SIGNAL(itemAddedSignal(ModelPart *, ItemBase *, ViewLayer::ViewLayerPlacement, const ViewGeometry &, long, SketchWidget *)),
++ slotter, SLOT(itemAddedSlot(ModelPart *, ItemBase *, ViewLayer::ViewLayerPlacement, const ViewGeometry &, long, SketchWidget *)));
++
++ succeeded = succeeded && connect(signaller, SIGNAL(itemDeletedSignal(long)),
++ slotter, SLOT(itemDeletedSlot(long)),
++ Qt::DirectConnection);
++
++ succeeded = succeeded && connect(signaller, SIGNAL(clearSelectionSignal()),
++ slotter, SLOT(clearSelectionSlot()));
++
++ succeeded = succeeded && connect(signaller, SIGNAL(itemSelectedSignal(long, bool)),
++ slotter, SLOT(itemSelectedSlot(long, bool)));
++ succeeded = succeeded && connect(signaller, SIGNAL(selectAllItemsSignal(bool, bool)),
++ slotter, SLOT(selectAllItems(bool, bool)));
++ succeeded = succeeded && connect(signaller, SIGNAL(wireDisconnectedSignal(long, QString)),
++ slotter, SLOT(wireDisconnectedSlot(long, QString)));
++ succeeded = succeeded && connect(signaller, SIGNAL(wireConnectedSignal(long, QString, long, QString)),
++ slotter, SLOT(wireConnectedSlot(long, QString, long, QString)));
++ succeeded = succeeded && connect(signaller, SIGNAL(changeConnectionSignal(long, QString, long, QString, ViewLayer::ViewLayerPlacement, bool, bool)),
++ slotter, SLOT(changeConnectionSlot(long, QString, long, QString, ViewLayer::ViewLayerPlacement, bool, bool)));
++ succeeded = succeeded && connect(signaller, SIGNAL(copyBoundingRectsSignal(QHash<QString, QRectF> &)),
++ slotter, SLOT(copyBoundingRectsSlot(QHash<QString, QRectF> &)),
++ Qt::DirectConnection);
++
++ succeeded = succeeded && connect(signaller, SIGNAL(cleanUpWiresSignal(CleanUpWiresCommand *)),
++ slotter, SLOT(cleanUpWiresSlot(CleanUpWiresCommand *)) );
++
++ succeeded = succeeded && connect(signaller, SIGNAL(cleanupRatsnestsSignal(bool)),
++ slotter, SLOT(cleanupRatsnests(bool)) );
++
++ succeeded = succeeded && connect(signaller, SIGNAL(checkStickySignal(long, bool, bool, CheckStickyCommand *)),
++ slotter, SLOT(checkSticky(long, bool, bool, CheckStickyCommand *)) );
++
++ succeeded = succeeded && connect(signaller, SIGNAL(disconnectAllSignal(QList<ConnectorItem *>, QHash<ItemBase *, SketchWidget *> &, QUndoCommand *)),
++ slotter, SLOT(disconnectAllSlot(QList<ConnectorItem *>, QHash<ItemBase *, SketchWidget *> &, QUndoCommand *)),
++ Qt::DirectConnection);
++ succeeded = succeeded && connect(signaller, SIGNAL(setResistanceSignal(long, QString, QString, bool)),
++ slotter, SLOT(setResistance(long, QString, QString, bool)));
++ succeeded = succeeded && connect(signaller, SIGNAL(makeDeleteItemCommandPrepSignal(ItemBase *, bool , QUndoCommand * )),
++ slotter, SLOT(makeDeleteItemCommandPrepSlot(ItemBase * , bool , QUndoCommand * )));
++ succeeded = succeeded && connect(signaller, SIGNAL(makeDeleteItemCommandFinalSignal(ItemBase *, bool , QUndoCommand * )),
++ slotter, SLOT(makeDeleteItemCommandFinalSlot(ItemBase * , bool , QUndoCommand * )));
++
++ succeeded = succeeded && connect(signaller, SIGNAL(setPropSignal(long, const QString &, const QString &, bool, bool)),
++ slotter, SLOT(setProp(long, const QString &, const QString &, bool, bool)));
++
++ succeeded = succeeded && connect(signaller, SIGNAL(setInstanceTitleSignal(long, const QString &, const QString &, bool, bool )),
++ slotter, SLOT(setInstanceTitle(long, const QString &, const QString &, bool, bool )));
++
++ succeeded = succeeded && connect(signaller, SIGNAL(setVoltageSignal(double, bool )),
++ slotter, SLOT(setVoltage(double, bool )));
++
++ succeeded = succeeded && connect(signaller, SIGNAL(showLabelFirstTimeSignal(long, bool, bool )),
++ slotter, SLOT(showLabelFirstTime(long, bool, bool )));
++
++ succeeded = succeeded && connect(signaller, SIGNAL(changeBoardLayersSignal(int, bool )),
++ slotter, SLOT(changeBoardLayers(int, bool )));
++
++ succeeded = succeeded && connect(signaller, SIGNAL(deleteTracesSignal(QSet<ItemBase *> &, QHash<ItemBase *, SketchWidget *> &, QList<long> &, bool, QUndoCommand *)),
++ slotter, SLOT(deleteTracesSlot(QSet<ItemBase *> &, QHash<ItemBase *, SketchWidget *> &, QList<long> &, bool, QUndoCommand *)),
++ Qt::DirectConnection);
++
++ succeeded = succeeded && connect(signaller, SIGNAL(ratsnestConnectSignal(long, const QString &, bool, bool)),
++ slotter, SLOT(ratsnestConnect(long, const QString &, bool, bool )),
++ Qt::DirectConnection);
++
++
++ succeeded = succeeded && connect(signaller, SIGNAL(updatePartLabelInstanceTitleSignal(long)),
++ slotter, SLOT(updatePartLabelInstanceTitleSlot(long)));
++
++ succeeded = succeeded && connect(signaller, SIGNAL(changePinLabelsSignal(ItemBase *, bool)),
++ slotter, SLOT(changePinLabelsSlot(ItemBase *, bool)));
++
++ succeeded = succeeded && connect(signaller, SIGNAL(collectRatsnestSignal(QList<SketchWidget *> &)),
++ slotter, SLOT(collectRatsnestSlot(QList<SketchWidget *> &)),
++ Qt::DirectConnection);
++
++ succeeded = succeeded && connect(signaller, SIGNAL(removeRatsnestSignal(QList<struct ConnectorEdge *> &, QUndoCommand *)),
++ slotter, SLOT(removeRatsnestSlot(QList<struct ConnectorEdge *> &, QUndoCommand *)),
++ Qt::DirectConnection);
++
++ succeeded = succeeded && connect(signaller, SIGNAL(canConnectSignal(Wire *, ItemBase *, bool &)),
++ slotter, SLOT(canConnect(Wire *, ItemBase *, bool &)),
++ Qt::DirectConnection);
++
++ succeeded = succeeded && connect(signaller, SIGNAL(swapStartSignal(SwapThing &, bool)),
++ slotter, SLOT(swapStart(SwapThing &, bool)),
++ Qt::DirectConnection);
++
++ succeeded = succeeded && connect(signaller, SIGNAL(packItemsSignal(int, const QList<long> &, QUndoCommand *, bool)),
++ slotter, SLOT(packItems(int, const QList<long> &, QUndoCommand *, bool)));
++
++ succeeded = succeeded && connect(signaller, SIGNAL(addSubpartSignal(long, long, bool)), slotter, SLOT(addSubpart(long, long, bool)));
++
++ if (!succeeded) {
++ DebugDialog::debug("connectPair failed");
++ }
++
++}
++
++void MainWindow::setCurrentFile(const QString &filename, bool addToRecent, bool setAsLastOpened) {
++ setFileName(filename);
++
++ if(setAsLastOpened) {
++ QSettings settings;
++ settings.setValue("lastOpenSketch",filename);
++ }
++
++ updateRaiseWindowAction();
++ setTitle();
++
++ if(addToRecent) {
++ QSettings settings;
++ QStringList files = settings.value("recentFileList").toStringList();
++ files.removeAll(filename);
++ files.prepend(filename);
++ while (files.size() > MaxRecentFiles)
++ files.removeLast();
++
++ settings.setValue("recentFileList", files);
++ }
++
++ foreach (QWidget *widget, QApplication::topLevelWidgets()) {
++ MainWindow *mainWin = qobject_cast<MainWindow *>(widget);
++ if (mainWin)
++ mainWin->updateRecentFileActions();
++ }
++}
++
++
++void MainWindow::createZoomOptions(SketchAreaWidget* parent) {
++
++ connect(parent->contentView(), SIGNAL(zoomChanged(double)), this, SLOT(updateZoomSlider(double)));
++ connect(parent->contentView(), SIGNAL(zoomOutOfRange(double)), this, SLOT(updateZoomOptionsNoMatterWhat(double)));
++}
++
++ExpandingLabel * MainWindow::createRoutingStatusLabel(SketchAreaWidget * parent) {
++ ExpandingLabel * routingStatusLabel = new ExpandingLabel(m_pcbWidget);
++
++ connect(routingStatusLabel, SIGNAL(mousePressSignal(QMouseEvent*)), this, SLOT(routingStatusLabelMousePress(QMouseEvent*)));
++ connect(routingStatusLabel, SIGNAL(mouseReleaseSignal(QMouseEvent*)), this, SLOT(routingStatusLabelMouseRelease(QMouseEvent*)));
++
++ routingStatusLabel->setTextInteractionFlags(Qt::NoTextInteraction);
++ routingStatusLabel->setCursor(Qt::WhatsThisCursor);
++ routingStatusLabel->viewport()->setCursor(Qt::WhatsThisCursor);
++
++ routingStatusLabel->setObjectName(SketchAreaWidget::RoutingStateLabelName);
++ parent->setRoutingStatusLabel(routingStatusLabel);
++ RoutingStatus routingStatus;
++ routingStatus.zero();
++ routingStatusSlot(qobject_cast<SketchWidget *>(parent->contentView()), routingStatus);
++ return routingStatusLabel;
++}
++
++SketchToolButton *MainWindow::createRotateButton(SketchAreaWidget *parent) {
++ QList<QAction*> rotateMenuActions;
++ rotateMenuActions << m_rotate45ccwAct << m_rotate90ccwAct << m_rotate180Act << m_rotate90cwAct << m_rotate45cwAct;
++ SketchToolButton * rotateButton = new SketchToolButton("Rotate",parent, rotateMenuActions);
++ rotateButton->setDefaultAction(m_rotate90ccwAct);
++ rotateButton->setText(tr("Rotate"));
++
++ m_rotateButtons << rotateButton;
++ return rotateButton;
++}
++
++SketchToolButton *MainWindow::createShareButton(SketchAreaWidget *parent) {
++ SketchToolButton *shareButton = new SketchToolButton("Share",parent, m_shareOnlineAct);
++ shareButton->setText(tr("Share"));
++ shareButton->setEnabledIcon(); // seems to need this to display button icon first time
++ return shareButton;
++}
++
++SketchToolButton *MainWindow::createFlipButton(SketchAreaWidget *parent) {
++ QList<QAction*> flipMenuActions;
++ flipMenuActions << m_flipHorizontalAct << m_flipVerticalAct;
++ SketchToolButton *flipButton = new SketchToolButton("Flip",parent, flipMenuActions);
++ flipButton->setText(tr("Flip"));
++
++ m_flipButtons << flipButton;
++ return flipButton;
++}
++
++SketchToolButton *MainWindow::createAutorouteButton(SketchAreaWidget *parent) {
++ SketchToolButton *autorouteButton = new SketchToolButton("Autoroute",parent, m_newAutorouteAct);
++ autorouteButton->setText(tr("Autoroute"));
++ autorouteButton->setEnabledIcon(); // seems to need this to display button icon first time
++
++ return autorouteButton;
++}
++
++SketchToolButton *MainWindow::createOrderFabButton(SketchAreaWidget *parent) {
++ SketchToolButton *orderFabButton = new SketchToolButton("Order",parent, m_orderFabAct);
++ orderFabButton->setText(tr("Order PCB"));
++ orderFabButton->setEnabledIcon(); // seems to need this to display button icon first time
++
++ return orderFabButton;
++}
++
++QWidget *MainWindow::createActiveLayerButton(SketchAreaWidget *parent)
++{
++ QList<QAction *> actions;
++ actions << m_activeLayerBothAct << m_activeLayerBottomAct << m_activeLayerTopAct;
++
++ m_activeLayerButtonWidget = new QStackedWidget;
++ m_activeLayerButtonWidget->setMaximumWidth(90);
++
++ SketchToolButton * button = new SketchToolButton("ActiveLayer", parent, actions);
++ button->setDefaultAction(m_activeLayerBottomAct);
++ button->setText(tr("Both Layers"));
++ m_activeLayerButtonWidget->addWidget(button);
++
++ button = new SketchToolButton("ActiveLayerB", parent, actions);
++ button->setDefaultAction(m_activeLayerTopAct);
++ button->setText(tr("Bottom Layer"));
++ m_activeLayerButtonWidget->addWidget(button);
++
++ button = new SketchToolButton("ActiveLayerT", parent, actions);
++ button->setDefaultAction(m_activeLayerBothAct);
++ button->setText(tr("Top Layer"));
++ m_activeLayerButtonWidget->addWidget(button);
++
++ return m_activeLayerButtonWidget;
++}
++
++QWidget *MainWindow::createViewFromButton(SketchAreaWidget *parent)
++{
++ QList<QAction *> actions;
++ actions << m_viewFromAboveAct << m_viewFromBelowAct;
++
++ m_viewFromButtonWidget = new QStackedWidget;
++ m_viewFromButtonWidget->setMaximumWidth(90);
++
++ SketchToolButton * button = new SketchToolButton("ViewFromT", parent, actions);
++ button->setDefaultAction(m_viewFromBelowAct);
++ button->setText(tr("View from Above"));
++ button->setEnabledIcon(); // seems to need this to display button icon first time
++
++ m_viewFromButtonWidget->addWidget(button);
++
++ button = new SketchToolButton("ViewFromB", parent, actions);
++ button->setDefaultAction(m_viewFromAboveAct);
++ button->setText(tr("View from Below"));
++ button->setEnabledIcon(); // seems to need this to display button icon first time
++ m_viewFromButtonWidget->addWidget(button);
++
++ return m_viewFromButtonWidget;
++}
++
++SketchToolButton *MainWindow::createNoteButton(SketchAreaWidget *parent) {
++ SketchToolButton *noteButton = new SketchToolButton("Notes",parent, m_addNoteAct);
++ noteButton->setText(tr("Add a note"));
++ noteButton->setEnabledIcon(); // seems to need this to display button icon first time
++ return noteButton;
++}
++
++SketchToolButton *MainWindow::createExportEtchableButton(SketchAreaWidget *parent) {
++ QList<QAction*> actions;
++ actions << m_exportEtchablePdfAct << m_exportEtchableSvgAct << m_exportGerberAct;
++ SketchToolButton *exportEtchableButton = new SketchToolButton("Diy",parent, actions);
++ exportEtchableButton->setDefaultAction(m_exportEtchablePdfAct);
++ exportEtchableButton->setText(tr("Export for PCB"));
++ exportEtchableButton->setEnabledIcon(); // seems to need this to display button icon first time
++ return exportEtchableButton;
++}
++
++QWidget *MainWindow::createToolbarSpacer(SketchAreaWidget *parent) {
++ QFrame *toolbarSpacer = new QFrame(parent);
++ QHBoxLayout *spacerLayout = new QHBoxLayout(toolbarSpacer);
++ spacerLayout->addSpacerItem(new QSpacerItem(0,0,QSizePolicy::Expanding));
++
++ return toolbarSpacer;
++}
++
++QList<QWidget*> MainWindow::getButtonsForView(ViewLayer::ViewID viewId) {
++ QList<QWidget*> retval;
++ SketchAreaWidget *parent;
++ switch(viewId) {
++ case ViewLayer::BreadboardView: parent = m_breadboardWidget; break;
++ case ViewLayer::SchematicView: parent = m_schematicWidget; break;
++ case ViewLayer::PCBView: parent = m_pcbWidget; break;
++ default: return retval;
++ }
++ retval << createShareButton(parent);
++
++ switch(viewId) {
++ case ViewLayer::BreadboardView:
++ case ViewLayer::SchematicView:
++ retval << createNoteButton(parent);
++ default:
++ break;
++ }
++
++ retval << createRotateButton(parent);
++ switch (viewId) {
++ case ViewLayer::BreadboardView:
++ retval << createFlipButton(parent);
++ break;
++ case ViewLayer::SchematicView:
++ retval << createFlipButton(parent) << createToolbarSpacer(parent) << createAutorouteButton(parent);
++ break;
++ case ViewLayer::PCBView:
++ retval << SketchAreaWidget::separator(parent)
++ << createViewFromButton(parent)
++ << createActiveLayerButton(parent)
++ << createAutorouteButton(parent)
++ << createExportEtchableButton(parent);
++ if (m_orderFabEnabled) {
++ SketchToolButton * orderFabButton = createOrderFabButton(parent);
++ retval << orderFabButton;
++ connect(orderFabButton, SIGNAL(entered()), this, SLOT(orderFabHoverEnter()));
++ connect(orderFabButton, SIGNAL(left()), this, SLOT(orderFabHoverLeave()));
++ }
++
++
++ break;
++ default:
++ break;
++ }
++
++ retval << createRoutingStatusLabel(parent);
++ return retval;
++}
++
++void MainWindow::updateZoomSlider(double zoom) {
++ m_zoomSlider->setValue(zoom);
++}
++
++SketchAreaWidget *MainWindow::currentSketchArea() {
++ return dynamic_cast<SketchAreaWidget*>(m_currentGraphicsView->parent());
++}
++
++void MainWindow::updateZoomOptionsNoMatterWhat(double zoom) {
++ m_zoomSlider->setValue(zoom);
++}
++
++void MainWindow::updateViewZoom(double newZoom) {
++ m_comboboxChanged = true;
++ if(m_currentGraphicsView) m_currentGraphicsView->absoluteZoom(newZoom);
++}
++
++
++void MainWindow::createStatusBar()
++{
++ m_statusBar->showMessage(tr("Ready"));
++}
++
++void MainWindow::tabWidget_currentChanged(int index) {
++ SketchAreaWidget * widgetParent = dynamic_cast<SketchAreaWidget *>(currentTabWidget());
++ if (widgetParent == NULL) return;
++
++ m_currentWidget = widgetParent;
++
++ if (m_locationLabel) {
++ m_locationLabel->setText("");
++ }
++
++ QStatusBar *sb = statusBar();
++ connect(sb, SIGNAL(messageChanged(const QString &)), this, SLOT(showStatusMessage(const QString &)));
++ widgetParent->addStatusBar(m_statusBar);
++ if(sb != m_statusBar) sb->hide();
++
++ if (m_breadboardGraphicsView) m_breadboardGraphicsView->setCurrent(false);
++ if (m_schematicGraphicsView) m_schematicGraphicsView->setCurrent(false);
++ if (m_pcbGraphicsView) m_pcbGraphicsView->setCurrent(false);
++
++ SketchWidget *widget = qobject_cast<SketchWidget *>(widgetParent->contentView());
++
++ if(m_currentGraphicsView) {
++ m_currentGraphicsView->saveZoom(m_zoomSlider->value());
++ disconnect(
++ m_currentGraphicsView,
++ SIGNAL(selectionChangedSignal()),
++ this,
++ SLOT(updateTransformationActions())
++ );
++ }
++ m_currentGraphicsView = widget;
++
++ if (m_programView) {
++ hideShowProgramMenu();
++ }
++
++ hideShowTraceMenu();
++
++ if (m_showBreadboardAct) {
++ QList<QAction *> actions;
++ actions << m_showBreadboardAct << m_showSchematicAct << m_showPCBAct;
++ if (m_programView) actions << m_showProgramAct;
++ setActionsIcons(index, actions);
++ }
++
++ if (widget == NULL) return;
++
++ m_zoomSlider->setValue(m_currentGraphicsView->retrieveZoom());
++
++ connect(
++ m_currentGraphicsView, // don't connect directly to the scene here, connect to the widget's signal
++ SIGNAL(selectionChangedSignal()),
++ this,
++ SLOT(updateTransformationActions())
++ );
++
++ updateActiveLayerButtons();
++
++ m_currentGraphicsView->setCurrent(true);
++
++ // !!!!!! hack alert !!!!!!!
++ // this item update loop seems to deal with a qt update bug:
++ // if one view is visible and you change something in another view,
++ // the change might not appear when you switch views until you move the item in question
++ foreach(QGraphicsItem * item, m_currentGraphicsView->items()) {
++ item->update();
++ }
++
++ updateLayerMenu(true);
++ updateTraceMenu();
++ updateTransformationActions();
++
++ setTitle();
++
++ // triggers a signal to the navigator widget
++ if (m_navigators.count() > index) {
++ m_navigators[index]->miniViewMousePressedSlot();
++ }
++ emit viewSwitched(index);
++
++ if (m_showInViewHelpAct) {
++ if (m_helper == NULL) {
++ m_showInViewHelpAct->setChecked(false);
++ }
++ else {
++ m_showInViewHelpAct->setChecked(m_helper->helpVisible(currentTabIndex()));
++ }
++ }
++
++ if (m_infoView) {
++ m_currentGraphicsView->updateInfoView();
++ }
++
++ // update issue with 4.5.1?: is this still valid (4.6.x?)
++ m_currentGraphicsView->updateConnectors();
++
++}
++
++void MainWindow::setActionsIcons(int index, QList<QAction *> & actions) {
++ for (int i = 0; i < actions.count(); i++) {
++ actions[i]->setIcon(index == i ? m_dotIcon : m_emptyIcon);
++ }
++}
++
++void MainWindow::closeEvent(QCloseEvent *event) {
++ if (m_dontClose) {
++ event->ignore();
++ return;
++ }
++
++ if (m_programWindow) {
++ m_programWindow->close();
++ if (m_programWindow->isVisible()) {
++ event->ignore();
++ return;
++ }
++ }
++
++ if (!m_closeSilently) {
++ bool whatWithAliens = whatToDoWithAlienFiles();
++ bool discard;
++ if(!beforeClosing(true, discard) || !whatWithAliens ||!m_binManager->beforeClosing()) {
++ event->ignore();
++ return;
++ }
++
++ if(whatWithAliens && m_binManager->hasAlienParts()) {
++ m_binManager->createIfMyPartsNotExists();
++ }
++ }
++
++ //DebugDialog::debug(QString("top level windows: %1").arg(QApplication::topLevelWidgets().size()));
++ /*
++ foreach (QWidget * widget, QApplication::topLevelWidgets()) {
++ QMenu * menu = qobject_cast<QMenu *>(widget);
++ if (menu != NULL) {
++ continue; // QMenus are always top level widgets, even if they have parents...
++ }
++ DebugDialog::debug(QString("top level widget %1 %2 %3")
++ .arg(widget->metaObject()->className())
++ .arg(widget->windowTitle())
++ .arg(widget->toolTip())
++ );
++ }
++ */
++
++ m_closing = true;
++
++ int count = 0;
++ foreach (QWidget *widget, QApplication::topLevelWidgets()) {
++ if (widget == this) continue;
++ if (qobject_cast<QMainWindow *>(widget) == NULL) continue;
++
++ count++;
++ }
++
++ if (count == 0) {
++ DebugDialog::closeDebug();
++ }
++
++ QSettings settings;
++ settings.setValue(m_settingsPrefix + "state",saveState());
++ settings.setValue(m_settingsPrefix + "geometry",saveGeometry());
++
++ QMainWindow::closeEvent(event);
++}
++
++bool MainWindow::whatToDoWithAlienFiles() {
++ if (m_alienFiles.size() > 0) {
++ QString basename = QFileInfo(m_fwFilename).fileName();
++ QMessageBox::StandardButton reply;
++ reply = QMessageBox::question(this, tr("Save %1").arg(basename),
++ m_alienPartsMsg
++ .arg(basename),
++ QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
++ // TODO: translate button text
++ if (reply == QMessageBox::Yes) {
++ return true;
++ } else if (reply == QMessageBox::No) {
++ foreach(QString pathToRemove, m_alienFiles) {
++ QFile::remove(pathToRemove);
++ }
++ m_alienFiles.clear();
++ recoverBackupedFiles();
++
++ emit alienPartsDismissed();
++ return true;
++ }
++ else {
++ return false;
++ }
++ } else {
++ return true;
++ }
++}
++
++void MainWindow::acceptAlienFiles() {
++ m_alienFiles.clear();
++}
++
++bool MainWindow::eventFilter(QObject *object, QEvent *event) {
++ if (object == this &&
++ (event->type() == QEvent::KeyPress
++ // || event->type() == QEvent::KeyRelease
++ || event->type() == QEvent::ShortcutOverride))
++ {
++ //DebugDialog::debug(QString("event filter %1").arg(event->type()) );
++ updatePartMenu();
++ updateTraceMenu();
++
++ // On the mac, the first time the delete key is pressed, to be used as a shortcut for QAction m_deleteAct,
++ // for some reason, the enabling of the m_deleteAct in UpdateEditMenu doesn't "take" until the next time the event loop is processed
++ // Thereafter, the delete key works as it should.
++ // So this call to processEvents() makes sure m_deleteAct is enabled.
++ ProcessEventBlocker::processEvents();
++ }
++
++ return QMainWindow::eventFilter(object, event);
++}
++
++const QString MainWindow::untitledFileName() {
++ return UntitledSketchName;
++}
++
++int &MainWindow::untitledFileCount() {
++ return UntitledSketchIndex;
++}
++
++const QString MainWindow::fileExtension() {
++ return FritzingBundleExtension;
++}
++
++const QString MainWindow::defaultSaveFolder() {
++ return FolderUtils::openSaveFolder();
++}
++
++bool MainWindow::undoStackIsEmpty() {
++ return m_undoStack->count() == 0;
++}
++
++void MainWindow::setInfoViewOnHover(bool infoViewOnHover) {
++ m_breadboardGraphicsView->setInfoViewOnHover(infoViewOnHover);
++ m_schematicGraphicsView->setInfoViewOnHover(infoViewOnHover);
++ m_pcbGraphicsView->setInfoViewOnHover(infoViewOnHover);
++
++ m_binManager->setInfoViewOnHover(infoViewOnHover);
++}
++
++void MainWindow::loadBundledSketch(const QString &fileName, bool addToRecent, bool setAsLastOpened) {
++
++ QString error;
++ if(!FolderUtils::unzipTo(fileName, m_fzzFolder, error)) {
++ QMessageBox::warning(
++ this,
++ tr("Fritzing"),
++ tr("Unable to open '%1': %2").arg(fileName).arg(error)
++ );
++
++ return;
++ }
++
++ QDir dir(m_fzzFolder);
++ QString binFileName = dir.absoluteFilePath(QFileInfo(BinManager::TempPartsBinTemplateLocation).fileName());
++ m_binManager->setTempPartsBinLocation(binFileName);
++ FolderUtils::copyBin(binFileName, BinManager::TempPartsBinTemplateLocation);
++
++ QStringList namefilters;
++ namefilters << "*"+FritzingSketchExtension;
++ QFileInfoList entryInfoList = dir.entryInfoList(namefilters);
++ if (entryInfoList.count() == 0) {
++ QMessageBox::warning(
++ this,
++ tr("Fritzing"),
++ tr("No Sketch found in '%1'").arg(fileName)
++ );
++
++ return;
++ }
++
++ QFileInfo sketchInfo = entryInfoList[0];
++
++ QString sketchName = dir.absoluteFilePath(sketchInfo.fileName());
++
++ namefilters.clear();
++ namefilters << "*" + FritzingPartExtension;
++ entryInfoList = dir.entryInfoList(namefilters);
++
++ namefilters.clear();
++ namefilters << "*.svg";
++ QFileInfoList svgEntryInfoList = dir.entryInfoList(namefilters);
++
++ m_addedToTemp = false;
++
++ QList<MissingSvgInfo> missing;
++ QList<ModelPart *> missingModelParts;
++
++ foreach (QFileInfo fzpInfo, entryInfoList) {
++ QFile file(dir.absoluteFilePath(fzpInfo.fileName()));
++ if (!file.open(QFile::ReadOnly)) {
++ DebugDialog::debug(QString("unable to open %1: %2").arg(file.fileName()));
++ continue;
++ }
++
++ // TODO: could be more efficient by using a streamreader
++ QString fzp = file.readAll();
++ file.close();
++
++ QString moduleID = TextUtils::parseForModuleID(fzp);
++ if (moduleID.isEmpty()) {
++ DebugDialog::debug("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
++ DebugDialog::debug(QString("unable to find module id in %1: %2").arg(file.fileName()).arg(fzp));
++ DebugDialog::debug("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
++ continue;
++ }
++
++ ModelPart * mp = m_referenceModel->retrieveModelPart(moduleID);
++ if (mp == NULL) {
++ QDomDocument doc;
++ if (!doc.setContent(fzp)) {
++ DebugDialog::debug(QString("unable to parse fzp in %1: %2").arg(file.fileName()).arg(fzp));
++ continue;
++ }
++
++ mp = copyToPartsFolder(fzpInfo, false, PartFactory::folderPath(), "contrib");
++ if (mp == NULL) {
++ DebugDialog::debug(QString("unable to create model part in %1: %2").arg(file.fileName()).arg(fzp));
++ continue;
++ }
++
++ QDomElement root = doc.documentElement();
++ QDomElement views = root.firstChildElement("views");
++ QDomElement view = views.firstChildElement();
++ while (!view.isNull()) {
++ QDomElement layers = view.firstChildElement("layers");
++ QString path = layers.attribute("image", "");
++ if (!path.isEmpty()) {
++ bool copied = copySvg(path, svgEntryInfoList);
++ if (!copied) {
++ DebugDialog::debug(QString("missing svg %1").arg(path));
++ MissingSvgInfo msi;
++ msi.equal = false;
++ msi.modelPart = mp;
++ missingModelParts << mp;
++ msi.requestedPath = path;
++ ViewLayer::ViewID viewID = ViewLayer::idFromXmlName(view.tagName());
++ QDomElement connectors = root.firstChildElement("connectors");
++ QDomElement connector = connectors.firstChildElement("connector");
++ while (!connector.isNull()) {
++ QString id, terminalID;
++ ViewLayer::getConnectorSvgIDs(connector, viewID, id, terminalID);
++ if (!id.isEmpty()) {
++ msi.connectorSvgIds.append(id);
++ }
++ connector = connector.nextSiblingElement("connector");
++ }
++ missing << msi;
++ }
++ }
++ view = view.nextSiblingElement();
++ }
++
++ mp->setFzz(true);
++ }
++
++ if (!missingModelParts.contains(mp)) {
++ m_binManager->addToTempPartsBin(mp);
++ m_addedToTemp = true;
++ }
++ }
++
++ qSort(missing.begin(), missing.end(), byConnectorCount);
++ foreach (MissingSvgInfo msi, missing) {
++ if (msi.equal) {
++ // two or more parts have the same number of connectors--so we can't figure out how to assign them
++ continue;
++ }
++
++ int slash = msi.requestedPath.indexOf("/");
++ QString suffix = msi.requestedPath.mid(slash + 1);
++ QString prefix = msi.requestedPath.left(slash);
++ for (int jx = svgEntryInfoList.count() - 1; jx >= 0; jx--) {
++ QFileInfo svgInfo = svgEntryInfoList.at(jx);
++ if (!svgInfo.fileName().contains(prefix, Qt::CaseInsensitive)) continue;
++
++ QFile svgfile(svgInfo.absoluteFilePath());
++ QDomDocument svgDoc;
++ if (!svgDoc.setContent(&svgfile)) continue;
++
++ QList<QDomElement> elements;
++ QDomElement root = svgDoc.documentElement();
++ TextUtils::findElementsWithAttribute(root, "id", elements);
++ if (elements.count() < msi.connectorSvgIds.count()) continue;
++
++ QStringList ids;
++ foreach (QDomElement element, elements) {
++ ids << element.attribute("id");
++ }
++
++ bool allGood = true;
++ foreach (QString id, msi.connectorSvgIds) {
++ if (!ids.contains(id)) {
++ allGood = false;
++ break;
++ }
++ }
++
++ if (!allGood) continue;
++
++ QString destPath = copyToSvgFolder(svgInfo, false, PartFactory::folderPath(), "contrib"); // copy file with original name
++ if (!destPath.isEmpty()) {
++ QFileInfo destInfo(destPath);
++ QFile file(destPath);
++ DebugDialog::debug(QString("found missing %1").arg(destPath));
++ file.copy(destInfo.absoluteDir().absoluteFilePath(suffix)); // make another copy that has the name used in the fzp file
++ svgEntryInfoList.removeAt(jx);
++ break;
++ }
++ }
++ }
++
++ foreach (ModelPart * mp, missingModelParts) {
++ m_binManager->addToTempPartsBin(mp);
++ m_addedToTemp = true;
++ }
++
++ if (!m_addedToTemp) {
++ m_binManager->hideTempPartsBin();
++ }
++
++ // the bundled itself
++ this->mainLoad(sketchName, "");
++ setCurrentFile(fileName, addToRecent, setAsLastOpened);
++}
++
++bool MainWindow::copySvg(const QString & path, QFileInfoList & svgEntryInfoList)
++{
++ int slash = path.indexOf("/");
++ QString subpath = path.mid(slash + 1);
++ bool gotOne = false;
++ for (int jx = svgEntryInfoList.count() - 1; jx >= 0; jx--) {
++ QFileInfo svgInfo = svgEntryInfoList.at(jx);
++ if (svgInfo.fileName().contains(subpath)) {
++ copyToSvgFolder(svgInfo, false, PartFactory::folderPath(), "contrib");
++ svgEntryInfoList.removeAt(jx);
++ // jrc 30 oct 2012: not sure why we can't just return at this point--can there be other matching files?
++ gotOne = true;
++ }
++ }
++
++ if (gotOne) return true;
++
++ // deal with a bug in which all the svg files exist in the fzz but the fz file points to the wrong name
++ // most of the time it's just a GUID difference
++
++ DebugDialog::debug(QString("svg matching fz path %1 not found").arg(path));
++ int guidix = GuidMatcher.lastIndexIn(subpath);
++ if (guidix < 0) return false;
++
++ QString originalGuid = GuidMatcher.cap(0);
++ QString tryPath = subpath;
++ tryPath.replace(guidix, originalGuid.length(), "%%%%");
++ for (int jx = svgEntryInfoList.count() - 1; jx >= 0; jx--) {
++ QFileInfo svgInfo = svgEntryInfoList.at(jx);
++ QString tempPath = svgInfo.fileName();
++ guidix = GuidMatcher.lastIndexIn(tempPath);
++ if (guidix < 0) continue;
++
++ tempPath.replace(guidix, GuidMatcher.cap(0).length(), "%%%%");
++ if (!tempPath.contains(tryPath)) continue;
++
++ QString destPath = copyToSvgFolder(svgInfo, false, PartFactory::folderPath(), "contrib");
++ if (!destPath.isEmpty()) {
++ QFile file(destPath);
++ guidix = GuidMatcher.lastIndexIn(destPath);
++ destPath.replace(guidix, GuidMatcher.cap(0).length(), originalGuid);
++ file.copy(destPath);
++ DebugDialog::debug(QString("found matching svg %1").arg(destPath));
++ svgEntryInfoList.removeAt(jx);
++ return true;
++ }
++ }
++
++ return false;
++
++}
++
++
++bool MainWindow::loadBundledNonAtomicEntity(const QString &fileName, Bundler* bundler, bool addToBin, bool dontAsk) {
++ QDir destFolder = QDir::temp();
++
++ FolderUtils::createFolderAnCdIntoIt(destFolder, TextUtils::getRandText());
++ QString unzipDirPath = destFolder.path();
++
++ QString error;
++ if(!FolderUtils::unzipTo(fileName, unzipDirPath, error)) {
++ QMessageBox::warning(
++ this,
++ tr("Fritzing"),
++ tr("Unable to open shareable '%1': %2").arg(fileName).arg(error)
++ );
++
++ // gotta return now, or loadBundledSketchAux will crash
++ return false;
++ }
++
++ QDir unzipDir(unzipDirPath);
++
++ if (bundler->preloadBundledAux(unzipDir, dontAsk)) {
++ QList<ModelPart*> mps = moveToPartsFolder(unzipDir,this,addToBin,true,FolderUtils::getUserDataStorePath("parts"), "contrib", false);
++ // the bundled itself
++ bundler->loadBundledAux(unzipDir,mps);
++ }
++
++ FolderUtils::rmdir(unzipDirPath);
++
++ return true;
++}
++
++/*
++void MainWindow::loadBundledPartFromWeb() {
++ QMainWindow *mw = new QMainWindow();
++ QString url = "http://localhost:8081/parts_gen/choose";
++ QWebView *view = new QWebView(mw);
++ mw->setCentralWidget(view);
++ view->setUrl(QUrl(url));
++ mw->show();
++ mw->raise();
++}
++*/
++
++ModelPart* MainWindow::loadBundledPart(const QString &fileName, bool addToBin) {
++ QDir destFolder = QDir::temp();
++
++ FolderUtils::createFolderAnCdIntoIt(destFolder, TextUtils::getRandText());
++ QString unzipDirPath = destFolder.path();
++
++ QString error;
++ if(!FolderUtils::unzipTo(fileName, unzipDirPath, error)) {
++ QMessageBox::warning(
++ this,
++ tr("Fritzing"),
++ tr("Unable to open shareable part '%1': %2").arg(fileName).arg(error)
++ );
++ return NULL;
++ }
++
++ QDir unzipDir(unzipDirPath);
++
++ QList<ModelPart*> mps;
++ try {
++ mps = moveToPartsFolder(unzipDir, this, addToBin, true, FolderUtils::getUserDataStorePath("parts"), "user", true);
++ }
++ catch (const QString & msg) {
++ QMessageBox::warning(
++ this,
++ tr("Fritzing"),
++ msg
++ );
++ return NULL;
++ }
++
++ if (mps.count() != 1) {
++ // if this fails, that means that the bundled was wrong
++ QMessageBox::warning(
++ this,
++ tr("Fritzing"),
++ tr("Unable to load part from '%1'").arg(fileName)
++ );
++ return NULL;
++ }
++
++ FolderUtils::rmdir(unzipDirPath);
++
++ return mps[0];
++}
++
++void MainWindow::saveBundledPart(const QString &moduleId) {
++ QString modIdToExport;
++ ModelPart* mp;
++
++ if(moduleId.isEmpty()) {
++ if (m_currentGraphicsView == NULL) return;
++ PaletteItem *selectedPart = m_currentGraphicsView->getSelectedPart();
++ mp = selectedPart->modelPart();
++ modIdToExport = mp->moduleID();
++ } else {
++ modIdToExport = moduleId;
++ mp = m_referenceModel->retrieveModelPart(moduleId);
++ }
++ QString partTitle = mp->title();
++
++ QString fileExt;
++ QString path = defaultSaveFolder()+"/"+partTitle+FritzingBundledPartExtension;
++ QString bundledFileName = FolderUtils::getSaveFileName(
++ this,
++ tr("Specify a file name"),
++ path,
++ tr("Fritzing Part (*%1)").arg(FritzingBundledPartExtension),
++ &fileExt
++ );
++
++ if (bundledFileName.isEmpty()) return; // Cancel pressed
++
++ if(!alreadyHasExtension(bundledFileName, FritzingBundledPartExtension)) {
++ bundledFileName += FritzingBundledPartExtension;
++ }
++
++ QDir destFolder = QDir::temp();
++
++ FolderUtils::createFolderAnCdIntoIt(destFolder, TextUtils::getRandText());
++ QString dirToRemove = destFolder.path();
++
++ QString aux = QFileInfo(bundledFileName).fileName();
++ QString destPartPath = // remove the last "z" from the extension
++ destFolder.path()+"/"+aux.left(aux.size()-1);
++ DebugDialog::debug("saving part temporarily to "+destPartPath);
++
++ //bool wasModified = isWindowModified();
++ //QString prevFileName = m_fileName;
++ //saveAsAux(destPartPath);
++ //m_fileName = prevFileName;
++ //setWindowModified(wasModified);
++ setTitle();
++
++ saveBundledAux(mp, destFolder);
++
++ QStringList skipSuffixes;
++ if(!FolderUtils::createZipAndSaveTo(destFolder, bundledFileName, skipSuffixes)) {
++ QMessageBox::warning(
++ this,
++ tr("Fritzing"),
++ tr("Unable to export %1 to shareable sketch").arg(bundledFileName)
++ );
++ }
++
++ FolderUtils::rmdir(dirToRemove);
++}
++
++QStringList MainWindow::saveBundledAux(ModelPart *mp, const QDir &destFolder) {
++ QStringList names;
++ QString partPath = mp->path();
++ QFile file(partPath);
++ QString fn = ZIP_PART + QFileInfo(partPath).fileName();
++ names << fn;
++ file.copy(destFolder.path()+"/"+fn);
++
++ QList<ViewLayer::ViewID> viewIDs;
++ viewIDs << ViewLayer::IconView << ViewLayer::BreadboardView << ViewLayer::SchematicView << ViewLayer::PCBView;
++ foreach (ViewLayer::ViewID viewID, viewIDs) {
++ QString basename = mp->hasBaseNameFor(viewID);
++ if (basename.isEmpty()) continue;
++
++ QString filename = PartFactory::getSvgFilename(mp, basename, true, true);
++ if (filename.isEmpty()) continue;
++
++ QFile file(filename);
++ basename.replace("/", ".");
++ QString fn = ZIP_SVG + basename;
++ names << fn;
++ file.copy(destFolder.path()+"/"+fn);
++ }
++
++ return names;
++}
++
++QList<ModelPart*> MainWindow::moveToPartsFolder(QDir &unzipDir, MainWindow* mw, bool addToBin, bool addToAlien, const QString & prefixFolder, const QString &destFolder, bool importingSinglePart) {
++ QStringList namefilters;
++ QList<ModelPart*> retval;
++
++ if (mw == NULL) {
++ throw tr("MainWindow::moveToPartsFolder mainwindow missing");
++ }
++
++ namefilters.clear();
++ namefilters << ZIP_PART+"*";
++ QList<QFileInfo> partEntryInfoList = unzipDir.entryInfoList(namefilters);
++
++ if (importingSinglePart && partEntryInfoList.count() > 0) {
++ // TODO use a stream reader
++ QFile file(partEntryInfoList[0].absoluteFilePath());
++ file.open(QFile::ReadOnly);
++ QString fzp = file.readAll();
++ file.close();
++ QString moduleID = TextUtils::parseForModuleID(fzp);
++ if (!moduleID.isEmpty() && m_referenceModel->retrieveModelPart(moduleID) != NULL) {
++ throw tr("There is already a part with id '%1' loaded into Fritzing.").arg(moduleID);
++ }
++ }
++
++
++ namefilters.clear();
++ namefilters << ZIP_SVG+"*";
++ foreach(QFileInfo file, unzipDir.entryInfoList(namefilters)) { // svg files
++ //DebugDialog::debug("unzip svg " + file.absoluteFilePath());
++ mw->copyToSvgFolder(file, addToAlien, prefixFolder, destFolder);
++ }
++
++
++ foreach(QFileInfo file, partEntryInfoList) { // part files
++ //DebugDialog::debug("unzip part " + file.absoluteFilePath());
++ ModelPart * mp = mw->copyToPartsFolder(file, addToAlien, prefixFolder, destFolder);
++ retval << mp;
++ if (addToBin) {
++ // should only be here when adding single new part
++ m_binManager->addToMyParts(mp);
++ }
++ }
++
++
++
++ return retval;
++}
++
++QString MainWindow::copyToSvgFolder(const QFileInfo& file, bool addToAlien, const QString & prefixFolder, const QString &destFolder) {
++ QFile svgfile(file.filePath());
++ // let's make sure that we remove just the suffix
++ QString fileName = file.fileName().remove(QRegExp("^"+ZIP_SVG));
++ QString viewFolder = fileName.left(fileName.indexOf("."));
++ fileName.remove(0, viewFolder.length() + 1);
++
++ QString destFilePath =
++ prefixFolder+"/svg/"+destFolder+"/"+viewFolder+"/"+fileName;
++
++ backupExistingFileIfExists(destFilePath);
++ if(svgfile.copy(destFilePath)) {
++ if (addToAlien) {
++ m_alienFiles << destFilePath;
++ }
++ return destFilePath;
++ }
++
++ return "";
++}
++
++ModelPart* MainWindow::copyToPartsFolder(const QFileInfo& file, bool addToAlien, const QString & prefixFolder, const QString &destFolder) {
++ QFile partfile(file.filePath());
++ // let's make sure that we remove just the suffix
++ QString destFilePath =
++ prefixFolder+"/"+destFolder+"/"+file.fileName().remove(QRegExp("^"+ZIP_PART));
++
++ backupExistingFileIfExists(destFilePath);
++ if(partfile.copy(destFilePath)) {
++ if (addToAlien) {
++ m_alienFiles << destFilePath;
++ m_alienPartsMsg = tr("Do you want to keep the imported parts?");
++ }
++ }
++ ModelPart *mp = m_referenceModel->loadPart(destFilePath, true);
++ mp->setAlien(true);
++
++ return mp;
++}
++
++void MainWindow::binSaved(bool hasPartsFromBundled) {
++ if(hasPartsFromBundled) {
++ // the bin will need those parts, so just keep them
++ m_alienFiles.clear();
++ resetTempFolder();
++ }
++}
++
++#undef ZIP_PART
++#undef ZIP_SVG
++
++
++void MainWindow::backupExistingFileIfExists(const QString &destFilePath) {
++ if(QFileInfo(destFilePath).exists()) {
++ if(m_tempDir.path() == ".") {
++ m_tempDir = QDir::temp();
++ FolderUtils::createFolderAnCdIntoIt(m_tempDir, TextUtils::getRandText());
++ DebugDialog::debug("debug folder for overwritten files: "+m_tempDir.path());
++ }
++
++ QString fileBackupName = QFileInfo(destFilePath).fileName();
++ m_filesReplacedByAlienOnes << destFilePath;
++ QFile file(destFilePath);
++ bool alreadyExists = file.exists();
++ file.copy(m_tempDir.path()+"/"+fileBackupName);
++
++ if(alreadyExists) {
++ file.remove(destFilePath);
++ }
++ }
++}
++
++void MainWindow::recoverBackupedFiles() {
++ foreach(QString originalFilePath, m_filesReplacedByAlienOnes) {
++ QFile file(m_tempDir.path()+"/"+QFileInfo(originalFilePath).fileName());
++ if(file.exists(originalFilePath)) {
++ file.remove();
++ }
++ file.copy(originalFilePath);
++ }
++ resetTempFolder();
++}
++
++void MainWindow::resetTempFolder() {
++ if(m_tempDir.path() != ".") {
++ FolderUtils::rmdir(m_tempDir);
++ m_tempDir = QDir::temp();
++ }
++ m_filesReplacedByAlienOnes.clear();
++}
++
++void MainWindow::routingStatusSlot(SketchWidget * sketchWidget, const RoutingStatus & routingStatus) {
++ m_routingStatus = routingStatus;
++ QString theText;
++ if (routingStatus.m_netCount == 0) {
++ theText = tr("No connections to route");
++ } else if (routingStatus.m_netCount == routingStatus.m_netRoutedCount) {
++ if (routingStatus.m_jumperItemCount == 0) {
++ theText = tr("Routing completed");
++ }
++ else {
++ theText = tr("Routing completed using %n jumper part(s)", "", routingStatus.m_jumperItemCount);
++ }
++ } else {
++ theText = tr("%1 of %2 nets routed - %n connector(s) still to be routed", "", routingStatus.m_connectorsLeftToRoute)
++ .arg(routingStatus.m_netRoutedCount)
++ .arg(routingStatus.m_netCount);
++ }
++
++ dynamic_cast<SketchAreaWidget *>(sketchWidget->parent())->routingStatusLabel()->setLabelText(theText);
++
++ updateTraceMenu();
++}
++
++void MainWindow::applyReadOnlyChange(bool isReadOnly) {
++ Q_UNUSED(isReadOnly);
++ //m_saveAct->setDisabled(isReadOnly);
++}
++
++void MainWindow::currentNavigatorChanged(MiniViewContainer * miniView)
++{
++ int index = m_navigators.indexOf(miniView);
++ if (index < 0) return;
++
++ int oldIndex = currentTabIndex();
++ if (oldIndex == index) return;
++
++ setCurrentTabIndex(index);
++}
++
++void MainWindow::viewSwitchedTo(int viewIndex) {
++ setCurrentTabIndex(viewIndex);
++}
++
++const QString MainWindow::fritzingTitle() {
++ if (m_currentGraphicsView == NULL) {
++ return FritzingWindow::fritzingTitle();
++ }
++
++ QString fritzing = FritzingWindow::fritzingTitle();
++ return tr("%1 - [%2]").arg(fritzing).arg(m_currentGraphicsView->viewName());
++}
++
++QAction *MainWindow::raiseWindowAction() {
++ return m_raiseWindowAct;
++}
++
++void MainWindow::raiseAndActivate() {
++ if(isMinimized()) {
++ showNormal();
++ }
++ raise();
++ QTimer::singleShot(20, this, SLOT(activateWindowAux()));
++}
++
++void MainWindow::activateWindowAux() {
++ activateWindow();
++}
++
++void MainWindow::updateRaiseWindowAction() {
++ QString actionText;
++ QFileInfo fileInfo(m_fwFilename);
++ if(fileInfo.exists()) {
++ int lastSlashIdx = m_fwFilename.lastIndexOf("/");
++ int beforeLastSlashIdx = m_fwFilename.left(lastSlashIdx).lastIndexOf("/");
++ actionText = beforeLastSlashIdx > -1 && lastSlashIdx > -1 ? "..." : "";
++ actionText += m_fwFilename.right(m_fwFilename.size()-beforeLastSlashIdx-1);
++ } else {
++ actionText = m_fwFilename;
++ }
++ m_raiseWindowAct->setText(actionText);
++ m_raiseWindowAct->setToolTip(m_fwFilename);
++ m_raiseWindowAct->setStatusTip("raise \""+m_fwFilename+"\" window");
++}
++
++QSizeGrip *MainWindow::sizeGrip() {
++ return m_sizeGrip;
++}
++
++QStatusBar *MainWindow::realStatusBar() {
++ return m_statusBar;
++}
++
++void MainWindow::moveEvent(QMoveEvent * event) {
++ FritzingWindow::moveEvent(event);
++ emit mainWindowMoved(this);
++}
++
++bool MainWindow::event(QEvent * e) {
++ switch (e->type()) {
++ case QEvent::WindowActivate:
++ emit changeActivationSignal(true, this);
++ break;
++ case QEvent::WindowDeactivate:
++ emit changeActivationSignal(false, this);
++ break;
++ default:
++ break;
++ }
++ return FritzingWindow::event(e);
++}
++
++void MainWindow::resizeEvent(QResizeEvent * event) {
++ if (m_sizeGrip) {
++ m_sizeGrip->rearrange();
++ }
++ FritzingWindow::resizeEvent(event);
++}
++
++void MainWindow::showInViewHelp() {
++ //delete m_helper;
++ if (m_helper == NULL) {
++ m_helper = new Helper(this, true);
++ return;
++ }
++
++ bool toggle = !m_helper->helpVisible(currentTabIndex());
++ showAllFirstTimeHelp(toggle);
++
++ /*
++ m_helper->toggleHelpVisibility(currentTabIndex());
++ */
++
++ m_showInViewHelpAct->setChecked(m_helper->helpVisible(currentTabIndex()));
++}
++
++
++void MainWindow::showAllFirstTimeHelp(bool show) {
++ if (m_helper) {
++ for (int i = 0; i < 3; i++) {
++ m_helper->setHelpVisibility(i, show);
++ }
++ }
++ m_showInViewHelpAct->setChecked(show);
++}
++
++void MainWindow::enableCheckUpdates(bool enabled)
++{
++ if (m_checkForUpdatesAct != NULL) {
++ m_checkForUpdatesAct->setEnabled(enabled);
++ }
++}
++
++
++void MainWindow::swapSelectedDelay(const QString & family, const QString & prop, QMap<QString, QString> & currPropsMap, ItemBase * itemBase)
++{
++ m_swapTimer.stop();
++ m_swapTimer.setAll(family, prop, currPropsMap, itemBase);
++ m_swapTimer.start();
++}
++
++void MainWindow::swapSelectedTimeout()
++{
++ if (sender() == &m_swapTimer) {
++ QMap<QString, QString> map = m_swapTimer.propsMap();
++ swapSelectedMap(m_swapTimer.family(), m_swapTimer.prop(), map, m_swapTimer.itemBase());
++ }
++}
++
++void MainWindow::swapSelectedMap(const QString & family, const QString & prop, QMap<QString, QString> & currPropsMap, ItemBase * itemBase)
++{
++ if (itemBase == NULL) return;
++
++ QString generatedModuleID = currPropsMap.value("moduleID");
++
++ if (generatedModuleID.isEmpty()) {
++ if (prop.compare("layer") == 0) {
++ if (family.compare("logo") == 0 || family.compare("pad") == 0 || family.contains("blocker", Qt::CaseInsensitive)) {
++ QString value = Board::convertToXmlName(currPropsMap.value(prop));
++ if (value.contains("copper1") && m_currentGraphicsView->boardLayers() == 1) {
++ QMessageBox::warning(
++ this,
++ tr("No copper top layer"),
++ 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.")
++ );
++ return;
++ }
++ // use the xml name
++ currPropsMap.insert(prop, value);
++ }
++ else if (itemBase->itemType() == ModelPart::Wire) {
++ // assume this option is disabled for a one-sided board, so we would not get here?
++ m_pcbGraphicsView->changeTraceLayer(itemBase, false, NULL);
++ return;
++ }
++ }
++ }
++
++ if (generatedModuleID.isEmpty()) {
++ if (family.compare("Prototyping Board", Qt::CaseInsensitive) == 0) {
++ if (prop.compare("size", Qt::CaseInsensitive) == 0 || prop.compare("type", Qt::CaseInsensitive) == 0) {
++ QString size = currPropsMap.value("size");
++ QString type = currPropsMap.value("type");
++ if (type.compare("perfboard", Qt::CaseInsensitive) == 0) {
++ generatedModuleID = Perfboard::genModuleID(currPropsMap);
++ }
++ else if (type.compare("stripboard", Qt::CaseInsensitive) == 0) {
++ generatedModuleID = Stripboard::genModuleID(currPropsMap);
++ }
++ }
++ }
++ }
++
++ bool swapLayer = false;
++ ViewLayer::ViewLayerPlacement newViewLayerPlacement = ViewLayer::UnknownPlacement;
++ if (prop.compare("layer") == 0) {
++ if (itemBase->modelPart()->flippedSMD() || itemBase->itemType() == ModelPart::Part) {
++ ItemBase * viewItem = itemBase->modelPart()->viewItem(ViewLayer::PCBView);
++ if (viewItem) {
++ ViewLayer::ViewLayerPlacement vlp = (currPropsMap.value(prop) == ItemBase::TranslatedPropertyNames.value("bottom") ? ViewLayer::NewBottom : ViewLayer::NewTop);
++ if (viewItem->viewLayerPlacement() != newViewLayerPlacement) {
++ swapLayer = true;
++ newViewLayerPlacement = vlp;
++ }
++ }
++ }
++ }
++
++ if (!generatedModuleID.isEmpty()) {
++ ModelPart * modelPart = m_referenceModel->retrieveModelPart(generatedModuleID);
++ if (modelPart == NULL) {
++ if (!m_referenceModel->genFZP(generatedModuleID, m_referenceModel)) {
++ return;
++ }
++ }
++
++ swapSelectedAux(itemBase->layerKinChief(), generatedModuleID, swapLayer, newViewLayerPlacement, currPropsMap);
++ return;
++ }
++
++ if (swapLayer) {
++ swapSelectedAux(itemBase->layerKinChief(), itemBase->moduleID(), true, newViewLayerPlacement, currPropsMap);
++ return;
++ }
++
++ if ((prop.compare("package", Qt::CaseSensitive) != 0) && swapSpecial(prop, currPropsMap)) {
++ return;
++ }
++
++ foreach (QString key, currPropsMap.keys()) {
++ QString value = currPropsMap.value(key);
++ m_referenceModel->recordProperty(key, value);
++ }
++
++ QString moduleID = m_referenceModel->retrieveModuleIdWith(family, prop, true);
++ bool exactMatch = m_referenceModel->lastWasExactMatch();
++
++ if (moduleID.isEmpty()) {
++ QMessageBox::information(
++ this,
++ tr("Sorry!"),
++ tr(
++ "No part with those characteristics.\n"
++ "We're working to avoid this message, and only let you choose between properties that do exist")
++ );
++ return;
++ }
++
++
++
++ itemBase = itemBase->layerKinChief();
++
++ if(!exactMatch) {
++ AutoCloseMessageBox::showMessage(this, tr("No exactly matching part found; Fritzing chose the closest match."));
++ }
++
++ swapSelectedAux(itemBase, moduleID, false, ViewLayer::UnknownPlacement, currPropsMap);
++}
++
++bool MainWindow::swapSpecial(const QString & theProp, QMap<QString, QString> & currPropsMap) {
++ ItemBase * itemBase = m_infoView->currentItem();
++ QString pinSpacing, resistance;
++ int layers = 0;
++
++ foreach (QString key, currPropsMap.keys()) {
++ if (key.compare("layers", Qt::CaseInsensitive) == 0) {
++ if (!Board::isBoard(itemBase)) continue;
++
++ QString value = currPropsMap.value(key, "");
++ if (value.compare(Board::OneLayerTranslated) == 0) {
++ layers = 1;
++ }
++ else if (value.compare(Board::TwoLayersTranslated) == 0) {
++ layers = 2;
++ }
++ }
++
++ if (key.compare("resistance", Qt::CaseInsensitive) == 0) {
++ resistance = currPropsMap.value(key);
++ continue;
++ }
++ if (key.compare("pin spacing", Qt::CaseInsensitive) == 0) {
++ pinSpacing = currPropsMap.value(key);
++ continue;
++ }
++ }
++
++ if (layers != 0) {
++ currPropsMap.insert("layers", QString::number(layers));
++ if (theProp.compare("layers") == 0) {
++ QString msg = (layers == 1) ? tr("Change to single layer pcb") : tr("Change to two layer pcb");
++ swapLayers(itemBase, layers, msg, SketchWidget::PropChangeDelay);
++ return true;
++ }
++ }
++
++ if (!resistance.isEmpty() || !pinSpacing.isEmpty()) {
++ if (theProp.contains("band", Qt::CaseInsensitive)) {
++ // swap 4band for 5band or vice versa.
++ return false;
++ }
++
++ Resistor * resistor = qobject_cast<Resistor *>(itemBase);
++ if (resistor != NULL) {
++ m_currentGraphicsView->setResistance(resistance, pinSpacing);
++ return true;
++ }
++ }
++
++ return false;
++}
++
++void MainWindow::swapLayers(ItemBase * itemBase, int layers, const QString & msg, int delay) {
++ QUndoCommand* parentCommand = new QUndoCommand(msg);
++ new CleanUpWiresCommand(m_breadboardGraphicsView, CleanUpWiresCommand::UndoOnly, parentCommand);
++ new CleanUpRatsnestsCommand(m_breadboardGraphicsView, CleanUpWiresCommand::UndoOnly, parentCommand);
++ m_pcbGraphicsView->swapLayers(itemBase, layers, parentCommand);
++ // need to defer execution so the content of the info view doesn't change during an event that started in the info view
++ m_undoStack->waitPush(parentCommand, delay);
++}
++
++void MainWindow::swapSelectedAux(ItemBase * itemBase, const QString & moduleID, bool useViewLayerPlacement, ViewLayer::ViewLayerPlacement overrideViewLayerPlacement, QMap<QString, QString> & propsMap) {
++
++ QUndoCommand* parentCommand = new QUndoCommand(tr("Swapped %1 with module %2").arg(itemBase->instanceTitle()).arg(moduleID));
++ new CleanUpWiresCommand(m_breadboardGraphicsView, CleanUpWiresCommand::UndoOnly, parentCommand);
++ new CleanUpRatsnestsCommand(m_breadboardGraphicsView, CleanUpWiresCommand::UndoOnly, parentCommand);
++
++ ViewLayer::ViewLayerPlacement viewLayerPlacement = itemBase->viewLayerPlacement();
++ ModelPart * modelPart = m_referenceModel->retrieveModelPart(moduleID);
++ if (m_pcbGraphicsView->boardLayers() == 2) {
++ if (modelPart->flippedSMD()) {
++ //viewLayerPlacement = m_pcbGraphicsView->dropOnBottom() ? ViewLayer::NewBottom : ViewLayer::NewTop;
++ if (useViewLayerPlacement) viewLayerPlacement = overrideViewLayerPlacement;
++ }
++ else if (modelPart->itemType() == ModelPart::Part) {
++ //viewLayerPlacement = m_pcbGraphicsView->dropOnBottom() ? ViewLayer::NewBottom : ViewLayer::NewTop;
++ if (useViewLayerPlacement) viewLayerPlacement = overrideViewLayerPlacement;
++ }
++ }
++ else {
++ if (modelPart->flippedSMD()) {
++ viewLayerPlacement = ViewLayer::NewBottom;
++ }
++ else if (modelPart->itemType() == ModelPart::Part) {
++ //viewLayerPlacement = m_pcbGraphicsView->dropOnBottom() ? ViewLayer::NewBottom : ViewLayer::NewTop;
++ if (useViewLayerPlacement) viewLayerPlacement = overrideViewLayerPlacement;
++ }
++ }
++
++ swapSelectedAuxAux(itemBase, moduleID, viewLayerPlacement, propsMap, parentCommand);
++
++ // need to defer execution so the content of the info view doesn't change during an event that started in the info view
++ m_undoStack->waitPush(parentCommand, SketchWidget::PropChangeDelay);
++
++}
++
++void MainWindow::swapBoardImageSlot(SketchWidget * sketchWidget, ItemBase * itemBase, const QString & filename, const QString & moduleID, bool addName) {
++
++ QUndoCommand* parentCommand = new QUndoCommand(tr("Change image to %2").arg(filename));
++ QMap<QString, QString> propsMap;
++ long newID = swapSelectedAuxAux(itemBase, moduleID, itemBase->viewLayerPlacement(), propsMap, parentCommand);
++
++ LoadLogoImageCommand * cmd = new LoadLogoImageCommand(sketchWidget, newID, "", QSizeF(0,0), filename, filename, addName, parentCommand);
++ cmd->setRedoOnly();
++
++ // need to defer execution so the content of the info view doesn't change during an event that started in the info view
++ m_undoStack->waitPush(parentCommand, SketchWidget::PropChangeDelay);
++}
++
++
++void MainWindow::subSwapSlot(SketchWidget * sketchWidget, ItemBase * itemBase, const QString & newModuleID, ViewLayer::ViewLayerPlacement viewLayerPlacement, long & newID, QUndoCommand * parentCommand) {
++ Q_UNUSED(sketchWidget);
++ QMap<QString, QString> propsMap;
++ newID = swapSelectedAuxAux(itemBase, newModuleID, viewLayerPlacement, propsMap, parentCommand);
++}
++
++long MainWindow::swapSelectedAuxAux(ItemBase * itemBase, const QString & moduleID, ViewLayer::ViewLayerPlacement viewLayerPlacement, QMap<QString, QString> & propsMap, QUndoCommand * parentCommand)
++{
++ long modelIndex = ModelPart::nextIndex();
++
++ QList<SketchWidget *> sketchWidgets;
++
++ // master view must go last, since it creates the delete command, and possibly has all the local props
++ switch (itemBase->viewID()) {
++ case ViewLayer::SchematicView:
++ sketchWidgets << m_pcbGraphicsView << m_breadboardGraphicsView << m_schematicGraphicsView;
++ break;
++ case ViewLayer::PCBView:
++ sketchWidgets << m_schematicGraphicsView << m_breadboardGraphicsView << m_pcbGraphicsView;
++ break;
++ default:
++ sketchWidgets << m_schematicGraphicsView << m_pcbGraphicsView << m_breadboardGraphicsView;
++ break;
++ }
++
++ SwapThing swapThing;
++ swapThing.firstTime = true;
++ swapThing.itemBase = itemBase;
++ swapThing.newModelIndex = modelIndex;
++ swapThing.newModuleID = moduleID;
++ swapThing.viewLayerPlacement = viewLayerPlacement;
++ swapThing.parentCommand = parentCommand;
++ swapThing.propsMap = propsMap;
++
++ long newID = 0;
++ for (int i = 0; i < 3; i++) {
++ long tempID = sketchWidgets[i]->setUpSwap(swapThing, i == 2);
++ if (newID == 0 && tempID != 0) newID = tempID;
++ }
++
++ // TODO: z-order?
++
++ return newID;
++}
++
++void MainWindow::svgMissingLayer(const QString & layername, const QString & path) {
++ QMessageBox::warning(
++ this,
++ tr("Fritzing"),
++ tr("Svg %1 is missing a '%2' layer. "
++ "For more information on how to create a custom board shape, "
++ "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>.")
++ .arg(path)
++ .arg(layername)
++ );
++}
++
++void MainWindow::addDefaultParts() {
++ if (m_pcbGraphicsView == NULL) return;
++
++ m_pcbGraphicsView->addDefaultParts();
++ m_breadboardGraphicsView->addDefaultParts();
++ m_schematicGraphicsView->addDefaultParts();
++}
++
++MainWindow * MainWindow::newMainWindow(ReferenceModel *referenceModel, const QString & displayPath, bool showProgress, bool lockFiles) {
++ MainWindow * mw = new MainWindow(referenceModel, NULL);
++ if (showProgress) {
++ mw->showFileProgressDialog(displayPath);
++ }
++
++ mw->init(referenceModel, lockFiles);
++
++ return mw;
++}
++
++void MainWindow::clearFileProgressDialog() {
++ if (m_fileProgressDialog) {
++ m_fileProgressDialog->close();
++ delete m_fileProgressDialog;
++ m_fileProgressDialog = NULL;
++ }
++}
++
++void MainWindow::setFileProgressPath(const QString & path)
++{
++ if (m_fileProgressDialog) m_fileProgressDialog->setMessage(tr("loading %1").arg(path));
++}
++
++FileProgressDialog * MainWindow::fileProgressDialog()
++{
++ return m_fileProgressDialog;
++}
++
++void MainWindow::showFileProgressDialog(const QString & path) {
++ m_fileProgressDialog = new FileProgressDialog(tr("Loading..."), 200, this);
++ m_fileProgressDialog->setBinLoadingChunk(50);
++ if (!path.isEmpty()) {
++ setFileProgressPath(QFileInfo(path).fileName());
++ }
++ else {
++ setFileProgressPath(tr("new sketch"));
++ }
++}
++
++const QString &MainWindow::selectedModuleID() {
++ if(m_currentGraphicsView) {
++ return m_currentGraphicsView->selectedModuleID();
++ } else {
++ return ___emptyString___;
++ }
++}
++
++void MainWindow::redrawSketch() {
++ QList<ConnectorItem *> visited;
++ foreach (QGraphicsItem * item, m_currentGraphicsView->scene()->items()) {
++ item->update();
++ ConnectorItem * c = dynamic_cast<ConnectorItem *>(item);
++ if (c != NULL) {
++ c->restoreColor(visited);
++ }
++ }
++}
++
++void MainWindow::statusMessage(QString message, int timeout) {
++ QStatusBar * sb = realStatusBar();
++ if (sb != NULL) {
++ sb->showMessage(message, timeout);
++ }
++}
++
++void MainWindow::dropPaste(SketchWidget * sketchWidget) {
++ Q_UNUSED(sketchWidget);
++ pasteInPlace();
++}
++
++void MainWindow::updateLayerMenuSlot() {
++ updateLayerMenu(true);
++}
++
++bool MainWindow::save() {
++ bool result = FritzingWindow::save();
++ if (result) {
++ QSettings settings;
++ settings.setValue("lastOpenSketch", m_fwFilename);
++ }
++ return result;
++}
++
++bool MainWindow::saveAs() {
++ bool result = false;
++ if (m_fwFilename.endsWith(FritzingSketchExtension)) {
++ result = FritzingWindow::saveAs(m_fwFilename + 'z', false);
++ }
++ else {
++ result = FritzingWindow::saveAs();
++ }
++ if (result) {
++ QSettings settings;
++ settings.setValue("lastOpenSketch", m_fwFilename);
++ }
++ return result;
++}
++
++void MainWindow::changeBoardLayers(int layers, bool doEmit) {
++ Q_UNUSED(doEmit);
++ Q_UNUSED(layers);
++ updateActiveLayerButtons();
++ m_currentGraphicsView->updateConnectors();
++}
++
++void MainWindow::updateActiveLayerButtons() {
++ if (m_activeLayerButtonWidget != NULL) {
++ int index = activeLayerIndex();
++ bool enabled = index >= 0;
++
++ m_activeLayerButtonWidget->setCurrentIndex(index);
++ m_activeLayerButtonWidget->setVisible(enabled);
++
++ m_activeLayerBothAct->setEnabled(enabled);
++ m_activeLayerBottomAct->setEnabled(enabled);
++ m_activeLayerTopAct->setEnabled(enabled);
++
++ QList<QAction *> actions;
++ actions << m_activeLayerBothAct << m_activeLayerBottomAct << m_activeLayerTopAct;
++ setActionsIcons(index, actions);
++ }
++
++ if (m_viewFromButtonWidget != NULL) {
++ if (m_pcbGraphicsView) {
++ bool viewFromBelow = m_pcbGraphicsView->viewFromBelow();
++ int index = (viewFromBelow ? 1 : 0);
++ m_viewFromButtonWidget->setCurrentIndex(index);
++ m_viewFromButtonWidget->setVisible(true);
++ m_viewFromBelowToggleAct->setChecked(viewFromBelow);
++
++ m_viewFromBelowToggleAct->setEnabled(true);
++ m_viewFromBelowAct->setEnabled(true);
++ m_viewFromAboveAct->setEnabled(true);
++ }
++ }
++}
++
++int MainWindow::activeLayerIndex()
++{
++ if (m_currentGraphicsView == NULL) return -1;
++
++ if (m_currentGraphicsView->boardLayers() == 2 || activeLayerWidgetAlwaysOn()) {
++ bool copper0Visible = m_currentGraphicsView->layerIsActive(ViewLayer::Copper0);
++ bool copper1Visible = m_currentGraphicsView->layerIsActive(ViewLayer::Copper1);
++ if (copper0Visible && copper1Visible) {
++ return 0;
++ }
++ else if (copper1Visible) {
++ return 2;
++ }
++ else if (copper0Visible) {
++ return 1;
++ }
++ }
++
++ return -1;
++}
++
++bool MainWindow::activeLayerWidgetAlwaysOn() {
++ return false;
++}
++
++/**
++ * A slot for saving a copy of the current sketch to a temp location.
++ * This should be called every X minutes as well as just before certain
++ * events, such as saves, part imports, file export/printing. This relies
++ * on the m_autosaveNeeded variable and the undoStack being dirty for
++ * an autosave to be attempted.
++ */
++void MainWindow::backupSketch() {
++ if (ProcessEventBlocker::isProcessing()) {
++ // don't want to autosave during autorouting, for example
++ return;
++ }
++
++ if (m_autosaveNeeded && !m_undoStack->isClean()) {
++ m_autosaveNeeded = false; // clear this now in case the save takes a really long time
++
++ DebugDialog::debug(QString("%1 autosaved as %2").arg(m_fwFilename).arg(m_backupFileNameAndPath));
++ statusBar()->showMessage(tr("Backing up '%1'").arg(m_fwFilename), 2000);
++ ProcessEventBlocker::processEvents();
++ m_backingUp = true;
++ connectStartSave(true);
++ m_sketchModel->save(m_backupFileNameAndPath, false);
++ connectStartSave(false);
++ m_backingUp = false;
++ }
++}
++
++/**
++ * This function is used to trigger an autosave at the next autosave
++ * timer event. It is connected to the QUndoStack::indexChanged(int)
++ * signal so that any change to the undo stack triggers autosaves.
++ * This function can be called independent of this signal and
++ * still work properly.
++ */
++void MainWindow::autosaveNeeded(int index) {
++ Q_UNUSED(index);
++ //DebugDialog::debug(QString("Triggering autosave"));
++ m_autosaveNeeded = true;
++}
++
++/**
++ * delete the backup file when the undostack is clean.
++ */
++void MainWindow::undoStackCleanChanged(bool isClean) {
++ // DebugDialog::debug(QString("Clean status changed to %1").arg(isClean));
++ if (isClean) {
++ QFile::remove(m_backupFileNameAndPath);
++ }
++}
++
++void MainWindow::setAutosavePeriod(int minutes) {
++ setAutosave(minutes, AutosaveEnabled);
++}
++
++void MainWindow::setAutosaveEnabled(bool enabled) {
++ setAutosave(AutosaveTimeoutMinutes, enabled);
++}
++
++void MainWindow::setAutosave(int minutes, bool enabled) {
++ AutosaveTimeoutMinutes = minutes;
++ AutosaveEnabled = enabled;
++ foreach (QWidget * widget, QApplication::topLevelWidgets()) {
++ MainWindow * mainWindow = qobject_cast<MainWindow *>(widget);
++ if (mainWindow == NULL) continue;
++
++ mainWindow->m_autosaveTimer.stop();
++ if (qobject_cast<PEMainWindow *>(widget)) {
++ continue;
++ }
++
++ if (AutosaveEnabled) {
++ // is there a way to get the current timer offset so that all the timers aren't running in sync?
++ // or just add some random time...
++ mainWindow->m_autosaveTimer.start(AutosaveTimeoutMinutes * 60 * 1000);
++ }
++ }
++}
++
++bool MainWindow::hasLinkedProgramFiles(const QString & filename, QStringList & linkedProgramFiles)
++{
++ QFile file(filename);
++ file.open(QFile::ReadOnly);
++ QXmlStreamReader xml(&file);
++ xml.setNamespaceProcessing(false);
++
++ bool done = false;
++ while (!xml.atEnd()) {
++ switch (xml.readNext()) {
++ case QXmlStreamReader::StartElement:
++ if (xml.name().toString().compare("program") == 0) {
++ linkedProgramFiles.append(xml.readElementText());
++ break;
++ }
++ if (xml.name().toString().compare("views") == 0) {
++ done = true;
++ break;
++ }
++ if (xml.name().toString().compare("instances") == 0) {
++ done = true;
++ break;
++ }
++ default:
++ break;
++ }
++
++ if (done) break;
++ }
++
++ return linkedProgramFiles.count() > 0;
++}
++
++QString MainWindow::getExtensionString() {
++ return tr("Fritzing (*%1)").arg(fileExtension());
++}
++
++QStringList MainWindow::getExtensions() {
++ QStringList extensions;
++ extensions.append(fileExtension());
++ return extensions;
++}
++
++void MainWindow::firstTimeHelpHidden() {
++ m_showInViewHelpAct->setChecked(false);
++}
++
++void MainWindow::routingStatusLabelMousePress(QMouseEvent* event) {
++ routingStatusLabelMouse(event, true);
++}
++
++void MainWindow::routingStatusLabelMouseRelease(QMouseEvent* event) {
++ routingStatusLabelMouse(event, false);
++}
++
++void MainWindow::routingStatusLabelMouse(QMouseEvent*, bool show) {
++ if (show) DebugDialog::debug("-------");
++
++ QSet<ConnectorItem *> toShow;
++ foreach (QGraphicsItem * item, m_currentGraphicsView->scene()->items()) {
++ VirtualWire * vw = dynamic_cast<VirtualWire *>(item);
++ if (vw == NULL) continue;
++
++ foreach (ConnectorItem * connectorItem, vw->connector0()->connectedToItems()) {
++ toShow.insert(connectorItem);
++ }
++ foreach (ConnectorItem * connectorItem, vw->connector1()->connectedToItems()) {
++ toShow.insert(connectorItem);
++ }
++ }
++ QList<ConnectorItem *> visited;
++ foreach (ConnectorItem * connectorItem, toShow) {
++ if (show) {
++ DebugDialog::debug(QString("unrouted %1 %2 %3 %4")
++ .arg(connectorItem->attachedToInstanceTitle())
++ .arg(connectorItem->attachedToID())
++ .arg(connectorItem->attachedTo()->title())
++ .arg(connectorItem->connectorSharedName()));
++ }
++
++ if (connectorItem->isActive() && connectorItem->isVisible() && !connectorItem->hidden() && !connectorItem->layerHidden()) {
++ connectorItem->showEqualPotential(show, visited);
++ }
++ else {
++ connectorItem = connectorItem->getCrossLayerConnectorItem();
++ if (connectorItem) connectorItem->showEqualPotential(show, visited);
++ }
++ }
++
++ if (!show && toShow.count() == 0) {
++ QMessageBox::information(this, tr("Unrouted connections"),
++ tr("There are no unrouted connections in this view."));
++ }
++}
++
++void MainWindow::setReportMissingModules(bool b) {
++ if (m_sketchModel) {
++ m_sketchModel->setReportMissingModules(b);
++ }
++}
++
++void MainWindow::boardDeletedSlot()
++{
++ activeLayerBottom();
++}
++
++void MainWindow::cursorLocationSlot(double xinches, double yinches)
++{
++ if (m_locationLabel) {
++ QString units;
++ double x, y;
++
++ m_locationLabel->setProperty("location", QSizeF(xinches, xinches));
++
++ if (m_locationLabelUnits.compare("mm") == 0) {
++ units = "mm";
++ x = xinches * 25.4;
++ y = yinches * 25.4;
++ }
++ else if (m_locationLabelUnits.compare("px") == 0) {
++ units = "px";
++ x = xinches * GraphicsUtils::SVGDPI;
++ y = yinches * GraphicsUtils::SVGDPI;
++ }
++ else {
++ units = "in";
++ x = xinches;
++ y = yinches;
++ }
++
++ m_locationLabel->setText(tr("%1 %2 %3")
++ .arg(x, 0, 'f', 3)
++ .arg(y, 0, 'f', 3)
++ .arg(units) );
++ }
++}
++
++void MainWindow::locationLabelClicked()
++{
++ if (m_locationLabelUnits.compare("mm") == 0) {
++ m_locationLabelUnits = "px";
++ }
++ else if (m_locationLabelUnits.compare("px") == 0) {
++ m_locationLabelUnits = "in";
++ }
++ else if (m_locationLabelUnits.compare("in") == 0) {
++ m_locationLabelUnits = "mm";
++ }
++ else {
++ m_locationLabelUnits = "in";
++ }
++
++ if (m_locationLabel) {
++ QVariant variant = m_locationLabel->property("location");
++ if (variant.isValid()) {
++ QSizeF size = variant.toSizeF();
++ cursorLocationSlot(size.width(), size.height());
++ }
++ else {
++ cursorLocationSlot(0, 0);
++ }
++ }
++
++ QSettings settings;
++ settings.setValue("LocationInches", QVariant(m_locationLabelUnits));
++}
++
++void MainWindow::filenameIfSlot(QString & filename)
++{
++ filename = QFileInfo(fileName()).fileName();
++}
++
++QList<SketchWidget *> MainWindow::sketchWidgets()
++{
++ QList<SketchWidget *> list;
++ list << m_breadboardGraphicsView << m_schematicGraphicsView << m_pcbGraphicsView;
++ return list;
++}
++
++void MainWindow::setCloseSilently(bool cs)
++{
++ m_closeSilently = cs;
++}
++
++PCBSketchWidget * MainWindow::pcbView() {
++ return m_pcbGraphicsView;
++}
++
++void MainWindow::noBackup()
++{
++ m_autosaveTimer.stop();
++}
++
++void MainWindow::hideTempPartsBin() {
++ if (m_binManager) m_binManager->hideTempPartsBin();
++}
++
++void MainWindow::setActiveWire(Wire * wire) {
++ m_activeWire = wire;
++}
++
++void MainWindow::setActiveConnectorItem(ConnectorItem * connectorItem) {
++ m_activeConnectorItem = connectorItem;
++}
++
++const QString & MainWindow::fritzingVersion() {
++ if (m_sketchModel) return m_sketchModel->fritzingVersion();
++
++ return ___emptyString___;
++}
++
++
++void MainWindow::dragEnterEvent(QDragEnterEvent *event)
++{
++ const QMimeData* mimeData = event->mimeData();
++
++ if (mimeData->hasUrls()) {
++ QStringList pathList;
++ QList<QUrl> urlList = mimeData->urls();
++
++ // extract the local paths of the files
++ for (int i = 0; i < urlList.size() && i < 32; ++i) {
++ QString fn = urlList.at(i).toLocalFile();
++ foreach (QString ext, fritzingExtensions()) {
++ if (fn.endsWith(ext)) {
++ event->acceptProposedAction();
++ return;
++ }
++ }
++ }
++ }
++}
++
++void MainWindow::dropEvent(QDropEvent *event)
++{
++ const QMimeData* mimeData = event->mimeData();
++
++ if (mimeData->hasUrls()) {
++ QStringList pathList;
++ QList<QUrl> urlList = mimeData->urls();
++
++ // extract the local paths of the files
++ for (int i = 0; i < urlList.size() && i < 32; ++i) {
++ mainLoadAux(urlList.at(i).toLocalFile());
++ }
++ }
++}
++
++bool MainWindow::hasAnyAlien() {
++ return m_addedToTemp;
++}
++
++void MainWindow::initStyleSheet()
++{
++ QString suffix = getStyleSheetSuffix();
++ QFile styleSheet(QString(":/resources/styles/%1.qss").arg(suffix));
++ if (!styleSheet.open(QIODevice::ReadOnly)) {
++ DebugDialog::debug(QString("Unable to open :/resources/styles/%1.qss").arg(suffix));
++ } else {
++ QString platformDependantStyle = "";
++ QString platformDependantStylePath;
++#ifdef Q_WS_X11
++ if(style()->metaObject()->className()==QString("OxygenStyle")) {
++ QFile oxygenStyleSheet(QString(":/resources/styles/linux-kde-oxygen-%1.qss").arg(suffix));
++ if(oxygenStyleSheet.open(QIODevice::ReadOnly)) {
++ platformDependantStyle += oxygenStyleSheet.readAll();
++ }
++ }
++ platformDependantStylePath = QString(":/resources/styles/linux-%1.qss").arg(suffix);
++#endif
++
++#ifdef Q_WS_MAC
++ platformDependantStylePath = QString(":/resources/styles/mac-%1.qss").arg(suffix);
++#endif
++
++#ifdef Q_WS_WIN
++ platformDependantStylePath = QString(":/resources/styles/win-%1.qss").arg(suffix);
++#endif
++
++ QFile platformDependantStyleSheet(platformDependantStylePath);
++ if(platformDependantStyleSheet.open(QIODevice::ReadOnly)) {
++ platformDependantStyle += platformDependantStyleSheet.readAll();
++ }
++ setStyleSheet(styleSheet.readAll()+platformDependantStyle);
++ }
++}
++
++QString MainWindow::getStyleSheetSuffix() {
++ return "fritzing";
++}
++
++void MainWindow::addToMyParts(ModelPart * modelPart)
++{
++ if (modelPart != NULL) m_binManager->addToMyParts(modelPart);
++}
++
++bool MainWindow::anyUsePart(const QString & moduleID) {
++ foreach (QWidget *widget, QApplication::topLevelWidgets()) {
++ MainWindow *mainWindow = qobject_cast<MainWindow *>(widget);
++ if (mainWindow == NULL) continue;
++
++ if (mainWindow->usesPart(moduleID)) {
++ return true;
++ }
++ }
++
++ return false;
++}
++
++bool MainWindow::usesPart(const QString & moduleID) {
++ if (m_currentGraphicsView == NULL) return false;
++
++ foreach (QGraphicsItem * item, m_currentGraphicsView->scene()->items()) {
++ ItemBase * itemBase = dynamic_cast<ItemBase *>(item);
++ if (itemBase != NULL && itemBase->moduleID().compare(moduleID) == 0) {
++ return true;
++ }
++ }
++
++ return false;
++}
++
++bool MainWindow::updateParts(const QString & moduleID, QUndoCommand * parentCommand) {
++ if (m_currentGraphicsView == NULL) return false;
++
++ QSet<ItemBase *> itemBases;
++ foreach (QGraphicsItem * item, m_currentGraphicsView->scene()->items()) {
++ ItemBase * itemBase = dynamic_cast<ItemBase *>(item);
++ if (itemBase == NULL) continue;
++ if (itemBase->moduleID().compare(moduleID) != 0) continue;
++
++ itemBases.insert(itemBase->layerKinChief());
++ }
++
++ QMap<QString, QString> propsMap;
++ foreach (ItemBase * itemBase, itemBases) {
++ swapSelectedAuxAux(itemBase, moduleID, itemBase->viewLayerPlacement(), propsMap, parentCommand);
++ }
++
++ return true;
++}
++
++void MainWindow::showStatusMessage(const QString & message)
++{
++ if (sender() == m_statusBar) {
++ return;
++ }
++
++ if (message == m_statusBar->currentMessage()) {
++ return;
++ }
++
++ //DebugDialog::debug("show message " + message);
++ m_statusBar->blockSignals(true);
++ m_statusBar->showMessage(message);
++ m_statusBar->blockSignals(false);
++}
++
++void MainWindow::updatePartsBin(const QString & moduleID) {
++ m_binManager->reloadPart(moduleID);
++}
++
++bool MainWindow::hasCustomBoardShape() {
++ if (m_pcbGraphicsView == NULL) return false;
++
++ return m_pcbGraphicsView->hasCustomBoardShape();
++}
++
++void MainWindow::selectPartsWithModuleID(ModelPart * modelPart) {
++ if (m_currentGraphicsView == NULL) return;
++
++ m_currentGraphicsView->selectItemsWithModuleID(modelPart);
++}
++
++void MainWindow::addToSketch(QList<ModelPart *> & modelParts) {
++ if (m_currentGraphicsView == NULL) return;
++
++ m_currentGraphicsView->addToSketch(modelParts);
++}
++
++void MainWindow::initProgrammingWidget() {
++ return; // not yet implemented
++
++ m_programView = new ProgramWindow(this);
++
++ connect(m_programView, SIGNAL(linkToProgramFile(const QString &, const QString &, const QString &, bool, bool)),
++ this, SLOT(linkToProgramFile(const QString &, const QString &, const QString &, bool, bool)));
++
++ m_programView->setup();
++
++ SketchAreaWidget * sketchAreaWidget = new SketchAreaWidget(m_programView, this);
++ addTab(sketchAreaWidget, tr("Code"));
++}
++
++void MainWindow::orderFabHoverEnter() {
++ if (!QuoteDialog::quoteSucceeded()) return;
++ if (m_rolloverQuoteDialog && m_rolloverQuoteDialog->isVisible()) return;
++
++ QTimer::singleShot(1, this, SLOT(fireQuote()));
++}
++
++void MainWindow::fireQuote() {
++ if (!QuoteDialog::quoteSucceeded()) return;
++
++ m_rolloverQuoteDialog = m_pcbGraphicsView->quoteDialog(m_pcbWidget);
++ if (m_rolloverQuoteDialog == NULL) return;
++
++ //DebugDialog::debug("enter fab button");
++ //QWidget * toolbar = m_pcbWidget->toolbar();
++ //QRect r = toolbar->geometry();
++ //QPointF p = toolbar->parentWidget()->mapToGlobal(r.topLeft());
++
++ Qt::WindowFlags flags = m_rolloverQuoteDialog->windowFlags();
++ flags = Qt::Window | Qt::Dialog | Qt::FramelessWindowHint;
++ m_rolloverQuoteDialog->setWindowFlags(flags);
++ m_rolloverQuoteDialog->show();
++
++ // seems to require setting position after show()
++
++ QRect t = m_pcbWidget->toolbar()->geometry();
++ QPoint gt = m_pcbWidget->toolbar()->parentWidget()->mapToGlobal(t.topLeft());
++ QRect q = m_rolloverQuoteDialog->geometry();
++
++ // I don't understand why--perhaps due to the windowFlags--but q is already in global coordinates
++ q.moveBottom(gt.y() - 20);
++ m_rolloverQuoteDialog->setGeometry(q);
++}
++
++void MainWindow::orderFabHoverLeave() {
++ //DebugDialog::debug("leave fab button");
++ if (m_rolloverQuoteDialog) {
++ m_rolloverQuoteDialog->hide();
++ }
++}
++
+diff -urN fritzing-0.8.3b.source.orig/src/mainwindow/mainwindow.h fritzing-0.8.3b.source/src/mainwindow/mainwindow.h
+--- fritzing-0.8.3b.source.orig/src/mainwindow/mainwindow.h 2013-07-27 14:03:38.000000000 -0700
++++ fritzing-0.8.3b.source/src/mainwindow/mainwindow.h 2013-08-10 22:49:23.904174341 -0700
+@@ -146,7 +146,6 @@
QSizeGrip *sizeGrip();
QStatusBar *realStatusBar();
void showAllFirstTimeHelp(bool show);
@@ -156,7 +3051,7 @@ diff -urN fritzing-0.7.12b.source.orig/src/mainwindow/mainwindow.h fritzing-0.7.
void getPartsEditorNewAnd(ItemBase * fromItem);
void addDefaultParts();
-@@ -776,7 +775,6 @@
+@@ -829,7 +828,6 @@
QAction *m_partsRefAct;
QAction *m_showInViewHelpAct;;
QAction *m_visitFritzingDotOrgAct;
@@ -164,10 +3059,940 @@ diff -urN fritzing-0.7.12b.source.orig/src/mainwindow/mainwindow.h fritzing-0.7.
QAction *m_aboutQtAct;
QAction *m_reportBugAct;
QAction *m_enableDebugAct;
-diff -urN fritzing-0.7.12b.source.orig/src/mainwindow/mainwindow_menu.cpp fritzing-0.7.12b.source/src/mainwindow/mainwindow_menu.cpp
---- fritzing-0.7.12b.source.orig/src/mainwindow/mainwindow_menu.cpp 2013-02-25 05:02:59.000000000 -0800
-+++ fritzing-0.7.12b.source/src/mainwindow/mainwindow_menu.cpp 2013-02-25 18:29:22.843459092 -0800
-@@ -1098,10 +1098,6 @@
+diff -urN fritzing-0.8.3b.source.orig/src/mainwindow/mainwindow.h.orig fritzing-0.8.3b.source/src/mainwindow/mainwindow.h.orig
+--- fritzing-0.8.3b.source.orig/src/mainwindow/mainwindow.h.orig 1969-12-31 16:00:00.000000000 -0800
++++ fritzing-0.8.3b.source/src/mainwindow/mainwindow.h.orig 2013-07-27 14:03:38.000000000 -0700
+@@ -0,0 +1,926 @@
++/*******************************************************************
++
++Part of the Fritzing project - http://fritzing.org
++Copyright (c) 2007-2013 Fachhochschule Potsdam - http://fh-potsdam.de
++
++Fritzing is free software: you can redistribute it and/or modify
++it under the terms of the GNU General Public License as published by
++the Free Software Foundation, either version 3 of the License, or
++(at your option) any later version.
++
++Fritzing is distributed in the hope that it will be useful,
++but WITHOUT ANY WARRANTY; without even the implied warranty of
++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++GNU General Public License for more details.
++
++You should have received a copy of the GNU General Public License
++along with Fritzing. If not, see <http://www.gnu.org/licenses/>.
++
++********************************************************************
++
++$Revision: 6999 $:
++$Author: irascibl at gmail.com $:
++$Date: 2013-04-28 14:14:07 +0200 (So, 28. Apr 2013) $
++
++********************************************************************/
++
++#ifndef MAINWINDOW_H
++#define MAINWINDOW_H
++
++#include <QUndoView>
++#include <QUndoGroup>
++#include <QRadioButton>
++#include <QLineEdit>
++#include <QToolButton>
++#include <QPushButton>
++#include <QStackedWidget>
++#include <QSizeGrip>
++#include <QProcess>
++#include <QDockWidget>
++#include <QXmlStreamWriter>
++#include <QRegExp>
++
++#include "fritzingwindow.h"
++#include "sketchareawidget.h"
++#include "../viewlayer.h"
++#include "../program/programwindow.h"
++#include "../svg/svg2gerber.h"
++#include "../dock/viewswitcher.h"
++#include "../routingstatus.h"
++
++QT_BEGIN_NAMESPACE
++class QAction;
++class QListWidget;
++class QMenu;
++QT_END_NAMESPACE
++
++class Helper;
++class FSizeGrip;
++
++typedef class FDockWidget * (*DockFactory)(const QString & title, QWidget * parent);
++
++bool sortPartList(class ItemBase * b1, class ItemBase * b2);
++
++static const QString ORDERFABENABLED = "OrderFabEnabled";
++
++class SwapTimer : public QTimer
++{
++Q_OBJECT
++
++public:
++ SwapTimer();
++
++ void setAll(const QString & family, const QString & prop, QMap<QString, QString> & propsMap, ItemBase *);
++ const QString & family();
++ const QString & prop();
++ QMap<QString, QString> propsMap();
++ ItemBase * itemBase();
++
++protected:
++ QString m_family;
++ QString m_prop;
++ QMap<QString, QString> m_propsMap;
++ QPointer <ItemBase> m_itemBase;
++};
++
++struct GridSizeThing
++{
++ QLineEdit * lineEdit;
++ QDoubleValidator * validator;
++ QRadioButton * mmButton;
++ QRadioButton * inButton;
++ double defaultGridSize;
++ QString gridSizeText;
++ QString viewName;
++ QString shortName;
++
++ GridSizeThing(const QString & viewName, const QString & shortName, double defaultSize, const QString & gridSizeText);
++};
++
++class GridSizeDialog : public QDialog {
++ Q_OBJECT
++
++public:
++ GridSizeDialog(GridSizeThing *);
++ GridSizeThing * gridSizeThing();
++
++protected:
++ GridSizeThing * m_gridSizeThing;
++};
++
++
++struct TraceMenuThing {
++ int boardCount;
++ int boardSelectedCount;
++ bool jiEnabled;
++ bool exEnabled;
++ bool viaEnabled;
++ bool exChecked;
++ bool gfrEnabled;
++ bool gfsEnabled;
++
++ TraceMenuThing() {
++ boardCount = 0;
++ boardSelectedCount = 0;
++ gfsEnabled = false;
++ jiEnabled = false;
++ exEnabled = false;
++ exChecked = true;
++ viaEnabled = false;
++ gfrEnabled = false;
++ }
++};
++
++class MainWindow : public FritzingWindow
++{
++ Q_OBJECT
++public:
++ MainWindow(class ReferenceModel *referenceModel, QWidget * parent);
++ MainWindow(QFile & fileToLoad);
++ ~MainWindow();
++
++ void mainLoad(const QString & fileName, const QString & displayName);
++ bool loadWhich(const QString & fileName, bool setAsLastOpened, bool addToRecent, const QString & displayName);
++ void notClosableForAWhile();
++ QAction *raiseWindowAction();
++ QSizeGrip *sizeGrip();
++ QStatusBar *realStatusBar();
++ void showAllFirstTimeHelp(bool show);
++ void enableCheckUpdates(bool enabled);
++
++ void getPartsEditorNewAnd(ItemBase * fromItem);
++ void addDefaultParts();
++ void init(ReferenceModel *referenceModel, bool lockFiles);
++ void showFileProgressDialog(const QString & path);
++ void setFileProgressPath(const QString & path);
++ void clearFileProgressDialog();
++ class FileProgressDialog * fileProgressDialog();
++
++ const QString &selectedModuleID();
++
++ void saveDocks();
++ void restoreDocks();
++
++ void redrawSketch();
++
++ // if we consider a part as the smallest ("atomic") entity inside
++ // fritzing, then this functions may help with the bundle tasks
++ // on the complex entities: sketches, bins, modules (?)
++ void saveBundledNonAtomicEntity(QString &filename, const QString &extension, Bundler *bundler, const QList<ModelPart*> &partsToSave, bool askForFilename, const QString & destFolderPath, bool saveModel, bool deleteLeftovers);
++ bool loadBundledNonAtomicEntity(const QString &filename, Bundler *bundler, bool addToBin, bool dontAsk);
++ void saveAsShareable(const QString & path, bool saveModel);
++
++
++ void setCurrentFile(const QString &fileName, bool addToRecent, bool setAsLastOpened);
++ void setReportMissingModules(bool);
++ QList<class SketchWidget *> sketchWidgets();
++ void setCloseSilently(bool);
++ class PCBSketchWidget * pcbView();
++ void noBackup();
++ void swapSelectedAux(ItemBase * itemBase, const QString & moduleID, bool useViewLayerPlacement, ViewLayer::ViewLayerPlacement, QMap<QString, QString> & propsMap);
++ void swapLayers(ItemBase * itemBase, int layers, const QString & msg, int delay);
++ bool saveAsAux(const QString & fileName);
++ void swapObsolete(bool displayFeedback);
++ void selectAllObsolete(bool displayFeedback);
++ void hideTempPartsBin();
++ const QString & fritzingVersion();
++ void removeGroundFill(ViewLayer::ViewLayerID, QUndoCommand * parentCommand);
++ void groundFill(ViewLayer::ViewLayerID);
++ void copperFill(ViewLayer::ViewLayerID);
++ bool hasAnyAlien();
++ void exportSvg(double res, bool selectedItems, bool flatten, const QString & filename);
++ void setCurrentView(ViewLayer::ViewID);
++ bool usesPart(const QString & moduleID);
++ bool anyUsePart(const QString & moduleID);
++ bool updateParts(const QString & moduleID, QUndoCommand * parentCommand);
++ void updatePartsBin(const QString & moduleID);
++ bool hasCustomBoardShape();
++ void selectPartsWithModuleID(ModelPart *);
++ void addToSketch(QList<ModelPart *> &);
++ QStringList newDesignRulesCheck(bool showOkMessage);
++
++public:
++ static void initNames();
++ static MainWindow * newMainWindow(ReferenceModel *referenceModel, const QString & displayPath, bool showProgress, bool lockFiles);
++ static void setAutosavePeriod(int);
++ static void setAutosaveEnabled(bool);
++
++signals:
++ void alienPartsDismissed();
++ void viewSwitched(int);
++ void mainWindowMoved(QWidget *);
++ void changeActivationSignal(bool activate, QWidget * originator);
++ void externalProcessSignal(QString & name, QString & path, QStringList & args);
++
++public slots:
++ void ensureClosable();
++ ModelPart* loadBundledPart(const QString &fileName, bool addToBin);
++ void importFilesFromPrevInstall();
++ void acceptAlienFiles();
++ void statusMessage(QString message, int timeout);
++ void showPCBView();
++ void groundFill();
++ void removeGroundFill();
++ void copperFill();
++ void setOneGroundFillSeed();
++ void setGroundFillSeeds();
++ void clearGroundFillSeeds();
++ void changeBoardLayers(int layers, bool doEmit);
++ void selectAllObsolete();
++ void swapObsolete();
++ void swapBoardImageSlot(SketchWidget * sketchWidget, ItemBase * itemBase, const QString & filename, const QString & moduleID, bool addName);
++ void updateTraceMenu();
++ virtual void updateFileMenu();
++ void showStatusMessage(const QString &);
++ void orderFabHoverEnter();
++ void orderFabHoverLeave();
++ void setGroundFillKeepout();
++
++protected slots:
++ void mainLoad();
++ void revert();
++ void openRecentOrExampleFile();
++ void print();
++ void doExport();
++ void exportEtchable();
++ void about();
++ void tipsAndTricks();
++ void copy();
++ void cut();
++ void paste();
++ void pasteInPlace();
++ void duplicate();
++ void doDelete();
++ void doDeleteMinus();
++ void selectAll();
++ void deselect();
++ void zoomIn();
++ void zoomOut();
++ void fitInWindow();
++ void actualSize();
++ void hundredPercentSize();
++ void alignToGrid();
++ void showGrid();
++ void setGridSize();
++ void setBackgroundColor();
++ void showBreadboardView();
++ void showSchematicView();
++ void showProgramView();
++ void showPartsBinIconView();
++ void showPartsBinListView();
++ void updateEditMenu();
++ virtual void updateLayerMenu(bool resetLayout = false);
++ void updatePartMenu();
++ virtual void updateWireMenu();
++ void updateTransformationActions();
++ void updateRecentFileActions();
++ virtual void tabWidget_currentChanged(int index);
++ void createNewSketch();
++ void minimize();
++ void toggleToolbar(bool toggle);
++ void togglePartLibrary(bool toggle);
++ void toggleInfo(bool toggle);
++ void toggleNavigator(bool toggle);
++ void toggleUndoHistory(bool toggle);
++ void toggleDebuggerOutput(bool toggle);
++ void openHelp();
++ void openDonate();
++ void openExamples();
++ void openPartsReference();
++ void visitFritzingDotOrg();
++ void partsEditorHelp();
++ virtual void updateWindowMenu();
++ void pageSetup();
++ void sendToBack();
++ void sendBackward();
++ void bringForward();
++ void bringToFront();
++ void alignLeft();
++ void alignRight();
++ void alignVerticalCenter();
++ void alignTop();
++ void alignHorizontalCenter();
++ void alignBottom();
++ void rotate90cw();
++ void rotate90ccw();
++ void rotate180();
++ void rotate45ccw();
++ void rotate45cw();
++ void rotateIncCCW();
++ void rotateIncCW();
++ void rotateIncCCWRubberBand();
++ void rotateIncCWRubberBand();
++ void flipHorizontal();
++ void flipVertical();
++ void showAllLayers();
++ void hideAllLayers();
++ void showInViewHelp();
++ void addBendpoint();
++ void convertToVia();
++ void convertToBendpoint();
++ void flattenCurve();
++ void disconnectAll();
++
++ void openInPartsEditorNew();
++ void openNewPartsEditor(class PaletteItem *);
++
++ void updateZoomSlider(double zoom);
++ void updateZoomOptionsNoMatterWhat(double zoom);
++ void updateViewZoom(double newZoom);
++
++ void setInfoViewOnHover(bool infoViewOnHover);
++ void updateItemMenu();
++
++ void newAutoroute();
++ void orderFab();
++ void activeLayerTop();
++ void activeLayerBottom();
++ void activeLayerBoth();
++ void toggleActiveLayer();
++ void createTrace();
++ void excludeFromAutoroute();
++ void selectAllTraces();
++ void showUnrouted();
++ void selectAllCopperFill();
++ void updateRoutingStatus();
++ void selectAllExcludedTraces();
++ void selectAllIncludedTraces();
++ void selectAllJumperItems();
++ void selectAllVias();
++
++ void shareOnline();
++ void saveBundledPart(const QString &moduleId=___emptyString___);
++ QStringList saveBundledAux(ModelPart *mp, const QDir &destFolder);
++
++ void binSaved(bool hasAlienParts);
++ void routingStatusSlot(class SketchWidget *, const RoutingStatus &);
++
++ void applyReadOnlyChange(bool isReadOnly);
++ void currentNavigatorChanged(class MiniViewContainer *);
++ void viewSwitchedTo(int viewIndex);
++
++ void raiseAndActivate();
++ void activateWindowAux();
++ void showPartLabels();
++ void addNote();
++ void reportBug();
++ void enableDebug();
++ void tidyWires();
++ void changeWireColor(bool checked);
++
++ void startSaveInstancesSlot(const QString & fileName, ModelPart *, QXmlStreamWriter &);
++ void loadedViewsSlot(class ModelBase *, QDomElement & views);
++ void loadedRootSlot(const QString & filename, ModelBase *, QDomElement & views);
++ void obsoleteSMDOrientationSlot();
++ void exportNormalizedSVG();
++ void exportNormalizedFlattenedSVG();
++
++ void launchExternalProcess();
++ bool externalProcess(QString & name, QString & path, QStringList & args);
++ void processError(QProcess::ProcessError processError);
++ void processFinished(int exitCode, QProcess::ExitStatus exitStatus);
++ void processReadyRead();
++ void processStateChanged(QProcess::ProcessState newState);
++ void throwFakeException();
++
++ void dropPaste(SketchWidget *);
++
++ void openProgramWindow();
++ void linkToProgramFile(const QString & filename, const QString & language, const QString & programmer, bool addLink, bool strong);
++ QStringList newDesignRulesCheck();
++ void subSwapSlot(SketchWidget *, ItemBase *, const QString & newModuleID, ViewLayer::ViewLayerPlacement, long & newID, QUndoCommand * parentCommand);
++ void updateLayerMenuSlot();
++ bool save();
++ bool saveAs();
++ virtual void backupSketch();
++ void undoStackCleanChanged(bool isClean);
++ void autosaveNeeded(int index = 0);
++ void firstTimeHelpHidden();
++ void changeTraceLayer();
++ void routingStatusLabelMousePress(QMouseEvent*);
++ void routingStatusLabelMouseRelease(QMouseEvent*);
++ void selectMoveLock();
++ void moveLock();
++ void setSticky();
++ void showNavigator();
++ void autorouterSettings();
++ void boardDeletedSlot();
++ void cursorLocationSlot(double, double);
++ void locationLabelClicked();
++ void swapSelectedMap(const QString & family, const QString & prop, QMap<QString, QString> & currPropsMap, ItemBase *);
++ void swapSelectedDelay(const QString & family, const QString & prop, QMap<QString, QString> & currPropsMap, ItemBase *);
++ void swapSelectedTimeout();
++ void filenameIfSlot(QString & filename);
++ void openURL();
++ void setActiveWire(class Wire *);
++ void setActiveConnectorItem(class ConnectorItem *);
++ void gridUnits(bool);
++ void restoreDefaultGrid();
++ void checkLoadedTraces();
++
++ void keepMargins();
++ void dockChangeActivation(bool activate, QWidget * originator);
++ void addToMyParts(ModelPart *);
++ void hidePartSilkscreen();
++ void fabQuote();
++ void findPartInSketch();
++ void fireQuote();
++ void setViewFromBelowToggle();
++ void setViewFromBelow();
++ void setViewFromAbove();
++
++protected:
++ void initSketchWidget(SketchWidget *);
++ virtual void initProgrammingWidget();
++
++ virtual void createActions();
++ virtual void createFileMenuActions();
++ void createExportActions();
++ void createRaiseWindowActions();
++ void createOrderFabAct();
++ void createOpenExampleMenu();
++ void createActiveLayerActions();
++ void populateMenuFromXMLFile(QMenu *parentMenu, QStringList &actionsTracker, const QString &folderPath, const QString &indexFileName);
++ QHash<QString, struct SketchDescriptor *> indexAvailableElements(QDomElement &domElem, const QString &srcPrefix, QStringList & actionsTracker);
++ void populateMenuWithIndex(const QHash<QString, struct SketchDescriptor *> &, QMenu * parentMenu, QDomElement &domElem);
++ void populateMenuFromFolderContent(QMenu *parentMenu, const QString &path);
++ void createOpenRecentMenu();
++ void createEditMenuActions();
++ void createPartMenuActions();
++ virtual void createViewMenuActions();
++ void createWindowMenuActions();
++ void createHelpMenuActions();
++ virtual void createMenus();
++ void createStatusBar();
++ virtual void connectPairs();
++ void connectPair(SketchWidget * signaller, SketchWidget * slotter);
++ void closeEvent(QCloseEvent * event);
++ void saveAsAuxAux(const QString & fileName);
++ void printAux(QPrinter &printer, bool removeBackground, bool paginate);
++ void exportAux(QString fileName, QImage::Format format, int quality, bool removeBackground);
++ void notYetImplemented(QString action);
++ bool eventFilter(QObject *obj, QEvent *event);
++ void setActionsIcons(int index, QList<QAction *> &);
++ void exportToEagle();
++ void exportToGerber();
++ void exportBOM();
++ void exportNetlist();
++ void exportSpiceNetlist();
++ void exportSvg(double res, bool selectedItems, bool flatten);
++ void exportSvgWatermark(QString & svg, double res);
++ void exportEtchable(bool wantPDF, bool wantSVG);
++
++ virtual QList<QWidget*> getButtonsForView(ViewLayer::ViewID viewId);
++ const QString untitledFileName();
++ int &untitledFileCount();
++ const QString fileExtension();
++ QString getExtensionString();
++ QStringList getExtensions();
++ const QString defaultSaveFolder();
++ bool undoStackIsEmpty();
++
++ void createTraceMenuActions();
++ void hideShowTraceMenu();
++ void hideShowProgramMenu();
++ void updatePCBTraceMenu(QGraphicsItem *, TraceMenuThing &);
++
++ QList<ModelPart*> moveToPartsFolder(QDir &unzipDir, MainWindow* mw, bool addToBin, bool addToAlien, const QString & prefixFolder, const QString &destFolder, bool importingSinglePart);
++ QString copyToSvgFolder(const QFileInfo& file, bool addToAlien, const QString & prefixFolder, const QString &destFolder);
++ ModelPart* copyToPartsFolder(const QFileInfo& file, bool addToAlien, const QString & prefixFolder, const QString &destFolder);
++
++ void closeIfEmptySketch(MainWindow* mw);
++ bool whatToDoWithAlienFiles();
++ void backupExistingFileIfExists(const QString &destFilePath);
++ void recoverBackupedFiles();
++ void resetTempFolder();
++
++ virtual QMenu *breadboardItemMenu();
++ virtual QMenu *schematicItemMenu();
++ virtual QMenu *pcbItemMenu();
++ virtual QMenu *pcbWireMenu();
++ virtual QMenu *schematicWireMenu();
++ virtual QMenu *breadboardWireMenu();
++
++ QMenu *viewItemMenuAux(QMenu* menu);
++
++ void createZoomOptions(SketchAreaWidget* parent);
++ class SketchToolButton *createRotateButton(SketchAreaWidget *parent);
++ SketchToolButton *createShareButton(SketchAreaWidget *parent);
++ SketchToolButton *createFlipButton(SketchAreaWidget *parent);
++ SketchToolButton *createAutorouteButton(SketchAreaWidget *parent);
++ SketchToolButton *createOrderFabButton(SketchAreaWidget *parent);
++ QWidget *createActiveLayerButton(SketchAreaWidget *parent);
++ QWidget *createViewFromButton(SketchAreaWidget *parent);
++ class ExpandingLabel * createRoutingStatusLabel(SketchAreaWidget *);
++ SketchToolButton *createExportEtchableButton(SketchAreaWidget *parent);
++ SketchToolButton *createNoteButton(SketchAreaWidget *parent);
++ QWidget *createToolbarSpacer(SketchAreaWidget *parent);
++ SketchAreaWidget *currentSketchArea();
++ const QString fritzingTitle();
++
++ virtual void updateRaiseWindowAction();
++
++ void moveEvent(QMoveEvent * event);
++ bool event(QEvent *);
++ void resizeEvent(QResizeEvent * event);
++ QString genIcon(SketchWidget *, LayerList & partViewLayerIDs, LayerList & wireViewLayerIDs);
++
++ bool alreadyOpen(const QString & fileName);
++ void svgMissingLayer(const QString & layername, const QString & path);
++ long swapSelectedAuxAux(ItemBase * itemBase, const QString & moduleID, ViewLayer::ViewLayerPlacement viewLayerPlacement, QMap<QString, QString> & propsMap, QUndoCommand * parentCommand);
++ bool swapSpecial(const QString & prop, QMap<QString, QString> & currPropsMap);
++
++ void enableAddBendpointAct(QGraphicsItem *);
++ class FileProgressDialog * exportProgress();
++ QString constructFileName(const QString & differentiator, const QString & extension);
++ bool isGroundFill(ItemBase * itemBase);
++
++ QString getBoardSvg(ItemBase * board, int res, LayerList &);
++ QString mergeBoardSvg(QString & svg, ItemBase * board, int res, bool flip, LayerList &);
++
++ void updateActiveLayerButtons();
++ int activeLayerIndex();
++ bool hasLinkedProgramFiles(const QString & filename, QStringList & linkedProgramFiles);
++ void pasteAux(bool pasteInPlace);
++
++ void routingStatusLabelMouse(QMouseEvent*, bool show);
++ class Wire * retrieveWire();
++ class ConnectorItem * retrieveConnectorItem();
++ QString getBomProps(ItemBase *);
++ ModelPart * findReplacedby(ModelPart * originalModelPart);
++ void groundFillAux(bool fillGroundTraces, ViewLayer::ViewLayerID viewLayerID);
++ void groundFillAux2(bool fillGroundTraces);
++ void connectStartSave(bool connect);
++ void loadBundledSketch(const QString &fileName, bool addToRecent, bool setAsLastOpened);
++ void dropEvent(QDropEvent *event);
++ void dragEnterEvent(QDragEnterEvent *event);
++ void mainLoadAux(const QString & fileName);
++ QWidget * createGridSizeForm(GridSizeThing *);
++ void massageOutput(QString & svg, bool doMask, bool doSilk, bool doPaste, QString & maskTop, QString & maskBottom, const QString & fileName, ItemBase * board, int dpi, const LayerList &);
++ virtual void initLockedFiles(bool lockFiles);
++ virtual void initSketchWidgets();
++ virtual void initDock();
++ virtual void initMenus();
++ virtual void moreInitDock();
++ virtual void initHelper();
++ virtual void createFileMenu();
++ virtual void createEditMenu();
++ virtual void createPartMenu();
++ virtual void createViewMenu();
++ virtual void createWindowMenu();
++ virtual void createTraceMenus();
++ virtual void createHelpMenu();
++ virtual void populateExportMenu();
++
++ // dock management
++ void createDockWindows();
++ void dontKeepMargins();
++ class FDockWidget * makeDock(const QString & title, QWidget * widget, int dockMinHeight, int dockDefaultHeight, Qt::DockWidgetArea area = Qt::RightDockWidgetArea, DockFactory dockFactory = NULL);
++ class FDockWidget * dockIt(FDockWidget* dock, int dockMinHeight, int dockDefaultHeight, Qt::DockWidgetArea area = Qt::RightDockWidgetArea);
++ FDockWidget *newTopWidget();
++ FDockWidget *newBottomWidget();
++ void removeMargin(FDockWidget* dock);
++ void addTopMargin(FDockWidget* dock);
++ void addBottomMargin(FDockWidget* dock);
++ void dockMarginAux(FDockWidget* dock, const QString &name, const QString &style);
++ void initStyleSheet();
++ virtual QString getStyleSheetSuffix();
++ virtual QWidget * createTabWidget();
++ virtual void addTab(QWidget * widget, const QString & label);
++ virtual int currentTabIndex();
++ virtual void setCurrentTabIndex(int);
++ virtual QWidget * currentTabWidget();
++ virtual bool activeLayerWidgetAlwaysOn();
++ bool copySvg(const QString & path, QFileInfoList & svgEntryInfoList);
++
++protected:
++ static void removeActionsStartingAt(QMenu *menu, int start=0);
++ static void setAutosave(int, bool);
++
++protected:
++
++ QUndoGroup *m_undoGroup;
++ QUndoView *m_undoView;
++
++ QPointer<SketchAreaWidget> m_breadboardWidget;
++ QPointer<class BreadboardSketchWidget> m_breadboardGraphicsView;
++
++ QPointer<SketchAreaWidget> m_schematicWidget;
++ QPointer<class SchematicSketchWidget> m_schematicGraphicsView;
++
++ QPointer<SketchAreaWidget> m_pcbWidget;
++ QPointer<class PCBSketchWidget> m_pcbGraphicsView;
++
++ QPointer<class BinManager> m_binManager;
++ QPointer<class MiniViewContainer> m_miniViewContainerBreadboard;
++ QPointer<class MiniViewContainer> m_miniViewContainerSchematic;
++ QPointer<class MiniViewContainer> m_miniViewContainerPCB;
++ QList <class MiniViewContainer *> m_navigators;
++ QPointer<QWidget> m_tabWidget;
++ QPointer<ReferenceModel> m_referenceModel;
++ QPointer<class SketchModel> m_sketchModel;
++ QPointer<class HtmlInfoView> m_infoView;
++ QPointer<QToolBar> m_toolbar;
++
++ bool m_closing;
++ bool m_dontClose;
++ bool m_firstOpen;
++
++ QPointer<SketchAreaWidget> m_currentWidget;
++ QPointer<SketchWidget> m_currentGraphicsView;
++
++ //QToolBar *m_fileToolBar;
++ //QToolBar *m_editToolBar;
++
++ QAction *m_raiseWindowAct;
++
++ // Fritzing Menu
++ QMenu *m_fritzingMenu;
++ QAction *m_aboutAct;
++ QAction *m_tipsAndTricksAct;
++ QAction *m_preferencesAct;
++ QAction *m_quitAct;
++ QAction *m_exceptionAct;
++
++ // File Menu
++ enum { MaxRecentFiles = 10 };
++
++ QMenu *m_fileMenu;
++ QAction *m_newAct;
++ QAction *m_openAct;
++ QAction *m_revertAct;
++ QMenu *m_openRecentFileMenu;
++ QAction *m_openRecentFileActs[MaxRecentFiles];
++ QMenu *m_openExampleMenu;
++ QAction *m_saveAct;
++ QAction *m_saveAsAct;
++ QAction *m_pageSetupAct;
++ QAction *m_printAct;
++ QAction *m_shareOnlineAct;
++
++ QAction * m_launchExternalProcessAct;
++
++ QMenu *m_zOrderMenu;
++ QMenu *m_zOrderWireMenu;
++ QAction *m_bringToFrontAct;
++ QAction *m_bringForwardAct;
++ QAction *m_sendBackwardAct;
++ QAction *m_sendToBackAct;
++ class WireAction *m_bringToFrontWireAct;
++ class WireAction *m_bringForwardWireAct;
++ class WireAction *m_sendBackwardWireAct;
++ class WireAction *m_sendToBackWireAct;
++
++ QMenu *m_alignMenu;
++ QAction * m_alignVerticalCenterAct;
++ QAction * m_alignHorizontalCenterAct;
++ QAction * m_alignTopAct;
++ QAction * m_alignLeftAct;
++ QAction * m_alignBottomAct;
++ QAction * m_alignRightAct;
++
++ // Export Menu
++ QMenu *m_exportMenu;
++ QAction *m_exportJpgAct;
++ QAction *m_exportPsAct;
++ QAction *m_exportPngAct;
++ QAction *m_exportPdfAct;
++ QAction *m_exportEagleAct;
++ QAction *m_exportGerberAct;
++ QAction *m_exportEtchablePdfAct;
++ QAction *m_exportEtchableSvgAct;
++ QAction *m_exportBomAct;
++ QAction *m_exportNetlistAct;
++ QAction *m_exportSpiceNetlistAct;
++ QAction *m_exportSvgAct;
++
++ // Edit Menu
++ QMenu *m_editMenu;
++ QAction *m_undoAct;
++ QAction *m_redoAct;
++ QAction *m_cutAct;
++ QAction *m_copyAct;
++ QAction *m_pasteAct;
++ QAction *m_pasteInPlaceAct;
++ QAction *m_duplicateAct;
++ QAction *m_deleteAct;
++ QAction *m_deleteMinusAct;
++ class WireAction *m_deleteWireAct;
++ class WireAction *m_deleteWireMinusAct;
++ QAction *m_selectAllAct;
++ QAction *m_deselectAct;
++ QAction *m_addNoteAct;
++
++ // Part Menu
++ QMenu *m_partMenu;
++ QAction *m_infoViewOnHoverAction;
++ QAction *m_exportNormalizedSvgAction;
++ QAction *m_exportNormalizedFlattenedSvgAction;
++ QAction *m_openInPartsEditorNewAct;
++ QMenu *m_addToBinMenu;
++
++
++ QMenu *m_rotateMenu;
++ QAction *m_rotate90cwAct;
++ QAction *m_rotate180Act;
++ QAction *m_rotate90ccwAct;
++ QAction *m_rotate45ccwAct;
++ QAction *m_rotate45cwAct;
++
++ QAction *m_moveLockAct;
++ QAction *m_stickyAct;
++ QAction *m_selectMoveLockAct;
++ QAction *m_flipHorizontalAct;
++ QAction *m_flipVerticalAct;
++ QAction *m_showPartLabelAct;
++ QAction *m_saveBundledPart;
++ QAction *m_disconnectAllAct;
++ QAction *m_selectAllObsoleteAct;
++ QAction *m_swapObsoleteAct;
++ QAction *m_findPartInSketchAct;
++ QAction * m_openProgramWindowAct;
++
++ QAction *m_addBendpointAct;
++ QAction *m_convertToViaAct;
++ QAction *m_convertToBendpointAct;
++ QAction * m_convertToBendpointSeparator;
++ QAction *m_flattenCurveAct;
++ QAction *m_showAllLayersAct;
++ QAction *m_hideAllLayersAct;
++
++ QAction *m_hidePartSilkscreenAct;
++
++ // View Menu
++ QMenu *m_viewMenu;
++ QAction *m_zoomInAct;
++ QAction *m_zoomOutAct;
++ QAction *m_fitInWindowAct;
++ QAction *m_actualSizeAct;
++ QAction *m_100PercentSizeAct;
++ QAction *m_alignToGridAct;
++ QAction *m_showGridAct;
++ QAction *m_setGridSizeAct;
++ QAction *m_setBackgroundColorAct;
++ QAction *m_showBreadboardAct;
++ QAction *m_showSchematicAct;
++ QAction *m_showProgramAct;
++ QAction *m_showPCBAct;
++ QAction *m_showPartsBinIconViewAct;
++ QAction *m_showPartsBinListViewAct;
++ //QAction *m_toggleToolbarAct;
++ int m_numFixedActionsInViewMenu;
++
++ // Window Menu
++ QMenu *m_windowMenu;
++ QAction *m_minimizeAct;
++ QAction *m_togglePartLibraryAct;
++ QAction *m_toggleInfoAct;
++ QAction *m_toggleNavigatorAct;
++ QAction *m_toggleUndoHistoryAct;
++ QAction *m_toggleDebuggerOutputAct;
++ QAction *m_windowMenuSeparator;
++
++ // Trace Menu
++ QMenu *m_pcbTraceMenu;
++ QMenu *m_schematicTraceMenu;
++ QMenu *m_breadboardTraceMenu;
++ QAction *m_newAutorouteAct;
++ QAction *m_orderFabAct;
++ QAction *m_activeLayerTopAct;
++ QAction *m_activeLayerBottomAct;
++ QAction *m_activeLayerBothAct;
++ QAction *m_viewFromBelowToggleAct;
++ QAction *m_viewFromBelowAct;
++ QAction *m_viewFromAboveAct;
++ class WireAction *m_createTraceWireAct;
++ class WireAction *m_createWireWireAct;
++ QAction *m_createJumperAct;
++ QAction *m_changeTraceLayerAct;
++ class WireAction *m_changeTraceLayerWireAct;
++ QAction *m_excludeFromAutorouteAct;
++ class WireAction *m_excludeFromAutorouteWireAct;
++ QAction * m_showUnroutedAct;
++ QAction *m_selectAllTracesAct;
++ QAction *m_selectAllWiresAct;
++ QAction *m_selectAllCopperFillAct;
++ QAction *m_updateRoutingStatusAct;
++ QAction *m_selectAllExcludedTracesAct;
++ QAction *m_selectAllIncludedTracesAct;
++ QAction *m_selectAllJumperItemsAct;
++ QAction *m_selectAllViasAct;
++ QAction *m_groundFillAct;
++ QAction *m_removeGroundFillAct;
++ QAction *m_copperFillAct;
++ class ConnectorItemAction *m_setOneGroundFillSeedAct;
++ QAction *m_setGroundFillSeedsAct;
++ QAction *m_clearGroundFillSeedsAct;
++ QAction *m_setGroundFillKeepoutAct;
++ QAction *m_newDesignRulesCheckAct;
++ QAction *m_autorouterSettingsAct;
++ QAction *m_fabQuoteAct;
++ QAction *m_tidyWiresAct;
++ QAction *m_checkLoadedTracesAct;
++
++ // Help Menu
++ QMenu *m_helpMenu;
++ QAction *m_openHelpAct;
++ QAction *m_openDonateAct;
++ QAction *m_examplesAct;
++ QAction *m_partsRefAct;
++ QAction *m_showInViewHelpAct;;
++ QAction *m_visitFritzingDotOrgAct;
++ QAction *m_checkForUpdatesAct;
++ QAction *m_aboutQtAct;
++ QAction *m_reportBugAct;
++ QAction *m_enableDebugAct;
++ QAction *m_importFilesFromPrevInstallAct;
++ QAction *m_partsEditorHelpAct;
++
++ // Wire Color Menu
++ QMenu * m_breadboardWireColorMenu;
++ QMenu * m_schematicWireColorMenu;
++
++ // Dot icons
++ QIcon m_dotIcon;
++ QIcon m_emptyIcon;
++
++ QList<SketchToolButton*> m_rotateButtons;
++ QList<SketchToolButton*> m_flipButtons;
++ QStackedWidget * m_activeLayerButtonWidget;
++ QStackedWidget * m_viewFromButtonWidget;
++
++ bool m_comboboxChanged;
++ bool m_restarting;
++
++ QStringList m_alienFiles;
++ QString m_alienPartsMsg;
++ QStringList m_filesReplacedByAlienOnes;
++
++ QStringList m_openExampleActions;
++
++ QPointer<class TripleNavigator> m_tripleNavigator;
++ QDockWidget * m_navigatorDock;
++ QPointer<class FSizeGrip> m_sizeGrip;
++
++ friend class Helper;
++
++ QPointer<class ViewSwitcher> m_viewSwitcher;
++ QPointer<class ViewSwitcherDockWidget> m_viewSwitcherDock;
++
++ QPointer<Helper> m_helper;
++ QTimer m_setUpDockManagerTimer;
++ QPointer<class FileProgressDialog> m_fileProgressDialog;
++ QPointer<class ZoomSlider> m_zoomSlider;
++ QPointer<QLabel> m_locationLabel;
++ QString m_locationLabelUnits;
++
++ QByteArray m_externalProcessOutput;
++
++ QPointer<class LayerPalette> m_layerPalette;
++ QPointer<class ProgramWindow> m_programWindow;
++ QPointer<class ProgramWindow> m_programView;
++ QList<LinkedFile *> m_linkedProgramFiles;
++ QString m_backupFileNameAndPath;
++ QTimer m_autosaveTimer;
++ bool m_autosaveNeeded;
++ bool m_backingUp;
++ QString m_bundledSketchName;
++ RoutingStatus m_routingStatus;
++ bool m_orderFabEnabled;
++ bool m_closeSilently;
++ QString m_fzzFolder;
++ QHash<QString, struct LockedFile *> m_fzzFiles;
++ SwapTimer m_swapTimer;
++ QPointer<Wire> m_activeWire;
++ QPointer<ConnectorItem> m_activeConnectorItem;
++ bool m_addedToTemp;
++ QString m_settingsPrefix;
++
++ // dock management
++ QList<FDockWidget*> m_docks;
++ FDockWidget* m_topDock;
++ FDockWidget* m_bottomDock;
++ QString m_oldTopDockStyle;
++ QString m_oldBottomDockStyle;
++ bool m_dontKeepMargins;
++ QPointer<QDialog> m_rolloverQuoteDialog;
++ bool m_obsoleteSMDOrientation;
++
++public:
++ static int AutosaveTimeoutMinutes;
++ static bool AutosaveEnabled;
++ static QString BackupFolder;
++ static const int DockMinWidth;
++ static const int DockMinHeight;
++
++
++protected:
++ static const QString UntitledSketchName;
++ static int UntitledSketchIndex;
++ static int CascadeFactorX;
++ static int CascadeFactorY;
++ static QRegExp GuidMatcher;
++};
++
++
++#endif
+diff -urN fritzing-0.8.3b.source.orig/src/mainwindow/mainwindow_menu.cpp fritzing-0.8.3b.source/src/mainwindow/mainwindow_menu.cpp
+--- fritzing-0.8.3b.source.orig/src/mainwindow/mainwindow_menu.cpp 2013-07-27 14:03:38.000000000 -0700
++++ fritzing-0.8.3b.source/src/mainwindow/mainwindow_menu.cpp 2013-08-10 22:49:23.905174341 -0700
+@@ -1150,10 +1150,6 @@
m_visitFritzingDotOrgAct->setStatusTip(tr("www.fritzing.org"));
connect(m_visitFritzingDotOrgAct, SIGNAL(triggered(bool)), this, SLOT(visitFritzingDotOrg()));*/
@@ -178,7 +4003,7 @@ diff -urN fritzing-0.7.12b.source.orig/src/mainwindow/mainwindow_menu.cpp fritzi
m_aboutAct = new QAction(tr("&About"), this);
m_aboutAct->setStatusTip(tr("Show the application's about box"));
connect(m_aboutAct, SIGNAL(triggered()), this, SLOT(about()));
-@@ -1395,7 +1391,6 @@
+@@ -1459,7 +1455,6 @@
m_helpMenu->addSeparator();
m_helpMenu->addAction(m_partsEditorHelpAct);
m_helpMenu->addSeparator();
@@ -186,3 +4011,4314 @@ diff -urN fritzing-0.7.12b.source.orig/src/mainwindow/mainwindow_menu.cpp fritzi
m_helpMenu->addAction(m_importFilesFromPrevInstallAct);
m_helpMenu->addSeparator();
m_helpMenu->addAction(m_reportBugAct);
+diff -urN fritzing-0.8.3b.source.orig/src/mainwindow/mainwindow_menu.cpp.orig fritzing-0.8.3b.source/src/mainwindow/mainwindow_menu.cpp.orig
+--- fritzing-0.8.3b.source.orig/src/mainwindow/mainwindow_menu.cpp.orig 1969-12-31 16:00:00.000000000 -0800
++++ fritzing-0.8.3b.source/src/mainwindow/mainwindow_menu.cpp.orig 2013-07-27 14:03:38.000000000 -0700
+@@ -0,0 +1,4307 @@
++/*******************************************************************
++
++Part of the Fritzing project - http://fritzing.org
++Copyright (c) 2007-2013 Fachhochschule Potsdam - http://fh-potsdam.de
++
++Fritzing is free software: you can redistribute it and/or modify
++it under the terms of the GNU General Public License as published by
++the Free Software Foundation, either version 3 of the License, or
++(at your option) any later version.
++
++Fritzing is distributed in the hope that it will be useful,
++but WITHOUT ANY WARRANTY; without even the implied warranty of
++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++GNU General Public License for more details.
++
++You should have received a copy of the GNU General Public License
++along with Fritzing. If not, see <http://www.gnu.org/licenses/>.
++
++********************************************************************
++
++$Revision: 6999 $:
++$Author: irascibl at gmail.com $:
++$Date: 2013-04-28 14:14:07 +0200 (So, 28. Apr 2013) $
++
++********************************************************************/
++
++#include <QtGui>
++#include <QSvgGenerator>
++#include <QColor>
++#include <QImageWriter>
++#include <QInputDialog>
++
++#include "mainwindow.h"
++#include "../debugdialog.h"
++#include "../waitpushundostack.h"
++#include "../partseditor/pemainwindow.h"
++#include "../help/aboutbox.h"
++#include "../autoroute/mazerouter/mazerouter.h"
++#include "../autoroute/autorouteprogressdialog.h"
++#include "../autoroute/drc.h"
++#include "../items/virtualwire.h"
++#include "../items/resizableboard.h"
++#include "../items/jumperitem.h"
++#include "../items/via.h"
++#include "../fsvgrenderer.h"
++#include "../items/note.h"
++#include "../eagle/fritzing2eagle.h"
++#include "../sketch/breadboardsketchwidget.h"
++#include "../sketch/schematicsketchwidget.h"
++#include "../sketch/pcbsketchwidget.h"
++#include "../partsbinpalette/binmanager/binmanager.h"
++#include "../utils/expandinglabel.h"
++#include "../infoview/htmlinfoview.h"
++#include "../utils/bendpointaction.h"
++#include "../sketch/fgraphicsscene.h"
++#include "../utils/fileprogressdialog.h"
++#include "../svg/svgfilesplitter.h"
++#include "../version/version.h"
++#include "../svg/groundplanegenerator.h"
++#include "../help/tipsandtricks.h"
++#include "../dialogs/setcolordialog.h"
++#include "../utils/folderutils.h"
++#include "../utils/graphicsutils.h"
++#include "../utils/textutils.h"
++#include "../connectors/ercdata.h"
++#include "../items/moduleidnames.h"
++#include "../dock/miniviewcontainer.h"
++#include "../utils/zoomslider.h"
++#include "../dock/layerpalette.h"
++#include "../program/programwindow.h"
++#include "../utils/autoclosemessagebox.h"
++#include "../processeventblocker.h"
++#include "../sketchtoolbutton.h"
++
++////////////////////////////////////////////////////////
++
++// help struct to create the example menu from a xml file
++struct SketchDescriptor {
++ SketchDescriptor(const QString &_id, const QString &_name, const QString &_src, QAction * _action) {
++ id = _id;
++ name = _name;
++ src = _src;
++ action = _action;
++ }
++
++ QString id;
++ QString name;
++ QString src;
++ QAction * action;
++};
++
++bool sortSketchDescriptors(SketchDescriptor * s1, SketchDescriptor * s2){
++ return s1->name.toLower() < s2->name.toLower();
++}
++
++////////////////////////////////////////////////////////
++
++GridSizeThing::GridSizeThing(const QString & vName, const QString & sName, double defaultSize, const QString & gsText)
++{
++ defaultGridSize = defaultSize;
++ viewName = vName;
++ shortName = sName;
++ gridSizeText = gsText;
++}
++
++GridSizeDialog::GridSizeDialog(GridSizeThing * gridSizeThing) : QDialog() {
++ m_gridSizeThing = gridSizeThing;
++}
++
++GridSizeThing * GridSizeDialog::gridSizeThing() {
++ return m_gridSizeThing;
++}
++
++
++/////////////////////////////////////////////////////////
++
++void MainWindow::closeIfEmptySketch(MainWindow* mw) {
++ int cascFactorX; int cascFactorY;
++ // close empty sketch window if user opens from a file
++ if (FolderUtils::isEmptyFileName(mw->m_fwFilename, untitledFileName()) && mw->undoStackIsEmpty()) {
++ QTimer::singleShot(0, mw, SLOT(close()) );
++ cascFactorX = 0;
++ cascFactorY = 0;
++ } else {
++ cascFactorX = CascadeFactorX;
++ cascFactorY = CascadeFactorY;
++ }
++ mw->move(x()+cascFactorX,y()+cascFactorY);
++ mw->show();
++}
++
++void MainWindow::mainLoad() {
++ QString path;
++ // if it's the first time load is called use Documents folder
++ if(m_firstOpen){
++ path = defaultSaveFolder();
++ m_firstOpen = false;
++ }
++ else {
++ path = "";
++ }
++
++ QString fileName = FolderUtils::getOpenFileName(
++ this,
++ tr("Select a Fritzing File to Open"),
++ path,
++ tr("Fritzing Files (*%1 *%2 *%3 *%4 *%5);;Fritzing (*%1);;Fritzing Shareable (*%2);;Fritzing Part (*%3);;Fritzing Bin (*%4);;Fritzing Shareable Bin (*%5)")
++ .arg(FritzingSketchExtension)
++ .arg(FritzingBundleExtension)
++ .arg(FritzingBundledPartExtension)
++ .arg(FritzingBinExtension)
++ .arg(FritzingBundledBinExtension)
++ );
++
++ if (fileName.isEmpty()) return;
++
++ if (fileName.endsWith(FritzingBundledPartExtension)) {
++ m_binManager->importPartToMineBin(fileName);
++ return;
++ }
++
++ if (fileName.endsWith(FritzingBinExtension) || fileName.endsWith(FritzingBundledBinExtension)) {
++ m_binManager->openBinIn(fileName, false);
++ return;
++ }
++
++ mainLoadAux(fileName);
++}
++
++void MainWindow::mainLoadAux(const QString & fileName)
++{
++ if (fileName.isNull()) return;
++
++ if (!fileName.endsWith(FritzingSketchExtension) && !fileName.endsWith(FritzingBundleExtension)) {
++ loadWhich(fileName, false, false, "");
++ return;
++ }
++
++ if (alreadyOpen(fileName)) return;
++
++ QFile file(fileName);
++ if (!file.exists()) {
++ QMessageBox::warning(this, tr("Fritzing"),
++ tr("Cannot find file %1.")
++ .arg(fileName));
++
++
++ return;
++ }
++
++
++
++ if (!file.open(QFile::ReadOnly | QFile::Text)) {
++ QMessageBox::warning(this, tr("Fritzing"),
++ tr("Cannot read file 1 %1:\n%2.")
++ .arg(fileName)
++ .arg(file.errorString()));
++ return;
++ }
++
++ file.close();
++
++ MainWindow* mw = newMainWindow(m_referenceModel, fileName, true, true);
++ mw->loadWhich(fileName, true, true, "");
++ mw->clearFileProgressDialog();
++ closeIfEmptySketch(mw);
++}
++
++void MainWindow::revert() {
++ QMessageBox::StandardButton answer = QMessageBox::question(
++ this,
++ tr("Revert?"),
++ tr("This operation can not be undone--you will lose all of your changes."
++ "\n\nGo ahead and revert?"),
++ QMessageBox::Yes | QMessageBox::No,
++ QMessageBox::Yes
++ );
++ // TODO: make button texts translatable
++ if (answer != QMessageBox::Yes) {
++ return;
++ }
++
++ MainWindow* mw = newMainWindow( m_referenceModel, fileName(), true, true);
++ mw->setGeometry(this->geometry());
++
++ QFileInfo info(fileName());
++ if (info.exists() || !FolderUtils::isEmptyFileName(this->m_fwFilename, untitledFileName())) {
++ mw->loadWhich(fileName(), true, true, "");
++ }
++ else {
++ mw->addDefaultParts();
++ mw->show();
++ mw->hideTempPartsBin();
++ }
++
++ mw->clearFileProgressDialog();
++
++ // TODO: restore zoom, scroll, etc. for each view
++ mw->setCurrentTabIndex(currentTabIndex());
++
++ this->setCloseSilently(true);
++ this->close();
++}
++
++bool MainWindow::loadWhich(const QString & fileName, bool setAsLastOpened, bool addToRecent, const QString & displayName)
++{
++ if (!QFileInfo(fileName).exists()) {
++ QMessageBox::warning(NULL, tr("Fritzing"), tr("File '%1' not found").arg(fileName));
++ return false;
++ }
++
++ bool result = false;
++ if (fileName.endsWith(FritzingSketchExtension)) {
++ QFileInfo info(fileName);
++ QMessageBox messageBox(NULL);
++ messageBox.setWindowTitle(tr("the .fz file format is obsolete"));
++ messageBox.setText(tr("The .fz file format has been deprecated.\n\nWould you like to convert '%1' to the .fzz format now or open it read-only?\n").arg(info.fileName()));
++ messageBox.setInformativeText(tr("The conversion process will not modify '%1'.").arg(info.fileName()));
++ messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
++ messageBox.setDefaultButton(QMessageBox::Yes);
++ messageBox.setIcon(QMessageBox::Question);
++ messageBox.setWindowModality(Qt::WindowModal);
++ messageBox.setButtonText(QMessageBox::Yes, tr("Convert"));
++ messageBox.setButtonText(QMessageBox::No, tr("Read-only"));
++ messageBox.setButtonText(QMessageBox::Cancel, tr("Cancel"));
++ QMessageBox::StandardButton answer = (QMessageBox::StandardButton) messageBox.exec();
++
++ if (answer == QMessageBox::Cancel) return false;
++
++ QString bundledFileName;
++ if (answer == QMessageBox::Yes) {
++ QString fileExt;
++ bundledFileName = FolderUtils::getSaveFileName(this, tr("Please specify an .fzz file name to save '%1' to").arg(info.fileName()), fileName + "z", tr("Fritzing (*%1)").arg(FritzingBundleExtension), &fileExt);
++ if (bundledFileName.isEmpty()) return false;
++ }
++
++ mainLoad(fileName, displayName);
++ result = true;
++
++ QFile file(fileName);
++ QDir dest(m_fzzFolder);
++ file.copy(dest.absoluteFilePath(info.fileName())); // copy the .fz file directly
++
++ if (answer == QMessageBox::Yes) {
++ saveAsShareable(bundledFileName, false); // false to prevent saving a bundle inside the bundle
++ setCurrentFile(bundledFileName, addToRecent, setAsLastOpened);
++ }
++ else {
++ this->setReadOnly(true);
++ setCurrentFile(fileName, false, false);
++ }
++ }
++ else if(fileName.endsWith(FritzingBundleExtension)) {
++ loadBundledSketch(fileName, addToRecent, setAsLastOpened);
++ result = true;
++ }
++ else if (
++ fileName.endsWith(FritzingBinExtension)
++ || fileName.endsWith(FritzingBundledBinExtension)
++ ) {
++ m_binManager->load(fileName);
++ result = true;
++ }
++ else if (fileName.endsWith(FritzingPartExtension)) {
++ notYetImplemented(tr("directly loading parts"));
++ }
++ else if (fileName.endsWith(FritzingBundledPartExtension)) {
++ loadBundledPart(fileName, true);
++ result = true;
++ }
++
++ if (result) {
++ this->show();
++ }
++
++ return result;
++}
++
++void MainWindow::mainLoad(const QString & fileName, const QString & displayName) {
++
++ if (m_fileProgressDialog) {
++ m_fileProgressDialog->setMaximum(200);
++ m_fileProgressDialog->setValue(102);
++ }
++ this->show();
++ showAllFirstTimeHelp(false);
++ ProcessEventBlocker::processEvents();
++
++
++ QString displayName2 = displayName;
++ if (displayName.isEmpty()) {
++ QFileInfo fileInfo(fileName);
++ displayName2 = fileInfo.fileName();
++ }
++
++ if (m_fileProgressDialog) {
++ m_fileProgressDialog->setMessage(tr("loading %1 (model)").arg(displayName2));
++ m_fileProgressDialog->setValue(110);
++ }
++ ProcessEventBlocker::processEvents();
++
++
++ QList<ModelPart *> modelParts;
++
++ connect(m_sketchModel, SIGNAL(loadedViews(ModelBase *, QDomElement &)),
++ this, SLOT(loadedViewsSlot(ModelBase *, QDomElement &)), Qt::DirectConnection);
++ connect(m_sketchModel, SIGNAL(loadedRoot(const QString &, ModelBase *, QDomElement &)),
++ this, SLOT(loadedRootSlot(const QString &, ModelBase *, QDomElement &)), Qt::DirectConnection);
++ connect(m_sketchModel, SIGNAL(obsoleteSMDOrientationSignal()),
++ this, SLOT(obsoleteSMDOrientationSlot()), Qt::DirectConnection);
++ m_obsoleteSMDOrientation = false;
++ m_sketchModel->loadFromFile(fileName, m_referenceModel, modelParts, true);
++
++ //DebugDialog::debug("core loaded");
++ disconnect(m_sketchModel, SIGNAL(loadedViews(ModelBase *, QDomElement &)),
++ this, SLOT(loadedViewsSlot(ModelBase *, QDomElement &)));
++ disconnect(m_sketchModel, SIGNAL(loadedRoot(const QString &, ModelBase *, QDomElement &)),
++ this, SLOT(loadedRootSlot(const QString &, ModelBase *, QDomElement &)));
++ disconnect(m_sketchModel, SIGNAL(obsoleteSMDOrientationSignal()),
++ this, SLOT(obsoleteSMDOrientationSlot()));
++
++ ProcessEventBlocker::processEvents();
++ if (m_fileProgressDialog) {
++ m_fileProgressDialog->setValue(155);
++ m_fileProgressDialog->setMessage(tr("loading %1 (breadboard)").arg(displayName2));
++ }
++
++ QList<long> newIDs;
++ m_breadboardGraphicsView->loadFromModelParts(modelParts, BaseCommand::SingleView, NULL, false, NULL, false, newIDs);
++
++ ProcessEventBlocker::processEvents();
++ if (m_fileProgressDialog) {
++ m_fileProgressDialog->setValue(170);
++ m_fileProgressDialog->setMessage(tr("loading %1 (pcb)").arg(displayName2));
++ }
++
++ newIDs.clear();
++ m_pcbGraphicsView->loadFromModelParts(modelParts, BaseCommand::SingleView, NULL, false, NULL, false, newIDs);
++
++
++ ProcessEventBlocker::processEvents();
++ if (m_fileProgressDialog) {
++ m_fileProgressDialog->setValue(185);
++ m_fileProgressDialog->setMessage(tr("loading %1 (schematic)").arg(displayName2));
++ }
++
++ newIDs.clear();
++ m_schematicGraphicsView->loadFromModelParts(modelParts, BaseCommand::SingleView, NULL, false, NULL, false, newIDs);
++
++ ProcessEventBlocker::processEvents();
++ if (m_fileProgressDialog) {
++ m_fileProgressDialog->setValue(198);
++ }
++
++ if (m_obsoleteSMDOrientation) {
++ QSet<ItemBase *> toConvert;
++ foreach (QGraphicsItem * item, m_pcbGraphicsView->items()) {
++ ItemBase * itemBase = dynamic_cast<ItemBase *>(item);
++ if (itemBase == NULL) continue;
++
++ itemBase = itemBase->layerKinChief();
++ if (itemBase->modelPart()->flippedSMD() && itemBase->viewLayerPlacement() == ViewLayer::NewBottom) {
++ toConvert.insert(itemBase);
++ }
++ }
++
++ QList<ConnectorItem *> already;
++ foreach (ItemBase * itemBase, toConvert) {
++ PaletteItem * paletteItem = qobject_cast<PaletteItem *>(itemBase);
++ if (paletteItem == NULL) continue; // shouldn't happen
++
++ paletteItem->rotateItem(180, true);
++ }
++ }
++
++ if (m_programView) {
++ QFileInfo fileInfo(m_fwFilename);
++ m_programView->linkFiles(m_linkedProgramFiles, fileInfo.absoluteDir().absolutePath());
++ }
++
++}
++
++void MainWindow::copy() {
++ if (m_currentGraphicsView == NULL) return;
++ m_currentGraphicsView->copy();
++}
++
++void MainWindow::cut() {
++ if (m_currentGraphicsView == NULL) return;
++ m_currentGraphicsView->cut();
++}
++
++void MainWindow::pasteInPlace() {
++ pasteAux(true);
++}
++
++void MainWindow::paste() {
++ pasteAux(false);
++}
++
++void MainWindow::pasteAux(bool pasteInPlace)
++{
++ if (m_currentGraphicsView == NULL) return;
++
++ QClipboard *clipboard = QApplication::clipboard();
++ if (clipboard == NULL) {
++ // shouldn't happen
++ return;
++ }
++
++ const QMimeData* mimeData = clipboard->mimeData(QClipboard::Clipboard);
++ if (mimeData == NULL) return;
++
++ if (!mimeData->hasFormat("application/x-dnditemsdata")) return;
++
++ QByteArray itemData = mimeData->data("application/x-dnditemsdata");
++ QList<ModelPart *> modelParts;
++ QHash<QString, QRectF> boundingRects;
++ if (m_sketchModel->paste(m_referenceModel, itemData, modelParts, boundingRects, false)) {
++ QUndoCommand * parentCommand = new QUndoCommand("Paste");
++
++ QList<SketchWidget *> sketchWidgets;
++ sketchWidgets << m_breadboardGraphicsView << m_schematicGraphicsView << m_pcbGraphicsView;
++ sketchWidgets.removeOne(m_currentGraphicsView);
++ sketchWidgets.prepend(m_currentGraphicsView);
++
++ QList<long> newIDs;
++ foreach (SketchWidget * sketchWidget, sketchWidgets) {
++ newIDs.clear();
++ QRectF r;
++ QRectF boundingRect = boundingRects.value(sketchWidget->viewName(), r);
++ sketchWidget->loadFromModelParts(modelParts, BaseCommand::SingleView, parentCommand, true, pasteInPlace ? &r : &boundingRect, false, newIDs);
++ }
++
++ foreach (long id, newIDs) {
++ new IncLabelTextCommand(m_breadboardGraphicsView, id, parentCommand);
++ }
++
++ m_breadboardGraphicsView->setPasting(true);
++ m_pcbGraphicsView->setPasting(true);
++ m_schematicGraphicsView->setPasting(true);
++ m_undoStack->push(parentCommand);
++ m_breadboardGraphicsView->setPasting(false);
++ m_pcbGraphicsView->setPasting(false);
++ m_schematicGraphicsView->setPasting(false);
++ }
++
++ m_currentGraphicsView->updateInfoView();
++}
++
++void MainWindow::duplicate() {
++ if (m_currentGraphicsView == NULL) return;
++
++ m_currentGraphicsView->copy();
++ paste();
++
++ //m_currentGraphicsView->duplicate();
++}
++
++void MainWindow::doDelete() {
++ //DebugDialog::debug(QString("invoking do delete") );
++
++ if (m_currentGraphicsView != NULL) {
++ m_currentGraphicsView->deleteSelected(retrieveWire(), false);
++ }
++}
++
++void MainWindow::doDeleteMinus() {
++ if (m_currentGraphicsView != NULL) {
++ m_currentGraphicsView->deleteSelected(retrieveWire(), true);
++ }
++}
++
++void MainWindow::selectAll() {
++ if (m_currentGraphicsView != NULL) {
++ m_currentGraphicsView->selectDeselectAllCommand(true);
++ }
++}
++
++void MainWindow::deselect() {
++ if (m_currentGraphicsView != NULL) {
++ m_currentGraphicsView->selectDeselectAllCommand(false);
++ }
++}
++
++void MainWindow::about()
++{
++ AboutBox::showAbout();
++}
++
++void MainWindow::tipsAndTricks()
++{
++ TipsAndTricks::showTipsAndTricks();
++}
++
++void MainWindow::createActions()
++{
++ createRaiseWindowActions();
++
++ createFileMenuActions();
++ createEditMenuActions();
++ createPartMenuActions();
++ createViewMenuActions();
++ createWindowMenuActions();
++ createHelpMenuActions();
++ createTraceMenuActions();
++}
++
++void MainWindow::createRaiseWindowActions() {
++ m_raiseWindowAct = new QAction(m_fwFilename, this);
++ m_raiseWindowAct->setCheckable(true);
++ connect( m_raiseWindowAct, SIGNAL(triggered()), this, SLOT(raiseAndActivate()));
++ updateRaiseWindowAction();
++}
++
++void MainWindow::createFileMenuActions() {
++ m_newAct = new QAction(tr("New"), this);
++ m_newAct->setShortcut(tr("Ctrl+N"));
++ m_newAct->setStatusTip(tr("Create a new sketch"));
++ connect(m_newAct, SIGNAL(triggered()), this, SLOT(createNewSketch()));
++
++ m_openAct = new QAction(tr("&Open..."), this);
++ m_openAct->setShortcut(tr("Ctrl+O"));
++ m_openAct->setStatusTip(tr("Open a Fritzing sketch (.fzz, .fz), or load a Fritzing part (.fzpz), or a Fritzing parts bin (.fzb, .fzbz)"));
++ connect(m_openAct, SIGNAL(triggered()), this, SLOT(mainLoad()));
++
++ m_revertAct = new QAction(tr("Revert"), this);
++ m_revertAct->setStatusTip(tr("Reload the sketch"));
++ connect(m_revertAct, SIGNAL(triggered()), this, SLOT(revert()));
++
++ createOpenRecentMenu();
++ createOpenExampleMenu();
++ createCloseAction();
++ createExportActions();
++ createOrderFabAct();
++
++ QString name;
++ QString path;
++ QStringList args;
++ if (externalProcess(name, path, args)) {
++ m_launchExternalProcessAct = new QAction(name, this);
++ m_launchExternalProcessAct->setStatusTip(tr("Shell launch %1").arg(path));
++ connect(m_launchExternalProcessAct, SIGNAL(triggered()), this, SLOT(launchExternalProcess()));
++ }
++
++#ifndef QT_NO_DEBUG
++ m_exceptionAct = new QAction(tr("throw test exception"), this);
++ m_exceptionAct->setStatusTip(tr("throw a fake exception to see what happens"));
++ connect(m_exceptionAct, SIGNAL(triggered()), this, SLOT(throwFakeException()));
++#endif
++
++ m_quitAct = new QAction(tr("&Quit"), this);
++ m_quitAct->setShortcut(tr("Ctrl+Q"));
++ m_quitAct->setStatusTip(tr("Quit the application"));
++ connect(m_quitAct, SIGNAL(triggered()), qApp, SLOT(closeAllWindows2()));
++ m_quitAct->setMenuRole(QAction::QuitRole);
++
++}
++
++void MainWindow::createOpenExampleMenu() {
++ m_openExampleMenu = new QMenu(tr("&Open Example"), this);
++ QString folderPath = FolderUtils::getApplicationSubFolderPath("sketches")+"/";
++ populateMenuFromXMLFile(m_openExampleMenu, m_openExampleActions, folderPath, "index.xml");
++}
++
++void MainWindow::populateMenuFromXMLFile(QMenu *parentMenu, QStringList &actionsTracker, const QString &folderPath, const QString &indexFileName)
++{
++ QDomDocument dom;
++ QFile file(folderPath+indexFileName);
++ dom.setContent(&file);
++
++ QDomElement domElem = dom.documentElement();
++ QDomElement indexDomElem = domElem.firstChildElement("sketches");
++ QDomElement taxonomyDomElem = domElem.firstChildElement("categories");
++
++ QHash<QString, struct SketchDescriptor *> index = indexAvailableElements(indexDomElem, folderPath, actionsTracker);
++ QList<SketchDescriptor *> sketchDescriptors(index.values());
++ qSort(sketchDescriptors.begin(), sketchDescriptors.end(), sortSketchDescriptors);
++
++ if (sketchDescriptors.size() > 0) {
++ // set up the "all" category
++ QDomElement all = dom.createElement("category");
++ all.setAttribute("name", tr("All"));
++ taxonomyDomElem.appendChild(all);
++ foreach (SketchDescriptor * sketchDescriptor, sketchDescriptors) {
++ QDomElement sketch = dom.createElement("sketch");
++ sketch.setAttribute("id", sketchDescriptor->id);
++ all.appendChild(sketch);
++ }
++ }
++ populateMenuWithIndex(index, parentMenu, taxonomyDomElem);
++ foreach (SketchDescriptor * sketchDescriptor, index.values()) {
++ delete sketchDescriptor;
++ }
++}
++
++QHash<QString, struct SketchDescriptor *> MainWindow::indexAvailableElements(QDomElement &domElem, const QString &srcPrefix, QStringList & actionsTracker) {
++ QHash<QString, struct SketchDescriptor *> retval;
++ QDomElement sketch = domElem.firstChildElement("sketch");
++ while(!sketch.isNull()) {
++ const QString id = sketch.attribute("id");
++ const QString name = sketch.attribute("name");
++ QString srcAux = sketch.attribute("src");
++ // if it's an absolute path, don't prefix it
++ const QString src = QFileInfo(srcAux).exists()? srcAux: srcPrefix+srcAux;
++ if(QFileInfo(src).exists()) {
++ actionsTracker << name;
++ QAction * action = new QAction(name, this);
++ action->setData(src);
++ connect(action,SIGNAL(triggered()),this,SLOT(openRecentOrExampleFile()));
++ retval[id] = new SketchDescriptor(id,name,src, action);
++ }
++ sketch = sketch.nextSiblingElement("sketch");
++ }
++ return retval;
++}
++
++void MainWindow::populateMenuWithIndex(const QHash<QString, struct SketchDescriptor *> &index, QMenu * parentMenu, QDomElement &domElem) {
++ // note: the <sketch> element here is not the same as the <sketch> element in indexAvailableElements()
++ QDomElement e = domElem.firstChildElement();
++ while(!e.isNull()) {
++ if (e.nodeName() == "sketch") {
++ QString id = e.attribute("id");
++ if (!id.isEmpty()) {
++ if(index[id]) {
++ SketchDescriptor * sketchDescriptor = index[id];
++ parentMenu->addAction(sketchDescriptor->action);
++ }
++ else
++ {
++ qWarning() << tr("MainWindow::populateMenuWithIndex: couldn't load example with id='%1'").arg(id);
++ }
++ }
++ }
++ else if (e.nodeName() == "category") {
++ QString name = e.attribute("name");
++ QMenu * currMenu = new QMenu(name, parentMenu);
++ parentMenu->addMenu(currMenu);
++ populateMenuWithIndex(index, currMenu, e);
++ }
++ else if (e.nodeName() == "separator") {
++ parentMenu->addSeparator();
++ }
++ else if (e.nodeName() == "url") {
++ QAction * action = new QAction(e.attribute("name"), this);
++ action->setData(e.attribute("href"));
++ connect(action, SIGNAL(triggered()), this, SLOT(openURL()));
++ parentMenu->addAction(action);
++ }
++ e = e.nextSiblingElement();
++ }
++}
++
++void MainWindow::populateMenuFromFolderContent(QMenu * parentMenu, const QString &path) {
++ QDir *currDir = new QDir(path);
++ QStringList content = currDir->entryList(QDir::AllEntries | QDir::NoDotAndDotDot);
++ if(content.size() > 0) {
++ for(int i=0; i < content.size(); i++) {
++ QString currFile = content.at(i);
++ QString currFilePath = currDir->absoluteFilePath(currFile);
++ if(QFileInfo(currFilePath).isDir()) {
++ QMenu * currMenu = new QMenu(currFile, parentMenu);
++ parentMenu->addMenu(currMenu);
++ populateMenuFromFolderContent(currMenu, currFilePath);
++ } else {
++ QString actionText = QFileInfo(currFilePath).completeBaseName();
++ m_openExampleActions << actionText;
++ QAction * currAction = new QAction(actionText, this);
++ currAction->setData(currFilePath);
++ connect(currAction,SIGNAL(triggered()),this,SLOT(openRecentOrExampleFile()));
++ parentMenu->addAction(currAction);
++ }
++ }
++ } else {
++ parentMenu->setEnabled(false);
++ }
++ delete currDir;
++}
++
++void MainWindow::createOpenRecentMenu() {
++ m_openRecentFileMenu = new QMenu(tr("&Open Recent Files"), this);
++
++ for (int i = 0; i < MaxRecentFiles; ++i) {
++ m_openRecentFileActs[i] = new QAction(this);
++ m_openRecentFileActs[i]->setVisible(false);
++ connect(m_openRecentFileActs[i], SIGNAL(triggered()),this, SLOT(openRecentOrExampleFile()));
++ }
++
++
++ for (int i = 0; i < MaxRecentFiles; ++i) {
++ m_openRecentFileMenu->addAction(m_openRecentFileActs[i]);
++ }
++ updateRecentFileActions();
++}
++
++void MainWindow::updateFileMenu() {
++ updateRecentFileActions();
++ m_orderFabAct->setEnabled(true);
++
++ m_revertAct->setEnabled(m_undoStack->canUndo());
++}
++
++void MainWindow::updateRecentFileActions() {
++ QSettings settings;
++ QStringList files = settings.value("recentFileList").toStringList();
++ int ix = 0;
++ for (int i = 0; i < files.size(); ++i) {
++ QFileInfo finfo(files[i]);
++ if (!finfo.exists()) continue;
++
++ QString text = tr("&%1 %2").arg(ix + 1).arg(finfo.fileName());
++ m_openRecentFileActs[ix]->setText(text);
++ m_openRecentFileActs[ix]->setData(files[i]);
++ m_openRecentFileActs[ix]->setVisible(true);
++ if (++ix >= (int) MaxRecentFiles) {
++ break;
++ }
++ }
++
++ for (int j = ix; j < MaxRecentFiles; ++j) {
++ m_openRecentFileActs[j]->setVisible(false);
++ }
++
++ m_openRecentFileMenu->setEnabled(ix > 0);
++}
++
++void MainWindow::createEditMenuActions() {
++ m_undoAct = m_undoGroup->createUndoAction(this, tr("Undo"));
++ m_undoAct->setShortcuts(QKeySequence::Undo);
++ m_undoAct->setText(tr("Undo"));
++
++ m_redoAct = m_undoGroup->createRedoAction(this, tr("Redo"));
++ m_redoAct->setShortcuts(QKeySequence::Redo);
++ m_redoAct->setText(tr("Redo"));
++
++ m_cutAct = new QAction(tr("&Cut"), this);
++ m_cutAct->setShortcut(tr("Ctrl+X"));
++ m_cutAct->setStatusTip(tr("Cut selection"));
++ connect(m_cutAct, SIGNAL(triggered()), this, SLOT(cut()));
++
++ m_copyAct = new QAction(tr("&Copy"), this);
++ m_copyAct->setShortcut(tr("Ctrl+C"));
++ m_copyAct->setStatusTip(tr("Copy selection"));
++ connect(m_copyAct, SIGNAL(triggered()), this, SLOT(copy()));
++
++ m_pasteAct = new QAction(tr("&Paste"), this);
++ m_pasteAct->setShortcut(tr("Ctrl+V"));
++ m_pasteAct->setStatusTip(tr("Paste clipboard contents"));
++ connect(m_pasteAct, SIGNAL(triggered()), this, SLOT(paste()));
++
++ m_pasteInPlaceAct = new QAction(tr("Paste in Place"), this);
++ m_pasteInPlaceAct->setShortcut(tr("Ctrl+B"));
++ m_pasteInPlaceAct->setStatusTip(tr("Paste clipboard contents in place"));
++ connect(m_pasteInPlaceAct, SIGNAL(triggered()), this, SLOT(pasteInPlace()));
++
++ m_duplicateAct = new QAction(tr("&Duplicate"), this);
++ m_duplicateAct->setShortcut(tr("Ctrl+D"));
++ m_duplicateAct->setStatusTip(tr("Duplicate selection"));
++ connect(m_duplicateAct, SIGNAL(triggered()), this, SLOT(duplicate()));
++
++ m_deleteAct = new QAction(tr("&Delete"), this);
++ m_deleteAct->setStatusTip(tr("Delete selection"));
++ connect(m_deleteAct, SIGNAL(triggered()), this, SLOT(doDelete()));
++ #ifdef Q_WS_MAC
++ m_deleteAct->setShortcut(Qt::Key_Backspace);
++ #else
++ m_deleteAct->setShortcut(QKeySequence::Delete);
++ #endif
++
++ m_deleteMinusAct = new QAction(tr("Delete Minus"), this);
++ m_deleteMinusAct->setStatusTip(tr("Delete selection without attached wires"));
++ connect(m_deleteMinusAct, SIGNAL(triggered()), this, SLOT(doDeleteMinus()));
++
++ m_deleteWireAct = new WireAction(m_deleteAct);
++ m_deleteWireAct->setText(tr("&Delete Wire"));
++ connect(m_deleteWireAct, SIGNAL(triggered()), this, SLOT(doDelete()));
++
++ m_deleteWireMinusAct = new WireAction(m_deleteMinusAct);
++ m_deleteWireMinusAct->setText(tr("Delete Wire up to bendpoints"));
++ connect(m_deleteWireMinusAct, SIGNAL(triggered()), this, SLOT(doDeleteMinus()));
++
++ m_selectAllAct = new QAction(tr("&Select All"), this);
++ m_selectAllAct->setShortcut(tr("Ctrl+A"));
++ m_selectAllAct->setStatusTip(tr("Select all elements"));
++ connect(m_selectAllAct, SIGNAL(triggered()), this, SLOT(selectAll()));
++
++ m_deselectAct = new QAction(tr("&Deselect"), this);
++ m_deselectAct->setStatusTip(tr("Deselect"));
++ connect(m_deselectAct, SIGNAL(triggered()), this, SLOT(deselect()));
++
++ m_addNoteAct = new QAction(tr("Add Note"), this);
++ m_addNoteAct->setStatusTip(tr("Add a note"));
++ connect(m_addNoteAct, SIGNAL(triggered()), this, SLOT(addNote()));
++
++ m_preferencesAct = new QAction(tr("&Preferences..."), this);
++ m_preferencesAct->setStatusTip(tr("Show the application's about box"));
++ m_preferencesAct->setMenuRole(QAction::PreferencesRole); // make sure this is added to the correct menu on mac
++ connect(m_preferencesAct, SIGNAL(triggered()), QApplication::instance(), SLOT(preferences()));
++}
++
++void MainWindow::createPartMenuActions() {
++ m_openInPartsEditorNewAct = new QAction(tr("Edit (new parts editor)"), this);
++ m_openInPartsEditorNewAct->setStatusTip(tr("Open the new parts editor on an existing part"));
++ connect(m_openInPartsEditorNewAct, SIGNAL(triggered()), this, SLOT(openInPartsEditorNew()));
++
++ m_addToBinMenu = new QMenu(tr("&Add to bin..."), this);
++ m_addToBinMenu->setStatusTip(tr("Add selected part to bin"));
++
++ m_disconnectAllAct = new QAction(tr("Disconnect All Wires"), this);
++ m_disconnectAllAct->setStatusTip(tr("Disconnect all wires connected to this connector"));
++ connect(m_disconnectAllAct, SIGNAL(triggered()), this, SLOT(disconnectAll()));
++
++#ifndef QT_NO_DEBUG
++ m_infoViewOnHoverAction = new QAction(tr("Update InfoView on hover"), this);
++ m_infoViewOnHoverAction->setCheckable(true);
++ bool infoViewOnHover = true;
++ m_infoViewOnHoverAction->setChecked(infoViewOnHover);
++ setInfoViewOnHover(infoViewOnHover);
++ connect(m_infoViewOnHoverAction, SIGNAL(toggled(bool)), this, SLOT(setInfoViewOnHover(bool)));
++
++ m_exportNormalizedSvgAction = new QAction(tr("Export Normalized SVG"), this);
++ m_exportNormalizedSvgAction->setStatusTip(tr("Export 1000 dpi SVG of this part in this view"));
++ connect(m_exportNormalizedSvgAction, SIGNAL(triggered()), this, SLOT(exportNormalizedSVG()));
++
++ m_exportNormalizedFlattenedSvgAction = new QAction(tr("Export Normalized Flattened SVG"), this);
++ m_exportNormalizedFlattenedSvgAction->setStatusTip(tr("Export 1000 dpi Flattened SVG of this part in this view"));
++ connect(m_exportNormalizedFlattenedSvgAction, SIGNAL(triggered()), this, SLOT(exportNormalizedFlattenedSVG()));
++#endif
++
++
++ m_rotate45cwAct = new QAction(tr("Rotate 45\x00B0 Clockwise"), this);
++ m_rotate45cwAct->setStatusTip(tr("Rotate current selection 45 degrees clockwise"));
++ connect(m_rotate45cwAct, SIGNAL(triggered()), this, SLOT(rotate45cw()));
++
++ m_rotate90cwAct = new QAction(tr("Rotate 90\x00B0 Clockwise"), this);
++ m_rotate90cwAct->setStatusTip(tr("Rotate the selected parts by 90 degrees clockwise"));
++ connect(m_rotate90cwAct, SIGNAL(triggered()), this, SLOT(rotate90cw()));
++
++ m_rotate180Act = new QAction(tr("Rotate 180\x00B0"), this);
++ m_rotate180Act->setStatusTip(tr("Rotate the selected parts by 180 degrees"));
++ connect(m_rotate180Act, SIGNAL(triggered()), this, SLOT(rotate180()));
++
++ m_rotate90ccwAct = new QAction(tr("Rotate 90\x00B0 Counter Clockwise"), this);
++ m_rotate90ccwAct->setStatusTip(tr("Rotate current selection 90 degrees counter clockwise"));
++ connect(m_rotate90ccwAct, SIGNAL(triggered()), this, SLOT(rotate90ccw()));
++
++ m_rotate45ccwAct = new QAction(tr("Rotate 45\x00B0 Counter Clockwise"), this);
++ m_rotate45ccwAct->setStatusTip(tr("Rotate current selection 45 degrees counter clockwise"));
++ connect(m_rotate45ccwAct, SIGNAL(triggered()), this, SLOT(rotate45ccw()));
++
++ m_flipHorizontalAct = new QAction(tr("&Flip Horizontal"), this);
++ m_flipHorizontalAct->setStatusTip(tr("Flip current selection horizontally"));
++ connect(m_flipHorizontalAct, SIGNAL(triggered()), this, SLOT(flipHorizontal()));
++
++ m_flipVerticalAct = new QAction(tr("&Flip Vertical"), this);
++ m_flipVerticalAct->setStatusTip(tr("Flip current selection vertically"));
++ connect(m_flipVerticalAct, SIGNAL(triggered()), this, SLOT(flipVertical()));
++
++ m_bringToFrontAct = new QAction(tr("Bring to Front"), this);
++ m_bringToFrontAct->setShortcut(tr("Shift+Ctrl+]"));
++ m_bringToFrontAct->setStatusTip(tr("Bring selected object(s) to front of their layer"));
++ connect(m_bringToFrontAct, SIGNAL(triggered()), this, SLOT(bringToFront()));
++ m_bringToFrontWireAct = new WireAction(m_bringToFrontAct);
++ connect(m_bringToFrontWireAct, SIGNAL(triggered()), this, SLOT(bringToFront()));
++
++ m_bringForwardAct = new QAction(tr("Bring Forward"), this);
++ m_bringForwardAct->setShortcut(tr("Ctrl+]"));
++ m_bringForwardAct->setStatusTip(tr("Bring selected object(s) forward in their layer"));
++ connect(m_bringForwardAct, SIGNAL(triggered()), this, SLOT(bringForward()));
++ m_bringForwardWireAct = new WireAction(m_bringForwardAct);
++ connect(m_bringForwardWireAct, SIGNAL(triggered()), this, SLOT(bringForward()));
++
++ m_sendBackwardAct = new QAction(tr("Send Backward"), this);
++ m_sendBackwardAct->setShortcut(tr("Ctrl+["));
++ m_sendBackwardAct->setStatusTip(tr("Send selected object(s) back in their layer"));
++ connect(m_sendBackwardAct, SIGNAL(triggered()), this, SLOT(sendBackward()));
++ m_sendBackwardWireAct = new WireAction(m_sendBackwardAct);
++ connect(m_sendBackwardWireAct, SIGNAL(triggered()), this, SLOT(sendBackward()));
++
++ m_sendToBackAct = new QAction(tr("Send to Back"), this);
++ m_sendToBackAct->setShortcut(tr("Shift+Ctrl+["));
++ m_sendToBackAct->setStatusTip(tr("Send selected object(s) to the back of their layer"));
++ connect(m_sendToBackAct, SIGNAL(triggered()), this, SLOT(sendToBack()));
++ m_sendToBackWireAct = new WireAction(m_sendToBackAct);
++ connect(m_sendToBackWireAct, SIGNAL(triggered()), this, SLOT(sendToBack()));
++
++ m_alignLeftAct = new QAction(tr("Align Left"), this);
++ m_alignLeftAct->setStatusTip(tr("Align selected items at the left"));
++ connect(m_alignLeftAct, SIGNAL(triggered()), this, SLOT(alignLeft()));
++
++ m_alignHorizontalCenterAct = new QAction(tr("Align Horizontal Center"), this);
++ m_alignHorizontalCenterAct->setStatusTip(tr("Align selected items at the horizontal center"));
++ connect(m_alignHorizontalCenterAct, SIGNAL(triggered()), this, SLOT(alignHorizontalCenter()));
++
++ m_alignRightAct = new QAction(tr("Align Right"), this);
++ m_alignRightAct->setStatusTip(tr("Align selected items at the right"));
++ connect(m_alignRightAct, SIGNAL(triggered()), this, SLOT(alignRight()));
++
++ m_alignTopAct = new QAction(tr("Align Top"), this);
++ m_alignTopAct->setStatusTip(tr("Align selected items at the top"));
++ connect(m_alignTopAct, SIGNAL(triggered()), this, SLOT(alignTop()));
++
++ m_alignVerticalCenterAct = new QAction(tr("Align Vertical Center"), this);
++ m_alignVerticalCenterAct->setStatusTip(tr("Align selected items at the vertical center"));
++ connect(m_alignVerticalCenterAct, SIGNAL(triggered()), this, SLOT(alignVerticalCenter()));
++
++ m_alignBottomAct = new QAction(tr("Align Bottom"), this);
++ m_alignBottomAct->setStatusTip(tr("Align selected items at the bottom"));
++ connect(m_alignBottomAct, SIGNAL(triggered()), this, SLOT(alignBottom()));
++
++ m_moveLockAct = new QAction(tr("Lock Part"), this);
++ m_moveLockAct->setStatusTip(tr("Prevent a part from being moved"));
++ m_moveLockAct->setCheckable(true);
++ connect(m_moveLockAct, SIGNAL(triggered()), this, SLOT(moveLock()));
++
++ m_stickyAct = new QAction(tr("Sticky"), this);
++ m_stickyAct->setStatusTip(tr("If a \"sticky\" part is moved, parts on top of it are also moved"));
++ m_stickyAct->setCheckable(true);
++ connect(m_stickyAct, SIGNAL(triggered()), this, SLOT(setSticky()));
++
++ m_selectMoveLockAct = new QAction(tr("Select All Locked Parts"), this);
++ m_selectMoveLockAct->setStatusTip(tr("Select all parts that can't be moved"));
++ connect(m_selectMoveLockAct, SIGNAL(triggered()), this, SLOT(selectMoveLock()));
++
++ m_showPartLabelAct = new QAction(tr("&Show part label"), this);
++ m_showPartLabelAct->setStatusTip(tr("Show/hide the label for the selected parts"));
++ connect(m_showPartLabelAct, SIGNAL(triggered()), this, SLOT(showPartLabels()));
++
++ m_saveBundledPart = new QAction(tr("&Export..."), this);
++ m_saveBundledPart->setStatusTip(tr("Export selected part"));
++ connect(m_saveBundledPart, SIGNAL(triggered()), this, SLOT(saveBundledPart()));
++
++ m_addBendpointAct = new BendpointAction(tr("Add Bendpoint"), this);
++ m_addBendpointAct->setStatusTip(tr("Add a bendpoint to the selected wire"));
++ connect(m_addBendpointAct, SIGNAL(triggered()), this, SLOT(addBendpoint()));
++
++ m_convertToViaAct = new BendpointAction(tr("Convert Bendpoint to Via"), this);
++ m_convertToViaAct->setStatusTip(tr("Convert the bendpoint to a via"));
++ connect(m_convertToViaAct, SIGNAL(triggered()), this, SLOT(convertToVia()));
++
++ m_convertToBendpointAct = new QAction(tr("Convert Via to Bendpoint"), this);
++ m_convertToBendpointAct->setStatusTip(tr("Convert the via to a bendpoint"));
++ connect(m_convertToBendpointAct, SIGNAL(triggered()), this, SLOT(convertToBendpoint()));
++
++ m_flattenCurveAct = new BendpointAction(tr("Straighten Curve"), this);
++ m_flattenCurveAct->setStatusTip(tr("Straighten the curve of the selected wire"));
++ connect(m_flattenCurveAct, SIGNAL(triggered()), this, SLOT(flattenCurve()));
++
++ m_selectAllObsoleteAct = new QAction(tr("Select outdated parts"), this);
++ m_selectAllObsoleteAct->setStatusTip(tr("Select outdated parts"));
++ connect(m_selectAllObsoleteAct, SIGNAL(triggered()), this, SLOT(selectAllObsolete()));
++
++ m_swapObsoleteAct = new QAction(tr("Update selected parts"), this);
++ m_swapObsoleteAct->setStatusTip(tr("Update selected parts"));
++ connect(m_swapObsoleteAct, SIGNAL(triggered()), this, SLOT(swapObsolete()));
++
++ m_findPartInSketchAct = new QAction(tr("Find part in sketch..."), this);
++ m_findPartInSketchAct->setStatusTip(tr("Search for parts in a sketch by matching text"));
++ connect(m_findPartInSketchAct, SIGNAL(triggered()), this, SLOT(findPartInSketch()));
++
++ m_openProgramWindowAct = new QAction(tr("Open programming window"), this);
++ m_openProgramWindowAct->setStatusTip(tr("Open microcontroller programming window"));
++ connect(m_openProgramWindowAct, SIGNAL(triggered()), this, SLOT(openProgramWindow()));
++
++ m_hidePartSilkscreenAct = new QAction(tr("Hide part silkscreen"), this);
++ m_hidePartSilkscreenAct->setStatusTip(tr("Hide/show the silkscreen layer for only this part"));
++ connect(m_hidePartSilkscreenAct, SIGNAL(triggered()), this, SLOT(hidePartSilkscreen()));
++
++
++}
++
++void MainWindow::createViewMenuActions() {
++ m_zoomInAct = new QAction(tr("&Zoom In"), this);
++ m_zoomInAct->setShortcut(tr("Ctrl++"));
++ m_zoomInAct->setStatusTip(tr("Zoom in"));
++ connect(m_zoomInAct, SIGNAL(triggered()), this, SLOT(zoomIn()));
++
++ // instead of creating a filter to grab the shortcut, let's create a new action
++ // and append it to the window
++ QAction *zoomInAux = new QAction(this);
++ zoomInAux->setShortcut(tr("Ctrl+="));
++ connect(zoomInAux, SIGNAL(triggered()), this, SLOT(zoomIn()));
++ this->addAction(zoomInAux);
++
++ m_zoomOutAct = new QAction(tr("&Zoom Out"), this);
++ m_zoomOutAct->setShortcut(tr("Ctrl+-"));
++ m_zoomOutAct->setStatusTip(tr("Zoom out"));
++ connect(m_zoomOutAct, SIGNAL(triggered()), this, SLOT(zoomOut()));
++
++ m_fitInWindowAct = new QAction(tr("&Fit in Window"), this);
++ m_fitInWindowAct->setShortcut(tr("Ctrl+0"));
++ m_fitInWindowAct->setStatusTip(tr("Fit in window"));
++ connect(m_fitInWindowAct, SIGNAL(triggered()), this, SLOT(fitInWindow()));
++
++ m_actualSizeAct = new QAction(tr("&Actual Size"), this);
++ m_actualSizeAct->setStatusTip(tr("Actual (real world physical) size"));
++ connect(m_actualSizeAct, SIGNAL(triggered()), this, SLOT(actualSize()));
++
++ m_100PercentSizeAct = new QAction(tr("100% Size"), this);
++ m_100PercentSizeAct->setShortcut(tr("Shift+Ctrl+0"));
++ m_100PercentSizeAct->setStatusTip(tr("100% (pixel) size"));
++ connect(m_100PercentSizeAct, SIGNAL(triggered()), this, SLOT(hundredPercentSize()));
++
++ m_alignToGridAct = new QAction(tr("Align to Grid"), this);
++ m_alignToGridAct->setStatusTip(tr("Align items to grid when dragging"));
++ m_alignToGridAct->setCheckable(true);
++ connect(m_alignToGridAct, SIGNAL(triggered()), this, SLOT(alignToGrid()));
++
++ m_showGridAct = new QAction(tr("Show Grid"), this);
++ m_showGridAct->setStatusTip(tr("Show the grid"));
++ m_showGridAct->setCheckable(true);
++ connect(m_showGridAct, SIGNAL(triggered()), this, SLOT(showGrid()));
++
++ m_setGridSizeAct = new QAction(tr("Set Grid Size..."), this);
++ m_setGridSizeAct->setStatusTip(tr("Set the size of the grid in this view"));
++ connect(m_setGridSizeAct, SIGNAL(triggered()), this, SLOT(setGridSize()));
++
++ m_setBackgroundColorAct = new QAction(tr("Set Background Color..."), this);
++ m_setBackgroundColorAct->setStatusTip(tr("Set the background color of this view"));
++ connect(m_setBackgroundColorAct, SIGNAL(triggered()), this, SLOT(setBackgroundColor()));
++
++ m_showBreadboardAct = new QAction(tr("&Show Breadboard"), this);
++ m_showBreadboardAct->setShortcut(tr("Ctrl+1"));
++ m_showBreadboardAct->setStatusTip(tr("Show the breadboard view"));
++ connect(m_showBreadboardAct, SIGNAL(triggered()), this, SLOT(showBreadboardView()));
++
++ m_showSchematicAct = new QAction(tr("&Show Schematic"), this);
++ m_showSchematicAct->setShortcut(tr("Ctrl+2"));
++ m_showSchematicAct->setStatusTip(tr("Show the schematic view"));
++ connect(m_showSchematicAct, SIGNAL(triggered()), this, SLOT(showSchematicView()));
++
++ m_showPCBAct = new QAction(tr("&Show PCB"), this);
++ m_showPCBAct->setShortcut(tr("Ctrl+3"));
++ m_showPCBAct->setStatusTip(tr("Show the PCB view"));
++ connect(m_showPCBAct, SIGNAL(triggered()), this, SLOT(showPCBView()));
++
++ if (m_programView) {
++ m_showProgramAct = new QAction(tr("Show Code"), this);
++ m_showProgramAct->setShortcut(tr("Ctrl+4"));
++ m_showProgramAct->setStatusTip(tr("Show the code (programming) view"));
++ connect(m_showProgramAct, SIGNAL(triggered()), this, SLOT(showProgramView()));
++ QList<QAction *> viewMenuActions;
++ viewMenuActions << m_showBreadboardAct << m_showSchematicAct << m_showPCBAct << m_showProgramAct;
++ m_programView->initViewMenu(viewMenuActions);
++ }
++
++ m_showPartsBinIconViewAct = new QAction(tr("Show Parts Bin Icon View"), this);
++ m_showPartsBinIconViewAct->setStatusTip(tr("Display the parts bin in an icon view"));
++ connect(m_showPartsBinIconViewAct, SIGNAL(triggered()), this, SLOT(showPartsBinIconView()));
++
++ m_showPartsBinListViewAct = new QAction(tr("Show Parts Bin List View"), this);
++ m_showPartsBinListViewAct->setStatusTip(tr("Display the parts bin in a list view"));
++ connect(m_showPartsBinListViewAct, SIGNAL(triggered()), this, SLOT(showPartsBinListView()));
++
++ m_showAllLayersAct = new QAction(tr("&Show All Layers"), this);
++ m_showAllLayersAct->setStatusTip(tr("Show all the available layers for the current view"));
++ connect(m_showAllLayersAct, SIGNAL(triggered()), this, SLOT(showAllLayers()));
++
++ m_hideAllLayersAct = new QAction(tr("&Hide All Layers"), this);
++ m_hideAllLayersAct->setStatusTip(tr("Hide all the layers of the current view"));
++ connect(m_hideAllLayersAct, SIGNAL(triggered()), this, SLOT(hideAllLayers()));
++
++}
++
++void MainWindow::createWindowMenuActions() {
++ m_minimizeAct = new QAction(tr("&Minimize"), this);
++ m_minimizeAct->setShortcut(tr("Ctrl+M"));
++ m_minimizeAct->setStatusTip(tr("Minimize current window"));
++ connect(m_minimizeAct, SIGNAL(triggered(bool)), this, SLOT(minimize()));
++
++ /*
++ m_toggleToolbarAct = new QAction(tr("&Toolbar"), this);
++ m_toggleToolbarAct->setShortcut(tr("Shift+Ctrl+T"));
++ m_toggleToolbarAct->setCheckable(true);
++ m_toggleToolbarAct->setChecked(true);
++ m_toggleToolbarAct->setStatusTip(tr("Toggle Toolbar visibility"));
++ connect(m_toggleToolbarAct, SIGNAL(triggered(bool)), this, SLOT(toggleToolbar(bool)));
++ */
++
++ m_toggleDebuggerOutputAct = new QAction(tr("Debugger Output"), this);
++ m_toggleDebuggerOutputAct->setCheckable(true);
++ connect(m_toggleDebuggerOutputAct, SIGNAL(triggered(bool)), this, SLOT(toggleDebuggerOutput(bool)));
++}
++
++void MainWindow::createHelpMenuActions() {
++ m_openHelpAct = new QAction(tr("Online Tutorials"), this);
++ m_openHelpAct->setShortcut(tr("Ctrl+?"));
++ m_openHelpAct->setStatusTip(tr("Open Fritzing help"));
++ connect(m_openHelpAct, SIGNAL(triggered(bool)), this, SLOT(openHelp()));
++
++ m_openDonateAct = new QAction(tr("Donate to Fritzing"), this);
++ m_openDonateAct->setStatusTip(tr("Open Fritzing donation web page"));
++ connect(m_openDonateAct, SIGNAL(triggered(bool)), this, SLOT(openDonate()));
++
++ m_examplesAct = new QAction(tr("Online Projects Gallery"), this);
++ m_examplesAct->setStatusTip(tr("Open Fritzing examples"));
++ connect(m_examplesAct, SIGNAL(triggered(bool)), this, SLOT(openExamples()));
++
++ m_partsRefAct = new QAction(tr("Online Parts Reference"), this);
++ m_partsRefAct->setStatusTip(tr("Open Parts Reference"));
++ connect(m_partsRefAct, SIGNAL(triggered(bool)), this, SLOT(openPartsReference()));
++
++ m_showInViewHelpAct = new QAction(tr("First Time Help"), this);
++ m_showInViewHelpAct->setStatusTip(tr("Show or Hide First Time Help"));
++ m_showInViewHelpAct->setCheckable(true);
++ m_showInViewHelpAct->setChecked(true);
++ connect(m_showInViewHelpAct, SIGNAL(triggered(bool)), this, SLOT(showInViewHelp()));
++
++ /*m_visitFritzingDotOrgAct = new QAction(tr("Visit fritzing.org"), this);
++ m_visitFritzingDotOrgAct->setStatusTip(tr("www.fritzing.org"));
++ connect(m_visitFritzingDotOrgAct, SIGNAL(triggered(bool)), this, SLOT(visitFritzingDotOrg()));*/
++
++ m_checkForUpdatesAct = new QAction(tr("Check for updates..."), this);
++ m_checkForUpdatesAct->setStatusTip(tr("Check whether a newer version of Fritzing is available for download"));
++ connect(m_checkForUpdatesAct, SIGNAL(triggered()), QApplication::instance(), SLOT(checkForUpdates()));
++
++ m_aboutAct = new QAction(tr("&About"), this);
++ m_aboutAct->setStatusTip(tr("Show the application's about box"));
++ connect(m_aboutAct, SIGNAL(triggered()), this, SLOT(about()));
++ m_aboutAct->setMenuRole(QAction::AboutRole);
++
++ m_tipsAndTricksAct = new QAction(tr("Tips, Tricks and Shortcuts"), this);
++ m_tipsAndTricksAct->setStatusTip(tr("Display some handy Fritzing tips and tricks"));
++ connect(m_tipsAndTricksAct, SIGNAL(triggered()), this, SLOT(tipsAndTricks()));
++
++ m_aboutQtAct = new QAction(tr("&About Qt"), this);
++ m_aboutQtAct->setStatusTip(tr("Show Qt's about box"));
++ connect(m_aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
++
++ m_reportBugAct = new QAction(tr("Report a bug..."), this);
++ m_reportBugAct->setStatusTip(tr("Report a but you've found in Fritzing"));
++ connect(m_reportBugAct, SIGNAL(triggered()), this, SLOT(reportBug()));
++
++ m_enableDebugAct = new QAction(tr("Enable debugging log"), this);
++ m_enableDebugAct->setStatusTip(tr("Report a but you've found in Fritzing"));
++ m_enableDebugAct->setCheckable(true);
++ m_enableDebugAct->setChecked(DebugDialog::enabled());
++ connect(m_enableDebugAct, SIGNAL(triggered()), this, SLOT(enableDebug()));
++
++ m_importFilesFromPrevInstallAct = new QAction(tr("&Import parts and bins from old version..."), this);
++ m_importFilesFromPrevInstallAct->setStatusTip(tr("Import parts and bins from previous installation"));
++ connect(m_importFilesFromPrevInstallAct, SIGNAL(triggered()), this, SLOT(importFilesFromPrevInstall()));
++
++ m_partsEditorHelpAct = new QAction(tr("Parts Editor Help"), this);
++ m_partsEditorHelpAct->setStatusTip(tr("Display Parts Editor help in a browser"));
++ connect(m_partsEditorHelpAct, SIGNAL(triggered(bool)), this, SLOT(partsEditorHelp()));
++
++
++}
++
++void MainWindow::createMenus()
++{
++ createFileMenu();
++ createEditMenu();
++ createPartMenu();
++ createViewMenu();
++ createWindowMenu();
++ createTraceMenus();
++ createHelpMenu();
++}
++
++void MainWindow::createFileMenu() {
++ m_fileMenu = menuBar()->addMenu(tr("&File"));
++ m_fileMenu->addAction(m_newAct);
++ m_fileMenu->addAction(m_openAct);
++ m_fileMenu->addAction(m_revertAct);
++ m_fileMenu->addMenu(m_openRecentFileMenu);
++ m_fileMenu->addMenu(m_openExampleMenu);
++
++ m_fileMenu->addSeparator();
++ m_fileMenu->addAction(m_closeAct);
++ m_fileMenu->addAction(m_saveAct);
++ m_fileMenu->addAction(m_saveAsAct);
++ m_fileMenu->addAction(m_shareOnlineAct);
++
++ if (m_orderFabEnabled) {
++ m_fileMenu->addAction(m_orderFabAct);
++ }
++
++ m_fileMenu->addSeparator();
++ m_exportMenu = m_fileMenu->addMenu(tr("&Export"));
++ //m_fileMenu->addAction(m_pageSetupAct);
++ m_fileMenu->addAction(m_printAct);
++
++ QString name;
++ QString path;
++ QStringList args;
++ if (externalProcess(name, path, args)) {
++ m_fileMenu->addSeparator();
++ m_fileMenu->addAction(m_launchExternalProcessAct);
++ }
++
++#ifndef QT_NO_DEBUG
++ m_fileMenu->addSeparator();
++ m_fileMenu->addAction(m_exceptionAct);
++#endif
++
++ m_fileMenu->addSeparator();
++ m_fileMenu->addAction(m_quitAct);
++ connect(m_fileMenu, SIGNAL(aboutToShow()), this, SLOT(updateFileMenu()));
++
++ populateExportMenu();
++
++ m_exportMenu->addAction(m_exportBomAct);
++ m_exportMenu->addAction(m_exportNetlistAct);
++ //m_exportMenu->addAction(m_exportSpiceNetlistAct);
++
++ //m_exportMenu->addAction(m_exportEagleAct);
++}
++
++void MainWindow::populateExportMenu() {
++ QMenu * imageMenu = m_exportMenu->addMenu(tr("as Image"));
++ imageMenu->addAction(m_exportPngAct);
++ imageMenu->addAction(m_exportJpgAct);
++ imageMenu->addSeparator();
++ imageMenu->addAction(m_exportSvgAct);
++ imageMenu->addAction(m_exportPdfAct);
++ imageMenu->addAction(m_exportPsAct);
++
++ QMenu * productionMenu = m_exportMenu->addMenu(tr("for Production"));
++ productionMenu->addAction(m_exportEtchablePdfAct);
++ productionMenu->addAction(m_exportEtchableSvgAct);
++ productionMenu->addSeparator();
++ productionMenu->addAction(m_exportGerberAct);
++}
++
++
++void MainWindow::createEditMenu()
++{
++ m_editMenu = menuBar()->addMenu(tr("&Edit"));
++ m_editMenu->addAction(m_undoAct);
++ m_editMenu->addAction(m_redoAct);
++ m_editMenu->addSeparator();
++ m_editMenu->addAction(m_cutAct);
++ m_editMenu->addAction(m_copyAct);
++ m_editMenu->addAction(m_pasteAct);
++ m_editMenu->addAction(m_pasteInPlaceAct);
++ m_editMenu->addAction(m_duplicateAct);
++ m_editMenu->addAction(m_deleteAct);
++ m_editMenu->addAction(m_deleteMinusAct);
++ m_editMenu->addSeparator();
++ m_editMenu->addAction(m_selectAllAct);
++ m_editMenu->addAction(m_deselectAct);
++ m_editMenu->addSeparator();
++ m_editMenu->addAction(m_addNoteAct);
++ m_editMenu->addSeparator();
++ m_editMenu->addAction(m_preferencesAct);
++ updateEditMenu();
++ connect(m_editMenu, SIGNAL(aboutToShow()), this, SLOT(updateEditMenu()));
++}
++
++void MainWindow::createPartMenu() {
++ m_partMenu = menuBar()->addMenu(tr("&Part"));
++ connect(m_partMenu, SIGNAL(aboutToShow()), this, SLOT(updatePartMenu()));
++
++ m_partMenu->addAction(m_openInPartsEditorNewAct);
++ m_partMenu->addSeparator();
++
++ m_partMenu->addAction(m_saveBundledPart);
++
++ m_partMenu->addSeparator();
++ m_partMenu->addAction(m_flipHorizontalAct);
++ m_partMenu->addAction(m_flipVerticalAct);
++ m_rotateMenu = m_partMenu->addMenu(tr("Rotate"));
++ m_zOrderMenu = m_partMenu->addMenu(tr("Raise and Lower"));
++ m_zOrderWireMenu = new QMenu(m_zOrderMenu);
++ m_zOrderWireMenu->setTitle(m_zOrderMenu->title());
++ m_alignMenu = m_partMenu->addMenu(tr("Align"));
++ m_partMenu->addAction(m_moveLockAct);
++ m_partMenu->addAction(m_stickyAct);
++ m_partMenu->addAction(m_selectMoveLockAct);
++
++
++ m_partMenu->addSeparator();
++ m_partMenu->addMenu(m_addToBinMenu);
++ m_partMenu->addAction(m_showPartLabelAct);
++ m_partMenu->addSeparator();
++ m_partMenu->addAction(m_selectAllObsoleteAct);
++ m_partMenu->addAction(m_swapObsoleteAct);
++
++ m_partMenu->addSeparator();
++ m_partMenu->addAction(m_findPartInSketchAct);
++
++ m_rotateMenu->addAction(m_rotate45cwAct);
++ m_rotateMenu->addAction(m_rotate90cwAct);
++ m_rotateMenu->addAction(m_rotate180Act);
++ m_rotateMenu->addAction(m_rotate90ccwAct);
++ m_rotateMenu->addAction(m_rotate45ccwAct);
++
++ m_zOrderMenu->addAction(m_bringToFrontAct);
++ m_zOrderMenu->addAction(m_bringForwardAct);
++ m_zOrderMenu->addAction(m_sendBackwardAct);
++ m_zOrderMenu->addAction(m_sendToBackAct);
++
++ m_zOrderWireMenu->addAction(m_bringToFrontWireAct);
++ m_zOrderWireMenu->addAction(m_bringForwardWireAct);
++ m_zOrderWireMenu->addAction(m_sendBackwardWireAct);
++ m_zOrderWireMenu->addAction(m_sendToBackWireAct);
++
++ m_alignMenu->addAction(m_alignLeftAct);
++ m_alignMenu->addAction(m_alignHorizontalCenterAct);
++ m_alignMenu->addAction(m_alignRightAct);
++ m_alignMenu->addAction(m_alignTopAct);
++ m_alignMenu->addAction(m_alignVerticalCenterAct);
++ m_alignMenu->addAction(m_alignBottomAct);
++}
++
++void MainWindow::createViewMenu()
++{
++ m_viewMenu = menuBar()->addMenu(tr("&View"));
++ m_viewMenu->addAction(m_zoomInAct);
++ m_viewMenu->addAction(m_zoomOutAct);
++ m_viewMenu->addAction(m_fitInWindowAct);
++ m_viewMenu->addAction(m_actualSizeAct);
++ m_viewMenu->addAction(m_100PercentSizeAct);
++ m_viewMenu->addSeparator();
++
++ m_viewMenu->addAction(m_alignToGridAct);
++ m_viewMenu->addAction(m_showGridAct);
++ m_viewMenu->addAction(m_setGridSizeAct);
++ m_viewMenu->addAction(m_setBackgroundColorAct);
++ m_viewMenu->addSeparator();
++
++ m_viewMenu->addAction(m_showBreadboardAct);
++ m_viewMenu->addAction(m_showSchematicAct);
++ m_viewMenu->addAction(m_showPCBAct);
++ if (m_programView) m_viewMenu->addAction(m_showProgramAct);
++ m_viewMenu->addSeparator();
++ if (m_binManager) {
++ m_viewMenu->addAction(m_showPartsBinIconViewAct);
++ m_viewMenu->addAction(m_showPartsBinListViewAct);
++ m_viewMenu->addSeparator();
++ }
++ connect(m_viewMenu, SIGNAL(aboutToShow()), this, SLOT(updateLayerMenu()));
++ m_numFixedActionsInViewMenu = m_viewMenu->actions().size();
++}
++
++void MainWindow::createWindowMenu() {
++ m_windowMenu = menuBar()->addMenu(tr("&Window"));
++ m_windowMenu->addAction(m_minimizeAct);
++ m_windowMenu->addSeparator();
++ //m_windowMenu->addAction(m_toggleToolbarAct);
++ updateWindowMenu();
++ connect(m_windowMenu, SIGNAL(aboutToShow()), this, SLOT(updateWindowMenu()));
++}
++
++void MainWindow::createTraceMenus()
++{
++ m_pcbTraceMenu = menuBar()->addMenu(tr("&Routing"));
++ m_pcbTraceMenu->addAction(m_newAutorouteAct);
++ m_pcbTraceMenu->addAction(m_newDesignRulesCheckAct);
++ m_pcbTraceMenu->addAction(m_autorouterSettingsAct);
++ m_pcbTraceMenu->addAction(m_fabQuoteAct);
++
++ QMenu * groundFillMenu = m_pcbTraceMenu->addMenu(tr("Ground Fill"));
++
++ groundFillMenu->addAction(m_copperFillAct);
++ groundFillMenu->addAction(m_groundFillAct);
++ groundFillMenu->addAction(m_removeGroundFillAct);
++ groundFillMenu->addAction(m_setGroundFillSeedsAct);
++ groundFillMenu->addAction(m_clearGroundFillSeedsAct);
++ groundFillMenu->addAction(m_setGroundFillKeepoutAct);
++ //m_pcbTraceMenu->addAction(m_updateRoutingStatusAct);
++ m_pcbTraceMenu->addSeparator();
++
++ m_pcbTraceMenu->addAction(m_viewFromBelowToggleAct);
++ m_pcbTraceMenu->addAction(m_activeLayerBothAct);
++ m_pcbTraceMenu->addAction(m_activeLayerBottomAct);
++ m_pcbTraceMenu->addAction(m_activeLayerTopAct);
++ m_pcbTraceMenu->addSeparator();
++
++ m_pcbTraceMenu->addAction(m_changeTraceLayerAct);
++ m_pcbTraceMenu->addAction(m_excludeFromAutorouteAct);
++ m_pcbTraceMenu->addSeparator();
++
++ m_pcbTraceMenu->addAction(m_showUnroutedAct);
++ m_pcbTraceMenu->addAction(m_selectAllTracesAct);
++ m_pcbTraceMenu->addAction(m_selectAllExcludedTracesAct);
++ m_pcbTraceMenu->addAction(m_selectAllIncludedTracesAct);
++ m_pcbTraceMenu->addAction(m_selectAllJumperItemsAct);
++ m_pcbTraceMenu->addAction(m_selectAllViasAct);
++ m_pcbTraceMenu->addAction(m_selectAllCopperFillAct);
++
++ //m_pcbTraceMenu->addSeparator();
++ //m_pcbTraceMenu->addAction(m_checkLoadedTracesAct);
++
++ m_schematicTraceMenu = menuBar()->addMenu(tr("&Routing"));
++ m_schematicTraceMenu->addAction(m_newAutorouteAct);
++ m_schematicTraceMenu->addAction(m_excludeFromAutorouteAct);
++ m_schematicTraceMenu->addAction(m_showUnroutedAct);
++ m_schematicTraceMenu->addAction(m_selectAllTracesAct);
++ m_schematicTraceMenu->addAction(m_selectAllExcludedTracesAct);
++ m_schematicTraceMenu->addAction(m_selectAllIncludedTracesAct);
++ //m_schematicTraceMenu->addAction(m_updateRoutingStatusAct);
++
++#ifndef QT_NO_DEBUG
++ m_schematicTraceMenu->addAction(m_tidyWiresAct);
++#endif
++
++ m_breadboardTraceMenu = menuBar()->addMenu(tr("&Routing"));
++ m_breadboardTraceMenu->addAction(m_showUnroutedAct);
++ m_breadboardTraceMenu->addAction(m_selectAllWiresAct);
++
++ updateTraceMenu();
++ connect(m_pcbTraceMenu, SIGNAL(aboutToShow()), this, SLOT(updateTraceMenu()));
++ connect(m_schematicTraceMenu, SIGNAL(aboutToShow()), this, SLOT(updateTraceMenu()));
++ connect(m_breadboardTraceMenu, SIGNAL(aboutToShow()), this, SLOT(updateTraceMenu()));
++
++ menuBar()->addSeparator();
++}
++
++void MainWindow::createHelpMenu()
++{
++ m_helpMenu = menuBar()->addMenu(tr("&Help"));
++ m_helpMenu->addAction(m_showInViewHelpAct);
++ m_helpMenu->addAction(m_openHelpAct);
++ m_helpMenu->addAction(m_examplesAct);
++ m_helpMenu->addAction(m_partsRefAct);
++ m_helpMenu->addSeparator();
++ m_helpMenu->addAction(m_partsEditorHelpAct);
++ m_helpMenu->addSeparator();
++ m_helpMenu->addAction(m_checkForUpdatesAct);
++ m_helpMenu->addAction(m_importFilesFromPrevInstallAct);
++ m_helpMenu->addSeparator();
++ m_helpMenu->addAction(m_reportBugAct);
++ m_helpMenu->addAction(m_enableDebugAct);
++ m_helpMenu->addSeparator();
++ m_helpMenu->addAction(m_aboutAct);
++ m_helpMenu->addAction(m_openDonateAct);
++ m_helpMenu->addAction(m_tipsAndTricksAct);
++#ifndef QT_NO_DEBUG
++ m_helpMenu->addAction(m_aboutQtAct);
++#endif
++}
++
++
++void MainWindow::updateLayerMenu(bool resetLayout) {
++ if (m_viewMenu == NULL) return;
++ if (m_showAllLayersAct == NULL) return;
++
++ QList<QAction *> actions;
++
++ if (m_showPartsBinIconViewAct) {
++ if (m_binManager) {
++ m_showPartsBinIconViewAct->setEnabled(true);
++ m_showPartsBinListViewAct->setEnabled(true);
++ actions << m_showPartsBinIconViewAct << m_showPartsBinListViewAct;
++ setActionsIcons(m_binManager->currentViewIsIconView() ? 0 : 1, actions);
++ }
++ else {
++ m_showPartsBinIconViewAct->setEnabled(false);
++ m_showPartsBinListViewAct->setEnabled(false);
++ }
++ }
++
++ removeActionsStartingAt(m_viewMenu, m_numFixedActionsInViewMenu);
++ if (m_showAllLayersAct) m_viewMenu->addAction(m_showAllLayersAct);
++ if (m_hideAllLayersAct) m_viewMenu->addAction(m_hideAllLayersAct);
++
++ if (m_currentGraphicsView == NULL) return;
++
++ m_alignToGridAct->setChecked(m_currentGraphicsView->alignedToGrid());
++ m_showGridAct->setChecked(m_currentGraphicsView->showingGrid());
++
++ LayerHash viewLayers = m_currentGraphicsView->viewLayers();
++ LayerList keys = viewLayers.keys();
++
++ // make sure they're in ascending order when inserting into the menu
++ qSort(keys.begin(), keys.end());
++
++ foreach (ViewLayer::ViewLayerID key, keys) {
++ ViewLayer * viewLayer = viewLayers.value(key);
++ //DebugDialog::debug(QString("Layer: %1 is %2").arg(viewLayer->action()->text()).arg(viewLayer->action()->isEnabled()));
++ if (viewLayer != NULL) {
++ if (viewLayer->parentLayer()) continue;
++ m_viewMenu->addAction(viewLayer->action());
++ disconnect(viewLayer->action(), SIGNAL(triggered()), this, SLOT(updateLayerMenu()));
++ connect(viewLayer->action(), SIGNAL(triggered()), this, SLOT(updateLayerMenu()));
++ }
++ }
++
++
++ m_hideAllLayersAct->setEnabled(false);
++ m_showAllLayersAct->setEnabled(false);
++
++ if (keys.count() <= 0) return;
++
++ ViewLayer *prev = viewLayers.value(keys[0]);
++ if (prev == NULL) {
++ // jrc: I think prev == NULL is actually a side effect from an earlier bug
++ // but I haven't figured out the cause yet
++ // at any rate, when this bug occurs, keys[0] is some big negative number that looks like an
++ // uninitialized or scrambled layerID
++ DebugDialog::debug(QString("updateAllLayersActions keys[0] failed %1").arg(keys[0]) );
++ return;
++ }
++
++ bool sameState = prev->action()->isChecked();
++ bool checked = prev->action()->isChecked();
++ //DebugDialog::debug(QString("Layer: %1 is %2").arg(prev->action()->text()).arg(prev->action()->isChecked()));
++ for (int i = 1; i < keys.count(); i++) {
++ ViewLayer *viewLayer = viewLayers.value(keys[i]);
++ //DebugDialog::debug(QString("Layer: %1 is %2").arg(viewLayer->action()->text()).arg(viewLayer->action()->isChecked()));
++ if (viewLayer != NULL) {
++ if (prev != NULL && prev->action()->isChecked() != viewLayer->action()->isChecked() ) {
++ // if the actions aren't all checked or unchecked I don't bother about the "checked" variable
++ sameState = false;
++ break;
++ }
++ else {
++ sameState = true;
++ checked = viewLayer->action()->isChecked();
++ }
++ prev = viewLayer;
++ }
++ }
++
++ //DebugDialog::debug(QString("sameState: %1").arg(sameState));
++ //DebugDialog::debug(QString("checked: %1").arg(checked));
++ if (sameState) {
++ if(checked) {
++ m_hideAllLayersAct->setEnabled(true);
++ }
++ else {
++ m_showAllLayersAct->setEnabled(true);
++ }
++ }
++ else {
++ m_showAllLayersAct->setEnabled(true);
++ m_hideAllLayersAct->setEnabled(true);
++ }
++
++ if (resetLayout) {
++ m_layerPalette->resetLayout(viewLayers, keys);
++ }
++ m_layerPalette->updateLayerPalette(viewLayers, keys);
++}
++
++void MainWindow::updateWireMenu() {
++ // assumes update wire menu is only called when right-clicking a wire
++ // and that wire is cached by the menu in Wire::mousePressEvent
++
++ Wire * wire = m_activeWire;
++ m_activeWire = NULL;
++
++ if (wire) {
++ enableAddBendpointAct(wire);
++ }
++
++ bool enableAll = true;
++ bool deleteOK = false;
++ bool createTraceOK = false;
++ bool excludeOK = false;
++ bool enableZOK = true;
++ bool gotRat = false;
++ bool ctlOK = false;
++
++ if (wire != NULL) {
++
++ if (wire->getRatsnest()) {
++ QList<ConnectorItem *> ends;
++ Wire * jt = wire->findTraced(m_currentGraphicsView->getTraceFlag(), ends);
++ createTraceOK = (jt == NULL) || (!jt->getTrace());
++ deleteOK = true;
++ gotRat = true;
++ enableZOK = false;
++ }
++ else if (wire->getTrace()) {
++ deleteOK = true;
++ excludeOK = true;
++ m_excludeFromAutorouteWireAct->setChecked(!wire->getAutoroutable());
++ if (m_currentGraphicsView == m_pcbGraphicsView && m_currentGraphicsView->boardLayers() > 1) {
++ if (wire->canSwitchLayers()) {
++ if (ViewLayer::topLayers().contains(wire->viewLayerID())) {
++ m_changeTraceLayerWireAct->setText(tr("Move to bottom layer"));
++ }
++ else {
++ m_changeTraceLayerWireAct->setText(tr("Move to top layer"));
++ }
++ ctlOK = true;
++ }
++ }
++
++ }
++ else {
++ deleteOK = true;
++ }
++ }
++
++
++ QMenu* wireColorMenu = (m_currentGraphicsView == m_breadboardGraphicsView ? m_breadboardWireColorMenu : m_schematicWireColorMenu);
++ if (wire) {
++ wireColorMenu->setEnabled(true);
++ QString colorString = wire->colorString();
++ //DebugDialog::debug("wire colorstring " + colorString);
++ foreach (QAction * action, wireColorMenu->actions()) {
++ QString colorName = action->data().toString();
++ //DebugDialog::debug("colorname " + colorName);
++ action->setChecked(colorName.compare(colorString) == 0);
++ }
++ }
++ else {
++ wireColorMenu->setEnabled(false);
++ }
++
++ m_bringToFrontWireAct->setWire(wire);
++ m_bringForwardWireAct->setWire(wire);
++ m_sendBackwardWireAct->setWire(wire);
++ m_sendToBackWireAct->setWire(wire);
++ m_createTraceWireAct->setWire(wire);
++ m_createWireWireAct->setWire(wire);
++ m_deleteWireAct->setWire(wire);
++ m_deleteWireMinusAct->setWire(wire);
++ m_excludeFromAutorouteWireAct->setWire(wire);
++ m_changeTraceLayerWireAct->setWire(wire);
++
++ m_bringToFrontWireAct->setEnabled(enableZOK);
++ m_bringForwardWireAct->setEnabled(enableZOK);
++ m_sendBackwardWireAct->setEnabled(enableZOK);
++ m_sendToBackWireAct->setEnabled(enableZOK);
++ m_createTraceWireAct->setEnabled(enableAll && createTraceOK);
++ m_createWireWireAct->setEnabled(enableAll && createTraceOK);
++ m_deleteWireAct->setEnabled(enableAll && deleteOK);
++ m_deleteWireMinusAct->setEnabled(enableAll && deleteOK && !gotRat);
++ m_excludeFromAutorouteWireAct->setEnabled(enableAll && excludeOK);
++ m_changeTraceLayerAct->setEnabled(ctlOK);
++ m_changeTraceLayerWireAct->setEnabled(ctlOK);
++
++ if (gotRat) {
++ m_deleteWireAct->setText(tr("Delete Ratsnest Line"));
++ }
++ else {
++ m_deleteWireAct->setText(tr("Delete Wire"));
++ }
++
++
++}
++
++void MainWindow::updatePartMenu() {
++ if (m_currentGraphicsView == NULL) return;
++ if (m_partMenu == NULL) return;
++
++ ItemCount itemCount = m_currentGraphicsView->calcItemCount();
++
++ bool enable = true;
++ bool zenable = true;
++
++ if (itemCount.selCount <= 0) {
++ zenable = enable = false;
++ }
++ else {
++ if (itemCount.itemsCount == itemCount.selCount) {
++ // if all items are selected
++ // z-reordering is a no-op
++ zenable = false;
++ }
++ }
++
++ m_alignLeftAct->setEnabled(itemCount.selCount - itemCount.wireCount > 1);
++ m_alignRightAct->setEnabled(itemCount.selCount - itemCount.wireCount > 1);
++ m_alignTopAct->setEnabled(itemCount.selCount - itemCount.wireCount > 1);
++ m_alignBottomAct->setEnabled(itemCount.selCount - itemCount.wireCount > 1);
++ m_alignVerticalCenterAct->setEnabled(itemCount.selCount - itemCount.wireCount > 1);
++ m_alignHorizontalCenterAct->setEnabled(itemCount.selCount - itemCount.wireCount > 1);
++
++ //DebugDialog::debug(QString("enable layer actions %1").arg(enable));
++ m_bringToFrontAct->setEnabled(zenable);
++ m_bringForwardAct->setEnabled(zenable);
++ m_sendBackwardAct->setEnabled(zenable);
++ m_sendToBackAct->setEnabled(zenable);
++
++ m_moveLockAct->setEnabled(itemCount.selCount > 0 && itemCount.selCount > itemCount.wireCount);
++ m_moveLockAct->setChecked(itemCount.moveLockCount > 0);
++ m_selectMoveLockAct->setEnabled(true);
++
++ m_showPartLabelAct->setEnabled((itemCount.hasLabelCount > 0) && enable);
++ m_showPartLabelAct->setText(itemCount.visLabelCount == itemCount.hasLabelCount ? tr("Hide part label") : tr("Show part label"));
++ m_showPartLabelAct->setData(itemCount.visLabelCount != itemCount.hasLabelCount);
++
++ bool renable = (itemCount.selRotatable > 0);
++ bool renable45 = (itemCount.sel45Rotatable > 0);
++
++ //DebugDialog::debug(QString("enable rotate (2) %1").arg(enable));
++
++ m_rotate90cwAct->setEnabled(renable && enable);
++ m_rotate180Act->setEnabled(renable && enable);
++ m_rotate90ccwAct->setEnabled(renable && enable);
++ m_rotate45ccwAct->setEnabled(renable && renable45 && enable);
++ m_rotate45cwAct->setEnabled(renable && renable45 && enable);
++
++ m_flipHorizontalAct->setEnabled(enable && (itemCount.selHFlipable > 0) && (m_currentGraphicsView != m_pcbGraphicsView));
++ m_flipVerticalAct->setEnabled(enable && (itemCount.selVFlipable > 0) && (m_currentGraphicsView != m_pcbGraphicsView));
++
++ updateItemMenu();
++ updateEditMenu();
++
++
++ bool ctbpVisible = false;
++ bool ctbpEnabled = false;
++ if (itemCount.selCount == 1) {
++ ItemBase * itemBase = dynamic_cast<ItemBase *>(m_currentGraphicsView->scene()->selectedItems()[0]);
++ enableAddBendpointAct(itemBase);
++
++ Via * via = qobject_cast<Via *>(itemBase->layerKinChief());
++ if (via) {
++ ctbpVisible = true;
++ int count = 0;
++ QList<ConnectorItem *> viaConnectorItems;
++ viaConnectorItems << via->connectorItem();
++ if (via->connectorItem()->getCrossLayerConnectorItem()) {
++ viaConnectorItems << via->connectorItem()->getCrossLayerConnectorItem();
++ }
++
++ foreach (ConnectorItem * viaConnectorItem, viaConnectorItems) {
++ foreach (ConnectorItem * connectorItem, viaConnectorItem->connectedToItems()) {
++ Wire * wire = qobject_cast<Wire *>(connectorItem->attachedTo());
++ if (wire == NULL) continue;
++ if (wire->getRatsnest()) continue;
++
++ if (wire->isTraceType(m_currentGraphicsView->getTraceFlag())) {
++ count++;
++ if (count > 1) {
++ ctbpEnabled = true;
++ break;
++ }
++ }
++ }
++ if (count > 1) break;
++ }
++ }
++
++
++ m_openInPartsEditorNewAct->setEnabled(itemBase->canEditPart());
++ m_stickyAct->setVisible(itemBase->isBaseSticky());
++ m_stickyAct->setEnabled(true);
++ m_stickyAct->setChecked(itemBase->isBaseSticky() && itemBase->isLocalSticky());
++
++ QList<ItemBase *> itemBases;
++ itemBases.append(itemBase);
++ itemBases.append(itemBase->layerKinChief()->layerKin());
++ bool hpsa = false;
++ foreach (ItemBase * lkpi, itemBases) {
++ if (lkpi->viewLayerID() == ViewLayer::Silkscreen1 || lkpi->viewLayerID() == ViewLayer::Silkscreen0) {
++ hpsa = true;
++ m_hidePartSilkscreenAct->setText(lkpi->layerHidden() ? tr("Show part silkscreen") : tr("Hide part silkscreen"));
++ break;
++ }
++ }
++
++ m_hidePartSilkscreenAct->setEnabled(hpsa);
++ }
++ else {
++ m_hidePartSilkscreenAct->setEnabled(false);
++ m_stickyAct->setVisible(false);
++ m_openInPartsEditorNewAct->setEnabled(false);
++ }
++ m_convertToBendpointAct->setEnabled(ctbpEnabled);
++ m_convertToBendpointAct->setVisible(ctbpVisible);
++ m_convertToBendpointSeparator->setVisible(ctbpVisible);
++
++ // TODO: only enable if there is an obsolete part in the sketch
++ m_selectAllObsoleteAct->setEnabled(true);
++ m_swapObsoleteAct->setEnabled(itemCount.obsoleteCount > 0);
++ m_findPartInSketchAct->setEnabled(m_currentGraphicsView != NULL);
++ m_openProgramWindowAct->setEnabled(true);
++}
++
++void MainWindow::updateTransformationActions() {
++ // update buttons in sketch toolbar at bottom
++
++ if (m_currentGraphicsView == NULL) return;
++ if (m_rotate90cwAct == NULL) return;
++
++ ItemCount itemCount = m_currentGraphicsView->calcItemCount();
++ bool enable = (itemCount.selRotatable > 0);
++ bool renable = (itemCount.sel45Rotatable > 0);
++
++ //DebugDialog::debug(QString("enable rotate (1) %1").arg(enable));
++
++ m_rotate90cwAct->setEnabled(enable);
++ m_rotate180Act->setEnabled(enable);
++ m_rotate90ccwAct->setEnabled(enable);
++ m_rotate45ccwAct->setEnabled(enable && renable);
++ m_rotate45cwAct->setEnabled(enable && renable);
++ foreach(SketchToolButton* rotateButton, m_rotateButtons) {
++ rotateButton->setEnabled(enable);
++ }
++
++ m_flipHorizontalAct->setEnabled((itemCount.selHFlipable > 0) && (m_currentGraphicsView != m_pcbGraphicsView));
++ m_flipVerticalAct->setEnabled((itemCount.selVFlipable > 0) && (m_currentGraphicsView != m_pcbGraphicsView));
++
++ enable = m_flipHorizontalAct->isEnabled() || m_flipVerticalAct->isEnabled();
++ foreach(SketchToolButton* flipButton, m_flipButtons) {
++ flipButton->setEnabled(enable);
++ }
++}
++
++void MainWindow::updateItemMenu() {
++ if (m_currentGraphicsView == NULL) return;
++
++ ConnectorItem * activeConnectorItem = m_activeConnectorItem;
++ m_activeConnectorItem = NULL;
++
++ QList<QGraphicsItem *> items = m_currentGraphicsView->scene()->selectedItems();
++
++ int selCount = 0;
++ ItemBase * itemBase = NULL;
++ foreach(QGraphicsItem * item, items) {
++ ItemBase * ib = ItemBase::extractTopLevelItemBase(item);
++ if (ib == NULL) continue;
++
++ selCount++;
++ if (selCount == 1) itemBase = ib;
++ else if (selCount > 1) break;
++ }
++
++ PaletteItem *selected = qobject_cast<PaletteItem *>(itemBase);
++ bool enabled = (selCount == 1) && (selected != NULL);
++ m_addToBinMenu->setEnabled(enabled);
++ m_addToBinMenu->clear();
++ if(enabled) {
++ QList<QAction*> acts = m_binManager->openedBinsActions(selectedModuleID());
++ m_addToBinMenu->addActions(acts);
++ }
++
++ m_saveBundledPart->setEnabled(enabled && !selected->modelPart()->isCore());
++
++
++ // can't open wire in parts editor
++ enabled &= selected != NULL && itemBase != NULL && itemBase->canEditPart();
++
++ m_disconnectAllAct->setEnabled(enabled && m_currentGraphicsView->canDisconnectAll() && (itemBase->rightClickedConnector() != NULL));
++
++ bool gfsEnabled = false;
++ if (activeConnectorItem) {
++ if (activeConnectorItem->attachedToItemType() != ModelPart::CopperFill) {
++ gfsEnabled = true;
++ m_setOneGroundFillSeedAct->setChecked(activeConnectorItem->isGroundFillSeed());
++ }
++ }
++ m_setOneGroundFillSeedAct->setEnabled(gfsEnabled);
++ m_setOneGroundFillSeedAct->setConnectorItem(activeConnectorItem);
++}
++
++void MainWindow::updateEditMenu() {
++ QClipboard *clipboard = QApplication::clipboard();
++ m_pasteAct->setEnabled(false);
++ m_pasteInPlaceAct->setEnabled(false);
++ if (clipboard != NULL) {
++ const QMimeData *mimeData = clipboard->mimeData(QClipboard::Clipboard);
++ if (mimeData != NULL) {
++ if (mimeData->hasFormat("application/x-dnditemsdata")) {
++ m_pasteAct->setEnabled(true);
++ m_pasteInPlaceAct->setEnabled(true);
++ //DebugDialog::debug(QString("paste enabled: true"));
++ }
++ }
++ }
++
++ if (m_currentGraphicsView != NULL) {
++ const QList<QGraphicsItem *> items = m_currentGraphicsView->scene()->selectedItems();
++ bool copyActsEnabled = false;
++ bool deleteActsEnabled = false;
++ foreach (QGraphicsItem * item, items) {
++ if (m_currentGraphicsView->canDeleteItem(item, items.count())) {
++ deleteActsEnabled = true;
++ }
++ if (m_currentGraphicsView->canCopyItem(item, items.count())) {
++ copyActsEnabled = true;
++ }
++ }
++
++ //DebugDialog::debug(QString("enable cut/copy/duplicate/delete %1 %2 %3").arg(copyActsEnabled).arg(deleteActsEnabled).arg(m_currentWidget->viewID()) );
++ m_deleteAct->setEnabled(deleteActsEnabled);
++ m_deleteMinusAct->setEnabled(deleteActsEnabled);
++ m_deleteAct->setText(tr("Delete"));
++ m_cutAct->setEnabled(deleteActsEnabled && copyActsEnabled);
++ m_copyAct->setEnabled(copyActsEnabled);
++ m_duplicateAct->setEnabled(copyActsEnabled);
++ }
++}
++
++void MainWindow::updateTraceMenu() {
++ if (m_pcbTraceMenu == NULL) return;
++
++ bool tEnabled = false;
++ bool twEnabled = false;
++ bool ctlEnabled = false;
++ bool arEnabled = false;
++
++ TraceMenuThing traceMenuThing;
++
++ if (m_currentGraphicsView != NULL) {
++ QList<QGraphicsItem *> items = m_currentGraphicsView->scene()->items();
++ foreach (QGraphicsItem * item, items) {
++ Wire * wire = dynamic_cast<Wire *>(item);
++ if (wire == NULL) {
++ if (m_currentGraphicsView == m_pcbGraphicsView) {
++ updatePCBTraceMenu(item, traceMenuThing);
++ }
++ continue;
++ }
++
++ if (!wire->isEverVisible()) continue;
++ if (wire->getRatsnest()) {
++ //rEnabled = true;
++ //if (wire->isSelected()) {
++ //ctEnabled = true;
++ //}
++ }
++ else if (wire->isTraceType(m_currentGraphicsView->getTraceFlag())) {
++ arEnabled = true;
++ tEnabled = true;
++ twEnabled = true;
++ if (wire->isSelected()) {
++ traceMenuThing.exEnabled = true;
++ if (wire->getAutoroutable()) {
++ traceMenuThing.exChecked = false;
++ }
++ }
++ if (m_currentGraphicsView == m_pcbGraphicsView && m_currentGraphicsView->boardLayers() > 1) {
++ if (wire->canSwitchLayers()) {
++ ctlEnabled = true;
++ }
++ }
++ }
++ }
++ }
++
++ if (!arEnabled) {
++ if (m_currentGraphicsView != NULL) {
++ arEnabled = m_currentGraphicsView->hasAnyNets();
++ }
++ }
++
++ bool anyOrNo = (traceMenuThing.boardCount >= 1 || m_currentGraphicsView != m_pcbGraphicsView);
++
++ m_excludeFromAutorouteAct->setEnabled(traceMenuThing.exEnabled);
++ m_excludeFromAutorouteAct->setChecked(traceMenuThing.exChecked);
++ m_changeTraceLayerAct->setEnabled(ctlEnabled);
++ m_orderFabAct->setEnabled(traceMenuThing.boardCount > 0);
++ m_showUnroutedAct->setEnabled(true);
++ m_selectAllTracesAct->setEnabled(tEnabled && anyOrNo);
++ m_selectAllWiresAct->setEnabled(tEnabled && anyOrNo);
++ m_selectAllCopperFillAct->setEnabled(traceMenuThing.gfrEnabled && traceMenuThing.boardCount >= 1);
++ m_selectAllExcludedTracesAct->setEnabled(tEnabled && anyOrNo);
++ m_selectAllIncludedTracesAct->setEnabled(tEnabled && anyOrNo);
++ m_selectAllJumperItemsAct->setEnabled(traceMenuThing.jiEnabled && traceMenuThing.boardCount >= 1);
++ m_selectAllViasAct->setEnabled(traceMenuThing.viaEnabled && traceMenuThing.boardCount >= 1);
++ m_tidyWiresAct->setEnabled(twEnabled);
++
++ QString sides;
++ if (m_pcbGraphicsView->layerIsActive(ViewLayer::Copper0) && m_pcbGraphicsView->layerIsActive(ViewLayer::Copper1)) {
++ sides = tr("top and bottom");
++ }
++ else if (m_pcbGraphicsView->layerIsActive(ViewLayer::Copper0)) {
++ sides = tr("bottom");
++ }
++ else sides = tr("top");
++
++ QString groundFillString = tr("Ground Fill (%1)").arg(sides);
++ QString copperFillString = tr("Copper Fill (%1)").arg(sides);
++
++ m_groundFillAct->setEnabled(traceMenuThing.boardCount >= 1);
++ m_groundFillAct->setText(groundFillString);
++ m_copperFillAct->setEnabled(traceMenuThing.boardCount >= 1);
++ m_copperFillAct->setText(copperFillString);
++ m_removeGroundFillAct->setEnabled(traceMenuThing.gfrEnabled && traceMenuThing.boardCount >= 1);
++
++ // TODO: set and clear enabler logic
++ m_setGroundFillSeedsAct->setEnabled(traceMenuThing.gfsEnabled && traceMenuThing.boardCount >= 1);
++ m_clearGroundFillSeedsAct->setEnabled(traceMenuThing.gfsEnabled && traceMenuThing.boardCount >= 1);
++
++ m_newDesignRulesCheckAct->setEnabled(traceMenuThing.boardCount >= 1);
++ m_checkLoadedTracesAct->setEnabled(true);
++ m_autorouterSettingsAct->setEnabled(m_currentGraphicsView == m_pcbGraphicsView);
++ m_updateRoutingStatusAct->setEnabled(true);
++
++
++ m_fabQuoteAct->setEnabled(m_currentGraphicsView == m_pcbGraphicsView);
++}
++
++
++void MainWindow::updatePCBTraceMenu(QGraphicsItem * item, TraceMenuThing & traceMenuThing)
++{
++ ItemBase * itemBase = dynamic_cast<ItemBase *>(item);
++ if (itemBase == NULL) return;
++ if (!itemBase->isEverVisible()) return;
++
++ if (!traceMenuThing.gfsEnabled) {
++ traceMenuThing.gfsEnabled = itemBase->itemType() != ModelPart::CopperFill && itemBase->hasConnectors();
++ }
++
++ if (Board::isBoard(itemBase)) {
++ traceMenuThing.boardCount++;
++ if (itemBase->isSelected()) traceMenuThing.boardSelectedCount++;
++ }
++
++ switch (itemBase->itemType()) {
++ case ModelPart::Jumper:
++ traceMenuThing.jiEnabled = true;
++ if (itemBase->isSelected()) {
++ traceMenuThing.exEnabled = true;
++ if (qobject_cast<JumperItem *>(itemBase->layerKinChief())->getAutoroutable()) {
++ traceMenuThing.exChecked = false;
++ }
++ }
++ break;
++ case ModelPart::Via:
++ traceMenuThing.viaEnabled = true;
++ if (itemBase->isSelected()) {
++ traceMenuThing.exEnabled = true;
++ if (qobject_cast<Via *>(itemBase->layerKinChief())->getAutoroutable()) {
++ traceMenuThing.exChecked = false;
++ }
++ }
++ break;
++ case ModelPart::CopperFill:
++ traceMenuThing.gfrEnabled = true;
++ default:
++ break;
++ }
++}
++
++void MainWindow::zoomIn() {
++ m_zoomSlider->zoomIn();
++}
++
++void MainWindow::zoomOut() {
++ m_zoomSlider->zoomOut();
++}
++
++void MainWindow::fitInWindow() {
++ if (m_currentGraphicsView == NULL) return;
++
++ double newZoom = m_currentGraphicsView->fitInWindow();
++ m_zoomSlider->setValue(newZoom);
++}
++
++void MainWindow::hundredPercentSize() {
++ m_currentGraphicsView->absoluteZoom(100);
++ m_zoomSlider->setValue(100);
++}
++
++void MainWindow::actualSize() {
++ QMessageBox::information(this, tr("Actual Size"),
++ tr("It doesn't seem to be possible to automatically determine the actual physical size of the monitor, so "
++ "'actual size' as currently implemented is only a guess. "
++ "Your best bet would be to drag out a ruler part, then place a real (physical) ruler on top and zoom until they match up."
++ ));
++
++
++ int dpi = this->physicalDpiX();
++ int l = this->logicalDpiX();
++
++ DebugDialog::debug(QString("actual size %1 %2").arg(dpi).arg(l));
++
++ // remember the parameter to the next two functions is a percent
++ m_currentGraphicsView->absoluteZoom(dpi * 100.0 / GraphicsUtils::SVGDPI);
++ m_zoomSlider->setValue(dpi * 100.0 / GraphicsUtils::SVGDPI);
++}
++
++void MainWindow::showBreadboardView() {
++ setCurrentTabIndex(0);
++}
++
++void MainWindow::showSchematicView() {
++ setCurrentTabIndex(1);
++}
++
++void MainWindow::showPCBView() {
++ setCurrentTabIndex(2);
++}
++
++void MainWindow::showProgramView() {
++ setCurrentTabIndex(3);
++}
++
++void MainWindow::setCurrentView(ViewLayer::ViewID viewID)
++{
++ if (viewID == ViewLayer::BreadboardView) showBreadboardView();
++ else if (viewID == ViewLayer::SchematicView) showSchematicView();
++ else if (viewID == ViewLayer::PCBView) showPCBView();
++}
++
++void MainWindow::showPartsBinIconView() {
++ if (m_binManager) m_binManager->toIconView();
++}
++
++void MainWindow::showPartsBinListView() {
++ if (m_binManager) m_binManager->toListView();
++}
++
++void MainWindow::openHelp() {
++ QDesktopServices::openUrl(QString("http://fritzing.org/learning/"));
++}
++
++void MainWindow::openDonate() {
++ QDesktopServices::openUrl(QString("http://fritzing.org/shop/donations/"));
++}
++
++void MainWindow::openExamples() {
++ QDesktopServices::openUrl(QString("http://fritzing.org/projects/"));
++}
++
++void MainWindow::openPartsReference() {
++ QDesktopServices::openUrl(QString("http://fritzing.org/parts/"));
++}
++
++void MainWindow::visitFritzingDotOrg() {
++ QDesktopServices::openUrl(QString("http://www.fritzing.org"));
++}
++
++void MainWindow::reportBug() {
++ QDesktopServices::openUrl(QString("http://code.google.com/p/fritzing/issues"));
++}
++
++void MainWindow::partsEditorHelp() {
++ QDir * dir = FolderUtils::getApplicationSubFolder("help");
++ QString path = dir->absoluteFilePath("parts_editor_help.html");
++ if (QFileInfo(path).exists()) {
++ QDesktopServices::openUrl(QString("file:///%1").arg(path));
++ }
++}
++
++
++
++void MainWindow::enableDebug() {
++ DebugDialog::setEnabled(m_enableDebugAct->isChecked());
++ if (!m_windowMenu->actions().contains(m_toggleDebuggerOutputAct)) {
++ m_windowMenu->insertSeparator(m_windowMenuSeparator);
++ m_windowMenu->insertAction(m_windowMenuSeparator, m_toggleDebuggerOutputAct);
++ toggleDebuggerOutput(true);
++ }
++}
++
++
++void MainWindow::openNewPartsEditor(PaletteItem * paletteItem)
++{
++ foreach (QWidget *widget, QApplication::topLevelWidgets()) {
++ PEMainWindow * peMainWindow = qobject_cast<PEMainWindow *>(widget);
++ if (peMainWindow == NULL) continue;
++
++ if (peMainWindow->editsModuleID(paletteItem->moduleID())) {
++ if (peMainWindow->isMinimized()) peMainWindow->showNormal();
++ else peMainWindow->show();
++ peMainWindow->raise();
++ return;
++ }
++ }
++
++ PEMainWindow * peMainWindow = new PEMainWindow(m_referenceModel, NULL);
++ peMainWindow->init(m_referenceModel, NULL);
++ if (peMainWindow->setInitialItem(paletteItem)) {
++ peMainWindow->show();
++ peMainWindow->raise();
++ connect(peMainWindow, SIGNAL(addToMyPartsSignal(ModelPart *)), this, SLOT(addToMyParts(ModelPart *)));
++ }
++ else {
++ delete peMainWindow;
++ }
++}
++
++void MainWindow::getPartsEditorNewAnd(ItemBase * fromItem)
++{
++ PaletteItem * paletteItem = qobject_cast<PaletteItem *>(fromItem);
++ if (paletteItem == NULL) return;
++
++ openNewPartsEditor(paletteItem);
++}
++
++void MainWindow::openInPartsEditorNew() {
++ if (m_currentGraphicsView == NULL) return;
++
++ PaletteItem *selectedPart = m_currentGraphicsView->getSelectedPart();
++ openNewPartsEditor(selectedPart);
++}
++
++void MainWindow::createNewSketch() {
++ MainWindow* mw = newMainWindow(m_referenceModel, "", true, true);
++ mw->move(x()+CascadeFactorX,y()+CascadeFactorY);
++ ProcessEventBlocker::processEvents();
++
++ mw->addDefaultParts();
++ mw->show();
++ mw->hideTempPartsBin();
++
++ QSettings settings;
++ settings.remove("lastOpenSketch");
++ mw->clearFileProgressDialog();
++}
++
++void MainWindow::minimize() {
++ this->showMinimized();
++}
++
++void MainWindow::toggleToolbar(bool toggle) {
++ Q_UNUSED(toggle);
++ /*if(toggle) {
++ this->m_fileToolBar->show();
++ this->m_editToolBar->show();
++ } else {
++ this->m_fileToolBar->hide();
++ this->m_editToolBar->hide();
++ }*/
++}
++
++void MainWindow::togglePartLibrary(bool toggle) {
++ if(toggle) {
++ m_binManager->show();
++ } else {
++ m_binManager->hide();
++ }
++}
++
++void MainWindow::toggleInfo(bool toggle) {
++ if(toggle) {
++ ((QDockWidget*)m_infoView->parent())->show();
++ } else {
++ ((QDockWidget*)m_infoView->parent())->hide();
++ }
++}
++
++void MainWindow::toggleNavigator(bool toggle) {
++ if(toggle) {
++ ((QDockWidget*)m_miniViewContainerBreadboard->parent())->show();
++ ((QDockWidget*)m_miniViewContainerSchematic->parent())->show();
++ ((QDockWidget*)m_miniViewContainerPCB->parent())->show();
++ } else {
++ ((QDockWidget*)m_miniViewContainerBreadboard->parent())->hide();
++ ((QDockWidget*)m_miniViewContainerSchematic->parent())->hide();
++ ((QDockWidget*)m_miniViewContainerPCB->parent())->hide();
++ }
++}
++
++void MainWindow::toggleUndoHistory(bool toggle) {
++ if(toggle) {
++ ((QDockWidget*)m_undoView->parent())->show();
++ } else {
++ ((QDockWidget*)m_undoView->parent())->hide();
++ }
++}
++
++void MainWindow::toggleDebuggerOutput(bool toggle) {
++ if (toggle) {
++ DebugDialog::showDebug();
++ }
++ else
++ {
++ }
++}
++
++void MainWindow::updateWindowMenu() {
++ m_toggleDebuggerOutputAct->setChecked(DebugDialog::visible());
++ foreach (QWidget * widget, QApplication::topLevelWidgets()) {
++ MainWindow * mainWindow = qobject_cast<MainWindow *>(widget);
++ if (mainWindow == NULL) continue;
++
++ QAction *action = mainWindow->raiseWindowAction();
++ if (action != NULL) {
++ action->setChecked(action == m_raiseWindowAct);
++ m_windowMenu->addAction(action);
++ }
++ }
++}
++
++void MainWindow::pageSetup() {
++ notYetImplemented(tr("Page Setup"));
++}
++
++void MainWindow::notYetImplemented(QString action) {
++ QMessageBox::warning(this, tr("Fritzing"),
++ tr("Sorry, \"%1\" has not been implemented yet").arg(action));
++}
++
++void MainWindow::rotateIncCW() {
++ if (m_currentGraphicsView == NULL) return;
++
++ if (m_rotate45cwAct->isEnabled()) {
++ rotate45cw();
++ }
++ else if (m_rotate90cwAct->isEnabled()) {
++ rotate90cw();
++ }
++}
++
++void MainWindow::rotateIncCWRubberBand() {
++ if (m_currentGraphicsView == NULL) return;
++
++ if (m_rotate45cwAct->isEnabled()) {
++ m_currentGraphicsView->rotateX(45, true, NULL);
++ }
++ else if (m_rotate90cwAct->isEnabled()) {
++ m_currentGraphicsView->rotateX(90, true, NULL);
++ }
++}
++
++void MainWindow::rotateIncCCW() {
++ if (m_currentGraphicsView == NULL) return;
++
++ if (m_rotate45ccwAct->isEnabled()) {
++ m_currentGraphicsView->rotateX(315, true, NULL);
++ }
++ else if (m_rotate90ccwAct->isEnabled()) {
++ m_currentGraphicsView->rotateX(270, true, NULL);
++ }
++}
++
++void MainWindow::rotateIncCCWRubberBand() {
++ if (m_currentGraphicsView == NULL) return;
++
++ if (m_rotate45ccwAct->isEnabled()) {
++ m_currentGraphicsView->rotateX(315, true, NULL);
++ }
++ else if (m_rotate90ccwAct->isEnabled()) {
++ m_currentGraphicsView->rotateX(270, true, NULL);
++ }
++}
++
++void MainWindow::rotate90cw() {
++ if (m_currentGraphicsView == NULL) return;
++
++ m_currentGraphicsView->rotateX(90, false, NULL);
++}
++
++void MainWindow::rotate90ccw() {
++ if (m_currentGraphicsView == NULL) return;
++
++ m_currentGraphicsView->rotateX(270, false, NULL);
++}
++
++void MainWindow::rotate45ccw() {
++ if (m_currentGraphicsView == NULL) return;
++
++ m_currentGraphicsView->rotateX(315, false, NULL);
++}
++
++void MainWindow::rotate45cw() {
++ if (m_currentGraphicsView == NULL) return;
++
++ m_currentGraphicsView->rotateX(45, false, NULL);
++}
++
++void MainWindow::rotate180() {
++ if (m_currentGraphicsView == NULL) return;
++
++ m_currentGraphicsView->rotateX(180, false, NULL);
++}
++
++void MainWindow::flipHorizontal() {
++ m_currentGraphicsView->flipX(Qt::Horizontal, false);
++}
++
++void MainWindow::flipVertical() {
++ m_currentGraphicsView->flipX(Qt::Vertical, false);
++}
++
++void MainWindow::sendToBack() {
++ if (m_currentGraphicsView == NULL) return;
++
++ m_currentGraphicsView->sendToBack();
++}
++
++void MainWindow::sendBackward() {
++ if (m_currentGraphicsView == NULL) return;
++
++ m_currentGraphicsView->sendBackward();
++}
++
++void MainWindow::bringForward() {
++ if (m_currentGraphicsView == NULL) return;
++
++ m_currentGraphicsView->bringForward();
++}
++
++void MainWindow::bringToFront() {
++ if (m_currentGraphicsView == NULL) return;
++
++ m_currentGraphicsView->bringToFront();
++}
++
++void MainWindow::alignLeft() {
++ if (m_currentGraphicsView == NULL) return;
++
++ m_currentGraphicsView->alignItems(Qt::AlignLeft);
++}
++
++void MainWindow::alignVerticalCenter() {
++ if (m_currentGraphicsView == NULL) return;
++
++ m_currentGraphicsView->alignItems(Qt::AlignVCenter);
++}
++
++void MainWindow::alignRight() {
++ if (m_currentGraphicsView == NULL) return;
++
++ m_currentGraphicsView->alignItems(Qt::AlignRight);
++}
++
++void MainWindow::alignTop() {
++ if (m_currentGraphicsView == NULL) return;
++
++ m_currentGraphicsView->alignItems(Qt::AlignTop);
++}
++
++void MainWindow::alignHorizontalCenter() {
++ if (m_currentGraphicsView == NULL) return;
++
++ m_currentGraphicsView->alignItems(Qt::AlignHCenter);
++}
++
++void MainWindow::alignBottom() {
++ if (m_currentGraphicsView == NULL) return;
++
++ m_currentGraphicsView->alignItems(Qt::AlignBottom);
++}
++
++void MainWindow::showAllLayers() {
++ if (m_currentGraphicsView == NULL) return;
++
++ m_currentGraphicsView->setAllLayersVisible(true);
++ updateLayerMenu();
++}
++
++void MainWindow::hideAllLayers() {
++ if (m_currentGraphicsView == NULL) return;
++
++ m_currentGraphicsView->setAllLayersVisible(false);
++ updateLayerMenu();
++}
++
++void MainWindow::openURL() {
++ QAction *action = qobject_cast<QAction *>(sender());
++ if (action == NULL) return;
++
++ QString href = action->data().toString();
++ if (href.isEmpty()) return;
++
++ QDesktopServices::openUrl(href);
++}
++
++void MainWindow::openRecentOrExampleFile() {
++ QAction *action = qobject_cast<QAction *>(sender());
++ if (action) {
++ QString filename = action->data().toString();
++ if (alreadyOpen(filename)) {
++ return;
++ }
++
++ if (!QFileInfo(filename).exists()) {
++ QMessageBox::warning(NULL, tr("Fritzing"), tr("File '%1' not found").arg(filename));
++ return;
++ }
++
++ MainWindow* mw = newMainWindow(m_referenceModel, action->data().toString(), true, true);
++ bool readOnly = m_openExampleActions.contains(action->text());
++ mw->setReadOnly(readOnly);
++ mw->loadWhich(filename,!readOnly,!readOnly,"");
++ mw->clearFileProgressDialog();
++ closeIfEmptySketch(mw);
++ }
++}
++
++void MainWindow::removeActionsStartingAt(QMenu * menu, int start) {
++ QList<QAction*> actions = menu->actions();
++
++ if(start == 0) {
++ menu->clear();
++ } else {
++ for(int i=start; i < actions.size(); i++) {
++ menu->removeAction(actions.at(i));
++ }
++ }
++}
++
++void MainWindow::hideShowProgramMenu() {
++ bool show = (m_currentGraphicsView != NULL);
++ if (m_viewMenu) m_viewMenu->menuAction()->setVisible(show);
++ if (m_partMenu) m_partMenu->menuAction()->setVisible(show);
++ if (m_fileMenu) m_fileMenu->menuAction()->setVisible(show);
++ if (m_editMenu) m_editMenu->menuAction()->setVisible(show);
++ if (m_programView) m_programView->showMenus(!show);
++}
++
++void MainWindow::hideShowTraceMenu() {
++ if (m_pcbTraceMenu) m_pcbTraceMenu->menuAction()->setVisible(m_currentGraphicsView == m_pcbGraphicsView);
++ if (m_schematicTraceMenu) m_schematicTraceMenu->menuAction()->setVisible(m_currentGraphicsView == m_schematicGraphicsView);
++ if (m_breadboardTraceMenu) m_breadboardTraceMenu->menuAction()->setVisible(m_currentGraphicsView == m_breadboardGraphicsView);
++}
++
++void MainWindow::createTraceMenuActions() {
++ m_newAutorouteAct = new QAction(tr("Autoroute"), this);
++ m_newAutorouteAct->setStatusTip(tr("Autoroute connections..."));
++ m_newAutorouteAct->setShortcut(tr("Shift+Ctrl+A"));
++ connect(m_newAutorouteAct, SIGNAL(triggered()), this, SLOT(newAutoroute()));
++
++ createOrderFabAct();
++ createActiveLayerActions();
++
++ QAction * traceAct = new QAction(tr("&Create trace from ratsnest"), this);
++ traceAct->setStatusTip(tr("Create a trace from the ratsnest line"));
++ m_createTraceWireAct = new WireAction(traceAct);
++ connect(m_createTraceWireAct, SIGNAL(triggered()), this, SLOT(createTrace()));
++ traceAct = new QAction(tr("&Create wire from ratsnest"), this);
++ traceAct->setStatusTip(tr("Create a wire from the ratsnest line"));
++ m_createWireWireAct = new WireAction(traceAct);
++ connect(m_createWireWireAct, SIGNAL(triggered()), this, SLOT(createTrace()));
++
++ m_excludeFromAutorouteAct = new QAction(tr("Do not autoroute"), this);
++ m_excludeFromAutorouteAct->setStatusTip(tr("When autorouting, do not rip up this trace wire, via, or jumper item"));
++ connect(m_excludeFromAutorouteAct, SIGNAL(triggered()), this, SLOT(excludeFromAutoroute()));
++ m_excludeFromAutorouteAct->setCheckable(true);
++ m_excludeFromAutorouteWireAct = new WireAction(m_excludeFromAutorouteAct);
++ connect(m_excludeFromAutorouteWireAct, SIGNAL(triggered()), this, SLOT(excludeFromAutoroute()));
++
++ m_changeTraceLayerAct = new QAction(tr("Move to other side of the board"), this);
++ m_changeTraceLayerAct->setStatusTip(tr("Move selected traces to the other side of the board (note: the 'first' trace will be moved and the rest will follow to the same side)"));
++ connect(m_changeTraceLayerAct, SIGNAL(triggered()), this, SLOT(changeTraceLayer()));
++ m_changeTraceLayerWireAct = new WireAction(m_changeTraceLayerAct);
++ connect(m_changeTraceLayerWireAct, SIGNAL(triggered()), this, SLOT(changeTraceLayer()));
++
++ m_showUnroutedAct = new QAction(tr("Show unrouted"), this);
++ m_showUnroutedAct->setStatusTip(tr("Highlight all unrouted connectors"));
++ connect(m_showUnroutedAct, SIGNAL(triggered()), this, SLOT(showUnrouted()));
++
++ m_selectAllTracesAct = new QAction(tr("Select All Traces"), this);
++ m_selectAllTracesAct->setStatusTip(tr("Select all trace wires"));
++ connect(m_selectAllTracesAct, SIGNAL(triggered()), this, SLOT(selectAllTraces()));
++
++ m_selectAllWiresAct = new QAction(tr("Select All Wires"), this);
++ m_selectAllWiresAct->setStatusTip(tr("Select all wires"));
++ connect(m_selectAllWiresAct, SIGNAL(triggered()), this, SLOT(selectAllTraces()));
++
++ m_selectAllCopperFillAct = new QAction(tr("Select All CopperFill"), this);
++ m_selectAllCopperFillAct->setStatusTip(tr("Select all copper fill items"));
++ connect(m_selectAllCopperFillAct, SIGNAL(triggered()), this, SLOT(selectAllCopperFill()));
++
++ m_updateRoutingStatusAct = new QAction(tr("Force Update Routing Status and Ratsnests"), this);
++ m_updateRoutingStatusAct->setStatusTip(tr("Recalculate routing status and ratsnest wires (in case the auto-update isn't working correctly)"));
++ connect(m_updateRoutingStatusAct, SIGNAL(triggered()), this, SLOT(updateRoutingStatus()));
++
++ m_selectAllExcludedTracesAct = new QAction(tr("Select All \"Don't Autoroute\" Traces"), this);
++ m_selectAllExcludedTracesAct->setStatusTip(tr("Select all trace wires excluded from autorouting"));
++ connect(m_selectAllExcludedTracesAct, SIGNAL(triggered()), this, SLOT(selectAllExcludedTraces()));
++
++ m_selectAllIncludedTracesAct = new QAction(tr("Select All Autoroutable Traces"), this);
++ m_selectAllIncludedTracesAct->setStatusTip(tr("Select all trace wires that can be changed during autorouting"));
++ connect(m_selectAllIncludedTracesAct, SIGNAL(triggered()), this, SLOT(selectAllIncludedTraces()));
++
++ m_selectAllJumperItemsAct = new QAction(tr("Select All Jumpers"), this);
++ m_selectAllJumperItemsAct->setStatusTip(tr("Select all jumper item parts"));
++ connect(m_selectAllJumperItemsAct, SIGNAL(triggered()), this, SLOT(selectAllJumperItems()));
++
++ m_selectAllViasAct = new QAction(tr("Select All Vias"), this);
++ m_selectAllViasAct->setStatusTip(tr("Select all via parts"));
++ connect(m_selectAllViasAct, SIGNAL(triggered()), this, SLOT(selectAllVias()));
++
++ m_tidyWiresAct = new QAction(tr("Tidy Wires"), this);
++ m_tidyWiresAct->setStatusTip(tr("Tidy selected wires"));
++ connect(m_tidyWiresAct, SIGNAL(triggered()), this, SLOT(tidyWires()));
++
++ m_groundFillAct = new QAction(tr("Ground Fill"), this);
++ m_groundFillAct->setStatusTip(tr("Fill empty regions of the copper layer--fill will include all traces connected to a GROUND"));
++ connect(m_groundFillAct, SIGNAL(triggered()), this, SLOT(groundFill()));
++
++ m_copperFillAct = new QAction(tr("Copper Fill"), this);
++ m_copperFillAct->setStatusTip(tr("Fill empty regions of the copper layer--not including traces connected to a GROUND"));
++ connect(m_copperFillAct, SIGNAL(triggered()), this, SLOT(copperFill()));
++
++ m_removeGroundFillAct = new QAction(tr("Remove Copper Fill"), this);
++ m_removeGroundFillAct->setStatusTip(tr("Remove the copper fill"));
++ connect(m_removeGroundFillAct, SIGNAL(triggered()), this, SLOT(removeGroundFill()));
++
++ m_setGroundFillSeedsAct = new QAction(tr("Choose Ground Fill Seed(s)..."), this);
++ m_setGroundFillSeedsAct->setStatusTip(tr("Fill empty regions of the copper layer--fill will include all traces connected to the seeds"));
++ connect(m_setGroundFillSeedsAct, SIGNAL(triggered()), this, SLOT(setGroundFillSeeds()));
++
++ m_setOneGroundFillSeedAct = new ConnectorItemAction(tr("Set Ground Fill Seed"), this);
++ m_setOneGroundFillSeedAct->setStatusTip(tr("Treat this connector and its connections as a 'ground' during ground fill."));
++ m_setOneGroundFillSeedAct->setCheckable(true);
++ connect(m_setOneGroundFillSeedAct, SIGNAL(triggered()), this, SLOT(setOneGroundFillSeed()));
++
++ m_clearGroundFillSeedsAct = new ConnectorItemAction(tr("Clear Ground Fill Seeds"), this);
++ m_clearGroundFillSeedsAct->setStatusTip(tr("Clear ground fill seeds--enable copper fill only."));
++ connect(m_clearGroundFillSeedsAct, SIGNAL(triggered()), this, SLOT(clearGroundFillSeeds()));
++
++ m_setGroundFillKeepoutAct = new QAction(tr("Set Ground Fill Keepout..."), this);
++ m_setGroundFillKeepoutAct->setStatusTip(tr("Set the minimum distance between ground fill and traces or connectors"));
++ connect(m_setGroundFillKeepoutAct, SIGNAL(triggered()), this, SLOT(setGroundFillKeepout()));
++
++
++
++ m_newDesignRulesCheckAct = new QAction(tr("Design Rules Check (DRC)"), this);
++ m_newDesignRulesCheckAct->setStatusTip(tr("Highlights any parts that are too close together for safe board production"));
++ m_newDesignRulesCheckAct->setShortcut(tr("Shift+Ctrl+D"));
++ connect(m_newDesignRulesCheckAct, SIGNAL(triggered()), this, SLOT(newDesignRulesCheck()));
++
++ m_checkLoadedTracesAct = new QAction(tr("Check Loaded Traces"), this);
++ m_checkLoadedTracesAct->setStatusTip(tr("Select any traces where the screen location doesn't match the actual location. Only needed for sketches autorouted with version 0.7.10 or earlier"));
++ connect(m_checkLoadedTracesAct, SIGNAL(triggered()), this, SLOT(checkLoadedTraces()));
++
++ m_autorouterSettingsAct = new QAction(tr("Autorouter/DRC settings..."), this);
++ m_autorouterSettingsAct->setStatusTip(tr("Set autorouting parameters including keepout..."));
++ connect(m_autorouterSettingsAct, SIGNAL(triggered()), this, SLOT(autorouterSettings()));
++
++ m_fabQuoteAct = new QAction(tr("Fritzing Fab Quote..."), this);
++ m_fabQuoteAct->setStatusTip(tr("How much would it could to produce a PCB from this sketch with Fritzing Fab"));
++ connect(m_fabQuoteAct, SIGNAL(triggered()), this, SLOT(fabQuote()));
++
++}
++
++void MainWindow::createActiveLayerActions() {
++
++ m_viewFromBelowToggleAct = new QAction(tr("View from below"), this);
++ m_viewFromBelowToggleAct->setStatusTip(tr("View the PCB from the bottom layers upwards"));
++ m_viewFromBelowToggleAct->setCheckable(true);
++ m_viewFromBelowToggleAct->setChecked(false);
++ connect(m_viewFromBelowToggleAct, SIGNAL(triggered()), this, SLOT(setViewFromBelowToggle()));
++
++ m_viewFromBelowAct = new QAction(tr("View from below"), this);
++ m_viewFromBelowAct->setStatusTip(tr("View the PCB from the bottom layers upwards"));
++ connect(m_viewFromBelowAct, SIGNAL(triggered()), this, SLOT(setViewFromBelow()));
++
++ m_viewFromAboveAct = new QAction(tr("View from above"), this);
++ m_viewFromAboveAct->setStatusTip(tr("View the PCB from the top layers downwards"));
++ connect(m_viewFromAboveAct, SIGNAL(triggered()), this, SLOT(setViewFromAbove()));
++
++ m_activeLayerBothAct = new QAction(tr("Set both copper layers clickable"), this);
++ m_activeLayerBothAct->setStatusTip(tr("Set both copper layers clickable"));
++ m_activeLayerBothAct->setShortcut(tr("Shift+Ctrl+3"));
++ connect(m_activeLayerBothAct, SIGNAL(triggered()), this, SLOT(activeLayerBoth()));
++
++ m_activeLayerTopAct = new QAction(tr("Set copper top layer clickable"), this);
++ m_activeLayerTopAct->setStatusTip(tr("Set copper top layer clickable"));
++ m_activeLayerTopAct->setShortcut(tr("Shift+Ctrl+2"));
++ connect(m_activeLayerTopAct, SIGNAL(triggered()), this, SLOT(activeLayerTop()));
++
++ m_activeLayerBottomAct = new QAction(tr("Set copper bottom layer clickable"), this);
++ m_activeLayerBottomAct->setStatusTip(tr("Set copper bottom layer clickable"));
++ m_activeLayerBottomAct->setShortcut(tr("Shift+Ctrl+1"));
++ connect(m_activeLayerBottomAct, SIGNAL(triggered()), this, SLOT(activeLayerBottom()));
++}
++
++void MainWindow::activeLayerBoth() {
++ PCBSketchWidget * pcbSketchWidget = qobject_cast<PCBSketchWidget *>(m_currentGraphicsView);
++ if (pcbSketchWidget == NULL) return;
++
++ pcbSketchWidget->setLayerActive(ViewLayer::Copper1, true);
++ pcbSketchWidget->setLayerActive(ViewLayer::Copper0, true);
++ pcbSketchWidget->setLayerActive(ViewLayer::Silkscreen0, true);
++ pcbSketchWidget->setLayerActive(ViewLayer::Silkscreen1, true);
++ AutoCloseMessageBox::showMessage(this, tr("Copper Top and Copper Bottom layers are both active"));
++ updateActiveLayerButtons();
++}
++
++void MainWindow::activeLayerTop() {
++ PCBSketchWidget * pcbSketchWidget = qobject_cast<PCBSketchWidget *>(m_currentGraphicsView);
++ if (pcbSketchWidget == NULL) return;
++
++ pcbSketchWidget->setLayerActive(ViewLayer::Copper1, true);
++ pcbSketchWidget->setLayerActive(ViewLayer::Silkscreen1, true);
++ pcbSketchWidget->setLayerActive(ViewLayer::Copper0, false);
++ pcbSketchWidget->setLayerActive(ViewLayer::Silkscreen0, false);
++ AutoCloseMessageBox::showMessage(this, tr("Copper Top layer is active"));
++ updateActiveLayerButtons();
++}
++
++void MainWindow::activeLayerBottom() {
++ PCBSketchWidget * pcbSketchWidget = qobject_cast<PCBSketchWidget *>(m_currentGraphicsView);
++ if (pcbSketchWidget == NULL) return;
++
++ pcbSketchWidget->setLayerActive(ViewLayer::Copper1, false);
++ pcbSketchWidget->setLayerActive(ViewLayer::Silkscreen1, false);
++ pcbSketchWidget->setLayerActive(ViewLayer::Copper0, true);
++ pcbSketchWidget->setLayerActive(ViewLayer::Silkscreen0, true);
++ AutoCloseMessageBox::showMessage(this, tr("Copper Bottom layer is active"));
++ updateActiveLayerButtons();
++}
++
++void MainWindow::toggleActiveLayer()
++{
++ PCBSketchWidget * pcbSketchWidget = qobject_cast<PCBSketchWidget *>(m_currentGraphicsView);
++ if (pcbSketchWidget == NULL) return;
++
++ int index = activeLayerIndex();
++ switch (index) {
++ case 0:
++ activeLayerBottom();
++ return;
++ case 1:
++ activeLayerTop();
++ return;
++ case 2:
++ activeLayerBoth();
++ return;
++ default:
++ return;
++ }
++}
++
++
++void MainWindow::createOrderFabAct() {
++ if (m_orderFabAct != NULL) return;
++
++ m_orderFabAct = new QAction(tr("Order a PCB..."), this);
++ m_orderFabAct->setStatusTip(tr("Order a PCB created from your sketch--from fabulous Fritzing Fab"));
++ connect(m_orderFabAct, SIGNAL(triggered()), this, SLOT(orderFab()));
++}
++
++
++void MainWindow::newAutoroute() {
++ PCBSketchWidget * pcbSketchWidget = qobject_cast<PCBSketchWidget *>(m_currentGraphicsView);
++ if (pcbSketchWidget == NULL) return;
++
++ ItemBase * board = NULL;
++ if (pcbSketchWidget->autorouteTypePCB()) {
++ int boardCount;
++ board = pcbSketchWidget->findSelectedBoard(boardCount);
++ if (boardCount == 0) {
++ QMessageBox::critical(this, tr("Fritzing"),
++ tr("Your sketch does not have a board yet! Please add a PCB in order to use the autorouter."));
++ return;
++ }
++ if (board == NULL) {
++ QMessageBox::critical(this, tr("Fritzing"),
++ tr("Please select the board you want to autoroute. The autorouter can only handle one board at a time."));
++ return;
++ }
++ }
++
++ dynamic_cast<SketchAreaWidget *>(pcbSketchWidget->parent())->routingStatusLabel()->setText(tr("Autorouting..."));
++
++ bool copper0Active = pcbSketchWidget->layerIsActive(ViewLayer::Copper0);
++ bool copper1Active = pcbSketchWidget->layerIsActive(ViewLayer::Copper1);
++
++ AutorouteProgressDialog progress(tr("Autorouting Progress..."), true, true, true, true, pcbSketchWidget, this);
++ progress.setModal(true);
++ progress.show();
++ QRect pr = progress.frameGeometry();
++ QRect wr = this->frameGeometry();
++ progress.move(wr.right() - pr.width(), pr.top());
++
++
++ pcbSketchWidget->scene()->clearSelection();
++ pcbSketchWidget->setIgnoreSelectionChangeEvents(true);
++ Autorouter * autorouter = NULL;
++ autorouter = new MazeRouter(pcbSketchWidget, board, true);
++
++ connect(autorouter, SIGNAL(wantTopVisible()), this, SLOT(activeLayerTop()), Qt::DirectConnection);
++ connect(autorouter, SIGNAL(wantBottomVisible()), this, SLOT(activeLayerBottom()), Qt::DirectConnection);
++ connect(autorouter, SIGNAL(wantBothVisible()), this, SLOT(activeLayerBoth()), Qt::DirectConnection);
++
++ connect(&progress, SIGNAL(cancel()), autorouter, SLOT(cancel()), Qt::DirectConnection);
++ connect(&progress, SIGNAL(skip()), autorouter, SLOT(cancelTrace()), Qt::DirectConnection);
++ connect(&progress, SIGNAL(stop()), autorouter, SLOT(stopTracing()), Qt::DirectConnection);
++ connect(&progress, SIGNAL(best()), autorouter, SLOT(useBest()), Qt::DirectConnection);
++ connect(&progress, SIGNAL(spinChange(int)), autorouter, SLOT(setMaxCycles(int)), Qt::DirectConnection);
++
++ connect(autorouter, SIGNAL(setMaximumProgress(int)), &progress, SLOT(setMaximum(int)), Qt::DirectConnection);
++ connect(autorouter, SIGNAL(setProgressValue(int)), &progress, SLOT(setValue(int)), Qt::DirectConnection);
++ connect(autorouter, SIGNAL(setProgressMessage(const QString &)), &progress, SLOT(setMessage(const QString &)));
++ connect(autorouter, SIGNAL(setProgressMessage2(const QString &)), &progress, SLOT(setMessage2(const QString &)));
++ connect(autorouter, SIGNAL(setCycleMessage(const QString &)), &progress, SLOT(setSpinLabel(const QString &)));
++ connect(autorouter, SIGNAL(setCycleCount(int)), &progress, SLOT(setSpinValue(int)));
++ connect(autorouter, SIGNAL(disableButtons()), &progress, SLOT(disableButtons()));
++
++ ProcessEventBlocker::processEvents();
++ ProcessEventBlocker::block();
++
++ autorouter->start();
++ pcbSketchWidget->setIgnoreSelectionChangeEvents(false);
++
++ delete autorouter;
++
++ pcbSketchWidget->setLayerActive(ViewLayer::Copper1, copper1Active);
++ pcbSketchWidget->setLayerActive(ViewLayer::Silkscreen1, copper1Active);
++ pcbSketchWidget->setLayerActive(ViewLayer::Copper0, copper0Active);
++ pcbSketchWidget->setLayerActive(ViewLayer::Silkscreen0, copper0Active);
++ updateActiveLayerButtons();
++
++ ProcessEventBlocker::unblock();
++}
++
++void MainWindow::createTrace() {
++ m_currentGraphicsView->createTrace(retrieveWire(), true);
++}
++
++void MainWindow::excludeFromAutoroute() {
++ Wire * wire = retrieveWire();
++ PCBSketchWidget * pcbSketchWidget = qobject_cast<PCBSketchWidget *>(m_currentGraphicsView);
++ if (pcbSketchWidget == NULL) return;
++
++ pcbSketchWidget->excludeFromAutoroute(wire == NULL ? m_excludeFromAutorouteAct->isChecked() : m_excludeFromAutorouteWireAct->isChecked());
++}
++
++void MainWindow::selectAllTraces()
++{
++ m_currentGraphicsView->selectAllWires(m_currentGraphicsView->getTraceFlag());
++}
++
++void MainWindow::updateRoutingStatus() {
++ RoutingStatus routingStatus;
++ routingStatus.zero();
++ m_currentGraphicsView->updateRoutingStatus(NULL, routingStatus, true);
++}
++
++void MainWindow::selectAllExcludedTraces() {
++ PCBSketchWidget * pcbSketchWidget = qobject_cast<PCBSketchWidget *>(m_currentGraphicsView);
++ if (pcbSketchWidget == NULL) return;
++
++ pcbSketchWidget->selectAllExcludedTraces();
++}
++
++void MainWindow::selectAllIncludedTraces() {
++ PCBSketchWidget * pcbSketchWidget = qobject_cast<PCBSketchWidget *>(m_currentGraphicsView);
++ if (pcbSketchWidget == NULL) return;
++
++ pcbSketchWidget->selectAllIncludedTraces();
++}
++
++void MainWindow::selectAllJumperItems() {
++ m_pcbGraphicsView->selectAllItemType(ModelPart::Jumper, tr("jumpers"));
++}
++
++void MainWindow::selectAllCopperFill() {
++ m_pcbGraphicsView->selectAllItemType(ModelPart::CopperFill, tr("copperfill"));
++}
++
++void MainWindow::selectAllVias() {
++ m_pcbGraphicsView->selectAllItemType(ModelPart::Via, tr("vias"));
++}
++
++void MainWindow::notClosableForAWhile() {
++ m_dontClose = true;
++
++ QTimer::singleShot(500, this, SLOT(ensureClosable()));
++}
++
++void MainWindow::ensureClosable() {
++ m_dontClose = false;
++}
++
++void MainWindow::showPartLabels() {
++ if (m_currentGraphicsView == NULL) return;
++
++ m_currentGraphicsView->showPartLabels(m_showPartLabelAct->data().toBool());
++}
++
++void MainWindow::addNote() {
++ if (m_currentGraphicsView == NULL) return;
++
++ ViewGeometry vg;
++ vg.setRect(0, 0, Note::initialMinWidth, Note::initialMinHeight);
++ QPointF tl = m_currentGraphicsView->mapToScene(QPoint(0, 0));
++ QSizeF vpSize = m_currentGraphicsView->viewport()->size();
++ tl.setX(tl.x() + ((vpSize.width() - Note::initialMinWidth) / 2.0));
++ tl.setY(tl.y() + ((vpSize.height() - Note::initialMinHeight) / 2.0));
++ vg.setLoc(tl);
++
++ QUndoCommand * parentCommand = new QUndoCommand(tr("Add Note"));
++ m_currentGraphicsView->stackSelectionState(false, parentCommand);
++ m_currentGraphicsView->scene()->clearSelection();
++ new AddItemCommand(m_currentGraphicsView, BaseCommand::SingleView, ModuleIDNames::NoteModuleIDName, m_currentGraphicsView->defaultViewLayerPlacement(NULL), vg, ItemBase::getNextID(), false, -1, parentCommand);
++ m_undoStack->push(parentCommand);
++}
++
++bool MainWindow::alreadyOpen(const QString & fileName) {
++ foreach (QWidget * widget, QApplication::topLevelWidgets()) {
++ MainWindow * mainWindow = qobject_cast<MainWindow *>(widget);
++ if (mainWindow == NULL) continue;
++
++ // don't load two copies of the same file
++ if (mainWindow->fileName().compare(fileName) == 0) {
++ mainWindow->raise();
++ return true;
++ }
++ }
++
++ return false;
++}
++
++void MainWindow::enableAddBendpointAct(QGraphicsItem * graphicsItem) {
++ m_addBendpointAct->setEnabled(false);
++ m_convertToViaAct->setEnabled(false);
++ m_flattenCurveAct->setEnabled(false);
++
++ Wire * wire = dynamic_cast<Wire *>(graphicsItem);
++ if (wire == NULL) return;
++ if (wire->getRatsnest()) return;
++
++ m_flattenCurveAct->setEnabled(wire->isCurved());
++
++ BendpointAction * bendpointAction = qobject_cast<BendpointAction *>(m_addBendpointAct);
++ BendpointAction * convertToViaAction = qobject_cast<BendpointAction *>(m_convertToViaAct);
++ FGraphicsScene * scene = qobject_cast<FGraphicsScene *>(graphicsItem->scene());
++ if (scene != NULL) {
++ bendpointAction->setLastLocation(scene->lastContextMenuPos());
++ convertToViaAction->setLastLocation(scene->lastContextMenuPos());
++ }
++
++ bool enabled = false;
++ bool ctvEnabled = false;
++ if (m_currentGraphicsView->lastHoverEnterConnectorItem()) {
++ bendpointAction->setText(tr("Remove Bendpoint"));
++ bendpointAction->setLastHoverEnterConnectorItem(m_currentGraphicsView->lastHoverEnterConnectorItem());
++ bendpointAction->setLastHoverEnterItem(NULL);
++ convertToViaAction->setLastHoverEnterConnectorItem(m_currentGraphicsView->lastHoverEnterConnectorItem());
++ convertToViaAction->setLastHoverEnterItem(NULL);
++ ctvEnabled = enabled = true;
++ }
++ else if (m_currentGraphicsView->lastHoverEnterItem()) {
++ bendpointAction->setText(tr("Add Bendpoint"));
++ bendpointAction->setLastHoverEnterItem(m_currentGraphicsView->lastHoverEnterItem());
++ bendpointAction->setLastHoverEnterConnectorItem(NULL);
++ convertToViaAction->setLastHoverEnterItem(NULL);
++ convertToViaAction->setLastHoverEnterConnectorItem(NULL);
++ enabled = true;
++ }
++ else {
++ bendpointAction->setLastHoverEnterItem(NULL);
++ bendpointAction->setLastHoverEnterConnectorItem(NULL);
++ convertToViaAction->setLastHoverEnterItem(NULL);
++ convertToViaAction->setLastHoverEnterConnectorItem(NULL);
++ }
++
++ m_addBendpointAct->setEnabled(enabled);
++ m_convertToViaAct->setEnabled(ctvEnabled && (m_currentGraphicsView == m_pcbGraphicsView));
++}
++
++void MainWindow::addBendpoint()
++{
++ BendpointAction * bendpointAction = qobject_cast<BendpointAction *>(m_addBendpointAct);
++
++ m_currentGraphicsView->addBendpoint(bendpointAction->lastHoverEnterItem(),
++ bendpointAction->lastHoverEnterConnectorItem(),
++ bendpointAction->lastLocation());
++}
++
++void MainWindow::convertToVia()
++{
++ BendpointAction * bendpointAction = qobject_cast<BendpointAction *>(m_convertToViaAct);
++
++ m_pcbGraphicsView->convertToVia(bendpointAction->lastHoverEnterConnectorItem());
++}
++
++void MainWindow::convertToBendpoint()
++{
++ m_pcbGraphicsView->convertToBendpoint();
++}
++
++void MainWindow::flattenCurve()
++{
++ BendpointAction * bendpointAction = qobject_cast<BendpointAction *>(m_addBendpointAct);
++
++ m_currentGraphicsView->flattenCurve(bendpointAction->lastHoverEnterItem(),
++ bendpointAction->lastHoverEnterConnectorItem(),
++ bendpointAction->lastLocation());
++}
++
++
++void MainWindow::importFilesFromPrevInstall() {
++ QString prevInstallPath = QFileDialog::getExistingDirectory(
++ this,
++ tr("Please choose the previous Fritzing folder..."),
++ QDir::homePath(),
++ QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
++ if(prevInstallPath.isNull()) return;
++ if(!QFileInfo(prevInstallPath+"/parts").exists()) {
++ QMessageBox::critical(
++ this, QObject::tr("Fritzing"),
++ tr("The folder \"%1\" isn't a Fritzing installation folder").arg(prevInstallPath));
++ return;
++ }
++
++ QString userDataPath = FolderUtils::getUserDataStorePath();
++
++ // replicate dirs
++ QStringList foldersToCopy = FolderUtils::getUserDataStoreFolders();
++ foreach(QString folder, foldersToCopy) {
++ FolderUtils::replicateDir(QDir(prevInstallPath+folder), QDir(userDataPath+folder));
++ }
++
++ // cleanup old bins
++ QDir dataStoreBins(userDataPath);
++ dataStoreBins.cd("bins");
++ QStringList binsToRemove;
++ binsToRemove
++ << "allParts.fzb" << "artreenoBin.fzb"
++ << "E6SetBin.fzb" << "pin_headers.fzb";
++ foreach(QString binToRemove, binsToRemove) {
++ dataStoreBins.remove(binToRemove);
++ }
++
++ // make sure to add the old my_parts.fzp to the folder
++ QString myPartsBinRelPath = "/bins/my_parts.fzb";
++ QFile myOldPartsBinFile(prevInstallPath+myPartsBinRelPath);
++ if(myOldPartsBinFile.exists()) {
++ QDateTime now = QDateTime::currentDateTime();
++ QString newNamePostfix = QString("__imported_on__%1.fzb").arg(now.toString("yyyy-MM-dd_hh-mm-ss"));
++ myOldPartsBinFile.copy(userDataPath+myPartsBinRelPath.replace(".fzb",newNamePostfix));
++ }
++
++ QMessageBox::information(
++ this, QObject::tr("Fritzing"),
++ tr("You will have to restart Fritzing in order to use the imported parts"));
++}
++
++void MainWindow::tidyWires() {
++ m_currentGraphicsView->tidyWires();
++}
++
++void MainWindow::copperFill() {
++ groundFillAux2(false);
++}
++
++void MainWindow::groundFill()
++{
++ groundFillAux2(true);
++}
++
++void MainWindow::groundFillAux2(bool fillGroundTraces) {
++
++ if (m_pcbGraphicsView->layerIsActive(ViewLayer::Copper0) && m_pcbGraphicsView->layerIsActive(ViewLayer::Copper1)) {
++ groundFillAux(fillGroundTraces, ViewLayer::UnknownLayer);
++ }
++ else if (m_pcbGraphicsView->layerIsActive(ViewLayer::Copper0)) {
++ groundFillAux(fillGroundTraces, ViewLayer::GroundPlane0);
++ }
++ else {
++ groundFillAux(fillGroundTraces, ViewLayer::GroundPlane1);
++ }
++}
++
++void MainWindow::copperFill(ViewLayer::ViewLayerID viewLayerID) {
++ groundFillAux(false, viewLayerID);
++}
++
++void MainWindow::groundFill(ViewLayer::ViewLayerID viewLayerID)
++{
++ groundFillAux(true, viewLayerID);
++}
++
++void MainWindow::groundFillAux(bool fillGroundTraces, ViewLayer::ViewLayerID viewLayerID)
++{
++ // TODO:
++ // what about leftover temp files from crashes?
++ // clear ground plane when anything changes
++ // some polygons can be combined
++ // remove old ground plane modules from paletteModel and database
++
++ if (m_pcbGraphicsView == NULL) return;
++
++ int boardCount;
++ ItemBase * board = m_pcbGraphicsView->findSelectedBoard(boardCount);
++ if (boardCount == 0) {
++ QMessageBox::critical(this, tr("Fritzing"),
++ tr("Your sketch does not have a board yet! Please add a PCB in order to use ground or copper fill."));
++ return;
++ }
++ if (board == NULL) {
++ QMessageBox::critical(this, tr("Fritzing"),
++ tr("Please select a PCB--copper fill only works for one board at a time."));
++ return;
++ }
++
++
++ FileProgressDialog fileProgress(tr("Generating %1 fill...").arg(fillGroundTraces ? tr("ground") : tr("copper")), 0, this);
++ fileProgress.setIndeterminate();
++ QUndoCommand * parentCommand = new QUndoCommand(fillGroundTraces ? tr("Ground Fill") : tr("Copper Fill"));
++ m_pcbGraphicsView->blockUI(true);
++ removeGroundFill(viewLayerID, parentCommand);
++ if (m_pcbGraphicsView->groundFill(fillGroundTraces, viewLayerID, parentCommand)) {
++ m_undoStack->push(parentCommand);
++ }
++ else {
++ delete parentCommand;
++ }
++ m_pcbGraphicsView->blockUI(false);
++}
++
++void MainWindow::removeGroundFill() {
++ removeGroundFill(ViewLayer::UnknownLayer, NULL);
++}
++
++void MainWindow::removeGroundFill(ViewLayer::ViewLayerID viewLayerID, QUndoCommand * parentCommand) {
++ QSet<ItemBase *> toDelete;
++ int boardCount;
++ ItemBase * board = m_pcbGraphicsView->findSelectedBoard(boardCount);
++ if (boardCount == 0) {
++ QMessageBox::critical(this, tr("Fritzing"),
++ tr("Your sketch does not have a board yet! Please add a PCB in order to remove copper fill."));
++ return;
++ }
++ if (board == NULL) {
++ QMessageBox::critical(this, tr("Fritzing"),
++ tr("Please select a PCB--ground fill operations only work on a one board at a time."));
++ return;
++ }
++
++ foreach (QGraphicsItem * item, m_pcbGraphicsView->scene()->collidingItems(board)) {
++ ItemBase * itemBase = dynamic_cast<ItemBase *>(item);
++ if (itemBase == NULL) continue;
++ if (itemBase->moveLock()) continue;
++ if (!isGroundFill(itemBase)) continue;
++
++ if (viewLayerID != ViewLayer::UnknownLayer) {
++ if (itemBase->viewLayerID() != viewLayerID) continue;
++ }
++
++ toDelete.insert(itemBase->layerKinChief());
++ }
++
++ if (toDelete.count() == 0) return;
++
++
++ bool push = (parentCommand == NULL);
++
++ if (push) {
++ parentCommand = new QUndoCommand(tr("Remove copper fill"));
++ }
++
++ new CleanUpWiresCommand(m_pcbGraphicsView, CleanUpWiresCommand::UndoOnly, parentCommand);
++ new CleanUpRatsnestsCommand(m_pcbGraphicsView, CleanUpWiresCommand::UndoOnly, parentCommand);
++
++ m_pcbGraphicsView->deleteMiddle(toDelete, parentCommand);
++ foreach (ItemBase * itemBase, toDelete) {
++ itemBase->saveGeometry();
++ m_pcbGraphicsView->makeDeleteItemCommand(itemBase, BaseCommand::CrossView, parentCommand);
++ }
++
++ new CleanUpRatsnestsCommand(m_pcbGraphicsView, CleanUpWiresCommand::RedoOnly, parentCommand);
++ new CleanUpWiresCommand(m_pcbGraphicsView, CleanUpWiresCommand::RedoOnly, parentCommand);
++
++ if (push) {
++ m_undoStack->push(parentCommand);
++ }
++ else {
++ foreach (ItemBase * itemBase, toDelete) {
++ // move them out of the way because they are about to be deleted anyhow
++ itemBase->setPos(itemBase->pos() + board->sceneBoundingRect().bottomRight() + QPointF(10000, 10000));
++ }
++ }
++}
++
++bool MainWindow::isGroundFill(ItemBase * itemBase) {
++ return (itemBase->itemType() == ModelPart::CopperFill);
++}
++
++
++QMenu *MainWindow::breadboardItemMenu() {
++ QMenu *menu = new QMenu(QObject::tr("Part"), this);
++ menu->addMenu(m_rotateMenu);
++ return viewItemMenuAux(menu);
++}
++
++QMenu *MainWindow::schematicItemMenu() {
++ QMenu *menu = new QMenu(QObject::tr("Part"), this);
++ menu->addMenu(m_rotateMenu);
++ menu->addAction(m_flipHorizontalAct);
++ menu->addAction(m_flipVerticalAct);
++ return viewItemMenuAux(menu);
++}
++
++QMenu *MainWindow::pcbItemMenu() {
++ QMenu *menu = new QMenu(QObject::tr("Part"), this);
++ menu->addMenu(m_rotateMenu);
++ menu = viewItemMenuAux(menu);
++ menu->addAction(m_hidePartSilkscreenAct);
++ menu->addSeparator();
++ menu->addAction(m_convertToBendpointAct);
++ m_convertToBendpointSeparator = menu->addSeparator();
++ menu->addAction(m_setOneGroundFillSeedAct);
++ menu->addAction(m_clearGroundFillSeedsAct);
++ return menu;
++}
++
++QMenu *MainWindow::breadboardWireMenu() {
++ QMenu *menu = new QMenu(QObject::tr("Wire"), this);
++ menu->addMenu(m_zOrderWireMenu);
++ menu->addSeparator();
++ m_breadboardWireColorMenu = menu->addMenu(tr("&Wire Color"));
++ foreach(QString colorName, Wire::colorNames) {
++ QString colorValue = Wire::colorTrans.value(colorName);
++ QAction * action = new QAction(colorName, this);
++ m_breadboardWireColorMenu->addAction(action);
++ action->setData(colorValue);
++ action->setCheckable(true);
++ action->setChecked(false);
++ connect(action, SIGNAL(triggered(bool)), this, SLOT(changeWireColor(bool)));
++ }
++ menu->addAction(m_createWireWireAct);
++ menu->addSeparator();
++ menu->addAction(m_deleteWireAct);
++ menu->addAction(m_deleteWireMinusAct);
++ menu->addSeparator();
++ menu->addAction(m_addBendpointAct);
++ menu->addAction(m_flattenCurveAct);
++
++#ifndef QT_NO_DEBUG
++ menu->addSeparator();
++ menu->addAction(m_infoViewOnHoverAction);
++#endif
++
++ connect( menu, SIGNAL(aboutToShow()), this, SLOT(updateWireMenu()));
++
++ return menu;
++}
++
++QMenu *MainWindow::pcbWireMenu() {
++ QMenu *menu = new QMenu(QObject::tr("Wire"), this);
++ menu->addMenu(m_zOrderWireMenu);
++ menu->addSeparator();
++ menu->addAction(m_changeTraceLayerWireAct);
++ menu->addAction(m_createTraceWireAct);
++ menu->addAction(m_excludeFromAutorouteWireAct);
++ menu->addSeparator();
++ menu->addAction(m_deleteWireAct);
++ menu->addAction(m_deleteWireMinusAct);
++ menu->addSeparator();
++ menu->addAction(m_addBendpointAct);
++ menu->addAction(m_convertToViaAct);
++ menu->addAction(m_flattenCurveAct);
++
++#ifndef QT_NO_DEBUG
++ menu->addSeparator();
++ menu->addAction(m_infoViewOnHoverAction);
++#endif
++
++ connect(menu, SIGNAL(aboutToShow()), this, SLOT(updateWireMenu()));
++
++ return menu;
++}
++
++QMenu *MainWindow::schematicWireMenu() {
++ QMenu *menu = new QMenu(QObject::tr("Wire"), this);
++ menu->addMenu(m_zOrderWireMenu);
++ menu->addSeparator();
++ m_schematicWireColorMenu = menu->addMenu(tr("&Wire Color"));
++ foreach(QString colorName, Wire::colorNames) {
++ QString colorValue = Wire::colorTrans.value(colorName);
++ if (colorValue == "white") continue;
++ QAction * action = new QAction(colorName, this);
++ m_schematicWireColorMenu->addAction(action);
++ action->setData(colorValue);
++ action->setCheckable(true);
++ connect(action, SIGNAL(triggered(bool)), this, SLOT(changeWireColor(bool)));
++ }
++ menu->addAction(m_createTraceWireAct);
++ menu->addAction(m_excludeFromAutorouteWireAct);
++ menu->addSeparator();
++ menu->addAction(m_deleteWireAct);
++ menu->addAction(m_deleteWireMinusAct);
++ menu->addSeparator();
++ menu->addAction(m_addBendpointAct);
++#ifndef QT_NO_DEBUG
++ menu->addSeparator();
++ menu->addAction(m_infoViewOnHoverAction);
++#endif
++
++ connect( menu, SIGNAL(aboutToShow()), this, SLOT(updateWireMenu()));
++
++ return menu;
++}
++
++QMenu *MainWindow::viewItemMenuAux(QMenu* menu) {
++ menu->addMenu(m_zOrderMenu);
++ menu->addAction(m_moveLockAct);
++ menu->addAction(m_stickyAct);
++ menu->addSeparator();
++ menu->addAction(m_copyAct);
++ menu->addAction(m_duplicateAct);
++ menu->addAction(m_deleteAct);
++ menu->addAction(m_deleteMinusAct);
++#ifndef QT_NO_DEBUG
++ menu->addSeparator();
++ menu->addAction(m_disconnectAllAct);
++#endif
++ menu->addSeparator();
++ menu->addAction(m_openInPartsEditorNewAct);
++ menu->addMenu(m_addToBinMenu);
++ menu->addSeparator();
++ menu->addAction(m_showPartLabelAct);
++#ifndef QT_NO_DEBUG
++ menu->addSeparator();
++ menu->addAction(m_infoViewOnHoverAction);
++ menu->addAction(m_exportNormalizedSvgAction);
++ menu->addAction(m_exportNormalizedFlattenedSvgAction);
++#endif
++
++ connect(
++ menu,
++ SIGNAL(aboutToShow()),
++ this,
++ SLOT(updatePartMenu())
++ );
++
++ return menu;
++}
++
++void MainWindow::changeWireColor(bool checked) {
++ if (checked == false) {
++ // choosing the same color again (assuming this action can only apply to a single wire at a time)
++ return;
++ }
++
++ QAction * action = qobject_cast<QAction *>(sender());
++ if (action == NULL) return;
++
++ QString colorName = action->data().toString();
++ if (colorName.isEmpty()) return;
++
++ m_currentGraphicsView->changeWireColor(colorName);
++}
++
++void MainWindow::startSaveInstancesSlot(const QString & fileName, ModelPart *, QXmlStreamWriter & streamWriter) {
++ Q_UNUSED(fileName);
++
++ if (m_backingUp) {
++ streamWriter.writeTextElement("originalFileName", m_fwFilename);
++ }
++
++ if (m_pcbGraphicsView) {
++ QList<ItemBase *> boards = m_pcbGraphicsView->findBoard();
++ if (boards.count()) {
++ streamWriter.writeStartElement("boards");
++ foreach (ItemBase * board, boards) {
++ QRectF r = board->sceneBoundingRect();
++ double w = 2.54 * r.width() / GraphicsUtils::SVGDPI;
++ double h = 2.54 * r.height() / GraphicsUtils::SVGDPI;
++ streamWriter.writeStartElement("board");
++ streamWriter.writeAttribute("moduleId", QString("%1").arg(board->moduleID()));
++ streamWriter.writeAttribute("title", QString("%1").arg(board->title()));
++ streamWriter.writeAttribute("instance", QString("%1").arg(board->instanceTitle()));
++ streamWriter.writeAttribute("width", QString("%1cm").arg(w));
++ streamWriter.writeAttribute("height", QString("%1cm").arg(h));
++ streamWriter.writeEndElement();
++ }
++ streamWriter.writeEndElement();
++ }
++ }
++
++ if (m_linkedProgramFiles.count() > 0) {
++ streamWriter.writeStartElement("programs");
++ QSettings settings;
++ streamWriter.writeAttribute("pid", settings.value("pid").toString());
++ foreach (LinkedFile * linkedFile, m_linkedProgramFiles) {
++ streamWriter.writeStartElement("program");
++ streamWriter.writeAttribute("language", linkedFile->language);
++ streamWriter.writeAttribute("programmer", linkedFile->programmer);
++ streamWriter.writeCharacters(linkedFile->linkedFilename);
++ streamWriter.writeEndElement();
++ }
++ streamWriter.writeEndElement();
++ }
++
++ streamWriter.writeStartElement("views");
++ QList<SketchWidget *> views;
++ views << m_breadboardGraphicsView << m_schematicGraphicsView << m_pcbGraphicsView;
++ foreach (SketchWidget * sketchWidget, views) {
++ streamWriter.writeStartElement("view");
++ streamWriter.writeAttribute("name", ViewLayer::viewIDXmlName(sketchWidget->viewID()));
++ streamWriter.writeAttribute("backgroundColor", sketchWidget->background().name());
++ streamWriter.writeAttribute("gridSize", sketchWidget->gridSizeText());
++ streamWriter.writeAttribute("showGrid", sketchWidget->showingGrid() ? "1" : "0");
++ streamWriter.writeAttribute("alignToGrid", sketchWidget->alignedToGrid() ? "1" : "0");
++ streamWriter.writeAttribute("viewFromBelow", sketchWidget->viewFromBelow() ? "1" : "0");
++ QHash<QString, QString> autorouterSettings = sketchWidget->getAutorouterSettings();
++ foreach (QString key, autorouterSettings.keys()) {
++ streamWriter.writeAttribute(key, autorouterSettings.value(key));
++ }
++ streamWriter.writeEndElement();
++ }
++ streamWriter.writeEndElement();
++}
++
++void MainWindow::obsoleteSMDOrientationSlot() {
++ m_obsoleteSMDOrientation = true;
++}
++
++void MainWindow::loadedRootSlot(const QString & fname, ModelBase *, QDomElement & root) {
++ if (root.isNull()) return;
++
++ QDomElement programs = root.firstChildElement("programs");
++ if (programs.isNull()) return;
++
++ QString thatPid = programs.attribute("pid");
++ QSettings settings;
++ QString thisPid = settings.value("pid").toString();
++ bool sameMachine = thatPid.isEmpty() || (!thisPid.isEmpty() && (thatPid.compare(thisPid) == 0));
++ QFileInfo fileInfo(fname);
++ QDir dir = fileInfo.absoluteDir();
++
++ QDomElement program = programs.firstChildElement("program");
++ while (!program.isNull()) {
++ bool obsolete = false;
++ bool inBundle = false;
++ QString text;
++ TextUtils::findText(program, text);
++ if (!text.isEmpty()) {
++ QString language = program.attribute("language");
++ QString programmer = program.attribute("programmer");
++ QString path;
++ if (thatPid.isEmpty()) {
++ // pre 0.7.0 relative path
++ QFileInfo newFileInfo(text);
++ dir.cd(newFileInfo.dir().path());
++ path = dir.absoluteFilePath(newFileInfo.fileName());
++ obsolete = true;
++ }
++ else {
++ path = text;
++ }
++
++ LinkedFile * linkedFile = new LinkedFile;
++ QFileInfo info(path);
++ if (!(sameMachine && info.exists())) {
++ inBundle = true;
++ path = dir.absoluteFilePath(info.fileName());
++ }
++ linkedFile->linkedFilename = path;
++ linkedFile->language = language;
++ linkedFile->programmer = programmer;
++ linkedFile->fileFlags = LinkedFile::NoFlag;
++ if (sameMachine) linkedFile->fileFlags |= LinkedFile::SameMachineFlag;
++ if (obsolete) linkedFile->fileFlags |= LinkedFile::ObsoleteFlag;
++ if (inBundle) linkedFile->fileFlags |= LinkedFile::InBundleFlag;
++ if (this->m_readOnly) linkedFile->fileFlags |= LinkedFile::ReadOnlyFlag;
++
++ m_linkedProgramFiles.append(linkedFile);
++ }
++ program = program.nextSiblingElement("program");
++ }
++
++}
++
++void MainWindow::loadedViewsSlot(ModelBase *, QDomElement & views) {
++ if (views.isNull()) return;
++
++ QDomElement view = views.firstChildElement("view");
++ while (!view.isNull()) {
++ QString name = view.attribute("name");
++ ViewLayer::ViewID viewID = ViewLayer::idFromXmlName(name);
++ SketchWidget * sketchWidget = NULL;
++ switch (viewID) {
++ case ViewLayer::BreadboardView:
++ sketchWidget = m_breadboardGraphicsView;
++ break;
++ case ViewLayer::SchematicView:
++ sketchWidget = m_schematicGraphicsView;
++ break;
++ case ViewLayer::PCBView:
++ sketchWidget = m_pcbGraphicsView;
++ break;
++ default:
++ break;
++ }
++
++ if (sketchWidget) {
++ QString colorName = view.attribute("backgroundColor", "");
++ QString gridSizeText = view.attribute("gridSize", "");
++ QString alignToGridText = view.attribute("alignToGrid", "");
++ QString showGridText = view.attribute("showGrid", "");
++ QString viewFromBelowText = view.attribute("viewFromBelow", "");
++
++ QHash<QString, QString> autorouterSettings;
++ QDomNamedNodeMap map = view.attributes();
++ for (int m = 0; m < map.count(); m++) {
++ QDomNode node = map.item(m);
++ autorouterSettings.insert(node.nodeName(), node.nodeValue());
++ }
++ sketchWidget->setAutorouterSettings(autorouterSettings);
++
++ QColor color;
++ color.setNamedColor(colorName);
++
++ bool redraw = false;
++ if (color.isValid()) {
++ sketchWidget->setBackground(color);
++ redraw = true;
++ }
++ if (!alignToGridText.isEmpty()) {
++ sketchWidget->alignToGrid(alignToGridText.compare("1") == 0);
++ }
++ if (!showGridText.isEmpty()) {
++ sketchWidget->showGrid(showGridText.compare("1") == 0);
++ redraw = 1;
++ }
++ if (!gridSizeText.isEmpty()) {
++ sketchWidget->setGridSize(gridSizeText);
++ redraw = true;
++ }
++
++ if (!viewFromBelowText.isEmpty()) {
++ sketchWidget->setViewFromBelow(viewFromBelowText.compare("1") == 0);
++ redraw = 1;
++ }
++
++ if (redraw) sketchWidget->invalidateScene();
++ }
++
++ view = view.nextSiblingElement("view");
++ }
++}
++
++void MainWindow::disconnectAll() {
++ m_currentGraphicsView->disconnectAll();
++}
++
++bool MainWindow::externalProcess(QString & name, QString & path, QStringList & args) {
++ emit externalProcessSignal(name, path, args);
++
++ if (path.isEmpty()) return false;
++
++ if (name.isEmpty()) {
++ name = tr("Launch %1...").arg(path);
++ }
++
++ return true;
++}
++
++void MainWindow::launchExternalProcess() {
++ QString name;
++ QString path;
++ QStringList args;
++ if (!externalProcess(name, path, args)) return;
++
++ args.append("-sketch");
++ args.append(fileName());
++ m_externalProcessOutput.clear();
++
++ QFileInfo f = QFileInfo(path);
++ QProcess * process = new QProcess(this);
++ process->setWorkingDirectory(f.dir().absolutePath());
++ process->setProcessChannelMode(QProcess::MergedChannels);
++ process->setReadChannel(QProcess::StandardOutput);
++
++ connect(process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError)));
++ connect(process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(processFinished(int, QProcess::ExitStatus)));
++ connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(processReadyRead()));
++ connect(process, SIGNAL(stateChanged(QProcess::ProcessState)), this, SLOT(processStateChanged(QProcess::ProcessState)));
++
++ process->start(path, args);
++}
++
++
++void MainWindow::processError(QProcess::ProcessError processError) {
++ DebugDialog::debug(QString("process error %1").arg(processError));
++}
++
++void MainWindow::processFinished(int exitCode, QProcess::ExitStatus exitStatus) {
++ DebugDialog::debug(QString("process finished %1 %2").arg(exitCode).arg(exitStatus));
++
++ QString name, path;
++ QStringList args;
++ externalProcess(name, path, args);
++ QMessageBox::information(this, name, QString(m_externalProcessOutput));
++
++ sender()->deleteLater();
++}
++
++void MainWindow::processReadyRead() {
++ QByteArray byteArray = qobject_cast<QProcess *>(sender())->readAllStandardOutput();
++ m_externalProcessOutput.append(byteArray);
++
++ DebugDialog::debug(byteArray.data());
++}
++
++void MainWindow::processStateChanged(QProcess::ProcessState newState) {
++ switch(newState) {
++ case QProcess::Running:
++ DebugDialog::debug(QString("process running"));
++ break;
++ case QProcess::Starting:
++ DebugDialog::debug(QString("process starting"));
++ break;
++ case QProcess::NotRunning:
++ DebugDialog::debug(QString("process not running"));
++ break;
++ }
++}
++
++void MainWindow::shareOnline() {
++ QDesktopServices::openUrl(QString("http://fritzing.org/projects/create/"));
++}
++
++
++void MainWindow::selectAllObsolete() {
++ selectAllObsolete(true);
++}
++
++void MainWindow::selectAllObsolete(bool displayFeedback) {
++ int obs = m_currentGraphicsView->selectAllObsolete();
++ if (!displayFeedback) return;
++
++ if (obs <= 0) {
++ QMessageBox::information(this, tr("Fritzing"), tr("No outdated parts found.\nAll your parts are up-to-date.") );
++ }
++ else {
++ QMessageBox::StandardButton answer = QMessageBox::question(
++ this,
++ tr("Outdated parts"),
++ tr("Found %n outdated parts. Do you want to update them now?", "", obs),
++ QMessageBox::Yes | QMessageBox::No,
++ QMessageBox::Yes
++ );
++ // TODO: make button texts translatable
++ if (answer == QMessageBox::Yes) {
++ swapObsolete();
++ }
++ }
++}
++
++ModelPart * MainWindow::findReplacedby(ModelPart * originalModelPart) {
++ ModelPart * newModelPart = originalModelPart;
++ while (true) {
++ QString newModuleID = newModelPart->replacedby();
++ if (newModuleID.isEmpty()) {
++ return ((newModelPart == originalModelPart) ? NULL : newModelPart);
++ }
++
++ ModelPart * tempModelPart = this->m_referenceModel->retrieveModelPart(newModuleID);
++ if (tempModelPart == NULL) {
++ // something's screwy
++ return NULL;
++ }
++
++ newModelPart = tempModelPart;
++ }
++}
++
++void MainWindow::swapObsolete() {
++ swapObsolete(true);
++}
++
++void MainWindow::swapObsolete(bool displayFeedback) {
++
++ QSet<ItemBase *> itemBases;
++ foreach (QGraphicsItem * item, m_currentGraphicsView->scene()->selectedItems()) {
++ ItemBase * itemBase = dynamic_cast<ItemBase *>(item);
++ if (itemBase == NULL) continue;
++ if (!itemBase->isObsolete()) continue;
++
++ itemBase = itemBase->layerKinChief();
++ itemBases.insert(itemBase);
++ }
++
++ if (itemBases.count() <= 0) return;
++
++ QUndoCommand* parentCommand = new QUndoCommand();
++ int count = 0;
++ QMap<QString, QString> propsMap;
++ foreach (ItemBase * itemBase, itemBases) {
++ ModelPart * newModelPart = findReplacedby(itemBase->modelPart());
++ if (newModelPart == NULL) {
++ QMessageBox::information(
++ this,
++ tr("Sorry!"),
++ tr( "unable to find replacement for %1.\n").arg(itemBase->title())
++ );
++ continue;
++ }
++
++ count++;
++ long newID = swapSelectedAuxAux(itemBase, newModelPart->moduleID(), itemBase->viewLayerPlacement(), propsMap, parentCommand);
++ if (itemBase->modelPart()) {
++ // special case for swapping old resistors.
++ QString resistance = itemBase->modelPart()->properties().value("resistance", "");
++ if (!resistance.isEmpty()) {
++ QChar r = resistance.at(resistance.length() - 1);
++ ushort ohm = r.unicode();
++ if (ohm == 8486) {
++ // ends with the ohm symbol
++ resistance.chop(1);
++ }
++ }
++ QString footprint = itemBase->modelPart()->properties().value("footprint", "");
++ if (!resistance.isEmpty() && !footprint.isEmpty()) {
++ new SetResistanceCommand(m_currentGraphicsView, newID, resistance, resistance, footprint, footprint, parentCommand);
++ }
++
++ // special case for swapping LEDs
++ if (newModelPart->moduleID().contains(ModuleIDNames::ColorLEDModuleIDName)) {
++ QString oldColor = itemBase->modelPart()->properties().value("color");
++ QString newColor;
++ if (oldColor.contains("red", Qt::CaseInsensitive)) {
++ newColor = "Red (633nm)";
++ }
++ else if (oldColor.contains("blue", Qt::CaseInsensitive)) {
++ newColor = "Blue (430nm)";
++ }
++ else if (oldColor.contains("yellow", Qt::CaseInsensitive)) {
++ newColor = "Yellow (585nm)";
++ }
++ else if (oldColor.contains("green", Qt::CaseInsensitive)) {
++ newColor = "Green (555nm)";
++ }
++ else if (oldColor.contains("white", Qt::CaseInsensitive)) {
++ newColor = "White (4500K)";
++ }
++
++ if (newColor.length() > 0) {
++ new SetPropCommand(m_currentGraphicsView, newID, "color", newColor, newColor, true, parentCommand);
++ }
++ }
++
++ }
++ }
++
++
++ if (count == 0) {
++ delete parentCommand;
++ }
++ else {
++ parentCommand->setText(tr("Update %1 part(s)", "").arg(count));
++ m_undoStack->push(parentCommand);
++ }
++
++ if (displayFeedback) {
++ QMessageBox::information(this, tr("Fritzing"), tr("Successfully updated %1 part(s).\n"
++ "Please check all views for potential side-effects.").arg(count) );
++ }
++ DebugDialog::debug(QString("updated %1 obsolete in %2").arg(count).arg(m_fwFilename));
++}
++
++void MainWindow::throwFakeException() {
++ throw "fake exception";
++}
++
++void MainWindow::alignToGrid() {
++ if (m_currentGraphicsView == NULL) return;
++
++ m_currentGraphicsView->alignToGrid(m_alignToGridAct->isChecked());
++ setWindowModified(true);
++}
++
++void MainWindow::showGrid() {
++ if (m_currentGraphicsView == NULL) return;
++
++ m_currentGraphicsView->showGrid(m_showGridAct->isChecked());
++ setWindowModified(true);
++}
++
++void MainWindow::setGridSize()
++{
++ GridSizeThing gridSizeThing(m_currentGraphicsView->viewName(),
++ m_currentGraphicsView->getShortName(),
++ m_currentGraphicsView->defaultGridSizeInches(),
++ m_currentGraphicsView->gridSizeText());
++
++ GridSizeDialog dialog(&gridSizeThing);
++ dialog.setWindowTitle(QObject::tr("Set Grid Size"));
++
++ QVBoxLayout * vLayout = new QVBoxLayout(&dialog);
++
++ vLayout->addWidget(createGridSizeForm(&gridSizeThing));
++
++ QDialogButtonBox * buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
++ buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("Cancel"));
++ buttonBox->button(QDialogButtonBox::Ok)->setText(tr("OK"));
++
++ connect(buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept()));
++ connect(buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject()));
++
++ vLayout->addWidget(buttonBox);
++
++ int result = dialog.exec();
++
++ if (result == QDialog::Accepted) {
++ QString units = (gridSizeThing.inButton->isChecked() ? "in" : "mm");
++ m_currentGraphicsView->setGridSize(gridSizeThing.lineEdit->text() + units);
++ setWindowModified(true);
++ }
++}
++
++QWidget * MainWindow::createGridSizeForm(GridSizeThing * gridSizeThing)
++{
++ QGroupBox * over = new QGroupBox("", this);
++
++ QVBoxLayout * vLayout = new QVBoxLayout();
++
++ QLabel * explain = new QLabel(tr("Set the grid size for %1.").arg(gridSizeThing->viewName));
++ vLayout->addWidget(explain);
++
++ QGroupBox * groupBox = new QGroupBox(this);
++
++ QHBoxLayout * hLayout = new QHBoxLayout();
++
++ QLabel * label = new QLabel(tr("Grid Size:"));
++ hLayout->addWidget(label);
++
++ gridSizeThing->lineEdit = new QLineEdit();
++
++ gridSizeThing->lineEdit->setFixedWidth(45);
++
++ gridSizeThing->validator = new QDoubleValidator(gridSizeThing->lineEdit);
++ gridSizeThing->validator->setRange(0.001, 1.0, 3);
++ gridSizeThing->validator->setNotation(QDoubleValidator::StandardNotation);
++ gridSizeThing->lineEdit->setValidator(gridSizeThing->validator);
++
++ hLayout->addWidget(gridSizeThing->lineEdit);
++
++ gridSizeThing->inButton = new QRadioButton(tr("in"), this);
++ hLayout->addWidget(gridSizeThing->inButton);
++
++ gridSizeThing->mmButton = new QRadioButton(tr("mm"), this);
++ hLayout->addWidget(gridSizeThing->mmButton);
++
++ groupBox->setLayout(hLayout);
++
++ vLayout->addWidget(groupBox);
++ vLayout->addSpacing(5);
++
++ QPushButton * pushButton = new QPushButton(this);
++ pushButton->setText(tr("Restore Default"));
++ pushButton->setMaximumWidth(115);
++ vLayout->addWidget(pushButton);
++ vLayout->addSpacing(10);
++
++ over->setLayout(vLayout);
++
++ if (gridSizeThing->gridSizeText.length() <= 2) {
++ gridSizeThing->inButton->setChecked(true);
++ gridSizeThing->lineEdit->setText(QString::number(gridSizeThing->defaultGridSize));
++ }
++ else {
++ if (gridSizeThing->gridSizeText.endsWith("mm")) {
++ gridSizeThing->mmButton->setChecked(true);
++ gridSizeThing->validator->setTop(25.4);
++ }
++ else {
++ gridSizeThing->inButton->setChecked(true);
++ }
++ QString szString = gridSizeThing->gridSizeText;
++ szString.chop(2);
++ gridSizeThing->lineEdit->setText(szString);
++ }
++
++ connect(gridSizeThing->inButton, SIGNAL(clicked(bool)), this, SLOT(gridUnits(bool)));
++ connect(pushButton, SIGNAL(clicked()), this, SLOT(restoreDefaultGrid()));
++ connect(gridSizeThing->mmButton, SIGNAL(clicked(bool)), this, SLOT(gridUnits(bool)));
++
++ return over;
++}
++
++
++void MainWindow::openProgramWindow() {
++ if (m_programWindow) {
++ m_programWindow->setVisible(true);
++ m_programWindow->raise();
++ return;
++ }
++
++ m_programWindow = new ProgramWindow();
++ connect(m_programWindow, SIGNAL(linkToProgramFile(const QString &, const QString &, const QString &, bool, bool)),
++ this, SLOT(linkToProgramFile(const QString &, const QString &, const QString &, bool, bool)));
++ connect(m_programWindow, SIGNAL(changeActivationSignal(bool, QWidget *)), qApp, SLOT(changeActivation(bool, QWidget *)), Qt::DirectConnection);
++ connect(m_programWindow, SIGNAL(destroyed(QObject *)), qApp, SLOT(topLevelWidgetDestroyed(QObject *)));
++
++ QFileInfo fileInfo(m_fwFilename);
++ m_programWindow->setup();
++ m_programWindow->linkFiles(m_linkedProgramFiles, fileInfo.absoluteDir().absolutePath());
++ m_programWindow->setVisible(true);
++}
++
++void MainWindow::linkToProgramFile(const QString & filename, const QString & language, const QString & programmer, bool addLink, bool strong) {
++#ifdef Q_WS_WIN
++ Qt::CaseSensitivity sensitivity = Qt::CaseInsensitive;
++#else
++ Qt::CaseSensitivity sensitivity = Qt::CaseSensitive;
++#endif
++
++ if (addLink && strong) {
++ bool gotOne = false;
++ foreach (LinkedFile * linkedFile, m_linkedProgramFiles) {
++ if (linkedFile->linkedFilename.compare(filename, sensitivity) == 0) {
++ if (linkedFile->language != language) {
++ linkedFile->language = language;
++ this->setWindowModified(true);
++ }
++ if (linkedFile->programmer != programmer) {
++ linkedFile->programmer = programmer;
++ this->setWindowModified(true);
++ }
++ gotOne = true;
++ break;
++ }
++ }
++ if (!gotOne) {
++ LinkedFile * linkedFile = new LinkedFile;
++ linkedFile->linkedFilename = filename;
++ linkedFile->language = language;
++ linkedFile->programmer = programmer;
++ m_linkedProgramFiles.append(linkedFile);
++ this->setWindowModified(true);
++ }
++ return;
++ }
++ else {
++ for (int i = 0; i < m_linkedProgramFiles.count(); i++) {
++ LinkedFile * linkedFile = m_linkedProgramFiles.at(i);
++ if (linkedFile->linkedFilename.compare(filename, sensitivity) == 0) {
++ if (strong) {
++ m_linkedProgramFiles.removeAt(i);
++ this->setWindowModified(true);
++ }
++ else {
++ if (linkedFile->language != language) {
++ linkedFile->language = language;
++ this->setWindowModified(true);
++ }
++ if (linkedFile->programmer != programmer) {
++ linkedFile->programmer = programmer;
++ this->setWindowModified(true);
++ }
++ }
++ return;
++ }
++ }
++ }
++}
++
++QStringList MainWindow::newDesignRulesCheck()
++{
++ return newDesignRulesCheck(true);
++}
++
++QStringList MainWindow::newDesignRulesCheck(bool showOkMessage)
++{
++ QStringList results;
++
++ if (m_currentGraphicsView == NULL) return results;
++
++ PCBSketchWidget * pcbSketchWidget = qobject_cast<PCBSketchWidget *>(m_currentGraphicsView);
++ if (pcbSketchWidget == NULL) return results;
++
++ ItemBase * board = NULL;
++ if (pcbSketchWidget->autorouteTypePCB()) {
++ int boardCount;
++ board = pcbSketchWidget->findSelectedBoard(boardCount);
++ if (boardCount == 0) {
++ QString message = tr("Your sketch does not have a board yet! DRC only works with a PCB.");
++ results << message;
++ QMessageBox::critical(this, tr("Fritzing"), message);
++ return results;
++ }
++ if (board == NULL) {
++ QString message = tr("Please select a PCB. DRC only works on one board at a time.");
++ results << message;
++ QMessageBox::critical(this, tr("Fritzing"), message);
++ return results;
++ }
++ }
++
++ bool copper0Active = pcbSketchWidget->layerIsActive(ViewLayer::Copper0);
++ bool copper1Active = pcbSketchWidget->layerIsActive(ViewLayer::Copper1);
++
++ AutorouteProgressDialog progress(tr("DRC Progress..."), true, false, false, false, pcbSketchWidget, this);
++ progress.setModal(true);
++ progress.show();
++ QRect pr = progress.frameGeometry();
++ QRect wr = pcbSketchWidget->frameGeometry();
++ QPoint p = pcbSketchWidget->mapTo(this, wr.topRight());
++ progress.move(p.x() - pr.width(), pr.top());
++
++ DRC drc(pcbSketchWidget, board);
++
++ connect(&drc, SIGNAL(wantTopVisible()), this, SLOT(activeLayerTop()), Qt::DirectConnection);
++ connect(&drc, SIGNAL(wantBottomVisible()), this, SLOT(activeLayerBottom()), Qt::DirectConnection);
++ connect(&drc, SIGNAL(wantBothVisible()), this, SLOT(activeLayerBoth()), Qt::DirectConnection);
++
++ connect(&progress, SIGNAL(cancel()), &drc, SLOT(cancel()), Qt::DirectConnection);
++
++ connect(&drc, SIGNAL(setMaximumProgress(int)), &progress, SLOT(setMaximum(int)), Qt::DirectConnection);
++ connect(&drc, SIGNAL(setProgressValue(int)), &progress, SLOT(setValue(int)), Qt::DirectConnection);
++ connect(&drc, SIGNAL(setProgressMessage(const QString &)), &progress, SLOT(setMessage(const QString &)));
++ connect(&drc, SIGNAL(setProgressMessage2(const QString &)), &progress, SLOT(setMessage2(const QString &)));
++ connect(&drc, SIGNAL(hideProgress()), &progress, SLOT(close()));
++
++ ProcessEventBlocker::processEvents();
++ ProcessEventBlocker::block();
++ results = drc.start(showOkMessage, pcbSketchWidget->getKeepout() * 1000 / GraphicsUtils::SVGDPI); // pixels to mils
++ ProcessEventBlocker::unblock();
++
++ pcbSketchWidget->setLayerActive(ViewLayer::Copper1, copper1Active);
++ pcbSketchWidget->setLayerActive(ViewLayer::Silkscreen1, copper1Active);
++ pcbSketchWidget->setLayerActive(ViewLayer::Copper0, copper0Active);
++ pcbSketchWidget->setLayerActive(ViewLayer::Silkscreen0, copper0Active);
++ updateActiveLayerButtons();
++ return results;
++}
++
++void MainWindow::changeTraceLayer() {
++ if (m_currentGraphicsView == NULL) return;
++ if (m_currentGraphicsView != m_pcbGraphicsView) return;
++
++ Wire * wire = retrieveWire();
++ m_pcbGraphicsView->changeTraceLayer(wire, false, NULL);
++}
++
++Wire * MainWindow::retrieveWire() {
++ WireAction * wireAction = qobject_cast<WireAction *>(sender());
++ if (wireAction == NULL) return NULL;
++
++ return wireAction->wire();
++}
++
++ConnectorItem * MainWindow::retrieveConnectorItem() {
++ ConnectorItemAction * connectorItemAction = qobject_cast<ConnectorItemAction *>(sender());
++ if (connectorItemAction == NULL) return NULL;
++
++ return connectorItemAction->connectorItem();
++}
++
++void MainWindow::setSticky()
++{
++ QList<QGraphicsItem *> items = m_currentGraphicsView->scene()->selectedItems();
++ if (items.count() < 1) return;
++
++ ItemBase * itemBase = dynamic_cast<ItemBase *>(items.at(0));
++ if (itemBase == NULL) return;
++
++ if (!itemBase->isBaseSticky()) return;
++
++ itemBase->setLocalSticky(!itemBase->isLocalSticky());
++}
++
++void MainWindow::moveLock()
++{
++ bool moveLock = true;
++
++ foreach (QGraphicsItem * item, m_currentGraphicsView->scene()->selectedItems()) {
++ ItemBase * itemBase = ItemBase::extractTopLevelItemBase(item);
++ if (itemBase == NULL) continue;
++ if (itemBase->itemType() == ModelPart::Wire) continue;
++
++ if (itemBase->moveLock()) {
++ moveLock = false;
++ break;
++ }
++ }
++
++ ItemBase * viewedItem = m_infoView->currentItem();
++ foreach (QGraphicsItem * item, m_currentGraphicsView->scene()->selectedItems()) {
++ ItemBase * itemBase = ItemBase::extractTopLevelItemBase(item);
++ if (itemBase == NULL) continue;
++ if (itemBase->itemType() == ModelPart::Wire) continue;
++
++ itemBase->setMoveLock(moveLock);
++ if (viewedItem && viewedItem->layerKinChief() == itemBase->layerKinChief()) {
++ m_currentGraphicsView->viewItemInfo(itemBase);
++ }
++ }
++}
++
++void MainWindow::selectMoveLock()
++{
++ m_currentGraphicsView->selectAllMoveLock();
++}
++
++void MainWindow::autorouterSettings() {
++ if (m_currentGraphicsView != m_pcbGraphicsView) return;
++
++ m_pcbGraphicsView->autorouterSettings();
++}
++
++void MainWindow::orderFab()
++{
++ QDesktopServices::openUrl(QString("http://fab.fritzing.org/"));
++}
++
++void MainWindow::setGroundFillSeeds() {
++ int boardCount;
++ ItemBase * board = m_pcbGraphicsView->findSelectedBoard(boardCount);
++ if (boardCount == 0) {
++ QMessageBox::critical(this, tr("Fritzing"),
++ tr("Your sketch does not have a board yet! Please add a PCB in order to use copper fill operations."));
++ return;
++ }
++ if (board == NULL) {
++ QMessageBox::critical(this, tr("Fritzing"),
++ tr("Please select a PCB. Copper fill operations only work on one board at a time."));
++ return;
++ }
++
++ m_pcbGraphicsView->setGroundFillSeeds();
++}
++
++void MainWindow::clearGroundFillSeeds() {
++ int boardCount;
++ ItemBase * board = m_pcbGraphicsView->findSelectedBoard(boardCount);
++ if (boardCount == 0) {
++ QMessageBox::critical(this, tr("Fritzing"),
++ tr("Your sketch does not have a board yet! Please add a PCB in order to use copper fill operations."));
++ return;
++ }
++ if (board == NULL) {
++ QMessageBox::critical(this, tr("Fritzing"),
++ tr("Please select a PCB. Copper fill operations only work on one board at a time."));
++ return;
++ }
++
++ m_pcbGraphicsView->clearGroundFillSeeds();
++}
++
++void MainWindow::setOneGroundFillSeed() {
++ ConnectorItemAction * action = qobject_cast<ConnectorItemAction *>(sender());
++ if (action == NULL) return;
++
++ ConnectorItem * connectorItem = action->connectorItem();
++ if (connectorItem == NULL) return;
++
++ GroundFillSeedCommand * command = new GroundFillSeedCommand(m_pcbGraphicsView, NULL);
++ command->addItem(connectorItem->attachedToID(), connectorItem->connectorSharedID(), action->isChecked());
++
++ m_undoStack->push(command);
++}
++
++void MainWindow::gridUnits(bool checked) {
++ QWidget * widget = qobject_cast<QWidget *>(sender());
++ if (widget == NULL) return;
++
++ GridSizeDialog * dialog = qobject_cast<GridSizeDialog *>(widget->window());
++ if (dialog == NULL) return;
++
++ GridSizeThing * gridSizeThing = dialog->gridSizeThing();
++
++ QString units;
++ if (sender() == gridSizeThing->inButton) {
++ units = (checked) ? "in" : "mm";
++ }
++ else {
++ units = (checked) ? "mm" : "in";
++ }
++
++ if (units.startsWith("mm")) {
++ gridSizeThing->validator->setTop(25.4);
++ gridSizeThing->lineEdit->setText(QString::number(gridSizeThing->lineEdit->text().toDouble() * 25.4));
++ }
++ else {
++ gridSizeThing->validator->setTop(1.0);
++ gridSizeThing->lineEdit->setText(QString::number(gridSizeThing->lineEdit->text().toDouble() / 25.4));
++ }
++
++}
++
++void MainWindow::restoreDefaultGrid() {
++ QWidget * widget = qobject_cast<QWidget *>(sender());
++ if (widget == NULL) return;
++
++ GridSizeDialog * dialog = qobject_cast<GridSizeDialog *>(widget->window());
++ if (dialog == NULL) return;
++
++ GridSizeThing * gridSizeThing = dialog->gridSizeThing();
++
++ gridSizeThing->inButton->setChecked(true);
++ gridSizeThing->mmButton->setChecked(false);
++ gridSizeThing->lineEdit->setText(QString::number(gridSizeThing->defaultGridSize));
++}
++
++void MainWindow::setBackgroundColor()
++{
++ QColor cc = m_currentGraphicsView->background();
++ QColor scc = m_currentGraphicsView->standardBackground();
++
++ SetColorDialog setColorDialog(tr("%1 background Color").arg(m_currentGraphicsView->viewName()), cc, scc, true, this);
++ int result = setColorDialog.exec();
++ if (result == QDialog::Rejected) return;
++
++ QColor newColor = setColorDialog.selectedColor();
++ m_currentGraphicsView->setBackgroundColor(newColor, setColorDialog.isPrefsColor());
++ setWindowModified(true);
++}
++
++void MainWindow::checkLoadedTraces() {
++ if (m_pcbGraphicsView) m_pcbGraphicsView->checkLoadedTraces();
++}
++
++void MainWindow::showUnrouted()
++{
++ m_currentGraphicsView->showUnrouted();
++}
++
++void MainWindow::hidePartSilkscreen()
++{
++ m_pcbGraphicsView->hidePartSilkscreen();
++}
++
++void MainWindow::fabQuote() {
++ if (m_pcbGraphicsView) m_pcbGraphicsView->fabQuote();
++}
++
++void MainWindow::findPartInSketch() {
++ static QString lastSearchText;
++
++ if (m_currentGraphicsView == NULL) return;
++
++ bool ok;
++ QString text = QInputDialog::getText(this, tr("Enter Text"),
++ tr("Text will match part label, description, title, etc. Enter text to search for:"),
++ QLineEdit::Normal, lastSearchText, &ok);
++ if (!ok || text.isEmpty()) return;
++
++ lastSearchText = text;
++ QSet<ItemBase *> itemBases;
++ foreach (QGraphicsItem * item, m_currentGraphicsView->scene()->items()) {
++ ItemBase * itemBase = dynamic_cast<ItemBase *>(item);
++ if (itemBase == NULL) continue;
++
++ itemBases.insert(itemBase->layerKinChief());
++ }
++
++ QStringList strings;
++ strings << text;
++ QList<ItemBase *> matched;
++ foreach (ItemBase * itemBase, itemBases) {
++
++#ifndef QT_NO_DEBUG
++ if (QString::number(itemBase->id()).contains(text)) {
++ matched << itemBase;
++ continue;
++ }
++#endif
++
++ if (itemBase->instanceTitle().contains(text, Qt::CaseInsensitive)) {
++ matched << itemBase;
++ continue;
++ }
++
++ QList<ModelPart *> modelParts;
++ m_referenceModel->search(itemBase->modelPart(), strings, modelParts, true);
++ if (modelParts.count() > 0) {
++ matched << itemBase;
++ }
++ }
++
++ if (matched.count() == 0) {
++ QMessageBox::information(this, tr("Search"), tr("No parts matched search term '%1'.").arg(text));
++ return;
++ }
++
++ m_currentGraphicsView->selectItems(matched);
++}
++
++void MainWindow::setGroundFillKeepout() {
++ if (m_pcbGraphicsView != NULL) m_pcbGraphicsView->setGroundFillKeepout();
++}
++
++void MainWindow::setViewFromBelowToggle() {
++ if (m_pcbGraphicsView != NULL) {
++ m_pcbGraphicsView->setViewFromBelow(m_viewFromBelowToggleAct->isChecked());
++ updateActiveLayerButtons();
++ }
++}
++
++void MainWindow::setViewFromBelow() {
++ if (m_pcbGraphicsView != NULL) {
++ m_pcbGraphicsView->setViewFromBelow(true);
++ updateActiveLayerButtons();
++ }
++}
++
++void MainWindow::setViewFromAbove() {
++ if (m_pcbGraphicsView != NULL) {
++ m_pcbGraphicsView->setViewFromBelow(false);
++ updateActiveLayerButtons();
++ }
++}
diff --git a/fritzing.spec b/fritzing.spec
index f385f61..749aa7a 100644
--- a/fritzing.spec
+++ b/fritzing.spec
@@ -1,6 +1,6 @@
Name: fritzing
-Version: 0.7.12b
-Release: 3%{?dist}
+Version: 0.8.3b
+Release: 0%{?dist}
Summary: Electronic Design Automation software; from prototype to product
Group: Applications/Engineering
@@ -61,6 +61,9 @@ desktop-file-install --dir=%{buildroot}%{_datadir}/applications %{SOURCE1}
%{_mandir}/man?/*
%changelog
+* Sat Aug 10 2013 Ed Marshall <esm at logic.net> - 0.8.3b-0
+- Updated to 0.8.3b release.
+
* Sat Aug 03 2013 Fedora Release Engineering <rel-eng at lists.fedoraproject.org> - 0.7.12b-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild
diff --git a/sources b/sources
index cb8b97d..9955511 100644
--- a/sources
+++ b/sources
@@ -1,2 +1 @@
-4f2d5e0dff6ce83d6f3d68d7408006fe fritzing-0.7.12b.source.tar.bz2
-cc5b90009ac9dbd1561935fd648b1037 fritzing-0.7.11b.source.tar.bz2
+427ff65d4c0bd75369f211d096f2ed56 fritzing-0.8.3b.source.tar.bz2
More information about the scm-commits
mailing list