# HG changeset patch # User Santeri Piippo # Date 1386887304 -7200 # Node ID 2478a6b3106dcd8b498fba0a2707154a147e52be # Parent 2418d59554219d5f52b5e5fbabc661cc8914d5b9 - Reworked primitive listing. No longer uses multi-threading. diff -r 2418d5955421 -r 2478a6b3106d src/addObjectDialog.cpp --- a/src/addObjectDialog.cpp Thu Dec 12 19:44:09 2013 +0200 +++ b/src/addObjectDialog.cpp Fri Dec 13 00:28:24 2013 +0200 @@ -62,33 +62,33 @@ switch (type) { case LDObject::Comment: - le_comment = new QLineEdit; + { le_comment = new QLineEdit; if (obj) le_comment->setText (static_cast (obj)->text); le_comment->setMinimumWidth (384); - break; + } break; case LDObject::Line: - coordCount = 6; - break; + { coordCount = 6; + } break; case LDObject::Triangle: - coordCount = 9; - break; + { coordCount = 9; + } break; case LDObject::Quad: case LDObject::CondLine: - coordCount = 12; - break; + { coordCount = 12; + } break; case LDObject::Vertex: - coordCount = 3; - break; + { coordCount = 3; + } break; case LDObject::BFC: - rb_bfcType = new RadioGroup ("Statement", {}, 0, Qt::Vertical); + { rb_bfcType = new RadioGroup ("Statement", {}, 0, Qt::Vertical); for (int i = 0; i < LDBFC::NumStatements; ++i) { // Separate these in two columns @@ -100,26 +100,19 @@ if (obj) rb_bfcType->setValue ( (int) static_cast (obj)->type); - - break; + } break; case LDObject::Subfile: - coordCount = 3; - - // If the primitive lister is busy writing data, we have to wait - // for that to happen first. This should be quite considerably rare. - while (isPrimitiveLoaderBusy()) - ; - + { coordCount = 3; tw_subfileList = new QTreeWidget(); tw_subfileList->setHeaderLabel (tr ("Primitives")); - for (PrimitiveCategory & cat : g_PrimitiveCategories) + for (PrimitiveCategory* cat : g_PrimitiveCategories) { SubfileListItem* parentItem = new SubfileListItem (tw_subfileList, null); - parentItem->setText (0, cat.getName()); + parentItem->setText (0, cat->getName()); QList subfileItems; - for (Primitive & prim : cat.prims) + for (Primitive& prim : cat->prims) { SubfileListItem* item = new SubfileListItem (parentItem, &prim); item->setText (0, fmt ("%1 - %2", prim.name, prim.title)); subfileItems << item; @@ -142,12 +135,11 @@ { LDSubfile* ref = static_cast (obj); le_subfileName->setText (ref->getFileInfo()->getName()); } - - break; + } break; default: - critical (fmt ("Unhandled LDObject type %1 (%2) in AddObjectDialog", (int) type, typeName)); - return; + { critical (fmt ("Unhandled LDObject type %1 (%2) in AddObjectDialog", (int) type, typeName)); + } return; } QPixmap icon = getIcon (fmt ("add-%1", typeName)); @@ -348,8 +340,7 @@ case LDObject::Triangle: case LDObject::Quad: case LDObject::CondLine: - - if (!obj) + { if (!obj) obj = LDObject::getDefault (type); for (int i = 0; i < obj->vertices(); ++i) @@ -360,14 +351,12 @@ obj->setVertex (i, v); } - - break; + } break; case LDObject::BFC: { LDBFC* bfc = initObj (obj); bfc->type = (LDBFC::Type) dlg.rb_bfcType->value(); - } - break; + } break; case LDObject::Vertex: { LDVertex* vert = initObj (obj); @@ -391,14 +380,14 @@ } LDSubfile* ref = initObj (obj); + assert (ref); for (const Axis ax : g_Axes) ref->setCoordinate (ax, dlg.dsb_coords[ax]->value()); ref->setTransform (transform); ref->setFileInfo (file); - } - break; + } break; default: break; diff -r 2418d5955421 -r 2478a6b3106d src/gui.cpp --- a/src/gui.cpp Thu Dec 12 19:44:09 2013 +0200 +++ b/src/gui.cpp Fri Dec 13 00:28:24 2013 +0200 @@ -653,6 +653,7 @@ AddObjectDialog::staticDialog (obj->getType(), obj); } +#if 0 // ============================================================================= // ----------------------------------------------------------------------------- void ForgeWindow::primitiveLoaderStart (int max) @@ -678,6 +679,7 @@ m_primLoaderBar->setFormat (tr ("Done")); log (tr ("Primitives scanned: %1 primitives listed"), m_primLoaderBar->value()); } +#endif // ============================================================================= // ----------------------------------------------------------------------------- diff -r 2418d5955421 -r 2478a6b3106d src/gui.h --- a/src/gui.h Thu Dec 12 19:44:09 2013 +0200 +++ b/src/gui.h Fri Dec 13 00:28:24 2013 +0200 @@ -134,9 +134,11 @@ #include "actions.h" public slots: +#if 0 void primitiveLoaderStart (int max); void primitiveLoaderUpdate (int prog); void primitiveLoaderEnd(); +#endif // 0 void slot_action(); void changeCurrentFile(); diff -r 2418d5955421 -r 2478a6b3106d src/gui_actions.cpp --- a/src/gui_actions.cpp Thu Dec 12 19:44:09 2013 +0200 +++ b/src/gui_actions.cpp Fri Dec 13 00:28:24 2013 +0200 @@ -71,7 +71,7 @@ default: QMessageBox::warning (null, "Warning", - fmt ("Unknown ld_defaultlicense value %1!", ld_defaultlicense)); + fmt ("Unknown ld_defaultlicense value %1!", ld_defaultlicense)); break; } @@ -93,9 +93,7 @@ new LDComment ("Name: .dat"), new LDComment (fmt ("Author: %1", ui.le_author->text())), new LDComment (fmt ("!LDRAW_ORG Unofficial_Part")), - (license != "" ? - new LDComment (license) : - null), + (license != "" ? new LDComment (license) : null), new LDEmpty, new LDBFC (BFCType), new LDEmpty, diff -r 2418d5955421 -r 2478a6b3106d src/ldtypes.cpp --- a/src/ldtypes.cpp Thu Dec 12 19:44:09 2013 +0200 +++ b/src/ldtypes.cpp Fri Dec 13 00:28:24 2013 +0200 @@ -761,6 +761,8 @@ getFile()->addToSelection (this); } +// ============================================================================= +// ----------------------------------------------------------------------------- void LDObject::unselect() { if (!getFile()) { log ("Warning: Object #%1 cannot be unselected as it is not assigned a file!\n", getID()); @@ -768,4 +770,22 @@ } getFile()->removeFromSelection (this); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +str getLicenseText (int id) +{ switch (id) + { case 0: + return CALicense; + + case 1: + return NonCALicense; + + case 2: + return ""; + } + + assert (false); + return ""; } \ No newline at end of file diff -r 2418d5955421 -r 2478a6b3106d src/ldtypes.h --- a/src/ldtypes.h Thu Dec 12 19:44:09 2013 +0200 +++ b/src/ldtypes.h Fri Dec 13 00:28:24 2013 +0200 @@ -476,4 +476,6 @@ static const int lores = 16; static const int hires = 48; +str getLicenseText (int id); + #endif // LDFORGE_LDTYPES_H diff -r 2418d5955421 -r 2478a6b3106d src/main.h --- a/src/main.h Thu Dec 12 19:44:09 2013 +0200 +++ b/src/main.h Fri Dec 13 00:28:24 2013 +0200 @@ -45,7 +45,6 @@ #include #include #include -#include #include #include "property.h" diff -r 2418d5955421 -r 2478a6b3106d src/primitives.cpp --- a/src/primitives.cpp Thu Dec 12 19:44:09 2013 +0200 +++ b/src/primitives.cpp Fri Dec 13 00:28:24 2013 +0200 @@ -16,10 +16,7 @@ * along with this program. If not, see . */ -// TODO: I believe the multi-threading is unnecessary here. Get rid of it. - #include -#include #include #include #include "document.h" @@ -30,11 +27,14 @@ #include "colors.h" #include "moc_primitives.cpp" -QList g_PrimitiveCategories; +QList g_PrimitiveCategories; QList g_primitives; static PrimitiveLister* g_activePrimLister = null; -static bool g_primListerMutex = false; -static const str g_Other = PrimitiveLister::tr ("Other"); +PrimitiveCategory* g_unmatched = null; + +extern_cfg (String, ld_defaultname); +extern_cfg (String, ld_defaultuser); +extern_cfg (Int, ld_defaultlicense); static const str g_radialNameRoots[] = { "edge", @@ -45,14 +45,15 @@ "con" }; -static void populateCategories(); -static void loadPrimitiveCatgories(); +PrimitiveLister* getPrimitiveLister() +{ return g_activePrimLister; +} // ============================================================================= // ----------------------------------------------------------------------------- void loadPrimitives() { log ("Loading primitives...\n"); - loadPrimitiveCatgories(); + PrimitiveCategory::loadCategories(); // Try to load prims.cfg File conf (Config::filepath ("prims.cfg"), File::Read); @@ -63,7 +64,7 @@ } else { // Read primitives from prims.cfg - for (str line : conf) + for (str line : conf) { int space = line.indexOf (" "); if (space == -1) @@ -75,7 +76,7 @@ g_primitives << info; } - populateCategories(); + PrimitiveCategory::populateCategories(); } } @@ -84,7 +85,7 @@ static void recursiveGetFilenames (QDir dir, QList& fnames) { QFileInfoList flist = dir.entryInfoList(); -for (const QFileInfo & info : flist) + for (const QFileInfo & info : flist) { if (info.fileName() == "." || info.fileName() == "..") continue; // skip . and .. @@ -97,24 +98,34 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void PrimitiveLister::work() +PrimitiveLister::PrimitiveLister (QObject* parent) : + QObject (parent), + m_i (0) { g_activePrimLister = this; - m_prims.clear(); - QDir dir (LDPaths::prims()); - int baselen = dir.absolutePath().length(); - int i = 0; - QList fnames; + assert (dir.exists()); + m_baselen = dir.absolutePath().length(); + recursiveGetFilenames (dir, m_files); + emit starting (m_files.size()); +} - assert (dir.exists()); - recursiveGetFilenames (dir, fnames); - emit starting (fnames.size()); +// ============================================================================= +// ----------------------------------------------------------------------------- +PrimitiveLister::~PrimitiveLister() +{ g_activePrimLister = null; +} -for (str fname : fnames) - { File f (fname, File::Read); +// ============================================================================= +// ----------------------------------------------------------------------------- +void PrimitiveLister::work() +{ int j = min (m_i + 300, m_files.size()); + log ("PrimitiveLister::work: %1 -> %2\n", m_i, j); + for (; m_i < j; ++m_i) + { str fname = m_files[m_i]; + File f (fname, File::Read); Primitive info; - info.name = fname.mid (baselen + 1); // make full path relative + info.name = fname.mid (m_baselen + 1); // make full path relative info.name.replace ('/', '\\'); // use DOS backslashes, they're expected info.cat = null; @@ -129,23 +140,29 @@ } m_prims << info; - emit update (++i); } - // Save to a config file - File conf (Config::filepath ("prims.cfg"), File::Write); + if (m_i == m_files.size()) + { // Done with primitives, now save to a config file + File conf (Config::filepath ("prims.cfg"), File::Write); -for (Primitive & info : m_prims) - fprint (conf, "%1 %2\n", info.name, info.title); + for (Primitive& info : m_prims) + fprint (conf, "%1 %2\n", info.name, info.title); + + conf.close(); - conf.close(); - - g_primListerMutex = true; - g_primitives = m_prims; - populateCategories(); - g_primListerMutex = false; - g_activePrimLister = null; - emit workDone(); + g_primitives = m_prims; + PrimitiveCategory::populateCategories(); + log ("%1 primitives listed", g_primitives.size()); + g_activePrimLister = null; + emit workDone(); + deleteLater(); + } + else + { // Defer to event loop, pick up the work later + emit update (m_i); + QMetaObject::invokeMethod (this, "work", Qt::QueuedConnection); + } } // ============================================================================= @@ -155,149 +172,153 @@ return; PrimitiveLister* lister = new PrimitiveLister; - QThread* listerThread = new QThread; - lister->moveToThread (listerThread); + /* connect (lister, SIGNAL (starting (int)), g_win, SLOT (primitiveLoaderStart (int))); connect (lister, SIGNAL (update (int)), g_win, SLOT (primitiveLoaderUpdate (int))); connect (lister, SIGNAL (workDone()), g_win, SLOT (primitiveLoaderEnd())); - connect (listerThread, SIGNAL (started()), lister, SLOT (work())); - connect (listerThread, SIGNAL (finished()), lister, SLOT (deleteLater())); - listerThread->start(); + */ + lister->work(); } // ============================================================================= // ----------------------------------------------------------------------------- -static PrimitiveCategory* findCategory (str name) -{ for (PrimitiveCategory & cat : g_PrimitiveCategories) - if (cat.getName() == name) - return &cat; - - return null; -} +PrimitiveCategory::PrimitiveCategory (str name, QObject* parent) : + QObject (parent), + m_Name (name) {} // ============================================================================= // ----------------------------------------------------------------------------- -static void populateCategories() -{ for (PrimitiveCategory & cat : g_PrimitiveCategories) - cat.prims.clear(); - - PrimitiveCategory* unmatched = findCategory (g_Other); +void PrimitiveCategory::populateCategories() +{ for (PrimitiveCategory* cat : g_PrimitiveCategories) + cat->prims.clear(); - if (!unmatched) - { // Shouldn't happen.. but catch it anyway. - PrimitiveCategory cat; - cat.setName (g_Other); - g_PrimitiveCategories << cat; - unmatched = &g_PrimitiveCategories.last(); - } - for (Primitive & prim : g_primitives) + for (Primitive& prim : g_primitives) { bool matched = false; prim.cat = null; // Go over the categories and their regexes, if and when there's a match, // the primitive's category is set to the category the regex beloings to. - for (PrimitiveCategory& cat : g_PrimitiveCategories) - { for (PrimitiveCategory::RegexEntry& entry : cat.regexes) + for (PrimitiveCategory* cat : g_PrimitiveCategories) + { for (RegexEntry& entry : cat->regexes) { switch (entry.type) - { case PrimitiveCategory::Filename: - // f-regex, check against filename + { case EFilenameRegex: + { // f-regex, check against filename matched = entry.regex.exactMatch (prim.name); - break; + } break; - case PrimitiveCategory::Title: - // t-regex, check against title + case ETitleRegex: + { // t-regex, check against title matched = entry.regex.exactMatch (prim.title); - break; + } break; } if (matched) - { prim.cat = &cat; + { prim.cat = cat; break; } } // Drop out if a category was decided on. - if (prim.cat) + if (prim.cat != null) break; } // If there was a match, add the primitive to the category. // Otherwise, add it to the list of unmatched primitives. - if (prim.cat) + if (prim.cat != null) prim.cat->prims << prim; else - unmatched->prims << prim; + g_unmatched->prims << prim; } } // ============================================================================= // ----------------------------------------------------------------------------- -static void loadPrimitiveCatgories() -{ g_PrimitiveCategories.clear(); +void PrimitiveCategory::loadCategories() +{ for (PrimitiveCategory* cat : g_PrimitiveCategories) + delete cat; + + g_PrimitiveCategories.clear(); File f (Config::dirpath() + "primregexps.cfg", File::Read); if (!f) f.open (":/data/primitive-categories.cfg", File::Read); if (!f) - critical (QObject::tr ("Failed to open primitive categories!")); + { critical (QObject::tr ("Failed to open primitive categories!")); + return; + } if (f) - { PrimitiveCategory cat; + { PrimitiveCategory* cat = null; - for (str line : f) + for (str line : f) { int colon; if (line.length() == 0 || line[0] == '#') continue; - if ( (colon = line.indexOf (":")) == -1) - { if (cat.regexes.size() > 0) + if ((colon = line.indexOf (":")) == -1) + { if (cat && cat->isValidToInclude()) g_PrimitiveCategories << cat; - cat.regexes.clear(); - cat.prims.clear(); - cat.setName (line); + cat = new PrimitiveCategory (line); } - else + elif (cat != null) { str cmd = line.left (colon); - PrimitiveCategory::Type type = PrimitiveCategory::Filename; + ERegexType type = EFilenameRegex; if (cmd == "f") - type = PrimitiveCategory::Filename; - + type = EFilenameRegex; elif (cmd == "t") - type = PrimitiveCategory::Title; + type = ETitleRegex; else + { log (tr ("Warning: unknown command \"%1\" on line \"%2\""), cmd, line); continue; + } QRegExp regex (line.mid (colon + 1)); - PrimitiveCategory::RegexEntry entry = { regex, type }; - cat.regexes << entry; + RegexEntry entry = { regex, type }; + cat->regexes << entry; } + else + log ("Warning: Rules given before the first category name"); } - if (cat.regexes.size() > 0) + if (cat->isValidToInclude()) g_PrimitiveCategories << cat; } - // Add a category for unmatched primitives - PrimitiveCategory cat; - cat.setName (g_Other); - g_PrimitiveCategories << cat; + // Add a category for unmatched primitives. + // Note: if this function is called the second time, g_unmatched has been + // deleted at the beginning of the function and is dangling at this point. + g_unmatched = new PrimitiveCategory (tr ("Other")); + g_PrimitiveCategories << g_unmatched; +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +bool PrimitiveCategory::isValidToInclude() +{ if (regexes.size() == 0) + { log (tr ("Warning: category \"%1\" left without patterns"), getName()); + deleteLater(); + return false; + } + + return true; } // ============================================================================= // ----------------------------------------------------------------------------- bool isPrimitiveLoaderBusy() -{ return g_primListerMutex; +{ return g_activePrimLister != null; } // ============================================================================= // ----------------------------------------------------------------------------- static double radialPoint (int i, int divs, double (*func) (double)) -{ return (*func) ( (i * 2 * pi) / divs); +{ return (*func) ((i * 2 * pi) / divs); } // ============================================================================= @@ -305,9 +326,9 @@ void makeCircle (int segs, int divs, double radius, QList& lines) { for (int i = 0; i < segs; ++i) { double x0 = radius * radialPoint (i, divs, cos), - x1 = radius * radialPoint (i + 1, divs, cos), - z0 = radius * radialPoint (i, divs, sin), - z1 = radius * radialPoint (i + 1, divs, sin); + x1 = radius * radialPoint (i + 1, divs, cos), + z0 = radius * radialPoint (i, divs, sin), + z1 = radius * radialPoint (i + 1, divs, sin); lines << QLineF (QPointF (x0, z0), QPointF (x1, z1)); } @@ -427,7 +448,7 @@ if (segs < divs && condLineSegs.size() != 0) condLineSegs << segs; -for (int i : condLineSegs) + for (int i : condLineSegs) { vertex v0 (radialPoint (i, divs, cos), 0.0f, radialPoint (i, divs, sin)), v1, v2 (radialPoint (i + 1, divs, cos), 0.0f, radialPoint (i + 1, divs, sin)), @@ -435,7 +456,6 @@ if (type == Cylinder) v1 = vertex (v0[X], 1.0f, v0[Z]); - elif (type == Cone) { v1 = vertex (v0[X] * (num + 1), 0.0f, v0[Z] * (num + 1)); v0[X] *= num; @@ -525,12 +545,20 @@ LDDocument* f = new LDDocument; f->setDefaultName (name); + str author = APPNAME; + str license = ""; + + if (ld_defaultname.value.isEmpty() == false) + { license = getLicenseText (ld_defaultlicense); + author = fmt ("%1 [%2]", ld_defaultname, ld_defaultuser); + } + f->addObjects ( { new LDComment (descr), new LDComment (fmt ("Name: %1", name)), - new LDComment (fmt ("Author: LDForge")), + new LDComment (fmt ("Author: %1", author)), new LDComment (fmt ("!LDRAW_ORG Unofficial_%1Primitive", divs == hires ? "48_" : "")), - new LDComment (CALicense), + new LDComment (license), new LDEmpty, new LDBFC (LDBFC::CertifyCCW), new LDEmpty, diff -r 2418d5955421 -r 2478a6b3106d src/primitives.h --- a/src/primitives.h Thu Dec 12 19:44:09 2013 +0200 +++ b/src/primitives.h Fri Dec 13 00:28:24 2013 +0200 @@ -32,23 +32,29 @@ PrimitiveCategory* cat; }; -class PrimitiveCategory -{ PROPERTY (public, str, Name, STR_OPS, STOCK_WRITE) +class PrimitiveCategory : public QObject +{ Q_OBJECT + PROPERTY (public, str, Name, STR_OPS, STOCK_WRITE) public: - enum Type - { Filename, - Title + enum ERegexType + { EFilenameRegex, + ETitleRegex }; struct RegexEntry - { QRegExp regex; - Type type; + { QRegExp regex; + ERegexType type; }; QList regexes; QList prims; - static QList uncat; + + explicit PrimitiveCategory (str name, QObject* parent = 0); + bool isValidToInclude(); + + static void loadCategories(); + static void populateCategories(); }; // ============================================================================= @@ -60,9 +66,11 @@ // builds an index of them. // ============================================================================= class PrimitiveLister : public QObject -{ Q_OBJECT +{ Q_OBJECT public: + explicit PrimitiveLister (QObject* parent = 0); + virtual ~PrimitiveLister(); static void start(); public slots: @@ -74,13 +82,16 @@ void update (int i); private: - QList m_prims; + QList m_prims; + QStringList m_files; + int m_i; + int m_baselen; }; -extern QList g_PrimitiveCategories; +extern QList g_PrimitiveCategories; void loadPrimitives(); -bool isPrimitiveLoaderBusy(); +PrimitiveLister* getPrimitiveLister(); enum PrimitiveType { Circle,