|
|
|
|
@ -1,6 +1,7 @@
|
|
|
|
|
import os
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
import uuid
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
|
|
|
|
import FreeCAD as App
|
|
|
|
|
|
|
|
|
|
@ -45,7 +46,12 @@ def _append_debug_log(message):
|
|
|
|
|
log_path = _debug_log_path()
|
|
|
|
|
os.makedirs(os.path.dirname(log_path), exist_ok=True)
|
|
|
|
|
with open(log_path, "a", encoding="utf-8") as handle:
|
|
|
|
|
handle.write(message + "\n")
|
|
|
|
|
handle.write(
|
|
|
|
|
"[{0}] {1}\n".format(
|
|
|
|
|
datetime.now().astimezone().isoformat(timespec="seconds"),
|
|
|
|
|
message,
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
@ -183,11 +189,24 @@ def _ensure_child_group(doc, parent_group, element_uuid, instance_id, name_prefi
|
|
|
|
|
def _ensure_document(scene_path):
|
|
|
|
|
preferred_name = _safe_token(Path(scene_path).stem if scene_path else "QETScene")[:48] or "QETScene"
|
|
|
|
|
normalized_scene_path = _native_path(scene_path)
|
|
|
|
|
_append_debug_log(
|
|
|
|
|
"DeviceImport _ensure_document: preferred_name={0}, normalized_scene_path={1}".format(
|
|
|
|
|
preferred_name,
|
|
|
|
|
normalized_scene_path or "<empty>",
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
if normalized_scene_path and os.path.isfile(normalized_scene_path):
|
|
|
|
|
normalized_target = os.path.normcase(os.path.normpath(normalized_scene_path))
|
|
|
|
|
for candidate in App.listDocuments().values():
|
|
|
|
|
candidate_path = getattr(candidate, "FileName", "") or ""
|
|
|
|
|
if candidate_path and os.path.normcase(os.path.normpath(candidate_path)) == normalized_target:
|
|
|
|
|
_append_debug_log(
|
|
|
|
|
"DeviceImport _ensure_document reusing already open scene doc: name={0}, path={1}, objects={2}".format(
|
|
|
|
|
getattr(candidate, "Name", ""),
|
|
|
|
|
candidate_path,
|
|
|
|
|
len(list(getattr(candidate, "Objects", []) or [])),
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
_activate_document(candidate)
|
|
|
|
|
return candidate
|
|
|
|
|
|
|
|
|
|
@ -203,15 +222,36 @@ def _ensure_document(scene_path):
|
|
|
|
|
"Cannot open existing FreeCAD scene file: {0}".format(normalized_scene_path)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
_append_debug_log(
|
|
|
|
|
"DeviceImport _ensure_document opened existing scene doc: name={0}, path={1}, objects={2}".format(
|
|
|
|
|
getattr(doc, "Name", ""),
|
|
|
|
|
getattr(doc, "FileName", "") or normalized_scene_path,
|
|
|
|
|
len(list(getattr(doc, "Objects", []) or [])),
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
_activate_document(doc)
|
|
|
|
|
return doc
|
|
|
|
|
|
|
|
|
|
existing_doc = DevicePreview.find_main_exchange_document(preferred_name)
|
|
|
|
|
if existing_doc is not None:
|
|
|
|
|
_append_debug_log(
|
|
|
|
|
"DeviceImport _ensure_document reusing unsaved exchange doc: name={0}, path={1}, objects={2}".format(
|
|
|
|
|
getattr(existing_doc, "Name", ""),
|
|
|
|
|
getattr(existing_doc, "FileName", "") or "<unsaved>",
|
|
|
|
|
len(list(getattr(existing_doc, "Objects", []) or [])),
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
_activate_document(existing_doc)
|
|
|
|
|
return existing_doc
|
|
|
|
|
|
|
|
|
|
doc = App.newDocument(preferred_name)
|
|
|
|
|
_append_debug_log(
|
|
|
|
|
"DeviceImport _ensure_document created new scene doc: name={0}, path={1}, objects={2}".format(
|
|
|
|
|
getattr(doc, "Name", ""),
|
|
|
|
|
getattr(doc, "FileName", "") or "<unsaved>",
|
|
|
|
|
len(list(getattr(doc, "Objects", []) or [])),
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
_activate_document(doc)
|
|
|
|
|
return doc
|
|
|
|
|
|
|
|
|
|
@ -220,6 +260,24 @@ def _activate_document(doc):
|
|
|
|
|
if doc is None:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
current_doc = getattr(App, "ActiveDocument", None)
|
|
|
|
|
if current_doc is doc:
|
|
|
|
|
_append_debug_log(
|
|
|
|
|
"DeviceImport _activate_document skipped: already active name={0}, path={1}".format(
|
|
|
|
|
getattr(doc, "Name", ""),
|
|
|
|
|
getattr(doc, "FileName", "") or "<unsaved>",
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
_append_debug_log(
|
|
|
|
|
"DeviceImport _activate_document: name={0}, path={1}, objects={2}".format(
|
|
|
|
|
getattr(doc, "Name", ""),
|
|
|
|
|
getattr(doc, "FileName", "") or "<unsaved>",
|
|
|
|
|
len(list(getattr(doc, "Objects", []) or [])),
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
setter = getattr(App, "setActiveDocument", None)
|
|
|
|
|
if callable(setter):
|
|
|
|
|
try:
|
|
|
|
|
@ -418,6 +476,21 @@ def _find_device_group(doc, element_uuid):
|
|
|
|
|
return candidate
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _find_device_group_by_instance_id(doc, instance_id):
|
|
|
|
|
target_instance_id = (instance_id or "").strip()
|
|
|
|
|
if not target_instance_id:
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
for candidate in doc.Objects:
|
|
|
|
|
if not getattr(candidate, "Name", "").startswith(DEVICE_GROUP_PREFIX):
|
|
|
|
|
continue
|
|
|
|
|
if "QetInstanceId" not in getattr(candidate, "PropertiesList", []):
|
|
|
|
|
continue
|
|
|
|
|
if getattr(candidate, "QetInstanceId", "").strip() == target_instance_id:
|
|
|
|
|
return candidate
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
def _device_label_text(display_tag, instance_id, element_uuid):
|
|
|
|
|
label = (display_tag or "").strip()
|
|
|
|
|
if label:
|
|
|
|
|
@ -441,50 +514,176 @@ def _device_warning_subject(display_tag, element_uuid):
|
|
|
|
|
return "设备"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _ensure_device_group(doc, root_group, element_uuid, instance_id, model_path, display_tag, layout_index):
|
|
|
|
|
created_now = False
|
|
|
|
|
device_group = _find_device_group(doc, element_uuid)
|
|
|
|
|
if device_group is not None and getattr(device_group, "TypeId", "") != "App::Part":
|
|
|
|
|
_remove_object_tree(doc, device_group)
|
|
|
|
|
device_group = None
|
|
|
|
|
def _device_report_label(display_tag, instance_id, element_uuid=""):
|
|
|
|
|
label = (display_tag or "").strip()
|
|
|
|
|
if label:
|
|
|
|
|
return label
|
|
|
|
|
fallback = (instance_id or "").strip() or (element_uuid or "").strip()
|
|
|
|
|
return fallback or "未命名设备"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _payload_device_instance_id(device):
|
|
|
|
|
if not isinstance(device, dict):
|
|
|
|
|
return ""
|
|
|
|
|
return (
|
|
|
|
|
(device.get("device_instance_id") or "").strip()
|
|
|
|
|
or (device.get("instance_id") or "").strip()
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _payload_device_element_uuid(device):
|
|
|
|
|
if not isinstance(device, dict):
|
|
|
|
|
return ""
|
|
|
|
|
element_uuid = (device.get("element_uuid") or "").strip()
|
|
|
|
|
if element_uuid:
|
|
|
|
|
return element_uuid
|
|
|
|
|
for terminal in device.get("terminals", []) or []:
|
|
|
|
|
if not isinstance(terminal, dict):
|
|
|
|
|
continue
|
|
|
|
|
element_uuid = (terminal.get("element_uuid") or "").strip()
|
|
|
|
|
if element_uuid:
|
|
|
|
|
return element_uuid
|
|
|
|
|
return ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _payload_terminal_uuid_set(device):
|
|
|
|
|
result = set()
|
|
|
|
|
if not isinstance(device, dict):
|
|
|
|
|
return result
|
|
|
|
|
for terminal in device.get("terminals", []) or []:
|
|
|
|
|
if not isinstance(terminal, dict):
|
|
|
|
|
continue
|
|
|
|
|
terminal_uuid = (terminal.get("terminal_uuid") or "").strip()
|
|
|
|
|
if terminal_uuid:
|
|
|
|
|
result.add(terminal_uuid)
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _existing_qet_terminal_uuids(device_group):
|
|
|
|
|
terminal_group = TerminalObjects.find_child_group_by_kind(
|
|
|
|
|
device_group,
|
|
|
|
|
TerminalObjects.TERMINAL_GROUP_KIND,
|
|
|
|
|
)
|
|
|
|
|
result = set()
|
|
|
|
|
for terminal_obj in TerminalObjects.collect_terminal_objects(terminal_group):
|
|
|
|
|
terminal_uuid = (getattr(terminal_obj, "QetTerminalUuid", "") or "").strip()
|
|
|
|
|
if not terminal_uuid or TerminalObjects.is_local_terminal_uuid(terminal_uuid):
|
|
|
|
|
continue
|
|
|
|
|
result.add(terminal_uuid)
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _device_change_detail(
|
|
|
|
|
display_tag,
|
|
|
|
|
instance_id,
|
|
|
|
|
element_uuid="",
|
|
|
|
|
change_types=None,
|
|
|
|
|
added_terminal_uuids=None,
|
|
|
|
|
removed_terminal_uuids=None,
|
|
|
|
|
previous_display_tag="",
|
|
|
|
|
previous_model_path="",
|
|
|
|
|
resolved_model_path="",
|
|
|
|
|
):
|
|
|
|
|
return {
|
|
|
|
|
"display_tag": (display_tag or "").strip(),
|
|
|
|
|
"instance_id": (instance_id or "").strip(),
|
|
|
|
|
"element_uuid": (element_uuid or "").strip(),
|
|
|
|
|
"label": _device_report_label(display_tag, instance_id, element_uuid),
|
|
|
|
|
"change_types": list(change_types or []),
|
|
|
|
|
"added_terminal_uuids": list(added_terminal_uuids or []),
|
|
|
|
|
"removed_terminal_uuids": list(removed_terminal_uuids or []),
|
|
|
|
|
"previous_display_tag": (previous_display_tag or "").strip(),
|
|
|
|
|
"previous_model_path": (previous_model_path or "").strip(),
|
|
|
|
|
"resolved_model_path": (resolved_model_path or "").strip(),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _update_device_group_metadata(device_group, root_group, element_uuid, instance_id, model_path, display_tag):
|
|
|
|
|
if device_group is None:
|
|
|
|
|
device_group = doc.addObject(
|
|
|
|
|
"App::Part",
|
|
|
|
|
DEVICE_GROUP_PREFIX + _safe_token(element_uuid),
|
|
|
|
|
)
|
|
|
|
|
created_now = True
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
if device_group not in getattr(root_group, "Group", []):
|
|
|
|
|
root_group.addObject(device_group)
|
|
|
|
|
current_element_uuid = getattr(device_group, "QetElementUuid", "").strip()
|
|
|
|
|
current_instance_id = getattr(device_group, "QetInstanceId", "").strip()
|
|
|
|
|
current_model_path = getattr(device_group, "QetResolvedModelPath", "").strip()
|
|
|
|
|
|
|
|
|
|
device_group.Label = _device_label_text(display_tag, instance_id, element_uuid)
|
|
|
|
|
final_element_uuid = (element_uuid or "").strip() or current_element_uuid
|
|
|
|
|
final_instance_id = (instance_id or "").strip() or current_instance_id
|
|
|
|
|
final_model_path = (model_path or "").strip() or current_model_path
|
|
|
|
|
final_display_tag = (display_tag or "").strip()
|
|
|
|
|
|
|
|
|
|
device_group.Label = _device_label_text(
|
|
|
|
|
final_display_tag,
|
|
|
|
|
final_instance_id,
|
|
|
|
|
final_element_uuid,
|
|
|
|
|
)
|
|
|
|
|
_ensure_string_property(
|
|
|
|
|
device_group,
|
|
|
|
|
"QetElementUuid",
|
|
|
|
|
"QET Exchange",
|
|
|
|
|
"2D element UUID from QET",
|
|
|
|
|
element_uuid,
|
|
|
|
|
final_element_uuid,
|
|
|
|
|
)
|
|
|
|
|
_ensure_string_property(
|
|
|
|
|
device_group,
|
|
|
|
|
"QetInstanceId",
|
|
|
|
|
"QET Exchange",
|
|
|
|
|
"3D instance id from QET/FreeCAD exchange",
|
|
|
|
|
instance_id,
|
|
|
|
|
final_instance_id,
|
|
|
|
|
)
|
|
|
|
|
_ensure_string_property(
|
|
|
|
|
device_group,
|
|
|
|
|
"QetResolvedModelPath",
|
|
|
|
|
"QET Exchange",
|
|
|
|
|
"Resolved local model path from QET exchange",
|
|
|
|
|
model_path,
|
|
|
|
|
final_model_path,
|
|
|
|
|
)
|
|
|
|
|
_ensure_string_property(
|
|
|
|
|
device_group,
|
|
|
|
|
"QetDisplayTag",
|
|
|
|
|
"QET Exchange",
|
|
|
|
|
"2D display tag from QET exchange",
|
|
|
|
|
final_display_tag,
|
|
|
|
|
)
|
|
|
|
|
_ensure_string_property(
|
|
|
|
|
device_group,
|
|
|
|
|
"QetProjectUuid",
|
|
|
|
|
"QET Exchange",
|
|
|
|
|
"Project UUID from QET exchange",
|
|
|
|
|
getattr(root_group, "QetProjectUuid", "").strip(),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _ensure_device_group(doc, root_group, element_uuid, instance_id, model_path, display_tag, layout_index):
|
|
|
|
|
created_now = False
|
|
|
|
|
device_group = _find_device_group_by_instance_id(doc, instance_id)
|
|
|
|
|
if device_group is None:
|
|
|
|
|
device_group = _find_device_group(doc, element_uuid)
|
|
|
|
|
if device_group is not None and getattr(device_group, "TypeId", "") != "App::Part":
|
|
|
|
|
_remove_object_tree(doc, device_group)
|
|
|
|
|
device_group = None
|
|
|
|
|
|
|
|
|
|
if device_group is None:
|
|
|
|
|
group_token = (
|
|
|
|
|
(element_uuid or "").strip()
|
|
|
|
|
or (instance_id or "").strip()
|
|
|
|
|
or (display_tag or "").strip()
|
|
|
|
|
or "device-{0}".format(layout_index)
|
|
|
|
|
)
|
|
|
|
|
device_group = doc.addObject(
|
|
|
|
|
"App::Part",
|
|
|
|
|
DEVICE_GROUP_PREFIX + _safe_token(group_token),
|
|
|
|
|
)
|
|
|
|
|
created_now = True
|
|
|
|
|
|
|
|
|
|
if device_group not in getattr(root_group, "Group", []):
|
|
|
|
|
root_group.addObject(device_group)
|
|
|
|
|
|
|
|
|
|
_update_device_group_metadata(
|
|
|
|
|
device_group,
|
|
|
|
|
root_group,
|
|
|
|
|
element_uuid,
|
|
|
|
|
instance_id,
|
|
|
|
|
model_path,
|
|
|
|
|
display_tag,
|
|
|
|
|
)
|
|
|
|
|
_ensure_bool_property(
|
|
|
|
|
@ -647,6 +846,14 @@ def _existing_group_objects(doc, group):
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _existing_model_objects(doc, group):
|
|
|
|
|
return [
|
|
|
|
|
child
|
|
|
|
|
for child in _existing_group_objects(doc, group)
|
|
|
|
|
if not _is_exchange_sidecar_group(child)
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _is_exchange_sidecar_group(obj):
|
|
|
|
|
child_name = _object_name(obj)
|
|
|
|
|
if child_name.startswith(TERMINAL_GROUP_PREFIX) or child_name.startswith(WIRE_GROUP_PREFIX):
|
|
|
|
|
@ -785,9 +992,21 @@ def _supported_for_import(model_path):
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _import_model_into_group(doc, device_group, model_path, merge=False, use_link_group=True):
|
|
|
|
|
def _import_model_into_group(
|
|
|
|
|
doc,
|
|
|
|
|
device_group,
|
|
|
|
|
model_path,
|
|
|
|
|
merge=False,
|
|
|
|
|
use_link_group=True,
|
|
|
|
|
source_doc_cache=None,
|
|
|
|
|
):
|
|
|
|
|
if Path(model_path).suffix.lower() == ".fcstd":
|
|
|
|
|
return _import_fcstd_into_group(doc, device_group, model_path)
|
|
|
|
|
return _import_fcstd_into_group(
|
|
|
|
|
doc,
|
|
|
|
|
device_group,
|
|
|
|
|
model_path,
|
|
|
|
|
source_doc_cache=source_doc_cache,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
before_names = _existing_object_names(doc)
|
|
|
|
|
try:
|
|
|
|
|
@ -812,26 +1031,84 @@ def _import_model_into_group(doc, device_group, model_path, merge=False, use_lin
|
|
|
|
|
return top_level_objects
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _open_fcstd_source_document(model_path):
|
|
|
|
|
def _open_fcstd_source_document(model_path, source_doc_cache=None):
|
|
|
|
|
normalized_target = os.path.normcase(os.path.normpath(model_path))
|
|
|
|
|
if source_doc_cache is not None:
|
|
|
|
|
cached_entry = source_doc_cache.get(normalized_target)
|
|
|
|
|
if cached_entry is not None:
|
|
|
|
|
cached_doc = cached_entry.get("doc")
|
|
|
|
|
if cached_doc is not None:
|
|
|
|
|
_append_debug_log(
|
|
|
|
|
"DeviceImport _open_fcstd_source_document cache hit: name={0}, path={1}, objects={2}, should_close={3}".format(
|
|
|
|
|
getattr(cached_doc, "Name", ""),
|
|
|
|
|
getattr(cached_doc, "FileName", "") or model_path,
|
|
|
|
|
len(list(getattr(cached_doc, "Objects", []) or [])),
|
|
|
|
|
bool(cached_entry.get("should_close")),
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
return cached_doc, False
|
|
|
|
|
|
|
|
|
|
for candidate in App.listDocuments().values():
|
|
|
|
|
candidate_path = getattr(candidate, "FileName", "") or ""
|
|
|
|
|
if candidate_path and os.path.normcase(os.path.normpath(candidate_path)) == normalized_target:
|
|
|
|
|
_append_debug_log(
|
|
|
|
|
"DeviceImport _open_fcstd_source_document reusing open source doc: name={0}, path={1}, objects={2}".format(
|
|
|
|
|
getattr(candidate, "Name", ""),
|
|
|
|
|
candidate_path,
|
|
|
|
|
len(list(getattr(candidate, "Objects", []) or [])),
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
if source_doc_cache is not None:
|
|
|
|
|
source_doc_cache[normalized_target] = {
|
|
|
|
|
"doc": candidate,
|
|
|
|
|
"should_close": False,
|
|
|
|
|
}
|
|
|
|
|
return candidate, False
|
|
|
|
|
source_doc = App.openDocument(model_path, hidden=True, temporary=True)
|
|
|
|
|
_append_debug_log(
|
|
|
|
|
"DeviceImport _open_fcstd_source_document opened temp source doc: name={0}, path={1}, objects={2}".format(
|
|
|
|
|
getattr(source_doc, "Name", "") if source_doc is not None else "<none>",
|
|
|
|
|
getattr(source_doc, "FileName", "") if source_doc is not None else model_path,
|
|
|
|
|
len(list(getattr(source_doc, "Objects", []) or [])) if source_doc is not None else -1,
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
if source_doc_cache is not None and source_doc is not None:
|
|
|
|
|
source_doc_cache[normalized_target] = {
|
|
|
|
|
"doc": source_doc,
|
|
|
|
|
"should_close": True,
|
|
|
|
|
}
|
|
|
|
|
return source_doc, False
|
|
|
|
|
return source_doc, True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _import_fcstd_into_group(doc, device_group, model_path):
|
|
|
|
|
def _import_fcstd_into_group(doc, device_group, model_path, source_doc_cache=None):
|
|
|
|
|
source_doc = None
|
|
|
|
|
should_close = False
|
|
|
|
|
try:
|
|
|
|
|
source_doc, should_close = _open_fcstd_source_document(model_path)
|
|
|
|
|
_append_debug_log(
|
|
|
|
|
"DeviceImport _import_fcstd_into_group start: target_doc={0}, target_objects={1}, device_group={2}, model_path={3}".format(
|
|
|
|
|
getattr(doc, "Name", ""),
|
|
|
|
|
len(list(getattr(doc, "Objects", []) or [])),
|
|
|
|
|
getattr(device_group, "Name", ""),
|
|
|
|
|
model_path,
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
source_doc, should_close = _open_fcstd_source_document(
|
|
|
|
|
model_path,
|
|
|
|
|
source_doc_cache=source_doc_cache,
|
|
|
|
|
)
|
|
|
|
|
if source_doc is None:
|
|
|
|
|
raise DeviceImportError("Cannot open FCStd file")
|
|
|
|
|
|
|
|
|
|
TemplateSemantics.clear_stored_template_slot_hints(device_group)
|
|
|
|
|
top_level_objects = _top_level_document_objects(source_doc)
|
|
|
|
|
_append_debug_log(
|
|
|
|
|
"DeviceImport _import_fcstd_into_group source ready: source_doc={0}, top_level_objects={1}, should_close={2}".format(
|
|
|
|
|
getattr(source_doc, "Name", ""),
|
|
|
|
|
len(top_level_objects),
|
|
|
|
|
should_close,
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
copied_objects = []
|
|
|
|
|
for source_obj in top_level_objects:
|
|
|
|
|
copied_obj = doc.copyObject(source_obj, True)
|
|
|
|
|
@ -853,26 +1130,81 @@ def _import_fcstd_into_group(doc, device_group, model_path):
|
|
|
|
|
copied_model_objects,
|
|
|
|
|
)
|
|
|
|
|
_keep_only_direct_model_children(device_group, direct_model_objects)
|
|
|
|
|
_append_debug_log(
|
|
|
|
|
"DeviceImport _import_fcstd_into_group completed: copied_objects={0}, direct_model_objects={1}, target_doc_objects={2}".format(
|
|
|
|
|
len(copied_objects),
|
|
|
|
|
len(direct_model_objects),
|
|
|
|
|
len(list(getattr(doc, "Objects", []) or [])),
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
return direct_model_objects
|
|
|
|
|
finally:
|
|
|
|
|
if should_close and source_doc is not None:
|
|
|
|
|
try:
|
|
|
|
|
_append_debug_log(
|
|
|
|
|
"DeviceImport _import_fcstd_into_group closing temp source doc: name={0}, path={1}".format(
|
|
|
|
|
getattr(source_doc, "Name", ""),
|
|
|
|
|
getattr(source_doc, "FileName", "") or model_path,
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
App.closeDocument(source_doc.Name)
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
_activate_document(doc)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _close_cached_source_documents(source_doc_cache, target_doc=None):
|
|
|
|
|
if not source_doc_cache:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
closed_count = 0
|
|
|
|
|
for normalized_target, cached_entry in list(source_doc_cache.items()):
|
|
|
|
|
cached_doc = cached_entry.get("doc")
|
|
|
|
|
should_close = bool(cached_entry.get("should_close"))
|
|
|
|
|
if not should_close or cached_doc is None:
|
|
|
|
|
continue
|
|
|
|
|
try:
|
|
|
|
|
_append_debug_log(
|
|
|
|
|
"DeviceImport _close_cached_source_documents closing cached doc: name={0}, path={1}".format(
|
|
|
|
|
getattr(cached_doc, "Name", ""),
|
|
|
|
|
getattr(cached_doc, "FileName", "") or normalized_target,
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
App.closeDocument(cached_doc.Name)
|
|
|
|
|
closed_count += 1
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
_append_debug_log(
|
|
|
|
|
"DeviceImport _close_cached_source_documents failed: name={0}, error={1}".format(
|
|
|
|
|
getattr(cached_doc, "Name", ""),
|
|
|
|
|
exc,
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
source_doc_cache.clear()
|
|
|
|
|
_append_debug_log(
|
|
|
|
|
"DeviceImport _close_cached_source_documents completed: closed_count={0}".format(
|
|
|
|
|
closed_count
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
if target_doc is not None:
|
|
|
|
|
_activate_document(target_doc)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _model_index(payload):
|
|
|
|
|
index = {}
|
|
|
|
|
for item in payload.get("device_models", []):
|
|
|
|
|
element_uuid = item.get("element_uuid", "").strip()
|
|
|
|
|
instance_id = (
|
|
|
|
|
(item.get("device_instance_id") or "").strip()
|
|
|
|
|
or (item.get("instance_id") or "").strip()
|
|
|
|
|
)
|
|
|
|
|
element_uuid = (item.get("element_uuid") or "").strip()
|
|
|
|
|
if instance_id and instance_id not in index:
|
|
|
|
|
index[instance_id] = item
|
|
|
|
|
if element_uuid and element_uuid not in index:
|
|
|
|
|
index[element_uuid] = item
|
|
|
|
|
return index
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _import_cabinet_model(doc, root_group, cabinet, report):
|
|
|
|
|
def _import_cabinet_model(doc, root_group, cabinet, report, source_doc_cache=None):
|
|
|
|
|
if not isinstance(cabinet, dict):
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
@ -934,6 +1266,7 @@ def _import_cabinet_model(doc, root_group, cabinet, report):
|
|
|
|
|
resolved_scene_path,
|
|
|
|
|
merge=False,
|
|
|
|
|
use_link_group=True,
|
|
|
|
|
source_doc_cache=source_doc_cache,
|
|
|
|
|
)
|
|
|
|
|
report["cabinet_imported"] += 1
|
|
|
|
|
if had_existing_model:
|
|
|
|
|
@ -960,6 +1293,7 @@ def import_devices_from_payload(payload, scene_path=""):
|
|
|
|
|
project_uuid = (payload.get("project_uuid") or "").strip()
|
|
|
|
|
root_group = _ensure_root_group(doc, cabinet, project_uuid)
|
|
|
|
|
models_by_element = _model_index(payload)
|
|
|
|
|
source_doc_cache = {}
|
|
|
|
|
|
|
|
|
|
report = {
|
|
|
|
|
"document_name": doc.Name,
|
|
|
|
|
@ -967,6 +1301,10 @@ def import_devices_from_payload(payload, scene_path=""):
|
|
|
|
|
"total_devices": 0,
|
|
|
|
|
"imported_devices": 0,
|
|
|
|
|
"updated_devices": 0,
|
|
|
|
|
"reused_devices": 0,
|
|
|
|
|
"added_device_details": [],
|
|
|
|
|
"updated_device_details": [],
|
|
|
|
|
"reused_device_details": [],
|
|
|
|
|
"imported_without_instance_id": 0,
|
|
|
|
|
"skipped_missing_model": 0,
|
|
|
|
|
"skipped_missing_file": 0,
|
|
|
|
|
@ -983,114 +1321,281 @@ def import_devices_from_payload(payload, scene_path=""):
|
|
|
|
|
"warnings": [],
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_import_cabinet_model(doc, root_group, cabinet, report)
|
|
|
|
|
|
|
|
|
|
for index, device in enumerate(payload.get("devices", [])):
|
|
|
|
|
report["total_devices"] += 1
|
|
|
|
|
|
|
|
|
|
element_uuid = device.get("element_uuid", "").strip()
|
|
|
|
|
instance_id = (device.get("instance_id") or "").strip()
|
|
|
|
|
display_tag = (device.get("display_tag") or "").strip()
|
|
|
|
|
model_info = models_by_element.get(element_uuid, {})
|
|
|
|
|
resolved_model_path = _native_path(model_info.get("resolved_model_path", ""))
|
|
|
|
|
_append_debug_log(
|
|
|
|
|
"DeviceImport device element_uuid={0}, instance_id={1}, display_tag={2}, resolved_model_path={3}".format(
|
|
|
|
|
element_uuid, instance_id, display_tag, resolved_model_path
|
|
|
|
|
)
|
|
|
|
|
try:
|
|
|
|
|
_import_cabinet_model(
|
|
|
|
|
doc,
|
|
|
|
|
root_group,
|
|
|
|
|
cabinet,
|
|
|
|
|
report,
|
|
|
|
|
source_doc_cache=source_doc_cache,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if not resolved_model_path:
|
|
|
|
|
report["skipped_missing_model"] += 1
|
|
|
|
|
report["warnings"].append(
|
|
|
|
|
"{0} 缺少 resolved_model_path,已跳过。".format(
|
|
|
|
|
_device_warning_subject(display_tag, element_uuid)
|
|
|
|
|
for index, device in enumerate(payload.get("devices", [])):
|
|
|
|
|
report["total_devices"] += 1
|
|
|
|
|
|
|
|
|
|
original_instance_id = _payload_device_instance_id(device)
|
|
|
|
|
instance_id = original_instance_id
|
|
|
|
|
element_uuid = _payload_device_element_uuid(device)
|
|
|
|
|
display_tag = (device.get("display_tag") or "").strip()
|
|
|
|
|
payload_terminal_uuids = _payload_terminal_uuid_set(device)
|
|
|
|
|
existing_device_group = _find_device_group_by_instance_id(doc, instance_id)
|
|
|
|
|
if existing_device_group is None:
|
|
|
|
|
existing_device_group = _find_device_group(doc, element_uuid)
|
|
|
|
|
previous_display_tag = ""
|
|
|
|
|
previous_path = ""
|
|
|
|
|
existing_terminal_uuids = set()
|
|
|
|
|
existing_model_objects = []
|
|
|
|
|
if existing_device_group is not None:
|
|
|
|
|
previous_display_tag = getattr(
|
|
|
|
|
existing_device_group,
|
|
|
|
|
"QetDisplayTag",
|
|
|
|
|
"",
|
|
|
|
|
).strip()
|
|
|
|
|
previous_path = getattr(
|
|
|
|
|
existing_device_group,
|
|
|
|
|
"QetResolvedModelPath",
|
|
|
|
|
"",
|
|
|
|
|
).strip()
|
|
|
|
|
existing_terminal_uuids = _existing_qet_terminal_uuids(
|
|
|
|
|
existing_device_group
|
|
|
|
|
)
|
|
|
|
|
existing_model_objects = _existing_model_objects(
|
|
|
|
|
doc, existing_device_group
|
|
|
|
|
)
|
|
|
|
|
model_info = models_by_element.get(instance_id or element_uuid, {})
|
|
|
|
|
resolved_model_path = _native_path(model_info.get("resolved_model_path", ""))
|
|
|
|
|
_append_debug_log(
|
|
|
|
|
"DeviceImport device instance_id={0}, display_tag={1}, resolved_model_path={2}".format(
|
|
|
|
|
instance_id, display_tag, resolved_model_path
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
if not os.path.isfile(resolved_model_path):
|
|
|
|
|
report["skipped_missing_file"] += 1
|
|
|
|
|
report["warnings"].append(
|
|
|
|
|
"{0} 的模型文件不存在:{1}".format(
|
|
|
|
|
_device_warning_subject(display_tag, element_uuid),
|
|
|
|
|
resolved_model_path,
|
|
|
|
|
if not resolved_model_path:
|
|
|
|
|
display_tag_changed = bool(
|
|
|
|
|
existing_device_group is not None
|
|
|
|
|
and previous_display_tag != display_tag
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
continue
|
|
|
|
|
if existing_device_group is not None:
|
|
|
|
|
_update_device_group_metadata(
|
|
|
|
|
existing_device_group,
|
|
|
|
|
root_group,
|
|
|
|
|
element_uuid,
|
|
|
|
|
instance_id,
|
|
|
|
|
previous_path,
|
|
|
|
|
display_tag,
|
|
|
|
|
)
|
|
|
|
|
if display_tag_changed:
|
|
|
|
|
report["updated_devices"] += 1
|
|
|
|
|
report["updated_device_details"].append(
|
|
|
|
|
_device_change_detail(
|
|
|
|
|
display_tag,
|
|
|
|
|
(instance_id or getattr(existing_device_group, "QetInstanceId", "")).strip(),
|
|
|
|
|
element_uuid=element_uuid,
|
|
|
|
|
change_types=["标注"],
|
|
|
|
|
previous_display_tag=previous_display_tag,
|
|
|
|
|
previous_model_path=previous_path,
|
|
|
|
|
resolved_model_path=previous_path,
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
report["skipped_missing_model"] += 1
|
|
|
|
|
report["warnings"].append(
|
|
|
|
|
"{0} 缺少 resolved_model_path,已跳过。".format(
|
|
|
|
|
_device_warning_subject(display_tag, instance_id)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
if not _supported_for_import(resolved_model_path):
|
|
|
|
|
report["skipped_unsupported_format"] += 1
|
|
|
|
|
report["warnings"].append(
|
|
|
|
|
"{0} 的模型格式暂不支持:{1}".format(
|
|
|
|
|
_device_warning_subject(display_tag, element_uuid),
|
|
|
|
|
resolved_model_path,
|
|
|
|
|
if not os.path.isfile(resolved_model_path):
|
|
|
|
|
report["skipped_missing_file"] += 1
|
|
|
|
|
report["warnings"].append(
|
|
|
|
|
"{0} 的模型文件不存在:{1}".format(
|
|
|
|
|
_device_warning_subject(display_tag, instance_id),
|
|
|
|
|
resolved_model_path,
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
continue
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
existing_group = _find_device_group(doc, element_uuid)
|
|
|
|
|
if not instance_id:
|
|
|
|
|
existing_instance_id = ""
|
|
|
|
|
if existing_group is not None:
|
|
|
|
|
existing_instance_id = getattr(existing_group, "QetInstanceId", "").strip()
|
|
|
|
|
instance_id = existing_instance_id or _generate_instance_id(project_uuid, element_uuid)
|
|
|
|
|
report.setdefault("generated_instance_ids", 0)
|
|
|
|
|
report["generated_instance_ids"] += 1
|
|
|
|
|
device_group, created_now = _ensure_device_group(
|
|
|
|
|
doc,
|
|
|
|
|
root_group,
|
|
|
|
|
element_uuid,
|
|
|
|
|
instance_id,
|
|
|
|
|
resolved_model_path,
|
|
|
|
|
display_tag,
|
|
|
|
|
index,
|
|
|
|
|
)
|
|
|
|
|
_clear_group_contents(doc, device_group)
|
|
|
|
|
if not _supported_for_import(resolved_model_path):
|
|
|
|
|
report["skipped_unsupported_format"] += 1
|
|
|
|
|
report["warnings"].append(
|
|
|
|
|
"{0} 的模型格式暂不支持:{1}".format(
|
|
|
|
|
_device_warning_subject(display_tag, instance_id),
|
|
|
|
|
resolved_model_path,
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
_append_debug_log(
|
|
|
|
|
"DeviceImport importing model for element_uuid={0}: {1}".format(
|
|
|
|
|
element_uuid, resolved_model_path
|
|
|
|
|
if not instance_id:
|
|
|
|
|
instance_id = _generate_instance_id(
|
|
|
|
|
project_uuid, display_tag or element_uuid or "device-{0}".format(index)
|
|
|
|
|
)
|
|
|
|
|
report.setdefault("generated_instance_ids", 0)
|
|
|
|
|
report["generated_instance_ids"] += 1
|
|
|
|
|
device_group, created_now = _ensure_device_group(
|
|
|
|
|
doc,
|
|
|
|
|
root_group,
|
|
|
|
|
element_uuid,
|
|
|
|
|
instance_id,
|
|
|
|
|
resolved_model_path,
|
|
|
|
|
display_tag,
|
|
|
|
|
index,
|
|
|
|
|
)
|
|
|
|
|
_import_model_into_group(doc, device_group, resolved_model_path)
|
|
|
|
|
_append_debug_log(
|
|
|
|
|
"DeviceImport import succeeded for element_uuid={0}".format(element_uuid)
|
|
|
|
|
|
|
|
|
|
same_source = (
|
|
|
|
|
_normalized_path_key(previous_path)
|
|
|
|
|
== _normalized_path_key(resolved_model_path)
|
|
|
|
|
)
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
report["skipped_import_error"] += 1
|
|
|
|
|
report["warnings"].append(
|
|
|
|
|
"{0} 导入失败:{1}".format(
|
|
|
|
|
_device_warning_subject(display_tag, element_uuid),
|
|
|
|
|
exc,
|
|
|
|
|
)
|
|
|
|
|
added_terminal_uuids = sorted(
|
|
|
|
|
payload_terminal_uuids - existing_terminal_uuids
|
|
|
|
|
)
|
|
|
|
|
_append_debug_log(
|
|
|
|
|
"DeviceImport import failed for element_uuid={0}: {1}".format(
|
|
|
|
|
element_uuid, exc
|
|
|
|
|
)
|
|
|
|
|
removed_terminal_uuids = sorted(
|
|
|
|
|
existing_terminal_uuids - payload_terminal_uuids
|
|
|
|
|
)
|
|
|
|
|
continue
|
|
|
|
|
terminals_changed = bool(
|
|
|
|
|
added_terminal_uuids or removed_terminal_uuids
|
|
|
|
|
)
|
|
|
|
|
display_tag_changed = (
|
|
|
|
|
not created_now and previous_display_tag != display_tag
|
|
|
|
|
)
|
|
|
|
|
model_changed = (
|
|
|
|
|
not created_now
|
|
|
|
|
and (not existing_model_objects or not same_source)
|
|
|
|
|
)
|
|
|
|
|
if existing_model_objects and same_source:
|
|
|
|
|
if display_tag_changed or terminals_changed:
|
|
|
|
|
change_types = []
|
|
|
|
|
if display_tag_changed:
|
|
|
|
|
change_types.append("标注")
|
|
|
|
|
if terminals_changed:
|
|
|
|
|
change_types.append("端子")
|
|
|
|
|
report["updated_devices"] += 1
|
|
|
|
|
report["updated_device_details"].append(
|
|
|
|
|
_device_change_detail(
|
|
|
|
|
display_tag,
|
|
|
|
|
instance_id,
|
|
|
|
|
element_uuid=element_uuid,
|
|
|
|
|
change_types=change_types,
|
|
|
|
|
added_terminal_uuids=added_terminal_uuids,
|
|
|
|
|
removed_terminal_uuids=removed_terminal_uuids,
|
|
|
|
|
previous_display_tag=previous_display_tag,
|
|
|
|
|
previous_model_path=previous_path,
|
|
|
|
|
resolved_model_path=resolved_model_path,
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
_append_debug_log(
|
|
|
|
|
"DeviceImport import skipped: metadata-only change for instance_id={0}, display_tag_changed={1}, added_terminals={2}, removed_terminals={3}".format(
|
|
|
|
|
instance_id,
|
|
|
|
|
display_tag_changed,
|
|
|
|
|
len(added_terminal_uuids),
|
|
|
|
|
len(removed_terminal_uuids),
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
continue
|
|
|
|
|
report["reused_devices"] += 1
|
|
|
|
|
report["reused_device_details"].append(
|
|
|
|
|
_device_change_detail(
|
|
|
|
|
display_tag,
|
|
|
|
|
instance_id,
|
|
|
|
|
element_uuid=element_uuid,
|
|
|
|
|
previous_display_tag=previous_display_tag,
|
|
|
|
|
previous_model_path=previous_path,
|
|
|
|
|
resolved_model_path=resolved_model_path,
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
_append_debug_log(
|
|
|
|
|
"DeviceImport import skipped: reused existing device group for instance_id={0}, model_path={1}, existing_model_objects={2}".format(
|
|
|
|
|
instance_id,
|
|
|
|
|
resolved_model_path,
|
|
|
|
|
len(existing_model_objects),
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
if created_now or existing_group is None:
|
|
|
|
|
report["imported_devices"] += 1
|
|
|
|
|
else:
|
|
|
|
|
report["updated_devices"] += 1
|
|
|
|
|
_clear_group_contents(doc, device_group)
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
_append_debug_log(
|
|
|
|
|
"DeviceImport importing model for device_instance_id={0}: {1}".format(
|
|
|
|
|
instance_id, resolved_model_path
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
_import_model_into_group(
|
|
|
|
|
doc,
|
|
|
|
|
device_group,
|
|
|
|
|
resolved_model_path,
|
|
|
|
|
source_doc_cache=source_doc_cache,
|
|
|
|
|
)
|
|
|
|
|
_append_debug_log(
|
|
|
|
|
"DeviceImport import succeeded for device_instance_id={0}".format(
|
|
|
|
|
instance_id
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
report["skipped_import_error"] += 1
|
|
|
|
|
report["warnings"].append(
|
|
|
|
|
"{0} 导入失败:{1}".format(
|
|
|
|
|
_device_warning_subject(display_tag, element_uuid or instance_id),
|
|
|
|
|
exc,
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
_append_debug_log(
|
|
|
|
|
"DeviceImport import failed for device_instance_id={0}: {1}".format(
|
|
|
|
|
instance_id, exc
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
if not instance_id:
|
|
|
|
|
report["imported_without_instance_id"] += 1
|
|
|
|
|
if created_now:
|
|
|
|
|
report["imported_devices"] += 1
|
|
|
|
|
report["added_device_details"].append(
|
|
|
|
|
_device_change_detail(
|
|
|
|
|
display_tag,
|
|
|
|
|
instance_id,
|
|
|
|
|
element_uuid=element_uuid,
|
|
|
|
|
previous_display_tag=previous_display_tag,
|
|
|
|
|
previous_model_path=previous_path,
|
|
|
|
|
resolved_model_path=resolved_model_path,
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
else:
|
|
|
|
|
report["updated_devices"] += 1
|
|
|
|
|
change_types = []
|
|
|
|
|
if display_tag_changed:
|
|
|
|
|
change_types.append("标注")
|
|
|
|
|
if model_changed:
|
|
|
|
|
change_types.append("3D模型")
|
|
|
|
|
if terminals_changed:
|
|
|
|
|
change_types.append("端子")
|
|
|
|
|
if not change_types:
|
|
|
|
|
change_types.append("3D模型")
|
|
|
|
|
report["updated_device_details"].append(
|
|
|
|
|
_device_change_detail(
|
|
|
|
|
display_tag,
|
|
|
|
|
instance_id,
|
|
|
|
|
element_uuid=element_uuid,
|
|
|
|
|
change_types=change_types,
|
|
|
|
|
added_terminal_uuids=added_terminal_uuids,
|
|
|
|
|
removed_terminal_uuids=removed_terminal_uuids,
|
|
|
|
|
previous_display_tag=previous_display_tag,
|
|
|
|
|
previous_model_path=previous_path,
|
|
|
|
|
resolved_model_path=resolved_model_path,
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if not original_instance_id:
|
|
|
|
|
report["imported_without_instance_id"] += 1
|
|
|
|
|
finally:
|
|
|
|
|
_close_cached_source_documents(source_doc_cache, target_doc=doc)
|
|
|
|
|
|
|
|
|
|
doc.recompute()
|
|
|
|
|
try:
|
|
|
|
|
Gui.SendMsgToActiveView("ViewFit")
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
_append_debug_log("DeviceImport ViewFit skipped during exchange import")
|
|
|
|
|
|
|
|
|
|
_append_debug_log(
|
|
|
|
|
"DeviceImport finished: cabinet_imported={0}, imported={1}, updated={2}, skipped_missing_model={3}, skipped_missing_file={4}, skipped_import_error={5}".format(
|
|
|
|
|
"DeviceImport finished: cabinet_imported={0}, imported={1}, updated={2}, reused={3}, skipped_missing_model={4}, skipped_missing_file={5}, skipped_import_error={6}".format(
|
|
|
|
|
report["cabinet_imported"],
|
|
|
|
|
report["imported_devices"],
|
|
|
|
|
report["updated_devices"],
|
|
|
|
|
report["reused_devices"],
|
|
|
|
|
report["skipped_missing_model"],
|
|
|
|
|
report["skipped_missing_file"],
|
|
|
|
|
report["skipped_import_error"],
|
|
|
|
|
|