1 /*******************************************************************
2
3 Part of the Fritzing project - http://fritzing.org
4 Copyright (c) 2007-2014 Fachhochschule Potsdam - http://fh-potsdam.de
5
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.
10
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.
15
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/>.
18
19 ********************************************************************
20
21 $Revision: 6962 $:
22 $Author: irascibl@gmail.com $:
23 $Date: 2013-04-14 00:08:36 +0200 (So, 14. Apr 2013) $
24
25 ********************************************************************/
26
27
28 #include <QVBoxLayout>
29 #include <QFileDialog>
30 #include <QMessageBox>
31 #include <QSettings>
32 #include <QtDebug>
33 #include <QInputDialog>
34 #include <QDropEvent>
35 #include <QMimeData>
36
37 #include "binmanager.h"
38 #include "stacktabwidget.h"
39 #include "stacktabbar.h"
40
41 #include "../../model/modelpart.h"
42 #include "../../mainwindow/mainwindow.h"
43 #include "../../model/palettemodel.h"
44 #include "../../waitpushundostack.h"
45 #include "../../debugdialog.h"
46 #include "../../utils/folderutils.h"
47 #include "../../utils/textutils.h"
48 #include "../../utils/fileprogressdialog.h"
49 #include "../../referencemodel/referencemodel.h"
50 #include "../../items/partfactory.h"
51 #include "../partsbinpalettewidget.h"
52 #include "../partsbinview.h"
53
54 ///////////////////////////////////////////////////////////
55
toString(BinLocation::Location location)56 QString BinLocation::toString(BinLocation::Location location) {
57 switch (location) {
58 case BinLocation::User:
59 return "user";
60 case BinLocation::More:
61 return "more";
62 case BinLocation::App:
63 return "app";
64 case BinLocation::Outside:
65 default:
66 return "outside";
67 }
68 }
69
fromString(const QString & locationString)70 BinLocation::Location BinLocation::fromString(const QString & locationString) {
71 if (locationString.compare("user", Qt::CaseInsensitive) == 0) return BinLocation::User;
72 if (locationString.compare("more", Qt::CaseInsensitive) == 0) return BinLocation::More;
73 if (locationString.compare("app", Qt::CaseInsensitive) == 0) return BinLocation::App;
74 return BinLocation::Outside;
75 }
76
findLocation(const QString & filename)77 BinLocation::Location BinLocation::findLocation(const QString & filename)
78 {
79
80 if (filename.startsWith(FolderUtils::getUserDataStorePath("bins"))) {
81 return BinLocation::User;
82 }
83 else if (filename.startsWith(FolderUtils::getApplicationSubFolderPath("bins") + "/more")) {
84 return BinLocation::More;
85 }
86 else if (filename.startsWith(FolderUtils::getApplicationSubFolderPath("bins"))) {
87 return BinLocation::App;
88 }
89
90 return BinLocation::Outside;
91 }
92 ///////////////////////////////////////////////////////////
93
94 QString BinManager::Title;
95 QString BinManager::MyPartsBinLocation;
96 QString BinManager::MyPartsBinTemplateLocation;
97 QString BinManager::SearchBinLocation;
98 QString BinManager::SearchBinTemplateLocation;
99 QString BinManager::ContribPartsBinLocation;
100 QString BinManager::TempPartsBinTemplateLocation;
101 QString BinManager::CorePartsBinLocation;
102
103 QString BinManager::StandardBinStyle = "background-color: gray;";
104 QString BinManager::CurrentBinStyle = "background-color: black;";
105
106 QHash<QString, QString> BinManager::StandardBinIcons;
107
BinManager(class ReferenceModel * referenceModel,class HtmlInfoView * infoView,WaitPushUndoStack * undoStack,MainWindow * parent)108 BinManager::BinManager(class ReferenceModel *referenceModel, class HtmlInfoView *infoView, WaitPushUndoStack *undoStack, MainWindow* parent)
109 : QFrame(parent)
110 {
111 BinManager::Title = tr("Parts");
112
113 m_combinedMenu = NULL;
114 m_showListViewAction = m_showIconViewAction = NULL;
115
116 m_referenceModel = referenceModel;
117 m_infoView = infoView;
118 m_undoStack = undoStack;
119 m_defaultSaveFolder = FolderUtils::getUserDataStorePath("bins");
120 m_mainWindow = parent;
121 m_currentBin = NULL;
122
123 connect(this, SIGNAL(savePartAsBundled(const QString &)), m_mainWindow, SLOT(saveBundledPart(const QString &)));
124
125 m_unsavedBinsCount = 0;
126
127 QVBoxLayout *lo = new QVBoxLayout(this);
128
129 m_stackTabWidget = new StackTabWidget(this);
130 m_stackTabWidget->setTabPosition(QTabWidget::West);
131 lo->addWidget(m_stackTabWidget);
132
133 lo->setMargin(0);
134 lo->setSpacing(0);
135 setMaximumHeight(500);
136 }
137
~BinManager()138 BinManager::~BinManager() {
139 }
140
initStandardBins()141 void BinManager::initStandardBins()
142 {
143 createCombinedMenu();
144 createContextMenus();
145
146 //DebugDialog::debug("init bin manager");
147 QList<BinLocation *> actualLocations;
148 findAllBins(actualLocations);
149
150 hackLocalContrib(actualLocations);
151
152 restoreStateAndGeometry(actualLocations);
153 foreach (BinLocation * location, actualLocations) {
154 PartsBinPaletteWidget* bin = newBin();
155 bin->load(location->path, m_mainWindow->fileProgressDialog(), true);
156 m_stackTabWidget->addTab(bin, bin->icon(), bin->title());
157 m_stackTabWidget->stackTabBar()->setTabToolTip(m_stackTabWidget->count() - 1, bin->title());
158 registerBin(bin);
159 delete location;
160 }
161 actualLocations.clear();
162
163 //DebugDialog::debug("open core bin");
164 openCoreBinIn();
165
166 //DebugDialog::debug("after core bin");
167 currentChanged(m_stackTabWidget->currentIndex());
168
169 connectTabWidget();
170 }
171
addBin(PartsBinPaletteWidget * bin)172 void BinManager::addBin(PartsBinPaletteWidget* bin) {
173 m_stackTabWidget->addTab(bin, bin->icon(), bin->title());
174 registerBin(bin);
175 setAsCurrentBin(bin);
176 }
177
registerBin(PartsBinPaletteWidget * bin)178 void BinManager::registerBin(PartsBinPaletteWidget* bin) {
179
180 if (!bin->fileName().isEmpty()) {
181 m_openedBins[bin->fileName()] = bin;
182
183 if (bin->fileName().compare(CorePartsBinLocation) == 0) {
184 bin->setAllowsChanges(false);
185 }
186 else if (bin->fileName().compare(SearchBinLocation) == 0) {
187 bin->setAllowsChanges(false);
188 }
189 else if (bin->fileName().compare(ContribPartsBinLocation) == 0) {
190 bin->setAllowsChanges(false);
191 }
192 else if (bin->fileName().compare(m_tempPartsBinLocation) == 0) {
193 bin->setAllowsChanges(false);
194 }
195 else if (bin->fileName().contains(FolderUtils::getApplicationSubFolderPath("bins"))) {
196 bin->setAllowsChanges(false);
197 }
198 }
199 }
200
connectTabWidget()201 void BinManager::connectTabWidget() {
202 connect(
203 m_stackTabWidget, SIGNAL(currentChanged(int)),
204 this, SLOT(currentChanged(int))
205 );
206 connect(
207 m_stackTabWidget, SIGNAL(tabCloseRequested(int)),
208 this, SLOT(tabCloseRequested(int))
209 );
210 }
211
insertBin(PartsBinPaletteWidget * bin,int index)212 void BinManager::insertBin(PartsBinPaletteWidget* bin, int index) {
213 registerBin(bin);
214 m_stackTabWidget->insertTab(index, bin, bin->icon(), bin->title());
215 m_stackTabWidget->setCurrentIndex(index);
216 }
217
beforeClosing()218 bool BinManager::beforeClosing() {
219 bool retval = true;
220
221 for(int j = 0; j < m_stackTabWidget->count(); j++) {
222 PartsBinPaletteWidget *bin = qobject_cast<PartsBinPaletteWidget*>(m_stackTabWidget->widget(j));
223 if (bin && !bin->fastLoaded()) {
224 setAsCurrentTab(bin);
225 retval = retval && bin->beforeClosing();
226 if(!retval) break;
227 }
228 }
229
230
231 if(retval) {
232 saveStateAndGeometry();
233 }
234
235 return retval;
236 }
237
setAsCurrentTab(PartsBinPaletteWidget * bin)238 void BinManager::setAsCurrentTab(PartsBinPaletteWidget* bin) {
239 m_stackTabWidget->setCurrentWidget(bin);
240 }
241
242
hasAlienParts()243 bool BinManager::hasAlienParts() {
244 return false;
245
246 }
247
setInfoViewOnHover(bool infoViewOnHover)248 void BinManager::setInfoViewOnHover(bool infoViewOnHover) {
249 Q_UNUSED(infoViewOnHover);
250 }
251
addNewPart(ModelPart * modelPart)252 void BinManager::addNewPart(ModelPart *modelPart) {
253 PartsBinPaletteWidget* myPartsBin = getOrOpenMyPartsBin();
254 myPartsBin->addPart(modelPart);
255 setDirtyTab(myPartsBin);
256 }
257
getOrOpenMyPartsBin()258 PartsBinPaletteWidget* BinManager::getOrOpenMyPartsBin() {
259 return getOrOpenBin(MyPartsBinLocation, MyPartsBinTemplateLocation);
260 }
261
getOrOpenSearchBin()262 PartsBinPaletteWidget* BinManager::getOrOpenSearchBin() {
263 PartsBinPaletteWidget * bin = getOrOpenBin(SearchBinLocation, SearchBinTemplateLocation);
264 if (bin) {
265 bin->setSaveQuietly(true);
266 }
267 return bin;
268 }
269
getOrOpenBin(const QString & binLocation,const QString & binTemplateLocation)270 PartsBinPaletteWidget* BinManager::getOrOpenBin(const QString & binLocation, const QString & binTemplateLocation) {
271
272 PartsBinPaletteWidget* partsBin = findBin(binLocation);
273
274 if(!partsBin) {
275 QString fileToOpen = QFileInfo(binLocation).exists() ? binLocation : createIfBinNotExists(binLocation, binTemplateLocation);
276 partsBin = openBinIn(fileToOpen, false);
277 }
278 if (partsBin != NULL && partsBin->fastLoaded()) {
279 partsBin->load(partsBin->fileName(), partsBin, false);
280 }
281
282 return partsBin;
283 }
284
findBin(const QString & binLocation)285 PartsBinPaletteWidget* BinManager::findBin(const QString & binLocation) {
286 for (int i = 0; i < m_stackTabWidget->count(); i++) {
287 PartsBinPaletteWidget* bin = (PartsBinPaletteWidget *) m_stackTabWidget->widget(i);
288 if(bin->fileName() == binLocation) {
289 return bin;
290 }
291 }
292
293 return NULL;
294 }
295
createIfMyPartsNotExists()296 QString BinManager::createIfMyPartsNotExists() {
297 return createIfBinNotExists(MyPartsBinLocation, MyPartsBinTemplateLocation);
298 }
299
createIfSearchNotExists()300 QString BinManager::createIfSearchNotExists() {
301 return createIfBinNotExists(SearchBinLocation, SearchBinTemplateLocation);
302 }
303
createIfBinNotExists(const QString & dest,const QString & source)304 QString BinManager::createIfBinNotExists(const QString & dest, const QString & source)
305 {
306 QString binPath = dest;
307 QFile file(source);
308 FolderUtils::slamCopy(file, binPath);
309 return binPath;
310 }
311
addPartToBin(ModelPart * modelPart,int position)312 void BinManager::addPartToBin(ModelPart *modelPart, int position) {
313 PartsBinPaletteWidget *bin = m_currentBin? m_currentBin: getOrOpenMyPartsBin();
314 addPartToBinAux(bin,modelPart,position);
315 }
316
addToMyParts(ModelPart * modelPart)317 void BinManager::addToMyParts(ModelPart *modelPart) {
318 PartsBinPaletteWidget *bin = getOrOpenMyPartsBin();
319 if (bin) {
320 addPartToBinAux(bin,modelPart);
321 setAsCurrentTab(bin);
322 }
323 }
324
addToTempPartsBin(ModelPart * modelPart)325 void BinManager::addToTempPartsBin(ModelPart *modelPart) {
326 PartsBinPaletteWidget *bin = getOrOpenBin(m_tempPartsBinLocation, TempPartsBinTemplateLocation);
327 if (bin) {
328 addPartToBinAux(bin,modelPart);
329 setAsCurrentTab(bin);
330 bin->setDirty(false);
331 }
332 }
333
hideTempPartsBin()334 void BinManager::hideTempPartsBin() {
335 for (int i = 0; i < m_stackTabWidget->count(); i++) {
336 PartsBinPaletteWidget* bin = (PartsBinPaletteWidget *) m_stackTabWidget->widget(i);
337 if (bin->fileName().compare(m_tempPartsBinLocation) == 0) {
338 m_stackTabWidget->removeTab(i);
339 break;
340 }
341 }
342 }
343
addPartToBinAux(PartsBinPaletteWidget * bin,ModelPart * modelPart,int position)344 void BinManager::addPartToBinAux(PartsBinPaletteWidget *bin, ModelPart *modelPart, int position) {
345 if(bin) {
346 if (bin->fastLoaded()) {
347 bin->load(bin->fileName(), bin, false);
348 }
349 bin->addPart(modelPart, position);
350 setDirtyTab(bin);
351 }
352 }
353
load(const QString & filename)354 void BinManager::load(const QString& filename) {
355 openBin(filename);
356 }
357
358
setDirtyTab(PartsBinPaletteWidget * w,bool dirty)359 void BinManager::setDirtyTab(PartsBinPaletteWidget* w, bool dirty) {
360 /*
361 if (!w->windowTitle().contains(FritzingWindow::QtFunkyPlaceholder)) {
362 // trying to deal with the warning in QWidget::setWindowModified
363 // but setting the title here doesn't work
364 QString t = w->windowTitle();
365 if (t.isEmpty()) t = " ";
366 w->setWindowTitle(t);
367 }
368 */
369 w->setWindowModified(dirty);
370 if(m_stackTabWidget != NULL) {
371 int tabIdx = m_stackTabWidget->indexOf(w);
372 m_stackTabWidget->setTabText(tabIdx, w->title()+(dirty? " *": ""));
373 } else {
374 qWarning() << tr("BinManager::setDirtyTab: Couldn't set the bin '%1' as dirty").arg(w->title());
375 }
376 }
377
updateTitle(PartsBinPaletteWidget * w,const QString & newTitle)378 void BinManager::updateTitle(PartsBinPaletteWidget* w, const QString& newTitle) {
379 if(m_stackTabWidget != NULL) {
380 m_stackTabWidget->setTabText(m_stackTabWidget->indexOf(w), newTitle+" *");
381 setDirtyTab(w);
382 }
383 else {
384 qWarning() << tr("BinManager::updateTitle: Couldn't set the bin '%1' as dirty").arg(w->title());
385 }
386 }
387
newBinIn()388 PartsBinPaletteWidget* BinManager::newBinIn() {
389 PartsBinPaletteWidget* bin = newBin();
390 bin->setPaletteModel(new PaletteModel(true, false), true);
391 bin->setTitle(tr("New bin (%1)").arg(++m_unsavedBinsCount));
392 insertBin(bin, m_stackTabWidget->count());
393 bin->setReadOnly(false);
394 renameBin();
395 return bin;
396 }
397
openBinIn(QString fileName,bool fastLoad)398 PartsBinPaletteWidget* BinManager::openBinIn(QString fileName, bool fastLoad) {
399 if(fileName.isNull() || fileName.isEmpty()) {
400 fileName = QFileDialog::getOpenFileName(
401 this,
402 tr("Select a Fritzing Parts Bin file to open"),
403 m_defaultSaveFolder,
404 tr("Fritzing Bin Files (*%1 *%2);;Fritzing Bin (*%1);;Fritzing Shareable Bin (*%2)")
405 .arg(FritzingBinExtension).arg(FritzingBundledBinExtension)
406 );
407 if (fileName.isNull()) return NULL;
408 }
409 PartsBinPaletteWidget* bin = NULL;
410 bool createNewOne = false;
411 if(m_openedBins.contains(fileName)) {
412 bin = m_openedBins[fileName];
413 if(m_stackTabWidget) {
414 m_stackTabWidget->setCurrentWidget(bin);
415 } else {
416 m_openedBins.remove(fileName);
417 createNewOne = true;
418 }
419 } else {
420 createNewOne = true;
421 }
422
423 if(createNewOne) {
424 bin = newBin();
425 if(bin->open(fileName, bin, fastLoad)) {
426 m_openedBins[fileName] = bin;
427 insertBin(bin, m_stackTabWidget->count());
428
429 // to force the user to take a decision of what to do with the imported parts
430 if(fileName.endsWith(FritzingBundledBinExtension)) {
431 setDirtyTab(bin);
432 }
433 }
434 }
435 if (!fastLoad) {
436 setAsCurrentBin(bin);
437 }
438 return bin;
439 }
440
openCoreBinIn()441 PartsBinPaletteWidget* BinManager::openCoreBinIn() {
442 PartsBinPaletteWidget* bin = findBin(CorePartsBinLocation);
443 if (bin != NULL) {
444 setAsCurrentTab(bin);
445 }
446 else {
447 bin = newBin();
448 bin->setAllowsChanges(false);
449 bin->load(BinManager::CorePartsBinLocation, bin, false);
450 insertBin(bin, 0);
451 }
452 setAsCurrentBin(bin);
453 return bin;
454 }
455
newBin()456 PartsBinPaletteWidget* BinManager::newBin() {
457 PartsBinPaletteWidget* bin = new PartsBinPaletteWidget(m_referenceModel, m_infoView, m_undoStack,this);
458 connect(
459 bin, SIGNAL(fileNameUpdated(PartsBinPaletteWidget*, const QString&, const QString&)),
460 this, SLOT(updateFileName(PartsBinPaletteWidget*, const QString&, const QString&))
461 );
462 connect(
463 bin, SIGNAL(focused(PartsBinPaletteWidget*)),
464 this, SLOT(setAsCurrentBin(PartsBinPaletteWidget*))
465 );
466 connect(bin, SIGNAL(saved(bool)), m_mainWindow, SLOT(binSaved(bool)));
467 connect(m_mainWindow, SIGNAL(alienPartsDismissed()), bin, SLOT(removeAlienParts()));
468
469 return bin;
470 }
471
currentChanged(int index)472 void BinManager::currentChanged(int index) {
473 for (int i = 0; i < m_stackTabWidget->count(); i++) {
474 PartsBinPaletteWidget* bin = (PartsBinPaletteWidget *) m_stackTabWidget->widget(i);
475 if (bin == NULL) continue;
476 if (!bin->hasMonoIcon()) continue;
477
478 if (i == index) {
479 m_stackTabWidget->setTabIcon(i, bin->icon());
480 }
481 else {
482 m_stackTabWidget->setTabIcon(i, bin->monoIcon());
483 }
484
485 }
486
487
488
489
490
491 PartsBinPaletteWidget *bin = getBin(index);
492 if (bin) setAsCurrentBin(bin);
493 }
494
setAsCurrentBin(PartsBinPaletteWidget * bin)495 void BinManager::setAsCurrentBin(PartsBinPaletteWidget* bin) {
496 if (bin == NULL) {
497 qWarning() << tr("Cannot set a NULL bin as the current one");
498 return;
499 }
500
501 if (bin->fastLoaded()) {
502 bin->load(bin->fileName(), bin, false);
503 }
504
505 if (m_currentBin == bin) return;
506
507 if (bin->fileName().compare(SearchBinLocation) == 0) {
508 bin->focusSearch();
509 }
510
511 /*
512
513 // jrc 3-july-2013 commented out this stylesheet change:
514 // it causes the tab bar to lose its scroll position
515 // the stylesheet change is commented out in the qss file, so visually it's a no-op
516
517 QString style = m_mainWindow->styleSheet();
518 if(m_currentBin && m_stackTabWidget) {
519 StackTabBar *currTabBar = m_stackTabWidget->stackTabBar();
520 currTabBar->setProperty("current","false");
521 currTabBar->setStyleSheet("");
522 currTabBar->setStyleSheet(style);
523 }
524 if(m_stackTabWidget) {
525 m_currentBin = bin;
526 StackTabBar *currTabBar = m_stackTabWidget->stackTabBar();
527 currTabBar->setProperty("current","true");
528 currTabBar->setStyleSheet("");
529 currTabBar->setStyleSheet(style);
530 }
531 */
532 }
533
closeBinIn(int index)534 void BinManager::closeBinIn(int index) {
535 if (m_stackTabWidget->count() == 1) return;
536
537 int realIndex = index == -1? m_stackTabWidget->currentIndex(): index;
538 PartsBinPaletteWidget *w = getBin(realIndex);
539 if(w && w->beforeClosing()) {
540 m_stackTabWidget->removeTab(realIndex);
541 m_openedBins.remove(w->fileName());
542 }
543 }
544
getBin(int index)545 PartsBinPaletteWidget* BinManager::getBin(int index) {
546 return qobject_cast<PartsBinPaletteWidget*>(m_stackTabWidget->widget(index));
547 }
548
currentBin()549 PartsBinPaletteWidget* BinManager::currentBin() {
550 return qobject_cast<PartsBinPaletteWidget*>(m_stackTabWidget->currentWidget());
551 }
552
updateFileName(PartsBinPaletteWidget * bin,const QString & newFileName,const QString & oldFilename)553 void BinManager::updateFileName(PartsBinPaletteWidget* bin, const QString &newFileName, const QString &oldFilename) {
554 m_openedBins.remove(oldFilename);
555 m_openedBins[newFileName] = bin;
556 }
557
saveStateAndGeometry()558 void BinManager::saveStateAndGeometry() {
559 QSettings settings;
560 settings.remove("bins2"); // clean up previous state
561 settings.beginGroup("bins2");
562
563 for(int j = m_stackTabWidget->count() - 1; j >= 0; j--) {
564 PartsBinPaletteWidget *bin = qobject_cast<PartsBinPaletteWidget*>(m_stackTabWidget->widget(j));
565 if (bin) {
566 settings.beginGroup(QString::number(j));
567 settings.setValue("location", BinLocation::toString(bin->location()));
568 settings.setValue("title", bin->title());
569 settings.setValue("path", bin->fileName());
570 settings.endGroup();
571 }
572 }
573
574 settings.endGroup();
575 }
576
restoreStateAndGeometry(QList<BinLocation * > & actualLocations)577 void BinManager::restoreStateAndGeometry(QList<BinLocation *> & actualLocations) {
578 QList<BinLocation *> theoreticalLocations;
579
580 QSettings settings;
581 settings.beginGroup("bins2");
582 int size = settings.childGroups().size();
583 if (size == 0) {
584 // first time
585 readTheoreticalLocations(theoreticalLocations);
586 }
587 else {
588 for (int i = 0; i < size; ++i) {
589 settings.beginGroup(QString::number(i));
590 BinLocation * location = new BinLocation;
591 location->location = BinLocation::fromString(settings.value("location").toString());
592 location->path = settings.value("path").toString();
593 location->title = settings.value("title").toString();
594 theoreticalLocations.append(location);
595 settings.endGroup();
596 }
597 }
598
599 foreach (BinLocation * location, actualLocations) {
600 location->marked = false;
601 }
602 foreach (BinLocation * tLocation, theoreticalLocations) {
603 foreach (BinLocation * aLocation, actualLocations) {
604 if (aLocation->title.compare(tLocation->title) == 0 && aLocation->location == tLocation->location) {
605 aLocation->marked = true;
606 break;
607 }
608 }
609 }
610
611 QList<BinLocation *> tempLocations(actualLocations);
612 actualLocations.clear();
613
614 foreach (BinLocation * tLocation, theoreticalLocations) {
615 tLocation->marked = false;
616 bool gotOne = false;
617
618 for (int ix = 0; ix < tempLocations.count(); ix++) {
619 BinLocation * aLocation = tempLocations[ix];
620 if (aLocation->title.compare(tLocation->title) == 0 && aLocation->location == tLocation->location) {
621 gotOne = true;
622 actualLocations.append(aLocation);
623 tempLocations.removeAt(ix);
624 //DebugDialog::debug("adding loc 1 " + aLocation->path);
625 break;
626 }
627 }
628 if (gotOne) continue;
629
630 if (tLocation->title == "___*___") {
631 for (int ix = 0; ix < tempLocations.count(); ix++) {
632 BinLocation * aLocation = tempLocations[ix];
633 if (!aLocation->marked && aLocation->location == tLocation->location) {
634 gotOne = true;
635 actualLocations.append(aLocation);
636 tempLocations.removeAt(ix);
637 //DebugDialog::debug("adding loc 2 " + aLocation->path);
638 break;
639 }
640 }
641 }
642 if (gotOne) continue;
643
644 if (!tLocation->path.isEmpty()) {
645 QFileInfo info(tLocation->path);
646 if (info.exists()) {
647 //DebugDialog::debug("adding loc 3 " + tLocation->path);
648 actualLocations.append(tLocation);
649 tLocation->marked = true;
650 }
651 }
652 }
653
654 foreach (BinLocation * tLocation, theoreticalLocations) {
655 if (!tLocation->marked) {
656 delete tLocation;
657 }
658 }
659
660 // catch the leftovers
661 actualLocations.append(tempLocations);
662 //foreach (BinLocation * aLocation, tempLocations) {
663 //DebugDialog::debug("adding loc 4 " + aLocation->path);
664 //}
665
666
667 }
668
readTheoreticalLocations(QList<BinLocation * > & theoreticalLocations)669 void BinManager::readTheoreticalLocations(QList<BinLocation *> & theoreticalLocations)
670 {
671 QFile file(":/resources/bins/order.xml");
672 QString errorStr;
673 int errorLine;
674 int errorColumn;
675 QDomDocument domDocument;
676
677 if (!domDocument.setContent(&file, true, &errorStr, &errorLine, &errorColumn)) {
678 DebugDialog::debug(QString("unable to parse order.xml: %1 %2 %3").arg(errorStr).arg(errorLine).arg(errorColumn));
679 return;
680 }
681
682 QDomElement bin = domDocument.documentElement().firstChildElement("bin");
683 while (!bin.isNull()) {
684 BinLocation * location = new BinLocation;
685 location->title = bin.attribute("title", "");
686 location->location = BinLocation::fromString(bin.attribute("location", ""));
687 theoreticalLocations.append(location);
688 bin = bin.nextSiblingElement("bin");
689 }
690 }
691
hackLocalContrib(QList<BinLocation * > & locations)692 void BinManager::hackLocalContrib(QList<BinLocation *> & locations)
693 {
694 // with release 0.7.12, there is no more local contrib bin
695 // so clear out existing local contrib bins by copying parts to mine bin
696
697 BinLocation * localContrib = NULL;
698 BinLocation * myParts = NULL;
699 foreach (BinLocation * location, locations) {
700 if (location->location == BinLocation::User) {
701 if (location->title == "Contributed Parts") {
702 localContrib = location;
703 }
704 else if (location->title == "My Parts") {
705 myParts = location;
706 }
707 }
708 }
709
710 if (localContrib == NULL) return;
711
712 if (myParts == NULL) {
713 createIfBinNotExists(MyPartsBinLocation, MyPartsBinTemplateLocation);
714 myParts = new BinLocation;
715 myParts->location = BinLocation::User;
716 myParts->path = MyPartsBinLocation;
717 QString icon;
718 getBinTitle(myParts->path, myParts->title, icon);
719 locations.append(myParts);
720 }
721
722 QString errorStr;
723 int errorLine;
724 int errorColumn;
725
726 QFile contribFile(localContrib->path);
727 QDomDocument contribDoc;
728 bool result = contribDoc.setContent(&contribFile, true, &errorStr, &errorLine, &errorColumn);
729 locations.removeOne(localContrib);
730 contribFile.close();
731 bool removed = contribFile.remove();
732 if (!removed) {
733 DebugDialog::debug("failed to remove contrib bin");
734 }
735
736 if (!result) return;
737
738 QFile myPartsFile(myParts->path);
739 QDomDocument myPartsDoc;
740 if (!myPartsDoc.setContent(&myPartsFile, true, &errorStr, &errorLine, &errorColumn)) {
741 return;
742 }
743
744 QDomElement myPartsRoot = myPartsDoc.documentElement();
745 QDomElement myPartsInstances = myPartsRoot.firstChildElement("instances");
746
747 bool changed = false;
748
749 QDomElement contribRoot = contribDoc.documentElement();
750 QDomElement contribInstances = contribRoot.firstChildElement("instances");
751 QDomElement contribInstance = contribInstances.firstChildElement("instance");
752 while (!contribInstance.isNull()) {
753 QString moduleIDRef = contribInstance.attribute("moduleIdRef");
754 QDomElement myPartsInstance = myPartsInstances.firstChildElement("instance");
755 bool already = false;
756 while (!myPartsInstance.isNull()) {
757 QString midr = myPartsInstance.attribute("moduleIdRef");
758 if (midr == moduleIDRef) {
759 already = true;
760 break;
761 }
762 myPartsInstance = myPartsInstance.nextSiblingElement("instance");
763 }
764
765 if (!already) {
766 QDomNode node = contribInstance.cloneNode(true);
767 myPartsInstances.appendChild(node);
768 changed = true;
769 }
770
771 contribInstance = contribInstance.nextSiblingElement("instance");
772 }
773
774 if (changed) {
775 TextUtils::writeUtf8(myParts->path, myPartsDoc.toString(0));
776 }
777 }
778
findAllBins(QList<BinLocation * > & locations)779 void BinManager::findAllBins(QList<BinLocation *> & locations)
780 {
781 BinLocation * location = new BinLocation;
782 location->location = BinLocation::App;
783 location->path = CorePartsBinLocation;
784 QString icon;
785 getBinTitle(location->path, location->title, icon);
786 locations.append(location);
787
788 location = new BinLocation;
789 location->location = BinLocation::App;
790 location->path = ContribPartsBinLocation;
791 getBinTitle(location->path, location->title, icon);
792 locations.append(location);
793
794 QDir userBinsDir(FolderUtils::getUserDataStorePath("bins"));
795 findBins(userBinsDir, locations, BinLocation::User);
796
797 QDir dir(FolderUtils::getApplicationSubFolderPath("bins"));
798 dir.cd("more");
799 findBins(dir, locations, BinLocation::More);
800 }
801
findBins(QDir & dir,QList<BinLocation * > & locations,BinLocation::Location loc)802 void BinManager::findBins(QDir & dir, QList<BinLocation *> & locations, BinLocation::Location loc) {
803
804 QStringList filters;
805 filters << "*"+FritzingBinExtension;
806 QFileInfoList files = dir.entryInfoList(filters);
807 foreach(QFileInfo info, files) {
808 BinLocation * location = new BinLocation;
809 location->path = info.absoluteFilePath();
810 location->location = loc;
811 QString icon;
812 getBinTitle(location->path, location->title, icon);
813 locations.append(location);
814 }
815 }
816
getBinTitle(const QString & filename,QString & binName,QString & iconName)817 bool BinManager::getBinTitle(const QString & filename, QString & binName, QString & iconName) {
818 QFile file(filename);
819 file.open(QFile::ReadOnly);
820 QXmlStreamReader xml(&file);
821 xml.setNamespaceProcessing(false);
822
823 while (!xml.atEnd()) {
824 switch (xml.readNext()) {
825 case QXmlStreamReader::StartElement:
826 if (xml.name().toString().compare("module") == 0) {
827 iconName = xml.attributes().value("icon").toString();
828 }
829 else if (xml.name().toString().compare("title") == 0) {
830 binName = xml.readElementText();
831 return true;
832 }
833 break;
834
835 default:
836 break;
837 }
838 }
839
840 return false;
841 }
842
tabCloseRequested(int index)843 void BinManager::tabCloseRequested(int index) {
844 closeBinIn(index);
845 }
846
addPartTo(PartsBinPaletteWidget * bin,ModelPart * mp,bool setDirty)847 void BinManager::addPartTo(PartsBinPaletteWidget* bin, ModelPart* mp, bool setDirty) {
848 if(mp) {
849 bool alreadyIn = bin->contains(mp->moduleID());
850 bin->addPart(mp);
851 if(!alreadyIn && setDirty) {
852 setDirtyTab(bin,true);
853 }
854 }
855 }
856
editSelectedPartNewFrom(PartsBinPaletteWidget * bin)857 void BinManager::editSelectedPartNewFrom(PartsBinPaletteWidget* bin) {
858 ItemBase * itemBase = bin->selectedItemBase();
859 m_mainWindow->getPartsEditorNewAnd(itemBase);
860 }
861
isTabReorderingEvent(QDropEvent * event)862 bool BinManager::isTabReorderingEvent(QDropEvent* event) {
863 const QMimeData *m = event->mimeData();
864 QStringList formats = m->formats();
865 return formats.contains("action") && (m->data("action") == "tab-reordering");
866 }
867
getSelectedModuleIDFromSketch()868 const QString &BinManager::getSelectedModuleIDFromSketch() {
869 return m_mainWindow->selectedModuleID();
870 }
871
openedBinsActions(const QString & moduleId)872 QList<QAction*> BinManager::openedBinsActions(const QString &moduleId) {
873 QMap<QString,QAction*> titlesAndActions; // QMap sorts values by key
874
875 for (int i = 0; i < m_stackTabWidget->count(); i++) {
876 PartsBinPaletteWidget* pppw = (PartsBinPaletteWidget *) m_stackTabWidget->widget(i);
877 if (pppw->readOnly()) continue;
878
879 QAction *act = pppw->addPartToMeAction();
880 act->setEnabled(!pppw->contains(moduleId));
881 titlesAndActions[pppw->title()] = act;
882 }
883
884 return titlesAndActions.values();
885 }
886
openBin(const QString & filename)887 void BinManager::openBin(const QString &filename) {
888 openBinIn(filename, false);
889 }
890
mainWindow()891 MainWindow* BinManager::mainWindow() {
892 return m_mainWindow;
893 }
894
initNames()895 void BinManager::initNames() {
896 BinManager::MyPartsBinLocation = FolderUtils::getUserDataStorePath("bins")+"/my_parts.fzb";
897 BinManager::MyPartsBinTemplateLocation =":/resources/bins/my_parts.fzb";
898 BinManager::SearchBinLocation = FolderUtils::getUserDataStorePath("bins")+"/search.fzb";
899 BinManager::SearchBinTemplateLocation =":/resources/bins/search.fzb";
900 BinManager::ContribPartsBinLocation = FolderUtils::getApplicationSubFolderPath("bins")+"/contribParts.fzb";
901 BinManager::CorePartsBinLocation = FolderUtils::getApplicationSubFolderPath("bins")+"/core.fzb";
902 BinManager::TempPartsBinTemplateLocation =":/resources/bins/temp.fzb";
903
904 StandardBinIcons.insert(BinManager::MyPartsBinLocation, "Mine.png");
905 StandardBinIcons.insert(BinManager::SearchBinLocation, "Search.png");
906 StandardBinIcons.insert(BinManager::ContribPartsBinLocation, "Contrib.png");
907 StandardBinIcons.insert(BinManager::CorePartsBinLocation, "Core.png");
908 }
909
search(const QString & searchText)910 void BinManager::search(const QString & searchText) {
911 PartsBinPaletteWidget * searchBin = getOrOpenSearchBin();
912 if (searchBin == NULL) return;
913
914 FileProgressDialog progress(tr("Searching..."), 0, this);
915 progress.setIncValueMod(10);
916 connect(m_referenceModel, SIGNAL(addSearchMaximum(int)), &progress, SLOT(addMaximum(int)));
917 connect(m_referenceModel, SIGNAL(incSearch()), &progress, SLOT(incValue()));
918
919 QList<ModelPart *> modelParts = m_referenceModel->search(searchText, false);
920
921 progress.setIncValueMod(1);
922 searchBin->removeParts();
923 foreach (ModelPart * modelPart, modelParts) {
924 //DebugDialog::debug(modelPart->title());
925 if (modelPart->itemType() == ModelPart::SchematicSubpart) {
926 }
927 else if (modelPart->moduleID().contains(PartFactory::OldSchematicPrefix)) {
928 }
929 else {
930 this->addPartTo(searchBin, modelPart, false);
931 }
932 progress.incValue();
933 }
934
935 setDirtyTab(searchBin);
936 }
937
currentViewIsIconView()938 bool BinManager::currentViewIsIconView() {
939 PartsBinPaletteWidget * bin = currentBin();
940 if (bin == NULL) return true;
941
942 return bin->currentViewIsIconView();
943 }
944
toIconView()945 void BinManager::toIconView() {
946 PartsBinPaletteWidget * bin = currentBin();
947 if (bin == NULL) return;
948
949 bin->toIconView();
950 }
951
toListView()952 void BinManager::toListView() {
953 PartsBinPaletteWidget * bin = currentBin();
954 if (bin == NULL) return;
955
956 bin->toListView();
957 }
958
updateBinCombinedMenuCurrent()959 void BinManager::updateBinCombinedMenuCurrent() {
960 PartsBinPaletteWidget * bin = currentBin();
961 if (bin == NULL) return;
962
963 updateBinCombinedMenu(bin);
964 }
965
updateBinCombinedMenu(PartsBinPaletteWidget * bin)966 void BinManager::updateBinCombinedMenu(PartsBinPaletteWidget * bin) {
967 if (m_combinedMenu == NULL) return;
968
969 m_saveBinAction->setEnabled(bin->allowsChanges());
970 m_renameBinAction->setEnabled(bin->canClose());
971 m_closeBinAction->setEnabled(bin->canClose());
972 m_deleteBinAction->setEnabled(bin->canClose());
973 ItemBase *itemBase = bin->selectedItemBase();
974 bool enabled = (itemBase != NULL);
975 m_editPartNewAction->setEnabled(enabled && itemBase->canEditPart());
976
977 bool enableAnyway = false;
978 #ifndef QT_NO_DEBUG
979 enableAnyway = true;
980 #endif
981 m_exportPartAction->setEnabled(enabled && (!itemBase->modelPart()->isCore() || enableAnyway));
982 m_removePartAction->setEnabled(enabled && bin->allowsChanges());
983 m_findPartAction->setEnabled(enabled);
984 }
985
createCombinedMenu()986 void BinManager::createCombinedMenu()
987 {
988 m_combinedMenu = new QMenu(tr("Bin"), this);
989
990 m_openAction = new QAction(tr("Import..."), this);
991 m_openAction->setStatusTip(tr("Load a Fritzing part (.fzpz), or a Fritzing parts bin (.fzb, .fzbz)"));
992 connect(m_openAction, SIGNAL(triggered()), this, SLOT(mainLoad()));
993
994 m_newBinAction = new QAction(tr("New Bin..."), this);
995 m_newBinAction->setStatusTip(tr("Create a new parts bin"));
996 connect(m_newBinAction, SIGNAL(triggered()),this, SLOT(newBinIn()));
997
998 m_closeBinAction = new QAction(tr("Close Bin"), this);
999 m_closeBinAction->setStatusTip(tr("Close parts bin"));
1000 connect(m_closeBinAction, SIGNAL(triggered()),this, SLOT(closeBin()));
1001
1002 m_deleteBinAction = new QAction(tr("Delete Bin"), this);
1003 m_deleteBinAction->setStatusTip(tr("Delete parts bin"));
1004 connect(m_deleteBinAction, SIGNAL(triggered()),this, SLOT(deleteBin()));
1005
1006 m_saveBinAction = new QAction(tr("Save Bin"), this);
1007 m_saveBinAction->setStatusTip(tr("Save parts bin"));
1008 connect(m_saveBinAction, SIGNAL(triggered()),this, SLOT(saveBin()));
1009
1010 m_saveBinAsAction = new QAction(tr("Save Bin As..."), this);
1011 m_saveBinAsAction->setStatusTip(tr("Save parts bin as..."));
1012 connect(m_saveBinAsAction, SIGNAL(triggered()),this, SLOT(saveBinAs()));
1013
1014 m_saveBinAsBundledAction = new QAction(tr("Export Bin..."), this);
1015 m_saveBinAsBundledAction->setStatusTip(tr("Save parts bin in compressed format..."));
1016 connect(m_saveBinAsBundledAction, SIGNAL(triggered()),this, SLOT(saveBundledBin()));
1017
1018 m_renameBinAction = new QAction(tr("Rename Bin..."), this);
1019 m_renameBinAction->setStatusTip(tr("Rename parts bin..."));
1020 connect(m_renameBinAction, SIGNAL(triggered()),this, SLOT(renameBin()));
1021
1022 m_copyToSketchAction = new QAction(tr("Copy to Sketch"), this);
1023 m_copyToSketchAction->setStatusTip(tr("Copy all the parts in the bin to a sketch"));
1024 connect(m_copyToSketchAction, SIGNAL(triggered()),this, SLOT(copyToSketch()));
1025
1026 m_copyAllToSketchAction = new QAction(tr("Copy all to Sketch"), this);
1027 m_copyAllToSketchAction->setStatusTip(tr("Copy all loaded parts to the sketch"));
1028 connect(m_copyAllToSketchAction, SIGNAL(triggered()),this, SLOT(copyAllToSketch()));
1029
1030 m_showListViewAction = new QAction(tr("Show Bin in List View"), this);
1031 m_showListViewAction->setCheckable(true);
1032 m_showListViewAction->setStatusTip(tr("Display parts as a list"));
1033 connect(m_showListViewAction, SIGNAL(triggered()),this, SLOT(toListView()));
1034
1035 m_showIconViewAction = new QAction(tr("Show Bin in Icon View"), this);
1036 m_showIconViewAction->setCheckable(true);
1037 m_showIconViewAction->setStatusTip(tr("Display parts as icons"));
1038 connect(m_showIconViewAction, SIGNAL(triggered()),this, SLOT(toIconView()));
1039
1040 m_combinedMenu->addAction(m_openAction);
1041 m_combinedMenu->addSeparator();
1042
1043 m_combinedMenu->addAction(m_newBinAction);
1044 m_combinedMenu->addAction(m_closeBinAction);
1045 m_combinedMenu->addAction(m_deleteBinAction);
1046 m_combinedMenu->addAction(m_saveBinAction);
1047 m_combinedMenu->addAction(m_saveBinAsAction);
1048 m_combinedMenu->addAction(m_saveBinAsBundledAction);
1049 m_combinedMenu->addAction(m_renameBinAction);
1050 #ifndef QT_NO_DEBUG
1051 m_combinedMenu->addAction(m_copyToSketchAction);
1052 m_combinedMenu->addAction(m_copyAllToSketchAction);
1053 #endif
1054 m_combinedMenu->addSeparator();
1055 m_combinedMenu->addAction(m_showIconViewAction);
1056 m_combinedMenu->addAction(m_showListViewAction);
1057
1058 m_editPartNewAction = new QAction(tr("Edit Part (new parts editor)..."),this);
1059 m_exportPartAction = new QAction(tr("Export Part..."),this);
1060 m_removePartAction = new QAction(tr("Remove Part"),this);
1061 m_findPartAction = new QAction(tr("Find Part in Sketch"),this);
1062
1063 connect(m_editPartNewAction, SIGNAL(triggered()),this, SLOT(editSelectedNew()));
1064 connect(m_exportPartAction, SIGNAL(triggered()),this, SLOT(exportSelected()));
1065 connect(m_removePartAction, SIGNAL(triggered()),this, SLOT(removeSelected()));
1066 connect(m_findPartAction, SIGNAL(triggered()),this, SLOT(findSelected()));
1067
1068 connect(m_combinedMenu, SIGNAL(aboutToShow()), this, SLOT(updateBinCombinedMenuCurrent()));
1069
1070 m_combinedMenu->addSeparator();
1071 m_combinedMenu->addAction(m_editPartNewAction);
1072 m_combinedMenu->addAction(m_exportPartAction);
1073 m_combinedMenu->addAction(m_removePartAction);
1074 m_combinedMenu->addAction(m_findPartAction);
1075
1076 }
1077
createContextMenus()1078 void BinManager::createContextMenus() {
1079 m_binContextMenu = new QMenu(this);
1080 m_binContextMenu->addAction(m_closeBinAction);
1081 m_binContextMenu->addAction(m_deleteBinAction);
1082 m_binContextMenu->addAction(m_saveBinAction);
1083 m_binContextMenu->addAction(m_saveBinAsAction);
1084 m_binContextMenu->addAction(m_saveBinAsBundledAction);
1085 m_binContextMenu->addAction(m_renameBinAction);
1086
1087 m_partContextMenu = new QMenu(this);
1088 m_partContextMenu->addAction(m_editPartNewAction);
1089 m_partContextMenu->addAction(m_exportPartAction);
1090 m_partContextMenu->addAction(m_removePartAction);
1091 m_partContextMenu->addAction(m_findPartAction);
1092 }
1093
closeBin()1094 void BinManager::closeBin() {
1095 closeBinIn(-1);
1096 }
1097
deleteBin()1098 void BinManager::deleteBin() {
1099 PartsBinPaletteWidget * bin = currentBin();
1100 if (bin == NULL) return;
1101
1102 QMessageBox::StandardButton answer = QMessageBox::question(
1103 this,
1104 tr("Delete bin"),
1105 tr("Do you really want to delete bin '%1'? This action cannot be undone.").arg(bin->title()),
1106 QMessageBox::Yes | QMessageBox::No,
1107 QMessageBox::No
1108 );
1109 // TODO: make button texts translatable
1110 if (answer != QMessageBox::Yes) return;
1111
1112 QString filename = bin->fileName();
1113 closeBinIn(-1);
1114 QFile::remove(filename);
1115 }
1116
importPartToMineBin(const QString & filename)1117 void BinManager::importPartToMineBin(const QString & filename) {
1118
1119 if (!filename.isEmpty() && !filename.isNull()) {
1120 PartsBinPaletteWidget * bin = getOrOpenBin(MyPartsBinLocation, MyPartsBinTemplateLocation);
1121 if (bin == NULL) return;
1122
1123 setAsCurrentTab(bin);
1124 importPart(filename, bin);
1125 }
1126 }
1127
importPartToCurrentBin(const QString & filename)1128 void BinManager::importPartToCurrentBin(const QString & filename) {
1129
1130 if (!filename.isEmpty() && !filename.isNull()) {
1131 PartsBinPaletteWidget * bin = currentBin();
1132 if (bin == NULL) return;
1133
1134 importPart(filename, bin);
1135 }
1136 }
1137
importPart(const QString & filename,PartsBinPaletteWidget * bin)1138 void BinManager::importPart(const QString & filename, PartsBinPaletteWidget * bin) {
1139 ModelPart *mp = m_mainWindow->loadBundledPart(filename, !bin->allowsChanges());
1140 if (bin->allowsChanges()) {
1141 addPartTo(bin, mp, true);
1142 }
1143 }
1144
editSelectedNew()1145 void BinManager::editSelectedNew() {
1146 editSelectedPartNewFrom(currentBin());
1147 }
1148
renameBin()1149 void BinManager::renameBin() {
1150 PartsBinPaletteWidget * bin = currentBin();
1151 if (bin == NULL) return;
1152
1153 if (!currentBin()->allowsChanges()) {
1154 // TODO: disable menu item instead
1155 QMessageBox::warning(this, tr("Read-only bin"), tr("This bin cannot be renamed."));
1156 return;
1157 }
1158
1159 bool ok;
1160 QString newTitle = QInputDialog::getText(
1161 this,
1162 tr("Rename bin"),
1163 tr("Please choose a name for the bin:"),
1164 QLineEdit::Normal,
1165 bin->title(),
1166 &ok
1167 );
1168 if(ok) {
1169 bin->setTitle(newTitle);
1170 m_stackTabWidget->stackTabBar()->setTabToolTip(m_stackTabWidget->currentIndex(), newTitle);
1171 bin->addPartToMeAction()->setText(newTitle);
1172 updateTitle(bin, newTitle);
1173 }
1174 }
1175
saveBin()1176 void BinManager::saveBin() {
1177 PartsBinPaletteWidget * bin = currentBin();
1178 if (bin == NULL) return;
1179
1180 bool result = bin->save();
1181 if (result) setDirtyTab(currentBin(),false);
1182 }
1183
saveBinAs()1184 void BinManager::saveBinAs() {
1185 PartsBinPaletteWidget * bin = currentBin();
1186 if (bin == NULL) return;
1187
1188 bin->saveAs();
1189 }
1190
1191
updateViewChecks(bool iconView)1192 void BinManager::updateViewChecks(bool iconView) {
1193 if (m_showListViewAction == NULL) return;
1194 if (m_showIconViewAction == NULL) return;
1195
1196 if (iconView) {
1197 m_showListViewAction->setChecked(false);
1198 m_showIconViewAction->setChecked(true);
1199 }
1200 else {
1201 m_showListViewAction->setChecked(true);
1202 m_showIconViewAction->setChecked(false);
1203 }
1204 }
1205
binContextMenu(PartsBinPaletteWidget * bin)1206 QMenu * BinManager::binContextMenu(PartsBinPaletteWidget * bin) {
1207 updateBinCombinedMenu(bin);
1208 return m_binContextMenu;
1209 }
1210
partContextMenu(PartsBinPaletteWidget * bin)1211 QMenu * BinManager::partContextMenu(PartsBinPaletteWidget * bin) {
1212 updateBinCombinedMenu(bin);
1213 return m_partContextMenu;
1214 }
1215
combinedMenu(PartsBinPaletteWidget * bin)1216 QMenu * BinManager::combinedMenu(PartsBinPaletteWidget * bin) {
1217 updateBinCombinedMenu(bin);
1218 return m_combinedMenu;
1219 }
1220
combinedMenu()1221 QMenu * BinManager::combinedMenu() {
1222 return m_combinedMenu;
1223 }
1224
removeSelected()1225 bool BinManager::removeSelected() {
1226 PartsBinPaletteWidget * bin = currentBin();
1227 if (bin == NULL) return false;
1228
1229 ModelPart * mp = bin->selectedModelPart();
1230 if (mp == NULL) return false;
1231
1232 if (m_mainWindow->anyUsePart(mp->moduleID())) {
1233 QMessageBox::warning(this, tr("Remove from Bin"), tr("Unable to remove part '%1'--it is in use in a sketch").arg(mp->title()));
1234 return false;
1235 }
1236
1237 QMessageBox::StandardButton answer = QMessageBox::question(
1238 this,
1239 tr("Remove from bin"),
1240 tr("Do you really want to remove '%1' from the bin? This operation cannot be undone.").arg(mp->title()),
1241 QMessageBox::Yes | QMessageBox::No,
1242 QMessageBox::No
1243 );
1244 // TODO: make button texts translatable
1245 if(answer != QMessageBox::Yes) return false;
1246
1247
1248 m_undoStack->push(new QUndoCommand("Parts bin: part removed"));
1249 bin->removePart(mp->moduleID(), mp->path());
1250 bin->setDirty();
1251
1252 return true;
1253 }
1254
findSelected()1255 void BinManager::findSelected() {
1256 PartsBinPaletteWidget * bin = currentBin();
1257 if (bin == NULL) return;
1258
1259 ModelPart * mp = bin->selectedModelPart();
1260 if (mp == NULL) return;
1261
1262 m_mainWindow->selectPartsWithModuleID(mp);
1263 }
1264
1265
exportSelected()1266 void BinManager::exportSelected() {
1267 PartsBinPaletteWidget * bin = currentBin();
1268 if (bin == NULL) return;
1269
1270 ModelPart * mp = bin->selectedModelPart();
1271 if (mp == NULL) return;
1272
1273 emit savePartAsBundled(mp->moduleID());
1274 }
1275
saveBundledBin()1276 void BinManager::saveBundledBin() {
1277 PartsBinPaletteWidget * bin = currentBin();
1278 if (bin == NULL) return;
1279
1280 bin->saveBundledBin();
1281 }
1282
setTabIcon(PartsBinPaletteWidget * w,QIcon * icon)1283 void BinManager::setTabIcon(PartsBinPaletteWidget* w, QIcon * icon)
1284 {
1285 if (m_stackTabWidget != NULL) {
1286 int tabIdx = m_stackTabWidget->indexOf(w);
1287 m_stackTabWidget->setTabIcon(tabIdx, *icon);
1288 }
1289 }
1290
copyFilesToContrib(ModelPart * mp,QWidget * originator)1291 void BinManager::copyFilesToContrib(ModelPart * mp, QWidget * originator) {
1292 PartsBinPaletteWidget * bin = qobject_cast<PartsBinPaletteWidget *>(originator);
1293 if (bin == NULL) return;
1294
1295 if (bin->fileName().compare(m_tempPartsBinLocation) != 0) return; // only copy from temp bin
1296
1297 QString path = mp->path();
1298 if (path.isEmpty()) return;
1299
1300 QFileInfo info(path);
1301 QFile fzp(path);
1302
1303 QString parts = FolderUtils::getUserDataStorePath("parts");
1304 FolderUtils::slamCopy(fzp, parts + "/contrib/" + info.fileName());
1305 QString prefix = parts + "/svg/contrib/";
1306
1307 QDir dir = info.absoluteDir();
1308 dir.cdUp();
1309 dir.cd("svg");
1310 dir.cd("contrib");
1311
1312 QList<ViewLayer::ViewID> viewIDs;
1313 viewIDs << ViewLayer::IconView << ViewLayer::BreadboardView << ViewLayer::SchematicView << ViewLayer::PCBView;
1314 foreach (ViewLayer::ViewID viewID, viewIDs) {
1315 QString fn = mp->hasBaseNameFor(viewID);
1316 if (!fn.isEmpty()) {
1317 QFile svg(dir.absoluteFilePath(fn));
1318 FolderUtils::slamCopy(svg, prefix + fn);
1319 }
1320 }
1321 }
1322
isTempPartsBin(PartsBinPaletteWidget * bin)1323 bool BinManager::isTempPartsBin(PartsBinPaletteWidget * bin) {
1324 return bin->fileName().compare(m_tempPartsBinLocation) == 0;
1325 }
1326
setTempPartsBinLocation(const QString & name)1327 void BinManager::setTempPartsBinLocation(const QString & name) {
1328 m_tempPartsBinLocation = name;
1329 //StandardBinIcons.insert(m_tempPartsBinLocation, "Temp.png");
1330 }
1331
mainLoad()1332 void BinManager::mainLoad() {
1333 QString path = m_defaultSaveFolder;
1334
1335 QString fileName = FolderUtils::getOpenFileName(
1336 this,
1337 tr("Select a Fritzing File to Open"),
1338 path,
1339 tr("Fritzing Files (*%1 *%2 *%3);;Fritzing Part (*%1);;Fritzing Bin (*%2);;Fritzing Shareable Bin (*%3)")
1340 .arg(FritzingBundledPartExtension)
1341 .arg(FritzingBinExtension)
1342 .arg(FritzingBundledBinExtension)
1343 );
1344
1345 if (fileName.isEmpty()) return;
1346
1347 if (fileName.endsWith(FritzingBundledPartExtension)) {
1348 importPartToCurrentBin(fileName);
1349 return;
1350 }
1351
1352 if (fileName.endsWith(FritzingBinExtension) || fileName.endsWith(FritzingBundledBinExtension)) {
1353 openBinIn(fileName, false);
1354 }
1355 }
1356
hideTabBar()1357 void BinManager::hideTabBar()
1358 {
1359 m_stackTabWidget->stackTabBar()->hide();
1360 }
1361
reloadPart(const QString & moduleID)1362 void BinManager::reloadPart(const QString & moduleID) {
1363 PartsBinView::removePartReference(moduleID);
1364 for(int j = 0; j < m_stackTabWidget->count(); j++) {
1365 PartsBinPaletteWidget *bin = qobject_cast<PartsBinPaletteWidget*>(m_stackTabWidget->widget(j));
1366 if (bin == NULL) continue;
1367
1368 bin->reloadPart(moduleID);
1369 }
1370 }
1371
copyToSketch()1372 void BinManager::copyToSketch() {
1373 PartsBinPaletteWidget * bin = currentBin();
1374 if (bin == NULL) return;
1375
1376 QList<ModelPart *> modelParts = bin->getAllParts();
1377 if (modelParts.count() == 0) return;
1378
1379 if (m_mainWindow) {
1380 m_mainWindow->addToSketch(modelParts);
1381 }
1382 }
1383
copyAllToSketch()1384 void BinManager::copyAllToSketch() {
1385 QList<ModelPart *> modelParts;
1386
1387 if (m_mainWindow) {
1388 m_mainWindow->addToSketch(modelParts);
1389 }
1390 }
1391
1392