1
/*******************************************************************
3
Part of the Fritzing project - http://fritzing.org
4
Copyright (c) 2007-2012 Fachhochschule Potsdam - http://fh-potsdam.de
6
Fritzing is free software: you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation, either version 3 of the License, or
9
(at your option) any later version.
11
Fritzing is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
GNU General Public License for more details.
16
You should have received a copy of the GNU General Public License
17
along with Fritzing. If not, see <http://www.gnu.org/licenses/>.
19
********************************************************************
22
$Author: cohen@irascible.com $:
23
$Date: 2012-08-08 04:07:28 +0200 (Wed, 08 Aug 2012) $
25
********************************************************************/
29
#include "partseditormainwindow.h"
31
#include "../debugdialog.h"
32
#include "../fdockwidget.h"
33
#include "../waitpushundostack.h"
34
#include "editabletextwidget.h"
35
#include "partseditorview.h"
36
#include "partseditorviewswidget.h"
37
#include "editabledatewidget.h"
38
#include "hashpopulatewidget.h"
39
#include "partspecificationswidget.h"
40
#include "partconnectorswidget.h"
41
#include "../model/palettemodel.h"
42
#include "../model/sketchmodel.h"
43
#include "../utils/folderutils.h"
44
#include "../processeventblocker.h"
47
#include <QCryptographicHash>
48
#include <QRegExpValidator>
53
QString PartsEditorMainWindow::TitleFreshStartText;
54
QString PartsEditorMainWindow::LabelFreshStartText;
55
QString PartsEditorMainWindow::DescriptionFreshStartText;
56
QString PartsEditorMainWindow::TaxonomyFreshStartText;
57
QString PartsEditorMainWindow::TagsFreshStartText;
58
QString PartsEditorMainWindow::FooterText;
59
QString PartsEditorMainWindow::UntitledPartName;
60
QString PartsEditorMainWindow::___partsEditorName___;
62
int PartsEditorMainWindow::UntitledPartIndex = 1;
63
QPointer<PartsEditorMainWindow> PartsEditorMainWindow::m_lastOpened = NULL;
64
int PartsEditorMainWindow::m_closedBeforeCount = 0;
65
bool PartsEditorMainWindow::m_closeAfterSaving = true;
68
#define CORE_EDITION_ENABLED false
70
#define CORE_EDITION_ENABLED false
74
PartsEditorMainWindow::PartsEditorMainWindow(QWidget *parent)
75
: FritzingWindow(untitledFileName(), untitledFileCount(), fileExtension(), parent)
77
m_iconItem = m_breadboardItem = m_schematicItem = m_pcbItem = NULL;
78
m_editingAlien = false;
81
PartsEditorMainWindow::~PartsEditorMainWindow()
84
// m_iconItem was custom-created for the PartsEditor; the other items exist in the sketch so shouldn't be deleted
89
// memory leak here, but delete or deleteLater causes a crash if you're editing an already existing part; a new part seems ok
94
delete m_paletteModel;
98
void PartsEditorMainWindow::initText() {
99
UntitledPartName = tr("Untitled Part");
100
TitleFreshStartText = tr("Please find a name for me!");
101
LabelFreshStartText = tr("Please provide a label");
102
DescriptionFreshStartText = tr("You could tell a little bit about this part");
103
TaxonomyFreshStartText = tr("Please classify this part");
104
TagsFreshStartText = tr("You can add your tags to make searching easier");
105
FooterText = tr("<i>created by</i> %1 <i>on</i> %2");
106
___partsEditorName___ = tr("Parts Editor");
110
void PartsEditorMainWindow::setup(long id, ModelPart *modelPart, bool fromTemplate, ItemBase * fromItem)
112
ModelPart * originalModelPart = NULL;
113
QFile styleSheet(":/resources/styles/partseditor.qss");
114
m_mainFrame = new QFrame(this);
115
m_mainFrame->setObjectName("partsEditor");
117
m_editingAlien = modelPart? modelPart->isAlien(): false;
119
if (!styleSheet.open(QIODevice::ReadOnly)) {
120
qWarning("Unable to open :/resources/styles/partseditor.qss");
122
m_mainFrame->setStyleSheet(styleSheet.readAll());
128
m_partUpdated = false;
129
m_savedAsNewPart = false;
131
setAttribute(Qt::WA_DeleteOnClose, true);
133
m_paletteModel = new PaletteModel(false, false, false);
135
if(modelPart == NULL){
137
m_updateEnabled = true;
139
// user only allowed to save parts, once he has saved it as a new one
140
m_updateEnabled = modelPart->isCore()?
141
CORE_EDITION_ENABLED:
142
(modelPart->isContrib() || modelPart->isAlien()? false: true);
143
m_fwFilename = modelPart->path();
145
UntitledPartIndex--; // TODO Mariano: not good enough
149
m_sketchModel = new SketchModel(true);
151
ModelPart * mp = m_paletteModel->loadPart(m_fwFilename, false, false);
152
// this seems hacky but maybe it's ok
153
if (mp == NULL || mp->modelPartShared() == NULL) {
154
QMessageBox::critical(this, tr("Parts Editor"),
155
tr("Error! Cannot load part.\n"),
157
QTimer::singleShot(60, this, SLOT(close()));
161
QHash<QString,QString> properties = mp->modelPartShared()->properties();
162
foreach (QString key, properties.keys()) {
163
QVariant prop = modelPart->localProp(key);
164
if (!prop.isNull() && prop.isValid()) {
165
QString p = prop.toString();
167
mp->modelPartShared()->properties()[key] = p;
168
if (key.compare("chip label") == 0) {
169
mp->modelPartShared()->properties()["family"] = p;
175
originalModelPart = modelPart;
177
m_sketchModel = new SketchModel(modelPart);
180
ModelPart *mp = fromTemplate ? modelPart : NULL;
183
createCenter(mp, fromItem);
186
// copy connector local names here if any
187
if (originalModelPart) {
188
foreach (Connector * fromConnector, originalModelPart->connectors()) {
189
foreach (Connector * toConnector, mp->connectors()) {
190
if (toConnector->connectorSharedID().compare(fromConnector->connectorSharedID()) == 0) {
191
toConnector->setConnectorLocalName(fromConnector->connectorLocalName());
197
layout()->setMargin(0);
198
layout()->setSpacing(0);
201
QGridLayout *layout = new QGridLayout(m_mainFrame);
202
layout->setMargin(0);
203
layout->setSpacing(0);
204
layout->addWidget(m_headerFrame,0,0);
205
layout->addWidget(m_centerFrame,1,0);
206
layout->addWidget(m_footerFrame,2,0);
207
setCentralWidget(m_mainFrame);
210
m_views->setViewItems(m_breadboardItem, m_schematicItem, m_pcbItem);
211
m_views->loadViewsImagesFromModel(m_paletteModel, m_sketchModel->root());
214
setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
217
if (!settings.value("peditor/state").isNull()) {
218
restoreState(settings.value("peditor/state").toByteArray());
220
if (!settings.value("peditor/geometry").isNull()) {
221
restoreGeometry(settings.value("peditor/geometry").toByteArray());
224
installEventFilter(this);
228
void PartsEditorMainWindow::createHeader(ModelPart *modelPart) {
229
m_headerFrame = new QFrame();
230
m_headerFrame->setSizePolicy(QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Fixed));
231
m_headerFrame->setObjectName("header");
232
m_headerFrame->setStyleSheet("padding: 2px; padding-bottom: 0;");
234
int iconViewSize = 50;
235
QGraphicsProxyWidget *startItem = modelPart? NULL: PartsEditorMainWindow::emptyViewItem("icon_icon.png",___emptyString___);
236
m_iconViewImage = new PartsEditorView(
237
ViewIdentifierClass::IconView, createTempFolderIfNecessary(), false, startItem, m_headerFrame, iconViewSize
239
m_iconViewImage->setViewItem(m_iconItem);
240
m_iconViewImage->setFixedSize(iconViewSize,iconViewSize);
241
m_iconViewImage->setObjectName("iconImage");
242
m_iconViewImage->setSketchModel(m_sketchModel);
243
m_iconViewImage->setUndoStack(m_undoStack);
244
m_iconViewImage->addViewLayer(new ViewLayer(ViewLayer::Icon, true, 2.5));
245
m_iconViewImage->setViewLayerIDs(ViewLayer::Icon, ViewLayer::Icon, ViewLayer::Icon, ViewLayer::Icon, ViewLayer::Icon);
247
m_iconViewImage->loadFromModel(m_paletteModel, modelPart);
250
QString linkStyle = "font-size: 10px; color: #7070ff;";
251
QLabel *button = new QLabel(
252
QString("<a style='%2' href='#'>%1</a>")
253
.arg(tr("Load icon.."))
256
button->setObjectName("iconBrowseButton");
257
//button->setFixedWidth(iconViewSize);
258
button->setFixedHeight(20);
259
//m_iconViewImage->addFixedToBottomRight(button);
260
connect(button, SIGNAL(linkActivated(const QString&)), m_iconViewImage, SLOT(loadFile()));
262
QString title = modelPart ? modelPart->title() : TitleFreshStartText;
263
m_title = new EditableLineWidget(title,m_undoStack,m_headerFrame,"",modelPart,true);
264
m_title->setObjectName("partTitle");
265
m_title->setSizePolicy(QSizePolicy(QSizePolicy::Expanding,QSizePolicy::MinimumExpanding));
267
QGridLayout *headerLayout = new QGridLayout();
268
headerLayout->addWidget(m_iconViewImage,0,0);
269
headerLayout->addWidget(m_title,0,1);
270
headerLayout->addWidget(button,1,0,1,2);
271
headerLayout->setVerticalSpacing(0);
272
headerLayout->setMargin(0);
273
m_headerFrame->setLayout(headerLayout);
276
void PartsEditorMainWindow::createCenter(ModelPart *modelPart, ItemBase * fromItem) {
277
m_moduleId = modelPart ? modelPart->moduleID() : "";
278
m_version = modelPart ? modelPart->version() : "";
279
m_uri = modelPart ? modelPart->uri() : "";
281
m_centerFrame = new QFrame();
282
m_centerFrame->setObjectName("center");
284
QList<QWidget*> specWidgets;
286
m_connsInfo = new ConnectorsInfoWidget(m_undoStack,this);
287
m_views = new PartsEditorViewsWidget(m_sketchModel, m_undoStack, m_connsInfo, this, fromItem);
289
QString label = modelPart ? modelPart->label() : LabelFreshStartText;
290
m_label = new EditableLineWidget(label,m_undoStack,this,tr("Label"),modelPart);
292
QString description = modelPart ? modelPart->description() : DescriptionFreshStartText;
293
m_description = new EditableTextWidget(description,m_undoStack,this,tr("Description"),modelPart);
295
/*QString taxonomy = modelPart ? modelPart->modelPartShared()->taxonomy() : TAXONOMY_FRESH_START_TEXT;
296
m_taxonomy = new EditableLineWidget(taxonomy,m_undoStack,this,tr("Taxonomy"),modelPart);
297
QRegExp regexp("[\\w+\\.]+\\w$");
298
m_taxonomy->setValidator(new QRegExpValidator(regexp,this));*/
300
QStringList readOnlyKeys;
301
readOnlyKeys << "family" << "voltage" << "type";
303
QHash<QString,QString> initValues;
305
initValues = modelPart->properties();
307
initValues["family"] = "";
308
//initValues["voltage"] = "";
309
//initValues["type"] = "Through-Hole";
312
m_properties = new HashPopulateWidget(tr("Properties"),initValues,readOnlyKeys,m_undoStack,this);
314
QString tags = modelPart ? modelPart->tags().join(", ") : TagsFreshStartText;
315
m_tags = new EditableLineWidget(tags,m_undoStack,this,tr("Tags"),modelPart);
318
m_author = new EditableLineWidget(
319
modelPart ? modelPart->author() : QString(getenvUser()),
320
m_undoStack, this, tr("Author"),true);
322
m_author,SIGNAL(editionCompleted(QString)),
323
this,SLOT(updateDateAndAuthor()));
325
m_createdOn = new EditableDateWidget(
326
modelPart ? modelPart->date() : QDate::currentDate(),
327
m_undoStack,this, tr("Created/Updated on"),true);
329
m_createdOn,SIGNAL(editionCompleted(QString)),
330
this,SLOT(updateDateAndAuthor()));
332
m_createdByText = new QLabel(FooterText.arg(m_author->text()).arg(m_createdOn->text()));
333
m_createdByText->setObjectName("createdBy");
335
specWidgets << m_label << m_description /*<< m_taxonomy*/ << m_properties << m_tags << m_author << m_createdOn << m_createdByText;
337
m_connsInfo->setViews(m_views);
339
connect(m_connsInfo, SIGNAL(repaintNeeded()), m_views, SLOT(repaint()));
340
connect(m_connsInfo, SIGNAL(drawConnector(Connector*)), m_views, SLOT(drawConnector(Connector*)));
342
m_connsInfo, SIGNAL(drawConnector(ViewIdentifierClass::ViewIdentifier, Connector*)),
343
m_views, SLOT(drawConnector(ViewIdentifierClass::ViewIdentifier, Connector*))
346
m_connsInfo, SIGNAL(setMismatching(ViewIdentifierClass::ViewIdentifier, const QString&, bool)),
347
m_views, SLOT(setMismatching(ViewIdentifierClass::ViewIdentifier, const QString&, bool))
349
connect(m_connsInfo, SIGNAL(removeConnectorFrom(const QString&,ViewIdentifierClass::ViewIdentifier)),
350
m_views, SLOT(removeConnectorFrom(const QString&,ViewIdentifierClass::ViewIdentifier)));
351
connect(m_views, SIGNAL(connectorSelectedInView(const QString&)),
352
m_connsInfo, SLOT(connectorSelectedInView(const QString&)));
353
m_views->showTerminalPointsCheckBox()->setChecked(false);
355
m_views->connectTerminalRemoval(m_connsInfo);
358
m_views, SIGNAL(connectorsFoundSignal(QList< QPointer<Connector> >)),
359
m_connsInfo, SLOT(connectorsFound(QList< QPointer<Connector> >))
362
m_tabWidget = new QTabWidget(m_centerFrame);
363
m_tabWidget->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
364
m_tabWidget->addTab(new PartSpecificationsWidget(specWidgets,this),tr("Specifications"));
365
m_tabWidget->addTab(new PartConnectorsWidget(m_connsInfo,this),tr("Connectors"));
367
QGridLayout *tabLayout = new QGridLayout(m_tabWidget);
368
tabLayout->setMargin(0);
369
tabLayout->setSpacing(0);
371
QSplitter *splitter = new QSplitter(Qt::Vertical,this);
372
splitter->addWidget(m_views);
373
splitter->addWidget(m_tabWidget);
375
QGridLayout *mainLayout = new QGridLayout(m_centerFrame);
376
mainLayout->setMargin(0);
377
mainLayout->setSpacing(0);
378
mainLayout->addWidget(splitter,0,0,1,1);
381
void PartsEditorMainWindow::connectWidgetsToSave(const QList<QWidget*> &widgets) {
382
for(int i=0; i < widgets.size(); i++) {
383
connect(m_saveAsNewPartButton,SIGNAL(clicked()),widgets[i],SLOT(informEditionCompleted()));
384
connect(this,SIGNAL(saveButtonClicked()),widgets[i],SLOT(informEditionCompleted()));
388
void PartsEditorMainWindow::createFooter() {
389
m_footerFrame = new QFrame();
390
m_footerFrame->setObjectName("footer");
391
m_footerFrame->setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Fixed);
393
m_saveAsNewPartButton = new QPushButton(tr("save as new part"));
394
m_saveAsNewPartButton->setObjectName("saveAsPartButton");
395
m_saveAsNewPartButton->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed);
397
m_saveButton = new QPushButton(tr("save"));
398
m_saveButton->setObjectName("saveAsButton");
399
m_saveButton->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed);
403
QList<QWidget*> editableLabelWidgets;
404
editableLabelWidgets << m_title << m_label << m_description /*<< m_taxonomy*/ << m_tags << m_author << m_createdOn << m_connsInfo ;
405
connectWidgetsToSave(editableLabelWidgets);
407
connect(m_saveAsNewPartButton, SIGNAL(clicked()), this, SLOT(saveAs()));
408
connect(m_saveButton, SIGNAL(clicked()), this, SLOT(save()));
410
m_cancelCloseButton = new QPushButton(tr("cancel"));
411
m_cancelCloseButton->setObjectName("cancelButton");
412
m_cancelCloseButton->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed);
413
connect(m_cancelCloseButton, SIGNAL(clicked()), this, SLOT(close()));
415
QHBoxLayout *footerLayout = new QHBoxLayout;
417
footerLayout->setMargin(0);
418
footerLayout->setSpacing(0);
419
footerLayout->addSpacerItem(new QSpacerItem(40,0,QSizePolicy::Minimum,QSizePolicy::Minimum));
420
footerLayout->addWidget(m_saveAsNewPartButton);
421
footerLayout->addSpacerItem(new QSpacerItem(0,0,QSizePolicy::Expanding,QSizePolicy::Minimum));
422
footerLayout->addWidget(m_saveButton);
423
footerLayout->addSpacerItem(new QSpacerItem(15,0,QSizePolicy::Minimum,QSizePolicy::Minimum));
424
footerLayout->addWidget(m_cancelCloseButton);
425
footerLayout->addSpacerItem(new QSpacerItem(40,0,QSizePolicy::Minimum,QSizePolicy::Minimum));
426
m_footerFrame->setLayout(footerLayout);
430
QGraphicsProxyWidget *PartsEditorMainWindow::emptyViewItem(QString iconFile, QString text) {
431
QLabel *icon = new QLabel();
432
icon->setPixmap(QPixmap(":/resources/images/"+iconFile));
433
icon->setAlignment(Qt::AlignHCenter);
435
QLabel *label = NULL;
436
if(!text.isNull() && !text.isEmpty()) {
437
label = new QLabel(text);
438
label->setAlignment(Qt::AlignHCenter);
441
QFrame *container = new QFrame();
442
container->setStyleSheet("background-color: transparent;");
443
QVBoxLayout *mainLo = new QVBoxLayout(container);
444
mainLo->setMargin(0);
445
mainLo->setSpacing(0);
447
QHBoxLayout *lo1 = new QHBoxLayout();
448
lo1->addWidget(icon);
451
mainLo->addLayout(lo1);
454
QHBoxLayout *lo2 = new QHBoxLayout();
455
lo2->addWidget(label);
458
mainLo->addLayout(lo2);
461
QGraphicsProxyWidget *item = new QGraphicsProxyWidget();
462
item->setWidget(container);
467
const QDir& PartsEditorMainWindow::createTempFolderIfNecessary() {
468
if(m_tempDir.path() == ".") {
469
QString randext = FolderUtils::getRandText();
470
m_tempDir = QDir(QDir::tempPath());
471
bool dirCreation = m_tempDir.mkdir(randext);
473
throw "PartsEditorMainWindow::createTempFolderIfNecessary creation failure";
476
bool cdResult = m_tempDir.cd(randext);
478
throw "PartsEditorMainWindow::createTempFolderIfNecessary cd failure";
481
// will use the standard location of the temp folder
482
// instead of a subfolder inside of it
488
bool PartsEditorMainWindow::save() {
489
if(validateMinRequirements() && wannaSaveAfterWarning(false)) {
490
bool result = (m_saveButton->isEnabled()) ? FritzingWindow::save() : saveAs();
492
m_cancelCloseButton->setText(tr("close"));
493
if(m_closeAfterSaving) close();
501
bool PartsEditorMainWindow::saveAs() {
502
if(!validateMinRequirements()) return false;
504
QString fileNameBU = m_fwFilename;
505
QString moduleIdBU = m_moduleId;
507
m_moduleId = ___emptyString___;
508
QString title = m_title->text();
509
m_fwFilename = !title.isEmpty() ? title+FritzingPartExtension : QFileInfo(m_fwFilename).baseName();
511
// TODO Mariano: This folder should be defined in the preferences... some day
512
QString partsFolderPath = FolderUtils::getUserDataStorePath("parts")+"/";
513
QString userPartsFolderPath = partsFolderPath+"user/";
515
bool firstTime = true; // Perhaps the user wants to use the default file name, confirm first
516
while(m_fwFilename.isEmpty()
517
|| QFileInfo(userPartsFolderPath+m_fwFilename).exists()
518
|| (FolderUtils::isEmptyFileName(m_fwFilename,untitledFileName()) && firstTime) )
521
m_fwFilename = QInputDialog::getText(
523
tr("Save as new part"),
524
tr("There's already a file with this name.\nPlease, specify a new filename"),
531
m_moduleId = moduleIdBU;
532
m_fwFilename = fileNameBU;
537
m_fwFilename.replace(QRegExp("[^A-Za-z0-9\\.]"), "_");
539
Qt::CaseSensitivity cs = Qt::CaseSensitive;
541
// seems to be necessary for Windows: getUserDataStorePath() returns a string starting with "c:"
542
// but the file dialog returns a string beginning with "C:"
543
cs = Qt::CaseInsensitive;
546
QString filename = !m_fwFilename.startsWith(userPartsFolderPath, cs)
547
&& !m_fwFilename.startsWith(partsFolderPath, cs)
548
? userPartsFolderPath+m_fwFilename
550
QString guid = "__"+FolderUtils::getRandText()+FritzingPartExtension;
551
if(!alreadyHasExtension(filename, FritzingPartExtension)) {
554
filename.replace(FritzingPartExtension,guid);
558
if (!saveAsAux(filename)) return false;
560
if(wannaSaveAfterWarning(true)) {
561
m_savedAsNewPart = true;
562
m_updateEnabled = true;
564
if(m_closeAfterSaving) close();
571
void PartsEditorMainWindow::makeNonCore() {
572
QString oldTags = m_tags->text();
573
QString newTags = oldTags.replace("fritzing core","user part",Qt::CaseInsensitive);
574
m_tags->setText(newTags);
577
bool PartsEditorMainWindow::saveAsAux(const QString & fileName) {
578
QFile file(fileName);
579
if (!file.open(QFile::WriteOnly | QFile::Text)) {
580
QMessageBox::warning(this, tr("Fritzing"),
581
tr("Cannot write file %1:\n%2.")
583
.arg(file.errorString()));
588
updateDateAndAuthor();
590
QApplication::setOverrideCursor(Qt::WaitCursor);
592
m_sketchModel->root()->setModelPartShared(createModelPartShared());
594
QString fileNameAux = QFileInfo(fileName).fileName();
595
m_views->copySvgFilesToDestiny(fileNameAux);
596
m_iconViewImage->copySvgFileToDestiny(fileNameAux);
598
m_sketchModel->save(fileName, true);
600
QApplication::restoreOverrideCursor();
602
statusBar()->showMessage(tr("Saved '%1'").arg(fileName), 2000);
604
m_partUpdated = true;
606
setFileName(fileName);
607
//setCurrentFile(fileName);
609
// mark the stack clean so we update the window dirty flag
610
m_undoStack->setClean();
614
// FIXME: this will keep ALL the external files, not just the ones that this part uses
615
emit alienPartUsed();
616
m_editingAlien = false;
622
void PartsEditorMainWindow::updateDateAndAuthor() {
623
m_createdByText->setText(FooterText.arg(m_author->text()).arg(m_createdOn->text()));
626
ModelPartShared* PartsEditorMainWindow::createModelPartShared() {
627
ModelPartShared* shared = new ModelPartShared();
629
if(m_moduleId.isNull() || m_moduleId.isEmpty()) {
630
m_moduleId = FolderUtils::getRandText();
633
shared->setModuleID(m_moduleId);
634
shared->setUri(m_uri);
635
shared->setVersion(m_version);
637
shared->setAuthor(m_author->text());
638
shared->setTitle(m_title->text());
639
shared->setDate(m_createdOn->text());
640
shared->setLabel(m_label->text());
641
//stuff->setTaxonomy(m_taxonomy->text());
642
shared->setDescription(m_description->text());
644
QStringList tags = m_tags->text().split(", ");
645
shared->setTags(tags);
646
shared->setProperties(m_properties->hash());
648
m_iconViewImage->aboutToSave(true);
649
m_views->aboutToSave();
651
// the deal seems to be that an original modelpart is created and becomes the official sketch model (root).
652
// the ConnectorsShared from that model are used to seed the PartsEditorConnectorsConnectorItems.
653
// When a new image is loaded into a view, the sketch model's ConnectorsShared are replaced with newly constructed ones.
654
// So now the sketch model points to one set of ConnectorsShared, but the original ones are still sitting
655
// back in the PartsEditorConnectorsConnectorItems. So now we replace the new ones with the old ones.
658
QList< QPointer<ConnectorShared> > connsShared = m_connsInfo->connectorsShared();
659
m_views->updatePinsInfo(connsShared);
660
shared->setConnectorsShared(m_connsInfo->connectorsShared());
665
void PartsEditorMainWindow::cleanUp() {
666
bool decUntitled = m_fwFilename.startsWith(untitledFileName());
668
if(m_lastOpened == this) {
669
UntitledPartIndex -= m_closedBeforeCount;
671
m_closedBeforeCount = 0;
673
m_closedBeforeCount++;
676
if(m_tempDir.path() != ".") {
677
FolderUtils::rmdir(m_tempDir);
682
void PartsEditorMainWindow::parentAboutToClose() {
683
if(beforeClosing(false)) {
688
void PartsEditorMainWindow::closeEvent(QCloseEvent *event) {
689
if(beforeClosing()) {
691
QMainWindow::closeEvent(event);
693
emit partUpdated(m_fwFilename, m_id, !m_savedAsNewPart &&
694
(m_connsInfo->connectorsCountChanged() || m_views->connectorsPosOrSizeChanged())
703
settings.setValue("peditor/state",saveState());
704
settings.setValue("peditor/geometry",saveGeometry());
707
const QDir& PartsEditorMainWindow::tempDir() {
708
return createTempFolderIfNecessary();
711
const QString PartsEditorMainWindow::untitledFileName() {
712
return UntitledPartName;
715
int &PartsEditorMainWindow::untitledFileCount() {
716
return UntitledPartIndex;
719
const QString PartsEditorMainWindow::fileExtension() {
720
return FritzingPartExtension;
723
const QString PartsEditorMainWindow::defaultSaveFolder() {
724
return QDir::currentPath()+"/parts/user/";
727
void PartsEditorMainWindow::updateSaveButton() {
728
if(m_saveButton) m_saveButton->setEnabled(m_updateEnabled);
731
bool PartsEditorMainWindow::wannaSaveAfterWarning(bool savingAsNew) {
733
bool errorFound = false;
734
QString msg = "Some errors found:\n";
735
if(!m_savedAsNewPart && !savingAsNew && m_connsInfo->connectorsRemoved()) {
737
msg += "- The connectors defined in this part have changed.\n"
738
"If you save it, you may break other sketches that already use it.\n";
741
if(m_connsInfo->hasMismatchingConnectors()) {
743
msg += "- Some connectors are not present in all views."
744
"If you save now, they will be removed.\n";
748
msg += "\nDo you want to save anyway?";
749
QMessageBox::StandardButton btn = QMessageBox::question(this,
750
tr("Updating existing part"),
752
QMessageBox::Yes|QMessageBox::No
754
doEmit = (btn == QMessageBox::Yes);
757
if(doEmit) emit saveButtonClicked();
762
void PartsEditorMainWindow::updateButtons() {
763
m_saveAsNewPartButton->setEnabled(false);
764
m_cancelCloseButton->setText(tr("close"));
767
bool PartsEditorMainWindow::eventFilter(QObject *object, QEvent *event) {
768
if (object == this && event->type() == QEvent::ShortcutOverride) {
769
QKeyEvent *keyEvent = dynamic_cast<QKeyEvent*>(event);
770
if(keyEvent && keyEvent->matches(QKeySequence::Close)) {
773
ProcessEventBlocker::processEvents();
775
FritzingWindow *parent = qobject_cast<FritzingWindow*>(parentWidget());
777
parent->notClosableForAWhile();
783
return QMainWindow::eventFilter(object, event);
786
const QString PartsEditorMainWindow::fritzingTitle() {
787
QString fritzing = FritzingWindow::fritzingTitle();
788
return tr("%1 %2").arg(fritzing).arg(___partsEditorName___);
791
bool PartsEditorMainWindow::event(QEvent * e) {
793
case QEvent::WindowActivate:
794
emit changeActivationSignal(true, this);
796
case QEvent::WindowDeactivate:
797
emit changeActivationSignal(false, this);
802
return FritzingWindow::event(e);
805
bool PartsEditorMainWindow::validateMinRequirements() {
806
if(!m_iconViewImage->isEmpty()) {
809
QMessageBox::information(this, tr("Icon needed"), tr("Please, provide an icon image for this part"));
814
void PartsEditorMainWindow::setViewItems(ItemBase * iiItem, ItemBase* bbItem, ItemBase* schemItem, ItemBase* pcbItem) {
816
m_breadboardItem = bbItem;
817
m_schematicItem = schemItem;
821
QString PartsEditorMainWindow::getExtensionString() {
822
return tr("Fritzing Parts (*%1)").arg(fileExtension());
825
QStringList PartsEditorMainWindow::getExtensions() {
826
QStringList extensions;
827
extensions.append(fileExtension());