From 0e1e13e5241a1e762893ca600aacb20ce525fe13 Mon Sep 17 00:00:00 2001 From: ramox81 <184937705+ramox81@users.noreply.github.com> Date: Mon, 5 Oct 2026 09:10:17 +0300 Subject: [PATCH] WIP: Sheet Set Manager palette, wizard, properties and sheet set fields Co-Authored-By: Claude Opus 5.5 --- Cargo.lock | 1 - Cargo.toml | 3 + locales/ar-SA/opencadstudio.ftl | 96 +++ locales/bg-BG/opencadstudio.ftl | 96 +++ locales/cs-CZ/opencadstudio.ftl | 96 +++ locales/de-DE/opencadstudio.ftl | 96 +++ locales/el-GR/opencadstudio.ftl | 96 +++ locales/en-US/opencadstudio.ftl | 96 +++ locales/es-ES/opencadstudio.ftl | 96 +++ locales/fi-FI/opencadstudio.ftl | 96 +++ locales/fr-FR/opencadstudio.ftl | 96 +++ locales/hi-IN/opencadstudio.ftl | 96 +++ locales/hu-HU/opencadstudio.ftl | 96 +++ locales/it-IT/opencadstudio.ftl | 96 +++ locales/ja-JP/opencadstudio.ftl | 96 +++ locales/ko-KR/opencadstudio.ftl | 96 +++ locales/nl-NL/opencadstudio.ftl | 96 +++ locales/pl-PL/opencadstudio.ftl | 96 +++ locales/pt-BR/opencadstudio.ftl | 96 +++ locales/ru-RU/opencadstudio.ftl | 96 +++ locales/tr-TR/opencadstudio.ftl | 96 +++ locales/zh-CN/opencadstudio.ftl | 96 +++ locales/zh-TW/opencadstudio.ftl | 96 +++ src/app/commands/display.rs | 6 - src/app/commands/field.rs | 17 +- src/app/commands/mod.rs | 13 + src/app/commands/sheet_set.rs | 1277 +++++++++++++++++++++++++++++++ src/app/control/actions.rs | 98 +++ src/app/mod.rs | 13 + src/app/settings.rs | 4 + src/app/update/dialog.rs | 5 + src/app/update/file.rs | 6 +- src/app/update/mod.rs | 5 + src/app/view/mod.rs | 4 + src/app/view/modal.rs | 9 + src/entities/field.rs | 18 + src/locale_catalog.rs | 96 +++ src/modules/view/sheetset.rs | 2 +- src/ui/dock.rs | 5 + src/ui/ribbon/mod.rs | 7 + src/ui/ribbon/widgets.rs | 2 + src/ui/window/field_dialog.rs | 186 +++++ src/ui/window/mod.rs | 1 + src/ui/window/sheet_set.rs | 968 +++++++++++++++++++++++ 44 files changed, 4752 insertions(+), 10 deletions(-) create mode 100644 src/app/commands/sheet_set.rs create mode 100644 src/ui/window/sheet_set.rs diff --git a/Cargo.lock b/Cargo.lock index 51294fb85..a42335e89 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4206,7 +4206,6 @@ dependencies = [ [[package]] name = "opencadcodec" version = "0.5.5" -source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=d96e3fa#d96e3fa2fe5acbeac966f1db4c01142618bf9c79" dependencies = [ "ahash 0.8.12", "anyhow", diff --git a/Cargo.toml b/Cargo.toml index 85cc56ce7..514f98106 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -90,6 +90,9 @@ objc2-app-kit = { version = "0.2", features = ["NSApplication", "NSResponder", " block2 = "0.5" objc2-foundation = { version = "0.2", features = ["NSArray", "NSURL", "NSString", "NSObject", "NSNotification", "NSThread", "NSEnumerator"] } +[patch."https://github.com/HakanSeven12/opencadcodec.git"] +opencadcodec = { path = "../cadcodec-sheetset" } + [patch.crates-io] iced_core = { git = "https://github.com/iced-rs/iced.git", rev = "23604ff22ab0aad9e00b9327cb7b8546ed84db39" } iced_widget = { git = "https://github.com/iced-rs/iced.git", rev = "23604ff22ab0aad9e00b9327cb7b8546ed84db39" } diff --git a/locales/ar-SA/opencadstudio.ftl b/locales/ar-SA/opencadstudio.ftl index 97fec3890..b1790f958 100644 --- a/locales/ar-SA/opencadstudio.ftl +++ b/locales/ar-SA/opencadstudio.ftl @@ -4352,6 +4352,102 @@ layout = .vplayer-f-layer-freeze-t-layer-thaw-enter-exit = VPLAYER F = تجميد | T = إلغاء التجميد | Enter = خروج view = + .ss-create-sheet-set = Create Sheet Set + .ss-new-sheet = New Sheet + .ss-subset-properties = Subset Properties + .ss-rename-renumber-sheet = Rename & Renumber Sheet + .ss-import-layout-as-sheet = Import Layout as Sheet + .ss-sheet-set-manager = Sheet Set Manager + .ss-open = Open... + .ss-open-a-sheet-set-or-create-one-with-newsheetset = Open a sheet set or create one with NEWSHEETSET. + .ss-no-sheet-views = No sheet views. + .ss-no-locations = No locations. + .ss-double-click-opens-a-sheet-right-click-for-more-commands = Double-click opens a sheet. Right-click for more commands. + .ss-an-empty-sheet-set = An empty sheet set + .ss-existing-drawings = Existing drawings + .ss-create-a-folder-hierarchy-based-on-subsets = Create a folder hierarchy based on subsets + .ss-sheet-set-properties = Sheet Set Properties... + .ss-select-folders-containing-drawings-layouts-in-the-drawings-c = Select folders containing drawings. Layouts in the drawings can be added to the sheet set. + .ss-sheet-set = Sheet Set + .ss-sheet-set-data-file = Sheet set data file + .ss-sheets-to-import = Sheets to import + .ss-add-custom-property = Add Custom Property... + .ss-new-sheet-x = New Sheet... + .ss-new-subset = New Subset... + .ss-import-layout-as-sheet-x = Import Layout as Sheet... + .ss-rename-renumber = Rename & Renumber... + .ss-close-sheet-set = Close Sheet Set + .ss-properties = Properties... + .ss-sheet-list = Sheet List + .ss-sheet-views = Sheet Views + .ss-model-views = Model Views + .ss-views-by-sheet = Views by sheet + .ss-locations = Locations + .ss-create-a-sheet-set-using = Create a sheet set using + .ss-name-of-new-sheet-set = Name of new sheet set: + .ss-description-optional = Description (optional): + .ss-store-sheet-set-data-file-dst-here = Store sheet set data file (.dst) here: + .ss-choose-layouts = Choose Layouts + .ss-confirm = Confirm + .ss-default-value = Default value: + .ss-owner = Owner + .ss-custom-properties = Custom Properties + .ss-sheet-title = Sheet title + .ss-folder-path = Folder path + .ss-sheet-template = Sheet template + .ss-subset-name = Subset name + .ss-new-sheet-location = New sheet location + .ss-remove-subset = Remove Subset + .ss-remove-sheet = Remove Sheet + .ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set. + .ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets. + .ss-open-sheet-set = Open Sheet Set + .ss-sheet-set-dst = Sheet Set (*.dst) + .ss-browse-for-folder = Browse for Folder + .ss-select-layout-as-sheet-template = Select Layout as Sheet Template + .ss-drawing-template-dwt = Drawing Template (*.dwt) + .ss-drawing-dwg = Drawing (*.dwg) + .ss-the-name-cannot-be-empty = The name cannot be empty. + .ss-a-custom-property-with-this-name-already-exists = A custom property with this name already exists. + .ss-sheet-sets-organize-layouts-from-several-drawings-into-one-n = Sheet sets organize layouts from several drawings into one named set of sheets. + .ss-default-new-drawing = (default new drawing) + .ss-select-drawing = Select Drawing + .ss-the-sheet-set-name-cannot-be-empty = The sheet set name cannot be empty. + .ss-the-folder-for-the-sheet-set-data-file-does-not-exist = The folder for the sheet set data file does not exist. + .ss-the-drawing-has-no-layout-to-use-as-a-sheet-template = The drawing has no layout to use as a sheet template. + .ss-the-subset-name-cannot-be-empty = The subset name cannot be empty. + .ss-the-drawing-has-no-layout-to-import = The drawing has no layout to import. + .ss-the-layout-is-already-a-sheet-of-this-sheet-set = The layout is already a sheet of this sheet set. + .ss-the-sheet-title-cannot-be-empty = The sheet title cannot be empty. + .ss-the-sheet-folder-cannot-be-created = The sheet folder cannot be created. + .ss-sheet-set-properties-x = Sheet Set Properties + .ss-sheet-properties = Sheet Properties + .ss-sheet-drawing-not-found = Sheet drawing not found: __ocs_fmt_0__ + .ss-already-exists = __ocs_fmt_0__ already exists. + .ss-model-view = Model view + .ss-label-block-for-views = Label block for views + .ss-callout-blocks = Callout blocks + .ss-page-setup-overrides-file = Page setup overrides file + .ss-project-control = Project Control + .ss-sheet-creation = Sheet Creation + .ss-sheet-storage-location = Sheet storage location + .ss-sheet-creation-template = Sheet creation template + .ss-prompt-for-template = Prompt for template + .ss-subset = Subset + .ss-layout-name = Layout name + .ss-drawing-file = Drawing file + .ss-project-number = Project number + .ss-project-name = Project name + .ss-project-phase = Project phase + .ss-project-milestone = Project milestone + .ss-revision-number = Revision number + .ss-revision-date = Revision date + .ss-issue-purpose = Issue purpose + .ss-custom-property-name = Custom property name + .ss-placeholder-type = Placeholder type + .ss-sheet-set-x = Sheet set + .ss-sheet-navigation-tree = Sheet navigation tree + .ss-sheetset = SheetSet .datalink-specify-insertion-point = DATALINK حدد نقطة الإدراج: .table-block-definition-not-found = TABLE: لم يتم العثور على تعريف الكتلة. .table-edit-applied = TABLE: تم تطبيق التعديل. diff --git a/locales/bg-BG/opencadstudio.ftl b/locales/bg-BG/opencadstudio.ftl index 0fb1d43e9..306ace996 100644 --- a/locales/bg-BG/opencadstudio.ftl +++ b/locales/bg-BG/opencadstudio.ftl @@ -4339,6 +4339,102 @@ layout = .vplayer-f-layer-freeze-t-layer-thaw-enter-exit = VPLAYER F <слой> = Замрази | T <слой> = Размрази | Enter = Изход view = + .ss-create-sheet-set = Create Sheet Set + .ss-new-sheet = New Sheet + .ss-subset-properties = Subset Properties + .ss-rename-renumber-sheet = Rename & Renumber Sheet + .ss-import-layout-as-sheet = Import Layout as Sheet + .ss-sheet-set-manager = Sheet Set Manager + .ss-open = Open... + .ss-open-a-sheet-set-or-create-one-with-newsheetset = Open a sheet set or create one with NEWSHEETSET. + .ss-no-sheet-views = No sheet views. + .ss-no-locations = No locations. + .ss-double-click-opens-a-sheet-right-click-for-more-commands = Double-click opens a sheet. Right-click for more commands. + .ss-an-empty-sheet-set = An empty sheet set + .ss-existing-drawings = Existing drawings + .ss-create-a-folder-hierarchy-based-on-subsets = Create a folder hierarchy based on subsets + .ss-sheet-set-properties = Sheet Set Properties... + .ss-select-folders-containing-drawings-layouts-in-the-drawings-c = Select folders containing drawings. Layouts in the drawings can be added to the sheet set. + .ss-sheet-set = Sheet Set + .ss-sheet-set-data-file = Sheet set data file + .ss-sheets-to-import = Sheets to import + .ss-add-custom-property = Add Custom Property... + .ss-new-sheet-x = New Sheet... + .ss-new-subset = New Subset... + .ss-import-layout-as-sheet-x = Import Layout as Sheet... + .ss-rename-renumber = Rename & Renumber... + .ss-close-sheet-set = Close Sheet Set + .ss-properties = Properties... + .ss-sheet-list = Sheet List + .ss-sheet-views = Sheet Views + .ss-model-views = Model Views + .ss-views-by-sheet = Views by sheet + .ss-locations = Locations + .ss-create-a-sheet-set-using = Create a sheet set using + .ss-name-of-new-sheet-set = Name of new sheet set: + .ss-description-optional = Description (optional): + .ss-store-sheet-set-data-file-dst-here = Store sheet set data file (.dst) here: + .ss-choose-layouts = Choose Layouts + .ss-confirm = Confirm + .ss-default-value = Default value: + .ss-owner = Owner + .ss-custom-properties = Custom Properties + .ss-sheet-title = Sheet title + .ss-folder-path = Folder path + .ss-sheet-template = Sheet template + .ss-subset-name = Subset name + .ss-new-sheet-location = New sheet location + .ss-remove-subset = Remove Subset + .ss-remove-sheet = Remove Sheet + .ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set. + .ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets. + .ss-open-sheet-set = Open Sheet Set + .ss-sheet-set-dst = Sheet Set (*.dst) + .ss-browse-for-folder = Browse for Folder + .ss-select-layout-as-sheet-template = Select Layout as Sheet Template + .ss-drawing-template-dwt = Drawing Template (*.dwt) + .ss-drawing-dwg = Drawing (*.dwg) + .ss-the-name-cannot-be-empty = The name cannot be empty. + .ss-a-custom-property-with-this-name-already-exists = A custom property with this name already exists. + .ss-sheet-sets-organize-layouts-from-several-drawings-into-one-n = Sheet sets organize layouts from several drawings into one named set of sheets. + .ss-default-new-drawing = (default new drawing) + .ss-select-drawing = Select Drawing + .ss-the-sheet-set-name-cannot-be-empty = The sheet set name cannot be empty. + .ss-the-folder-for-the-sheet-set-data-file-does-not-exist = The folder for the sheet set data file does not exist. + .ss-the-drawing-has-no-layout-to-use-as-a-sheet-template = The drawing has no layout to use as a sheet template. + .ss-the-subset-name-cannot-be-empty = The subset name cannot be empty. + .ss-the-drawing-has-no-layout-to-import = The drawing has no layout to import. + .ss-the-layout-is-already-a-sheet-of-this-sheet-set = The layout is already a sheet of this sheet set. + .ss-the-sheet-title-cannot-be-empty = The sheet title cannot be empty. + .ss-the-sheet-folder-cannot-be-created = The sheet folder cannot be created. + .ss-sheet-set-properties-x = Sheet Set Properties + .ss-sheet-properties = Sheet Properties + .ss-sheet-drawing-not-found = Sheet drawing not found: __ocs_fmt_0__ + .ss-already-exists = __ocs_fmt_0__ already exists. + .ss-model-view = Model view + .ss-label-block-for-views = Label block for views + .ss-callout-blocks = Callout blocks + .ss-page-setup-overrides-file = Page setup overrides file + .ss-project-control = Project Control + .ss-sheet-creation = Sheet Creation + .ss-sheet-storage-location = Sheet storage location + .ss-sheet-creation-template = Sheet creation template + .ss-prompt-for-template = Prompt for template + .ss-subset = Subset + .ss-layout-name = Layout name + .ss-drawing-file = Drawing file + .ss-project-number = Project number + .ss-project-name = Project name + .ss-project-phase = Project phase + .ss-project-milestone = Project milestone + .ss-revision-number = Revision number + .ss-revision-date = Revision date + .ss-issue-purpose = Issue purpose + .ss-custom-property-name = Custom property name + .ss-placeholder-type = Placeholder type + .ss-sheet-set-x = Sheet set + .ss-sheet-navigation-tree = Sheet navigation tree + .ss-sheetset = SheetSet .datalink-specify-insertion-point = DATALINK Посочете точка на вмъкване: .table-block-definition-not-found = TABLE: дефиницията на блока не е намерена. .table-edit-applied = TABLE: редакцията е приложена. diff --git a/locales/cs-CZ/opencadstudio.ftl b/locales/cs-CZ/opencadstudio.ftl index d17ecfb1d..6e04fa9d0 100644 --- a/locales/cs-CZ/opencadstudio.ftl +++ b/locales/cs-CZ/opencadstudio.ftl @@ -4337,6 +4337,102 @@ layout = .vplayer-f-layer-freeze-t-layer-thaw-enter-exit = VPLAYER F = Zmrazit | T = Rozmrazit | Enter = Konec view = + .ss-create-sheet-set = Create Sheet Set + .ss-new-sheet = New Sheet + .ss-subset-properties = Subset Properties + .ss-rename-renumber-sheet = Rename & Renumber Sheet + .ss-import-layout-as-sheet = Import Layout as Sheet + .ss-sheet-set-manager = Sheet Set Manager + .ss-open = Open... + .ss-open-a-sheet-set-or-create-one-with-newsheetset = Open a sheet set or create one with NEWSHEETSET. + .ss-no-sheet-views = No sheet views. + .ss-no-locations = No locations. + .ss-double-click-opens-a-sheet-right-click-for-more-commands = Double-click opens a sheet. Right-click for more commands. + .ss-an-empty-sheet-set = An empty sheet set + .ss-existing-drawings = Existing drawings + .ss-create-a-folder-hierarchy-based-on-subsets = Create a folder hierarchy based on subsets + .ss-sheet-set-properties = Sheet Set Properties... + .ss-select-folders-containing-drawings-layouts-in-the-drawings-c = Select folders containing drawings. Layouts in the drawings can be added to the sheet set. + .ss-sheet-set = Sheet Set + .ss-sheet-set-data-file = Sheet set data file + .ss-sheets-to-import = Sheets to import + .ss-add-custom-property = Add Custom Property... + .ss-new-sheet-x = New Sheet... + .ss-new-subset = New Subset... + .ss-import-layout-as-sheet-x = Import Layout as Sheet... + .ss-rename-renumber = Rename & Renumber... + .ss-close-sheet-set = Close Sheet Set + .ss-properties = Properties... + .ss-sheet-list = Sheet List + .ss-sheet-views = Sheet Views + .ss-model-views = Model Views + .ss-views-by-sheet = Views by sheet + .ss-locations = Locations + .ss-create-a-sheet-set-using = Create a sheet set using + .ss-name-of-new-sheet-set = Name of new sheet set: + .ss-description-optional = Description (optional): + .ss-store-sheet-set-data-file-dst-here = Store sheet set data file (.dst) here: + .ss-choose-layouts = Choose Layouts + .ss-confirm = Confirm + .ss-default-value = Default value: + .ss-owner = Owner + .ss-custom-properties = Custom Properties + .ss-sheet-title = Sheet title + .ss-folder-path = Folder path + .ss-sheet-template = Sheet template + .ss-subset-name = Subset name + .ss-new-sheet-location = New sheet location + .ss-remove-subset = Remove Subset + .ss-remove-sheet = Remove Sheet + .ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set. + .ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets. + .ss-open-sheet-set = Open Sheet Set + .ss-sheet-set-dst = Sheet Set (*.dst) + .ss-browse-for-folder = Browse for Folder + .ss-select-layout-as-sheet-template = Select Layout as Sheet Template + .ss-drawing-template-dwt = Drawing Template (*.dwt) + .ss-drawing-dwg = Drawing (*.dwg) + .ss-the-name-cannot-be-empty = The name cannot be empty. + .ss-a-custom-property-with-this-name-already-exists = A custom property with this name already exists. + .ss-sheet-sets-organize-layouts-from-several-drawings-into-one-n = Sheet sets organize layouts from several drawings into one named set of sheets. + .ss-default-new-drawing = (default new drawing) + .ss-select-drawing = Select Drawing + .ss-the-sheet-set-name-cannot-be-empty = The sheet set name cannot be empty. + .ss-the-folder-for-the-sheet-set-data-file-does-not-exist = The folder for the sheet set data file does not exist. + .ss-the-drawing-has-no-layout-to-use-as-a-sheet-template = The drawing has no layout to use as a sheet template. + .ss-the-subset-name-cannot-be-empty = The subset name cannot be empty. + .ss-the-drawing-has-no-layout-to-import = The drawing has no layout to import. + .ss-the-layout-is-already-a-sheet-of-this-sheet-set = The layout is already a sheet of this sheet set. + .ss-the-sheet-title-cannot-be-empty = The sheet title cannot be empty. + .ss-the-sheet-folder-cannot-be-created = The sheet folder cannot be created. + .ss-sheet-set-properties-x = Sheet Set Properties + .ss-sheet-properties = Sheet Properties + .ss-sheet-drawing-not-found = Sheet drawing not found: __ocs_fmt_0__ + .ss-already-exists = __ocs_fmt_0__ already exists. + .ss-model-view = Model view + .ss-label-block-for-views = Label block for views + .ss-callout-blocks = Callout blocks + .ss-page-setup-overrides-file = Page setup overrides file + .ss-project-control = Project Control + .ss-sheet-creation = Sheet Creation + .ss-sheet-storage-location = Sheet storage location + .ss-sheet-creation-template = Sheet creation template + .ss-prompt-for-template = Prompt for template + .ss-subset = Subset + .ss-layout-name = Layout name + .ss-drawing-file = Drawing file + .ss-project-number = Project number + .ss-project-name = Project name + .ss-project-phase = Project phase + .ss-project-milestone = Project milestone + .ss-revision-number = Revision number + .ss-revision-date = Revision date + .ss-issue-purpose = Issue purpose + .ss-custom-property-name = Custom property name + .ss-placeholder-type = Placeholder type + .ss-sheet-set-x = Sheet set + .ss-sheet-navigation-tree = Sheet navigation tree + .ss-sheetset = SheetSet .datalink-specify-insertion-point = DATALINK Určete bod vložení: .table-block-definition-not-found = TABLE: definice bloku nebyla nalezena. .table-edit-applied = TABLE: úprava byla použita. diff --git a/locales/de-DE/opencadstudio.ftl b/locales/de-DE/opencadstudio.ftl index 7fd9f0bd4..b16b87501 100644 --- a/locales/de-DE/opencadstudio.ftl +++ b/locales/de-DE/opencadstudio.ftl @@ -4338,6 +4338,102 @@ layout = .vplayer-f-layer-freeze-t-layer-thaw-enter-exit = VPLAYER F = Einfrieren | T = Auftauen | Eingabe = Beenden view = + .ss-create-sheet-set = Create Sheet Set + .ss-new-sheet = New Sheet + .ss-subset-properties = Subset Properties + .ss-rename-renumber-sheet = Rename & Renumber Sheet + .ss-import-layout-as-sheet = Import Layout as Sheet + .ss-sheet-set-manager = Sheet Set Manager + .ss-open = Open... + .ss-open-a-sheet-set-or-create-one-with-newsheetset = Open a sheet set or create one with NEWSHEETSET. + .ss-no-sheet-views = No sheet views. + .ss-no-locations = No locations. + .ss-double-click-opens-a-sheet-right-click-for-more-commands = Double-click opens a sheet. Right-click for more commands. + .ss-an-empty-sheet-set = An empty sheet set + .ss-existing-drawings = Existing drawings + .ss-create-a-folder-hierarchy-based-on-subsets = Create a folder hierarchy based on subsets + .ss-sheet-set-properties = Sheet Set Properties... + .ss-select-folders-containing-drawings-layouts-in-the-drawings-c = Select folders containing drawings. Layouts in the drawings can be added to the sheet set. + .ss-sheet-set = Sheet Set + .ss-sheet-set-data-file = Sheet set data file + .ss-sheets-to-import = Sheets to import + .ss-add-custom-property = Add Custom Property... + .ss-new-sheet-x = New Sheet... + .ss-new-subset = New Subset... + .ss-import-layout-as-sheet-x = Import Layout as Sheet... + .ss-rename-renumber = Rename & Renumber... + .ss-close-sheet-set = Close Sheet Set + .ss-properties = Properties... + .ss-sheet-list = Sheet List + .ss-sheet-views = Sheet Views + .ss-model-views = Model Views + .ss-views-by-sheet = Views by sheet + .ss-locations = Locations + .ss-create-a-sheet-set-using = Create a sheet set using + .ss-name-of-new-sheet-set = Name of new sheet set: + .ss-description-optional = Description (optional): + .ss-store-sheet-set-data-file-dst-here = Store sheet set data file (.dst) here: + .ss-choose-layouts = Choose Layouts + .ss-confirm = Confirm + .ss-default-value = Default value: + .ss-owner = Owner + .ss-custom-properties = Custom Properties + .ss-sheet-title = Sheet title + .ss-folder-path = Folder path + .ss-sheet-template = Sheet template + .ss-subset-name = Subset name + .ss-new-sheet-location = New sheet location + .ss-remove-subset = Remove Subset + .ss-remove-sheet = Remove Sheet + .ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set. + .ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets. + .ss-open-sheet-set = Open Sheet Set + .ss-sheet-set-dst = Sheet Set (*.dst) + .ss-browse-for-folder = Browse for Folder + .ss-select-layout-as-sheet-template = Select Layout as Sheet Template + .ss-drawing-template-dwt = Drawing Template (*.dwt) + .ss-drawing-dwg = Drawing (*.dwg) + .ss-the-name-cannot-be-empty = The name cannot be empty. + .ss-a-custom-property-with-this-name-already-exists = A custom property with this name already exists. + .ss-sheet-sets-organize-layouts-from-several-drawings-into-one-n = Sheet sets organize layouts from several drawings into one named set of sheets. + .ss-default-new-drawing = (default new drawing) + .ss-select-drawing = Select Drawing + .ss-the-sheet-set-name-cannot-be-empty = The sheet set name cannot be empty. + .ss-the-folder-for-the-sheet-set-data-file-does-not-exist = The folder for the sheet set data file does not exist. + .ss-the-drawing-has-no-layout-to-use-as-a-sheet-template = The drawing has no layout to use as a sheet template. + .ss-the-subset-name-cannot-be-empty = The subset name cannot be empty. + .ss-the-drawing-has-no-layout-to-import = The drawing has no layout to import. + .ss-the-layout-is-already-a-sheet-of-this-sheet-set = The layout is already a sheet of this sheet set. + .ss-the-sheet-title-cannot-be-empty = The sheet title cannot be empty. + .ss-the-sheet-folder-cannot-be-created = The sheet folder cannot be created. + .ss-sheet-set-properties-x = Sheet Set Properties + .ss-sheet-properties = Sheet Properties + .ss-sheet-drawing-not-found = Sheet drawing not found: __ocs_fmt_0__ + .ss-already-exists = __ocs_fmt_0__ already exists. + .ss-model-view = Model view + .ss-label-block-for-views = Label block for views + .ss-callout-blocks = Callout blocks + .ss-page-setup-overrides-file = Page setup overrides file + .ss-project-control = Project Control + .ss-sheet-creation = Sheet Creation + .ss-sheet-storage-location = Sheet storage location + .ss-sheet-creation-template = Sheet creation template + .ss-prompt-for-template = Prompt for template + .ss-subset = Subset + .ss-layout-name = Layout name + .ss-drawing-file = Drawing file + .ss-project-number = Project number + .ss-project-name = Project name + .ss-project-phase = Project phase + .ss-project-milestone = Project milestone + .ss-revision-number = Revision number + .ss-revision-date = Revision date + .ss-issue-purpose = Issue purpose + .ss-custom-property-name = Custom property name + .ss-placeholder-type = Placeholder type + .ss-sheet-set-x = Sheet set + .ss-sheet-navigation-tree = Sheet navigation tree + .ss-sheetset = SheetSet .datalink-specify-insertion-point = DATALINK Einfügepunkt angeben: .table-block-definition-not-found = TABLE: Blockdefinition nicht gefunden. .table-edit-applied = TABLE: Bearbeitung angewendet. diff --git a/locales/el-GR/opencadstudio.ftl b/locales/el-GR/opencadstudio.ftl index 53601f4be..571dea0e2 100644 --- a/locales/el-GR/opencadstudio.ftl +++ b/locales/el-GR/opencadstudio.ftl @@ -4340,6 +4340,102 @@ layout = .vplayer-f-layer-freeze-t-layer-thaw-enter-exit = VPLAYER F <επίπεδο> = Πάγωμα | T <επίπεδο> = Ξεπάγωμα | Enter = Έξοδος view = + .ss-create-sheet-set = Create Sheet Set + .ss-new-sheet = New Sheet + .ss-subset-properties = Subset Properties + .ss-rename-renumber-sheet = Rename & Renumber Sheet + .ss-import-layout-as-sheet = Import Layout as Sheet + .ss-sheet-set-manager = Sheet Set Manager + .ss-open = Open... + .ss-open-a-sheet-set-or-create-one-with-newsheetset = Open a sheet set or create one with NEWSHEETSET. + .ss-no-sheet-views = No sheet views. + .ss-no-locations = No locations. + .ss-double-click-opens-a-sheet-right-click-for-more-commands = Double-click opens a sheet. Right-click for more commands. + .ss-an-empty-sheet-set = An empty sheet set + .ss-existing-drawings = Existing drawings + .ss-create-a-folder-hierarchy-based-on-subsets = Create a folder hierarchy based on subsets + .ss-sheet-set-properties = Sheet Set Properties... + .ss-select-folders-containing-drawings-layouts-in-the-drawings-c = Select folders containing drawings. Layouts in the drawings can be added to the sheet set. + .ss-sheet-set = Sheet Set + .ss-sheet-set-data-file = Sheet set data file + .ss-sheets-to-import = Sheets to import + .ss-add-custom-property = Add Custom Property... + .ss-new-sheet-x = New Sheet... + .ss-new-subset = New Subset... + .ss-import-layout-as-sheet-x = Import Layout as Sheet... + .ss-rename-renumber = Rename & Renumber... + .ss-close-sheet-set = Close Sheet Set + .ss-properties = Properties... + .ss-sheet-list = Sheet List + .ss-sheet-views = Sheet Views + .ss-model-views = Model Views + .ss-views-by-sheet = Views by sheet + .ss-locations = Locations + .ss-create-a-sheet-set-using = Create a sheet set using + .ss-name-of-new-sheet-set = Name of new sheet set: + .ss-description-optional = Description (optional): + .ss-store-sheet-set-data-file-dst-here = Store sheet set data file (.dst) here: + .ss-choose-layouts = Choose Layouts + .ss-confirm = Confirm + .ss-default-value = Default value: + .ss-owner = Owner + .ss-custom-properties = Custom Properties + .ss-sheet-title = Sheet title + .ss-folder-path = Folder path + .ss-sheet-template = Sheet template + .ss-subset-name = Subset name + .ss-new-sheet-location = New sheet location + .ss-remove-subset = Remove Subset + .ss-remove-sheet = Remove Sheet + .ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set. + .ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets. + .ss-open-sheet-set = Open Sheet Set + .ss-sheet-set-dst = Sheet Set (*.dst) + .ss-browse-for-folder = Browse for Folder + .ss-select-layout-as-sheet-template = Select Layout as Sheet Template + .ss-drawing-template-dwt = Drawing Template (*.dwt) + .ss-drawing-dwg = Drawing (*.dwg) + .ss-the-name-cannot-be-empty = The name cannot be empty. + .ss-a-custom-property-with-this-name-already-exists = A custom property with this name already exists. + .ss-sheet-sets-organize-layouts-from-several-drawings-into-one-n = Sheet sets organize layouts from several drawings into one named set of sheets. + .ss-default-new-drawing = (default new drawing) + .ss-select-drawing = Select Drawing + .ss-the-sheet-set-name-cannot-be-empty = The sheet set name cannot be empty. + .ss-the-folder-for-the-sheet-set-data-file-does-not-exist = The folder for the sheet set data file does not exist. + .ss-the-drawing-has-no-layout-to-use-as-a-sheet-template = The drawing has no layout to use as a sheet template. + .ss-the-subset-name-cannot-be-empty = The subset name cannot be empty. + .ss-the-drawing-has-no-layout-to-import = The drawing has no layout to import. + .ss-the-layout-is-already-a-sheet-of-this-sheet-set = The layout is already a sheet of this sheet set. + .ss-the-sheet-title-cannot-be-empty = The sheet title cannot be empty. + .ss-the-sheet-folder-cannot-be-created = The sheet folder cannot be created. + .ss-sheet-set-properties-x = Sheet Set Properties + .ss-sheet-properties = Sheet Properties + .ss-sheet-drawing-not-found = Sheet drawing not found: __ocs_fmt_0__ + .ss-already-exists = __ocs_fmt_0__ already exists. + .ss-model-view = Model view + .ss-label-block-for-views = Label block for views + .ss-callout-blocks = Callout blocks + .ss-page-setup-overrides-file = Page setup overrides file + .ss-project-control = Project Control + .ss-sheet-creation = Sheet Creation + .ss-sheet-storage-location = Sheet storage location + .ss-sheet-creation-template = Sheet creation template + .ss-prompt-for-template = Prompt for template + .ss-subset = Subset + .ss-layout-name = Layout name + .ss-drawing-file = Drawing file + .ss-project-number = Project number + .ss-project-name = Project name + .ss-project-phase = Project phase + .ss-project-milestone = Project milestone + .ss-revision-number = Revision number + .ss-revision-date = Revision date + .ss-issue-purpose = Issue purpose + .ss-custom-property-name = Custom property name + .ss-placeholder-type = Placeholder type + .ss-sheet-set-x = Sheet set + .ss-sheet-navigation-tree = Sheet navigation tree + .ss-sheetset = SheetSet .message = __ocs_fmt_0__ .code-page = Κωδικοσελίδα: __ocs_fmt_0__ .created-julian-6 = Δημιουργία (Julian): __ocs_fmt_0__ diff --git a/locales/en-US/opencadstudio.ftl b/locales/en-US/opencadstudio.ftl index dcbbb7b69..026e3be67 100644 --- a/locales/en-US/opencadstudio.ftl +++ b/locales/en-US/opencadstudio.ftl @@ -4341,6 +4341,102 @@ layout = .vplayer-f-layer-freeze-t-layer-thaw-enter-exit = VPLAYER F = Freeze | T = Thaw | Enter = Exit view = + .ss-create-sheet-set = Create Sheet Set + .ss-new-sheet = New Sheet + .ss-subset-properties = Subset Properties + .ss-rename-renumber-sheet = Rename & Renumber Sheet + .ss-import-layout-as-sheet = Import Layout as Sheet + .ss-sheet-set-manager = Sheet Set Manager + .ss-open = Open... + .ss-open-a-sheet-set-or-create-one-with-newsheetset = Open a sheet set or create one with NEWSHEETSET. + .ss-no-sheet-views = No sheet views. + .ss-no-locations = No locations. + .ss-double-click-opens-a-sheet-right-click-for-more-commands = Double-click opens a sheet. Right-click for more commands. + .ss-an-empty-sheet-set = An empty sheet set + .ss-existing-drawings = Existing drawings + .ss-create-a-folder-hierarchy-based-on-subsets = Create a folder hierarchy based on subsets + .ss-sheet-set-properties = Sheet Set Properties... + .ss-select-folders-containing-drawings-layouts-in-the-drawings-c = Select folders containing drawings. Layouts in the drawings can be added to the sheet set. + .ss-sheet-set = Sheet Set + .ss-sheet-set-data-file = Sheet set data file + .ss-sheets-to-import = Sheets to import + .ss-add-custom-property = Add Custom Property... + .ss-new-sheet-x = New Sheet... + .ss-new-subset = New Subset... + .ss-import-layout-as-sheet-x = Import Layout as Sheet... + .ss-rename-renumber = Rename & Renumber... + .ss-close-sheet-set = Close Sheet Set + .ss-properties = Properties... + .ss-sheet-list = Sheet List + .ss-sheet-views = Sheet Views + .ss-model-views = Model Views + .ss-views-by-sheet = Views by sheet + .ss-locations = Locations + .ss-create-a-sheet-set-using = Create a sheet set using + .ss-name-of-new-sheet-set = Name of new sheet set: + .ss-description-optional = Description (optional): + .ss-store-sheet-set-data-file-dst-here = Store sheet set data file (.dst) here: + .ss-choose-layouts = Choose Layouts + .ss-confirm = Confirm + .ss-default-value = Default value: + .ss-owner = Owner + .ss-custom-properties = Custom Properties + .ss-sheet-title = Sheet title + .ss-folder-path = Folder path + .ss-sheet-template = Sheet template + .ss-subset-name = Subset name + .ss-new-sheet-location = New sheet location + .ss-remove-subset = Remove Subset + .ss-remove-sheet = Remove Sheet + .ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set. + .ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets. + .ss-open-sheet-set = Open Sheet Set + .ss-sheet-set-dst = Sheet Set (*.dst) + .ss-browse-for-folder = Browse for Folder + .ss-select-layout-as-sheet-template = Select Layout as Sheet Template + .ss-drawing-template-dwt = Drawing Template (*.dwt) + .ss-drawing-dwg = Drawing (*.dwg) + .ss-the-name-cannot-be-empty = The name cannot be empty. + .ss-a-custom-property-with-this-name-already-exists = A custom property with this name already exists. + .ss-sheet-sets-organize-layouts-from-several-drawings-into-one-n = Sheet sets organize layouts from several drawings into one named set of sheets. + .ss-default-new-drawing = (default new drawing) + .ss-select-drawing = Select Drawing + .ss-the-sheet-set-name-cannot-be-empty = The sheet set name cannot be empty. + .ss-the-folder-for-the-sheet-set-data-file-does-not-exist = The folder for the sheet set data file does not exist. + .ss-the-drawing-has-no-layout-to-use-as-a-sheet-template = The drawing has no layout to use as a sheet template. + .ss-the-subset-name-cannot-be-empty = The subset name cannot be empty. + .ss-the-drawing-has-no-layout-to-import = The drawing has no layout to import. + .ss-the-layout-is-already-a-sheet-of-this-sheet-set = The layout is already a sheet of this sheet set. + .ss-the-sheet-title-cannot-be-empty = The sheet title cannot be empty. + .ss-the-sheet-folder-cannot-be-created = The sheet folder cannot be created. + .ss-sheet-set-properties-x = Sheet Set Properties + .ss-sheet-properties = Sheet Properties + .ss-sheet-drawing-not-found = Sheet drawing not found: __ocs_fmt_0__ + .ss-already-exists = __ocs_fmt_0__ already exists. + .ss-model-view = Model view + .ss-label-block-for-views = Label block for views + .ss-callout-blocks = Callout blocks + .ss-page-setup-overrides-file = Page setup overrides file + .ss-project-control = Project Control + .ss-sheet-creation = Sheet Creation + .ss-sheet-storage-location = Sheet storage location + .ss-sheet-creation-template = Sheet creation template + .ss-prompt-for-template = Prompt for template + .ss-subset = Subset + .ss-layout-name = Layout name + .ss-drawing-file = Drawing file + .ss-project-number = Project number + .ss-project-name = Project name + .ss-project-phase = Project phase + .ss-project-milestone = Project milestone + .ss-revision-number = Revision number + .ss-revision-date = Revision date + .ss-issue-purpose = Issue purpose + .ss-custom-property-name = Custom property name + .ss-placeholder-type = Placeholder type + .ss-sheet-set-x = Sheet set + .ss-sheet-navigation-tree = Sheet navigation tree + .ss-sheetset = SheetSet .message = __ocs_fmt_0__ .code-page = Code page: __ocs_fmt_0__ .created-julian-6 = Created (Julian): __ocs_fmt_0__ diff --git a/locales/es-ES/opencadstudio.ftl b/locales/es-ES/opencadstudio.ftl index df1b19661..49474bbda 100644 --- a/locales/es-ES/opencadstudio.ftl +++ b/locales/es-ES/opencadstudio.ftl @@ -4340,6 +4340,102 @@ layout = .vplayer-f-layer-freeze-t-layer-thaw-enter-exit = VPLAYER F = Inutilizar | T = Reutilizar | Intro = Salir view = + .ss-create-sheet-set = Create Sheet Set + .ss-new-sheet = New Sheet + .ss-subset-properties = Subset Properties + .ss-rename-renumber-sheet = Rename & Renumber Sheet + .ss-import-layout-as-sheet = Import Layout as Sheet + .ss-sheet-set-manager = Sheet Set Manager + .ss-open = Open... + .ss-open-a-sheet-set-or-create-one-with-newsheetset = Open a sheet set or create one with NEWSHEETSET. + .ss-no-sheet-views = No sheet views. + .ss-no-locations = No locations. + .ss-double-click-opens-a-sheet-right-click-for-more-commands = Double-click opens a sheet. Right-click for more commands. + .ss-an-empty-sheet-set = An empty sheet set + .ss-existing-drawings = Existing drawings + .ss-create-a-folder-hierarchy-based-on-subsets = Create a folder hierarchy based on subsets + .ss-sheet-set-properties = Sheet Set Properties... + .ss-select-folders-containing-drawings-layouts-in-the-drawings-c = Select folders containing drawings. Layouts in the drawings can be added to the sheet set. + .ss-sheet-set = Sheet Set + .ss-sheet-set-data-file = Sheet set data file + .ss-sheets-to-import = Sheets to import + .ss-add-custom-property = Add Custom Property... + .ss-new-sheet-x = New Sheet... + .ss-new-subset = New Subset... + .ss-import-layout-as-sheet-x = Import Layout as Sheet... + .ss-rename-renumber = Rename & Renumber... + .ss-close-sheet-set = Close Sheet Set + .ss-properties = Properties... + .ss-sheet-list = Sheet List + .ss-sheet-views = Sheet Views + .ss-model-views = Model Views + .ss-views-by-sheet = Views by sheet + .ss-locations = Locations + .ss-create-a-sheet-set-using = Create a sheet set using + .ss-name-of-new-sheet-set = Name of new sheet set: + .ss-description-optional = Description (optional): + .ss-store-sheet-set-data-file-dst-here = Store sheet set data file (.dst) here: + .ss-choose-layouts = Choose Layouts + .ss-confirm = Confirm + .ss-default-value = Default value: + .ss-owner = Owner + .ss-custom-properties = Custom Properties + .ss-sheet-title = Sheet title + .ss-folder-path = Folder path + .ss-sheet-template = Sheet template + .ss-subset-name = Subset name + .ss-new-sheet-location = New sheet location + .ss-remove-subset = Remove Subset + .ss-remove-sheet = Remove Sheet + .ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set. + .ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets. + .ss-open-sheet-set = Open Sheet Set + .ss-sheet-set-dst = Sheet Set (*.dst) + .ss-browse-for-folder = Browse for Folder + .ss-select-layout-as-sheet-template = Select Layout as Sheet Template + .ss-drawing-template-dwt = Drawing Template (*.dwt) + .ss-drawing-dwg = Drawing (*.dwg) + .ss-the-name-cannot-be-empty = The name cannot be empty. + .ss-a-custom-property-with-this-name-already-exists = A custom property with this name already exists. + .ss-sheet-sets-organize-layouts-from-several-drawings-into-one-n = Sheet sets organize layouts from several drawings into one named set of sheets. + .ss-default-new-drawing = (default new drawing) + .ss-select-drawing = Select Drawing + .ss-the-sheet-set-name-cannot-be-empty = The sheet set name cannot be empty. + .ss-the-folder-for-the-sheet-set-data-file-does-not-exist = The folder for the sheet set data file does not exist. + .ss-the-drawing-has-no-layout-to-use-as-a-sheet-template = The drawing has no layout to use as a sheet template. + .ss-the-subset-name-cannot-be-empty = The subset name cannot be empty. + .ss-the-drawing-has-no-layout-to-import = The drawing has no layout to import. + .ss-the-layout-is-already-a-sheet-of-this-sheet-set = The layout is already a sheet of this sheet set. + .ss-the-sheet-title-cannot-be-empty = The sheet title cannot be empty. + .ss-the-sheet-folder-cannot-be-created = The sheet folder cannot be created. + .ss-sheet-set-properties-x = Sheet Set Properties + .ss-sheet-properties = Sheet Properties + .ss-sheet-drawing-not-found = Sheet drawing not found: __ocs_fmt_0__ + .ss-already-exists = __ocs_fmt_0__ already exists. + .ss-model-view = Model view + .ss-label-block-for-views = Label block for views + .ss-callout-blocks = Callout blocks + .ss-page-setup-overrides-file = Page setup overrides file + .ss-project-control = Project Control + .ss-sheet-creation = Sheet Creation + .ss-sheet-storage-location = Sheet storage location + .ss-sheet-creation-template = Sheet creation template + .ss-prompt-for-template = Prompt for template + .ss-subset = Subset + .ss-layout-name = Layout name + .ss-drawing-file = Drawing file + .ss-project-number = Project number + .ss-project-name = Project name + .ss-project-phase = Project phase + .ss-project-milestone = Project milestone + .ss-revision-number = Revision number + .ss-revision-date = Revision date + .ss-issue-purpose = Issue purpose + .ss-custom-property-name = Custom property name + .ss-placeholder-type = Placeholder type + .ss-sheet-set-x = Sheet set + .ss-sheet-navigation-tree = Sheet navigation tree + .ss-sheetset = SheetSet .datalink-specify-insertion-point = DATALINK Especifique el punto de inserción: .table-block-definition-not-found = TABLE: no se encontró la definición de bloque. .table-edit-applied = TABLE: edición aplicada. diff --git a/locales/fi-FI/opencadstudio.ftl b/locales/fi-FI/opencadstudio.ftl index 99f18d514..18846481f 100644 --- a/locales/fi-FI/opencadstudio.ftl +++ b/locales/fi-FI/opencadstudio.ftl @@ -4339,6 +4339,102 @@ layout = .vplayer-f-layer-freeze-t-layer-thaw-enter-exit = VPLAYER F = Jäädytys | T = Sulatus | Enter = Poistu view = + .ss-create-sheet-set = Create Sheet Set + .ss-new-sheet = New Sheet + .ss-subset-properties = Subset Properties + .ss-rename-renumber-sheet = Rename & Renumber Sheet + .ss-import-layout-as-sheet = Import Layout as Sheet + .ss-sheet-set-manager = Sheet Set Manager + .ss-open = Open... + .ss-open-a-sheet-set-or-create-one-with-newsheetset = Open a sheet set or create one with NEWSHEETSET. + .ss-no-sheet-views = No sheet views. + .ss-no-locations = No locations. + .ss-double-click-opens-a-sheet-right-click-for-more-commands = Double-click opens a sheet. Right-click for more commands. + .ss-an-empty-sheet-set = An empty sheet set + .ss-existing-drawings = Existing drawings + .ss-create-a-folder-hierarchy-based-on-subsets = Create a folder hierarchy based on subsets + .ss-sheet-set-properties = Sheet Set Properties... + .ss-select-folders-containing-drawings-layouts-in-the-drawings-c = Select folders containing drawings. Layouts in the drawings can be added to the sheet set. + .ss-sheet-set = Sheet Set + .ss-sheet-set-data-file = Sheet set data file + .ss-sheets-to-import = Sheets to import + .ss-add-custom-property = Add Custom Property... + .ss-new-sheet-x = New Sheet... + .ss-new-subset = New Subset... + .ss-import-layout-as-sheet-x = Import Layout as Sheet... + .ss-rename-renumber = Rename & Renumber... + .ss-close-sheet-set = Close Sheet Set + .ss-properties = Properties... + .ss-sheet-list = Sheet List + .ss-sheet-views = Sheet Views + .ss-model-views = Model Views + .ss-views-by-sheet = Views by sheet + .ss-locations = Locations + .ss-create-a-sheet-set-using = Create a sheet set using + .ss-name-of-new-sheet-set = Name of new sheet set: + .ss-description-optional = Description (optional): + .ss-store-sheet-set-data-file-dst-here = Store sheet set data file (.dst) here: + .ss-choose-layouts = Choose Layouts + .ss-confirm = Confirm + .ss-default-value = Default value: + .ss-owner = Owner + .ss-custom-properties = Custom Properties + .ss-sheet-title = Sheet title + .ss-folder-path = Folder path + .ss-sheet-template = Sheet template + .ss-subset-name = Subset name + .ss-new-sheet-location = New sheet location + .ss-remove-subset = Remove Subset + .ss-remove-sheet = Remove Sheet + .ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set. + .ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets. + .ss-open-sheet-set = Open Sheet Set + .ss-sheet-set-dst = Sheet Set (*.dst) + .ss-browse-for-folder = Browse for Folder + .ss-select-layout-as-sheet-template = Select Layout as Sheet Template + .ss-drawing-template-dwt = Drawing Template (*.dwt) + .ss-drawing-dwg = Drawing (*.dwg) + .ss-the-name-cannot-be-empty = The name cannot be empty. + .ss-a-custom-property-with-this-name-already-exists = A custom property with this name already exists. + .ss-sheet-sets-organize-layouts-from-several-drawings-into-one-n = Sheet sets organize layouts from several drawings into one named set of sheets. + .ss-default-new-drawing = (default new drawing) + .ss-select-drawing = Select Drawing + .ss-the-sheet-set-name-cannot-be-empty = The sheet set name cannot be empty. + .ss-the-folder-for-the-sheet-set-data-file-does-not-exist = The folder for the sheet set data file does not exist. + .ss-the-drawing-has-no-layout-to-use-as-a-sheet-template = The drawing has no layout to use as a sheet template. + .ss-the-subset-name-cannot-be-empty = The subset name cannot be empty. + .ss-the-drawing-has-no-layout-to-import = The drawing has no layout to import. + .ss-the-layout-is-already-a-sheet-of-this-sheet-set = The layout is already a sheet of this sheet set. + .ss-the-sheet-title-cannot-be-empty = The sheet title cannot be empty. + .ss-the-sheet-folder-cannot-be-created = The sheet folder cannot be created. + .ss-sheet-set-properties-x = Sheet Set Properties + .ss-sheet-properties = Sheet Properties + .ss-sheet-drawing-not-found = Sheet drawing not found: __ocs_fmt_0__ + .ss-already-exists = __ocs_fmt_0__ already exists. + .ss-model-view = Model view + .ss-label-block-for-views = Label block for views + .ss-callout-blocks = Callout blocks + .ss-page-setup-overrides-file = Page setup overrides file + .ss-project-control = Project Control + .ss-sheet-creation = Sheet Creation + .ss-sheet-storage-location = Sheet storage location + .ss-sheet-creation-template = Sheet creation template + .ss-prompt-for-template = Prompt for template + .ss-subset = Subset + .ss-layout-name = Layout name + .ss-drawing-file = Drawing file + .ss-project-number = Project number + .ss-project-name = Project name + .ss-project-phase = Project phase + .ss-project-milestone = Project milestone + .ss-revision-number = Revision number + .ss-revision-date = Revision date + .ss-issue-purpose = Issue purpose + .ss-custom-property-name = Custom property name + .ss-placeholder-type = Placeholder type + .ss-sheet-set-x = Sheet set + .ss-sheet-navigation-tree = Sheet navigation tree + .ss-sheetset = SheetSet .datalink-specify-insertion-point = DATALINK Määritä lisäyspiste: .table-block-definition-not-found = TABLE: lohkomääritystä ei löytynyt. .table-edit-applied = TABLE: muokkaus otettu käyttöön. diff --git a/locales/fr-FR/opencadstudio.ftl b/locales/fr-FR/opencadstudio.ftl index bc00d9334..b8c592fa8 100644 --- a/locales/fr-FR/opencadstudio.ftl +++ b/locales/fr-FR/opencadstudio.ftl @@ -4340,6 +4340,102 @@ layout = .vplayer-f-layer-freeze-t-layer-thaw-enter-exit = VPLAYER F = Freeze , T = Thaw , Entrée = Sortie view = + .ss-create-sheet-set = Create Sheet Set + .ss-new-sheet = New Sheet + .ss-subset-properties = Subset Properties + .ss-rename-renumber-sheet = Rename & Renumber Sheet + .ss-import-layout-as-sheet = Import Layout as Sheet + .ss-sheet-set-manager = Sheet Set Manager + .ss-open = Open... + .ss-open-a-sheet-set-or-create-one-with-newsheetset = Open a sheet set or create one with NEWSHEETSET. + .ss-no-sheet-views = No sheet views. + .ss-no-locations = No locations. + .ss-double-click-opens-a-sheet-right-click-for-more-commands = Double-click opens a sheet. Right-click for more commands. + .ss-an-empty-sheet-set = An empty sheet set + .ss-existing-drawings = Existing drawings + .ss-create-a-folder-hierarchy-based-on-subsets = Create a folder hierarchy based on subsets + .ss-sheet-set-properties = Sheet Set Properties... + .ss-select-folders-containing-drawings-layouts-in-the-drawings-c = Select folders containing drawings. Layouts in the drawings can be added to the sheet set. + .ss-sheet-set = Sheet Set + .ss-sheet-set-data-file = Sheet set data file + .ss-sheets-to-import = Sheets to import + .ss-add-custom-property = Add Custom Property... + .ss-new-sheet-x = New Sheet... + .ss-new-subset = New Subset... + .ss-import-layout-as-sheet-x = Import Layout as Sheet... + .ss-rename-renumber = Rename & Renumber... + .ss-close-sheet-set = Close Sheet Set + .ss-properties = Properties... + .ss-sheet-list = Sheet List + .ss-sheet-views = Sheet Views + .ss-model-views = Model Views + .ss-views-by-sheet = Views by sheet + .ss-locations = Locations + .ss-create-a-sheet-set-using = Create a sheet set using + .ss-name-of-new-sheet-set = Name of new sheet set: + .ss-description-optional = Description (optional): + .ss-store-sheet-set-data-file-dst-here = Store sheet set data file (.dst) here: + .ss-choose-layouts = Choose Layouts + .ss-confirm = Confirm + .ss-default-value = Default value: + .ss-owner = Owner + .ss-custom-properties = Custom Properties + .ss-sheet-title = Sheet title + .ss-folder-path = Folder path + .ss-sheet-template = Sheet template + .ss-subset-name = Subset name + .ss-new-sheet-location = New sheet location + .ss-remove-subset = Remove Subset + .ss-remove-sheet = Remove Sheet + .ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set. + .ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets. + .ss-open-sheet-set = Open Sheet Set + .ss-sheet-set-dst = Sheet Set (*.dst) + .ss-browse-for-folder = Browse for Folder + .ss-select-layout-as-sheet-template = Select Layout as Sheet Template + .ss-drawing-template-dwt = Drawing Template (*.dwt) + .ss-drawing-dwg = Drawing (*.dwg) + .ss-the-name-cannot-be-empty = The name cannot be empty. + .ss-a-custom-property-with-this-name-already-exists = A custom property with this name already exists. + .ss-sheet-sets-organize-layouts-from-several-drawings-into-one-n = Sheet sets organize layouts from several drawings into one named set of sheets. + .ss-default-new-drawing = (default new drawing) + .ss-select-drawing = Select Drawing + .ss-the-sheet-set-name-cannot-be-empty = The sheet set name cannot be empty. + .ss-the-folder-for-the-sheet-set-data-file-does-not-exist = The folder for the sheet set data file does not exist. + .ss-the-drawing-has-no-layout-to-use-as-a-sheet-template = The drawing has no layout to use as a sheet template. + .ss-the-subset-name-cannot-be-empty = The subset name cannot be empty. + .ss-the-drawing-has-no-layout-to-import = The drawing has no layout to import. + .ss-the-layout-is-already-a-sheet-of-this-sheet-set = The layout is already a sheet of this sheet set. + .ss-the-sheet-title-cannot-be-empty = The sheet title cannot be empty. + .ss-the-sheet-folder-cannot-be-created = The sheet folder cannot be created. + .ss-sheet-set-properties-x = Sheet Set Properties + .ss-sheet-properties = Sheet Properties + .ss-sheet-drawing-not-found = Sheet drawing not found: __ocs_fmt_0__ + .ss-already-exists = __ocs_fmt_0__ already exists. + .ss-model-view = Model view + .ss-label-block-for-views = Label block for views + .ss-callout-blocks = Callout blocks + .ss-page-setup-overrides-file = Page setup overrides file + .ss-project-control = Project Control + .ss-sheet-creation = Sheet Creation + .ss-sheet-storage-location = Sheet storage location + .ss-sheet-creation-template = Sheet creation template + .ss-prompt-for-template = Prompt for template + .ss-subset = Subset + .ss-layout-name = Layout name + .ss-drawing-file = Drawing file + .ss-project-number = Project number + .ss-project-name = Project name + .ss-project-phase = Project phase + .ss-project-milestone = Project milestone + .ss-revision-number = Revision number + .ss-revision-date = Revision date + .ss-issue-purpose = Issue purpose + .ss-custom-property-name = Custom property name + .ss-placeholder-type = Placeholder type + .ss-sheet-set-x = Sheet set + .ss-sheet-navigation-tree = Sheet navigation tree + .ss-sheetset = SheetSet .datalink-specify-insertion-point = DATALINK Spécifiez le point d’insertion : .table-block-definition-not-found = TABLE : définition de bloc introuvable. .table-edit-applied = TABLE : modification appliquée. diff --git a/locales/hi-IN/opencadstudio.ftl b/locales/hi-IN/opencadstudio.ftl index 59440e35e..47fcb2c81 100644 --- a/locales/hi-IN/opencadstudio.ftl +++ b/locales/hi-IN/opencadstudio.ftl @@ -4328,6 +4328,102 @@ layout = .vplayer-f-layer-freeze-t-layer-thaw-enter-exit = VPLAYER F <लेयर> = फ़्रीज़ | T <लेयर> = थॉ | Enter = बाहर निकलें view = + .ss-create-sheet-set = Create Sheet Set + .ss-new-sheet = New Sheet + .ss-subset-properties = Subset Properties + .ss-rename-renumber-sheet = Rename & Renumber Sheet + .ss-import-layout-as-sheet = Import Layout as Sheet + .ss-sheet-set-manager = Sheet Set Manager + .ss-open = Open... + .ss-open-a-sheet-set-or-create-one-with-newsheetset = Open a sheet set or create one with NEWSHEETSET. + .ss-no-sheet-views = No sheet views. + .ss-no-locations = No locations. + .ss-double-click-opens-a-sheet-right-click-for-more-commands = Double-click opens a sheet. Right-click for more commands. + .ss-an-empty-sheet-set = An empty sheet set + .ss-existing-drawings = Existing drawings + .ss-create-a-folder-hierarchy-based-on-subsets = Create a folder hierarchy based on subsets + .ss-sheet-set-properties = Sheet Set Properties... + .ss-select-folders-containing-drawings-layouts-in-the-drawings-c = Select folders containing drawings. Layouts in the drawings can be added to the sheet set. + .ss-sheet-set = Sheet Set + .ss-sheet-set-data-file = Sheet set data file + .ss-sheets-to-import = Sheets to import + .ss-add-custom-property = Add Custom Property... + .ss-new-sheet-x = New Sheet... + .ss-new-subset = New Subset... + .ss-import-layout-as-sheet-x = Import Layout as Sheet... + .ss-rename-renumber = Rename & Renumber... + .ss-close-sheet-set = Close Sheet Set + .ss-properties = Properties... + .ss-sheet-list = Sheet List + .ss-sheet-views = Sheet Views + .ss-model-views = Model Views + .ss-views-by-sheet = Views by sheet + .ss-locations = Locations + .ss-create-a-sheet-set-using = Create a sheet set using + .ss-name-of-new-sheet-set = Name of new sheet set: + .ss-description-optional = Description (optional): + .ss-store-sheet-set-data-file-dst-here = Store sheet set data file (.dst) here: + .ss-choose-layouts = Choose Layouts + .ss-confirm = Confirm + .ss-default-value = Default value: + .ss-owner = Owner + .ss-custom-properties = Custom Properties + .ss-sheet-title = Sheet title + .ss-folder-path = Folder path + .ss-sheet-template = Sheet template + .ss-subset-name = Subset name + .ss-new-sheet-location = New sheet location + .ss-remove-subset = Remove Subset + .ss-remove-sheet = Remove Sheet + .ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set. + .ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets. + .ss-open-sheet-set = Open Sheet Set + .ss-sheet-set-dst = Sheet Set (*.dst) + .ss-browse-for-folder = Browse for Folder + .ss-select-layout-as-sheet-template = Select Layout as Sheet Template + .ss-drawing-template-dwt = Drawing Template (*.dwt) + .ss-drawing-dwg = Drawing (*.dwg) + .ss-the-name-cannot-be-empty = The name cannot be empty. + .ss-a-custom-property-with-this-name-already-exists = A custom property with this name already exists. + .ss-sheet-sets-organize-layouts-from-several-drawings-into-one-n = Sheet sets organize layouts from several drawings into one named set of sheets. + .ss-default-new-drawing = (default new drawing) + .ss-select-drawing = Select Drawing + .ss-the-sheet-set-name-cannot-be-empty = The sheet set name cannot be empty. + .ss-the-folder-for-the-sheet-set-data-file-does-not-exist = The folder for the sheet set data file does not exist. + .ss-the-drawing-has-no-layout-to-use-as-a-sheet-template = The drawing has no layout to use as a sheet template. + .ss-the-subset-name-cannot-be-empty = The subset name cannot be empty. + .ss-the-drawing-has-no-layout-to-import = The drawing has no layout to import. + .ss-the-layout-is-already-a-sheet-of-this-sheet-set = The layout is already a sheet of this sheet set. + .ss-the-sheet-title-cannot-be-empty = The sheet title cannot be empty. + .ss-the-sheet-folder-cannot-be-created = The sheet folder cannot be created. + .ss-sheet-set-properties-x = Sheet Set Properties + .ss-sheet-properties = Sheet Properties + .ss-sheet-drawing-not-found = Sheet drawing not found: __ocs_fmt_0__ + .ss-already-exists = __ocs_fmt_0__ already exists. + .ss-model-view = Model view + .ss-label-block-for-views = Label block for views + .ss-callout-blocks = Callout blocks + .ss-page-setup-overrides-file = Page setup overrides file + .ss-project-control = Project Control + .ss-sheet-creation = Sheet Creation + .ss-sheet-storage-location = Sheet storage location + .ss-sheet-creation-template = Sheet creation template + .ss-prompt-for-template = Prompt for template + .ss-subset = Subset + .ss-layout-name = Layout name + .ss-drawing-file = Drawing file + .ss-project-number = Project number + .ss-project-name = Project name + .ss-project-phase = Project phase + .ss-project-milestone = Project milestone + .ss-revision-number = Revision number + .ss-revision-date = Revision date + .ss-issue-purpose = Issue purpose + .ss-custom-property-name = Custom property name + .ss-placeholder-type = Placeholder type + .ss-sheet-set-x = Sheet set + .ss-sheet-navigation-tree = Sheet navigation tree + .ss-sheetset = SheetSet .datalink-specify-insertion-point = DATALINK सम्मिलन बिंदु निर्दिष्ट करें: .table-block-definition-not-found = TABLE: ब्लॉक परिभाषा नहीं मिली। .table-edit-applied = TABLE: संपादन लागू किया गया। diff --git a/locales/hu-HU/opencadstudio.ftl b/locales/hu-HU/opencadstudio.ftl index 2066c5156..81c064f6f 100644 --- a/locales/hu-HU/opencadstudio.ftl +++ b/locales/hu-HU/opencadstudio.ftl @@ -4339,6 +4339,102 @@ layout = .vplayer-f-layer-freeze-t-layer-thaw-enter-exit = VPLAYER F = Fagyasztás | T = Felengedés | Enter = Kilépés view = + .ss-create-sheet-set = Create Sheet Set + .ss-new-sheet = New Sheet + .ss-subset-properties = Subset Properties + .ss-rename-renumber-sheet = Rename & Renumber Sheet + .ss-import-layout-as-sheet = Import Layout as Sheet + .ss-sheet-set-manager = Sheet Set Manager + .ss-open = Open... + .ss-open-a-sheet-set-or-create-one-with-newsheetset = Open a sheet set or create one with NEWSHEETSET. + .ss-no-sheet-views = No sheet views. + .ss-no-locations = No locations. + .ss-double-click-opens-a-sheet-right-click-for-more-commands = Double-click opens a sheet. Right-click for more commands. + .ss-an-empty-sheet-set = An empty sheet set + .ss-existing-drawings = Existing drawings + .ss-create-a-folder-hierarchy-based-on-subsets = Create a folder hierarchy based on subsets + .ss-sheet-set-properties = Sheet Set Properties... + .ss-select-folders-containing-drawings-layouts-in-the-drawings-c = Select folders containing drawings. Layouts in the drawings can be added to the sheet set. + .ss-sheet-set = Sheet Set + .ss-sheet-set-data-file = Sheet set data file + .ss-sheets-to-import = Sheets to import + .ss-add-custom-property = Add Custom Property... + .ss-new-sheet-x = New Sheet... + .ss-new-subset = New Subset... + .ss-import-layout-as-sheet-x = Import Layout as Sheet... + .ss-rename-renumber = Rename & Renumber... + .ss-close-sheet-set = Close Sheet Set + .ss-properties = Properties... + .ss-sheet-list = Sheet List + .ss-sheet-views = Sheet Views + .ss-model-views = Model Views + .ss-views-by-sheet = Views by sheet + .ss-locations = Locations + .ss-create-a-sheet-set-using = Create a sheet set using + .ss-name-of-new-sheet-set = Name of new sheet set: + .ss-description-optional = Description (optional): + .ss-store-sheet-set-data-file-dst-here = Store sheet set data file (.dst) here: + .ss-choose-layouts = Choose Layouts + .ss-confirm = Confirm + .ss-default-value = Default value: + .ss-owner = Owner + .ss-custom-properties = Custom Properties + .ss-sheet-title = Sheet title + .ss-folder-path = Folder path + .ss-sheet-template = Sheet template + .ss-subset-name = Subset name + .ss-new-sheet-location = New sheet location + .ss-remove-subset = Remove Subset + .ss-remove-sheet = Remove Sheet + .ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set. + .ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets. + .ss-open-sheet-set = Open Sheet Set + .ss-sheet-set-dst = Sheet Set (*.dst) + .ss-browse-for-folder = Browse for Folder + .ss-select-layout-as-sheet-template = Select Layout as Sheet Template + .ss-drawing-template-dwt = Drawing Template (*.dwt) + .ss-drawing-dwg = Drawing (*.dwg) + .ss-the-name-cannot-be-empty = The name cannot be empty. + .ss-a-custom-property-with-this-name-already-exists = A custom property with this name already exists. + .ss-sheet-sets-organize-layouts-from-several-drawings-into-one-n = Sheet sets organize layouts from several drawings into one named set of sheets. + .ss-default-new-drawing = (default new drawing) + .ss-select-drawing = Select Drawing + .ss-the-sheet-set-name-cannot-be-empty = The sheet set name cannot be empty. + .ss-the-folder-for-the-sheet-set-data-file-does-not-exist = The folder for the sheet set data file does not exist. + .ss-the-drawing-has-no-layout-to-use-as-a-sheet-template = The drawing has no layout to use as a sheet template. + .ss-the-subset-name-cannot-be-empty = The subset name cannot be empty. + .ss-the-drawing-has-no-layout-to-import = The drawing has no layout to import. + .ss-the-layout-is-already-a-sheet-of-this-sheet-set = The layout is already a sheet of this sheet set. + .ss-the-sheet-title-cannot-be-empty = The sheet title cannot be empty. + .ss-the-sheet-folder-cannot-be-created = The sheet folder cannot be created. + .ss-sheet-set-properties-x = Sheet Set Properties + .ss-sheet-properties = Sheet Properties + .ss-sheet-drawing-not-found = Sheet drawing not found: __ocs_fmt_0__ + .ss-already-exists = __ocs_fmt_0__ already exists. + .ss-model-view = Model view + .ss-label-block-for-views = Label block for views + .ss-callout-blocks = Callout blocks + .ss-page-setup-overrides-file = Page setup overrides file + .ss-project-control = Project Control + .ss-sheet-creation = Sheet Creation + .ss-sheet-storage-location = Sheet storage location + .ss-sheet-creation-template = Sheet creation template + .ss-prompt-for-template = Prompt for template + .ss-subset = Subset + .ss-layout-name = Layout name + .ss-drawing-file = Drawing file + .ss-project-number = Project number + .ss-project-name = Project name + .ss-project-phase = Project phase + .ss-project-milestone = Project milestone + .ss-revision-number = Revision number + .ss-revision-date = Revision date + .ss-issue-purpose = Issue purpose + .ss-custom-property-name = Custom property name + .ss-placeholder-type = Placeholder type + .ss-sheet-set-x = Sheet set + .ss-sheet-navigation-tree = Sheet navigation tree + .ss-sheetset = SheetSet .datalink-specify-insertion-point = DATALINK Adja meg a beszúrási pontot: .table-block-definition-not-found = TABLE: a blokkdefiníció nem található. .table-edit-applied = TABLE: a módosítás alkalmazva. diff --git a/locales/it-IT/opencadstudio.ftl b/locales/it-IT/opencadstudio.ftl index bab01a81c..0137d3a34 100644 --- a/locales/it-IT/opencadstudio.ftl +++ b/locales/it-IT/opencadstudio.ftl @@ -4339,6 +4339,102 @@ layout = .vplayer-f-layer-freeze-t-layer-thaw-enter-exit = VPLAYER F = Congela | T = Scongela | Enter = Esci view = + .ss-create-sheet-set = Create Sheet Set + .ss-new-sheet = New Sheet + .ss-subset-properties = Subset Properties + .ss-rename-renumber-sheet = Rename & Renumber Sheet + .ss-import-layout-as-sheet = Import Layout as Sheet + .ss-sheet-set-manager = Sheet Set Manager + .ss-open = Open... + .ss-open-a-sheet-set-or-create-one-with-newsheetset = Open a sheet set or create one with NEWSHEETSET. + .ss-no-sheet-views = No sheet views. + .ss-no-locations = No locations. + .ss-double-click-opens-a-sheet-right-click-for-more-commands = Double-click opens a sheet. Right-click for more commands. + .ss-an-empty-sheet-set = An empty sheet set + .ss-existing-drawings = Existing drawings + .ss-create-a-folder-hierarchy-based-on-subsets = Create a folder hierarchy based on subsets + .ss-sheet-set-properties = Sheet Set Properties... + .ss-select-folders-containing-drawings-layouts-in-the-drawings-c = Select folders containing drawings. Layouts in the drawings can be added to the sheet set. + .ss-sheet-set = Sheet Set + .ss-sheet-set-data-file = Sheet set data file + .ss-sheets-to-import = Sheets to import + .ss-add-custom-property = Add Custom Property... + .ss-new-sheet-x = New Sheet... + .ss-new-subset = New Subset... + .ss-import-layout-as-sheet-x = Import Layout as Sheet... + .ss-rename-renumber = Rename & Renumber... + .ss-close-sheet-set = Close Sheet Set + .ss-properties = Properties... + .ss-sheet-list = Sheet List + .ss-sheet-views = Sheet Views + .ss-model-views = Model Views + .ss-views-by-sheet = Views by sheet + .ss-locations = Locations + .ss-create-a-sheet-set-using = Create a sheet set using + .ss-name-of-new-sheet-set = Name of new sheet set: + .ss-description-optional = Description (optional): + .ss-store-sheet-set-data-file-dst-here = Store sheet set data file (.dst) here: + .ss-choose-layouts = Choose Layouts + .ss-confirm = Confirm + .ss-default-value = Default value: + .ss-owner = Owner + .ss-custom-properties = Custom Properties + .ss-sheet-title = Sheet title + .ss-folder-path = Folder path + .ss-sheet-template = Sheet template + .ss-subset-name = Subset name + .ss-new-sheet-location = New sheet location + .ss-remove-subset = Remove Subset + .ss-remove-sheet = Remove Sheet + .ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set. + .ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets. + .ss-open-sheet-set = Open Sheet Set + .ss-sheet-set-dst = Sheet Set (*.dst) + .ss-browse-for-folder = Browse for Folder + .ss-select-layout-as-sheet-template = Select Layout as Sheet Template + .ss-drawing-template-dwt = Drawing Template (*.dwt) + .ss-drawing-dwg = Drawing (*.dwg) + .ss-the-name-cannot-be-empty = The name cannot be empty. + .ss-a-custom-property-with-this-name-already-exists = A custom property with this name already exists. + .ss-sheet-sets-organize-layouts-from-several-drawings-into-one-n = Sheet sets organize layouts from several drawings into one named set of sheets. + .ss-default-new-drawing = (default new drawing) + .ss-select-drawing = Select Drawing + .ss-the-sheet-set-name-cannot-be-empty = The sheet set name cannot be empty. + .ss-the-folder-for-the-sheet-set-data-file-does-not-exist = The folder for the sheet set data file does not exist. + .ss-the-drawing-has-no-layout-to-use-as-a-sheet-template = The drawing has no layout to use as a sheet template. + .ss-the-subset-name-cannot-be-empty = The subset name cannot be empty. + .ss-the-drawing-has-no-layout-to-import = The drawing has no layout to import. + .ss-the-layout-is-already-a-sheet-of-this-sheet-set = The layout is already a sheet of this sheet set. + .ss-the-sheet-title-cannot-be-empty = The sheet title cannot be empty. + .ss-the-sheet-folder-cannot-be-created = The sheet folder cannot be created. + .ss-sheet-set-properties-x = Sheet Set Properties + .ss-sheet-properties = Sheet Properties + .ss-sheet-drawing-not-found = Sheet drawing not found: __ocs_fmt_0__ + .ss-already-exists = __ocs_fmt_0__ already exists. + .ss-model-view = Model view + .ss-label-block-for-views = Label block for views + .ss-callout-blocks = Callout blocks + .ss-page-setup-overrides-file = Page setup overrides file + .ss-project-control = Project Control + .ss-sheet-creation = Sheet Creation + .ss-sheet-storage-location = Sheet storage location + .ss-sheet-creation-template = Sheet creation template + .ss-prompt-for-template = Prompt for template + .ss-subset = Subset + .ss-layout-name = Layout name + .ss-drawing-file = Drawing file + .ss-project-number = Project number + .ss-project-name = Project name + .ss-project-phase = Project phase + .ss-project-milestone = Project milestone + .ss-revision-number = Revision number + .ss-revision-date = Revision date + .ss-issue-purpose = Issue purpose + .ss-custom-property-name = Custom property name + .ss-placeholder-type = Placeholder type + .ss-sheet-set-x = Sheet set + .ss-sheet-navigation-tree = Sheet navigation tree + .ss-sheetset = SheetSet .datalink-specify-insertion-point = DATALINK Specificare il punto di inserimento: .table-block-definition-not-found = TABLE: definizione del blocco non trovata. .table-edit-applied = TABLE: modifica applicata. diff --git a/locales/ja-JP/opencadstudio.ftl b/locales/ja-JP/opencadstudio.ftl index f0df48710..101252168 100644 --- a/locales/ja-JP/opencadstudio.ftl +++ b/locales/ja-JP/opencadstudio.ftl @@ -4328,6 +4328,102 @@ layout = .vplayer-f-layer-freeze-t-layer-thaw-enter-exit = VPLAYER F = フリーズ | T = フリーズ解除 | Enter = 終了 view = + .ss-create-sheet-set = Create Sheet Set + .ss-new-sheet = New Sheet + .ss-subset-properties = Subset Properties + .ss-rename-renumber-sheet = Rename & Renumber Sheet + .ss-import-layout-as-sheet = Import Layout as Sheet + .ss-sheet-set-manager = Sheet Set Manager + .ss-open = Open... + .ss-open-a-sheet-set-or-create-one-with-newsheetset = Open a sheet set or create one with NEWSHEETSET. + .ss-no-sheet-views = No sheet views. + .ss-no-locations = No locations. + .ss-double-click-opens-a-sheet-right-click-for-more-commands = Double-click opens a sheet. Right-click for more commands. + .ss-an-empty-sheet-set = An empty sheet set + .ss-existing-drawings = Existing drawings + .ss-create-a-folder-hierarchy-based-on-subsets = Create a folder hierarchy based on subsets + .ss-sheet-set-properties = Sheet Set Properties... + .ss-select-folders-containing-drawings-layouts-in-the-drawings-c = Select folders containing drawings. Layouts in the drawings can be added to the sheet set. + .ss-sheet-set = Sheet Set + .ss-sheet-set-data-file = Sheet set data file + .ss-sheets-to-import = Sheets to import + .ss-add-custom-property = Add Custom Property... + .ss-new-sheet-x = New Sheet... + .ss-new-subset = New Subset... + .ss-import-layout-as-sheet-x = Import Layout as Sheet... + .ss-rename-renumber = Rename & Renumber... + .ss-close-sheet-set = Close Sheet Set + .ss-properties = Properties... + .ss-sheet-list = Sheet List + .ss-sheet-views = Sheet Views + .ss-model-views = Model Views + .ss-views-by-sheet = Views by sheet + .ss-locations = Locations + .ss-create-a-sheet-set-using = Create a sheet set using + .ss-name-of-new-sheet-set = Name of new sheet set: + .ss-description-optional = Description (optional): + .ss-store-sheet-set-data-file-dst-here = Store sheet set data file (.dst) here: + .ss-choose-layouts = Choose Layouts + .ss-confirm = Confirm + .ss-default-value = Default value: + .ss-owner = Owner + .ss-custom-properties = Custom Properties + .ss-sheet-title = Sheet title + .ss-folder-path = Folder path + .ss-sheet-template = Sheet template + .ss-subset-name = Subset name + .ss-new-sheet-location = New sheet location + .ss-remove-subset = Remove Subset + .ss-remove-sheet = Remove Sheet + .ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set. + .ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets. + .ss-open-sheet-set = Open Sheet Set + .ss-sheet-set-dst = Sheet Set (*.dst) + .ss-browse-for-folder = Browse for Folder + .ss-select-layout-as-sheet-template = Select Layout as Sheet Template + .ss-drawing-template-dwt = Drawing Template (*.dwt) + .ss-drawing-dwg = Drawing (*.dwg) + .ss-the-name-cannot-be-empty = The name cannot be empty. + .ss-a-custom-property-with-this-name-already-exists = A custom property with this name already exists. + .ss-sheet-sets-organize-layouts-from-several-drawings-into-one-n = Sheet sets organize layouts from several drawings into one named set of sheets. + .ss-default-new-drawing = (default new drawing) + .ss-select-drawing = Select Drawing + .ss-the-sheet-set-name-cannot-be-empty = The sheet set name cannot be empty. + .ss-the-folder-for-the-sheet-set-data-file-does-not-exist = The folder for the sheet set data file does not exist. + .ss-the-drawing-has-no-layout-to-use-as-a-sheet-template = The drawing has no layout to use as a sheet template. + .ss-the-subset-name-cannot-be-empty = The subset name cannot be empty. + .ss-the-drawing-has-no-layout-to-import = The drawing has no layout to import. + .ss-the-layout-is-already-a-sheet-of-this-sheet-set = The layout is already a sheet of this sheet set. + .ss-the-sheet-title-cannot-be-empty = The sheet title cannot be empty. + .ss-the-sheet-folder-cannot-be-created = The sheet folder cannot be created. + .ss-sheet-set-properties-x = Sheet Set Properties + .ss-sheet-properties = Sheet Properties + .ss-sheet-drawing-not-found = Sheet drawing not found: __ocs_fmt_0__ + .ss-already-exists = __ocs_fmt_0__ already exists. + .ss-model-view = Model view + .ss-label-block-for-views = Label block for views + .ss-callout-blocks = Callout blocks + .ss-page-setup-overrides-file = Page setup overrides file + .ss-project-control = Project Control + .ss-sheet-creation = Sheet Creation + .ss-sheet-storage-location = Sheet storage location + .ss-sheet-creation-template = Sheet creation template + .ss-prompt-for-template = Prompt for template + .ss-subset = Subset + .ss-layout-name = Layout name + .ss-drawing-file = Drawing file + .ss-project-number = Project number + .ss-project-name = Project name + .ss-project-phase = Project phase + .ss-project-milestone = Project milestone + .ss-revision-number = Revision number + .ss-revision-date = Revision date + .ss-issue-purpose = Issue purpose + .ss-custom-property-name = Custom property name + .ss-placeholder-type = Placeholder type + .ss-sheet-set-x = Sheet set + .ss-sheet-navigation-tree = Sheet navigation tree + .ss-sheetset = SheetSet .datalink-specify-insertion-point = DATALINK 挿入点を指定: .table-block-definition-not-found = TABLE: ブロック定義が見つかりません。 .table-edit-applied = TABLE: 編集を適用しました。 diff --git a/locales/ko-KR/opencadstudio.ftl b/locales/ko-KR/opencadstudio.ftl index 6ad109cc7..02604f8ec 100644 --- a/locales/ko-KR/opencadstudio.ftl +++ b/locales/ko-KR/opencadstudio.ftl @@ -4339,6 +4339,102 @@ layout = .vplayer-f-layer-freeze-t-layer-thaw-enter-exit = VPLAYER F = 동결 | T = 해동 | Enter = 종료 view = + .ss-create-sheet-set = Create Sheet Set + .ss-new-sheet = New Sheet + .ss-subset-properties = Subset Properties + .ss-rename-renumber-sheet = Rename & Renumber Sheet + .ss-import-layout-as-sheet = Import Layout as Sheet + .ss-sheet-set-manager = Sheet Set Manager + .ss-open = Open... + .ss-open-a-sheet-set-or-create-one-with-newsheetset = Open a sheet set or create one with NEWSHEETSET. + .ss-no-sheet-views = No sheet views. + .ss-no-locations = No locations. + .ss-double-click-opens-a-sheet-right-click-for-more-commands = Double-click opens a sheet. Right-click for more commands. + .ss-an-empty-sheet-set = An empty sheet set + .ss-existing-drawings = Existing drawings + .ss-create-a-folder-hierarchy-based-on-subsets = Create a folder hierarchy based on subsets + .ss-sheet-set-properties = Sheet Set Properties... + .ss-select-folders-containing-drawings-layouts-in-the-drawings-c = Select folders containing drawings. Layouts in the drawings can be added to the sheet set. + .ss-sheet-set = Sheet Set + .ss-sheet-set-data-file = Sheet set data file + .ss-sheets-to-import = Sheets to import + .ss-add-custom-property = Add Custom Property... + .ss-new-sheet-x = New Sheet... + .ss-new-subset = New Subset... + .ss-import-layout-as-sheet-x = Import Layout as Sheet... + .ss-rename-renumber = Rename & Renumber... + .ss-close-sheet-set = Close Sheet Set + .ss-properties = Properties... + .ss-sheet-list = Sheet List + .ss-sheet-views = Sheet Views + .ss-model-views = Model Views + .ss-views-by-sheet = Views by sheet + .ss-locations = Locations + .ss-create-a-sheet-set-using = Create a sheet set using + .ss-name-of-new-sheet-set = Name of new sheet set: + .ss-description-optional = Description (optional): + .ss-store-sheet-set-data-file-dst-here = Store sheet set data file (.dst) here: + .ss-choose-layouts = Choose Layouts + .ss-confirm = Confirm + .ss-default-value = Default value: + .ss-owner = Owner + .ss-custom-properties = Custom Properties + .ss-sheet-title = Sheet title + .ss-folder-path = Folder path + .ss-sheet-template = Sheet template + .ss-subset-name = Subset name + .ss-new-sheet-location = New sheet location + .ss-remove-subset = Remove Subset + .ss-remove-sheet = Remove Sheet + .ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set. + .ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets. + .ss-open-sheet-set = Open Sheet Set + .ss-sheet-set-dst = Sheet Set (*.dst) + .ss-browse-for-folder = Browse for Folder + .ss-select-layout-as-sheet-template = Select Layout as Sheet Template + .ss-drawing-template-dwt = Drawing Template (*.dwt) + .ss-drawing-dwg = Drawing (*.dwg) + .ss-the-name-cannot-be-empty = The name cannot be empty. + .ss-a-custom-property-with-this-name-already-exists = A custom property with this name already exists. + .ss-sheet-sets-organize-layouts-from-several-drawings-into-one-n = Sheet sets organize layouts from several drawings into one named set of sheets. + .ss-default-new-drawing = (default new drawing) + .ss-select-drawing = Select Drawing + .ss-the-sheet-set-name-cannot-be-empty = The sheet set name cannot be empty. + .ss-the-folder-for-the-sheet-set-data-file-does-not-exist = The folder for the sheet set data file does not exist. + .ss-the-drawing-has-no-layout-to-use-as-a-sheet-template = The drawing has no layout to use as a sheet template. + .ss-the-subset-name-cannot-be-empty = The subset name cannot be empty. + .ss-the-drawing-has-no-layout-to-import = The drawing has no layout to import. + .ss-the-layout-is-already-a-sheet-of-this-sheet-set = The layout is already a sheet of this sheet set. + .ss-the-sheet-title-cannot-be-empty = The sheet title cannot be empty. + .ss-the-sheet-folder-cannot-be-created = The sheet folder cannot be created. + .ss-sheet-set-properties-x = Sheet Set Properties + .ss-sheet-properties = Sheet Properties + .ss-sheet-drawing-not-found = Sheet drawing not found: __ocs_fmt_0__ + .ss-already-exists = __ocs_fmt_0__ already exists. + .ss-model-view = Model view + .ss-label-block-for-views = Label block for views + .ss-callout-blocks = Callout blocks + .ss-page-setup-overrides-file = Page setup overrides file + .ss-project-control = Project Control + .ss-sheet-creation = Sheet Creation + .ss-sheet-storage-location = Sheet storage location + .ss-sheet-creation-template = Sheet creation template + .ss-prompt-for-template = Prompt for template + .ss-subset = Subset + .ss-layout-name = Layout name + .ss-drawing-file = Drawing file + .ss-project-number = Project number + .ss-project-name = Project name + .ss-project-phase = Project phase + .ss-project-milestone = Project milestone + .ss-revision-number = Revision number + .ss-revision-date = Revision date + .ss-issue-purpose = Issue purpose + .ss-custom-property-name = Custom property name + .ss-placeholder-type = Placeholder type + .ss-sheet-set-x = Sheet set + .ss-sheet-navigation-tree = Sheet navigation tree + .ss-sheetset = SheetSet .datalink-specify-insertion-point = DATALINK 삽입점 지정: .table-block-definition-not-found = TABLE: 블록 정의를 찾을 수 없습니다. .table-edit-applied = TABLE: 편집을 적용했습니다. diff --git a/locales/nl-NL/opencadstudio.ftl b/locales/nl-NL/opencadstudio.ftl index 2f5e39e39..232c1de7f 100644 --- a/locales/nl-NL/opencadstudio.ftl +++ b/locales/nl-NL/opencadstudio.ftl @@ -4338,6 +4338,102 @@ layout = .vplayer-f-layer-freeze-t-layer-thaw-enter-exit = VPLAYER F = Bevriezen | T = Ontdooien | Enter = Afsluiten view = + .ss-create-sheet-set = Create Sheet Set + .ss-new-sheet = New Sheet + .ss-subset-properties = Subset Properties + .ss-rename-renumber-sheet = Rename & Renumber Sheet + .ss-import-layout-as-sheet = Import Layout as Sheet + .ss-sheet-set-manager = Sheet Set Manager + .ss-open = Open... + .ss-open-a-sheet-set-or-create-one-with-newsheetset = Open a sheet set or create one with NEWSHEETSET. + .ss-no-sheet-views = No sheet views. + .ss-no-locations = No locations. + .ss-double-click-opens-a-sheet-right-click-for-more-commands = Double-click opens a sheet. Right-click for more commands. + .ss-an-empty-sheet-set = An empty sheet set + .ss-existing-drawings = Existing drawings + .ss-create-a-folder-hierarchy-based-on-subsets = Create a folder hierarchy based on subsets + .ss-sheet-set-properties = Sheet Set Properties... + .ss-select-folders-containing-drawings-layouts-in-the-drawings-c = Select folders containing drawings. Layouts in the drawings can be added to the sheet set. + .ss-sheet-set = Sheet Set + .ss-sheet-set-data-file = Sheet set data file + .ss-sheets-to-import = Sheets to import + .ss-add-custom-property = Add Custom Property... + .ss-new-sheet-x = New Sheet... + .ss-new-subset = New Subset... + .ss-import-layout-as-sheet-x = Import Layout as Sheet... + .ss-rename-renumber = Rename & Renumber... + .ss-close-sheet-set = Close Sheet Set + .ss-properties = Properties... + .ss-sheet-list = Sheet List + .ss-sheet-views = Sheet Views + .ss-model-views = Model Views + .ss-views-by-sheet = Views by sheet + .ss-locations = Locations + .ss-create-a-sheet-set-using = Create a sheet set using + .ss-name-of-new-sheet-set = Name of new sheet set: + .ss-description-optional = Description (optional): + .ss-store-sheet-set-data-file-dst-here = Store sheet set data file (.dst) here: + .ss-choose-layouts = Choose Layouts + .ss-confirm = Confirm + .ss-default-value = Default value: + .ss-owner = Owner + .ss-custom-properties = Custom Properties + .ss-sheet-title = Sheet title + .ss-folder-path = Folder path + .ss-sheet-template = Sheet template + .ss-subset-name = Subset name + .ss-new-sheet-location = New sheet location + .ss-remove-subset = Remove Subset + .ss-remove-sheet = Remove Sheet + .ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set. + .ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets. + .ss-open-sheet-set = Open Sheet Set + .ss-sheet-set-dst = Sheet Set (*.dst) + .ss-browse-for-folder = Browse for Folder + .ss-select-layout-as-sheet-template = Select Layout as Sheet Template + .ss-drawing-template-dwt = Drawing Template (*.dwt) + .ss-drawing-dwg = Drawing (*.dwg) + .ss-the-name-cannot-be-empty = The name cannot be empty. + .ss-a-custom-property-with-this-name-already-exists = A custom property with this name already exists. + .ss-sheet-sets-organize-layouts-from-several-drawings-into-one-n = Sheet sets organize layouts from several drawings into one named set of sheets. + .ss-default-new-drawing = (default new drawing) + .ss-select-drawing = Select Drawing + .ss-the-sheet-set-name-cannot-be-empty = The sheet set name cannot be empty. + .ss-the-folder-for-the-sheet-set-data-file-does-not-exist = The folder for the sheet set data file does not exist. + .ss-the-drawing-has-no-layout-to-use-as-a-sheet-template = The drawing has no layout to use as a sheet template. + .ss-the-subset-name-cannot-be-empty = The subset name cannot be empty. + .ss-the-drawing-has-no-layout-to-import = The drawing has no layout to import. + .ss-the-layout-is-already-a-sheet-of-this-sheet-set = The layout is already a sheet of this sheet set. + .ss-the-sheet-title-cannot-be-empty = The sheet title cannot be empty. + .ss-the-sheet-folder-cannot-be-created = The sheet folder cannot be created. + .ss-sheet-set-properties-x = Sheet Set Properties + .ss-sheet-properties = Sheet Properties + .ss-sheet-drawing-not-found = Sheet drawing not found: __ocs_fmt_0__ + .ss-already-exists = __ocs_fmt_0__ already exists. + .ss-model-view = Model view + .ss-label-block-for-views = Label block for views + .ss-callout-blocks = Callout blocks + .ss-page-setup-overrides-file = Page setup overrides file + .ss-project-control = Project Control + .ss-sheet-creation = Sheet Creation + .ss-sheet-storage-location = Sheet storage location + .ss-sheet-creation-template = Sheet creation template + .ss-prompt-for-template = Prompt for template + .ss-subset = Subset + .ss-layout-name = Layout name + .ss-drawing-file = Drawing file + .ss-project-number = Project number + .ss-project-name = Project name + .ss-project-phase = Project phase + .ss-project-milestone = Project milestone + .ss-revision-number = Revision number + .ss-revision-date = Revision date + .ss-issue-purpose = Issue purpose + .ss-custom-property-name = Custom property name + .ss-placeholder-type = Placeholder type + .ss-sheet-set-x = Sheet set + .ss-sheet-navigation-tree = Sheet navigation tree + .ss-sheetset = SheetSet .datalink-specify-insertion-point = DATALINK Geef invoegpunt op: .table-block-definition-not-found = TABLE: blokdefinitie niet gevonden. .table-edit-applied = TABLE: bewerking toegepast. diff --git a/locales/pl-PL/opencadstudio.ftl b/locales/pl-PL/opencadstudio.ftl index c31421220..bc0e67dd0 100644 --- a/locales/pl-PL/opencadstudio.ftl +++ b/locales/pl-PL/opencadstudio.ftl @@ -4339,6 +4339,102 @@ layout = .vplayer-f-layer-freeze-t-layer-thaw-enter-exit = VPLAYER F = Zamrożenie | T = Odwilż | Enter = Wyjście view = + .ss-create-sheet-set = Create Sheet Set + .ss-new-sheet = New Sheet + .ss-subset-properties = Subset Properties + .ss-rename-renumber-sheet = Rename & Renumber Sheet + .ss-import-layout-as-sheet = Import Layout as Sheet + .ss-sheet-set-manager = Sheet Set Manager + .ss-open = Open... + .ss-open-a-sheet-set-or-create-one-with-newsheetset = Open a sheet set or create one with NEWSHEETSET. + .ss-no-sheet-views = No sheet views. + .ss-no-locations = No locations. + .ss-double-click-opens-a-sheet-right-click-for-more-commands = Double-click opens a sheet. Right-click for more commands. + .ss-an-empty-sheet-set = An empty sheet set + .ss-existing-drawings = Existing drawings + .ss-create-a-folder-hierarchy-based-on-subsets = Create a folder hierarchy based on subsets + .ss-sheet-set-properties = Sheet Set Properties... + .ss-select-folders-containing-drawings-layouts-in-the-drawings-c = Select folders containing drawings. Layouts in the drawings can be added to the sheet set. + .ss-sheet-set = Sheet Set + .ss-sheet-set-data-file = Sheet set data file + .ss-sheets-to-import = Sheets to import + .ss-add-custom-property = Add Custom Property... + .ss-new-sheet-x = New Sheet... + .ss-new-subset = New Subset... + .ss-import-layout-as-sheet-x = Import Layout as Sheet... + .ss-rename-renumber = Rename & Renumber... + .ss-close-sheet-set = Close Sheet Set + .ss-properties = Properties... + .ss-sheet-list = Sheet List + .ss-sheet-views = Sheet Views + .ss-model-views = Model Views + .ss-views-by-sheet = Views by sheet + .ss-locations = Locations + .ss-create-a-sheet-set-using = Create a sheet set using + .ss-name-of-new-sheet-set = Name of new sheet set: + .ss-description-optional = Description (optional): + .ss-store-sheet-set-data-file-dst-here = Store sheet set data file (.dst) here: + .ss-choose-layouts = Choose Layouts + .ss-confirm = Confirm + .ss-default-value = Default value: + .ss-owner = Owner + .ss-custom-properties = Custom Properties + .ss-sheet-title = Sheet title + .ss-folder-path = Folder path + .ss-sheet-template = Sheet template + .ss-subset-name = Subset name + .ss-new-sheet-location = New sheet location + .ss-remove-subset = Remove Subset + .ss-remove-sheet = Remove Sheet + .ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set. + .ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets. + .ss-open-sheet-set = Open Sheet Set + .ss-sheet-set-dst = Sheet Set (*.dst) + .ss-browse-for-folder = Browse for Folder + .ss-select-layout-as-sheet-template = Select Layout as Sheet Template + .ss-drawing-template-dwt = Drawing Template (*.dwt) + .ss-drawing-dwg = Drawing (*.dwg) + .ss-the-name-cannot-be-empty = The name cannot be empty. + .ss-a-custom-property-with-this-name-already-exists = A custom property with this name already exists. + .ss-sheet-sets-organize-layouts-from-several-drawings-into-one-n = Sheet sets organize layouts from several drawings into one named set of sheets. + .ss-default-new-drawing = (default new drawing) + .ss-select-drawing = Select Drawing + .ss-the-sheet-set-name-cannot-be-empty = The sheet set name cannot be empty. + .ss-the-folder-for-the-sheet-set-data-file-does-not-exist = The folder for the sheet set data file does not exist. + .ss-the-drawing-has-no-layout-to-use-as-a-sheet-template = The drawing has no layout to use as a sheet template. + .ss-the-subset-name-cannot-be-empty = The subset name cannot be empty. + .ss-the-drawing-has-no-layout-to-import = The drawing has no layout to import. + .ss-the-layout-is-already-a-sheet-of-this-sheet-set = The layout is already a sheet of this sheet set. + .ss-the-sheet-title-cannot-be-empty = The sheet title cannot be empty. + .ss-the-sheet-folder-cannot-be-created = The sheet folder cannot be created. + .ss-sheet-set-properties-x = Sheet Set Properties + .ss-sheet-properties = Sheet Properties + .ss-sheet-drawing-not-found = Sheet drawing not found: __ocs_fmt_0__ + .ss-already-exists = __ocs_fmt_0__ already exists. + .ss-model-view = Model view + .ss-label-block-for-views = Label block for views + .ss-callout-blocks = Callout blocks + .ss-page-setup-overrides-file = Page setup overrides file + .ss-project-control = Project Control + .ss-sheet-creation = Sheet Creation + .ss-sheet-storage-location = Sheet storage location + .ss-sheet-creation-template = Sheet creation template + .ss-prompt-for-template = Prompt for template + .ss-subset = Subset + .ss-layout-name = Layout name + .ss-drawing-file = Drawing file + .ss-project-number = Project number + .ss-project-name = Project name + .ss-project-phase = Project phase + .ss-project-milestone = Project milestone + .ss-revision-number = Revision number + .ss-revision-date = Revision date + .ss-issue-purpose = Issue purpose + .ss-custom-property-name = Custom property name + .ss-placeholder-type = Placeholder type + .ss-sheet-set-x = Sheet set + .ss-sheet-navigation-tree = Sheet navigation tree + .ss-sheetset = SheetSet .datalink-specify-insertion-point = DATALINK Wskaż punkt wstawienia: .table-block-definition-not-found = TABLE: nie znaleziono definicji bloku. .table-edit-applied = TABLE: zastosowano edycję. diff --git a/locales/pt-BR/opencadstudio.ftl b/locales/pt-BR/opencadstudio.ftl index e96dea04d..c7c1934df 100644 --- a/locales/pt-BR/opencadstudio.ftl +++ b/locales/pt-BR/opencadstudio.ftl @@ -4340,6 +4340,102 @@ layout = .vplayer-f-layer-freeze-t-layer-thaw-enter-exit = VPLAYER F = Congelar | T = Descongelar | Enter = Sair view = + .ss-create-sheet-set = Create Sheet Set + .ss-new-sheet = New Sheet + .ss-subset-properties = Subset Properties + .ss-rename-renumber-sheet = Rename & Renumber Sheet + .ss-import-layout-as-sheet = Import Layout as Sheet + .ss-sheet-set-manager = Sheet Set Manager + .ss-open = Open... + .ss-open-a-sheet-set-or-create-one-with-newsheetset = Open a sheet set or create one with NEWSHEETSET. + .ss-no-sheet-views = No sheet views. + .ss-no-locations = No locations. + .ss-double-click-opens-a-sheet-right-click-for-more-commands = Double-click opens a sheet. Right-click for more commands. + .ss-an-empty-sheet-set = An empty sheet set + .ss-existing-drawings = Existing drawings + .ss-create-a-folder-hierarchy-based-on-subsets = Create a folder hierarchy based on subsets + .ss-sheet-set-properties = Sheet Set Properties... + .ss-select-folders-containing-drawings-layouts-in-the-drawings-c = Select folders containing drawings. Layouts in the drawings can be added to the sheet set. + .ss-sheet-set = Sheet Set + .ss-sheet-set-data-file = Sheet set data file + .ss-sheets-to-import = Sheets to import + .ss-add-custom-property = Add Custom Property... + .ss-new-sheet-x = New Sheet... + .ss-new-subset = New Subset... + .ss-import-layout-as-sheet-x = Import Layout as Sheet... + .ss-rename-renumber = Rename & Renumber... + .ss-close-sheet-set = Close Sheet Set + .ss-properties = Properties... + .ss-sheet-list = Sheet List + .ss-sheet-views = Sheet Views + .ss-model-views = Model Views + .ss-views-by-sheet = Views by sheet + .ss-locations = Locations + .ss-create-a-sheet-set-using = Create a sheet set using + .ss-name-of-new-sheet-set = Name of new sheet set: + .ss-description-optional = Description (optional): + .ss-store-sheet-set-data-file-dst-here = Store sheet set data file (.dst) here: + .ss-choose-layouts = Choose Layouts + .ss-confirm = Confirm + .ss-default-value = Default value: + .ss-owner = Owner + .ss-custom-properties = Custom Properties + .ss-sheet-title = Sheet title + .ss-folder-path = Folder path + .ss-sheet-template = Sheet template + .ss-subset-name = Subset name + .ss-new-sheet-location = New sheet location + .ss-remove-subset = Remove Subset + .ss-remove-sheet = Remove Sheet + .ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set. + .ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets. + .ss-open-sheet-set = Open Sheet Set + .ss-sheet-set-dst = Sheet Set (*.dst) + .ss-browse-for-folder = Browse for Folder + .ss-select-layout-as-sheet-template = Select Layout as Sheet Template + .ss-drawing-template-dwt = Drawing Template (*.dwt) + .ss-drawing-dwg = Drawing (*.dwg) + .ss-the-name-cannot-be-empty = The name cannot be empty. + .ss-a-custom-property-with-this-name-already-exists = A custom property with this name already exists. + .ss-sheet-sets-organize-layouts-from-several-drawings-into-one-n = Sheet sets organize layouts from several drawings into one named set of sheets. + .ss-default-new-drawing = (default new drawing) + .ss-select-drawing = Select Drawing + .ss-the-sheet-set-name-cannot-be-empty = The sheet set name cannot be empty. + .ss-the-folder-for-the-sheet-set-data-file-does-not-exist = The folder for the sheet set data file does not exist. + .ss-the-drawing-has-no-layout-to-use-as-a-sheet-template = The drawing has no layout to use as a sheet template. + .ss-the-subset-name-cannot-be-empty = The subset name cannot be empty. + .ss-the-drawing-has-no-layout-to-import = The drawing has no layout to import. + .ss-the-layout-is-already-a-sheet-of-this-sheet-set = The layout is already a sheet of this sheet set. + .ss-the-sheet-title-cannot-be-empty = The sheet title cannot be empty. + .ss-the-sheet-folder-cannot-be-created = The sheet folder cannot be created. + .ss-sheet-set-properties-x = Sheet Set Properties + .ss-sheet-properties = Sheet Properties + .ss-sheet-drawing-not-found = Sheet drawing not found: __ocs_fmt_0__ + .ss-already-exists = __ocs_fmt_0__ already exists. + .ss-model-view = Model view + .ss-label-block-for-views = Label block for views + .ss-callout-blocks = Callout blocks + .ss-page-setup-overrides-file = Page setup overrides file + .ss-project-control = Project Control + .ss-sheet-creation = Sheet Creation + .ss-sheet-storage-location = Sheet storage location + .ss-sheet-creation-template = Sheet creation template + .ss-prompt-for-template = Prompt for template + .ss-subset = Subset + .ss-layout-name = Layout name + .ss-drawing-file = Drawing file + .ss-project-number = Project number + .ss-project-name = Project name + .ss-project-phase = Project phase + .ss-project-milestone = Project milestone + .ss-revision-number = Revision number + .ss-revision-date = Revision date + .ss-issue-purpose = Issue purpose + .ss-custom-property-name = Custom property name + .ss-placeholder-type = Placeholder type + .ss-sheet-set-x = Sheet set + .ss-sheet-navigation-tree = Sheet navigation tree + .ss-sheetset = SheetSet .datalink-specify-insertion-point = DATALINK Especifique o ponto de inserção: .table-block-definition-not-found = TABLE: definição de bloco não encontrada. .table-edit-applied = TABLE: edição aplicada. diff --git a/locales/ru-RU/opencadstudio.ftl b/locales/ru-RU/opencadstudio.ftl index e3eb50fa6..63a92d307 100644 --- a/locales/ru-RU/opencadstudio.ftl +++ b/locales/ru-RU/opencadstudio.ftl @@ -4341,6 +4341,102 @@ layout = .vplayer-f-layer-freeze-t-layer-thaw-enter-exit = VPLAYER F <слой> = заморозить | T <слой> = разморозить | Enter = выход view = + .ss-create-sheet-set = Create Sheet Set + .ss-new-sheet = New Sheet + .ss-subset-properties = Subset Properties + .ss-rename-renumber-sheet = Rename & Renumber Sheet + .ss-import-layout-as-sheet = Import Layout as Sheet + .ss-sheet-set-manager = Sheet Set Manager + .ss-open = Open... + .ss-open-a-sheet-set-or-create-one-with-newsheetset = Open a sheet set or create one with NEWSHEETSET. + .ss-no-sheet-views = No sheet views. + .ss-no-locations = No locations. + .ss-double-click-opens-a-sheet-right-click-for-more-commands = Double-click opens a sheet. Right-click for more commands. + .ss-an-empty-sheet-set = An empty sheet set + .ss-existing-drawings = Existing drawings + .ss-create-a-folder-hierarchy-based-on-subsets = Create a folder hierarchy based on subsets + .ss-sheet-set-properties = Sheet Set Properties... + .ss-select-folders-containing-drawings-layouts-in-the-drawings-c = Select folders containing drawings. Layouts in the drawings can be added to the sheet set. + .ss-sheet-set = Sheet Set + .ss-sheet-set-data-file = Sheet set data file + .ss-sheets-to-import = Sheets to import + .ss-add-custom-property = Add Custom Property... + .ss-new-sheet-x = New Sheet... + .ss-new-subset = New Subset... + .ss-import-layout-as-sheet-x = Import Layout as Sheet... + .ss-rename-renumber = Rename & Renumber... + .ss-close-sheet-set = Close Sheet Set + .ss-properties = Properties... + .ss-sheet-list = Sheet List + .ss-sheet-views = Sheet Views + .ss-model-views = Model Views + .ss-views-by-sheet = Views by sheet + .ss-locations = Locations + .ss-create-a-sheet-set-using = Create a sheet set using + .ss-name-of-new-sheet-set = Name of new sheet set: + .ss-description-optional = Description (optional): + .ss-store-sheet-set-data-file-dst-here = Store sheet set data file (.dst) here: + .ss-choose-layouts = Choose Layouts + .ss-confirm = Confirm + .ss-default-value = Default value: + .ss-owner = Owner + .ss-custom-properties = Custom Properties + .ss-sheet-title = Sheet title + .ss-folder-path = Folder path + .ss-sheet-template = Sheet template + .ss-subset-name = Subset name + .ss-new-sheet-location = New sheet location + .ss-remove-subset = Remove Subset + .ss-remove-sheet = Remove Sheet + .ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set. + .ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets. + .ss-open-sheet-set = Open Sheet Set + .ss-sheet-set-dst = Sheet Set (*.dst) + .ss-browse-for-folder = Browse for Folder + .ss-select-layout-as-sheet-template = Select Layout as Sheet Template + .ss-drawing-template-dwt = Drawing Template (*.dwt) + .ss-drawing-dwg = Drawing (*.dwg) + .ss-the-name-cannot-be-empty = The name cannot be empty. + .ss-a-custom-property-with-this-name-already-exists = A custom property with this name already exists. + .ss-sheet-sets-organize-layouts-from-several-drawings-into-one-n = Sheet sets organize layouts from several drawings into one named set of sheets. + .ss-default-new-drawing = (default new drawing) + .ss-select-drawing = Select Drawing + .ss-the-sheet-set-name-cannot-be-empty = The sheet set name cannot be empty. + .ss-the-folder-for-the-sheet-set-data-file-does-not-exist = The folder for the sheet set data file does not exist. + .ss-the-drawing-has-no-layout-to-use-as-a-sheet-template = The drawing has no layout to use as a sheet template. + .ss-the-subset-name-cannot-be-empty = The subset name cannot be empty. + .ss-the-drawing-has-no-layout-to-import = The drawing has no layout to import. + .ss-the-layout-is-already-a-sheet-of-this-sheet-set = The layout is already a sheet of this sheet set. + .ss-the-sheet-title-cannot-be-empty = The sheet title cannot be empty. + .ss-the-sheet-folder-cannot-be-created = The sheet folder cannot be created. + .ss-sheet-set-properties-x = Sheet Set Properties + .ss-sheet-properties = Sheet Properties + .ss-sheet-drawing-not-found = Sheet drawing not found: __ocs_fmt_0__ + .ss-already-exists = __ocs_fmt_0__ already exists. + .ss-model-view = Model view + .ss-label-block-for-views = Label block for views + .ss-callout-blocks = Callout blocks + .ss-page-setup-overrides-file = Page setup overrides file + .ss-project-control = Project Control + .ss-sheet-creation = Sheet Creation + .ss-sheet-storage-location = Sheet storage location + .ss-sheet-creation-template = Sheet creation template + .ss-prompt-for-template = Prompt for template + .ss-subset = Subset + .ss-layout-name = Layout name + .ss-drawing-file = Drawing file + .ss-project-number = Project number + .ss-project-name = Project name + .ss-project-phase = Project phase + .ss-project-milestone = Project milestone + .ss-revision-number = Revision number + .ss-revision-date = Revision date + .ss-issue-purpose = Issue purpose + .ss-custom-property-name = Custom property name + .ss-placeholder-type = Placeholder type + .ss-sheet-set-x = Sheet set + .ss-sheet-navigation-tree = Sheet navigation tree + .ss-sheetset = SheetSet .datalink-specify-insertion-point = DATALINK Укажите точку вставки: .table-block-definition-not-found = TABLE: определение блока не найдено. .table-edit-applied = TABLE: изменение применено. diff --git a/locales/tr-TR/opencadstudio.ftl b/locales/tr-TR/opencadstudio.ftl index 3b01d7c2c..662134e13 100644 --- a/locales/tr-TR/opencadstudio.ftl +++ b/locales/tr-TR/opencadstudio.ftl @@ -4300,6 +4300,102 @@ layout = .vplayer-f-layer-freeze-t-layer-thaw-enter-exit = VPLAYER F = Dondur | T = Çöz | Enter = Çık view = + .ss-create-sheet-set = Sayfa Kümesi Oluştur + .ss-new-sheet = Yeni Sayfa + .ss-subset-properties = Alt Küme Özellikleri + .ss-rename-renumber-sheet = Sayfayı Yeniden Adlandır ve Numaralandır + .ss-import-layout-as-sheet = Düzeni Sayfa Olarak İçe Aktar + .ss-sheet-set-manager = Sayfa Kümesi Yöneticisi + .ss-open = Aç... + .ss-open-a-sheet-set-or-create-one-with-newsheetset = Bir sayfa kümesi açın veya NEWSHEETSET ile yeni bir küme oluşturun. + .ss-no-sheet-views = Sayfa görünümü yok. + .ss-no-locations = Konum yok. + .ss-double-click-opens-a-sheet-right-click-for-more-commands = Çift tık sayfayı açar. Diğer komutlar için sağ tıklayın. + .ss-an-empty-sheet-set = Boş sayfa kümesi + .ss-existing-drawings = Var olan çizimler + .ss-create-a-folder-hierarchy-based-on-subsets = Alt kümelere göre klasör hiyerarşisi oluştur + .ss-sheet-set-properties = Sayfa Kümesi Özellikleri... + .ss-select-folders-containing-drawings-layouts-in-the-drawings-c = Çizim içeren klasörleri seçin. Çizimlerdeki düzenler sayfa kümesine eklenebilir. + .ss-sheet-set = Sayfa Kümesi + .ss-sheet-set-data-file = Sayfa kümesi veri dosyası + .ss-sheets-to-import = İçe aktarılacak sayfalar + .ss-add-custom-property = Özel Özellik Ekle... + .ss-new-sheet-x = Yeni Sayfa... + .ss-new-subset = Yeni Alt Küme... + .ss-import-layout-as-sheet-x = Düzeni Sayfa Olarak İçe Aktar... + .ss-rename-renumber = Yeniden Adlandır ve Numaralandır... + .ss-close-sheet-set = Sayfa Kümesini Kapat + .ss-properties = Özellikler... + .ss-sheet-list = Sayfa Listesi + .ss-sheet-views = Sayfa Görünümleri + .ss-model-views = Model Görünümleri + .ss-views-by-sheet = Sayfaya göre görünümler + .ss-locations = Konumlar + .ss-create-a-sheet-set-using = Sayfa kümesini şununla oluştur + .ss-name-of-new-sheet-set = Yeni sayfa kümesinin adı: + .ss-description-optional = Açıklama (isteğe bağlı): + .ss-store-sheet-set-data-file-dst-here = Sayfa kümesi veri dosyasını (.dst) buraya kaydet: + .ss-choose-layouts = Düzenleri Seç + .ss-confirm = Onayla + .ss-default-value = Varsayılan değer: + .ss-owner = Sahip + .ss-custom-properties = Özel Özellikler + .ss-sheet-title = Sayfa başlığı + .ss-folder-path = Klasör yolu + .ss-sheet-template = Sayfa şablonu + .ss-subset-name = Alt küme adı + .ss-new-sheet-location = Yeni sayfa konumu + .ss-remove-subset = Alt Kümeyi Kaldır + .ss-remove-sheet = Sayfayı Kaldır + .ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Çizim içeren bir veya daha fazla klasör belirtmenizi sağlar. Bu çizimlerdeki düzenler sayfa kümesine otomatik olarak aktarılabilir. + .ss-creates-a-sheet-set-with-no-subsets-or-sheets = Alt kümesi ve sayfası olmayan bir sayfa kümesi oluşturur. + .ss-open-sheet-set = Sayfa Kümesini Aç + .ss-sheet-set-dst = Sayfa Kümesi (*.dst) + .ss-browse-for-folder = Klasöre Gözat + .ss-select-layout-as-sheet-template = Sayfa Şablonu Olarak Düzen Seç + .ss-drawing-template-dwt = Çizim Şablonu (*.dwt) + .ss-drawing-dwg = Çizim (*.dwg) + .ss-the-name-cannot-be-empty = Ad boş olamaz. + .ss-a-custom-property-with-this-name-already-exists = Bu adda bir özel özellik zaten var. + .ss-sheet-sets-organize-layouts-from-several-drawings-into-one-n = Sayfa kümeleri birden çok çizimdeki düzenleri adlandırılmış tek bir sayfa grubunda toplar. + .ss-default-new-drawing = (varsayılan yeni çizim) + .ss-select-drawing = Çizim Seç + .ss-the-sheet-set-name-cannot-be-empty = Sayfa kümesi adı boş olamaz. + .ss-the-folder-for-the-sheet-set-data-file-does-not-exist = Sayfa kümesi veri dosyasının klasörü yok. + .ss-the-drawing-has-no-layout-to-use-as-a-sheet-template = Çizimde sayfa şablonu olarak kullanılabilecek düzen yok. + .ss-the-subset-name-cannot-be-empty = Alt küme adı boş olamaz. + .ss-the-drawing-has-no-layout-to-import = Çizimde içe aktarılacak düzen yok. + .ss-the-layout-is-already-a-sheet-of-this-sheet-set = Bu düzen zaten bu sayfa kümesinin bir sayfası. + .ss-the-sheet-title-cannot-be-empty = Sayfa başlığı boş olamaz. + .ss-the-sheet-folder-cannot-be-created = Sayfa klasörü oluşturulamıyor. + .ss-sheet-set-properties-x = Sayfa Kümesi Özellikleri + .ss-sheet-properties = Sayfa Özellikleri + .ss-sheet-drawing-not-found = Sayfa çizimi bulunamadı: __ocs_fmt_0__ + .ss-already-exists = __ocs_fmt_0__ zaten var. + .ss-model-view = Model görünümü + .ss-label-block-for-views = Görünümler için etiket bloğu + .ss-callout-blocks = Belirtme blokları + .ss-page-setup-overrides-file = Sayfa düzeni geçersiz kılma dosyası + .ss-project-control = Proje Denetimi + .ss-sheet-creation = Sayfa Oluşturma + .ss-sheet-storage-location = Sayfa kayıt konumu + .ss-sheet-creation-template = Sayfa oluşturma şablonu + .ss-prompt-for-template = Şablon için sor + .ss-subset = Alt Küme + .ss-layout-name = Düzen adı + .ss-drawing-file = Çizim dosyası + .ss-project-number = Proje numarası + .ss-project-name = Proje adı + .ss-project-phase = Proje evresi + .ss-project-milestone = Proje aşaması + .ss-revision-number = Revizyon numarası + .ss-revision-date = Revizyon tarihi + .ss-issue-purpose = Yayın amacı + .ss-custom-property-name = Özel özellik adı + .ss-placeholder-type = Yer tutucu türü + .ss-sheet-set-x = Sayfa kümesi + .ss-sheet-navigation-tree = Sayfa gezinme ağacı + .ss-sheetset = Sayfa Kümesi .message = __ocs_fmt_0__ .code-page = Kod sayfası: __ocs_fmt_0__ .created-julian-6 = Oluşturulma (Jülyen): __ocs_fmt_0__ diff --git a/locales/zh-CN/opencadstudio.ftl b/locales/zh-CN/opencadstudio.ftl index 290f64be0..2c74a6ab2 100644 --- a/locales/zh-CN/opencadstudio.ftl +++ b/locales/zh-CN/opencadstudio.ftl @@ -4323,6 +4323,102 @@ layout = .vplayer-f-layer-freeze-t-layer-thaw-enter-exit = VPLAYER F <图层> = 冻结 | T <图层> = 解冻 | Enter = 退出 view = + .ss-create-sheet-set = Create Sheet Set + .ss-new-sheet = New Sheet + .ss-subset-properties = Subset Properties + .ss-rename-renumber-sheet = Rename & Renumber Sheet + .ss-import-layout-as-sheet = Import Layout as Sheet + .ss-sheet-set-manager = Sheet Set Manager + .ss-open = Open... + .ss-open-a-sheet-set-or-create-one-with-newsheetset = Open a sheet set or create one with NEWSHEETSET. + .ss-no-sheet-views = No sheet views. + .ss-no-locations = No locations. + .ss-double-click-opens-a-sheet-right-click-for-more-commands = Double-click opens a sheet. Right-click for more commands. + .ss-an-empty-sheet-set = An empty sheet set + .ss-existing-drawings = Existing drawings + .ss-create-a-folder-hierarchy-based-on-subsets = Create a folder hierarchy based on subsets + .ss-sheet-set-properties = Sheet Set Properties... + .ss-select-folders-containing-drawings-layouts-in-the-drawings-c = Select folders containing drawings. Layouts in the drawings can be added to the sheet set. + .ss-sheet-set = Sheet Set + .ss-sheet-set-data-file = Sheet set data file + .ss-sheets-to-import = Sheets to import + .ss-add-custom-property = Add Custom Property... + .ss-new-sheet-x = New Sheet... + .ss-new-subset = New Subset... + .ss-import-layout-as-sheet-x = Import Layout as Sheet... + .ss-rename-renumber = Rename & Renumber... + .ss-close-sheet-set = Close Sheet Set + .ss-properties = Properties... + .ss-sheet-list = Sheet List + .ss-sheet-views = Sheet Views + .ss-model-views = Model Views + .ss-views-by-sheet = Views by sheet + .ss-locations = Locations + .ss-create-a-sheet-set-using = Create a sheet set using + .ss-name-of-new-sheet-set = Name of new sheet set: + .ss-description-optional = Description (optional): + .ss-store-sheet-set-data-file-dst-here = Store sheet set data file (.dst) here: + .ss-choose-layouts = Choose Layouts + .ss-confirm = Confirm + .ss-default-value = Default value: + .ss-owner = Owner + .ss-custom-properties = Custom Properties + .ss-sheet-title = Sheet title + .ss-folder-path = Folder path + .ss-sheet-template = Sheet template + .ss-subset-name = Subset name + .ss-new-sheet-location = New sheet location + .ss-remove-subset = Remove Subset + .ss-remove-sheet = Remove Sheet + .ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set. + .ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets. + .ss-open-sheet-set = Open Sheet Set + .ss-sheet-set-dst = Sheet Set (*.dst) + .ss-browse-for-folder = Browse for Folder + .ss-select-layout-as-sheet-template = Select Layout as Sheet Template + .ss-drawing-template-dwt = Drawing Template (*.dwt) + .ss-drawing-dwg = Drawing (*.dwg) + .ss-the-name-cannot-be-empty = The name cannot be empty. + .ss-a-custom-property-with-this-name-already-exists = A custom property with this name already exists. + .ss-sheet-sets-organize-layouts-from-several-drawings-into-one-n = Sheet sets organize layouts from several drawings into one named set of sheets. + .ss-default-new-drawing = (default new drawing) + .ss-select-drawing = Select Drawing + .ss-the-sheet-set-name-cannot-be-empty = The sheet set name cannot be empty. + .ss-the-folder-for-the-sheet-set-data-file-does-not-exist = The folder for the sheet set data file does not exist. + .ss-the-drawing-has-no-layout-to-use-as-a-sheet-template = The drawing has no layout to use as a sheet template. + .ss-the-subset-name-cannot-be-empty = The subset name cannot be empty. + .ss-the-drawing-has-no-layout-to-import = The drawing has no layout to import. + .ss-the-layout-is-already-a-sheet-of-this-sheet-set = The layout is already a sheet of this sheet set. + .ss-the-sheet-title-cannot-be-empty = The sheet title cannot be empty. + .ss-the-sheet-folder-cannot-be-created = The sheet folder cannot be created. + .ss-sheet-set-properties-x = Sheet Set Properties + .ss-sheet-properties = Sheet Properties + .ss-sheet-drawing-not-found = Sheet drawing not found: __ocs_fmt_0__ + .ss-already-exists = __ocs_fmt_0__ already exists. + .ss-model-view = Model view + .ss-label-block-for-views = Label block for views + .ss-callout-blocks = Callout blocks + .ss-page-setup-overrides-file = Page setup overrides file + .ss-project-control = Project Control + .ss-sheet-creation = Sheet Creation + .ss-sheet-storage-location = Sheet storage location + .ss-sheet-creation-template = Sheet creation template + .ss-prompt-for-template = Prompt for template + .ss-subset = Subset + .ss-layout-name = Layout name + .ss-drawing-file = Drawing file + .ss-project-number = Project number + .ss-project-name = Project name + .ss-project-phase = Project phase + .ss-project-milestone = Project milestone + .ss-revision-number = Revision number + .ss-revision-date = Revision date + .ss-issue-purpose = Issue purpose + .ss-custom-property-name = Custom property name + .ss-placeholder-type = Placeholder type + .ss-sheet-set-x = Sheet set + .ss-sheet-navigation-tree = Sheet navigation tree + .ss-sheetset = SheetSet .datalink-specify-insertion-point = DATALINK 指定插入点: .table-block-definition-not-found = TABLE:未找到块定义。 .table-edit-applied = TABLE:已应用编辑。 diff --git a/locales/zh-TW/opencadstudio.ftl b/locales/zh-TW/opencadstudio.ftl index c38cc4a04..db069f401 100644 --- a/locales/zh-TW/opencadstudio.ftl +++ b/locales/zh-TW/opencadstudio.ftl @@ -4335,6 +4335,102 @@ layout = .vplayer-f-layer-freeze-t-layer-thaw-enter-exit = VPLAYER F <圖層> = 凍結 | T <圖層> = 解凍 | Enter = 退出 view = + .ss-create-sheet-set = Create Sheet Set + .ss-new-sheet = New Sheet + .ss-subset-properties = Subset Properties + .ss-rename-renumber-sheet = Rename & Renumber Sheet + .ss-import-layout-as-sheet = Import Layout as Sheet + .ss-sheet-set-manager = Sheet Set Manager + .ss-open = Open... + .ss-open-a-sheet-set-or-create-one-with-newsheetset = Open a sheet set or create one with NEWSHEETSET. + .ss-no-sheet-views = No sheet views. + .ss-no-locations = No locations. + .ss-double-click-opens-a-sheet-right-click-for-more-commands = Double-click opens a sheet. Right-click for more commands. + .ss-an-empty-sheet-set = An empty sheet set + .ss-existing-drawings = Existing drawings + .ss-create-a-folder-hierarchy-based-on-subsets = Create a folder hierarchy based on subsets + .ss-sheet-set-properties = Sheet Set Properties... + .ss-select-folders-containing-drawings-layouts-in-the-drawings-c = Select folders containing drawings. Layouts in the drawings can be added to the sheet set. + .ss-sheet-set = Sheet Set + .ss-sheet-set-data-file = Sheet set data file + .ss-sheets-to-import = Sheets to import + .ss-add-custom-property = Add Custom Property... + .ss-new-sheet-x = New Sheet... + .ss-new-subset = New Subset... + .ss-import-layout-as-sheet-x = Import Layout as Sheet... + .ss-rename-renumber = Rename & Renumber... + .ss-close-sheet-set = Close Sheet Set + .ss-properties = Properties... + .ss-sheet-list = Sheet List + .ss-sheet-views = Sheet Views + .ss-model-views = Model Views + .ss-views-by-sheet = Views by sheet + .ss-locations = Locations + .ss-create-a-sheet-set-using = Create a sheet set using + .ss-name-of-new-sheet-set = Name of new sheet set: + .ss-description-optional = Description (optional): + .ss-store-sheet-set-data-file-dst-here = Store sheet set data file (.dst) here: + .ss-choose-layouts = Choose Layouts + .ss-confirm = Confirm + .ss-default-value = Default value: + .ss-owner = Owner + .ss-custom-properties = Custom Properties + .ss-sheet-title = Sheet title + .ss-folder-path = Folder path + .ss-sheet-template = Sheet template + .ss-subset-name = Subset name + .ss-new-sheet-location = New sheet location + .ss-remove-subset = Remove Subset + .ss-remove-sheet = Remove Sheet + .ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set. + .ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets. + .ss-open-sheet-set = Open Sheet Set + .ss-sheet-set-dst = Sheet Set (*.dst) + .ss-browse-for-folder = Browse for Folder + .ss-select-layout-as-sheet-template = Select Layout as Sheet Template + .ss-drawing-template-dwt = Drawing Template (*.dwt) + .ss-drawing-dwg = Drawing (*.dwg) + .ss-the-name-cannot-be-empty = The name cannot be empty. + .ss-a-custom-property-with-this-name-already-exists = A custom property with this name already exists. + .ss-sheet-sets-organize-layouts-from-several-drawings-into-one-n = Sheet sets organize layouts from several drawings into one named set of sheets. + .ss-default-new-drawing = (default new drawing) + .ss-select-drawing = Select Drawing + .ss-the-sheet-set-name-cannot-be-empty = The sheet set name cannot be empty. + .ss-the-folder-for-the-sheet-set-data-file-does-not-exist = The folder for the sheet set data file does not exist. + .ss-the-drawing-has-no-layout-to-use-as-a-sheet-template = The drawing has no layout to use as a sheet template. + .ss-the-subset-name-cannot-be-empty = The subset name cannot be empty. + .ss-the-drawing-has-no-layout-to-import = The drawing has no layout to import. + .ss-the-layout-is-already-a-sheet-of-this-sheet-set = The layout is already a sheet of this sheet set. + .ss-the-sheet-title-cannot-be-empty = The sheet title cannot be empty. + .ss-the-sheet-folder-cannot-be-created = The sheet folder cannot be created. + .ss-sheet-set-properties-x = Sheet Set Properties + .ss-sheet-properties = Sheet Properties + .ss-sheet-drawing-not-found = Sheet drawing not found: __ocs_fmt_0__ + .ss-already-exists = __ocs_fmt_0__ already exists. + .ss-model-view = Model view + .ss-label-block-for-views = Label block for views + .ss-callout-blocks = Callout blocks + .ss-page-setup-overrides-file = Page setup overrides file + .ss-project-control = Project Control + .ss-sheet-creation = Sheet Creation + .ss-sheet-storage-location = Sheet storage location + .ss-sheet-creation-template = Sheet creation template + .ss-prompt-for-template = Prompt for template + .ss-subset = Subset + .ss-layout-name = Layout name + .ss-drawing-file = Drawing file + .ss-project-number = Project number + .ss-project-name = Project name + .ss-project-phase = Project phase + .ss-project-milestone = Project milestone + .ss-revision-number = Revision number + .ss-revision-date = Revision date + .ss-issue-purpose = Issue purpose + .ss-custom-property-name = Custom property name + .ss-placeholder-type = Placeholder type + .ss-sheet-set-x = Sheet set + .ss-sheet-navigation-tree = Sheet navigation tree + .ss-sheetset = SheetSet .datalink-specify-insertion-point = DATALINK 指定插入點: .table-block-definition-not-found = TABLE:找不到圖塊定義。 .table-edit-applied = TABLE:已套用編輯。 diff --git a/src/app/commands/display.rs b/src/app/commands/display.rs index b979fec69..41fb964c3 100644 --- a/src/app/commands/display.rs +++ b/src/app/commands/display.rs @@ -587,12 +587,6 @@ impl OpenCADStudio { .push_info(crate::t!("TOOLPALETTES: Tool Palettes not yet implemented.").as_ref()); } - // ── SHEETSET — not yet implemented ─────────────────────────────────── - "SHEETSET" => { - self.command_line - .push_info(crate::t!("SHEETSET: Sheet Set Manager not yet implemented.").as_ref()); - } - // ── XDATA — read/write extended entity data ────────────────────────── // XDATA LIST — show all xdata records on selected entities // XDATA SET — append a string xdata value for diff --git a/src/app/commands/field.rs b/src/app/commands/field.rs index 5c084fc78..aa14b0516 100644 --- a/src/app/commands/field.rs +++ b/src/app/commands/field.rs @@ -46,6 +46,13 @@ impl OpenCADStudio { .iter() .map(|f| self.field_value(&format!("\\AcVar Date \\f \"{f}\""), &[])) .collect(); + if let Some(db) = self.sheet_set.db() { + let custom = codec::sheet_set::custom_properties(db.sheet_set()); + let names = |flag: i32| custom.iter().filter(|(_, _, f)| f & flag != 0).map(|(n, _, _)| n.clone()).collect(); + state.ss_sheet_custom = names(codec::sheet_set::CUSTOM_SHEET_PROP); + state.ss_set_custom = names(codec::sheet_set::CUSTOM_SHEET_SET_PROP); + state.ss_set_name = db.name().to_string(); + } self.field_dialog = Some(state); self.fill_named_objects(); self.refresh_field_preview(); @@ -113,8 +120,16 @@ impl OpenCADStudio { } FieldDialogMsg::Name(n) => { state.name = n; - state.text_case = 0; + // Sheet set fields start in Title case. + state.text_case = if crate::ui::window::field_dialog::SHEET_SET_FIELDS.contains(&n) { 4 } else { 0 }; + state.ss_custom.clear(); } + FieldDialogMsg::SsCustom(name) => state.ss_custom = name, + FieldDialogMsg::SsPlaceholder(k) => { + state.ss_placeholder = k; + state.ss_custom.clear(); + } + FieldDialogMsg::SsScaleFormat(k) => state.ss_scale_format = k, FieldDialogMsg::DateFormat(f) => state.date_format = f, FieldDialogMsg::DateExample(k) => { if let Some(f) = DATE_FORMATS.get(k) { diff --git a/src/app/commands/mod.rs b/src/app/commands/mod.rs index 7b9f22f2b..325fa24ef 100644 --- a/src/app/commands/mod.rs +++ b/src/app/commands/mod.rs @@ -21,6 +21,7 @@ mod pc_colormap; mod pc_extract; mod pdf_underlay; mod pdf_dialogs; +pub(crate) mod sheet_set; mod xclip; mod blockvars; mod plotvars; @@ -293,6 +294,9 @@ impl OpenCADStudio { if let Some(t) = self.dispatch_attdef(cmd, i) { return Some(t); } + if let Some(t) = self.dispatch_sheet_set(cmd, i) { + return Some(t); + } if let Some(t) = self.dispatch_field(cmd, i) { return Some(t); } @@ -854,6 +858,15 @@ inventory::submit!(crate::command::CommandRegistration { "CREATESKETCH", "FINISHSKETCH", "SHEETSET", + "SHEETSETHIDE", + "NEWSHEETSET", + "OPENSHEETSET", + "SSMAUTOOPEN", + "SSLOCATE", + "SSMPOLLTIME", + "SSMSHEETSTATUS", + "SSMSTATE", + "SSFOUND", "SHORTCUTS", "SSM", "STEPOUT", diff --git a/src/app/commands/sheet_set.rs b/src/app/commands/sheet_set.rs new file mode 100644 index 000000000..73d7ecef8 --- /dev/null +++ b/src/app/commands/sheet_set.rs @@ -0,0 +1,1277 @@ +//! Sheet sets: SHEETSET / SHEETSETHIDE / NEWSHEETSET / OPENSHEETSET, the +//! SSM* / SS* system variables, the Sheet Set Manager palette and its +//! dialogs, the drawing's sheet link written on save and located on open. + +use crate::app::{Message, OpenCADStudio}; +use crate::ui::window::sheet_set::{ + FieldId, Form, FormKind, FoundLayout, MenuAction, PropRow, Properties, RowKey, SheetSetMsg, SsDialog, + Wizard, WizardMsg, +}; +use codec::sheet_set::{self as ss, ComponentKind, LayoutReference, SheetSetData, SheetSetDatabase}; +use iced::Task; +use std::path::{Path, PathBuf}; + +/// The variables this family answers for. +pub(super) const SHEET_SET_SYSVARS: &[&str] = + &["SSMAUTOOPEN", "SSLOCATE", "SSMPOLLTIME", "SSMSHEETSTATUS", "SSMSTATE", "SSFOUND"]; + +/// Paper-space layouts of a drawing in tab order: name and handle (hex). +fn paper_layouts(doc: &codec::CadDocument) -> Vec<(String, String)> { + let mut layouts: Vec<(i16, String, String)> = doc + .objects + .values() + .filter_map(|o| match o { + codec::objects::ObjectType::Layout(l) if !l.name.eq_ignore_ascii_case("Model") => { + Some((l.tab_order, l.name.clone(), format!("{:X}", l.handle.value()))) + } + _ => None, + }) + .collect(); + layouts.sort(); + layouts.into_iter().map(|(_, n, h)| (n, h)).collect() +} + +/// UTC now as the reference stamps `UpdateTime`: `yyyy/MM/dd HH:mm:ss.fff`. +fn utc_stamp() -> String { + let ms = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map(|d| d.as_millis() as i64) + .unwrap_or(0); + let (days, rem) = (ms.div_euclid(86_400_000), ms.rem_euclid(86_400_000)); + // Civil date from days since 1970-01-01. + let z = days + 719_468; + let era = z.div_euclid(146_097); + let doe = z - era * 146_097; + let yoe = (doe - doe / 1460 + doe / 36_524 - doe / 146_096) / 365; + let doy = doe - (365 * yoe + yoe / 4 - yoe / 100); + let mp = (5 * doy + 2) / 153; + let d = doy - (153 * mp + 2) / 5 + 1; + let m = if mp < 10 { mp + 3 } else { mp - 9 }; + let y = yoe + era * 400 + i64::from(m <= 2); + format!( + "{y:04}/{m:02}/{d:02} {:02}:{:02}:{:02}.{:03}", + rem / 3_600_000, + rem / 60_000 % 60, + rem / 1000 % 60, + rem % 1000 + ) +} + +fn folder_of(path: &str) -> String { + Path::new(path).parent().map(|p| p.to_string_lossy().to_string()).unwrap_or_default() +} + +/// Template of a component for new sheets: its own `DefDwtLayout`, else +/// the nearest parent's. +fn template_of(db: &SheetSetDatabase, component: &str) -> Option { + let mut id = component.to_string(); + for _ in 0..32 { + if let Some(t) = db.layout_reference(&id, "DefDwtLayout") { + return Some(t); + } + id = db.parent_of(&id)?.id().to_string(); + } + None +} + +/// New sheet folder of a component: its `NewSheetLocation`, else the +/// nearest parent's, else the `.dst` folder. +fn sheet_folder_of(db: &SheetSetDatabase, component: &str) -> String { + let mut id = component.to_string(); + for _ in 0..32 { + if let Some(f) = db.file_reference(&id, "NewSheetLocation").filter(|f| !f.is_empty()) { + return f; + } + match db.parent_of(&id) { + Some(p) => id = p.id().to_string(), + None => break, + } + } + db.path.as_deref().map(folder_of).unwrap_or_default() +} + +impl OpenCADStudio { + pub(super) fn dispatch_sheet_set(&mut self, cmd: &str, i: usize) -> Option> { + let upper = cmd.trim().to_ascii_uppercase(); + let (verb, arg) = match upper.split_once(char::is_whitespace) { + Some((v, _)) => (v.to_string(), cmd.trim()[v.len()..].trim().to_string()), + None => (upper.clone(), String::new()), + }; + match verb.as_str() { + "SHEETSET" | "SSM" => { + self.show_sheet_set_manager(true); + Some(Task::none()) + } + "SHEETSETHIDE" => { + self.show_sheet_set_manager(false); + Some(Task::none()) + } + // The ribbon toggle (its macro picks SHEETSET or SHEETSETHIDE by SSMSTATE). + "_SSMTOGGLE" => { + let on = !self.sheet_set.show; + self.show_sheet_set_manager(on); + Some(Task::none()) + } + "NEWSHEETSET" => { + self.open_new_sheet_set_wizard(); + Some(Task::none()) + } + "OPENSHEETSET" => { + if !arg.is_empty() { + return Some(self.update(Message::SheetSet(SheetSetMsg::OpenPicked(Some(PathBuf::from( + arg.trim_matches('"'), + )))))); + } + Some(Task::perform( + async { + crate::sys::file_dialog() + .set_title(crate::t!("Open Sheet Set").as_ref()) + .add_filter(crate::t!("Sheet Set (*.dst)").as_ref(), &["dst", "DST"]) + .pick_file() + .await + .map(|h| crate::sys::handle_path(&h)) + }, + |p| Message::SheetSet(SheetSetMsg::OpenPicked(p)), + )) + } + _ => self.dispatch_sheet_set_vars(cmd, i), + } + } + + fn dispatch_sheet_set_vars(&mut self, cmd: &str, _i: usize) -> Option> { + let rest = cmd.strip_prefix("SETVAR ").map(str::trim).unwrap_or(cmd); + let mut parts = rest.splitn(2, char::is_whitespace); + let name = parts.next().unwrap_or("").to_ascii_uppercase(); + if !SHEET_SET_SYSVARS.contains(&name.as_str()) { + return None; + } + let value = parts.next().map(str::trim).filter(|v| !v.is_empty()); + let s = &mut self.sheet_set.settings; + match name.as_str() { + "SSMSTATE" => { + let v = u8::from(self.sheet_set.show); + self.command_line.push_output(&format!("SSMSTATE = {v} (read only)")); + } + "SSFOUND" => { + let v = self.sheet_set.found.clone(); + self.command_line.push_output(&format!("SSFOUND = \"{v}\" (read only)")); + } + _ => { + let (current, min, max) = match name.as_str() { + "SSMAUTOOPEN" => (i32::from(s.auto_open), 0, 1), + "SSLOCATE" => (i32::from(s.locate), 0, 1), + "SSMPOLLTIME" => (i32::from(s.poll_time), 20, 600), + _ => (i32::from(s.sheet_status), 0, 2), + }; + let ask = |app: &mut Self, name: String| { + app.command_line.push_output(&format!("Enter new value for {name} <{current}>:")); + app.pending_setvar = Some(name); + }; + match value { + None => ask(self, name), + Some(v) => match v.parse::() { + Err(_) => { + self.command_line.push_error("Requires an integer value."); + ask(self, name); + } + Ok(n) if !(min..=max).contains(&n) => { + self.command_line.push_error(&if max == 1 { + "Requires 0 or 1 only.".to_string() + } else { + format!("Requires an integer between {min} and {max}.") + }); + ask(self, name); + } + Ok(n) => { + let s = &mut self.sheet_set.settings; + match name.as_str() { + "SSMAUTOOPEN" => s.auto_open = n as u8, + "SSLOCATE" => s.locate = n as u8, + "SSMPOLLTIME" => s.poll_time = n as u16, + _ => s.sheet_status = n as u8, + } + self.persist_settings_if_changed(); + } + }, + } + } + } + Some(Task::none()) + } + + /// Show or hide the palette (docked on the right like the other + /// managers). + pub(in crate::app) fn show_sheet_set_manager(&mut self, on: bool) { + let id = crate::ui::dock::PanelId::SheetSetManager; + self.sheet_set.show = on; + self.ribbon.set_sheet_set(on); + if on { + if self.dock.location(id).is_none() { + self.dock.dock(id, crate::app::config::DockSide::Right, usize::MAX); + } + self.dock_expanded = Some(id); + } else if self.dock_expanded == Some(id) { + self.dock_expanded = None; + } + } + + /// Publish the open sets to the field engine and redraw every field. + fn sheet_sets_changed(&mut self) { + crate::entities::field::set_sheet_sets(self.sheet_set.sets.clone()); + for tab in &mut self.tabs { + let changes: Vec<_> = tab + .scene + .document + .entities() + .filter(|e| crate::entities::field::hosts_field(&tab.scene.document, e)) + .map(|e| (e.common().handle, crate::scene::ChangeKind::Modified)) + .collect(); + if !changes.is_empty() { + tab.scene.bump_entities(&changes); + } + } + } + + /// Open (or bring forward) the sheet set in `path`. + pub(in crate::app) fn open_sheet_set(&mut self, path: &Path, show: bool) -> Result<(), String> { + let key = ss::path_key(&path.to_string_lossy()); + if let Some(k) = self + .sheet_set + .sets + .iter() + .position(|db| db.path.as_deref().is_some_and(|p| ss::path_key(p) == key)) + { + self.sheet_set.current = Some(k); + } else { + let db = SheetSetDatabase::read(&path.to_string_lossy())?; + self.sheet_set.sets.push(db); + self.sheet_set.current = Some(self.sheet_set.sets.len() - 1); + } + if show { + self.show_sheet_set_manager(true); + } + self.sheet_sets_changed(); + Ok(()) + } + + /// Write the current set back to its `.dst`. + fn save_current_sheet_set(&mut self) { + let Some(db) = self.sheet_set.db_mut() else { + return; + }; + let Some(path) = db.path.clone() else { + return; + }; + if let Err(e) = db.write(&path) { + self.command_line.push_error(&format!("{path}: {e}")); + } + self.sheet_sets_changed(); + } + + fn open_new_sheet_set_wizard(&mut self) { + let mut n = 1; + let folder = dirs_next_documents(); + let name = loop { + let name = format!("New Sheet Set ({n})"); + if !Path::new(&folder).join(format!("{name}.dst")).exists() { + break name; + } + n += 1; + }; + let draft = SheetSetDatabase::new(&name, ""); + self.sheet_set.dialog = Some(SsDialog::Wizard(Wizard { + step: 0, + existing: false, + name, + description: String::new(), + folder, + hierarchy: false, + folders: Vec::new(), + layouts: Vec::new(), + draft, + error: None, + })); + self.active_modal = Some(crate::app::ModalKind::SheetSet); + } + + /// Resolve a palette / automation target: a component id, a sheet + /// number or title, a subset name, or `set`. + pub(in crate::app) fn sheet_set_target(&self, spec: &str) -> Option { + let db = self.sheet_set.db()?; + if spec.eq_ignore_ascii_case("set") { + return Some(db.sheet_set().id().to_string()); + } + if db.find(spec).is_some() { + return Some(spec.to_string()); + } + fn go(el: &ss::Element, spec: &str) -> Option { + for c in &el.children { + match ComponentKind::of(c) { + Some(ComponentKind::Sheet) + if c.prop("Number") == Some(spec) + || c.prop("Title") == Some(spec) + || ss::number_and_title(c) == spec => + { + return Some(c.id().to_string()) + } + Some(ComponentKind::Subset) => { + if c.prop("Name") == Some(spec) { + return Some(c.id().to_string()); + } + if let Some(id) = go(c, spec) { + return Some(id); + } + } + _ => {} + } + } + None + } + go(db.sheet_set(), spec) + } + + fn component_kind(&self, id: &str) -> Option { + ComponentKind::of(self.sheet_set.db()?.find(id)?) + } + + pub(in crate::app) fn on_sheet_set(&mut self, m: SheetSetMsg) -> Task { + match m { + SheetSetMsg::PickSet(Some(k)) => { + if k < self.sheet_set.sets.len() { + self.sheet_set.current = Some(k); + } + } + SheetSetMsg::PickSet(None) => return self.dispatch_command("OPENSHEETSET"), + SheetSetMsg::Tab(t) => self.sheet_set.tab = t, + SheetSetMsg::Expand(id) => { + if !self.sheet_set.collapsed.remove(&id) { + self.sheet_set.collapsed.insert(id); + } + } + SheetSetMsg::Select(id) => self.sheet_set.selected = Some(id), + SheetSetMsg::Activate(id) => { + self.sheet_set.selected = Some(id.clone()); + if self.component_kind(&id) == Some(ComponentKind::Sheet) { + return self.open_sheet(&id); + } + if !self.sheet_set.collapsed.remove(&id) { + self.sheet_set.collapsed.insert(id); + } + } + SheetSetMsg::Refresh => { + if let Some(path) = self.sheet_set.db().and_then(|db| db.path.clone()) { + match SheetSetDatabase::read(&path) { + Ok(db) => { + if let Some(slot) = self.sheet_set.db_mut() { + *slot = db; + } + self.sheet_sets_changed(); + } + Err(e) => self.command_line.push_error(&format!("{path}: {e}")), + } + } + } + SheetSetMsg::Menu(id, action) => return self.sheet_set_menu(id, action), + SheetSetMsg::OpenPicked(Some(path)) => { + if let Err(e) = self.open_sheet_set(&path, true) { + self.command_line.push_error(&format!("{}: {e}", path.display())); + } + } + SheetSetMsg::OpenPicked(None) | SheetSetMsg::ImportPicked(None) | SheetSetMsg::TemplatePicked(None) => {} + SheetSetMsg::ImportPicked(Some(path)) => self.import_layout_form(path), + SheetSetMsg::FolderPicked(field, Some(path)) => self.dialog_folder(field, path), + SheetSetMsg::FolderPicked(_, None) => {} + SheetSetMsg::TemplatePicked(Some(path)) => self.properties_template(path), + SheetSetMsg::Browse(field) => { + return Task::perform( + async { + crate::sys::file_dialog() + .set_title(crate::t!("Browse for Folder").as_ref()) + .pick_folder() + .await + .map(|h| crate::sys::handle_path(&h)) + }, + move |p| Message::SheetSet(SheetSetMsg::FolderPicked(field, p)), + ) + } + SheetSetMsg::BrowseTemplate => { + return Task::perform( + async { + crate::sys::file_dialog() + .set_title(crate::t!("Select Layout as Sheet Template").as_ref()) + .add_filter(crate::t!("Drawing Template (*.dwt)").as_ref(), &["dwt", "DWT"]) + .add_filter(crate::t!("Drawing (*.dwg)").as_ref(), &["dwg", "DWG"]) + .pick_file() + .await + .map(|h| crate::sys::handle_path(&h)) + }, + |p| Message::SheetSet(SheetSetMsg::TemplatePicked(p)), + ) + } + SheetSetMsg::Input(field, v) => self.dialog_input(field, v), + SheetSetMsg::Toggle(field, v) => { + if let (FieldId::Hierarchy, Some(SsDialog::Wizard(w))) = (field, self.sheet_set.dialog.as_mut()) { + w.hierarchy = v; + } + } + SheetSetMsg::Choose(field, k) => match (field, self.sheet_set.dialog.as_mut()) { + (FieldId::Layout, Some(SsDialog::Form(f))) => f.layout = k, + (FieldId::CustomOwner, Some(SsDialog::Properties(p))) => { + if let Some(a) = p.adding.as_mut() { + a.2 = k == 1; + } + } + (FieldId::Row(r), Some(SsDialog::Properties(p))) => { + if let Some(row) = p.rows.get_mut(r) { + row.value = if k == 0 { "Yes" } else { "No" }.into(); + } + } + _ => {} + }, + SheetSetMsg::Wizard(w) => self.on_wizard(w), + SheetSetMsg::WizardProperties => { + if let Some(SsDialog::Wizard(mut w)) = self.sheet_set.dialog.take() { + sync_wizard_draft(&mut w); + let set = w.draft.sheet_set().id().to_string(); + let mut p = build_properties(&w.draft, &set, None); + p.wizard = Some(Box::new(w)); + self.sheet_set.dialog = Some(SsDialog::Properties(p)); + } + } + SheetSetMsg::AddCustom => { + if let Some(SsDialog::Properties(p)) = self.sheet_set.dialog.as_mut() { + let mut n = 1; + while p.custom.iter().any(|(name, _, _)| *name == format!("New Name ({n})")) { + n += 1; + } + p.adding = Some((format!("New Name ({n})"), "Value".into(), false)); + } + } + SheetSetMsg::AddCustomCancel => { + if let Some(SsDialog::Properties(p)) = self.sheet_set.dialog.as_mut() { + p.adding = None; + } + } + SheetSetMsg::AddCustomOk => { + if let Some(SsDialog::Properties(p)) = self.sheet_set.dialog.as_mut() { + if let Some((name, value, sheet)) = p.adding.take() { + let name = name.trim().to_string(); + if name.is_empty() { + p.error = Some(crate::t!("The name cannot be empty.").into_owned()); + } else if p.custom.iter().any(|(n, _, _)| n.eq_ignore_ascii_case(&name)) { + p.error = Some(crate::t!("A custom property with this name already exists.").into_owned()); + } else { + p.error = None; + let flags = if sheet { ss::CUSTOM_SHEET_PROP } else { ss::CUSTOM_SHEET_SET_PROP }; + p.custom.push((name, value, flags)); + } + } + } + } + SheetSetMsg::CustomValue(k, v) => { + if let Some(SsDialog::Properties(p)) = self.sheet_set.dialog.as_mut() { + if let Some(c) = p.custom.get_mut(k) { + c.1 = v; + } + } + } + SheetSetMsg::Ok => return self.sheet_set_dialog_ok(), + SheetSetMsg::Cancel => self.close_sheet_set_dialog(), + SheetSetMsg::Help => self.command_line.push_info( + crate::t!("Sheet sets organize layouts from several drawings into one named set of sheets.").as_ref(), + ), + } + Task::none() + } + + /// Cancel / × of the sheet set dialogs: the Properties dialog opened from + /// the wizard goes back to it. + pub(in crate::app) fn close_sheet_set_dialog(&mut self) { + match self.sheet_set.dialog.take() { + Some(SsDialog::Properties(p)) if p.wizard.is_some() => { + self.sheet_set.dialog = p.wizard.map(|w| SsDialog::Wizard(*w)); + } + _ => self.close_active_modal(), + } + } + + fn sheet_set_menu(&mut self, id: String, action: MenuAction) -> Task { + let Some(set) = self.sheet_set.current else { + return Task::none(); + }; + self.sheet_set.selected = Some(id.clone()); + let Some(db) = self.sheet_set.db() else { + return Task::none(); + }; + match action { + MenuAction::Open => return self.open_sheet(&id), + MenuAction::NewSheet => { + // Next number: the last sheet's number + 1 when it ends in digits. + let template = template_of(db, &id) + .map(|t| format!("{} ({})", t.name, t.file_name)) + .unwrap_or_else(|| crate::t!("(default new drawing)").into_owned()); + self.sheet_set.dialog = Some(SsDialog::Form(Form { + kind: FormKind::NewSheet, + set, + component: id.clone(), + number: String::new(), + title: String::new(), + file_name: String::new(), + folder: sheet_folder_of(db, &id), + drawing: template, + layouts: Vec::new(), + layout: 0, + error: None, + })); + self.active_modal = Some(crate::app::ModalKind::SheetSet); + } + MenuAction::NewSubset => { + let mut n = 1; + let parent = db.find(&id); + while parent.is_some_and(|p| { + p.children.iter().any(|c| c.prop("Name") == Some(format!("New Subset ({n})").as_str())) + }) { + n += 1; + } + self.sheet_set.dialog = Some(SsDialog::Form(Form { + kind: FormKind::NewSubset, + set, + component: id.clone(), + number: String::new(), + title: format!("New Subset ({n})"), + file_name: String::new(), + folder: sheet_folder_of(db, &id), + drawing: String::new(), + layouts: Vec::new(), + layout: 0, + error: None, + })); + self.active_modal = Some(crate::app::ModalKind::SheetSet); + } + MenuAction::ImportLayout => { + self.sheet_set_import_parent = Some(id); + return Task::perform( + async { + crate::sys::file_dialog() + .set_title(crate::t!("Select Drawing").as_ref()) + .add_filter(crate::t!("Drawing (*.dwg)").as_ref(), &["dwg", "DWG"]) + .pick_file() + .await + .map(|h| crate::sys::handle_path(&h)) + }, + |p| Message::SheetSet(SheetSetMsg::ImportPicked(p)), + ); + } + MenuAction::Rename => { + let el = db.find(&id); + self.sheet_set.dialog = Some(SsDialog::Form(Form { + kind: FormKind::Rename, + set, + component: id.clone(), + number: el.and_then(|e| e.prop("Number")).unwrap_or("").to_string(), + title: el.and_then(|e| e.prop("Title")).unwrap_or("").to_string(), + file_name: String::new(), + folder: String::new(), + drawing: String::new(), + layouts: Vec::new(), + layout: 0, + error: None, + })); + self.active_modal = Some(crate::app::ModalKind::SheetSet); + } + MenuAction::Remove => { + if let Some(db) = self.sheet_set.db_mut() { + db.remove(&id); + } + self.sheet_set.selected = None; + self.save_current_sheet_set(); + } + MenuAction::Properties => { + let p = build_properties(db, &id, Some(set)); + self.sheet_set.dialog = Some(SsDialog::Properties(p)); + self.active_modal = Some(crate::app::ModalKind::SheetSet); + } + MenuAction::Close => { + self.sheet_set.sets.remove(set); + self.sheet_set.current = (!self.sheet_set.sets.is_empty()).then_some(0); + self.sheet_set.selected = None; + self.sheet_sets_changed(); + } + } + Task::none() + } + + /// Open a sheet's drawing (or switch to it) at the sheet's layout. + fn open_sheet(&mut self, id: &str) -> Task { + let Some(reference) = self.sheet_set.db().and_then(|db| db.layout_reference(id, "Layout")) else { + return Task::none(); + }; + let path = PathBuf::from(&reference.file_name); + if let Some(k) = self.tab_showing(&path) { + return Task::batch([ + self.update(Message::TabSwitch(k)), + Task::done(Message::LayoutSwitch(reference.name)), + ]); + } + if !path.exists() { + self.command_line + .push_error(crate::tf!("Sheet drawing not found: {}", path.display()).as_ref()); + return Task::none(); + } + self.sheet_set_pending_layout = Some((ss::path_key(&reference.file_name), reference.name)); + self.update(Message::OpenRecent(path)) + } + + /// After a drawing opened: switch to the sheet layout that was asked for, + /// and locate the sheet set the drawing names (SSLOCATE / SSMAUTOOPEN). + pub(in crate::app) fn sheet_set_after_open(&mut self, i: usize) -> Task { + let mut task = Task::none(); + let path = self.tabs[i].current_path.as_ref().map(|p| p.to_string_lossy().to_string()); + if let (Some(path), Some((want, layout))) = (path.as_ref(), self.sheet_set_pending_layout.as_ref()) { + if ss::path_key(path) == *want { + task = Task::done(Message::LayoutSwitch(layout.clone())); + self.sheet_set_pending_layout = None; + } + } + if self.sheet_set.settings.locate == 1 { + if let Some(data) = self.tabs[i].scene.document.sheet_set_data() { + let named = PathBuf::from(&data.sheet_set_file_name); + // A moved set is looked for next to the drawing. + let found = if named.exists() { + Some(named) + } else { + path.as_deref().and_then(|p| { + let beside = Path::new(p).parent()?.join(named.file_name()?); + beside.exists().then_some(beside) + }) + }; + self.sheet_set.found = found.as_ref().map(|f| f.to_string_lossy().to_string()).unwrap_or_default(); + if let Some(found) = found { + let show = self.sheet_set.settings.auto_open == 1; + if let Err(e) = self.open_sheet_set(&found, show) { + self.command_line.push_error(&format!("{}: {e}", found.display())); + } + } + } + } + task + } + + /// Before a native save: a drawing that is a sheet of an open set records + /// its link (`AcSheetSetData`), as the reference does when it saves a + /// sheet while its set is open. + pub(in crate::app) fn stamp_sheet_set_data(&mut self, i: usize) { + let Some(path) = self.tabs[i].current_path.as_ref().map(|p| p.to_string_lossy().to_string()) else { + return; + }; + let layout = self.tabs[i].scene.current_layout.clone(); + let layouts = paper_layouts(&self.tabs[i].scene.document); + for db in &self.sheet_set.sets { + let wanted = (!layout.eq_ignore_ascii_case("Model")).then_some(layout.as_str()); + let Some(sheet) = db.sheet_for(&path, wanted) else { + continue; + }; + let Some(reference) = db.layout_reference(sheet.id(), "Layout") else { + continue; + }; + let handle = layouts + .iter() + .find(|(n, _)| n.eq_ignore_ascii_case(&reference.name)) + .map(|(_, h)| h.to_lowercase()) + .unwrap_or_else(|| reference.handle.to_lowercase()); + let doc = &mut self.tabs[i].scene.document; + let previous = doc.sheet_set_data().unwrap_or_default(); + doc.set_sheet_set_data(&SheetSetData { + layout_handle: handle, + layout_name: reference.name, + sheet_dwg_name: path.clone(), + sheet_set_file_name: db.path.clone().unwrap_or_default(), + sheet_set_version: db.file_revision(), + update_count: previous.update_count + 1, + update_time: utc_stamp(), + }); + return; + } + } + + fn dialog_input(&mut self, field: FieldId, v: String) { + match self.sheet_set.dialog.as_mut() { + Some(SsDialog::Wizard(w)) => match field { + FieldId::Name => w.name = v, + FieldId::Description => w.description = v, + FieldId::Folder => w.folder = v, + _ => {} + }, + Some(SsDialog::Properties(p)) => match field { + FieldId::Row(r) => { + if let Some(row) = p.rows.get_mut(r) { + row.value = v; + } + } + FieldId::CustomName => { + if let Some(a) = p.adding.as_mut() { + a.0 = v; + } + } + FieldId::CustomDefault => { + if let Some(a) = p.adding.as_mut() { + a.1 = v; + } + } + _ => {} + }, + Some(SsDialog::Form(f)) => { + let file_follows = f.file_name == format!("{} {}", f.number, f.title).trim(); + match field { + FieldId::Number => f.number = v, + FieldId::Title => f.title = v, + FieldId::FileName => f.file_name = v, + FieldId::Folder => f.folder = v, + _ => {} + } + // The file name follows "Number Title" until edited. + if f.kind == FormKind::NewSheet && file_follows && field != FieldId::FileName { + f.file_name = format!("{} {}", f.number, f.title).trim().to_string(); + } + } + None => {} + } + } + + fn dialog_folder(&mut self, field: FieldId, path: PathBuf) { + let folder = path.to_string_lossy().to_string(); + if field == FieldId::AddFolder { + self.wizard_add_folder(path); + return; + } + self.dialog_input(field, folder); + } + + fn wizard_add_folder(&mut self, path: PathBuf) { + let Some(SsDialog::Wizard(w)) = self.sheet_set.dialog.as_mut() else { + return; + }; + let folder = path.to_string_lossy().to_string(); + if w.folders.contains(&folder) { + return; + } + let mut files: Vec = std::fs::read_dir(&path) + .map(|rd| { + rd.filter_map(|e| e.ok().map(|e| e.path())) + .filter(|p| p.extension().is_some_and(|x| x.eq_ignore_ascii_case("dwg"))) + .collect() + }) + .unwrap_or_default(); + files.sort(); + for file in files { + let Ok(doc) = crate::io::load_file(&file) else { + continue; + }; + for (layout, handle) in paper_layouts(&doc) { + w.layouts.push(FoundLayout { + folder: folder.clone(), + file: file.to_string_lossy().to_string(), + layout, + handle, + on: true, + }); + } + } + w.folders.push(folder); + } + + fn on_wizard(&mut self, m: WizardMsg) { + let Some(SsDialog::Wizard(w)) = self.sheet_set.dialog.as_mut() else { + return; + }; + match m { + WizardMsg::Step(s) => { + w.error = None; + if s > 1 && w.step <= 1 { + if w.name.trim().is_empty() { + w.error = Some(crate::t!("The sheet set name cannot be empty.").into_owned()); + return; + } + if !Path::new(&w.folder).is_dir() { + w.error = Some(crate::t!("The folder for the sheet set data file does not exist.").into_owned()); + return; + } + } + w.step = if s == 2 && !w.existing { 3 } else { s }; + sync_wizard_draft(w); + } + WizardMsg::Existing(on) => w.existing = on, + WizardMsg::LayoutOn(k, on) => { + if let Some(l) = w.layouts.get_mut(k) { + l.on = on; + } + } + WizardMsg::RemoveFolder(k) => { + if k < w.folders.len() { + let folder = w.folders.remove(k); + w.layouts.retain(|l| l.folder != folder); + } + } + } + } + + fn import_layout_form(&mut self, path: PathBuf) { + let (Some(set), Some(parent)) = (self.sheet_set.current, self.sheet_set_import_parent.take()) else { + return; + }; + let layouts = match crate::io::load_file(&path) { + Ok(doc) => paper_layouts(&doc), + Err(e) => { + self.command_line.push_error(&format!("{}: {e}", path.display())); + return; + } + }; + self.sheet_set.dialog = Some(SsDialog::Form(Form { + kind: FormKind::ImportLayout, + set, + component: parent, + number: String::new(), + title: String::new(), + file_name: String::new(), + folder: String::new(), + drawing: path.to_string_lossy().to_string(), + layouts, + layout: 0, + error: None, + })); + self.active_modal = Some(crate::app::ModalKind::SheetSet); + } + + fn properties_template(&mut self, path: PathBuf) { + let layouts = crate::io::load_file(&path).map(|d| paper_layouts(&d)).unwrap_or_default(); + let Some(SsDialog::Properties(p)) = self.sheet_set.dialog.as_mut() else { + return; + }; + match layouts.first() { + Some((name, _)) => { + let file = path.to_string_lossy().to_string(); + if let Some(row) = p.rows.iter_mut().find(|r| r.key == RowKey::Template) { + row.value = format!("{name} ({file})"); + } + p.template = Some((file, name.clone())); + p.error = None; + } + None => p.error = Some(crate::t!("The drawing has no layout to use as a sheet template.").into_owned()), + } + } + + fn sheet_set_dialog_ok(&mut self) -> Task { + match self.sheet_set.dialog.take() { + Some(SsDialog::Wizard(w)) => self.finish_wizard(w), + Some(SsDialog::Properties(p)) => { + self.apply_properties(p); + Task::none() + } + Some(SsDialog::Form(f)) => self.form_ok(f), + None => Task::none(), + } + } + + fn finish_wizard(&mut self, mut w: Wizard) -> Task { + sync_wizard_draft(&mut w); + let path = crate::ui::window::sheet_set::wizard_dst_path(&w); + if w.name.trim().is_empty() || !Path::new(&w.folder).is_dir() { + w.error = Some(crate::t!("The folder for the sheet set data file does not exist.").into_owned()); + self.sheet_set.dialog = Some(SsDialog::Wizard(w)); + return Task::none(); + } + if Path::new(&path).exists() { + w.error = Some(crate::tf!("{} already exists.", path).into_owned()); + self.sheet_set.dialog = Some(SsDialog::Wizard(w)); + return Task::none(); + } + let mut db = w.draft.clone(); + db.path = Some(path.clone()); + let set = db.sheet_set().id().to_string(); + if db.file_reference(&set, "NewSheetLocation").is_none() { + db.set_file_reference(&set, "NewSheetLocation", &w.folder); + } + // Existing drawings: a subset per folder, a sheet per chosen layout. + if w.existing { + for folder in &w.folders { + let chosen: Vec<&FoundLayout> = w.layouts.iter().filter(|l| l.on && &l.folder == folder).collect(); + if chosen.is_empty() { + continue; + } + let name = Path::new(folder).file_name().map(|n| n.to_string_lossy().to_string()).unwrap_or_default(); + let Some(sub) = db.add_subset(&set, &name, "") else { + continue; + }; + if w.hierarchy { + db.set_file_reference(&sub, "NewSheetLocation", folder); + } + for l in chosen { + let stem = Path::new(&l.file).file_stem().map(|s| s.to_string_lossy().to_string()).unwrap_or_default(); + if let Some(sheet) = db.add_sheet(&sub, "", &format!("{stem} - {}", l.layout), "") { + db.set_layout_reference( + &sheet, + "Layout", + &LayoutReference { file_name: l.file.clone(), name: l.layout.clone(), handle: l.handle.clone() }, + ); + } + } + } + } + if let Err(e) = db.write(&path) { + w.error = Some(e); + self.sheet_set.dialog = Some(SsDialog::Wizard(w)); + return Task::none(); + } + self.close_active_modal(); + if let Err(e) = self.open_sheet_set(Path::new(&path), true) { + self.command_line.push_error(&e); + } + Task::none() + } + + fn apply_properties(&mut self, mut p: Properties) { + // Back to the wizard: the draft takes the edits. + if let Some(mut w) = p.wizard.take() { + write_properties(&mut w.draft, &p); + let set = w.draft.sheet_set(); + w.name = set.prop("Name").unwrap_or("").to_string(); + w.description = set.prop("Desc").unwrap_or("").to_string(); + self.sheet_set.dialog = Some(SsDialog::Wizard(*w)); + return; + } + self.close_active_modal(); + let Some(db) = p.set.and_then(|k| self.sheet_set.sets.get_mut(k)) else { + return; + }; + write_properties(db, &p); + self.sheet_set.current = p.set; + self.save_current_sheet_set(); + } + + fn form_ok(&mut self, mut f: Form) -> Task { + let Some(db) = self.sheet_set.sets.get_mut(f.set) else { + self.close_active_modal(); + return Task::none(); + }; + match f.kind { + FormKind::Rename => { + if let Some(el) = db.find_mut(&f.component) { + el.set_prop("Number", f.number.trim()); + el.set_prop("Title", f.title.trim()); + } + } + FormKind::NewSubset => { + let name = f.title.trim().to_string(); + if name.is_empty() { + f.error = Some(crate::t!("The subset name cannot be empty.").into_owned()); + self.sheet_set.dialog = Some(SsDialog::Form(f)); + return Task::none(); + } + if let Some(sub) = db.add_subset(&f.component, &name, "") { + if !f.folder.trim().is_empty() { + db.set_file_reference(&sub, "NewSheetLocation", f.folder.trim()); + } + } + } + FormKind::ImportLayout => { + let Some((layout, handle)) = f.layouts.get(f.layout).cloned() else { + f.error = Some(crate::t!("The drawing has no layout to import.").into_owned()); + self.sheet_set.dialog = Some(SsDialog::Form(f)); + return Task::none(); + }; + if db.sheet_for(&f.drawing, Some(&layout)).is_some_and(|s| { + s.named("Layout").and_then(|r| r.prop("Name")).is_some_and(|n| n.eq_ignore_ascii_case(&layout)) + }) { + f.error = Some(crate::t!("The layout is already a sheet of this sheet set.").into_owned()); + self.sheet_set.dialog = Some(SsDialog::Form(f)); + return Task::none(); + } + let stem = Path::new(&f.drawing).file_stem().map(|s| s.to_string_lossy().to_string()).unwrap_or_default(); + if let Some(sheet) = db.add_sheet(&f.component, "", &format!("{stem} - {layout}"), "") { + db.set_layout_reference( + &sheet, + "Layout", + &LayoutReference { file_name: f.drawing.clone(), name: layout, handle }, + ); + } + } + FormKind::NewSheet => return self.create_sheet(f), + } + self.close_active_modal(); + self.sheet_set.current = Some(f.set); + self.save_current_sheet_set(); + Task::none() + } + + /// New Sheet: a drawing in the sheet folder holding one layout, named + /// "Number Title", from the sheet creation template (a new drawing's + /// Layout1 when the set names none); then the sheet and its layout + /// reference, and the drawing opens at it. + fn create_sheet(&mut self, mut f: Form) -> Task { + let fail = |app: &mut Self, mut f: Form, e: String| { + f.error = Some(e); + app.sheet_set.dialog = Some(SsDialog::Form(f)); + Task::none() + }; + let title = f.title.trim().to_string(); + if title.is_empty() { + return fail(self, f, crate::t!("The sheet title cannot be empty.").into_owned()); + } + let stem = if f.file_name.trim().is_empty() { + format!("{} {}", f.number.trim(), title).trim().to_string() + } else { + f.file_name.trim().trim_end_matches(".dwg").to_string() + }; + let folder = PathBuf::from(f.folder.trim()); + if std::fs::create_dir_all(&folder).is_err() { + return fail(self, f, crate::t!("The sheet folder cannot be created.").into_owned()); + } + let path = folder.join(format!("{stem}.dwg")); + if path.exists() { + return fail(self, f, crate::tf!("{} already exists.", path.display()).into_owned()); + } + let layout_name = format!("{} {}", f.number.trim(), title).trim().to_string(); + let template = self.sheet_set.sets.get(f.set).and_then(|db| template_of(db, &f.component)); + let mut scene = crate::scene::Scene::new(); + let source_layout = match template.as_ref().and_then(|t| crate::io::load_file(Path::new(&t.file_name)).ok().map(|d| (d, t.name.clone()))) { + Some((doc, name)) => { + scene.document = doc; + name + } + None => { + scene.populate_new_drawing_defaults(); + paper_layouts(&scene.document).into_iter().next().map(|(n, _)| n).unwrap_or_else(|| "Layout1".into()) + } + }; + for (name, _) in paper_layouts(&scene.document) { + if !name.eq_ignore_ascii_case(&source_layout) { + scene.delete_layout(&name); + } + } + scene.rename_layout(&source_layout, &layout_name); + let handle = paper_layouts(&scene.document) + .into_iter() + .find(|(n, _)| *n == layout_name) + .map(|(_, h)| h) + .unwrap_or_default(); + f.number = f.number.trim().to_string(); + let Some(db) = self.sheet_set.sets.get_mut(f.set) else { + return Task::none(); + }; + let Some(sheet) = db.add_sheet(&f.component, &f.number, &title, "") else { + return Task::none(); + }; + let file = path.to_string_lossy().to_string(); + db.set_layout_reference( + &sheet, + "Layout", + &LayoutReference { file_name: file.clone(), name: layout_name.clone(), handle: handle.clone() }, + ); + let dst = db.path.clone().unwrap_or_default(); + if let Err(e) = db.write(&dst) { + self.command_line.push_error(&format!("{dst}: {e}")); + } + let revision = db.file_revision(); + scene.document.set_sheet_set_data(&SheetSetData { + layout_handle: handle.to_lowercase(), + layout_name, + sheet_dwg_name: file.clone(), + sheet_set_file_name: dst, + sheet_set_version: revision, + update_count: 1, + update_time: utc_stamp(), + }); + crate::entities::field::stamp_save_dates(&mut scene.document); + if let Err(e) = crate::io::save(&scene.document, &path) { + self.command_line.push_error(&format!("{file}: {e}")); + } + self.close_active_modal(); + self.sheet_set.current = Some(f.set); + self.sheet_set.selected = Some(sheet.clone()); + self.sheet_sets_changed(); + self.open_sheet(&sheet) + } +} + +/// The reference's default folder for new sheet set data: My Documents. +fn dirs_next_documents() -> String { + #[cfg(target_os = "windows")] + if let Ok(profile) = std::env::var("USERPROFILE") { + for sub in ["Documents", "OneDrive\\Belgeler", "OneDrive\\Documents"] { + let p = Path::new(&profile).join(sub); + if p.is_dir() { + return p.to_string_lossy().to_string(); + } + } + return profile; + } + std::env::var("HOME").unwrap_or_default() +} + +/// Copy the wizard's name and description into its draft set. +fn sync_wizard_draft(w: &mut Wizard) { + let set = w.draft.sheet_set_mut(); + set.set_prop("Name", w.name.trim()); + set.set_prop("Desc", &w.description); +} + +/// The Properties rows for component `id` of `db` (`set` = its index among +/// the open sets; `None` for the wizard's draft). +pub(in crate::app) fn build_properties(db: &SheetSetDatabase, id: &str, set: Option) -> Properties { + let el = db.find(id).cloned().unwrap_or_default(); + let kind = ComponentKind::of(&el).unwrap_or(ComponentKind::SheetSet); + let prop = |name: &str| el.prop(name).unwrap_or("").to_string(); + let row = |group: &'static str, label: &'static str, key: RowKey, value: String| PropRow { group, label, key, value }; + let template = || { + db.layout_reference(id, "DefDwtLayout") + .map(|t| format!("{} ({})", t.name, t.file_name)) + .unwrap_or_default() + }; + let prompt = || if el.prop("PromptForDwt").is_some_and(|v| v.trim() != "0") { "Yes" } else { "No" }.to_string(); + let named_file = |name: &str| el.named(name).map(|r| db.resolve_file(r)).unwrap_or_default(); + let mut rows = Vec::new(); + let title; + match kind { + ComponentKind::SheetSet => { + title = format!("{} - {}", crate::t!("Sheet Set Properties"), prop("Name")); + rows.push(row("Sheet Set", "Name", RowKey::Prop("Name"), prop("Name"))); + rows.push(row("Sheet Set", "Sheet set data file", RowKey::ReadOnly, db.path.clone().unwrap_or_default())); + rows.push(row("Sheet Set", "Description", RowKey::Prop("Desc"), prop("Desc"))); + let resources = el + .named("Resources") + .map(|r| r.children.iter().map(|c| db.resolve_file(c)).collect::>().join("; ")) + .unwrap_or_default(); + rows.push(row("Sheet Set", "Model view", RowKey::ReadOnly, resources)); + let label_block = el + .named("DefLabelBlk") + .map(|r| format!("{} ({})", r.prop("Name").unwrap_or(""), db.resolve_file(r))) + .unwrap_or_default(); + rows.push(row("Sheet Set", "Label block for views", RowKey::ReadOnly, label_block)); + let callouts = el + .named("CalloutBlocks") + .map(|r| r.children.iter().filter_map(|c| c.prop("Name")).collect::>().join("; ")) + .unwrap_or_default(); + rows.push(row("Sheet Set", "Callout blocks", RowKey::ReadOnly, callouts)); + rows.push(row("Sheet Set", "Page setup overrides file", RowKey::ReadOnly, named_file("AltPageSetups"))); + for (label, name) in [ + ("Project number", "ProjectNumber"), + ("Project name", "ProjectName"), + ("Project phase", "ProjectPhase"), + ("Project milestone", "ProjectMilestone"), + ] { + rows.push(row("Project Control", label, RowKey::Prop(name), prop(name))); + } + rows.push(row("Sheet Creation", "Sheet storage location", RowKey::Folder("NewSheetLocation"), named_file("NewSheetLocation"))); + rows.push(row("Sheet Creation", "Sheet creation template", RowKey::Template, template())); + rows.push(row("Sheet Creation", "Prompt for template", RowKey::PromptTemplate, prompt())); + } + ComponentKind::Subset => { + title = format!("{} - {}", crate::t!("Subset Properties"), prop("Name")); + rows.push(row("Subset", "Subset name", RowKey::Prop("Name"), prop("Name"))); + rows.push(row("Subset", "Description", RowKey::Prop("Desc"), prop("Desc"))); + rows.push(row("Subset", "New sheet location", RowKey::Folder("NewSheetLocation"), named_file("NewSheetLocation"))); + rows.push(row("Subset", "Sheet creation template", RowKey::Template, template())); + rows.push(row("Subset", "Prompt for template", RowKey::PromptTemplate, prompt())); + } + ComponentKind::Sheet => { + title = format!("{} - {}", crate::t!("Sheet Properties"), ss::number_and_title(&el)); + for (label, name) in [ + ("Title", "Title"), + ("Number", "Number"), + ("Description", "Desc"), + ("Revision number", "RevisionNumber"), + ("Revision date", "RevisionDate"), + ("Issue purpose", "IssuePurpose"), + ("Category", "Category"), + ] { + rows.push(row("Sheet", label, RowKey::Prop(name), prop(name))); + } + let layout = db.layout_reference(id, "Layout").unwrap_or_default(); + rows.push(row("Sheet", "Layout name", RowKey::ReadOnly, layout.name)); + rows.push(row("Sheet", "Drawing file", RowKey::ReadOnly, layout.file_name)); + } + } + // A sheet shows the set's sheet properties, with its own value when set. + let custom = match kind { + ComponentKind::Sheet => { + let own = ss::custom_properties(&el); + ss::custom_properties(db.sheet_set()) + .into_iter() + .filter(|(_, _, f)| f & ss::CUSTOM_SHEET_PROP != 0) + .map(|(n, v, f)| { + let value = own.iter().find(|(o, _, _)| *o == n).map(|(_, v, _)| v.clone()).unwrap_or(v); + (n, value, f) + }) + .collect() + } + ComponentKind::SheetSet => ss::custom_properties(&el), + ComponentKind::Subset => Vec::new(), + }; + Properties { + set, + component: id.to_string(), + kind, + title, + rows, + custom, + adding: None, + template: None, + wizard: None, + error: None, + } +} + +/// Write a Properties dialog back into its component. +fn write_properties(db: &mut SheetSetDatabase, p: &Properties) { + for r in &p.rows { + match &r.key { + RowKey::Prop(name) => { + if let Some(el) = db.find_mut(&p.component) { + el.set_prop(name, &r.value); + } + } + RowKey::Folder(name) => { + db.set_file_reference(&p.component, name, r.value.trim()); + } + RowKey::PromptTemplate => { + if let Some(el) = db.find_mut(&p.component) { + if r.value == "Yes" { + el.set_prop_vt("PromptForDwt", 3, "1"); + } else { + el.remove_named("PromptForDwt"); + } + } + } + RowKey::Template | RowKey::ReadOnly => {} + } + } + if let Some((file, name)) = &p.template { + db.set_layout_reference( + &p.component, + "DefDwtLayout", + &LayoutReference { file_name: file.clone(), name: name.clone(), handle: String::new() }, + ); + } + match p.kind { + ComponentKind::SheetSet => { + if let Some(el) = db.find_mut(&p.component) { + let old: Vec = ss::custom_properties(el).into_iter().map(|(n, _, _)| n).collect(); + for n in old.iter().filter(|n| !p.custom.iter().any(|(c, _, _)| c == *n)) { + ss::remove_custom_property(el, n); + } + for (n, v, f) in &p.custom { + ss::set_custom_property(el, n, v, *f); + } + } + } + ComponentKind::Sheet => { + if let Some(el) = db.find_mut(&p.component) { + for (n, v, f) in &p.custom { + ss::set_custom_property(el, n, v, *f); + } + } + } + ComponentKind::Subset => {} + } +} + diff --git a/src/app/control/actions.rs b/src/app/control/actions.rs index 671a08b77..0fe7272b1 100644 --- a/src/app/control/actions.rs +++ b/src/app/control/actions.rs @@ -82,6 +82,7 @@ pub(super) const NAMES: &[&str] = &[ "dialog_ok", "attdef_dialog", "field_dialog", + "sheet_set", "close_document", "toggle_properties", "toggle_layers", @@ -1019,9 +1020,103 @@ impl OpenCADStudio { "link_text" => F::HyperlinkText(v.into()), "link_url" => F::HyperlinkUrl(v.into()), "plot_scale" => F::PlotScale(index(codec::fields::PLOT_SCALE_FORMATS.len())?), + "ss_custom" => F::SsCustom(v.into()), + "ss_placeholder" => F::SsPlaceholder(index(fd::PLACEHOLDER_TYPES.len())?), + "ss_scale" => F::SsScaleFormat(index(codec::fields::PLOT_SCALE_FORMATS.len())?), _ => return Err(failure("invalid_value", "Unknown field dialog key")), }) } + // Sheet Set Manager and its dialogs: "open=", "tab=list|views|model", + // "select=", "activate=", "menu=:" + // (open, new_sheet, new_subset, import, rename, remove, properties, + // close; a target is a sheet number or title, a subset name or + // "set"), "import_file=", "new" (wizard), "existing=0|1", + // "step=", "name=", "description=", "folder=", "hierarchy=0|1", + // "add_folder=", "layout=:0|1", "wizard_props", + // "row=:", "prompt=0|1:", "template=", + // "custom=:", "add_custom", "custom_name=", "custom_default=", + // "custom_owner=0|1", "add_custom_ok", "number=", "title=", + // "file_name=", "pick_layout=", "ok", "cancel". + "sheet_set" => { + use crate::ui::window::sheet_set::{FieldId as F, MenuAction as A, SheetSetMsg as M, SsmTab, WizardMsg as W}; + let value = string(req, "value")?; + let (key, arg) = value.split_once('=').unwrap_or((value, "")); + let target = |app: &Self, spec: &str| { + app.sheet_set_target(spec).ok_or_else(|| failure("invalid_value", "No such sheet set component")) + }; + let index_value = |spec: &str| -> Result<(usize, String), Value> { + let (i, v) = spec.split_once(':').unwrap_or((spec, "")); + Ok((i.parse().map_err(|_| failure("invalid_value", "Expected :"))?, v.to_string())) + }; + Message::SheetSet(match key { + "open" => M::OpenPicked(Some(std::path::PathBuf::from(arg))), + "import_file" => M::ImportPicked(Some(std::path::PathBuf::from(arg))), + "tab" => M::Tab(match arg { + "views" => SsmTab::SheetViews, + "model" => SsmTab::ModelViews, + _ => SsmTab::SheetList, + }), + "select" => M::Select(target(self, arg)?), + "activate" => M::Activate(target(self, arg)?), + "menu" => { + let (action, spec) = arg.split_once(':').unwrap_or((arg, "set")); + let action = match action { + "open" => A::Open, + "new_sheet" => A::NewSheet, + "new_subset" => A::NewSubset, + "import" => A::ImportLayout, + "rename" => A::Rename, + "remove" => A::Remove, + "properties" => A::Properties, + "close" => A::Close, + _ => return Err(failure("invalid_value", "Unknown sheet set menu action")), + }; + if action == A::ImportLayout { + self.sheet_set_import_parent = Some(target(self, spec)?); + return Ok(Task::none()); + } + M::Menu(target(self, spec)?, action) + } + "new" => return Ok(self.dispatch_command("NEWSHEETSET")), + "existing" => M::Wizard(W::Existing(arg == "1")), + "step" => M::Wizard(W::Step(arg.parse().map_err(|_| failure("invalid_value", "step"))?)), + "layout" => { + let (i, v) = index_value(arg)?; + M::Wizard(W::LayoutOn(i, v == "1")) + } + "name" => M::Input(F::Name, arg.into()), + "description" => M::Input(F::Description, arg.into()), + "folder" => M::Input(F::Folder, arg.into()), + "hierarchy" => M::Toggle(F::Hierarchy, arg == "1"), + "add_folder" => M::FolderPicked(F::AddFolder, Some(std::path::PathBuf::from(arg))), + "wizard_props" => M::WizardProperties, + "row" => { + let (i, v) = index_value(arg)?; + M::Input(F::Row(i), v) + } + "prompt" => { + let (i, v) = index_value(arg)?; + M::Choose(F::Row(i), usize::from(v != "1")) + } + "template" => M::TemplatePicked(Some(std::path::PathBuf::from(arg))), + "custom" => { + let (i, v) = index_value(arg)?; + M::CustomValue(i, v) + } + "add_custom" => M::AddCustom, + "custom_name" => M::Input(F::CustomName, arg.into()), + "custom_default" => M::Input(F::CustomDefault, arg.into()), + "custom_owner" => M::Choose(F::CustomOwner, usize::from(arg == "1")), + "add_custom_ok" => M::AddCustomOk, + "number" => M::Input(F::Number, arg.into()), + "title" => M::Input(F::Title, arg.into()), + "file_name" => M::Input(F::FileName, arg.into()), + "pick_layout" => M::Choose(F::Layout, arg.parse().map_err(|_| failure("invalid_value", "index"))?), + "ok" => M::Ok, + "cancel" => M::Cancel, + _ => return Err(failure("invalid_value", "Unknown sheet set action")), + }) + } "ribbon_dropdown" => Message::ToggleRibbonDropdown(string(req, "value")?.into()), "pdf_dialog_ok" => { use crate::ui::window::pdf_dialogs::PdfDialogMsg; @@ -1048,6 +1143,9 @@ impl OpenCADStudio { Some(crate::app::ModalKind::AttDefEdit) => Message::AttdefDialog( crate::ui::window::attdef_dialog::AttdefDialogMsg::EditOk, ), + Some(crate::app::ModalKind::SheetSet) => Message::SheetSet( + crate::ui::window::sheet_set::SheetSetMsg::Ok, + ), Some(crate::app::ModalKind::Field) => Message::FieldDialog( crate::ui::window::field_dialog::FieldDialogMsg::Ok, ), diff --git a/src/app/mod.rs b/src/app/mod.rs index 392e1bed1..1e75e477c 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -816,6 +816,13 @@ pub(super) struct OpenCADStudio { pub(crate) show_browser: bool, /// Point Cloud Manager palette (POINTCLOUDMANAGER). pub(crate) pc_manager: crate::ui::window::pc_manager::PcManager, + /// Sheet Set Manager palette, the open sheet sets and their dialogs. + pub(crate) sheet_set: crate::ui::window::sheet_set::SheetSetManager, + /// A sheet opened from the manager: its drawing (path key) and layout, + /// switched to once the drawing has loaded. + pub(crate) sheet_set_pending_layout: Option<(String, String)>, + /// The subset / set Import Layout as Sheet adds to, while its file picker is open. + pub(crate) sheet_set_import_parent: Option, /// Which viewport background the colour wheel is editing, or `None` when /// it is closed. One slot, because only one wheel can be open at a time. pub(crate) bg_picker: Option, @@ -1988,6 +1995,8 @@ pub enum ModalKind { GpuWarning, /// Reference Manager help window (toolbar Help button). XrefHelp, + /// Sheet set wizard, properties and sheet / subset forms. + SheetSet, } /// A property group controlled by a layer state's restore mask. @@ -3897,6 +3906,7 @@ pub enum Message { FieldDialog(crate::ui::window::field_dialog::FieldDialogMsg), /// A click or search in the Point Cloud Manager. PcManager(crate::ui::window::pc_manager::PcManagerMsg), + SheetSet(crate::ui::window::sheet_set::SheetSetMsg), PdfImportPickResult(Result<(std::path::PathBuf, std::sync::Arc>), String>), /// Result of the PDFATTACH file picker. PdfAttachPickResult(Result<(std::path::PathBuf, std::sync::Arc>), String>), @@ -4222,6 +4232,9 @@ impl OpenCADStudio { show_external_references: false, show_browser: false, pc_manager: Default::default(), + sheet_set: Default::default(), + sheet_set_pending_layout: None, + sheet_set_import_parent: None, bg_picker: None, block_palette: Default::default(), xref_manager: Default::default(), diff --git a/src/app/settings.rs b/src/app/settings.rs index 690114e91..f2a23cec7 100644 --- a/src/app/settings.rs +++ b/src/app/settings.rs @@ -612,6 +612,9 @@ pub struct UserSettings { /// BLOCKNAVIGATE (default "."). #[serde(default = "default_block_navigate")] pub block_navigate: String, + /// SSMAUTOOPEN, SSLOCATE, SSMPOLLTIME, SSMSHEETSTATUS. + #[serde(default)] + pub sheet_set: crate::ui::window::sheet_set::SheetSetSettings, } /// A block the Blocks palette lists from outside the current drawing (a @@ -851,6 +854,7 @@ impl Default for UserSettings { block_mru_list: 50, block_redefine_mode: 1, block_navigate: ".".to_string(), + sheet_set: Default::default(), } } } diff --git a/src/app/update/dialog.rs b/src/app/update/dialog.rs index 943ab3d4a..02de26082 100644 --- a/src/app/update/dialog.rs +++ b/src/app/update/dialog.rs @@ -606,6 +606,10 @@ pub(super) fn on_ribbon_tool_click(&mut self, tool_id: String, event: ModuleEven PanelId::PointCloudManager => { self.pc_manager.show = false; } + PanelId::SheetSetManager => { + self.sheet_set.show = false; + self.ribbon.set_sheet_set(false); + } PanelId::Properties => { self.show_properties = false; self.ribbon.set_properties(false); @@ -711,6 +715,7 @@ pub(super) fn on_ribbon_tool_click(&mut self, tool_id: String, event: ModuleEven PanelId::Browser => self.show_browser, PanelId::NodeGraph => self.show_node_graph, PanelId::PointCloudManager => self.pc_manager.show, + PanelId::SheetSetManager => self.sheet_set.show, } } diff --git a/src/app/update/file.rs b/src/app/update/file.rs index 2edd18786..c68ee8117 100644 --- a/src/app/update/file.rs +++ b/src/app/update/file.rs @@ -744,6 +744,7 @@ impl OpenCADStudio { block_mru_list: self.block_mru_list, block_redefine_mode: self.block_redefine_mode, block_navigate: self.block_navigate.clone(), + sheet_set: self.sheet_set.settings, } } @@ -874,6 +875,7 @@ impl OpenCADStudio { self.block_mru_list = s.block_mru_list.min(100); self.block_redefine_mode = s.block_redefine_mode.min(2); self.block_navigate = s.block_navigate.clone(); + self.sheet_set.settings = s.sheet_set; self.block_palette.recent = s.block_recent.clone(); self.block_palette.favorites = s.block_favorites.clone(); self.block_palette.libraries = s.block_libraries.clone(); @@ -2044,7 +2046,8 @@ impl OpenCADStudio { } else { Task::none() }; - Task::batch([thumbs_task, pending_open_task, interaction_task, startup_script_task]) + let sheet_set_task = self.sheet_set_after_open(i); + Task::batch([thumbs_task, pending_open_task, interaction_task, startup_script_task, sheet_set_task]) } pub(super) fn on_wblock_save_result_some( @@ -2149,6 +2152,7 @@ impl OpenCADStudio { self.tabs[i].scene.document.header.user_real1 = self.tabs[i].scene.annotation_scale as f64; self.sync_solid_models_for_save(i); self.tabs[i].scene.sync_native_parametric_graph(); + self.stamp_sheet_set_data(i); } #[cfg(not(target_arch = "wasm32"))] diff --git a/src/app/update/mod.rs b/src/app/update/mod.rs index fdcac3bea..cb4ad3500 100644 --- a/src/app/update/mod.rs +++ b/src/app/update/mod.rs @@ -1819,6 +1819,7 @@ impl OpenCADStudio { Message::AttdefDialog(message) => self.on_attdef_dialog(message), Message::FieldDialog(message) => self.on_field_dialog(message), Message::PcManager(message) => self.update_pc_manager(message), + Message::SheetSet(message) => self.on_sheet_set(message), Message::RibbonSelectTab(idx) => { self.ribbon.select(idx); Task::none() @@ -8521,6 +8522,10 @@ impl OpenCADStudio { } Message::CloseModal => { + if self.active_modal == Some(super::ModalKind::SheetSet) { + self.close_sheet_set_dialog(); + return Task::none(); + } if self.active_modal == Some(super::ModalKind::Field) { self.close_field_dialog(); return Task::none(); diff --git a/src/app/view/mod.rs b/src/app/view/mod.rs index ee8e0d7fc..f8b3ebc15 100644 --- a/src/app/view/mod.rs +++ b/src/app/view/mod.rs @@ -1888,6 +1888,7 @@ bg={bg_ms:.1}ms n={view_count}" crate::ui::dock::PanelId::Browser => self.show_browser, crate::ui::dock::PanelId::NodeGraph => self.show_node_graph, crate::ui::dock::PanelId::PointCloudManager => self.pc_manager.show, + crate::ui::dock::PanelId::SheetSetManager => self.sheet_set.show, } }; let edge_stack = |side: crate::app::config::DockSide| -> Option> { @@ -3030,6 +3031,9 @@ impl OpenCADStudio { width, auto_collapse, ), + crate::ui::dock::PanelId::SheetSetManager => { + crate::ui::window::sheet_set::view(&self.sheet_set, width, auto_collapse) + } }; let divider = dock_divider(id); match side { diff --git a/src/app/view/modal.rs b/src/app/view/modal.rs index d5f81eae6..5d1a51e6e 100644 --- a/src/app/view/modal.rs +++ b/src/app/view/modal.rs @@ -75,6 +75,7 @@ impl OpenCADStudio { Some(K::RecoveryPrompt) => crate::tr!("modal", "recovery-prompt"), Some(K::GpuWarning) => crate::tr!("gpu", "title"), Some(K::XrefHelp) => crate::t!("Reference Manager Help").into_owned(), + Some(K::SheetSet) => self.sheet_set.dialog.as_ref().map(|d| d.title()).unwrap_or_default(), None => String::new(), } } @@ -580,6 +581,14 @@ impl OpenCADStudio { let state = self.attdef_dialog.as_ref()?; sized_flow(ex, 720, 520, |flow| crate::ui::window::attdef_dialog::view(state, flow)) } + super::super::ModalKind::SheetSet => { + let (w, h) = match self.sheet_set.dialog.as_ref()? { + crate::ui::window::sheet_set::SsDialog::Wizard(_) => (720, 560), + crate::ui::window::sheet_set::SsDialog::Properties(_) => (640, 700), + crate::ui::window::sheet_set::SsDialog::Form(_) => (560, 420), + }; + sized_flow(ex, w, h, |flow| crate::ui::window::sheet_set::dialog_view(&self.sheet_set, flow)) + } super::super::ModalKind::Field => { let state = self.field_dialog.as_ref()?; sized_flow(ex, 760, 660, |flow| crate::ui::window::field_dialog::view(state, flow)) diff --git a/src/entities/field.rs b/src/entities/field.rs index c05b5ccb3..af7885e77 100644 --- a/src/entities/field.rs +++ b/src/entities/field.rs @@ -71,6 +71,14 @@ impl FieldContext for OcsFieldContext<'_> { os_date_locale() } + fn sheet_sets( + &self, + f: &mut dyn FnMut(&codec::sheet_set::SheetSetDatabase) -> Option, + ) -> Option { + let sets = SHEET_SETS.read().ok()?; + sets.iter().find_map(|db| f(db)) + } + fn getenv(&self, name: &str) -> Option { #[cfg(not(target_arch = "wasm32"))] { @@ -84,6 +92,16 @@ impl FieldContext for OcsFieldContext<'_> { } } +/// The sheet sets open in the Sheet Set Manager, for `\AcSm` fields. The +/// manager replaces the list whenever a set opens, closes or changes. +static SHEET_SETS: std::sync::RwLock> = std::sync::RwLock::new(Vec::new()); + +pub fn set_sheet_sets(sets: Vec) { + if let Ok(mut guard) = SHEET_SETS.write() { + *guard = sets; + } +} + /// Re-evaluate the field hosted by entity `host` (usually an MTEXT), or `None` /// to keep the cached text. Thin wrapper over the library engine. pub fn resolve(document: &CadDocument, host: Handle) -> Option { diff --git a/src/locale_catalog.rs b/src/locale_catalog.rs index 4ec7f0109..ec64e084c 100644 --- a/src/locale_catalog.rs +++ b/src/locale_catalog.rs @@ -3,6 +3,102 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static str)> { match source { + "Create Sheet Set" => Some(("view", "ss-create-sheet-set")), + "New Sheet" => Some(("view", "ss-new-sheet")), + "Subset Properties" => Some(("view", "ss-subset-properties")), + "Rename & Renumber Sheet" => Some(("view", "ss-rename-renumber-sheet")), + "Import Layout as Sheet" => Some(("view", "ss-import-layout-as-sheet")), + "Sheet Set Manager" => Some(("view", "ss-sheet-set-manager")), + "Open..." => Some(("view", "ss-open")), + "Open a sheet set or create one with NEWSHEETSET." => Some(("view", "ss-open-a-sheet-set-or-create-one-with-newsheetset")), + "No sheet views." => Some(("view", "ss-no-sheet-views")), + "No locations." => Some(("view", "ss-no-locations")), + "Double-click opens a sheet. Right-click for more commands." => Some(("view", "ss-double-click-opens-a-sheet-right-click-for-more-commands")), + "An empty sheet set" => Some(("view", "ss-an-empty-sheet-set")), + "Existing drawings" => Some(("view", "ss-existing-drawings")), + "Create a folder hierarchy based on subsets" => Some(("view", "ss-create-a-folder-hierarchy-based-on-subsets")), + "Sheet Set Properties..." => Some(("view", "ss-sheet-set-properties")), + "Select folders containing drawings. Layouts in the drawings can be added to the sheet set." => Some(("view", "ss-select-folders-containing-drawings-layouts-in-the-drawings-c")), + "Sheet Set" => Some(("view", "ss-sheet-set")), + "Sheet set data file" => Some(("view", "ss-sheet-set-data-file")), + "Sheets to import" => Some(("view", "ss-sheets-to-import")), + "Add Custom Property..." => Some(("view", "ss-add-custom-property")), + "New Sheet..." => Some(("view", "ss-new-sheet-x")), + "New Subset..." => Some(("view", "ss-new-subset")), + "Import Layout as Sheet..." => Some(("view", "ss-import-layout-as-sheet-x")), + "Rename & Renumber..." => Some(("view", "ss-rename-renumber")), + "Close Sheet Set" => Some(("view", "ss-close-sheet-set")), + "Properties..." => Some(("view", "ss-properties")), + "Sheet List" => Some(("view", "ss-sheet-list")), + "Sheet Views" => Some(("view", "ss-sheet-views")), + "Model Views" => Some(("view", "ss-model-views")), + "Views by sheet" => Some(("view", "ss-views-by-sheet")), + "Locations" => Some(("view", "ss-locations")), + "Create a sheet set using" => Some(("view", "ss-create-a-sheet-set-using")), + "Name of new sheet set:" => Some(("view", "ss-name-of-new-sheet-set")), + "Description (optional):" => Some(("view", "ss-description-optional")), + "Store sheet set data file (.dst) here:" => Some(("view", "ss-store-sheet-set-data-file-dst-here")), + "Choose Layouts" => Some(("view", "ss-choose-layouts")), + "Confirm" => Some(("view", "ss-confirm")), + "Default value:" => Some(("view", "ss-default-value")), + "Owner" => Some(("view", "ss-owner")), + "Custom Properties" => Some(("view", "ss-custom-properties")), + "Sheet title" => Some(("view", "ss-sheet-title")), + "Folder path" => Some(("view", "ss-folder-path")), + "Sheet template" => Some(("view", "ss-sheet-template")), + "Subset name" => Some(("view", "ss-subset-name")), + "New sheet location" => Some(("view", "ss-new-sheet-location")), + "Remove Subset" => Some(("view", "ss-remove-subset")), + "Remove Sheet" => Some(("view", "ss-remove-sheet")), + "Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set." => Some(("view", "ss-lets-you-specify-one-or-more-folders-containing-drawings-the")), + "Creates a sheet set with no subsets or sheets." => Some(("view", "ss-creates-a-sheet-set-with-no-subsets-or-sheets")), + "Open Sheet Set" => Some(("view", "ss-open-sheet-set")), + "Sheet Set (*.dst)" => Some(("view", "ss-sheet-set-dst")), + "Browse for Folder" => Some(("view", "ss-browse-for-folder")), + "Select Layout as Sheet Template" => Some(("view", "ss-select-layout-as-sheet-template")), + "Drawing Template (*.dwt)" => Some(("view", "ss-drawing-template-dwt")), + "Drawing (*.dwg)" => Some(("view", "ss-drawing-dwg")), + "The name cannot be empty." => Some(("view", "ss-the-name-cannot-be-empty")), + "A custom property with this name already exists." => Some(("view", "ss-a-custom-property-with-this-name-already-exists")), + "Sheet sets organize layouts from several drawings into one named set of sheets." => Some(("view", "ss-sheet-sets-organize-layouts-from-several-drawings-into-one-n")), + "(default new drawing)" => Some(("view", "ss-default-new-drawing")), + "Select Drawing" => Some(("view", "ss-select-drawing")), + "The sheet set name cannot be empty." => Some(("view", "ss-the-sheet-set-name-cannot-be-empty")), + "The folder for the sheet set data file does not exist." => Some(("view", "ss-the-folder-for-the-sheet-set-data-file-does-not-exist")), + "The drawing has no layout to use as a sheet template." => Some(("view", "ss-the-drawing-has-no-layout-to-use-as-a-sheet-template")), + "The subset name cannot be empty." => Some(("view", "ss-the-subset-name-cannot-be-empty")), + "The drawing has no layout to import." => Some(("view", "ss-the-drawing-has-no-layout-to-import")), + "The layout is already a sheet of this sheet set." => Some(("view", "ss-the-layout-is-already-a-sheet-of-this-sheet-set")), + "The sheet title cannot be empty." => Some(("view", "ss-the-sheet-title-cannot-be-empty")), + "The sheet folder cannot be created." => Some(("view", "ss-the-sheet-folder-cannot-be-created")), + "Sheet Set Properties" => Some(("view", "ss-sheet-set-properties-x")), + "Sheet Properties" => Some(("view", "ss-sheet-properties")), + "Sheet drawing not found: {}" => Some(("view", "ss-sheet-drawing-not-found")), + "{} already exists." => Some(("view", "ss-already-exists")), + "Model view" => Some(("view", "ss-model-view")), + "Label block for views" => Some(("view", "ss-label-block-for-views")), + "Callout blocks" => Some(("view", "ss-callout-blocks")), + "Page setup overrides file" => Some(("view", "ss-page-setup-overrides-file")), + "Project Control" => Some(("view", "ss-project-control")), + "Sheet Creation" => Some(("view", "ss-sheet-creation")), + "Sheet storage location" => Some(("view", "ss-sheet-storage-location")), + "Sheet creation template" => Some(("view", "ss-sheet-creation-template")), + "Prompt for template" => Some(("view", "ss-prompt-for-template")), + "Subset" => Some(("view", "ss-subset")), + "Layout name" => Some(("view", "ss-layout-name")), + "Drawing file" => Some(("view", "ss-drawing-file")), + "Project number" => Some(("view", "ss-project-number")), + "Project name" => Some(("view", "ss-project-name")), + "Project phase" => Some(("view", "ss-project-phase")), + "Project milestone" => Some(("view", "ss-project-milestone")), + "Revision number" => Some(("view", "ss-revision-number")), + "Revision date" => Some(("view", "ss-revision-date")), + "Issue purpose" => Some(("view", "ss-issue-purpose")), + "Custom property name" => Some(("view", "ss-custom-property-name")), + "Placeholder type" => Some(("view", "ss-placeholder-type")), + "Sheet set" => Some(("view", "ss-sheet-set-x")), + "Sheet navigation tree" => Some(("view", "ss-sheet-navigation-tree")), + "SheetSet" => Some(("view", "ss-sheetset")), "Entire drawing" => Some(("common", "entire-drawing")), "Delete from drawing" => Some(("common", "delete-from-drawing")), "Destination" => Some(("common", "destination")), diff --git a/src/modules/view/sheetset.rs b/src/modules/view/sheetset.rs index c15680237..d5f582dfb 100644 --- a/src/modules/view/sheetset.rs +++ b/src/modules/view/sheetset.rs @@ -5,6 +5,6 @@ pub fn tool() -> ToolDef { id: "SHEETSET", label: "Sheet Set\nManager", icon: ICON, - event: ModuleEvent::Command("SHEETSET".to_string()), + event: ModuleEvent::Command("_SSMTOGGLE".to_string()), } } diff --git a/src/ui/dock.rs b/src/ui/dock.rs index 1e62a58cf..958b1ca85 100644 --- a/src/ui/dock.rs +++ b/src/ui/dock.rs @@ -48,6 +48,8 @@ pub enum PanelId { NodeGraph, /// Regions and scans of the drawing's point clouds. PointCloudManager, + /// The open sheet sets: subsets and sheets. + SheetSetManager, } impl PanelId { @@ -60,6 +62,7 @@ impl PanelId { PanelId::Browser => "Browser", PanelId::NodeGraph => "Node Graph", PanelId::PointCloudManager => "Point Cloud Manager", + PanelId::SheetSetManager => "Sheet Set Manager", } } @@ -72,6 +75,7 @@ impl PanelId { PanelId::Browser => 230.0, PanelId::NodeGraph => 220.0, PanelId::PointCloudManager => 280.0, + PanelId::SheetSetManager => 280.0, } } @@ -162,6 +166,7 @@ impl DockState { PanelId::Browser, PanelId::NodeGraph, PanelId::PointCloudManager, + PanelId::SheetSetManager, ] { self.panels.entry(id).or_insert_with(|| DockPanel::for_id(id)); } diff --git a/src/ui/ribbon/mod.rs b/src/ui/ribbon/mod.rs index 20989bd37..fe14d1e54 100644 --- a/src/ui/ribbon/mod.rs +++ b/src/ui/ribbon/mod.rs @@ -57,6 +57,8 @@ pub struct Ribbon { pub show_ucs_icon: bool, /// Properties panel (PROPERTIES) visibility — drives the Properties button highlight. pub show_properties: bool, + /// Sheet Set Manager palette shown (SSMSTATE). + pub show_sheet_set: bool, /// File tabs (FILETAB) visibility — drives the File Tabs button highlight. pub show_file_tabs: bool, /// Layout tabs (LAYOUTTAB) visibility — drives the Layout Tabs button highlight. @@ -173,6 +175,7 @@ impl Ribbon { show_viewcube: true, show_ucs_icon: true, show_properties: true, + show_sheet_set: false, show_file_tabs: true, show_layout_tabs: true, open_dropdown: None, @@ -330,6 +333,9 @@ impl Ribbon { pub fn set_properties(&mut self, on: bool) { self.show_properties = on; } + pub fn set_sheet_set(&mut self, on: bool) { + self.show_sheet_set = on; + } pub fn set_file_tabs(&mut self, on: bool) { self.show_file_tabs = on; } @@ -348,6 +354,7 @@ impl Ribbon { show_ucs_icon: self.show_ucs_icon, show_properties: self.show_properties, show_block_palette, + show_sheet_set: self.show_sheet_set, show_file_tabs: self.show_file_tabs, show_layout_tabs: self.show_layout_tabs, } diff --git a/src/ui/ribbon/widgets.rs b/src/ui/ribbon/widgets.rs index 74e7d9393..ef3230b66 100644 --- a/src/ui/ribbon/widgets.rs +++ b/src/ui/ribbon/widgets.rs @@ -38,6 +38,7 @@ pub(super) struct ToggleState { pub show_ucs_icon: bool, pub show_properties: bool, pub show_block_palette: bool, + pub show_sheet_set: bool, pub show_file_tabs: bool, pub show_layout_tabs: bool, } @@ -380,6 +381,7 @@ pub(super) fn is_active_tool( "UCSICON" => state.show_ucs_icon, "PROPERTIES" => state.show_properties, "BLOCKPALETTE" => state.show_block_palette, + "SHEETSET" => state.show_sheet_set, "FILETAB" => state.show_file_tabs, "LAYOUTTAB" => state.show_layout_tabs, id => active_tool.as_deref() == Some(id), diff --git a/src/ui/window/field_dialog.rs b/src/ui/window/field_dialog.rs index 0d76b6816..55fa8c911 100644 --- a/src/ui/window/field_dialog.rs +++ b/src/ui/window/field_dialog.rs @@ -38,8 +38,83 @@ pub const CATEGORIES: &[(&str, &[&str])] = &[ "Plot", &["DeviceName", "Login", "PageSetupName", "PaperSize", "PlotDate", "PlotOrientation", "PlotScale", "PlotStyleTable"], ), + ("SheetSet", SHEET_SET_FIELDS), ]; +/// The SheetSet category, in the reference's order. +pub const SHEET_SET_FIELDS: &[&str] = &[ + "CurrentSheetCategory", + "CurrentSheetCustom", + "CurrentSheetDescription", + "CurrentSheetIssuePurpose", + "CurrentSheetNumber", + "CurrentSheetNumberAndTitle", + "CurrentSheetRevisionDate", + "CurrentSheetRevisionNumber", + "CurrentSheetSet", + "CurrentSheetSetCustom", + "CurrentSheetSetDescription", + "CurrentSheetSetProjectMilestone", + "CurrentSheetSetProjectName", + "CurrentSheetSetProjectNumber", + "CurrentSheetSetProjectPhase", + "CurrentSheetSubSet", + "CurrentSheetTitle", + "SheetSet", + "SheetSetPlaceholder", + "SheetView", +]; + +/// A sheet set field's code without format: `\AcSm[.16.2] Component.Property`. +fn sheet_set_code(name: &str, custom: &str) -> String { + let (version, target) = match name { + "CurrentSheetCategory" => (".16.2", "Sheet.Category".to_string()), + "CurrentSheetCustom" => ("", format!("Sheet.{custom}")), + "CurrentSheetDescription" => ("", "Sheet.Description".into()), + "CurrentSheetIssuePurpose" => (".16.2", "Sheet.IssuePurpose".into()), + "CurrentSheetNumber" => ("", "Sheet.Number".into()), + "CurrentSheetNumberAndTitle" => ("", "Sheet.NumberAndTitle".into()), + "CurrentSheetRevisionDate" => (".16.2", "Sheet.RevisionDate".into()), + "CurrentSheetRevisionNumber" => (".16.2", "Sheet.RevisionNumber".into()), + "CurrentSheetSet" => ("", "SheetSet.Name".into()), + "CurrentSheetSetCustom" => ("", format!("SheetSet.{custom}")), + "CurrentSheetSetDescription" => ("", "SheetSet.Description".into()), + "CurrentSheetSetProjectMilestone" => (".16.2", "SheetSet.ProjectMilestone".into()), + "CurrentSheetSetProjectName" => (".16.2", "SheetSet.ProjectName".into()), + "CurrentSheetSetProjectNumber" => (".16.2", "SheetSet.ProjectNumber".into()), + "CurrentSheetSetProjectPhase" => (".16.2", "SheetSet.ProjectPhase".into()), + "CurrentSheetSubSet" => ("", "Subset.Name".into()), + "CurrentSheetTitle" => ("", "Sheet.Title".into()), + _ => return "\\AcSm".into(), + }; + format!("\\AcSm{version} {target}") +} + +/// SheetSetPlaceholder types: list label, the `?` target, field version. +pub const PLACEHOLDER_TYPES: &[(&str, &str, &str)] = &[ + ("SheetNumberAndTitle", "?Sheet.NumberAndTitle", ""), + ("SheetTitle", "?Sheet.Title", ""), + ("SheetNumber", "?Sheet.Number", ""), + ("SheetDescription", "?Sheet.Description", ""), + ("RevisionNumber", "?Sheet.RevisionNumber", ".16.2"), + ("RevisionDate", "?Sheet.RevisionDate", ".16.2"), + ("IssuePurpose", "?Sheet.IssuePurpose", ".16.2"), + ("Category", "?Sheet.Category", ".16.2"), + ("Custom", "?Sheet.", ""), + ("ViewNumberAndTitle", "?View.NumberAndTitle", ""), + ("ViewTitle", "?View.Title", ""), + ("ViewNumber", "?View.Number", ""), + ("ViewportScale", "?View.ViewportScale", ".16.2"), +]; + +/// ViewportScale placeholder formats: the PlotScale pictures. +pub fn viewport_scale_picture(k: usize) -> String { + codec::fields::PLOT_SCALE_FORMATS + .get(k) + .and_then(|(_, code)| code.find("\\f ").map(|p| code[p..].to_string())) + .unwrap_or_default() +} + /// The fields of a category; "All" lists every field once, sorted. pub fn fields_of(category: usize) -> Vec<&'static str> { if category == 0 { @@ -77,6 +152,13 @@ pub enum FieldKind { Formula, Hyperlink, PlotScale, + /// A CurrentSheet* / CurrentSheetSet* field (text case). + SheetSet, + /// CurrentSheetCustom / CurrentSheetSetCustom (text case + property). + SheetSetCustom, + SheetSetPlaceholder, + /// SheetSet / SheetView: a component picked in a sheet set. + SheetSetNavigation, } /// Formula precisions: the current one, then 0 to 8 decimals. @@ -95,6 +177,10 @@ pub fn kind_of(name: &str) -> FieldKind { "Formula" => FieldKind::Formula, "Hyperlink" => FieldKind::Hyperlink, "PlotScale" => FieldKind::PlotScale, + "CurrentSheetCustom" | "CurrentSheetSetCustom" => FieldKind::SheetSetCustom, + "SheetSetPlaceholder" => FieldKind::SheetSetPlaceholder, + "SheetSet" | "SheetView" => FieldKind::SheetSetNavigation, + n if SHEET_SET_FIELDS.contains(&n) => FieldKind::SheetSet, _ => FieldKind::Text, } } @@ -129,6 +215,16 @@ pub struct FieldDialogState { /// Index into codec PLOT_SCALE_FORMATS. pub plot_scale: usize, pub preview: String, + /// Sheet set fields: the open set's sheet (flags 2) and set (flags 1) + /// custom property names, the chosen one, the placeholder type and the + /// ViewportScale format. + pub ss_sheet_custom: Vec, + pub ss_set_custom: Vec, + pub ss_custom: String, + pub ss_placeholder: usize, + pub ss_scale_format: usize, + /// The open sheet set's name (SheetSet / SheetView fields). + pub ss_set_name: String, /// Today in each of DATE_FORMATS, for the Examples list. pub examples: Vec, } @@ -159,6 +255,12 @@ impl FieldDialogState { hyperlink_url: String::new(), plot_scale: 0, preview: String::new(), + ss_sheet_custom: Vec::new(), + ss_set_custom: Vec::new(), + ss_custom: String::new(), + ss_placeholder: 0, + ss_scale_format: 6, + ss_set_name: String::new(), examples: Vec::new(), } } @@ -211,6 +313,21 @@ impl FieldDialogState { .map_or_else(|| "\\AcVar PlotScale".to_string(), |f| f.1.to_string()), vec![], ), + FieldKind::SheetSet | FieldKind::SheetSetCustom => (case(sheet_set_code(self.name, &self.ss_custom)), vec![]), + FieldKind::SheetSetNavigation => ("\\AcSm".into(), vec![]), + FieldKind::SheetSetPlaceholder => { + let (label, target, version) = PLACEHOLDER_TYPES[self.ss_placeholder.min(PLACEHOLDER_TYPES.len() - 1)]; + let target = if label == "Custom" { format!("{target}{}", self.ss_custom) } else { target.to_string() }; + let base = format!("\\AcSm{version} {target}"); + if label == "ViewportScale" { + match viewport_scale_picture(self.ss_scale_format) { + f if f.is_empty() => (base, vec![]), + f => (format!("{base} {f}"), vec![]), + } + } else { + (case(base), vec![]) + } + } FieldKind::SystemVariable => (format!("\\AcVar {}", self.sysvar), vec![]), FieldKind::Diesel => (format!("\\AcDiesel {}", self.diesel), vec![]), FieldKind::NamedObject => match self.named.and_then(|i| self.named_names.get(i)) { @@ -278,6 +395,9 @@ pub enum FieldDialogMsg { HyperlinkUrl(String), BrowseHyperlink, PlotScale(usize), + SsCustom(String), + SsPlaceholder(usize), + SsScaleFormat(usize), Help, Ok, } @@ -542,6 +662,72 @@ fn format_panel<'a>(state: &'a FieldDialogState) -> Element<'a, Message> { ] .spacing(8) .into(), + FieldKind::SheetSet => column![text(t!("Format")).size(12), case_list(state)].spacing(8).into(), + FieldKind::SheetSetCustom => { + let names = if state.name == "CurrentSheetCustom" { &state.ss_sheet_custom } else { &state.ss_set_custom }; + column![ + text(t!("Format")).size(12), + case_list(state), + text(t!("Custom property name")).size(12), + pick_list( + (!state.ss_custom.is_empty()).then(|| state.ss_custom.clone()), + names.clone(), + |s: &String| s.clone(), + ) + .on_select(|s| msg(FieldDialogMsg::SsCustom(s))) + .text_size(12) + .padding([5, 8]) + .width(Fill), + ] + .spacing(8) + .into() + } + FieldKind::SheetSetPlaceholder => { + let kind = PLACEHOLDER_TYPES[state.ss_placeholder.min(PLACEHOLDER_TYPES.len() - 1)].0; + let types = list( + PLACEHOLDER_TYPES + .iter() + .enumerate() + .map(|(i, (n, _, _))| (n.to_string(), state.ss_placeholder == i, FieldDialogMsg::SsPlaceholder(i))) + .collect(), + 200.0, + ); + let format: Element<'a, Message> = if kind == "ViewportScale" { + list( + codec::fields::PLOT_SCALE_FORMATS + .iter() + .enumerate() + .map(|(i, (n, _))| (t!(*n).into_owned(), state.ss_scale_format == i, FieldDialogMsg::SsScaleFormat(i))) + .collect(), + 170.0, + ) + } else { + case_list(state) + }; + let mut col = column![text(t!("Placeholder type")).size(12), types, text(t!("Format")).size(12), format].spacing(8); + if kind == "Custom" { + col = col.push(text(t!("Custom property name")).size(12)).push( + pick_list( + (!state.ss_custom.is_empty()).then(|| state.ss_custom.clone()), + state.ss_sheet_custom.clone(), + |s: &String| s.clone(), + ) + .on_select(|s| msg(FieldDialogMsg::SsCustom(s))) + .text_size(12) + .padding([5, 8]) + .width(Fill), + ); + } + col.into() + } + FieldKind::SheetSetNavigation => column![ + text(t!("Sheet set")).size(12), + container(text(state.ss_set_name.clone()).size(12).style(muted_style)).padding([5, 8]).width(Fill), + text(t!("Sheet navigation tree")).size(12), + container(Space::new()).height(Length::Fixed(120.0)), + ] + .spacing(8) + .into(), FieldKind::Object => column![ row![ text(t!("Object type")).size(12).width(Length::Fixed(96.0)), diff --git a/src/ui/window/mod.rs b/src/ui/window/mod.rs index 3b3282d0f..7497baed3 100644 --- a/src/ui/window/mod.rs +++ b/src/ui/window/mod.rs @@ -27,6 +27,7 @@ pub mod alias_editor; pub mod find_replace; pub mod named_parameters; pub mod pc_manager; +pub mod sheet_set; pub mod pdf_dialogs; pub mod xref_attach; pub mod xref_help; diff --git a/src/ui/window/sheet_set.rs b/src/ui/window/sheet_set.rs new file mode 100644 index 000000000..690de72dc --- /dev/null +++ b/src/ui/window/sheet_set.rs @@ -0,0 +1,968 @@ +//! Sheet Set Manager (SHEETSET): the open sheet sets as a tree of subsets +//! and sheets, the New Sheet Set wizard (NEWSHEETSET), the Sheet Set / +//! Subset / Sheet Properties dialog and the small New Sheet, New Subset, +//! Import Layout and Rename & Renumber forms. The tree is read from the +//! sheet set database (`.dst`) itself on every view. + +use crate::app::Message; +use crate::t; +use crate::ui::dock::PanelId; +use crate::ui::style::common::muted_style; +use crate::ui::style::form::{button_style, dialog_button, field_style}; +use crate::ui::window::pdf_dialogs::{accent_text, card_style}; +use codec::sheet_set::{self as ss, ComponentKind, Element as SsElement, SheetSetDatabase}; +use iced::widget::{ + button, checkbox, column, container, mouse_area, pick_list, row, scrollable, text, text_input, Space, +}; +use iced::{Background, Border, Element, Fill, Length, Theme}; +use serde::{Deserialize, Serialize}; +use std::collections::HashSet; + +const SET_ICON: &[u8] = include_bytes!("../../../assets/icons/sheetset.svg"); + +/// SSMAUTOOPEN, SSLOCATE, SSMPOLLTIME and SSMSHEETSTATUS: profile settings. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(default)] +pub struct SheetSetSettings { + pub auto_open: u8, + pub locate: u8, + pub poll_time: u16, + pub sheet_status: u8, +} + +impl Default for SheetSetSettings { + fn default() -> Self { + Self { auto_open: 1, locate: 1, poll_time: 60, sheet_status: 2 } + } +} + +/// The palette's three pages. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub enum SsmTab { + #[default] + SheetList, + SheetViews, + ModelViews, +} + +/// The palette and the open sheet sets. +#[derive(Debug, Default)] +pub struct SheetSetManager { + pub show: bool, + pub settings: SheetSetSettings, + /// Open sheet sets (each read from its `.dst`). + pub sets: Vec, + /// The set the palette shows. + pub current: Option, + pub tab: SsmTab, + /// Folded subset / set ids. + pub collapsed: HashSet, + /// Highlighted component id. + pub selected: Option, + /// SSFOUND: the `.dst` the last opened sheet drawing named, when found. + pub found: String, + /// The open dialog (shown in the `SheetSet` modal). + pub dialog: Option, +} + +impl SheetSetManager { + pub fn db(&self) -> Option<&SheetSetDatabase> { + self.sets.get(self.current?) + } + + pub fn db_mut(&mut self) -> Option<&mut SheetSetDatabase> { + self.sets.get_mut(self.current?) + } +} + +/// Right-click commands of a tree row. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum MenuAction { + Open, + NewSheet, + NewSubset, + ImportLayout, + Rename, + Remove, + Properties, + Close, +} + +#[derive(Debug, Clone)] +pub enum SheetSetMsg { + /// The set combo: a set by index, or `None` for "Open...". + PickSet(Option), + Tab(SsmTab), + Expand(String), + Select(String), + /// Double-click: open the sheet's drawing at its layout. + Activate(String), + Menu(String, MenuAction), + Refresh, + /// A `.dst` picked by Open (or given by automation). + OpenPicked(Option), + /// A drawing picked by Import Layout as Sheet. + ImportPicked(Option), + /// A folder picked for a dialog field. + FolderPicked(FieldId, Option), + /// A template drawing picked for a sheet creation template. + TemplatePicked(Option), + Browse(FieldId), + BrowseTemplate, + /// Edit a text field of the open dialog. + Input(FieldId, String), + Toggle(FieldId, bool), + Choose(FieldId, usize), + Wizard(WizardMsg), + /// Open the Properties dialog from the wizard. + WizardProperties, + AddCustom, + AddCustomOk, + AddCustomCancel, + /// A custom property row's value. + CustomValue(usize, String), + Ok, + Cancel, + Help, +} + +#[derive(Debug, Clone)] +pub enum WizardMsg { + Step(u8), + Existing(bool), + /// Toggle one drawing layout of the "existing drawings" page. + LayoutOn(usize, bool), + RemoveFolder(usize), +} + +/// Text fields, toggles and lists of the dialogs. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum FieldId { + /// A Properties row by index. + Row(usize), + Name, + Description, + Folder, + Hierarchy, + Number, + Title, + FileName, + /// The layout list of Import Layout as Sheet. + Layout, + /// Add Custom Property: name, default value, owner (0 set, 1 sheet). + CustomName, + CustomDefault, + CustomOwner, + /// A wizard "existing drawings" folder to add. + AddFolder, + /// Prompt for template (Properties). + PromptTemplate, +} + +/// What a Properties row edits. +#[derive(Debug, Clone, PartialEq)] +pub enum RowKey { + /// An `AcSmProp` of the component. + Prop(&'static str), + /// A file reference property (`NewSheetLocation`). + Folder(&'static str), + /// The sheet creation template (`DefDwtLayout`): the value shows + /// `Layout (file)`; `template` holds the picked drawing and layout. + Template, + /// Yes / No: prompt for template. + PromptTemplate, + /// Shown only. + ReadOnly, +} + +#[derive(Debug, Clone)] +pub struct PropRow { + pub group: &'static str, + pub label: &'static str, + pub key: RowKey, + pub value: String, +} + +/// The Sheet Set / Subset / Sheet Properties dialog. +#[derive(Debug, Clone)] +pub struct Properties { + /// `None` edits the wizard's draft set. + pub set: Option, + pub component: String, + pub kind: ComponentKind, + pub title: String, + pub rows: Vec, + /// Name, value, flags. + pub custom: Vec<(String, String, i32)>, + /// Add Custom Property being filled: name, default value, owner is sheet. + pub adding: Option<(String, String, bool)>, + /// The template picked in this dialog: drawing and layout. + pub template: Option<(String, String)>, + /// Back to the wizard on OK / Cancel. + pub wizard: Option>, + pub error: Option, +} + +/// One layout found by the "existing drawings" wizard page. +#[derive(Debug, Clone)] +pub struct FoundLayout { + pub folder: String, + pub file: String, + pub layout: String, + pub handle: String, + pub on: bool, +} + +/// NEWSHEETSET. +#[derive(Debug, Clone)] +pub struct Wizard { + /// 0 Begin, 1 Sheet Set Details, 2 Choose Layouts (existing drawings), 3 Confirm. + pub step: u8, + pub existing: bool, + pub name: String, + pub description: String, + pub folder: String, + pub hierarchy: bool, + pub folders: Vec, + pub layouts: Vec, + /// The set being built: name, description, properties and custom + /// properties go into it; Finish writes it. + pub draft: SheetSetDatabase, + pub error: Option, +} + +/// New Sheet, New Subset, Rename & Renumber and Import Layout as Sheet. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum FormKind { + NewSheet, + NewSubset, + Rename, + ImportLayout, +} + +#[derive(Debug, Clone)] +pub struct Form { + pub kind: FormKind, + pub set: usize, + /// Parent (new sheet / subset / import) or the sheet / subset renamed. + pub component: String, + pub number: String, + pub title: String, + pub file_name: String, + pub folder: String, + /// Import: the drawing and its layouts (name, handle). + pub drawing: String, + pub layouts: Vec<(String, String)>, + pub layout: usize, + pub error: Option, +} + +#[derive(Debug, Clone)] +pub enum SsDialog { + Wizard(Wizard), + Properties(Properties), + Form(Form), +} + +impl SsDialog { + pub fn title(&self) -> String { + match self { + SsDialog::Wizard(_) => t!("Create Sheet Set").into_owned(), + SsDialog::Properties(p) => p.title.clone(), + SsDialog::Form(f) => match f.kind { + FormKind::NewSheet => t!("New Sheet").into_owned(), + FormKind::NewSubset => t!("Subset Properties").into_owned(), + FormKind::Rename => t!("Rename & Renumber Sheet").into_owned(), + FormKind::ImportLayout => t!("Import Layout as Sheet").into_owned(), + }, + } + } +} + +fn msg(m: SheetSetMsg) -> Message { + Message::SheetSet(m) +} + +// ── palette ────────────────────────────────────────────────────────────────── + +#[derive(Debug, Clone, PartialEq, Eq)] +struct Pick(Option, String); + +impl std::fmt::Display for Pick { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(&self.1) + } +} + +fn menu_entry(label: String, m: Option) -> Element<'static, Message> { + button(text(label).size(12)) + .width(Fill) + .padding([5, 12]) + .on_press_maybe(m) + .style(|theme: &Theme, status| { + let mut s = button::text(theme, status); + if matches!(status, button::Status::Hovered) { + s.background = Some(Background::Color(theme.palette().primary.base.color)); + s.text_color = theme.palette().primary.base.text; + } + s + }) + .into() +} + +fn menu_separator() -> Element<'static, Message> { + container(Space::new()) + .height(1) + .width(Fill) + .style(|theme: &Theme| container::Style { + background: Some(Background::Color(theme.palette().background.neutral.color)), + ..Default::default() + }) + .into() +} + +/// A row's right-click menu. +fn row_menu(id: String, kind: ComponentKind) -> Element<'static, Message> { + let entry = |label: &str, action: MenuAction, on: bool| { + menu_entry(t!(label).into_owned(), on.then(|| msg(SheetSetMsg::Menu(id.clone(), action)))) + }; + let sheet = kind == ComponentKind::Sheet; + let mut items = vec![ + entry("Open", MenuAction::Open, sheet), + menu_separator(), + entry("New Sheet...", MenuAction::NewSheet, !sheet), + entry("New Subset...", MenuAction::NewSubset, !sheet), + entry("Import Layout as Sheet...", MenuAction::ImportLayout, !sheet), + menu_separator(), + entry("Rename & Renumber...", MenuAction::Rename, sheet), + entry(if kind == ComponentKind::Subset { "Remove Subset" } else { "Remove Sheet" }, MenuAction::Remove, kind != ComponentKind::SheetSet), + ]; + if kind == ComponentKind::SheetSet { + items.push(entry("Close Sheet Set", MenuAction::Close, true)); + } + items.push(menu_separator()); + items.push(entry("Properties...", MenuAction::Properties, true)); + container(iced::widget::Column::with_children(items).spacing(1)) + .padding(4) + .width(Length::Fixed(220.0)) + .style(|theme: &Theme| container::Style { + background: Some(Background::Color(theme.palette().background.weak.color)), + border: Border { color: theme.palette().background.neutral.color, width: 1.0, radius: 4.0.into() }, + ..Default::default() + }) + .into() +} + +fn tree_row<'a>( + state: &SheetSetManager, + el: &SsElement, + depth: u16, + icon: &'static [u8], + label: String, + fold: Option, +) -> Element<'a, Message> { + let id = el.id().to_string(); + let kind = ComponentKind::of(el).unwrap_or(ComponentKind::Sheet); + let arrow: Element<'a, Message> = match fold { + Some(open) => button(if open { + crate::ui::icons::themed_arrow_down(10.0) + } else { + crate::ui::icons::themed_arrow_right(10.0) + }) + .on_press(msg(SheetSetMsg::Expand(id.clone()))) + .style(button::text) + .padding(2) + .into(), + None => Space::new().width(14).into(), + }; + let selected = state.selected.as_deref() == Some(id.as_str()); + let cells = row![ + Space::new().width(Length::Fixed(f32::from(depth) * 16.0)), + arrow, + crate::ui::icons::semantic(icon, 14.0), + text(label).size(12).width(Fill), + ] + .spacing(5) + .align_y(iced::Center); + let area = mouse_area(container(cells).width(Fill).padding([3, 6]).style(move |theme: &Theme| container::Style { + background: selected.then(|| Background::Color(theme.palette().primary.weak.color)), + text_color: selected.then(|| theme.palette().primary.weak.text), + ..Default::default() + })) + .on_press(msg(SheetSetMsg::Select(id.clone()))) + .on_double_click(msg(SheetSetMsg::Activate(id.clone()))); + iced_aw::ContextMenu::new(area, move || row_menu(id.clone(), kind)).into() +} + +fn push_tree<'a>( + state: &SheetSetManager, + el: &SsElement, + depth: u16, + out: &mut Vec>, +) { + for c in &el.children { + match ComponentKind::of(c) { + Some(ComponentKind::Subset) => { + let open = !state.collapsed.contains(c.id()); + out.push(tree_row(state, c, depth, crate::ui::icons::FOLDER_OPEN, c.prop("Name").unwrap_or("").to_string(), Some(open))); + if open { + push_tree(state, c, depth + 1, out); + } + } + Some(ComponentKind::Sheet) => { + out.push(tree_row(state, c, depth, crate::ui::icons::DOC, ss::number_and_title(c), None)); + } + _ => {} + } + } +} + +/// Sheet views of the set: each sheet's `AcSmSheetView` children. +fn sheet_views(db: &SheetSetDatabase) -> Vec { + db.sheets() + .into_iter() + .flat_map(|sheet| { + sheet + .named("SheetViews") + .map(|v| v.children.iter().filter(|c| c.name == "AcSmSheetView").collect::>()) + .unwrap_or_default() + .into_iter() + .map(|v| { + let number = v.prop("Number").unwrap_or(""); + let title = v.prop("Title").unwrap_or(""); + if number.is_empty() { title.to_string() } else { format!("{number} - {title}") } + }) + }) + .collect() +} + +/// Model view locations (`Resources`) of the set. +fn model_views(db: &SheetSetDatabase) -> Vec { + db.sheet_set() + .named("Resources") + .map(|r| r.children.iter().map(|c| db.resolve_file(c)).collect()) + .unwrap_or_default() +} + +fn heading(label: &str) -> Element<'static, Message> { + text(t!(label).into_owned()) + .size(11) + .font(iced::Font { weight: iced::font::Weight::Bold, ..iced::Font::DEFAULT }) + .style(|theme: &Theme| text::Style { color: Some(theme.palette().primary.base.color) }) + .width(Fill) + .into() +} + +pub fn view<'a>(state: &'a SheetSetManager, width: f32, auto_collapse: bool) -> Element<'a, Message> { + let title_bar = + crate::ui::dock::title_bar(PanelId::SheetSetManager, t!("Sheet Set Manager").into_owned(), auto_collapse); + let mut picks: Vec = + state.sets.iter().enumerate().map(|(i, db)| Pick(Some(i), db.name().to_string())).collect(); + picks.push(Pick(None, t!("Open...").into_owned())); + let current = state.current.and_then(|i| picks.get(i).cloned()); + let combo = pick_list(current, picks, |p: &Pick| p.1.clone()) + .placeholder(t!("Open...").into_owned()) + .on_select(|p: Pick| msg(SheetSetMsg::PickSet(p.0))) + .text_size(12) + .padding([5, 8]) + .width(Fill); + let tab = |label: &str, t: SsmTab| { + button(text(t!(label).into_owned()).size(11).center().width(Fill)) + .on_press(msg(SheetSetMsg::Tab(t))) + .style(button_style(state.tab == t)) + .padding([5, 4]) + .width(Fill) + }; + let tabs = row![ + tab("Sheet List", SsmTab::SheetList), + tab("Sheet Views", SsmTab::SheetViews), + tab("Model Views", SsmTab::ModelViews), + ] + .spacing(2); + + let body: Element<'a, Message> = match (state.db(), state.tab) { + (None, _) => text(t!("Open a sheet set or create one with NEWSHEETSET.").into_owned()) + .size(12) + .style(muted_style) + .into(), + (Some(db), SsmTab::SheetList) => { + let set = db.sheet_set(); + let open = !state.collapsed.contains(set.id()); + let mut rows = vec![tree_row(state, set, 0, SET_ICON, db.name().to_string(), Some(open))]; + if open { + push_tree(state, set, 1, &mut rows); + } + let header = row![ + heading("Sheets"), + button(text("↻").size(13)) + .on_press(msg(SheetSetMsg::Refresh)) + .style(button::subtle) + .padding([2, 4]), + ] + .align_y(iced::Center); + column![header, scrollable(iced::widget::Column::with_children(rows).spacing(1)).height(Fill)] + .spacing(6) + .into() + } + (Some(db), SsmTab::SheetViews) => { + let views = sheet_views(db); + let list: Element<'a, Message> = if views.is_empty() { + text(t!("No sheet views.").into_owned()).size(12).style(muted_style).into() + } else { + iced::widget::Column::with_children(views.into_iter().map(|v| text(v).size(12).into())).spacing(3).into() + }; + column![heading("Views by sheet"), list].spacing(6).into() + } + (Some(db), SsmTab::ModelViews) => { + let locations = model_views(db); + let list: Element<'a, Message> = if locations.is_empty() { + text(t!("No locations.").into_owned()).size(12).style(muted_style).into() + } else { + iced::widget::Column::with_children(locations.into_iter().map(|v| text(v).size(12).into())) + .spacing(3) + .into() + }; + column![heading("Locations"), list].spacing(6).into() + } + }; + let card = container(body).padding(6).width(Fill).height(Fill).style(|theme: &Theme| container::Style { + background: Some(Background::Color(theme.palette().background.weak.color)), + border: Border { radius: 4.0.into(), ..Default::default() }, + ..Default::default() + }); + let hint = text(t!("Double-click opens a sheet. Right-click for more commands.").into_owned()) + .size(10) + .style(muted_style); + crate::ui::dock::frame(column![title_bar, combo, tabs, card, hint].spacing(6), width) +} + +// ── dialogs ────────────────────────────────────────────────────────────────── + +fn card<'a>(title: &str, content: impl Into>) -> Element<'a, Message> { + container(column![text(t!(title).to_uppercase()).size(10).style(accent_text), content.into()].spacing(8)) + .padding([10, 12]) + .width(Fill) + .style(card_style) + .into() +} + +fn input<'a>(value: &str, field: FieldId) -> Element<'a, Message> { + text_input("", value) + .size(12) + .padding([5, 8]) + .style(field_style) + .on_input(move |v| msg(SheetSetMsg::Input(field, v))) + .into() +} + +fn labeled<'a>(label: &str, control: impl Into>) -> Element<'a, Message> { + row![text(t!(label).into_owned()).size(12).width(Length::Fixed(170.0)), control.into()] + .spacing(8) + .align_y(iced::Center) + .into() +} + +fn browse<'a>(m: SheetSetMsg) -> Element<'a, Message> { + button(text("...").size(12)).on_press(msg(m)).style(button_style(false)).padding([5, 10]).into() +} + +fn error_band<'a>(error: &Option) -> Option> { + error.as_ref().map(|e| { + container(text(e.clone()).size(12)) + .padding([6, 10]) + .width(Fill) + .style(|theme: &Theme| container::Style { + background: Some(Background::Color(theme.palette().danger.weak.color)), + text_color: Some(theme.palette().danger.weak.text), + border: Border { radius: 4.0.into(), ..Default::default() }, + ..Default::default() + }) + .into() + }) +} + +fn footer<'a>(left: Vec>, right: Vec>) -> Element<'a, Message> { + let mut r = row![button(text("?").size(12)).on_press(msg(SheetSetMsg::Help)).style(button_style(false)).padding([5, 11])] + .spacing(6) + .align_y(iced::Center); + for e in left { + r = r.push(e); + } + r = r.push(Space::new().width(Fill)); + for e in right { + r = r.push(e); + } + r.into() +} + +fn wizard_view<'a>(w: &'a Wizard) -> Element<'a, Message> { + let steps: Vec<(u8, &str)> = if w.existing { + vec![(0, "Begin"), (1, "Details"), (2, "Choose Layouts"), (3, "Confirm")] + } else { + vec![(0, "Begin"), (1, "Details"), (3, "Confirm")] + }; + let chips = iced::widget::Row::with_children(steps.iter().enumerate().map(|(n, (s, label))| { + button(text(format!("{} {}", n + 1, t!(*label))).size(12)) + .on_press(msg(SheetSetMsg::Wizard(WizardMsg::Step(*s)))) + .style(button_style(w.step == *s)) + .padding([4, 10]) + .into() + })) + .spacing(6); + let page: Element<'a, Message> = match w.step { + 0 => card( + "Create a sheet set using", + column![ + checkbox(!w.existing) + .label(t!("An empty sheet set").into_owned()) + .text_size(12) + .size(14) + .on_toggle(|_| msg(SheetSetMsg::Wizard(WizardMsg::Existing(false)))), + checkbox(w.existing) + .label(t!("Existing drawings").into_owned()) + .text_size(12) + .size(14) + .on_toggle(|_| msg(SheetSetMsg::Wizard(WizardMsg::Existing(true)))), + text( + t!(if w.existing { + "Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set." + } else { + "Creates a sheet set with no subsets or sheets." + }) + .into_owned() + ) + .size(11) + .style(muted_style), + ] + .spacing(8), + ), + 1 => card( + "Sheet Set", + column![ + labeled("Name of new sheet set:", input(&w.name, FieldId::Name)), + labeled("Description (optional):", input(&w.description, FieldId::Description)), + labeled( + "Store sheet set data file (.dst) here:", + row![input(&w.folder, FieldId::Folder), browse(SheetSetMsg::Browse(FieldId::Folder))].spacing(6) + ), + checkbox(w.hierarchy) + .label(t!("Create a folder hierarchy based on subsets").into_owned()) + .text_size(12) + .size(14) + .on_toggle(|v| msg(SheetSetMsg::Toggle(FieldId::Hierarchy, v))), + row![ + Space::new().width(Fill), + button(text(t!("Sheet Set Properties...").into_owned()).size(12)) + .on_press(msg(SheetSetMsg::WizardProperties)) + .style(button_style(false)) + .padding([5, 12]), + ], + ] + .spacing(8), + ), + 2 => { + let rows = w.layouts.iter().enumerate().map(|(i, l)| { + checkbox(l.on) + .label(format!("{} — {}", l.file, l.layout)) + .text_size(12) + .size(14) + .on_toggle(move |v| msg(SheetSetMsg::Wizard(WizardMsg::LayoutOn(i, v)))) + .into() + }); + let folders = w.folders.iter().enumerate().map(|(i, f)| { + row![ + text(f.clone()).size(12).width(Fill), + button(text("×").size(12)) + .on_press(msg(SheetSetMsg::Wizard(WizardMsg::RemoveFolder(i)))) + .style(button::text) + .padding([0, 6]), + ] + .into() + }); + card( + "Choose Layouts", + column![ + row![ + text(t!("Select folders containing drawings. Layouts in the drawings can be added to the sheet set.").into_owned()) + .size(11) + .style(muted_style) + .width(Fill), + button(text(t!("Browse...").into_owned()).size(12)) + .on_press(msg(SheetSetMsg::Browse(FieldId::AddFolder))) + .style(button_style(false)) + .padding([5, 12]), + ] + .spacing(8) + .align_y(iced::Center), + iced::widget::Column::with_children(folders.collect::>()).spacing(2), + container(scrollable(iced::widget::Column::with_children(rows.collect::>()).spacing(3))) + .height(Length::Fixed(180.0)), + ] + .spacing(8), + ) + } + _ => { + let mut lines = vec![ + format!("{}: {}", t!("Sheet Set"), w.name), + format!("{}: {}", t!("Sheet set data file"), wizard_dst_path(w)), + format!("{}: {}", t!("Description"), w.description), + ]; + if w.existing { + let n = w.layouts.iter().filter(|l| l.on).count(); + lines.push(format!("{}: {n}", t!("Sheets to import"))); + } + for (name, value, _) in ss::custom_properties(w.draft.sheet_set()) { + lines.push(format!("{name}: {value}")); + } + card( + "Confirm", + iced::widget::Column::with_children(lines.into_iter().map(|l| text(l).size(12).into())).spacing(4), + ) + } + }; + let next_step = match (w.step, w.existing) { + (0, _) => Some(1), + (1, true) => Some(2), + (1, false) | (2, _) => Some(3), + _ => None, + }; + let back_step = match (w.step, w.existing) { + (3, true) => Some(2), + (3, false) | (2, _) => Some(1), + (1, _) => Some(0), + _ => None, + }; + let back = button(text(format!("‹ {}", t!("Back"))).size(12)) + .on_press_maybe(back_step.map(|s| msg(SheetSetMsg::Wizard(WizardMsg::Step(s))))) + .style(button_style(false)) + .padding([6, 14]); + let next: Element<'a, Message> = match next_step { + Some(s) => button(text(format!("{} ›", t!("Next"))).size(12)) + .on_press(msg(SheetSetMsg::Wizard(WizardMsg::Step(s)))) + .style(button_style(true)) + .padding([6, 14]) + .into(), + None => dialog_button(t!("Finish"), msg(SheetSetMsg::Ok), true).into(), + }; + let mut col = column![chips, page].spacing(10); + if let Some(e) = error_band(&w.error) { + col = col.push(e); + } + col.push(footer(vec![], vec![back.into(), next, dialog_button(t!("Cancel"), msg(SheetSetMsg::Cancel), false).into()])) + .into() +} + +/// Where the wizard writes the `.dst`. +pub fn wizard_dst_path(w: &Wizard) -> String { + std::path::Path::new(&w.folder).join(format!("{}.dst", w.name.trim())).to_string_lossy().to_string() +} + +fn properties_view<'a>(p: &'a Properties) -> Element<'a, Message> { + let mut groups: Vec> = Vec::new(); + let mut current: Option<&'static str> = None; + let mut rows: Vec> = Vec::new(); + let flush = |group: Option<&'static str>, rows: &mut Vec>, groups: &mut Vec>| { + if let Some(g) = group { + groups.push(card(g, iced::widget::Column::with_children(std::mem::take(rows)).spacing(6))); + } + }; + for (i, r) in p.rows.iter().enumerate() { + if current != Some(r.group) { + flush(current, &mut rows, &mut groups); + current = Some(r.group); + } + let control: Element<'a, Message> = match r.key { + RowKey::ReadOnly => container(text(r.value.clone()).size(12).style(muted_style)) + .padding([5, 8]) + .width(Fill) + .into(), + RowKey::Folder(_) => row![input(&r.value, FieldId::Row(i)), browse(SheetSetMsg::Browse(FieldId::Row(i)))] + .spacing(6) + .into(), + RowKey::Template => row![ + container(text(r.value.clone()).size(12)).padding([5, 8]).width(Fill), + browse(SheetSetMsg::BrowseTemplate) + ] + .spacing(6) + .align_y(iced::Center) + .into(), + RowKey::PromptTemplate => { + let yes = r.value == "Yes"; + let opts = vec![t!("Yes").into_owned(), t!("No").into_owned()]; + pick_list(Some(opts[if yes { 0 } else { 1 }].clone()), opts.clone(), |s: &String| s.clone()) + .on_select(move |s: String| msg(SheetSetMsg::Choose(FieldId::Row(i), usize::from(s != t!("Yes"))))) + .text_size(12) + .padding([5, 8]) + .width(Fill) + .into() + } + RowKey::Prop(_) => input(&r.value, FieldId::Row(i)), + }; + rows.push(labeled(r.label, control)); + } + flush(current, &mut rows, &mut groups); + if p.kind != ComponentKind::Subset { + let owner = |f: i32| if f & ss::CUSTOM_SHEET_PROP != 0 { t!("Sheet") } else { t!("Sheet Set") }; + let mut custom: Vec> = p + .custom + .iter() + .enumerate() + .map(|(i, (name, value, flags))| { + let label = if p.kind == ComponentKind::SheetSet { format!("{name} ({})", owner(*flags)) } else { name.clone() }; + row![ + text(label).size(12).width(Length::Fixed(170.0)), + text_input("", value) + .size(12) + .padding([5, 8]) + .style(field_style) + .on_input(move |v| msg(SheetSetMsg::CustomValue(i, v))), + ] + .spacing(8) + .align_y(iced::Center) + .into() + }) + .collect(); + if p.kind == ComponentKind::SheetSet { + match &p.adding { + Some((name, value, sheet)) => custom.push( + container( + column![ + labeled("Name:", input(name, FieldId::CustomName)), + labeled("Default value:", input(value, FieldId::CustomDefault)), + labeled( + "Owner", + row![ + checkbox(!*sheet) + .label(t!("Sheet Set").into_owned()) + .text_size(12) + .size(14) + .on_toggle(|_| msg(SheetSetMsg::Choose(FieldId::CustomOwner, 0))), + checkbox(*sheet) + .label(t!("Sheet").into_owned()) + .text_size(12) + .size(14) + .on_toggle(|_| msg(SheetSetMsg::Choose(FieldId::CustomOwner, 1))), + ] + .spacing(12) + ), + row![ + Space::new().width(Fill), + dialog_button(t!("Cancel"), msg(SheetSetMsg::AddCustomCancel), false), + dialog_button(t!("OK"), msg(SheetSetMsg::AddCustomOk), true), + ] + .spacing(6), + ] + .spacing(6), + ) + .padding(8) + .style(|theme: &Theme| container::Style { + border: Border { color: theme.palette().background.neutral.color, width: 1.0, radius: 4.0.into() }, + ..Default::default() + }) + .into(), + ), + None => custom.push( + row![ + Space::new().width(Fill), + button(text(t!("Add Custom Property...").into_owned()).size(12)) + .on_press(msg(SheetSetMsg::AddCustom)) + .style(button_style(false)) + .padding([5, 12]), + ] + .into(), + ), + } + } + groups.push(card("Custom Properties", iced::widget::Column::with_children(custom).spacing(6))); + } + let mut col = column![scrollable(iced::widget::Column::with_children(groups).spacing(10)).height(Fill)].spacing(10); + if let Some(e) = error_band(&p.error) { + col = col.push(e); + } + col.push(footer( + vec![], + vec![ + dialog_button(t!("Cancel"), msg(SheetSetMsg::Cancel), false).into(), + dialog_button(t!("OK"), msg(SheetSetMsg::Ok), true).into(), + ], + )) + .into() +} + +fn form_view<'a>(f: &'a Form) -> Element<'a, Message> { + let body: Element<'a, Message> = match f.kind { + FormKind::NewSheet => column![ + labeled("Number", input(&f.number, FieldId::Number)), + labeled("Sheet title", input(&f.title, FieldId::Title)), + labeled("File name", input(&f.file_name, FieldId::FileName)), + labeled("Folder path", container(text(f.folder.clone()).size(12).style(muted_style)).padding([5, 8])), + labeled("Sheet template", container(text(f.drawing.clone()).size(12).style(muted_style)).padding([5, 8])), + ] + .spacing(8) + .into(), + FormKind::NewSubset => column![ + labeled("Subset name", input(&f.title, FieldId::Title)), + labeled( + "New sheet location", + row![input(&f.folder, FieldId::Folder), browse(SheetSetMsg::Browse(FieldId::Folder))].spacing(6) + ), + ] + .spacing(8) + .into(), + FormKind::Rename => column![ + labeled("Number", input(&f.number, FieldId::Number)), + labeled("Sheet title", input(&f.title, FieldId::Title)), + ] + .spacing(8) + .into(), + FormKind::ImportLayout => { + let rows = f.layouts.iter().enumerate().map(|(i, (name, _))| { + button(text(name.clone()).size(12)) + .on_press(msg(SheetSetMsg::Choose(FieldId::Layout, i))) + .style(button_style(f.layout == i)) + .padding([3, 8]) + .width(Fill) + .into() + }); + column![ + labeled("Drawing", container(text(f.drawing.clone()).size(12).style(muted_style)).padding([5, 8])), + text(t!("Layouts").into_owned()).size(12), + container(scrollable(iced::widget::Column::with_children(rows.collect::>()).spacing(1))) + .height(Length::Fixed(160.0)), + ] + .spacing(8) + .into() + } + }; + let mut col = column![card( + match f.kind { + FormKind::NewSheet => "Sheet", + FormKind::NewSubset => "Subset", + FormKind::Rename => "Sheet", + FormKind::ImportLayout => "Import Layout as Sheet", + }, + body + )] + .spacing(10); + if let Some(e) = error_band(&f.error) { + col = col.push(e); + } + col.push(footer( + vec![], + vec![ + dialog_button(t!("Cancel"), msg(SheetSetMsg::Cancel), false).into(), + dialog_button(t!("OK"), msg(SheetSetMsg::Ok), true).into(), + ], + )) + .into() +} + +pub fn dialog_view<'a>(state: &'a SheetSetManager, sizing: crate::ui::modal::ModalSizing) -> Element<'a, Message> { + let body = match state.dialog.as_ref() { + Some(SsDialog::Wizard(w)) => wizard_view(w), + Some(SsDialog::Properties(p)) => properties_view(p), + Some(SsDialog::Form(f)) => form_view(f), + None => Space::new().into(), + }; + container(body).padding([10, 12]).width(sizing.width).into() +}