Fri, 20 Dec 2013 04:03:48 +0200
- added selection auto-subfiling(!)
changelog.txt | file | annotate | diff | comparison | revisions | |
src/actions.h | file | annotate | diff | comparison | revisions | |
src/document.cc | file | annotate | diff | comparison | revisions | |
src/document.h | file | annotate | diff | comparison | revisions | |
src/gui.cc | file | annotate | diff | comparison | revisions | |
src/gui.h | file | annotate | diff | comparison | revisions | |
src/gui_actions.cc | file | annotate | diff | comparison | revisions | |
ui/ldforge.ui | file | annotate | diff | comparison | revisions |
--- a/changelog.txt Fri Dec 20 02:05:19 2013 +0200 +++ b/changelog.txt Fri Dec 20 04:03:48 2013 +0200 @@ -15,6 +15,7 @@ - Fixed: "Hi-Res" was not prepended to the names of 48/ primitives. - Fixed: Checking the Hi-Res option would not allow segment values over 16. - Added support for multiple spaces before the ring number. +- Added an action for quickly subfiling the group of selected objects. - Coordinate rounding now works properly, figures scientific notation and rounds subfile position and matrix. Values are also now properly rounded instead of just floored, 1.2348 now rounds to 1.235 and not 1.234. Subfile matrix values are rounded to 4 decimals, everything else to 3 decimals.
--- a/src/actions.h Fri Dec 20 02:05:19 2013 +0200 +++ b/src/actions.h Fri Dec 20 04:03:48 2013 +0200 @@ -108,5 +108,6 @@ act (RotationPoint) act (AddHistoryLine) act (JumpTo) +act (SubfileSelection) #undef act \ No newline at end of file
--- a/src/document.cc Fri Dec 20 02:05:19 2013 +0200 +++ b/src/document.cc Fri Dec 20 04:03:48 2013 +0200 @@ -174,7 +174,7 @@ // ----------------------------------------------------------------------------- LDDocument* findDocument (str name) { for (LDDocument * file : g_loadedFiles) - if (!file->getName().isEmpty() && file->getShortName() == name) + if (!file->getName().isEmpty() && file->getDisplayName() == name) return file; return null; @@ -189,10 +189,8 @@ return path.left (lastpos); #ifndef _WIN32 - if (path[0] == DIRSLASH_CHAR) return DIRSLASH; - #endif // _WIN32 return ""; @@ -425,7 +423,8 @@ return null; LDDocument* load = new LDDocument; - load->setName (path); + load->setFullPath (path); + load->setName (LDDocument::shortenName (path)); // Don't take the file loading as actual edits to the file load->getHistory()->setIgnoring (true); @@ -615,13 +614,7 @@ { fpathComment = static_cast<LDComment*> (first); if (fpathComment->text.left (6) == "Name: ") - { str newname; - str dir = basename (dirname (savepath)); - - if (dir == "s" || dir == "48") - newname = dir + "\\"; - - newname += basename (savepath); + { str newname = shortenName (savepath); fpathComment->text = fmt ("Name: %1", newname); g_win->buildObjList(); } @@ -637,7 +630,8 @@ // We have successfully saved, update the save position now. setSavePosition (getHistory()->getPosition()); - setName (savepath); + setFullPath (savepath); + setName (shortenName (savepath)); g_win->updateDocumentListItem (this); g_win->updateTitle(); @@ -1074,12 +1068,12 @@ // ============================================================================= // ----------------------------------------------------------------------------- -str LDDocument::getShortName() +str LDDocument::getDisplayName() { if (!getName().isEmpty()) - return basename (getName()); + return getName(); if (!getDefaultName().isEmpty()) - return getDefaultName(); + return "[" + getDefaultName() + "]"; return tr ("<anonymous>"); } @@ -1180,7 +1174,7 @@ g_win->R()->setFile (f); g_win->R()->resetAllAngles(); g_win->R()->repaint(); - log ("Changed file to %1", f->getShortName()); + log ("Changed file to %1", f->getDisplayName()); } } @@ -1271,4 +1265,16 @@ m_Objects[b] = one; m_Objects[a] = other; addToHistory (new SwapHistory (one->getID(), other->getID())); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +str LDDocument::shortenName (str a) // [static] +{ str shortname = basename (a); + str topdirname = basename (dirname (a)); + + if (topdirname == "s" || topdirname == "48") + shortname.prepend (topdirname + "\\"); + + return shortname; } \ No newline at end of file
--- a/src/document.h Fri Dec 20 02:05:19 2013 +0200 +++ b/src/document.h Fri Dec 20 04:03:48 2013 +0200 @@ -57,6 +57,7 @@ PROPERTY (private, History*, History, NO_OPS, STOCK_WRITE) PROPERTY (private, QList<LDObject*>, Vertices, NO_OPS, STOCK_WRITE) PROPERTY (public, str, Name, STR_OPS, STOCK_WRITE) + PROPERTY (public, str, FullPath, STR_OPS, STOCK_WRITE) PROPERTY (public, str, DefaultName, STR_OPS, STOCK_WRITE) PROPERTY (public, bool, Implicit, BOOL_OPS, STOCK_WRITE) PROPERTY (public, QList<LDObject*>, Cache, NO_OPS, STOCK_WRITE) @@ -72,7 +73,7 @@ void addObjects (const QList<LDObject*> objs); void clearSelection(); void forgetObject (LDObject* obj); // Deletes the given object from the object chain. - str getShortName(); + str getDisplayName(); const QList<LDObject*>& getSelection() const; bool hasUnsavedChanges() const; // Does this document.have unsaved changes? QList<LDObject*> inlineContents (LDSubfile::InlineFlags flags); @@ -115,6 +116,9 @@ static void closeInitialFile(); static int countExplicitFiles(); + // Turns a full path into a relative path + static str shortenName (str a); + protected: void addToSelection (LDObject* obj); void removeFromSelection (LDObject* obj);
--- a/src/gui.cc Fri Dec 20 02:05:19 2013 +0200 +++ b/src/gui.cc Fri Dec 20 04:03:48 2013 +0200 @@ -597,6 +597,11 @@ contextMenu->addAction (ui->actionModeDraw); contextMenu->addAction (ui->actionModeCircle); + if (selection().size() > 0) + { contextMenu->addSeparator(); + contextMenu->addAction (ui->actionSubfileSelection); + } + if (R()->camera() != GL::EFreeCamera) { contextMenu->addSeparator(); contextMenu->addAction (ui->actionSetDrawDepth); @@ -682,47 +687,54 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void ForgeWindow::save (LDDocument* f, bool saveAs) -{ str path = f->getName(); +bool ForgeWindow::save (LDDocument* f, bool saveAs) +{ str path = f->getFullPath(); if (saveAs || path.isEmpty()) - { path = QFileDialog::getSaveFileName (g_win, tr ("Save As"), - (f->getName().isEmpty()) ? f->getName() : f->getDefaultName(), - tr ("LDraw files (*.dat *.ldr)")); + { str name = f->getDefaultName(); + + if (!f->getFullPath().isEmpty()) + name = f->getFullPath(); + elif (!f->getName().isEmpty()) + name = f->getName(); + + name.replace ("\\", "/"); + path = QFileDialog::getSaveFileName (g_win, tr ("Save As"), + name, tr ("LDraw files (*.dat *.ldr)")); if (path.isEmpty()) { // User didn't give a file name, abort. - return; + return false; } } if (f->save (path)) - { f->setName (path); - - if (f == getCurrentDocument()) - g_win->updateTitle(); + { if (f == getCurrentDocument()) + updateTitle(); log ("Saved to %1.", path); // Add it to recent files addRecentFile (path); + return true; } - else - { str message = fmt (tr ("Failed to save to %1: %2"), path, strerror (errno)); + + str message = fmt (tr ("Failed to save to %1: %2"), path, strerror (errno)); - // Tell the user the save failed, and give the option for saving as with it. - QMessageBox dlg (QMessageBox::Critical, tr ("Save Failure"), message, QMessageBox::Close, g_win); + // Tell the user the save failed, and give the option for saving as with it. + QMessageBox dlg (QMessageBox::Critical, tr ("Save Failure"), message, QMessageBox::Close, g_win); - // Add a save-as button - QPushButton* saveAsBtn = new QPushButton (tr ("Save As")); - saveAsBtn->setIcon (getIcon ("file-save-as")); - dlg.addButton (saveAsBtn, QMessageBox::ActionRole); - dlg.setDefaultButton (QMessageBox::Close); - dlg.exec(); + // Add a save-as button + QPushButton* saveAsBtn = new QPushButton (tr ("Save As")); + saveAsBtn->setIcon (getIcon ("file-save-as")); + dlg.addButton (saveAsBtn, QMessageBox::ActionRole); + dlg.setDefaultButton (QMessageBox::Close); + dlg.exec(); - if (dlg.clickedButton() == saveAsBtn) - save (f, true); // yay recursion! - } + if (dlg.clickedButton() == saveAsBtn) + return save (f, true); // yay recursion! + + return false; } void ForgeWindow::addMessage (str msg) @@ -823,11 +835,14 @@ void ForgeWindow::updateDocumentList() { ui->fileList->clear(); + QStringList names; for (LDDocument* f : g_loadedFiles) { // Don't list implicit files unless explicitly desired. if (f->isImplicit() && !gui_implicitfiles) + { dlog ("Skipped implicit file %1", f->getName()); continue; + } // Add an item to the list for this file and store a pointer to it in // the file, so we can find files by the list item. @@ -835,8 +850,12 @@ QListWidgetItem* item = ui->fileList->item (ui->fileList->count() - 1); f->setListItem (item); + names << f->getName(); + updateDocumentListItem (f); } + + dlog ("Document list updated: %1", names); } void ForgeWindow::updateDocumentListItem (LDDocument* f) @@ -857,7 +876,7 @@ if (f->isImplicit()) f->getListItem()->setForeground (QColor (96, 96, 96)); - f->getListItem()->setText (f->getShortName()); + f->getListItem()->setText (f->getDisplayName()); // If the document has unsaved changes, draw a little icon next to it to mark that. f->getListItem()->setIcon (f->hasUnsavedChanges() ? getIcon ("file-save") : QIcon());
--- a/src/gui.h Fri Dec 20 02:05:19 2013 +0200 +++ b/src/gui.h Fri Dec 20 04:03:48 2013 +0200 @@ -112,7 +112,7 @@ void deleteObjects (QList<LDObject*> objs); int deleteSelection(); void deleteByColor (const int colnum); - void save (LDDocument* f, bool saveAs); + bool save (LDDocument* f, bool saveAs); void updateActions(); inline GLRenderer* R()
--- a/src/gui_actions.cc Fri Dec 20 02:05:19 2013 +0200 +++ b/src/gui_actions.cc Fri Dec 20 04:03:48 2013 +0200 @@ -35,6 +35,7 @@ #include "primitives.h" #include "ui_newpart.h" #include "widgets.h" +#include "colors.h" extern_cfg (Bool, gl_wireframe); extern_cfg (Bool, gl_colorbfc); @@ -632,3 +633,162 @@ obj->select(); g_win->updateSelection(); } + +// ============================================================================= +// ----------------------------------------------------------------------------- +DEFINE_ACTION (SubfileSelection, 0) +{ if (selection().size() == 0) + return; + + str parentpath = getCurrentDocument()->getFullPath(); + + // BFC type of the new subfile - it shall inherit the BFC type of the parent document + LDBFC::Type bfctype = LDBFC::NoCertify; + + // Dirname of the new subfile + str subdirname = dirname (parentpath); + + // Title of the new subfile + str subtitle; + + // Comment containing the title of the parent document + LDComment* titleobj = dynamic_cast<LDComment*> (getCurrentDocument()->getObject (0)); + + // License text for the subfile + str license = getLicenseText (ld_defaultlicense); + + // LDraw code body of the new subfile (i.e. code of the selection) + QStringList code; + + // Full path of the subfile to be + str fullsubname; + + // Where to insert the subfile reference? + int refidx = selection()[0]->getIndex(); + + // Determine title of subfile + if (titleobj != null) + subtitle = "~" + titleobj->text; + else + subtitle = "~subfile"; + + // Remove duplicate tildes + while (subtitle[0] == '~' && subtitle[1] == '~') + subtitle.remove (0, 1); + + // If this the parent document isn't already in s/, we need to stuff it into + // a subdirectory named s/. Ensure it exists! + str topdirname = basename (dirname (getCurrentDocument()->getFullPath())); + dlog ("topdirname: %1", topdirname); + + if (topdirname != "s") + { str desiredPath = subdirname + "/s"; + str title = ForgeWindow::tr ("Create subfile directory?"); + str text = fmt (ForgeWindow::tr ("The directory <b>%1</b> is suggested for " + "subfiles. This directory does not exist, create it?"), desiredPath); + + if (QDir (desiredPath).exists() || confirm (title, text)) + { subdirname = desiredPath; + QDir().mkpath (subdirname); + } + } + + // Determine the body of the name of the subfile + if (!parentpath.isEmpty()) + { if (parentpath.endsWith (".dat")) + parentpath.chop (4); + + // Remove the s?? suffix if it's there, otherwise we'll get filenames + // like s01s01.dat when subfiling subfiles. + QRegExp subfilesuffix ("s[0-9][0-9]$"); + if (subfilesuffix.indexIn (parentpath) != -1) + parentpath.chop (subfilesuffix.matchedLength()); + + int subidx = 1; + str digits; + QFile f; + str testfname; + + do + { digits.setNum (subidx++); + + // pad it with a zero + if (digits.length() == 1) + digits.prepend ("0"); + + fullsubname = subdirname + "/" + basename (parentpath) + "s" + digits + ".dat"; + } while (findDocument ("s\\" + basename (fullsubname)) != null || QFile (fullsubname).exists()); + } + + // Determine the BFC winding type used in the main document - it is to + // be carried over to the subfile. + for (LDObject* obj : getCurrentDocument()->getObjects()) + { LDBFC* bfc = dynamic_cast<LDBFC*> (obj); + + if (!bfc) + continue; + + LDBFC::Type a = bfc->type; + + if (a == LDBFC::CertifyCCW || a == LDBFC::CertifyCW || a == LDBFC::NoCertify) + { bfctype = a; + break; + } + } + + // Get the body of the document in LDraw code + for (LDObject* obj : selection()) + code << obj->raw(); + + // Create the new subfile document + LDDocument* doc = new LDDocument; + doc->setImplicit (false); + doc->setFullPath (fullsubname); + doc->setName (LDDocument::shortenName (fullsubname)); + doc->addObjects ( + { new LDComment (subtitle), + new LDComment ("Name: "), + new LDComment (fmt ("Author: %1 [%2]", ld_defaultname, ld_defaultuser)), + new LDComment (fmt ("!LDRAW_ORG Unofficial_Subpart")), + (license != "" ? new LDComment (license) : null), + new LDEmpty, + new LDBFC (bfctype), + new LDEmpty, + }); + + // Add the actual subfile code to the new document + for (str line : code) + { LDObject* obj = parseLine (line); + doc->addObject (obj); + } + + // Try save it + if (g_win->save (doc, true)) + { // Remove the selection now + for (LDObject* obj : selection()) + obj->deleteSelf(); + + // Compile all objects in the new subfile + for (LDObject* obj : doc->getObjects()) + g_win->R()->compileObject (obj); + + g_loadedFiles << doc; + + // Add a reference to the new subfile to where the selection was + LDSubfile* ref = new LDSubfile(); + ref->setColor (maincolor); + ref->setFileInfo (doc); + ref->setPosition (g_origin); + ref->setTransform (g_identity); + getCurrentDocument()->insertObj (refidx, ref); + g_win->R()->compileObject (ref); + + // Refresh stuff + g_win->updateDocumentList(); + g_win->doFullRefresh(); + } + else + { // Failed to save. + delete doc; + } +} \ No newline at end of file
--- a/ui/ldforge.ui Fri Dec 20 02:05:19 2013 +0200 +++ b/ui/ldforge.ui Fri Dec 20 04:03:48 2013 +0200 @@ -70,7 +70,7 @@ <x>0</x> <y>0</y> <width>1010</width> - <height>25</height> + <height>24</height> </rect> </property> <widget class="QMenu" name="menuFile"> @@ -1340,6 +1340,11 @@ <string>Reveals objects. Undoes hiding.</string> </property> </action> + <action name="actionSubfileSelection"> + <property name="text"> + <string>Subfile Selection</string> + </property> + </action> </widget> <resources> <include location="../ldforge.qrc"/>