1- import {
2- ICollaborativeDrive ,
3- SharedDocumentFactory
4- } from '@jupyter/collaborative-drive' ;
1+ // plugins.ts
2+ import { ICollaborativeDrive } from '@jupyter/collaborative-drive' ;
53import {
64 IAnnotationModel ,
75 IJCadWorkerRegistry ,
@@ -17,8 +15,12 @@ import {
1715import {
1816 IThemeManager ,
1917 showErrorMessage ,
18+ InputDialog ,
19+ showDialog ,
2020 WidgetTracker
2121} from '@jupyterlab/apputils' ;
22+ import { IMainMenu } from '@jupyterlab/mainmenu' ;
23+ import { PathExt } from '@jupyterlab/coreutils' ;
2224import { LabIcon } from '@jupyterlab/ui-components' ;
2325
2426import { JupyterCadWidgetFactory } from '@jupytercad/jupytercad-core' ;
@@ -32,109 +34,144 @@ import { JupyterCadFCModelFactory } from './modelfactory';
3234import freecadIconSvg from '../style/freecad.svg' ;
3335
3436const freecadIcon = new LabIcon ( {
35- name : 'jupytercad:stp ' ,
37+ name : 'jupytercad:freecad ' ,
3638 svgstr : freecadIconSvg
3739} ) ;
3840
3941const FACTORY = 'Jupytercad Freecad Factory' ;
40-
41- class JupyterCadFCstdDoc extends JupyterCadDoc {
42- toJcadEndpoint = 'jupytercad_freecad/export-jcad' ;
43- toFcstdEndpoint = 'jupytercad_freecad/export-fcstd' ;
44- }
45-
46- const activate = async (
47- app : JupyterFrontEnd ,
48- tracker : WidgetTracker < IJupyterCadWidget > ,
49- themeManager : IThemeManager ,
50- annotationModel : IAnnotationModel ,
51- drive : ICollaborativeDrive ,
52- workerRegistry : IJCadWorkerRegistry ,
53- externalCommandRegistry : IJCadExternalCommandRegistry
54- ) : Promise < void > => {
55- const fcCheck = await requestAPI < { installed : boolean } > (
56- 'jupytercad_freecad/backend-check' ,
57- {
58- method : 'POST' ,
59- body : JSON . stringify ( {
60- backend : 'FreeCAD'
61- } )
62- }
63- ) ;
64- const { installed } = fcCheck ;
65- const backendCheck = ( ) => {
66- if ( ! installed ) {
67- showErrorMessage (
68- 'FreeCAD is not installed' ,
69- 'FreeCAD is required to open FCStd files'
70- ) ;
71- }
72- return installed ;
73- } ;
74- const widgetFactory = new JupyterCadWidgetFactory ( {
75- name : FACTORY ,
76- modelName : 'jupytercad-fcmodel' ,
77- fileTypes : [ 'FCStd' ] ,
78- defaultFor : [ 'FCStd' ] ,
79- tracker,
80- commands : app . commands ,
81- workerRegistry,
82- externalCommandRegistry,
83- backendCheck
84- } ) ;
85-
86- // Registering the widget factory
87- app . docRegistry . addWidgetFactory ( widgetFactory ) ;
88-
89- // Creating and registering the model factory for our custom DocumentModel
90- const modelFactory = new JupyterCadFCModelFactory ( { annotationModel } ) ;
91- app . docRegistry . addModelFactory ( modelFactory ) ;
92- // register the filetype
93- app . docRegistry . addFileType ( {
94- name : 'FCStd' ,
95- displayName : 'FCStd' ,
96- mimeTypes : [ 'application/octet-stream' ] ,
97- extensions : [ '.FCStd' , 'fcstd' ] ,
98- fileFormat : 'base64' ,
99- contentType : 'FCStd' ,
100- icon : freecadIcon
101- } ) ;
102-
103- const FCStdSharedModelFactory : SharedDocumentFactory = ( ) => {
104- return new JupyterCadFCstdDoc ( ) ;
105- } ;
106- drive . sharedModelFactory . registerDocumentFactory (
107- 'FCStd' ,
108- FCStdSharedModelFactory
109- ) ;
110-
111- widgetFactory . widgetCreated . connect ( ( sender , widget ) => {
112- widget . title . icon = freecadIcon ;
113- // Notify the instance tracker if restore data needs to update.
114- widget . context . pathChanged . connect ( ( ) => {
115- tracker . save ( widget ) ;
116- } ) ;
117- themeManager . themeChanged . connect ( ( _ , changes ) =>
118- widget . context . model . themeChanged . emit ( changes )
119- ) ;
120-
121- tracker . add ( widget ) ;
122- app . shell . activateById ( 'jupytercad::leftControlPanel' ) ;
123- app . shell . activateById ( 'jupytercad::rightControlPanel' ) ;
124- } ) ;
125- console . log ( 'jupytercad:fcplugin is activated!' ) ;
126- } ;
42+ const EXPORT_FCSTD_CMD = 'jupytercad:export-fcstd' ;
12743
12844export const fcplugin : JupyterFrontEndPlugin < void > = {
12945 id : 'jupytercad:fcplugin' ,
13046 requires : [
13147 IJupyterCadDocTracker ,
48+ IMainMenu ,
13249 IThemeManager ,
13350 IAnnotationToken ,
13451 ICollaborativeDrive ,
13552 IJCadWorkerRegistryToken ,
13653 IJCadExternalCommandRegistryToken
13754 ] ,
13855 autoStart : true ,
139- activate
56+ activate : async (
57+ app : JupyterFrontEnd ,
58+ tracker : WidgetTracker < IJupyterCadWidget > ,
59+ mainMenu : IMainMenu ,
60+ themeManager : IThemeManager ,
61+ annotationModel : IAnnotationModel ,
62+ drive : ICollaborativeDrive ,
63+ workerRegistry : IJCadWorkerRegistry ,
64+ externalCommandRegistry : IJCadExternalCommandRegistry
65+ ) => {
66+ const { installed } = await requestAPI < { installed : boolean } > (
67+ 'jupytercad_freecad/backend-check' ,
68+ {
69+ method : 'POST' ,
70+ body : JSON . stringify ( { backend : 'FreeCAD' } )
71+ }
72+ ) ;
73+ const backendCheck = ( ) => {
74+ if ( ! installed ) {
75+ showErrorMessage (
76+ 'FreeCAD is not installed' ,
77+ 'FreeCAD is required to open or export FCStd files'
78+ ) ;
79+ }
80+ return installed ;
81+ } ;
82+
83+ const widgetFactory = new JupyterCadWidgetFactory ( {
84+ name : FACTORY ,
85+ modelName : 'jupytercad-fcmodel' ,
86+ fileTypes : [ 'FCStd' ] ,
87+ defaultFor : [ 'FCStd' ] ,
88+ tracker,
89+ commands : app . commands ,
90+ workerRegistry,
91+ externalCommandRegistry,
92+ backendCheck
93+ } ) ;
94+ app . docRegistry . addWidgetFactory ( widgetFactory ) ;
95+
96+ const modelFactory = new JupyterCadFCModelFactory ( { annotationModel } ) ;
97+ app . docRegistry . addModelFactory ( modelFactory ) ;
98+
99+ app . docRegistry . addFileType ( {
100+ name : 'FCStd' ,
101+ displayName : 'FCStd' ,
102+ mimeTypes : [ 'application/octet-stream' ] ,
103+ extensions : [ '.FCStd' , '.fcstd' ] ,
104+ fileFormat : 'base64' ,
105+ contentType : 'FCStd' ,
106+ icon : freecadIcon
107+ } ) ;
108+
109+ drive . sharedModelFactory . registerDocumentFactory (
110+ 'FCStd' ,
111+ ( ) : JupyterCadDoc => new JupyterCadDoc ( )
112+ ) ;
113+
114+ widgetFactory . widgetCreated . connect ( ( _ , widget ) => {
115+ widget . title . icon = freecadIcon ;
116+ widget . context . pathChanged . connect ( ( ) => tracker . save ( widget ) ) ;
117+ themeManager . themeChanged . connect ( ( _ , changes ) =>
118+ widget . context . model . themeChanged . emit ( changes )
119+ ) ;
120+ app . shell . activateById ( 'jupytercad::leftControlPanel' ) ;
121+ app . shell . activateById ( 'jupytercad::rightControlPanel' ) ;
122+ tracker . add ( widget ) ;
123+ } ) ;
124+
125+ console . log ( 'jupytercad:fcplugin is activated!' ) ;
126+
127+ app . commands . addCommand ( EXPORT_FCSTD_CMD , {
128+ label : 'Export to .FCStd' ,
129+ iconClass : 'fa fa-file-export' ,
130+ isEnabled : ( ) => {
131+ const w = tracker . currentWidget ;
132+ return ! ! w && w . context . path . toLowerCase ( ) . endsWith ( '.jcad' ) ;
133+ } ,
134+ execute : async ( ) => {
135+ const w = tracker . currentWidget ;
136+ if ( ! w ) {
137+ return ;
138+ }
139+ const defaultName = PathExt . basename ( w . context . path ) . replace (
140+ / \. [ ^ . ] + $ / ,
141+ '.FCStd'
142+ ) ;
143+ const result = await InputDialog . getText ( {
144+ title : 'Export to .FCStd' ,
145+ placeholder : 'Output file name' ,
146+ text : defaultName
147+ } ) ;
148+ if ( ! result . value ) {
149+ return ;
150+ }
151+ try {
152+ const resp = await requestAPI < { path ?: string ; done ?: boolean } > (
153+ 'jupytercad_freecad/export-fcstd' ,
154+ {
155+ method : 'POST' ,
156+ body : JSON . stringify ( {
157+ path : w . context . path ,
158+ newName : result . value
159+ } )
160+ }
161+ ) ;
162+ const outPath = resp . path ?? result . value ;
163+ await showDialog ( {
164+ title : 'Export successful' ,
165+ body : `Wrote file to: ${ outPath } `
166+ } ) ;
167+ } catch ( e : any ) {
168+ showErrorMessage ( 'Export Error' , e . message || String ( e ) ) ;
169+ }
170+ }
171+ } ) ;
172+
173+ mainMenu . fileMenu . addGroup ( [ { command : EXPORT_FCSTD_CMD } ] , /* rank */ 100 ) ;
174+ }
140175} ;
176+
177+ export default [ fcplugin ] ;
0 commit comments