Skip to content

[WIP] Add "Save as..." command and toolbar button #596

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 55 additions & 1 deletion packages/base/src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
SourceType
} from '@jupytergis/schema';
import { JupyterFrontEnd } from '@jupyterlab/application';
import { showErrorMessage } from '@jupyterlab/apputils';
import { InputDialog, showErrorMessage } from '@jupyterlab/apputils';
import { ICompletionProviderManager } from '@jupyterlab/completer';
import { IStateDB } from '@jupyterlab/statedb';
import { ITranslator } from '@jupyterlab/translation';
Expand Down Expand Up @@ -252,6 +252,60 @@ export function addCommands(
...icons.get(CommandIDs.temporalController)
});

commands.addCommand(CommandIDs.saveAs, {
label: trans.__('Save As...'),
isEnabled: () => true,
execute: async () => {
if (!tracker.currentWidget) {
return;
}

const model = tracker.currentWidget.model;
const oldFilename = model.filePath;
let newFilename = (
await InputDialog.getText({
title: 'Save as...',
label: 'New filename',
placeholder: oldFilename
})
).value;

if (!newFilename) {
return;
}

if (newFilename.toLowerCase().endsWith('.qgz')) {
throw Error('Not supported yet');
} else if (!newFilename.toLowerCase().endsWith('.jgis')) {
newFilename += '.jGIS';
}

const content = model.toJSON();

// FIXME: This doesn't re-open the project file in the current view where the save button was clicked.
app.serviceManager.contents.save(newFilename, {
content: JSON.stringify(content),
format: 'text',
type: 'file',
mimetype: 'text/json'
});
// FIXME: The widget will only save to this new filename once, as opposed to continuously saving changes to the file like we expect.
model.filePath = newFilename;

// FIXME: Saves to the currently open directory, while the above save is to the JupyterLab root directory.
// FIXME: Get "unsaved_project" from a constant
if (oldFilename && !oldFilename.endsWith('unsaved_project')) {
app.serviceManager.contents.save(oldFilename, {
content: JSON.stringify(content),
format: 'text',
type: 'file',
mimetype: 'text/json'
});
}
},
...icons.get(CommandIDs.saveAs),
})

/**
* SOURCES and LAYERS creation commands.
*/
Expand Down
4 changes: 3 additions & 1 deletion packages/base/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export namespace CommandIDs {
export const symbology = 'jupytergis:symbology';
export const identify = 'jupytergis:identify';
export const temporalController = 'jupytergis:temporalController';
export const saveAs = 'jupytergis:saveAs';

// Layers and sources creation commands
export const openLayerBrowser = 'jupytergis:openLayerBrowser';
Expand Down Expand Up @@ -106,7 +107,8 @@ const iconObject = {
[CommandIDs.newGeoTiffEntry]: { iconClass: 'fa fa-image' },
[CommandIDs.symbology]: { iconClass: 'fa fa-brush' },
[CommandIDs.identify]: { iconClass: 'fa fa-info' },
[CommandIDs.temporalController]: { iconClass: 'fa fa-clock' }
[CommandIDs.temporalController]: { iconClass: 'fa fa-clock' },
[CommandIDs.saveAs]: {iconClass: 'fa fa-save'}
};

/**
Expand Down
92 changes: 92 additions & 0 deletions packages/base/src/formbuilder/objectform/bufferProcessForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { BaseForm, IBaseFormProps, IBaseFormStates } from './baseform'; // Ensure BaseForm imports states
import { IDict, IJupyterGISModel } from '@jupytergis/schema';
import { IChangeEvent } from '@rjsf/core';
// import { loadFile } from '../../tools';
import proj4 from 'proj4';

interface IBufferFormOptions extends IBaseFormProps {
schema: IDict;
sourceData: IDict;
title: string;
cancelButton: (() => void) | boolean;
syncData: (props: IDict) => void;
model: IJupyterGISModel;
}

export class BufferForm extends BaseForm {
private model: IJupyterGISModel;
private unit = '';

constructor(options: IBufferFormOptions) {
super(options);
this.model = options.model;

// Ensure initial state matches IBaseFormStates
this.state = {
schema: options.schema ?? {} // Ensure schema is never undefined
};

this.onFormChange = this.handleFormChange.bind(this);

this.computeDistanceUnits(options.sourceData.inputLayer);
}

private async computeDistanceUnits(layerId: string) {
const layer = this.model.getLayer(layerId);
if (!layer?.parameters?.source) {
return;
}
const source = this.model.getSource(layer.parameters.source);
if (!source) {
return;
}

const projection = source.parameters?.projection;
console.log(projection);

// TODO: how to get layer info from OpenLayers?
// const srs = layer.from_ol().srs;
const srs = 'EPSG:4326';

try {
// console.log(proj4, srs);
this.unit = (proj4(srs) as any).oProj.units;
debugger;
this.updateSchema();
} catch (error) {
console.error('Error calculating units:', error);
}
}

public handleFormChange(e: IChangeEvent) {
super.onFormChange(e);

if (e.formData.inputLayer) {
this.computeDistanceUnits(e.formData.inputLayer);
}
}

private updateSchema() {
this.setState(
(prevState: IBaseFormStates) => ({
schema: {
...prevState.schema,
properties: {
...prevState.schema?.properties,
bufferDistance: {
...prevState.schema?.properties?.bufferDistance,
description:
prevState.schema?.properties?.bufferDistance.description.replace(
'projection units',
this.unit
)
}
}
}
}),
() => {
this.forceUpdate();
}
);
}
}
8 changes: 8 additions & 0 deletions packages/base/src/toolbar/widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ export class ToolbarWidget extends ReactiveToolbar {
this.addClass('jGIS-toolbar-widget');

if (options.commands) {
this.addItem(
'Save as...',
new CommandToolbarButton({
id: CommandIDs.saveAs,
label: '',
commands: options.commands
}),
);
this.addItem(
'undo',
new CommandToolbarButton({
Expand Down
Loading