diff --git a/src/App/Document.cpp b/src/App/Document.cpp index 3707e51933..8454df3eac 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -64,6 +64,7 @@ recompute path. Also enables more complicated dependencies beyond trees. #include #include #include +#include #include #include @@ -1135,6 +1136,58 @@ std::vector Document::getInList(const DocumentObject* me) return result; } +std::vector +Document::getDependencyList(const std::vector& objs) const +{ + DependencyList DepList; + std::map ObjectMap; + std::map VertexMap; + + // Filling up the adjacency List + for (std::map::const_iterator It = d->objectMap.begin(); It != d->objectMap.end();++It) { + // add the object as Vertex and remember the index + Vertex v = add_vertex(DepList); + ObjectMap[It->second] = v; + VertexMap[v] = It->second; + } + // add the edges + for (std::map::const_iterator It = d->objectMap.begin(); It != d->objectMap.end();++It) { + std::vector OutList = It->second->getOutList(); + for (std::vector::const_iterator It2=OutList.begin();It2!=OutList.end();++It2) { + if (*It2) + add_edge(ObjectMap[It->second],ObjectMap[*It2],DepList); + } + } + + std::list make_order; + DependencyList::out_edge_iterator j, jend; + + try { + // this sort gives the execute + boost::topological_sort(DepList, std::front_inserter(make_order)); + } + catch (const std::exception&) { + return std::vector(); + } + + //std::vector out; + boost::unordered_set out; + for (std::vector::const_iterator it = objs.begin(); it != objs.end(); ++it) { + std::map::iterator jt = ObjectMap.find(*it); + // ok, object is part of this graph + if (jt != ObjectMap.end()) { + for (boost::tie(j, jend) = boost::out_edges(jt->second, DepList); j != jend; ++j) { + out.insert(VertexMap[boost::target(*j, DepList)]); + } + out.insert(*it); + } + } + + std::vector ary; + ary.insert(ary.end(), out.begin(), out.end()); + return ary; +} + void Document::_rebuildDependencyList(void) { d->VertexObjectList.clear(); @@ -1164,21 +1217,6 @@ void Document::recompute() // updates the dependency graph _rebuildDependencyList(); - //DependencyList DepList; - //std::map VertexObjectList; - - //// Filling up the adjacency List - //for (std::map::const_iterator It = d->objectMap.begin(); It != d->objectMap.end();++It) - // // add the object as Vertex and remember the index - // VertexObjectList[It->second] = add_vertex(DepList); - //// add the edges - //for (std::map::const_iterator It = d->objectMap.begin(); It != d->objectMap.end();++It) { - // std::vector OutList = It->second->getOutList(); - // for (std::vector::const_iterator It2=OutList.begin();It2!=OutList.end();++It2) - // if (*It2) - // add_edge(VertexObjectList[It->second],VertexObjectList[*It2],DepList); - //} - std::list make_order; DependencyList::out_edge_iterator j, jend; diff --git a/src/App/Document.h b/src/App/Document.h index 06a7fbdcbb..3ab0cb6391 100644 --- a/src/App/Document.h +++ b/src/App/Document.h @@ -265,6 +265,10 @@ public: bool checkOnCycle(void); /// get a list of all objects linking to the given object std::vector getInList(const DocumentObject* me) const; + /// Get a complete list of all objects the given objects depend on. The list + /// also contains the given objects! + std::vector getDependencyList + (const std::vector&) const; // set Changed //void setChanged(DocumentObject* change); //@} diff --git a/src/Gui/CommandDoc.cpp b/src/Gui/CommandDoc.cpp index 1c14ba62f2..212f89f079 100644 --- a/src/Gui/CommandDoc.cpp +++ b/src/Gui/CommandDoc.cpp @@ -841,7 +841,6 @@ void StdCmdCopy::activated(int iMsg) { bool done = getGuiApplication()->sendMsgToActiveView("Copy"); if (!done) { - WaitCursor wc; QMimeData * mimeData = getMainWindow()->createMimeDataFromSelection(); QClipboard* cb = QApplication::clipboard(); cb->setMimeData(mimeData); @@ -911,24 +910,42 @@ StdCmdDuplicateSelection::StdCmdDuplicateSelection() void StdCmdDuplicateSelection::activated(int iMsg) { std::vector sel = Selection().getCompleteSelection(); - std::vector obj; - obj.reserve(sel.size()); + std::map< App::Document*, std::vector > objs; for (std::vector::iterator it = sel.begin(); it != sel.end(); ++it) { - if (it->pObject) { - obj.push_back(it->pObject); + if (it->pObject && it->pObject->getDocument()) { + objs[it->pObject->getDocument()].push_back(it->pObject); } } - if (obj.empty()) + if (objs.empty()) return; Base::FileInfo fi(Base::FileInfo::getTempFileName()); { + std::vector sel; // selected + std::vector all; // object sub-graph + for (std::map< App::Document*, std::vector >::iterator it = objs.begin(); it != objs.end(); ++it) { + std::vector dep = it->first->getDependencyList(it->second); + sel.insert(sel.end(), it->second.begin(), it->second.end()); + all.insert(all.end(), dep.begin(), dep.end()); + } + + if (all.size() > sel.size()) { + int ret = QMessageBox::question(getMainWindow(), + qApp->translate("Std_DuplicateSelection","Object dependencies"), + qApp->translate("Std_DuplicateSelection","The selected objects have a dependency to unselected objects.\n" + "Do you want to duplicate them, too?"), + QMessageBox::Yes,QMessageBox::No); + if (ret == QMessageBox::Yes) { + sel = all; + } + } + // save stuff to file Base::ofstream str(fi, std::ios::out | std::ios::binary); - App::Document* doc = obj.front()->getDocument(); + App::Document* doc = sel.front()->getDocument(); MergeDocuments mimeView(doc); - doc->exportObjects(obj, str); + doc->exportObjects(sel, str); str.close(); } App::Document* doc = App::GetApplication().getActiveDocument(); diff --git a/src/Gui/MainWindow.cpp b/src/Gui/MainWindow.cpp index e1cc361a1e..6c91f19ed3 100644 --- a/src/Gui/MainWindow.cpp +++ b/src/Gui/MainWindow.cpp @@ -23,6 +23,7 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# include # include # include # include @@ -63,6 +64,7 @@ #include "MainWindow.h" #include "Application.h" #include "Assistant.h" +#include "WaitCursor.h" #include "Action.h" #include "Command.h" @@ -1403,21 +1405,39 @@ void MainWindow::dragEnterEvent (QDragEnterEvent * e) QMimeData * MainWindow::createMimeDataFromSelection () const { - std::vector sel = Selection().getCompleteSelection(); - unsigned int memsize=1000; // ~ for the meta-information - std::vector obj; - obj.reserve(sel.size()); - for (std::vector::iterator it = sel.begin(); it != sel.end(); ++it) { - if (it->pObject) { - obj.push_back(it->pObject); - memsize += it->pObject->getMemSize(); + std::vector selobj = Selection().getCompleteSelection(); + std::map< App::Document*, std::vector > objs; + for (std::vector::iterator it = selobj.begin(); it != selobj.end(); ++it) { + if (it->pObject && it->pObject->getDocument()) { + objs[it->pObject->getDocument()].push_back(it->pObject); } } - // get a pointer to a document - if (obj.empty()) return 0; - App::Document* doc = obj.front()->getDocument(); - if (!doc) return 0; + if (objs.empty()) + return 0; + + std::vector sel; // selected + std::vector all; // object sub-graph + for (std::map< App::Document*, std::vector >::iterator it = objs.begin(); it != objs.end(); ++it) { + std::vector dep = it->first->getDependencyList(it->second); + sel.insert(sel.end(), it->second.begin(), it->second.end()); + all.insert(all.end(), dep.begin(), dep.end()); + } + + if (all.size() > sel.size()) { + int ret = QMessageBox::question(getMainWindow(), + tr("Object dependencies"), + tr("The selected objects have a dependency to unselected objects.\n" + "Do you want to copy them, too?"), + QMessageBox::Yes,QMessageBox::No); + if (ret == QMessageBox::Yes) { + sel = all; + } + } + + unsigned int memsize=1000; // ~ for the meta-information + for (std::vector::iterator it = sel.begin(); it != sel.end(); ++it) + memsize += (*it)->getMemSize(); // if less than ~10 MB bool use_buffer=(memsize < 0xA00000); @@ -1429,22 +1449,25 @@ QMimeData * MainWindow::createMimeDataFromSelection () const use_buffer = false; } + WaitCursor wc; QString mime; if (use_buffer) { mime = QLatin1String("application/x-documentobject"); Base::ByteArrayOStreambuf buf(res); std::ostream str(&buf); // need this instance to call MergeDocuments::Save() + App::Document* doc = sel.front()->getDocument(); MergeDocuments mimeView(doc); - doc->exportObjects(obj, str); + doc->exportObjects(sel, str); } else { mime = QLatin1String("application/x-documentobject-file"); static Base::FileInfo fi(Base::FileInfo::getTempFileName()); Base::ofstream str(fi, std::ios::out | std::ios::binary); // need this instance to call MergeDocuments::Save() + App::Document* doc = sel.front()->getDocument(); MergeDocuments mimeView(doc); - doc->exportObjects(obj, str); + doc->exportObjects(sel, str); str.close(); res = fi.filePath().c_str(); }