# HG changeset patch # User Santeri Piippo # Date 1387505028 -7200 # Node ID 59c0b57e843bd0dc19073217cbbbb90c6e855f3b # Parent 10874674fe302b8416d72a9341adf02a2f6842c3 - added selection auto-subfiling(!) diff -r 10874674fe30 -r 59c0b57e843b changelog.txt --- 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. diff -r 10874674fe30 -r 59c0b57e843b src/actions.h --- 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 diff -r 10874674fe30 -r 59c0b57e843b src/document.cc --- 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 (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 (""); } @@ -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 diff -r 10874674fe30 -r 59c0b57e843b src/document.h --- 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, 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, Cache, NO_OPS, STOCK_WRITE) @@ -72,7 +73,7 @@ void addObjects (const QList objs); void clearSelection(); void forgetObject (LDObject* obj); // Deletes the given object from the object chain. - str getShortName(); + str getDisplayName(); const QList& getSelection() const; bool hasUnsavedChanges() const; // Does this document.have unsaved changes? QList 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); diff -r 10874674fe30 -r 59c0b57e843b src/gui.cc --- 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()); diff -r 10874674fe30 -r 59c0b57e843b src/gui.h --- 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 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() diff -r 10874674fe30 -r 59c0b57e843b src/gui_actions.cc --- 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 (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 %1 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 (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 diff -r 10874674fe30 -r 59c0b57e843b ui/ldforge.ui --- 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 @@ 0 0 1010 - 25 + 24 @@ -1340,6 +1340,11 @@ Reveals objects. Undoes hiding. + + + Subfile Selection + +