Files
OrcaSlicer/src/slic3r/GUI/AuxiliaryDataViewModel.cpp
T
HanifKoh 4895bc03b4 Remove Unused Project Includes and Forward-Declare Where a Type Is Only Referenced (#16099)
* Remove Unused Project Includes and Forward-Declare Where a Type Is Only Referenced

Generated with include-what-you-use and applied conservatively. Only OrcaSlicer's own headers, the ones under src/ and tests/, are removed or forward-declared; standard-library and third-party includes are left alone. An include is removed only when both the Release and the Debug configuration leave it unused, never from inside a conditional block, and never from a file with platform-specific blocks, which only gain includes. Files whose only use of a header sits behind a feature or debug macro (libvgcode's OpenGL ES and marker code, the ARACHNE/TESTS_EXPORT_SVGS debug output) keep their includes.

clonable_ptr.hpp gains #pragma once; it had no include guard and was only safe while Config.hpp was its sole includer.

* Remove Unused Project Includes From Files With Platform-Specific Code

A Linux include-what-you-use run cannot see the code inside _WIN32, __APPLE__ or __linux__ blocks, so its verdict is only taken where nothing the removed header declares, directly or through what it includes, is named inside those blocks. Removals also have to hold in both the Release and Debug configuration and never touch a line inside a conditional block.

* Restore the libslic3r Precompiled Header and Direct Includes Lost in the Platform Pass

The platform-file pass treated pchheader.hpp as an ordinary header and
emptied it, and left GUI_Preview.hpp and 14 other files relying on
headers they no longer reached directly.

* Restore MainFrame.hpp in ParamsDialog.cpp for the Windows-Only Reparent Call

* Include Headers That Files Reached Through Ones the Cleanup Removed

* Drop Includes Duplicated by the Cleanup or by Main's Own Additions

* Leave PreciseSeam.cpp as Main Has It After the Precise Seam Rework
2026-10-05 16:47:17 +08:00

514 lines
14 KiB
C++

#include "AuxiliaryDataViewModel.hpp"
#include "libslic3r/Format/bbs_3mf.hpp"
#include <array>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/directory.hpp>
#include <boost/log/trivial.hpp>
#include <wx/filefn.h>
#include <wx/dataview.h>
#include <map>
#include <wx/debug.h>
#include <cstddef>
#include <wx/arrstr.h>
#include <wx/log.h>
#include <wx/string.h>
#include <wx/variant.h>
#include <wx/types.h>
#include "libslic3r/Format/STEP.hpp"
#include "slic3r/GUI/I18N.hpp"
#include <wx/defs.h>
namespace fs = boost::filesystem;
const static std::array<wxString, 4> s_default_folders = {
_L("Model Pictures"),
_L("Bill of Materials"),
_L("Assembly Guide"),
_L("Others")
};
AuxiliaryModel::AuxiliaryModel()
{
m_root = nullptr;
}
void AuxiliaryModel::Init(wxString aux_path)
{
m_root = new AuxiliaryModelNode();
m_root_dir = aux_path;
if (wxDirExists(m_root_dir)) {
fs::path path_to_del(m_root_dir.ToStdWstring());
try {
fs::remove_all(path_to_del);
}
catch (...) {
BOOST_LOG_TRIVIAL(error) << "Failed removing the auxiliary directory " << m_root_dir.c_str();
}
}
fs::path top_dir_path(m_root_dir.ToStdWstring());
fs::create_directory(top_dir_path);
for (auto folder : s_default_folders)
CreateFolder(folder);
}
AuxiliaryModel::~AuxiliaryModel()
{
if (wxDirExists(m_root_dir)) {
fs::path path_to_del(m_root_dir.ToStdWstring());
try {
fs::remove_all(path_to_del);
}
catch (...) {
BOOST_LOG_TRIVIAL(error) << "Failed removing the auxiliary directory " << m_root_dir.c_str();
}
m_root_dir = "";
}
delete m_root;
m_root = nullptr;
}
void AuxiliaryModel::Reload(wxString aux_path)
{
fs::path new_aux_path(aux_path.ToStdWstring());
// Clean
try {
fs::remove_all(fs::path(m_root_dir.ToStdWstring()));
}
catch (...) {
BOOST_LOG_TRIVIAL(error) << "Failed removing the auxiliary directory " << m_root_dir.c_str();
}
if (m_root) {
delete m_root;
m_root = nullptr;
}
Cleared();
// Create new root.
m_root = new AuxiliaryModelNode();
m_root_dir = aux_path;
// Check new path. If not exist, create a new one.
if (!fs::exists(new_aux_path)) {
fs::create_directory(new_aux_path);
// Create default folders if they are not loaded
wxDataViewItemArray default_items;
for (auto folder : s_default_folders) {
wxString folder_path = aux_path + "\\" + folder;
if (fs::exists(folder_path.ToStdWstring())) continue;
fs::create_directory(folder_path.ToStdWstring());
AuxiliaryModelNode *node = new AuxiliaryModelNode(m_root,
folder_path,
true);
default_items.Add(wxDataViewItem(node));
}
ItemsAdded(wxDataViewItem(nullptr), default_items);
return;
}
// Load from new path
std::map<fs::path, AuxiliaryModelNode *> dir_cache;
fs::directory_iterator iter_end;
wxDataViewItemArray items;
for (fs::directory_iterator iter(new_aux_path); iter != iter_end; iter++) {
wxString path = iter->path().generic_wstring();
AuxiliaryModelNode* node = new AuxiliaryModelNode(m_root, path, fs::is_directory(iter->path()));
items.Add(wxDataViewItem(node));
if (node->IsContainer()) {
dir_cache.insert({ iter->path(), node });
}
}
ItemsAdded(wxDataViewItem(nullptr), items);
items.Clear();
for (auto dir : dir_cache) {
for (fs::directory_iterator iter(dir.first); iter != iter_end; iter++) {
if (fs::is_directory(iter->path()))
continue;
wxString file_path = iter->path().generic_wstring();
AuxiliaryModelNode* file = new AuxiliaryModelNode(dir.second, file_path, false);
items.Add(wxDataViewItem(file));
}
ItemsAdded(wxDataViewItem(dir.second), items);
}
// Create default folders if they are not loaded
wxDataViewItemArray default_items;
for (auto folder : s_default_folders) {
wxString folder_path = aux_path + "\\" + folder;
if (fs::exists(folder_path.ToStdWstring()))
continue;
fs::create_directory(folder_path.ToStdWstring());
AuxiliaryModelNode* node = new AuxiliaryModelNode(m_root, folder_path, true);
default_items.Add(wxDataViewItem(node));
}
ItemsAdded(wxDataViewItem(nullptr), default_items);
}
int AuxiliaryModel::Compare(const wxDataViewItem& item1, const wxDataViewItem& item2,
unsigned int column, bool ascending) const
{
wxASSERT(item1.IsOk() && item2.IsOk());
// should never happen
if (IsContainer(item1) && IsContainer(item2))
{
wxVariant value1, value2;
GetValue(value1, item1, 0);
GetValue(value2, item2, 0);
wxString str1 = value1.GetString();
wxString str2 = value2.GetString();
int res = str1.Cmp(str2);
if (res) return res;
// items must be different
wxUIntPtr litem1 = (wxUIntPtr)item1.GetID();
wxUIntPtr litem2 = (wxUIntPtr)item2.GetID();
return litem1 - litem2;
}
return wxDataViewModel::Compare(item1, item2, column, ascending);
}
void AuxiliaryModel::GetValue(wxVariant& variant,
const wxDataViewItem& item, unsigned int col) const
{
wxASSERT(item.IsOk());
AuxiliaryModelNode* node = (AuxiliaryModelNode*)item.GetID();
switch (col)
{
case 0:
variant = node->name;
break;
default:
wxLogError("AuxiliaryModel::GetValue: wrong column %d", col);
}
}
bool AuxiliaryModel::SetValue(const wxVariant& variant,
const wxDataViewItem& item, unsigned int col)
{
wxASSERT(item.IsOk());
AuxiliaryModelNode* node = (AuxiliaryModelNode*)item.GetID();
switch (col)
{
case 0:
node->name = variant.GetString();
return true;
default:
wxLogError("AuxiliaryModel::SetValue: wrong column");
}
return false;
}
bool AuxiliaryModel::IsEnabled(const wxDataViewItem& item,
unsigned int col) const
{
return true;
}
wxDataViewItem AuxiliaryModel::GetParent(const wxDataViewItem& item) const
{
AuxiliaryModelNode* node = (AuxiliaryModelNode*)item.GetID();
return wxDataViewItem(GetParent(node));
}
bool AuxiliaryModel::IsContainer(const wxDataViewItem& item) const
{
// the invisible root node can have children
// (in our model always "MyMusic")
if (!item.IsOk())
return true;
AuxiliaryModelNode* node = (AuxiliaryModelNode*)item.GetID();
return node->IsContainer();
}
static unsigned int count = 0;
unsigned int AuxiliaryModel::GetChildren(const wxDataViewItem& parent,
wxDataViewItemArray& array) const
{
if (m_root == nullptr)
return 0;
AuxiliaryModelNode* node = (AuxiliaryModelNode*)parent.GetID();
if (!node)
{
node = m_root;
}
count = node->GetChildren().GetCount();
for (unsigned int pos = 0; pos < count; pos++)
{
AuxiliaryModelNode* child = node->GetChildren().Item(pos);
array.Add(wxDataViewItem((void*)child));
}
return count;
}
wxDataViewItem AuxiliaryModel::CreateFolder(wxString name)
{
wxString folder_name = name;
if (folder_name == wxEmptyString) {
folder_name = _L("New Folder");
for (int i = 1; i <= 1000; i++) {
bool exist = false;
for (AuxiliaryModelNode* node : m_root->GetChildren()) {
if (!node->IsContainer())
continue;
if (node->name == folder_name) {
exist = true;
break;
}
}
if (!exist)
break;
folder_name = _L("New Folder");
folder_name << "(" << i << ")";
}
}
else {
for (AuxiliaryModelNode* node : m_root->GetChildren()) {
if (!node->IsContainer())
continue;
if (node->name == folder_name) {
return wxDataViewItem(nullptr);
}
}
}
// Create folder in file system
fs::path bfs_path((m_root_dir + "\\" + folder_name).ToStdWstring());
if (fs::exists(bfs_path)) {
try {
bool is_done = fs::remove_all(bfs_path);
if (!is_done)
return wxDataViewItem(nullptr);
}
catch (...) {
BOOST_LOG_TRIVIAL(error) << "Failed removing the auxiliary directory " << m_root_dir.c_str();
}
}
fs::create_directory(bfs_path);
// Create model node
AuxiliaryModelNode* folder = new AuxiliaryModelNode(m_root, bfs_path.generic_wstring(), true);
// Notify wxDataViewCtrl to update ui
wxDataViewItem folder_item(folder);
ItemAdded(wxDataViewItem(NULL), folder_item);
return folder_item;
}
wxDataViewItemArray AuxiliaryModel::ImportFile(AuxiliaryModelNode* sel, wxArrayString file_paths)
{
if (sel == nullptr) {
sel = m_root;
}
wxDataViewItemArray added_items;
AuxiliaryModelNode* parent = sel->IsContainer() ? sel : sel->GetParent();
for (wxString file_path : file_paths) {
bool exists = false;
for (AuxiliaryModelNode* node : parent->GetChildren()) {
if (node->path == file_path) {
exists = true;
break;
}
}
if (exists)
continue;
// Copy imported file to project temp directory
fs::path src_bfs_path(file_path.ToStdWstring());
wxString dir_path = m_root_dir;
if (sel != m_root) {
dir_path += "\\";
dir_path += sel->name;
}
dir_path += "\\";
dir_path += src_bfs_path.filename().generic_wstring();
boost::system::error_code ec;
if (!fs::copy_file(src_bfs_path, fs::path(dir_path.ToStdWstring()), fs::copy_options::overwrite_existing, ec))
continue;
// Update model data
AuxiliaryModelNode* file = new AuxiliaryModelNode(parent, dir_path, false);
// Notify wxDataViewCtrl to update ui
wxDataViewItem file_item(file);
if (parent == m_root)
parent = nullptr;
Slic3r::put_other_changes();
wxDataViewItem parent_item(parent);
ItemAdded(parent_item, file_item);
added_items.push_back(file_item);
}
return added_items;
}
void AuxiliaryModel::Delete(const wxDataViewItem& item)
{
AuxiliaryModelNode* node = (AuxiliaryModelNode*)item.GetID();
if (!node) // happens if item.IsOk()==false
return;
bool is_done = false;
if (node->IsContainer()) {
fs::path bfs_path((m_root_dir + "\\" + node->name).ToStdWstring());
try {
is_done = fs::remove_all(bfs_path);
}
catch (...) {
BOOST_LOG_TRIVIAL(error) << "Failed removing the auxiliary directory " << m_root_dir.c_str();
}
}
else {
fs::path bfs_path(node->path.ToStdWstring());
is_done = fs::remove(bfs_path);
}
if (!is_done)
return;
node->GetParent()->GetChildren().Remove(node);
Slic3r::put_other_changes();
wxDataViewItem parent_item = GetParent(item);
ItemDeleted(parent_item, item);
delete node;
}
void AuxiliaryModel::MoveItem(const wxDataViewItem& dropped_item, const wxDataViewItem& dragged_item)
{
AuxiliaryModelNode* dropped = (AuxiliaryModelNode*)dropped_item.GetID();
AuxiliaryModelNode* dragged = (AuxiliaryModelNode*)dragged_item.GetID();
if (dragged == nullptr || dragged->IsContainer())
return;
AuxiliaryModelNode* target_folder = nullptr;
if (dropped == nullptr) {
target_folder = m_root;
}
else if (dropped->IsContainer()) {
target_folder = dropped;
}
else {
target_folder = dropped->GetParent();
}
if (dragged->GetParent() == target_folder)
return;
for (AuxiliaryModelNode* node : target_folder->GetChildren()) {
if (node->path == dragged->path)
return;
}
// Generate new path
wxString new_path = m_root_dir;
if (target_folder != m_root)
new_path += "\\" + target_folder->name;
new_path += "\\" + dragged->name;
// Perform file movement in file system
fs::path bfs_new_path(new_path.ToStdWstring());
fs::path bfs_old_path(dragged->path.ToStdWstring());
boost::system::error_code err;
fs::rename(bfs_old_path, bfs_new_path, err);
if (err.failed())
return;
// Reparent dragged node
wxDataViewItem old_parent_item = this->GetParent(dragged_item);
this->Reparent(dragged, target_folder);
dragged->path = new_path;
// Notify wxDataViewCtrl to update ui
Slic3r::put_other_changes();
ItemDeleted(old_parent_item, wxDataViewItem(dragged));
ItemAdded(wxDataViewItem(target_folder == m_root ? nullptr : target_folder), wxDataViewItem(dragged));
}
bool AuxiliaryModel::IsOrphan(const wxDataViewItem& item)
{
AuxiliaryModelNode* node = (AuxiliaryModelNode*)item.GetID();
return node->GetParent() != m_root;
}
bool AuxiliaryModel::Rename(const wxDataViewItem& item, const wxString& name)
{
AuxiliaryModelNode* node = (AuxiliaryModelNode*)item.GetID();
AuxiliaryModelNode* parent = node->GetParent();
if (node->IsContainer())
return false;
if (!parent->IsContainer())
return false;
for (AuxiliaryModelNode* cur_node : parent->GetChildren()) {
if (cur_node->name == name)
return false;
}
boost::system::error_code err;
fs::path old_path((m_root_dir + "\\" + parent->name + "\\" + node->name).ToStdWstring());
fs::path new_path((m_root_dir + "\\" + parent->name + "\\" + name).ToStdWstring());
fs::rename(old_path, new_path, err);
if (err.failed())
return false;
Slic3r::put_other_changes();
node->name = name;
node->path = m_root_dir + "\\" + parent->name + "\\" + name;
return true;
}
AuxiliaryModelNode* AuxiliaryModel::GetParent(AuxiliaryModelNode* node) const
{
if (node == m_root || node->GetParent() == m_root)
return nullptr;
return node->GetParent();
}
void AuxiliaryModel::Reparent(AuxiliaryModelNode* node, AuxiliaryModelNode* new_parent)
{
if (node->IsContainer())
return;
node->GetParent()->GetChildren().Remove(node);
node->SetParent(new_parent);
new_parent->Append(node);
}