diff --git a/src/blenderbim/blenderbim/bim/data/webui/sioserver.py b/src/blenderbim/blenderbim/bim/data/webui/sioserver.py index 75106c6e8c..6d81c03665 100644 --- a/src/blenderbim/blenderbim/bim/data/webui/sioserver.py +++ b/src/blenderbim/blenderbim/bim/data/webui/sioserver.py @@ -2,7 +2,9 @@ import sys import os import webbrowser -blenderbim_lib_path = os.environ.get("blenderbim_lib_path") +blenderbim_lib_path = os.environ.get("BLENDERBIM_LIB_PATH") +blenderbim_version = os.environ.get("BLENDERBIM_VERSION") + if blenderbim_lib_path: sys.path.insert(0, blenderbim_lib_path) @@ -52,9 +54,16 @@ class WebNamespace(socketio.AsyncNamespace): "web_operator", data, namespace="/blender", - room=data["blenderId"], + room=data.get("blenderId", None), ) + async def on_get_svg(self, sid, data): + print("hello world!") + file_path = data["path"] + with open(file_path, "r") as file: + svg_data = file.read() + await sio.emit("svg_data", svg_data, room=sid, namespace="/web") + async def send_cached_messages(self, sid): # Send cached messages to the connected web client for blenderId, messages in blender_messages.items(): @@ -98,6 +107,12 @@ class BlenderNamespace(socketio.AsyncNamespace): blender_messages[sid]["gantt_data"] = data await sio.emit("gantt_data", {"blenderId": sid, "data": data}, namespace="/web") + async def on_drawings_data(self, sid, data): + print(f"Drawings directory from Blender client {sid}") + print(data) + blender_messages[sid]["drwings_data"] = data + await sio.emit("drawings_data", {"blenderId": sid, "data": data}, namespace="/web") + # Attach namespaces sio.register_namespace(WebNamespace("/web")) @@ -108,13 +123,20 @@ sio.register_namespace(BlenderNamespace("/blender")) async def index(request): with open("templates/index.html", "r") as f: template = f.read() - html_content = pystache.render(template, {"port": sio_port}) + html_content = pystache.render(template, {"port": sio_port, "version": blenderbim_version}) return web.Response(text=html_content, content_type="text/html") async def gantt(request): with open("templates/gantt.html", "r") as f: template = f.read() + html_content = pystache.render(template, {"port": sio_port, "version": blenderbim_version}) + return web.Response(text=html_content, content_type="text/html") + + +async def drawings(request): + with open("templates/drawings.html", "r") as f: + template = f.read() html_content = pystache.render(template, {"port": sio_port}) return web.Response(text=html_content, content_type="text/html") @@ -135,6 +157,7 @@ async def on_startup(app): app.router.add_get("/", index) +app.router.add_get("/drawings", drawings) app.router.add_get("/gantt", gantt) app.router.add_static("/jsgantt/", path="../gantt", name="jsgantt") app.router.add_static("/static/", path="./static", name="static") diff --git a/src/blenderbim/blenderbim/bim/data/webui/static/css/drawings.css b/src/blenderbim/blenderbim/bim/data/webui/static/css/drawings.css new file mode 100644 index 0000000000..9dd2437ecf --- /dev/null +++ b/src/blenderbim/blenderbim/bim/data/webui/static/css/drawings.css @@ -0,0 +1,249 @@ +:root { + --font-family: Arial, sans-serif; + --base-font-size: 16px; + --margin-tiny: 0.125rem; + --margin-small: 0.625rem; + --margin-medium: 1.25rem; + --margin-large: 2.5rem; + --padding-tiny: 0.125rem; + --padding-small: 0.625rem; + --padding-medium: 1rem; + --font-size-large: 1.2rem; + --logo-height: 2.5rem; + --nav-height: 2.5rem; +} + +:root.dark { + color-scheme: dark; + --bg-color: #252525; + --text-color: #e0e0e0; + --nav-bg-color: #121212; + --nav-border-color: #25682a; + --nav-link-color: #fff; + --nav-link-hover-color: #3fb449; + --warning-color: #FFDB8F; + --border-color: #464444; +} + +:root.light { + color-scheme: light; + --bg-color: #ffffff; + --text-color: #000000; + --nav-bg-color: #f8f8f8; + --nav-border-color: #cccccc; + --nav-link-color: #000000; + --nav-link-hover-color: #38a63d; + --warning-color: #FF4500; + --border-color: #222; +} + +html { + font-size: var(--base-font-size); + color: var(--text-color); +} + +body { + background-color: var(--bg-color); + color: var(--text-color); + margin: 0; + font-family: var(--font-family); +} + +#container { + margin-top: var(--margin-medium); + margin-left: var(--margin-small); + margin-right: var(--margin-small); + margin-bottom: var(--margin-medium); + height: calc(100vh - var(--nav-height)); + box-sizing: border-box; + display: flex; +} + +h3 { + margin-top: 0; +} + +nav { + background-color: var(--nav-bg-color); + height: var(--nav-height); + padding: var(--padding-medium) 0; + display: flex; + align-items: center; + position: relative; + border-bottom: 2px solid var(--nav-border-color); +} + +nav .logo { + margin-left: var(--margin-large); + height: var(--logo-height); +} + +nav ul { + list-style-type: none; + margin: 0; + margin-left: 0.0625rem; + display: flex; + flex-grow: 1; + justify-content: center; +} + +nav ul li { + margin-right: 3.125rem; +} + +nav ul li a { + text-decoration: none; + color: var(--nav-link-color); + font-size: var(--font-size-large); +} + +nav ul li a:hover, +nav ul li a.active { + color: var(--nav-link-hover-color); +} + +.warning { + color: var(--warning-color); + margin-bottom: var(--margin-small); + padding: var(--padding-tiny); + display: none; +} + +#toggle-theme { + border: none; + background: none; + cursor: pointer; + font-size: var(--font-size-large); + margin-right: var(--margin-medium); +} + +#toggle-theme:focus { + outline: none; +} + +#client-list { + position: absolute; + top: calc(0 + var(--nav-height)); + overflow-y: auto; + overflow: hidden; + transition: opacity 0.3s ease-out, visibility 0.3s ease-out; + border: 1px solid var(--table-border-color); + background-color: var(--nav-bg-color); + z-index: 1; + opacity: 0; + visibility: hidden; + width: auto; +} + +#client-list.show { + opacity: 1; + visibility: visible; +} + +#connected-list-div { + display: inline-block; +} + +.client { + padding: var(--margin-small); + border-bottom: 1px solid var(--table-border-color); + cursor: pointer; +} + +.client-details { + max-height: 0; + overflow: hidden; + padding-left: var(--padding-small); + transition: max-height 0.2s ease-out, padding 0.2s ease-out, opacity 0.1s ease-out; + background-color: var(--nav-bg-color); + margin-top: var(--margin-tiny); + opacity: 0; +} + +.client-details.show { + max-height: none; + opacity: 1; +} + +.client-detail { + border-bottom: 1px solid var(--table-border-color); + padding: var(--padding-small); +} + +#show-connected-button { + width: auto; + background-color: var(--bg-color); + border: none; + font-size: var(--base-font-size); +} + +#show-connected-button:hover, +.scroll-button:hover { + cursor: pointer; +} + +.scroll-button { + font-size: var(--base-font-size); + margin-left: var(--margin-tiny); + margin-top: var(--margin-small); +} + + +.left { + flex: 1; + background-color: var(--bg-color); + display: flex; + flex-direction: column; + padding: 20px; +} + +.right { + flex: 4; + background-color: var(--bg-color); + border: 1px solid var(--border-color); +} + +#svg-container { + height: 100%; +} + +.panel { + background-color: var(--nav-bg-color); + border: 1px solid var(--border-color); + padding: 10px; + flex-grow: 1; + display: flex; + flex-direction: column; +} + +.card-header, +.card-body { + background-color: var(--bg-color); + border: 1px solid var(--border-color); + overflow: auto; +} + +.card { + background-color: var(--nav-bg-color); + overflow: auto; +} + +li.svg-name { + list-style-type: none; +} + +#dropdown-menu:focus { + outline: none; +} + +/* remove bootstrap css confilcts */ +*, +::after, +::before { + box-sizing: unset; +} + +.btn, +.btn:hover { + color: var(--nav-link-hover-color); +} \ No newline at end of file diff --git a/src/blenderbim/blenderbim/bim/data/webui/static/css/gantt.css b/src/blenderbim/blenderbim/bim/data/webui/static/css/gantt.css index 1256b09080..f19ab94c28 100644 --- a/src/blenderbim/blenderbim/bim/data/webui/static/css/gantt.css +++ b/src/blenderbim/blenderbim/bim/data/webui/static/css/gantt.css @@ -1,13 +1,17 @@ :root { --font-family: Arial, sans-serif; + --base-font-size: 16px; + --margin-tiny: 0.125rem; --margin-small: 0.625rem; --margin-medium: 1.25rem; --margin-large: 2.5rem; - --padding-small: 0.125rem; + --padding-tiny: 0.125rem; + --padding-small: 0.625rem; --padding-medium: 1rem; --font-size-small: 1rem; --font-size-large: 1.2rem; --logo-height: 2.5rem; + --nav-height: 2.5rem; --folder-collapse-font-size: 0.75rem; --folder-collapse-font-family: Courier, "Courier New", monospace; --box-shadow: 0 0 0.7rem #5f5f5f66; @@ -31,6 +35,7 @@ --group-item-bg-color: #4b4b4b; --input-bg-color: #3b3b3b; --input-border-color: #000; + --details-border-color: #464444; } :root.light { @@ -42,6 +47,7 @@ --nav-link-color: #000000; --nav-link-hover-color: #38a63d; --warning-color: #FF4500; + --details-border-color: #222; } html { @@ -53,9 +59,13 @@ body { color: var(--primary-text-color); margin: 0; font-family: var(--font-family); + display: flex; + flex-direction: column; + min-height: 100vh; } #container { + flex: 1; margin-top: var(--margin-medium); margin-left: var(--margin-small); margin-right: var(--margin-small); @@ -107,7 +117,7 @@ nav ul li a.active { .warning { color: var(--warning-color); margin-bottom: var(--margin-small); - padding: var(--padding-small); + padding: var(--padding-tiny); display: none; } @@ -141,6 +151,87 @@ nav ul li a.active { outline: none; } +#client-list { + position: absolute; + top: calc(0 + var(--nav-height)); + overflow-y: auto; + overflow: hidden; + transition: opacity 0.3s ease-out, visibility 0.3s ease-out; + border: 1px solid var(--table-border-color); + background-color: var(--nav-bg-color); + z-index: 1; + opacity: 0; + visibility: hidden; + width: auto; +} + +#client-list.show { + opacity: 1; + visibility: visible; +} + +#connected-list-div { + display: inline-block; +} + +.client { + padding: var(--margin-small); + border-bottom: 1px solid var(--table-border-color); + cursor: pointer; +} + +.client-details { + max-height: 0; + overflow: hidden; + padding-left: var(--padding-small); + transition: max-height 0.2s ease-out, padding 0.2s ease-out, opacity 0.1s ease-out; + background-color: var(--nav-bg-color); + margin-top: var(--margin-tiny); + opacity: 0; +} + +.client-details.show { + max-height: none; + opacity: 1; +} + +.client-detail { + border-bottom: 1px solid var(--table-border-color); + padding: var(--padding-small); +} + +#show-connected-button { + width: auto; + background-color: var(--bg-color); + border: none; + font-size: var(--base-font-size); +} + +#show-connected-button:hover, +.scroll-button:hover { + cursor: pointer; +} + +.scroll-button { + font-size: var(--base-font-size); + margin-left: var(--margin-tiny); + margin-top: var(--margin-small); +} + +footer { + background-color: var(--nav-bg-color); + text-align: right; + padding: var(--padding-tiny); + border-top: 1px solid var(--nav-border-color); +} + +footer p { + margin: 0; + color: var(--text-color); + margin-right: var(--margin-small); + font-size: 0.8rem; +} + .gantt-info { margin: 0.5rem; font-size: var(--font-size-small); diff --git a/src/blenderbim/blenderbim/bim/data/webui/static/css/index.css b/src/blenderbim/blenderbim/bim/data/webui/static/css/index.css index 7a480b42c8..37386ebea9 100644 --- a/src/blenderbim/blenderbim/bim/data/webui/static/css/index.css +++ b/src/blenderbim/blenderbim/bim/data/webui/static/css/index.css @@ -1,12 +1,16 @@ :root { --font-family: Arial, sans-serif; + --base-font-size: 16px; + --margin-tiny: 0.125rem; --margin-small: 0.625rem; --margin-medium: 1.25rem; --margin-large: 2.5rem; - --padding-small: 0.125rem; + --padding-tiny: 0.125rem; + --padding-small: 0.625rem; --padding-medium: 1rem; --font-size-large: 1.2rem; --logo-height: 2.5rem; + --nav-height: 2.5rem; } :root.dark { @@ -18,6 +22,7 @@ --nav-link-color: #fff; --nav-link-hover-color: #3fb449; --warning-color: #FFDB8F; + --table-border-color: #464444; } :root.light { @@ -29,6 +34,7 @@ --nav-link-color: #000000; --nav-link-hover-color: #38a63d; --warning-color: #FF4500; + --table-border-color: #222; } html { @@ -40,29 +46,26 @@ body { color: var(--text-color); margin: 0; font-family: var(--font-family); + display: flex; + flex-direction: column; + min-height: 100vh; } #container { + flex: 1; margin-top: var(--margin-medium); margin-left: var(--margin-small); margin-right: var(--margin-small); margin-bottom: var(--margin-medium); } -.table-container { - margin-bottom: var(--margin-large); -} - -.csv-table { - margin-top: var(--margin-small); -} - h3 { margin-top: 0; } nav { background-color: var(--nav-bg-color); + height: var(--nav-height); padding: var(--padding-medium) 0; display: flex; align-items: center; @@ -102,7 +105,7 @@ nav ul li a.active { .warning { color: var(--warning-color); margin-bottom: var(--margin-small); - padding: var(--padding-small); + padding: var(--padding-tiny); display: none; } @@ -118,6 +121,95 @@ nav ul li a.active { outline: none; } +#client-list { + position: absolute; + top: calc(0 + var(--nav-height)); + overflow-y: auto; + overflow: hidden; + transition: opacity 0.3s ease-out, visibility 0.3s ease-out; + border: 1px solid var(--table-border-color); + background-color: var(--nav-bg-color); + z-index: 1; + opacity: 0; + visibility: hidden; + width: auto; +} + +#client-list.show { + opacity: 1; + visibility: visible; +} + +#connected-list-div { + display: inline-block; +} + +.client { + padding: var(--margin-small); + border-bottom: 1px solid var(--table-border-color); + cursor: pointer; +} + +.client-details { + max-height: 0; + overflow: hidden; + padding-left: var(--padding-small); + transition: max-height 0.2s ease-out, padding 0.2s ease-out, opacity 0.1s ease-out; + background-color: var(--nav-bg-color); + margin-top: var(--margin-tiny); + opacity: 0; +} + +.client-details.show { + max-height: none; + opacity: 1; +} + +.client-detail { + border-bottom: 1px solid var(--table-border-color); + padding: var(--padding-small); +} + +#show-connected-button { + width: auto; + background-color: var(--bg-color); + border: none; + font-size: var(--base-font-size); +} + +#show-connected-button:hover, +.scroll-button:hover { + cursor: pointer; +} + +.scroll-button { + font-size: var(--base-font-size); + margin-left: var(--margin-tiny); + margin-top: var(--margin-small); +} + +footer { + background-color: var(--nav-bg-color); + text-align: right; + padding: var(--padding-tiny); + border-top: 1px solid var(--nav-border-color); +} + +footer p { + margin: 0; + color: var(--text-color); + margin-right: var(--margin-small); + font-size: 0.8rem; +} + +.table-container { + margin-bottom: var(--margin-large); +} + +.csv-table { + margin-top: var(--margin-small); +} + /* ------------ Overwriting Tabulator CSS rules ------------ */ :root.light .tabulator-header, @@ -127,6 +219,6 @@ nav ul li a.active { } :root.light .tabulator { - border-top: 1px solid #222; - border-bottom: 2px solid #222; + border-top: 1px solid var(--table-border-color); + border-bottom: 2px solid var(--table-border-color); } \ No newline at end of file diff --git a/src/blenderbim/blenderbim/bim/data/webui/static/js/drawings.js b/src/blenderbim/blenderbim/bim/data/webui/static/js/drawings.js new file mode 100644 index 0000000000..8a865dcab1 --- /dev/null +++ b/src/blenderbim/blenderbim/bim/data/webui/static/js/drawings.js @@ -0,0 +1,263 @@ +// keeps track of blenders connected +const connectedClients = {}; +const allDrawings = {}; +let socket; + +// Document ready function +$(document).ready(function () { + var systemTheme = window.matchMedia("(prefers-color-scheme: light)").matches + ? "light" + : "dark"; + var theme = localStorage.getItem("theme") || systemTheme; + setTheme(theme); + + $("#dropdown-menu").change(function () { + const blenderId = $(this).attr("id"); + const ifcFile = $(this).val(); + displayDrawingsNames(blenderId, ifcFile); + }); + + connectSocket(); +}); + +// Function to connect to Socket.IO server +function connectSocket() { + const url = "ws://localhost:" + SOCKET_PORT + "/web"; + socket = io(url); + console.log("socket: ", socket); + + // Register socket event handlers + socket.on("blender_connect", handleBlenderConnect); + socket.on("blender_disconnect", handleBlenderDisconnect); + socket.on("connect", handleWebConnect); + socket.on("drawings_data", handleDrawingsData); + socket.on("svg_data", handleSvgData); + // socket.on("default_data", handleDefaultData); +} + +// function used to get drawings data from blenderbim +function handleWebConnect() { + const msg = { + sourcePage: "drawings", + operator: { + type: "getDrawings", + }, + }; + socket.emit("web_operator", msg); +} + +// Function to handle 'blender_connect' event +function handleBlenderConnect(blenderId) { + console.log("blender_connect: ", blenderId); + if (!connectedClients.hasOwnProperty(blenderId)) { + connectedClients[blenderId] = { + shown: false, + ifc_file: "", + }; + } +} + +// Function to handle 'blender_disconnect' event +function handleBlenderDisconnect(blenderId) { + console.log("blender_disconnect: ", blenderId); + if (connectedClients.hasOwnProperty(blenderId)) { + delete connectedClients[blenderId]; + // remove(blenderId); + } + + $("#blender-count").text(function (i, text) { + return parseInt(text, 10) - 1; + }); +} + +function handleDrawingsData(data) { + const blenderId = data["blenderId"]; + + console.log(data); + + const filename = data["data"]["ifc_file"]; + const drawings = data["data"]["drawings_data"]["drawings"]; + const sheets = data["data"]["drawings_data"]["sheets"]; + + allDrawings[filename] = { drawings: drawings, sheets: sheets }; + + console.log(connectedClients); + + if (connectedClients.hasOwnProperty(blenderId)) { + if (!connectedClients[blenderId].shown) { + connectedClients[blenderId] = { + shown: true, + ifc_file: filename, + }; + addSelectOption(blenderId, filename); + } else { + // update(blenderId, data, filename); + } + } else { + connectedClients[blenderId] = { + shown: true, + ifc_file: filename, + }; + addSelectOption(blenderId, filename); + } +} + +function handleSvgData(data) { + const svgContainer = document.getElementById("svg-container"); + svgContainer.innerHTML = ""; + svgContainer.style.backgroundColor = "white"; + + const dom = SVG(svgContainer).svg(data); + const svgElement = dom.node.children[0]; + + // to make the svg not grow outside the svg container + svgElement.setAttribute("width", "100%"); + svgElement.setAttribute("height", "100%"); + svgElement.style.maxWidth = "100%"; + svgElement.style.maxHeight = "100%"; + svgElement.style.width = "100%"; + svgElement.style.height = "100%"; + svgElement.style.boxSizing = "border-box"; // Ensure padding and borders are included in the element's total width and height + + const panZoomControls = svgPanZoom(svgElement, { + zoomEnabled: true, + controlIconsEnabled: true, + fit: true, + center: true, + }); +} + +function addSelectOption(blenderId, filename) { + const filenameOption = $("") + .attr("id", "blender-" + blenderId) + .val(filename) + .text(filename); + $("#dropdown-menu").append(filenameOption); +} + +function displayDrawingsNames(blenderId, ifcFile) { + drawings = allDrawings[ifcFile].drawings; + sheets = allDrawings[ifcFile].sheets; + + function createSvgNames(text, index, type) { + var label = $("
  • ") + .text(text) + .attr("id", type + "-" + index) + .addClass("svg-name") + .click(function () { + const id = $(this).attr("id").split("-"); + const index = parseInt(id[1]); + const type = id[0]; + const ifcFile = $("#dropdown-menu").val(); + + var path = ""; + + if (type === "drawing") { + path = allDrawings[ifcFile].drawings[index].path; + } else if (type === "sheet") { + path = allDrawings[ifcFile].sheets[index].path; + } + + const msg = { + path: path, + }; + console.log(msg); + socket.emit("get_svg", msg); + }); + + if (type === "drawing") $("#drawings-sub-panel").append(label); + else if (type === "sheet") $("#sheets-sub-panel").append(label); + } + + $("#drawings-sub-panel").empty(); + drawings.forEach(function (drawing, index) { + createSvgNames(drawing.name, index, "drawing"); + }); + + $("#sheets-sub-panel").empty(); + sheets.forEach(function (sheet, index) { + createSvgNames(sheet.name, index, "sheet"); + }); +} + +function setTheme(theme) { + if (theme === "light") { + $("html").removeClass("dark").addClass("light"); + $("#toggle-theme").html(''); + } else { + $("html").removeClass("light").addClass("dark"); + $("#toggle-theme").html(''); + } + localStorage.setItem("theme", theme); +} + +function toggleTheme() { + if ($("html").hasClass("dark")) { + setTheme("light"); + } else { + setTheme("dark"); + } +} + +function toggleClientList() { + var clientList = $("#client-list"); + + if (clientList.hasClass("show")) { + clientList.removeClass("show"); + return; + } + + clientList.empty(); + + $.each(connectedClients, function (id, client) { + if (!client.shown) return; + + const dropdownIcon = $("") + .addClass("fas fa-chevron-down") + .css("margin-left", "0.5rem"); + + const clientDiv = $("
    ").addClass("client").text(client.ifc_file); + + clientDiv.append(dropdownIcon); + + const clientDetailsDiv = $("
    ").addClass("client-details"); + + if (id) { + const clientId = $("
    ") + .addClass("client-detail") + .text(`Blender ID: ${id}`); + clientDetailsDiv.append(clientId); + } + + if (client.headers && client.headers.length) { + const clientHeaders = $("
    ") + .addClass("client-detail") + .text(`Table Headers: ${client.headers.join(", ")}`); + + const scrollButton = $(" + +
    + +
    +
    +
    +
    + + + +
    +
    +
    +
    + +
    + +
    +
    +
      + +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
      + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + diff --git a/src/blenderbim/blenderbim/bim/data/webui/templates/gantt.html b/src/blenderbim/blenderbim/bim/data/webui/templates/gantt.html index 78044d45a3..280c116dbb 100644 --- a/src/blenderbim/blenderbim/bim/data/webui/templates/gantt.html +++ b/src/blenderbim/blenderbim/bim/data/webui/templates/gantt.html @@ -34,11 +34,23 @@ +
    + +
    +
    +
    +

    BlenderBIM Version: {{version}}

    +
    diff --git a/src/blenderbim/blenderbim/bim/data/webui/templates/index.html b/src/blenderbim/blenderbim/bim/data/webui/templates/index.html index e948b4c4be..e31204d197 100644 --- a/src/blenderbim/blenderbim/bim/data/webui/templates/index.html +++ b/src/blenderbim/blenderbim/bim/data/webui/templates/index.html @@ -41,11 +41,23 @@ +
    + +
    +
    + diff --git a/src/blenderbim/blenderbim/tool/web.py b/src/blenderbim/blenderbim/tool/web.py index 326547eac0..b5161e2d68 100644 --- a/src/blenderbim/blenderbim/tool/web.py +++ b/src/blenderbim/blenderbim/tool/web.py @@ -123,7 +123,8 @@ class Web(blenderbim.core.tool.Web): blenderbim_lib_path = os.path.join(blenderbim_path, "libs", "site", "packages") env = os.environ.copy() - env["blenderbim_lib_path"] = str(blenderbim_lib_path) + env["BLENDERBIM_LIB_PATH"] = str(blenderbim_lib_path) + env["BLENDERBIM_VERSION"] = tool.Blender.get_blenderbim_version() ws_process = subprocess.Popen( [sys.executable, ws_path, "--p", str(port), "--host", "127.0.0.1"], @@ -284,6 +285,8 @@ class Web(blenderbim.core.tool.Web): cls.handle_csv_operator(operator["operator"]) elif operator["sourcePage"] == "gantt": cls.handle_gantt_operator(operator["operator"]) + elif operator["sourcePage"] == "drawings": + cls.handle_drawings_operator(operator["operator"]) return 1.0 @classmethod @@ -328,6 +331,29 @@ class Web(blenderbim.core.tool.Web): gantt_data = {"tasks": task_json, "work_schedule": work_schedule.get_info(recursive=True)} cls.send_webui_data(data=gantt_data, data_key="gantt_data", event="gantt_data") + @classmethod + def handle_drawings_operator(cls, operator_data: dict) -> None: + if operator_data["type"] == "getDrawings": + drawings_data = [] + sheets_data = [] + ifc_file_dir = os.path.dirname(bpy.context.scene.BIMProperties.ifc_file) + + sheets = [d for d in tool.Ifc.get().by_type("IfcDocumentInformation") if d.Scope == "SHEET"] + for sheet in sorted(sheets, key=lambda s: getattr(s, "Identification", getattr(s, "DocumentId", None))): + for reference in tool.Drawing.get_document_references(sheet): + reference_description = tool.Drawing.get_reference_description(reference) + reference_location = tool.Drawing.get_reference_location(reference) + reference_name = os.path.basename(reference_location) + reference_path = os.path.join(ifc_file_dir, reference_location) + if reference_description == "SHEET": + sheets_data.append({"name": reference_name, "path": reference_path}) + if reference_description == "DRAWING": + drawings_data.append({"name": reference_name, "path": reference_path}) + + cls.send_webui_data( + data={"drawings": drawings_data, "sheets": sheets_data}, data_key="drawings_data", event="drawings_data" + ) + @classmethod def open_web_browser(cls, port: int) -> None: webbrowser.open(f"http://127.0.0.1:{port}/")