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.floadfrom
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: 6956 $:
22 $Author: irascibl@gmail.com $:
23 $Date: 2013-04-07 12:14:50 +0200 (So, 07. Apr 2013) $
24
25 ********************************************************************/
26
27 // copying a table from one SQWL database to another http://sqlite.phxsoftware.com/forums/t/285.aspx
28
29 #include <QSqlRecord>
30 #include <QSqlError>
31 #include <QMessageBox>
32 #include <QVector>
33 #include <QSqlResult>
34 #include <limits>
35
36 #include "sqlitereferencemodel.h"
37 #include "../debugdialog.h"
38 #include "../connectors/svgidlayer.h"
39 #include "../connectors/connector.h"
40 #include "../connectors/connectorshared.h"
41 #include "../connectors/busshared.h"
42 #include "../utils/folderutils.h"
43 #include "../utils/fmessagebox.h"
44
45
46 #define MAX_CONN_TRIES 3
47
48 static const qulonglong NO_ID = std::numeric_limits<qulonglong>::max();
49
debugError(bool result,QSqlQuery & query)50 void debugError(bool result, QSqlQuery & query) {
51 if (result) return;
52
53 QSqlError error = query.lastError();
54 DebugDialog::debug(QString("%1 %2 %3").arg(error.text()).arg(error.number()).arg(error.type()));
55 }
56
57 static ModelPart * DebugModelPart = NULL;
58
debugExec(const QString & msg,QSqlQuery & query)59 void debugExec(const QString & msg, QSqlQuery & query) {
60 DebugDialog::debug(
61 "SQLITE: " + msg + "\n"
62 "\t "+ query.lastQuery() + "\n"
63 "\t ERROR DRIVER: "+ query.lastError().driverText() + "\n"
64 "\t ERROR DB: " + query.lastError().databaseText() + "\n"
65 "\t moduleid:" + (DebugModelPart == NULL ? "" : DebugModelPart->moduleID()) + ""
66 );
67 QMap<QString, QVariant> map = query.boundValues();
68 foreach (QString name, map.keys()) {
69 DebugDialog::debug(QString("\t%1:%2").arg(name).arg(map.value(name).toString()));
70 }
71 }
72
killConnectors(QVector<Connector * > & connectors)73 void killConnectors(QVector<Connector *> & connectors) {
74 foreach (Connector * connector, connectors) {
75 delete connector->connectorShared();
76 delete connector;
77 }
78 connectors.clear();
79 }
80
killBuses(QVector<BusShared * > & buses)81 void killBuses(QVector<BusShared *> & buses) {
82 foreach (BusShared * bus, buses) {
83 delete bus;
84 }
85 buses.clear();
86 }
87
88 QStringList FailurePartMessages;
89 QStringList FailurePropertyMessages;
90
noSwappingMessage()91 void noSwappingMessage()
92 {
93 FMessageBox::warning(NULL,
94 QObject::tr("Oops!"),
95 QObject::tr("Sorry, we have a problem with the swapping mechanism.\nFritzing still works, but you won't be able to change parts properties."),
96 QMessageBox::Ok);
97 }
98
99 ///////////////////////////////////////////////////
100
SqliteReferenceModel()101 SqliteReferenceModel::SqliteReferenceModel() {
102 m_swappingEnabled = false;
103 m_lastWasExactMatch = true;
104 }
105
loadAll(const QString & databaseName,bool fullLoad,bool dbExists)106 bool SqliteReferenceModel::loadAll(const QString & databaseName, bool fullLoad, bool dbExists)
107 {
108 FailurePartMessages.clear();
109 FailurePropertyMessages.clear();
110 m_fullLoad = fullLoad;
111 initParts(dbExists);
112
113 int tries = 0;
114 m_keepGoing = true;
115 while(!m_swappingEnabled && tries < MAX_CONN_TRIES && m_keepGoing) {
116 createConnection(databaseName, fullLoad);
117 if(!m_swappingEnabled) {
118 deleteConnection();
119 }
120 tries++;
121 }
122 /* TODO Mariano: perhaps we should check that there are no parts with
123 * the same family and providing exactly the same properties set
124 */
125
126 if (!m_swappingEnabled) {
127 noSwappingMessage();
128 }
129 else if (FailurePartMessages.count() > 0) {
130 QString message = tr("The swapping mechanism is disabled for:\n\n");
131 if (FailurePartMessages.count() == 1) {
132 message += FailurePartMessages.at(0);
133 }
134 else if (FailurePartMessages.count() < 6) {
135 message += FailurePartMessages.join("\n");
136 }
137 else {
138 for (int i = 0; i < 4; i++) {
139 message += FailurePartMessages.at(i);
140 message += ("\n");
141 }
142 message += "\n" + tr("and %1 other parts").arg(FailurePartMessages.count() - 4);
143 }
144 FMessageBox::warning(NULL, QObject::tr("Oops!"), message, QMessageBox::Ok);
145 }
146 else if (FailurePropertyMessages.count() > 0) {
147 QString message = tr("The swapping mechanism is disabled for:\n\n");
148 if (FailurePropertyMessages.count() == 1) {
149 message += FailurePropertyMessages.at(0);
150 }
151 else if (FailurePropertyMessages.count() < 6) {
152 message += FailurePropertyMessages.join("\n");
153 }
154 else {
155 for (int i = 0; i < 4; i++) {
156 message += FailurePropertyMessages.at(i);
157 message += ("\n");
158 }
159 message += "\n" + tr("and %1 other properties").arg(FailurePropertyMessages.count() - 4);
160 }
161 FMessageBox::warning(NULL, QObject::tr("Oops!"), message, QMessageBox::Ok);
162 }
163 return m_swappingEnabled;
164
165 }
166
loadFromDB(const QString & databaseName)167 bool SqliteReferenceModel::loadFromDB(const QString & databaseName)
168 {
169 QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "temporary");
170 db.setDatabaseName(databaseName);
171
172 m_swappingEnabled = loadFromDB(m_database, db);
173 if (db.isOpen()) db.close();
174 if (!m_swappingEnabled) {
175 killParts();
176 noSwappingMessage();
177 }
178
179 return m_swappingEnabled;
180 }
181
loadFromDB(QSqlDatabase & keep_db,QSqlDatabase & db)182 bool SqliteReferenceModel::loadFromDB(QSqlDatabase & keep_db, QSqlDatabase & db)
183 {
184 bool opened = false;
185 for (int i = 0; i < MAX_CONN_TRIES; i++) {
186 if (!db.open()) continue;
187
188 opened = true;
189 break;
190 }
191
192 if (!opened) {
193 return false;
194 }
195
196 QSqlQuery query = db.exec("SELECT COUNT(*) FROM parts");
197 debugError(query.isActive(), query);
198 if (!query.isActive() || !query.next()) return false;
199
200 int count = query.value(0).toInt();
201 if (count == 0) {
202 return false;
203 }
204
205 DebugDialog::debug(QString("parts count %1").arg(count));
206
207
208 QVector<ModelPart *> parts(count + 1, NULL);
209 QVector<qulonglong > oldToNew(count + 1, 0);
210
211 query = db.exec("SELECT path, moduleID, id, family, version, replacedby, fritzingversion, author, title, label, date, description, spice, spicemodel, taxonomy, itemtype FROM parts");
212 debugError(query.isActive(), query);
213 if (!query.isActive()) return false;
214
215 QSqlQuery q2(keep_db);
216 bool result = q2.prepare("INSERT INTO parts(moduleID, family, core) VALUES (:moduleID, :family, :core)");
217 debugError(result, q2);
218
219 QFileInfo info(db.databaseName());
220 QDir partsDir = info.absoluteDir(); // parts folder
221
222 while (query.next()) {
223 int ix = 0;
224
225 QString path = query.value(ix++).toString();
226 QString moduleID = query.value(ix++).toString();
227 qulonglong dbid = query.value(ix++).toULongLong();
228
229 if (m_partHash.value(moduleID, NULL) != NULL) {
230 // a part with this moduleID was already loaded--the file version overrides the db version
231 continue;
232 }
233
234 if (!path.startsWith(ResourcePath)) { // not the resources path
235 path = partsDir.absoluteFilePath(path);
236 if (QFileInfo(path).exists()) {
237 // assume this is a later version of the fzp so load it later via xml
238 CoreList << moduleID;
239 continue;
240 }
241
242 path.replace("/parts/", "/pdb/");
243 }
244
245 ModelPart * modelPart = new ModelPart();
246 ModelPartShared * modelPartShared = new ModelPartShared();
247 modelPart->setModelPartShared(modelPartShared);
248
249 modelPartShared->setModuleID(moduleID);
250 modelPartShared->setDBID(dbid);
251 QString family = query.value(ix++).toString();
252 modelPartShared->setFamily(family);
253 modelPartShared->setVersion(query.value(ix++).toString());
254 modelPartShared->setReplacedby(query.value(ix++).toString());
255 modelPartShared->setFritzingVersion(query.value(ix++).toString());
256 modelPartShared->setAuthor(query.value(ix++).toString());
257 modelPartShared->setTitle(query.value(ix++).toString());
258 modelPartShared->setLabel(query.value(ix++).toString());
259 modelPartShared->setDate(query.value(ix++).toString());
260 modelPartShared->setDescription(query.value(ix++).toString());
261 modelPartShared->setSpice(query.value(ix++).toString());
262 modelPartShared->setSpiceModel(query.value(ix++).toString());
263 modelPartShared->setTaxonomy(query.value(ix++).toString());
264 modelPart->setItemType((ModelPart::ItemType) query.value(ix++).toInt());
265 modelPartShared->setPath(path);
266 modelPart->setCore(true);
267
268 modelPartShared->setConnectorsInitialized(true);
269
270 m_partHash.insert(modelPartShared->moduleID(), modelPart);
271 parts[dbid] = modelPart;
272
273 q2.bindValue(":moduleID", modelPartShared->moduleID());
274 q2.bindValue(":family", family);
275 q2.bindValue(":core", "1");
276 bool result = q2.exec();
277 if (!result) debugExec("unable to add part to memory", q2);
278
279 qulonglong newid = q2.lastInsertId().toULongLong();
280 oldToNew[dbid] = newid;
281 }
282
283 query = db.exec("SELECT viewid, image, layers, sticky, flipvertical, fliphorizontal, part_id FROM viewimages");
284 debugError(query.isActive(), query);
285 if (!query.isActive()) return false;
286
287 while (query.next()) {
288 int ix = 0;
289 ViewImage * viewImage = new ViewImage(ViewLayer::BreadboardView);
290 viewImage->viewID = (ViewLayer::ViewID) query.value(ix++).toInt();
291 viewImage->image = query.value(ix++).toString();
292 viewImage->layers = query.value(ix++).toULongLong();
293 viewImage->sticky = query.value(ix++).toULongLong();
294 viewImage->canFlipVertical = query.value(ix++).toInt() == 0 ? false : true;
295 viewImage->canFlipHorizontal = query.value(ix++).toInt() == 0 ? false : true;
296 qulonglong dbid = query.value(ix++).toULongLong();
297
298 ModelPart * modelPart = parts.at(dbid);
299 if (modelPart) {
300 parts.at(dbid)->setViewImage(viewImage);
301 }
302 }
303
304 query = db.exec("SELECT tag, part_id FROM tags");
305 debugError(query.isActive(), query);
306 if (!query.isActive()) return false;
307
308 while (query.next()) {
309 int ix = 0;
310 QString tag = query.value(ix++).toString();
311 qulonglong dbid = query.value(ix++).toULongLong();
312 ModelPart * modelPart = parts.at(dbid);
313 if (modelPart) {
314 parts.at(dbid)->setTag(tag);
315 }
316 }
317
318 query = db.exec("SELECT name, value, part_id, show_in_label FROM properties");
319 debugError(query.isActive(), query);
320 if (!query.isActive()) return false;
321
322 QSqlQuery q3(keep_db);
323 result = q3.prepare("INSERT INTO properties(name, value, part_id, show_in_label) VALUES (:name, :value, :part_id, :show_in_label)");
324 debugError(result, q3);
325
326 while (query.next()) {
327 int ix = 0;
328 QString name = query.value(ix++).toString();
329 QString value = query.value(ix++).toString();
330 qulonglong dbid = query.value(ix++).toULongLong();
331 int showInLabel = query.value(ix++).toInt();
332 ModelPart * modelPart = parts.at(dbid);
333 if (modelPart) {
334 parts.at(dbid)->setProperty(name, value, showInLabel);
335 q3.bindValue(":name", name.toLower().trimmed());
336 q3.bindValue(":value", value);
337 q3.bindValue(":part_id", oldToNew[dbid]);
338 q3.bindValue(":show_in_label", showInLabel);
339 bool result = q3.exec();
340 if (!result) debugExec("unable to add property to memory", q3);
341 }
342 }
343
344 query = db.exec("SELECT COUNT(*) FROM connectors");
345 debugError(query.isActive(), query);
346 if (!query.isActive() || !query.next()) return false;
347
348 int connectorCount = query.value(0).toInt();
349 if (connectorCount == 0) return false;
350
351 QVector<Connector *> connectors(connectorCount + 1, NULL);
352
353 query = db.exec("SELECT id, connectorid, type, name, description, replacedby, part_id FROM connectors");
354 debugError(query.isActive(), query);
355 if (!query.isActive()) {
356 killConnectors(connectors);
357 return false;
358 }
359
360 while (query.next()) {
361 int ix = 0;
362 qulonglong cid = query.value(ix++).toULongLong();
363 QString connectorid = query.value(ix++).toString();
364 Connector::ConnectorType type = (Connector::ConnectorType) query.value(ix++).toInt();
365 QString name = query.value(ix++).toString();
366 QString description = query.value(ix++).toString();
367 QString replacedby = query.value(ix++).toString();
368 qulonglong dbid = query.value(ix++).toULongLong();
369 ModelPart * modelPart = parts.at(dbid);
370 if (modelPart) {
371 ConnectorShared * connectorShared = new ConnectorShared();
372 connectorShared->setConnectorType(type);
373 connectorShared->setDescription(description);
374 connectorShared->setReplacedby(replacedby);
375 connectorShared->setSharedName(name);
376 connectorShared->setId(connectorid);
377
378 Connector * connector = new Connector(connectorShared, modelPart);
379 modelPart->addConnector(connector);
380
381 connectors[cid] = connector;
382 }
383 }
384
385 query = db.exec("SELECT view, layer, svgid, hybrid, terminalid, legid, connector_id FROM connectorlayers");
386 debugError(query.isActive(), query);
387 if (!query.isActive()) {
388 killConnectors(connectors);
389 return false;
390 }
391
392 while (query.next()) {
393 int ix = 0;
394 ViewLayer::ViewID viewID = (ViewLayer::ViewID) query.value(ix++).toInt();
395 ViewLayer::ViewLayerID viewLayerID = (ViewLayer::ViewLayerID) query.value(ix++).toInt();
396 QString svgID = query.value(ix++).toString();
397 bool hybrid = query.value(ix++).toInt() == 0 ? false : true;
398 QString terminalID = query.value(ix++).toString();
399 QString legID = query.value(ix++).toString();
400 qulonglong cid = query.value(ix++).toULongLong();
401 Connector * connector = connectors.at(cid);
402 if (connector) {
403 connectors[cid]->addPin(viewID, svgID, viewLayerID, terminalID, legID, hybrid);
404 }
405 }
406
407 query = db.exec("SELECT COUNT(*) FROM buses");
408 debugError(query.isActive(), query);
409 if (!query.isActive() || !query.next()) return false;
410
411 int busCount = query.value(0).toInt();
412 if (busCount == 0) return false;
413
414 QVector<BusShared *> buses(busCount + 1, NULL);
415 QHash<BusShared *, qulonglong> busids;
416
417 query = db.exec("SELECT id, name, part_id FROM buses");
418 debugError(query.isActive(), query);
419 if (!query.isActive()) {
420 killConnectors(connectors);
421 killBuses(buses);
422 return false;
423 }
424
425 while (query.next()) {
426 int ix = 0;
427 qulonglong bid = query.value(ix++).toULongLong();
428 QString name = query.value(ix++).toString();
429 qulonglong dbid = query.value(ix++).toULongLong();
430 ModelPart * modelPart = parts.at(dbid);
431 if (modelPart) {
432 BusShared * busShared = new BusShared(name);
433 ModelPart * modelPart = parts.at(dbid);
434 modelPart->modelPartShared()->insertBus(busShared);
435
436 buses[bid] = busShared;
437 busids.insert(busShared, dbid);
438 }
439 }
440
441 query = db.exec("SELECT connectorid, bus_id FROM busmembers");
442 debugError(query.isActive(), query);
443 if (!query.isActive()) {
444 killConnectors(connectors);
445 killBuses(buses);
446 return false;
447 }
448
449 while (query.next()) {
450 int ix = 0;
451
452 QString connectorid = query.value(ix++).toString();
453 qulonglong bid = query.value(ix++).toULongLong();
454 BusShared * busShared = buses[bid];
455 if (busShared) {
456 qulonglong dbid = busids.value(busShared);
457 ModelPart * modelPart = parts.at(dbid);
458 if (modelPart) {
459 ConnectorShared * connectorShared = modelPart->modelPartShared()->getConnectorShared(connectorid);
460 busShared->addConnectorShared(connectorShared);
461 }
462 }
463 }
464
465 query = db.exec("SELECT subpart_id, part_id FROM schematic_subparts");
466 debugError(query.isActive(), query);
467 if (query.isActive()) {
468 while (query.next()) {
469 int ix = 0;
470 QString subpartID = query.value(ix++).toString();
471 qulonglong dbid = query.value(ix++).toULongLong();
472 ModelPart * modelPart = parts.at(dbid);
473 if (modelPart) {
474 QString subModuleID = modelPart->moduleID() + "_" + subpartID;
475 ModelPart * subModelPart = m_partHash.value(subModuleID);
476 if (subModelPart) {
477 subModelPart->setSubpartID(subpartID);
478 modelPart->modelPartShared()->addSubpart(subModelPart->modelPartShared());
479 }
480 }
481 }
482 }
483
484 if (m_root == NULL) {
485 m_root = new ModelPart();
486 }
487 foreach (ModelPart * modelPart, m_partHash.values()) {
488 if (modelPart->dbid() != 0) {
489 // initConnectors is not redundant here
490 // there may be parts in m_partHash loaded from a file rather from the database
491 //
492 modelPart->initConnectors();
493 modelPart->flipSMDAnd();
494 modelPart->initBuses();
495 modelPart->setParent(m_root);
496 modelPart->lookForZeroConnector();
497 }
498 }
499
500 return true;
501 }
502
503
~SqliteReferenceModel()504 SqliteReferenceModel::~SqliteReferenceModel() {
505 deleteConnection();
506 }
507
initParts(bool dbExists)508 void SqliteReferenceModel::initParts(bool dbExists) {
509 m_init = true;
510 PaletteModel::initParts(dbExists);
511 m_init = false;
512 }
513
createConnection(const QString & databaseName,bool fullLoad)514 bool SqliteReferenceModel::createConnection(const QString & databaseName, bool fullLoad) {
515 m_swappingEnabled = true;
516 m_database = QSqlDatabase::addDatabase("QSQLITE");
517 m_database.setDatabaseName(databaseName.isEmpty() ? ":memory:" : databaseName);
518 if (!m_database.open()) {
519 m_swappingEnabled = false;
520 }
521 else {
522 m_keepGoing = false;
523 bool gotTransaction = m_database.transaction();
524 DebugDialog::debug(gotTransaction ? "got transaction" : "no transaction");
525
526 bool result = createParts(m_database, fullLoad);
527
528 QSqlQuery query;
529 result = query.exec("CREATE TABLE viewimages (\n"
530 "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
531 "viewid INTEGER NOT NULL,\n" // ViewLayer::ViewID
532 "image TEXT NOT NULL,\n"
533 "layers INTEGER NOT NULL,\n" // bit flag (max 8 bytes = 64 layers)
534 "sticky INTEGER NOT NULL,\n" // bit flag (max 8 bytes = 64 layers)
535 "flipvertical INTEGER NOT NULL,\n" // boolean
536 "fliphorizontal INTEGER NOT NULL,\n" // boolean
537 "part_id INTEGER NOT NULL"
538 ")");
539 debugError(result, query);
540
541 result = query.exec("CREATE TABLE connectors (\n"
542 "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
543 "connectorid TEXT NOT NULL,\n"
544 "type INTEGER NOT NULL,\n"
545 "name TEXT NOT NULL,\n"
546 "description TEXT,\n"
547 "replacedby TEXT,\n"
548 "part_id INTEGER NOT NULL"
549 ")");
550 debugError(result, query);
551
552 result = query.exec("CREATE TABLE connectorlayers (\n"
553 "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
554 "view INTEGER NOT NULL,\n" // ViewLayer::ViewID
555 "layer INTEGER NOT NULL,\n" // ViewLayer::ViewLayerID
556 "svgid TEXT NOT NULL,\n"
557 "hybrid INTEGER NOT NULL,\n"
558 "terminalid TEXT,\n"
559 "legid TEXT,\n"
560 "connector_id INTEGER NOT NULL"
561 ")");
562 debugError(result, query);
563
564 result = query.exec("CREATE TABLE buses (\n"
565 "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
566 "name TEXT NOT NULL,\n"
567 "part_id INTEGER NOT NULL"
568 ")");
569 debugError(result, query);
570
571 result = query.exec("CREATE TABLE busmembers (\n"
572 "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
573 "connectorid TEXT NOT NULL,\n"
574 "bus_id INTEGER NOT NULL"
575 ")");
576 debugError(result, query);
577
578 result = query.exec("CREATE TABLE schematic_subparts (\n"
579 "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
580 "label TEXT NOT NULL,\n"
581 "subpart_id TEXT NOT NULL,\n"
582 "part_id INTEGER NOT NULL"
583 ")");
584 debugError(result, query);
585
586 // TODO: create a dictionary table so redundant tags, property names, and property values aren't stored multiple times
587
588 result = query.exec("CREATE TABLE tags (\n"
589 "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL ,\n"
590 "tag TEXT NOT NULL,\n"
591 "part_id INTEGER NOT NULL"
592 ")");
593 debugError(result, query);
594
595 result = createProperties(m_database);
596
597 result = query.exec("CREATE TRIGGER unique_part__moduleID \n"
598 "BEFORE INSERT ON parts \n"
599 "FOR EACH ROW BEGIN \n"
600 "SELECT RAISE(ROLLBACK, 'insert on table \"parts\" violates unique constraint \"unique_part__moduleID\"') \n"
601 "WHERE (SELECT count(*) FROM parts WHERE moduleID = NEW.moduleID) > 0; \n"
602 "END; "
603 );
604 debugError(result, query);
605
606 if (fullLoad) {
607 foreach(ModelPart* mp, m_partHash.values()) {
608 mp->initConnectors(false);
609 }
610 }
611 foreach(ModelPart* mp, m_partHash.values()) {
612 addPartAux(mp, fullLoad);
613 }
614
615 createIndexes();
616 createMoreIndexes(m_database);
617
618 m_database.commit();
619
620 }
621 return m_swappingEnabled;
622 }
623
deleteConnection()624 void SqliteReferenceModel::deleteConnection() {
625 QSqlDatabase::removeDatabase("SQLITE");
626 }
627
loadPart(const QString & path,bool update)628 ModelPart *SqliteReferenceModel::loadPart(const QString & path, bool update) {
629 ModelPart *modelPart = PaletteModel::loadPart(path, update);
630 if (modelPart == NULL) return modelPart;
631
632 if (!m_init) addPart(modelPart, update);
633 return modelPart;
634 }
635
retrieveModelPart(const QString & moduleID)636 ModelPart *SqliteReferenceModel::retrieveModelPart(const QString &moduleID) {
637 if (moduleID.isEmpty()) {
638 return NULL;
639 }
640 return m_partHash.value(moduleID, NULL);
641 }
642
retrieveModuleIdWith(const QString & family,const QString & propertyName,bool closestMatch)643 QString SqliteReferenceModel::retrieveModuleIdWith(const QString &family, const QString &propertyName, bool closestMatch) {
644 QString moduleID = retrieveModuleId(family,m_recordedProperties,propertyName, closestMatch);
645 m_recordedProperties.clear();
646 return moduleID;
647 }
648
retrieveModuleId(const QString & family,const QMultiHash<QString,QString> & properties,const QString & propertyName,bool closestMatch)649 QString SqliteReferenceModel::retrieveModuleId(const QString &family, const QMultiHash<QString, QString> &properties, const QString &propertyName, bool closestMatch)
650 {
651 QString propertyValue;
652
653 if(properties.size() > 0) {
654 QString queryStr =
655 "SELECT moduleID FROM parts part \n"
656 "WHERE part.family = :family AND (1=1 ";
657 QHash<QString, QString> params;
658 int ix = 0;
659 foreach (QString name, properties.uniqueKeys()) {
660 foreach (QString value, properties.values(name)) {
661 QString propParam = QString(":prop%1").arg(ix++);
662 queryStr += QString(" AND EXISTS (SELECT * FROM properties prop WHERE prop.part_id = part.id AND prop.name = %1_name AND prop.value = %1_value)").arg(propParam);
663 params[propParam+"_name"] = name;
664 params[propParam+"_value"] = value;
665 if(name == propertyName) {
666 propertyValue = value;
667 }
668 }
669 }
670 queryStr += ") order by part.core desc";
671
672 QSqlQuery query;
673 query.prepare(queryStr);
674
675 query.bindValue(":family",family.toLower().trimmed());
676 foreach(QString name, params.uniqueKeys()) {
677 query.bindValue(name,params[name].toLower().trimmed());
678 }
679
680 QString moduleId;
681 if(query.exec()) {
682 if(query.next()) {
683 moduleId = query.value(0).toString(); //grab the first
684 }
685 //DebugDialog::debug("SQLITE: found: "+moduleId);
686 } else {
687 debugExec("couldn't retrieve part", query);
688 }
689
690 if(!moduleId.isEmpty()) {
691 m_lastWasExactMatch = true;
692 return moduleId;
693 } else if(closestMatch || !propertyName.isEmpty()) {
694 m_lastWasExactMatch = false;
695 return closestMatchId(family, properties, propertyName, propertyValue);
696 } else {
697 return ___emptyString___;
698 }
699 } else {
700 return ___emptyString___;
701 }
702 }
703
closestMatchId(const QString & family,const QMultiHash<QString,QString> & properties,const QString & propertyName,const QString & propertyValue)704 QString SqliteReferenceModel::closestMatchId(const QString &family, const QMultiHash<QString, QString> &properties, const QString &propertyName, const QString &propertyValue) {
705 QStringList possibleMatches = getPossibleMatches(family, properties, propertyName, propertyValue);
706 return getClosestMatch(family, properties, possibleMatches);
707 }
708
getPossibleMatches(const QString & family,const QMultiHash<QString,QString> & properties,const QString & propertyName,const QString & propertyValue)709 QStringList SqliteReferenceModel::getPossibleMatches(const QString &family, const QMultiHash<QString, QString> &properties, const QString &propertyName, const QString &propertyValue) {
710 Q_UNUSED(properties);
711
712 QStringList result;
713 QString queryStr =
714 "SELECT moduleID FROM parts part \n"
715 "WHERE part.family = :family AND EXISTS ( \n"
716 "SELECT * FROM properties prop \n"
717 "WHERE prop.part_id = part.id %1 \n"
718 ") ";
719 queryStr = queryStr.arg((propertyName.isEmpty()) ? "" : "AND prop.name = :prop_name AND prop.value = :prop_value ");
720 QSqlQuery query;
721 query.prepare(queryStr);
722
723 query.bindValue(":family", family.toLower().trimmed());
724 if (!propertyName.isEmpty()) {
725 query.bindValue(":prop_name", propertyName.toLower().trimmed());
726 query.bindValue(":prop_value", propertyValue);
727 }
728
729
730 if(query.exec()) {
731 while(query.next()) {
732 result << query.value(0).toString();
733 }
734 //DebugDialog::debug(QString("SQLITE: %1 possible matches found").arg(result.size()));
735 } else {
736 debugExec("couldn't get possible match", query);
737 }
738
739 return result;
740 }
741
getClosestMatch(const QString & family,const QMultiHash<QString,QString> & properties,QStringList possibleMatches)742 QString SqliteReferenceModel::getClosestMatch(const QString &family, const QMultiHash<QString, QString> &properties, QStringList possibleMatches) {
743 int propsInCommonCount = 0;
744 int propsInCommonCountAux = 0;
745 QString result;
746 foreach(QString modId, possibleMatches) {
747 propsInCommonCountAux = countPropsInCommon(family, properties, retrieveModelPart(modId));
748 if(propsInCommonCountAux > propsInCommonCount) {
749 result = modId;
750 propsInCommonCount = propsInCommonCountAux;
751 }
752 }
753 return result;
754 }
755
countPropsInCommon(const QString & family,const QMultiHash<QString,QString> & properties,const ModelPart * part2)756 int SqliteReferenceModel::countPropsInCommon(const QString &family, const QMultiHash<QString, QString> &properties, const ModelPart *part2) {
757 Q_UNUSED(family)
758
759 if (part2 == NULL) {
760 DebugDialog::debug("countPropsInCommon failure");
761 return 0;
762 }
763
764 int result = 0;
765 QMultiHash<QString,QString> props2 = part2->properties();
766 foreach(QString prop, properties.uniqueKeys()) {
767 QStringList values1 = properties.values(prop);
768 QStringList values2 = props2.values(prop);
769 foreach (QString value1, values1) {
770 if (values2.contains(value1)) {
771 result++;
772 }
773 }
774 }
775 return result;
776 }
777
lastWasExactMatch()778 bool SqliteReferenceModel::lastWasExactMatch() {
779 return m_lastWasExactMatch;
780 }
781
addPartAux(ModelPart * newModel,bool fullLoad)782 bool SqliteReferenceModel::addPartAux(ModelPart * newModel, bool fullLoad) {
783 try {
784 bool result = insertPart(newModel, fullLoad);
785 return result;
786 }
787 catch (const char * msg) {
788 DebugDialog::debug(msg);
789 }
790 catch (const QString & msg) {
791 DebugDialog::debug(msg);
792 }
793 catch (...) {
794 DebugDialog::debug("SqliteReferenceModel::addPartAux failure");
795 }
796
797 return false;
798 }
799
addPart(ModelPart * newModel,bool update)800 bool SqliteReferenceModel::addPart(ModelPart * newModel, bool update) {
801 bool result;
802 if(update && containsModelPart(newModel->moduleID())) {
803 result = updatePart(newModel);
804 } else {
805 result = addPartAux(newModel, false);
806 }
807 return result;
808 }
809
addPart(QString newPartPath,bool addToReference,bool updateIdAlreadyExists)810 ModelPart * SqliteReferenceModel::addPart(QString newPartPath, bool addToReference, bool updateIdAlreadyExists)
811 {
812 return PaletteModel::addPart(newPartPath, addToReference, updateIdAlreadyExists);
813 }
814
815
reloadPart(const QString & path,const QString & moduleID)816 ModelPart * SqliteReferenceModel::reloadPart(const QString & path, const QString & moduleID) {
817 m_partHash.remove(moduleID);
818 ModelPart *modelPart = PaletteModel::loadPart(path, false);
819 if (modelPart == NULL) return modelPart;
820
821 updatePart(modelPart);
822 return modelPart;
823 }
824
825
updatePart(ModelPart * newModel)826 bool SqliteReferenceModel::updatePart(ModelPart * newModel) {
827 if(m_swappingEnabled) {
828 qulonglong partId = this->partId(newModel->moduleID());
829 if(partId != NO_ID) {
830 removePart(partId);
831 removeProperties(partId);
832 return addPartAux(newModel, false);
833 } else {
834 return false;
835 }
836 } else {
837 return false;
838 }
839
840 }
841
insertPart(ModelPart * modelPart,bool fullLoad)842 bool SqliteReferenceModel::insertPart(ModelPart * modelPart, bool fullLoad) {
843 DebugModelPart = modelPart;
844
845 QHash<QString, QString> properties = modelPart->properties();
846 QSqlQuery query;
847 QString fields;
848 QString values;
849 if (fullLoad) {
850 fields = " version, replacedby, fritzingversion, author, title, label, date, description, spice, spicemodel, taxonomy, itemtype, path";
851 values = " :version, :replacedby, :fritzingversion, :author, :title, :label, :date, :description, :spice, :spicemodel, :taxonomy, :itemtype, :path";
852 }
853 else {
854 fields = " core";
855 values = " :core";
856 }
857 query.prepare(QString("INSERT INTO parts(moduleID, family, %1) VALUES (:moduleID, :family, %2)").arg(fields).arg(values));
858 query.bindValue(":moduleID", modelPart->moduleID());
859 query.bindValue(":family", properties.value("family").toLower().trimmed());
860 if (fullLoad) {
861 QString path = modelPart->path();
862 QString prefix = FolderUtils::getApplicationSubFolderPath("parts");
863
864 if (path.startsWith(ResourcePath)) {
865 }
866 else if (path.startsWith(prefix)) {
867 // copy the fzp away so it's not consulted at normal load time
868 QString newPath = path;
869 newPath.replace("/parts/", "/pdb/");
870 QFile::remove(newPath);
871 QFile::rename(path, newPath);
872 path = path.mid(prefix.count() + 1); // + 1 to remove the beginning "/"
873 }
874 else {
875 bool bail = true;
876 if (modelPart->itemType() == ModelPart::SchematicSubpart) {
877 ModelPartShared * mps = modelPart->modelPartShared();
878 if (mps && mps->superpart() && mps->superpart()->path().startsWith(prefix)) {
879 bail = false;
880 }
881 }
882
883 if (bail) {
884 DebugDialog::debug(QString("part path not in parts:%1").arg(path));
885 return true;
886 }
887 }
888
889
890 query.bindValue(":version", modelPart->version());
891 query.bindValue(":replacedby", modelPart->replacedby());
892 query.bindValue(":fritzingversion", modelPart->fritzingVersion());
893 query.bindValue(":author", modelPart->author());
894 query.bindValue(":title", modelPart->title());
895 query.bindValue(":label", modelPart->label());
896 query.bindValue(":date", modelPart->date());
897 query.bindValue(":description", modelPart->description());
898 query.bindValue(":spice", modelPart->spice());
899 query.bindValue(":spicemodel", modelPart->spiceModel());
900 query.bindValue(":taxonomy", modelPart->taxonomy());
901 query.bindValue(":itemtype", (int) modelPart->itemType());
902
903 query.bindValue(":path", path);
904 }
905 else {
906 query.bindValue(":core", modelPart->isCore() ? "1" : "0");
907 }
908
909
910 if (query.exec()) {
911 qulonglong id = query.lastInsertId().toULongLong();
912 modelPart->setDBID(id);
913 foreach (QString prop, properties.keys()) {
914 if (prop == "family") continue;
915
916 bool result = insertProperty(prop, properties.value(prop), id, modelPart->showInLabel(prop));
917 if (fullLoad && !result) {
918 m_swappingEnabled = false;
919 }
920 if (!result) {
921 FailurePropertyMessages << tr("property '%1' in part '%2' with id '%3'.")
922 .arg(prop).arg(modelPart->path()).arg(modelPart->moduleID());
923 }
924 }
925
926 if (fullLoad) {
927 foreach (QString tag, modelPart->tags()) {
928 insertTag(tag, id);
929 }
930
931 foreach (ViewImage * viewImage, modelPart->viewImages()) {
932 insertViewImage(viewImage, id);
933 }
934
935 foreach (Connector * connector, modelPart->connectors().values()) {
936 insertConnector(connector, id);
937 }
938
939 foreach (Bus * bus, modelPart->buses().values()) {
940 insertBus(bus, id);
941 }
942
943 ModelPartShared * mps = modelPart->modelPartShared();
944 if (mps) {
945 foreach (ModelPartShared * sub, mps->subparts()) {
946 insertSubpart(sub, id);
947 }
948 }
949 }
950 } else {
951 debugExec("couldn't insert part", query);
952 FailurePartMessages << tr("part '%1' with id '%2'; possibly because it has no 'family' property.")
953 .arg(modelPart->path()).arg(modelPart->moduleID());
954 }
955
956 DebugModelPart = NULL;
957 return true;
958 }
959
insertProperty(const QString & name,const QString & value,qulonglong id,bool showInLabel)960 bool SqliteReferenceModel::insertProperty(const QString & name, const QString & value, qulonglong id, bool showInLabel) {
961 QSqlQuery query;
962 query.prepare("INSERT INTO properties(name, value, part_id, show_in_label) VALUES (:name, :value, :part_id, :show_in_label)");
963 query.bindValue(":name", name.toLower().trimmed());
964 query.bindValue(":value", value);
965 query.bindValue(":part_id", id);
966 query.bindValue(":show_in_label", showInLabel ? 1 : 0);
967 if(!query.exec()) {
968 debugExec("couldn't insert property", query);
969 return false;
970 } else {
971 // qulonglong id = query.lastInsertId().toULongLong();
972 }
973
974 return true;
975 }
976
insertTag(const QString & tag,qulonglong id)977 bool SqliteReferenceModel::insertTag(const QString & tag, qulonglong id)
978 {
979 QSqlQuery query;
980 query.prepare("INSERT INTO tags(tag, part_id) VALUES (:tag, :part_id)");
981 query.bindValue(":tag", tag.toLower().trimmed());
982 query.bindValue(":part_id", id);
983 if(!query.exec()) {
984 debugExec("couldn't insert tag", query);
985 m_swappingEnabled = false;
986 } else {
987 // qulonglong id = query.lastInsertId().toULongLong();
988 }
989
990 return true;
991 }
992
insertViewImage(const ViewImage * viewImage,qulonglong id)993 bool SqliteReferenceModel::insertViewImage(const ViewImage * viewImage, qulonglong id)
994 {
995 if (viewImage->image.isEmpty() && viewImage->layers == 0) return true;
996
997 QSqlQuery query;
998 query.prepare("INSERT INTO viewimages(viewid, image, layers, sticky, flipvertical, fliphorizontal, part_id) "
999 "VALUES (:viewid, :image, :layers, :sticky, :flipvertical, :fliphorizontal, :part_id)");
1000 query.bindValue(":viewid", viewImage->viewID);
1001 query.bindValue(":image", viewImage->image);
1002 query.bindValue(":layers", viewImage->layers);
1003 query.bindValue(":sticky", viewImage->sticky);
1004 query.bindValue(":flipvertical", viewImage->canFlipVertical ? 1 : 0);
1005 query.bindValue(":fliphorizontal", viewImage->canFlipHorizontal ? 1 : 0);
1006 query.bindValue(":part_id", id);
1007 if(!query.exec()) {
1008 debugExec("couldn't insert viewimage", query);
1009 m_swappingEnabled = false;
1010 } else {
1011 // qulonglong id = query.lastInsertId().toULongLong();
1012 }
1013
1014 return true;
1015 }
1016
insertBus(const Bus * bus,qulonglong id)1017 bool SqliteReferenceModel::insertBus(const Bus * bus, qulonglong id)
1018 {
1019 QSqlQuery query;
1020 query.prepare("INSERT INTO buses(name, part_id) VALUES (:name, :part_id)");
1021 query.bindValue(":name", bus->id());
1022 query.bindValue(":part_id", id);
1023 if(!query.exec()) {
1024 debugExec("couldn't insert bus", query);
1025 m_swappingEnabled = false;
1026 } else {
1027 qulonglong bid = query.lastInsertId().toULongLong();
1028 foreach (Connector * connector, bus->connectors()) {
1029 insertBusMember(connector, bid);
1030 }
1031 }
1032
1033 return true;
1034 }
1035
insertBusMember(const Connector * connector,qulonglong id)1036 bool SqliteReferenceModel::insertBusMember(const Connector * connector, qulonglong id)
1037 {
1038 QSqlQuery query;
1039 query.prepare("INSERT INTO busmembers(connectorid, bus_id) VALUES (:connectorid, :bus_id)");
1040 query.bindValue(":connectorid", connector->connectorSharedID());
1041 query.bindValue(":bus_id", id);
1042 if(!query.exec()) {
1043 debugExec("couldn't insert busmember", query);
1044 m_swappingEnabled = false;
1045 } else {
1046 //qulonglong id = query.lastInsertId().toULongLong();
1047 }
1048
1049 return true;
1050 }
1051
insertConnector(const Connector * connector,qulonglong id)1052 bool SqliteReferenceModel::insertConnector(const Connector * connector, qulonglong id)
1053 {
1054 QSqlQuery query;
1055 query.prepare("INSERT INTO connectors(connectorid, type, name, description, replacedby, part_id) VALUES (:connectorid, :type, :name, :description, :replacedby, :part_id)");
1056 query.bindValue(":connectorid", connector->connectorSharedID());
1057 query.bindValue(":type", (int) connector->connectorType());
1058 query.bindValue(":name", connector->connectorSharedName());
1059 query.bindValue(":description", connector->connectorSharedDescription());
1060 query.bindValue(":replacedby", connector->connectorSharedReplacedby());
1061 query.bindValue(":part_id", id);
1062 if(!query.exec()) {
1063 debugExec("couldn't insert connector", query);
1064 m_swappingEnabled = false;
1065 } else {
1066 qulonglong id = query.lastInsertId().toULongLong();
1067 foreach (SvgIdLayer * layer, connector->svgIdLayers()) {
1068 insertConnectorLayer(layer, id);
1069 }
1070 }
1071
1072 return true;
1073 }
1074
1075
insertConnectorLayer(const SvgIdLayer * svgIdLayer,qulonglong id)1076 bool SqliteReferenceModel::insertConnectorLayer(const SvgIdLayer * svgIdLayer, qulonglong id)
1077 {
1078
1079 QSqlQuery query;
1080 query.prepare("INSERT INTO connectorLayers(view, layer, svgid, hybrid, terminalid, legid, connector_id) VALUES "
1081 "(:view, :layer, :svgid, :hybrid, :terminalid, :legid, :connector_id)");
1082 query.bindValue(":view", svgIdLayer->m_viewID);
1083 query.bindValue(":layer", svgIdLayer->m_svgViewLayerID);
1084 query.bindValue(":svgid", svgIdLayer->m_svgId);
1085 query.bindValue(":hybrid", svgIdLayer->m_hybrid ? 1 : 0);
1086 query.bindValue(":terminalid", svgIdLayer->m_terminalId);
1087 query.bindValue(":legid", svgIdLayer->m_legId);
1088 query.bindValue(":connector_id", id);
1089 if(!query.exec()) {
1090 debugExec("couldn't insert viewimage", query);
1091 m_swappingEnabled = false;
1092 } else {
1093 // qulonglong id = query.lastInsertId().toULongLong();
1094 }
1095
1096 return true;
1097 }
1098
propValues(const QString & family,const QString & propName,bool distinct)1099 QStringList SqliteReferenceModel::propValues(const QString &family, const QString &propName, bool distinct) {
1100 QStringList retval;
1101
1102 QSqlQuery query;
1103 query.prepare(QString(
1104 "SELECT %1 prop.value FROM properties prop JOIN parts PART ON part.id = prop.part_id \n"
1105 "WHERE part.family = :family AND prop.name = :propName ORDER BY prop.value \n"
1106 ).arg(distinct ? " DISTINCT ":"")
1107 );
1108 query.bindValue(":family",family.toLower().trimmed());
1109 query.bindValue(":propName",propName.toLower().trimmed());
1110
1111 if(query.exec()) {
1112 while(query.next()) {
1113 QString value = query.value(0).toString();
1114 if (!value.isEmpty()) retval << value;
1115 }
1116 } else {
1117 debugExec("couldn't retrieve values", query);
1118 m_swappingEnabled = false;
1119 }
1120
1121 return retval;
1122 }
1123
allPropValues(const QString & family,const QString & propName)1124 QMultiHash<QString, QString> SqliteReferenceModel::allPropValues(const QString &family, const QString &propName) {
1125 QMultiHash<QString, QString> retval;
1126
1127 QSqlQuery query;
1128 query.prepare(QString(
1129 "SELECT value, moduleID FROM properties prop JOIN parts part ON part.id = prop.part_id \n"
1130 "WHERE part.family = :family AND prop.name = :propName\n"
1131 )
1132 );
1133 query.bindValue(":family",family.toLower().trimmed());
1134 query.bindValue(":propName",propName.toLower().trimmed());
1135
1136 if(query.exec()) {
1137 while(query.next()) {
1138 //QSqlRecord record = query.record();
1139 //for (int i = 0; i < record.count(); i++) {
1140 // DebugDialog::debug("result " + record.fieldName(i) + " " + record.value(i).toString());
1141 //}
1142 QString prop = query.value(0).toString();
1143 if (!prop.isEmpty()) retval.insert(prop, query.value(1).toString());
1144 }
1145 } else {
1146 debugExec("couldn't retrieve values", query);
1147 m_swappingEnabled = false;
1148 }
1149
1150 return retval;
1151 }
1152
1153
1154
recordProperty(const QString & name,const QString & value)1155 void SqliteReferenceModel::recordProperty(const QString &name, const QString &value) {
1156 DebugDialog::debug(QString("RECORDING PROPERTY %1:%2").arg(name).arg(value));
1157 m_recordedProperties.insert(name,value);
1158 }
1159
swapEnabled()1160 bool SqliteReferenceModel::swapEnabled() {
1161 return m_swappingEnabled;
1162 }
1163
containsModelPart(const QString & moduleID)1164 bool SqliteReferenceModel::containsModelPart(const QString & moduleID) {
1165 return partId(moduleID) != NO_ID;
1166 }
1167
partId(QString moduleID)1168 qulonglong SqliteReferenceModel::partId(QString moduleID) {
1169 qulonglong partId = NO_ID;
1170
1171 QSqlQuery query;
1172 query.prepare(
1173 "SELECT id FROM parts \n"
1174 "WHERE moduleID = :moduleID "
1175 );
1176 query.bindValue(":moduleID",moduleID);
1177
1178 if(query.exec()) {
1179 //DebugDialog::debug("SQLITE: retrieving id: "+moduleID);
1180 if(query.next()) {
1181 partId = query.value(0).toULongLong(); //grab the first
1182 }
1183 //DebugDialog::debug(QString("SQLITE: found: %1").arg(partId));
1184 } else {
1185 debugExec("couldn't retrieve part", query);
1186 }
1187
1188 return partId;
1189 }
1190
removePart(qulonglong partId)1191 bool SqliteReferenceModel::removePart(qulonglong partId) {
1192 bool result = true;
1193
1194 QSqlQuery query;
1195 query.prepare(
1196 "DELETE FROM parts \n"
1197 "WHERE id = :id "
1198 );
1199 query.bindValue(":id",partId);
1200
1201 if(query.exec()) {
1202 result = true;
1203 } else {
1204 DebugDialog::debug(
1205 "SQLITE: couldn't delete part\n"
1206 "\t "+query.lastQuery()+"\n"
1207 "\t ERROR DRIVER: "+query.lastError().driverText()+"\n"
1208 "\t ERROR DB: "+query.lastError().databaseText()+"\n"
1209 );
1210 result = false;
1211 }
1212
1213 return result;
1214 }
1215
removeProperties(qulonglong partId)1216 bool SqliteReferenceModel::removeProperties(qulonglong partId) {
1217 bool result = true;
1218
1219 QSqlQuery query;
1220 query.prepare(
1221 "DELETE FROM properties \n"
1222 "WHERE part_id = :id "
1223 );
1224 query.bindValue(":id",partId);
1225
1226 if(query.exec()) {
1227 result = true;
1228 } else {
1229 DebugDialog::debug(
1230 "SQLITE: couldn't delete properties \n"
1231 "\t "+query.lastQuery()+"\n"
1232 "\t ERROR DRIVER: "+query.lastError().driverText()+"\n"
1233 "\t ERROR DB: "+query.lastError().databaseText()+"\n"
1234 );
1235 result = false;
1236 }
1237
1238 return result;
1239 }
1240
partTitle(const QString & moduleID)1241 QString SqliteReferenceModel::partTitle(const QString & moduleID) {
1242 ModelPart *mp = retrieveModelPart(moduleID);
1243 if(mp) {
1244 return mp->modelPartShared()->title();
1245 } else {
1246 return ___emptyString___;
1247 }
1248 }
1249
killParts()1250 void SqliteReferenceModel::killParts()
1251 {
1252 foreach (ModelPart * modelPart, m_partHash.values()) {
1253 delete modelPart;
1254 }
1255 m_partHash.clear();
1256 }
1257
createProperties(QSqlDatabase & db)1258 bool SqliteReferenceModel::createProperties(QSqlDatabase & db) {
1259 QSqlQuery query = db.exec("CREATE TABLE properties (\n"
1260 "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL ,\n"
1261 "name TEXT NOT NULL,\n"
1262 "value TEXT NOT NULL,\n"
1263 "show_in_label INTEGER NOT NULL,\n"
1264 "part_id INTEGER NOT NULL"
1265 ")");
1266 debugError(query.isActive(), query);
1267 return query.isActive();
1268 }
1269
createParts(QSqlDatabase & db,bool fullLoad)1270 bool SqliteReferenceModel::createParts(QSqlDatabase & db, bool fullLoad)
1271 {
1272 QString extra;
1273 if (fullLoad) {
1274 extra = "version TEXT,\n"
1275 "replacedby TEXT,\n"
1276 "fritzingversion TEXT,\n"
1277 "author TEXT,\n"
1278 "title TEXT,\n"
1279 "label TEXT,\n"
1280 "date TEXT,\n"
1281 "description TEXT,\n"
1282 "spice TEXT,\n"
1283 "spicemodel TEXT,\n"
1284 "taxonomy TEXT,\n"
1285 "itemtype INTEGER NOT NULL,\n"
1286 "path TEXT\n"
1287 ;
1288 }
1289 else {
1290 extra = "core TEXT NOT NULL\n"
1291 ;
1292 }
1293
1294
1295 QString string = QString("CREATE TABLE parts (\n"
1296 "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
1297 "moduleID TEXT NOT NULL,\n"
1298 "family TEXT NOT NULL,\n"
1299 "%1"
1300 ")")
1301 .arg(extra);
1302
1303 QSqlQuery query = db.exec(string);
1304 debugError(query.isActive(), query);
1305 return query.isActive();
1306 }
1307
insertSubpart(ModelPartShared * mps,qulonglong id)1308 bool SqliteReferenceModel::insertSubpart(ModelPartShared * mps, qulonglong id)
1309 {
1310 QSqlQuery query;
1311 query.prepare("INSERT INTO schematic_subparts(label, subpart_id, part_id) VALUES (:label, :subpart_id, :part_id)");
1312 query.bindValue(":label", mps->label());
1313 query.bindValue(":subpart_id", mps->subpartID());
1314 query.bindValue(":part_id", id);
1315 if(!query.exec()) {
1316 debugExec("couldn't insert bus", query);
1317 m_swappingEnabled = false;
1318 }
1319 //else {
1320 // qulonglong sid = query.lastInsertId().toULongLong();
1321 //}
1322
1323 return true;
1324 }
1325
createIndexes()1326 void SqliteReferenceModel::createIndexes() {
1327 // supposedly faster to add these after the data is inserted
1328
1329 QSqlQuery query;
1330 bool result = query.exec("CREATE INDEX idx_viewimage_part_id ON viewimages (part_id ASC)");
1331 debugError(result, query);
1332 result = query.exec("CREATE INDEX idx_connector_part_id ON connectors (part_id ASC)");
1333 debugError(result, query);
1334 result = query.exec("CREATE INDEX idx_connectorlayer_connector_id ON connectorlayers (connector_id ASC)");
1335 debugError(result, query);
1336 result = query.exec("CREATE INDEX idx_bus_part_id ON buses (part_id ASC)");
1337 debugError(result, query);
1338 result = query.exec("CREATE INDEX idx_busmember_bus_id ON busmembers (bus_id ASC)");
1339 debugError(result, query);
1340 result = query.exec("CREATE INDEX idx_schematic_subpart_part_id ON schematic_subparts (part_id ASC)");
1341 debugError(result, query);
1342 result = query.exec("CREATE INDEX idx_tag_part_id ON tags (part_id ASC)");
1343 debugError(result, query);
1344 }
1345
createMoreIndexes(QSqlDatabase & db)1346 void SqliteReferenceModel::createMoreIndexes(QSqlDatabase & db)
1347 {
1348 // supposedly faster to add these after the data is inserted
1349
1350 QSqlQuery query = db.exec("CREATE INDEX idx_property_name ON properties (name ASC)");
1351 debugError(query.isActive(), query);
1352
1353 query = db.exec("CREATE INDEX idx_part_id ON parts (id ASC)");
1354 debugError(query.isActive(), query);
1355
1356 query = db.exec("CREATE INDEX idx_part_moduleID ON parts (moduleID ASC)");
1357 debugError(query.isActive(), query);
1358
1359 query = db.exec("CREATE INDEX idx_part_family ON parts (family ASC)");
1360 debugError(query.isActive(), query);
1361 }
1362
1363