/**
* Copyright 2012 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.kie.workbench.common.screens.datamodeller.client;
import java.util.List;
import javax.enterprise.context.Dependent;
import javax.enterprise.event.Event;
import javax.enterprise.event.Observes;
import javax.inject.Inject;
import com.google.gwt.user.client.ui.IsWidget;
import org.guvnor.common.services.shared.validation.model.ValidationMessage;
import org.guvnor.messageconsole.events.PublishBaseEvent;
import org.guvnor.messageconsole.events.PublishBatchMessagesEvent;
import org.guvnor.messageconsole.events.SystemMessage;
import org.guvnor.messageconsole.events.UnpublishMessagesEvent;
import org.gwtbootstrap3.client.ui.constants.ButtonType;
import org.jboss.errai.bus.client.api.messaging.Message;
import org.jboss.errai.common.client.api.Caller;
import org.jboss.errai.common.client.api.RemoteCallback;
import org.kie.workbench.common.screens.datamodeller.client.context.DataModelerWorkbenchContext;
import org.kie.workbench.common.screens.datamodeller.client.context.DataModelerWorkbenchFocusEvent;
import org.kie.workbench.common.screens.datamodeller.client.resources.i18n.Constants;
import org.kie.workbench.common.screens.datamodeller.client.util.DataModelerUtils;
import org.kie.workbench.common.screens.datamodeller.client.validation.JavaFileNameValidator;
import org.kie.workbench.common.screens.datamodeller.client.validation.ValidatorService;
import org.kie.workbench.common.screens.datamodeller.events.DataModelSaved;
import org.kie.workbench.common.screens.datamodeller.events.DataModelStatusChangeEvent;
import org.kie.workbench.common.screens.datamodeller.events.DataModelerEvent;
import org.kie.workbench.common.screens.datamodeller.events.DataObjectChangeEvent;
import org.kie.workbench.common.screens.datamodeller.events.DataObjectCreatedEvent;
import org.kie.workbench.common.screens.datamodeller.events.DataObjectDeletedEvent;
import org.kie.workbench.common.screens.datamodeller.events.DataObjectFieldChangeEvent;
import org.kie.workbench.common.screens.datamodeller.events.DataObjectFieldCreatedEvent;
import org.kie.workbench.common.screens.datamodeller.events.DataObjectFieldDeletedEvent;
import org.kie.workbench.common.screens.datamodeller.events.DataObjectFieldSelectedEvent;
import org.kie.workbench.common.screens.datamodeller.events.DataObjectSelectedEvent;
import org.kie.workbench.common.screens.datamodeller.model.DataModelerError;
import org.kie.workbench.common.screens.datamodeller.model.EditorModelContent;
import org.kie.workbench.common.screens.datamodeller.model.GenerationResult;
import org.kie.workbench.common.screens.datamodeller.model.TypeInfoResult;
import org.kie.workbench.common.screens.datamodeller.security.DataModelerFeatures;
import org.kie.workbench.common.screens.datamodeller.service.DataModelerService;
import org.kie.workbench.common.screens.javaeditor.client.type.JavaResourceType;
import org.kie.workbench.common.screens.javaeditor.client.widget.EditJavaSourceWidget;
import org.kie.workbench.common.services.datamodeller.core.DataModel;
import org.kie.workbench.common.services.datamodeller.core.DataObject;
import org.kie.workbench.common.services.datamodeller.core.JavaTypeInfo;
import org.kie.workbench.common.services.datamodeller.core.ObjectProperty;
import org.kie.workbench.common.services.datamodeller.core.impl.JavaTypeInfoImpl;
import org.kie.workbench.common.services.shared.validation.ValidationService;
import org.kie.workbench.common.widgets.client.popups.validation.ValidationPopup;
import org.kie.workbench.common.widgets.metadata.client.KieEditor;
import org.kie.workbench.common.widgets.metadata.client.KieEditorView;
import org.uberfire.backend.vfs.ObservablePath;
import org.uberfire.backend.vfs.Path;
import org.uberfire.client.annotations.WorkbenchEditor;
import org.uberfire.client.annotations.WorkbenchMenu;
import org.uberfire.client.annotations.WorkbenchPartTitle;
import org.uberfire.client.annotations.WorkbenchPartTitleDecoration;
import org.uberfire.client.annotations.WorkbenchPartView;
import org.uberfire.client.mvp.LockRequiredEvent;
import org.uberfire.client.views.pfly.multipage.PageImpl;
import org.uberfire.client.workbench.events.PlaceHiddenEvent;
import org.uberfire.ext.editor.commons.client.file.CommandWithFileNameAndCommitMessage;
import org.uberfire.ext.editor.commons.client.file.FileNameAndCommitMessage;
import org.uberfire.ext.editor.commons.client.file.popups.CopyPopUpPresenter;
import org.uberfire.ext.editor.commons.client.file.popups.RenamePopUpPresenter;
import org.uberfire.ext.widgets.common.client.resources.i18n.CommonConstants;
import org.uberfire.lifecycle.OnClose;
import org.uberfire.lifecycle.OnFocus;
import org.uberfire.lifecycle.OnMayClose;
import org.uberfire.lifecycle.OnStartup;
import org.uberfire.mvp.Command;
import org.uberfire.mvp.ParameterizedCommand;
import org.uberfire.mvp.PlaceRequest;
import org.uberfire.rpc.SessionInfo;
import org.uberfire.security.authz.AuthorizationManager;
import org.uberfire.workbench.events.NotificationEvent;
import org.uberfire.workbench.model.menu.Menus;
@Dependent
@WorkbenchEditor(identifier = "DataModelerEditor",
supportedTypes = { JavaResourceType.class },
priority = Integer.MAX_VALUE)
public class DataModelerScreenPresenter
extends KieEditor {
public interface DataModelerScreenView
extends
KieEditorView {
void setContext( DataModelerContext context );
void refreshTypeLists( boolean keepCurrentSelection );
void showUsagesPopupForDeletion( String message,
List<Path> paths,
Command yesCommand,
Command cancelCommand );
void showUsagesPopupForRenaming( String message,
List<Path> paths,
Command yesCommand,
Command cancelCommand );
void showYesNoCancelPopup( String title,
String message,
Command yesCommand,
String yesButtonText,
ButtonType yesButtonType,
Command noCommand,
String noButtonText,
ButtonType noButtonType );
void showYesNoCancelPopup( String title,
String message,
Command yesCommand,
Command noCommand );
void showParseErrorsDialog( String title, String message, Command onCloseCommand );
void setDomainContainerTitle( String title, String tooltip );
void redraw();
}
protected DataModelerScreenView view;
@Inject
protected EditJavaSourceWidget javaSourceEditor;
@Inject
protected Event<DataModelerEvent> dataModelerEvent;
@Inject
protected Event<UnpublishMessagesEvent> unpublishMessagesEvent;
@Inject
protected Event<PublishBatchMessagesEvent> publishBatchMessagesEvent;
@Inject
protected Event<LockRequiredEvent> lockRequired;
@Inject
protected Event<DataModelerWorkbenchFocusEvent> dataModelerFocusEvent;
@Inject
protected Caller<DataModelerService> modelerService;
@Inject
protected ValidationPopup validationPopup;
@Inject
protected ValidatorService validatorService;
@Inject
protected Caller<ValidationService> validationService;
@Inject
protected JavaFileNameValidator javaFileNameValidator;
@Inject
protected JavaResourceType resourceType;
@Inject
protected DataModelerWorkbenchContext dataModelerWBContext;
@Inject
protected AuthorizationManager authorizationManager;
protected DataModelerContext context;
protected boolean uiStarted = false;
protected boolean loading = false;
private boolean loadTypesInfo = false;
private SessionInfo sessionInfo;
private String currentMessageType;
private Integer originalSourceHash = null;
private boolean sourceEditionEnabled = false;
private static final int EDITABLE_SOURCE_TAB = 2;
private static int editorIds = 0;
private String editorId;
@WorkbenchPartTitle
public String getTitleText() {
return super.getTitleText();
}
@WorkbenchPartTitleDecoration
public IsWidget getTitle() {
return super.getTitle();
}
@WorkbenchPartView
public IsWidget getView() {
return super.getWidget();
}
@WorkbenchMenu
public Menus getMenus() {
return menus;
}
@Inject
public DataModelerScreenPresenter( DataModelerScreenView baseView,
SessionInfo sessionInfo ) {
super( baseView );
view = baseView;
this.sessionInfo = sessionInfo;
editorId = sessionInfo.getId() + "-" + editorIds++;
}
@OnStartup
public void onStartup( final ObservablePath path,
final PlaceRequest place ) {
loading = true;
loadTypesInfo = !dataModelerWBContext.isTypesInfoLoaded();
context = new DataModelerContext( editorId );
setSourceEditionGrant();
init( path, place, resourceType );
currentMessageType = "DataModeler" + path.toURI();
cleanSystemMessages( getCurrentMessageType() );
javaSourceEditor.addChangeHandler( new EditJavaSourceWidget.TextChangeHandler() {
@Override
public void onTextChange() {
if ( context != null ) {
context.setEditionStatus( DataModelerContext.EditionStatus.SOURCE_CHANGED );
}
}
} );
}
@OnFocus
public void onFocus() {
if ( !loading && context != null ) {
view.redraw();
setActiveContext();
showDataModellerDocks();
}
}
private void showDataModellerDocks() {
dataModelerFocusEvent.fire( new DataModelerWorkbenchFocusEvent() );
}
private void hideDataModellerDocks( @Observes PlaceHiddenEvent event ) {
if ( context != null ) {
if ( "DataModelerEditor".equals( event.getPlace().getIdentifier() ) &&
place != null && place.equals( event.getPlace() ) ) {
dataModelerFocusEvent.fire( new DataModelerWorkbenchFocusEvent().lostFocus() );
}
}
}
@OnMayClose
public boolean onMayClose() {
if ( isDirty() ) {
return view.confirmClose();
}
return true;
}
@OnClose
public void OnClose() {
versionRecordManager.clear();
cleanSystemMessages( getCurrentMessageType() );
clearContext();
super.OnClose();
dataModelerWBContext.clearContext();
}
private void setActiveContext() {
dataModelerWBContext.setActiveContext( context );
if ( context.getDataObject() != null && context.getObjectProperty() != null ) {
refreshTitle( context.getDataObject(), context.getObjectProperty() );
} else if ( context.getDataObject() != null ) {
refreshTitle( context.getDataObject() );
}
}
private void onSafeDelete() {
if ( context.getEditorModelContent().getOriginalClassName() != null ) {
//if we are about to delete a .java file that could be parsed without errors, and we can calculate the
//className then we can check for class usages prior to deletion.
final String className = context.getEditorModelContent().getOriginalClassName();
modelerService.call( new RemoteCallback<List<Path>>() {
@Override
public void callback( List<Path> paths ) {
if ( paths != null && paths.size() > 0 ) {
//If usages for this class were detected in project assets
//show the confirmation message to the user.
view.showUsagesPopupForDeletion(
Constants.INSTANCE.modelEditor_confirm_deletion_of_used_class( className ),
paths,
new Command() {
@Override
public void execute() {
onDelete( versionRecordManager.getPathToLatest() );
}
},
new Command() {
@Override
public void execute() {
//do nothing.
}
} );
} else {
//no usages, just proceed with the deletion.
onDelete( versionRecordManager.getPathToLatest() );
}
}
} ).findClassUsages( versionRecordManager.getPathToLatest(), className );
} else {
//we couldn't parse the class, so no check can be done. Just proceed with the standard
//file deletion procedure.
onDelete( versionRecordManager.getPathToLatest() );
}
}
private void onDelete( final Path path ) {
validationService.call( validationMessages -> {
if ( ( (List<ValidationMessage>) validationMessages ).isEmpty() ) {
showDeletePopup( path );
} else {
validationPopup.showDeleteValidationMessages( () -> showDeletePopup( path ),
() -> {},
( List<ValidationMessage> ) validationMessages );
}
} ).validateForDelete( versionRecordManager.getPathToLatest(),
context.getDataObject() );
}
private void showDeletePopup( final Path path ) {
deletePopUpPresenter.show( new ParameterizedCommand<String>() {
@Override
public void execute( final String comment ) {
view.showBusyIndicator( org.kie.workbench.common.widgets.client.resources.i18n.CommonConstants.INSTANCE.Deleting() );
modelerService.call( getDeleteSuccessCallback(), new DataModelerErrorCallback( Constants.INSTANCE.modelEditor_deleting_error() ) ).delete( path,
comment );
}
} );
}
void onCopy() {
validationService.call( checkMessages -> {
if ( ( (List<ValidationMessage>) checkMessages ).isEmpty() ) {
showCopyPopup();
} else {
validationPopup.showCopyValidationMessages( () -> showCopyPopup(),
() -> {},
( (List<ValidationMessage>) checkMessages ) );
}
} ).validateForCopy( versionRecordManager.getPathToLatest(),
context.getDataObject() );
}
private void showCopyPopup() {
copyPopUpPresenter.show( versionRecordManager.getCurrentPath(),
javaFileNameValidator,
details -> {
view.showBusyIndicator( org.kie.workbench.common.widgets.client.resources.i18n.CommonConstants.INSTANCE.Copying() );
modelerService.call( getCopySuccessCallback( copyPopUpPresenter.getView() ),
getCopyErrorCallback( copyPopUpPresenter.getView() ) ).copy( versionRecordManager.getCurrentPath(),
details.getNewFileName(),
copyPopUpPresenter.getView().getPackageName(),
copyPopUpPresenter.getView().getTargetPath(),
details.getCommitMessage(),
true );
} );
}
protected DataModelerErrorCallback getCopyErrorCallback( final CopyPopUpPresenter.View copyPopupView ) {
return new DataModelerErrorCallback( Constants.INSTANCE.modelEditor_copying_error() ) {
@Override
public boolean error( final Message message,
final Throwable throwable ) {
copyPopupView.hide();
return super.error( message, throwable );
}
};
}
private void onSafeRename() {
if ( context.getEditorModelContent().getOriginalClassName() != null ) {
//if we are about to rename a .java file that could be parsed without errors, and we can calculate the
//className we can check for class usages prior to renaming and we can also suggest to perform an automatic
// class renaming.
final String className = context.getEditorModelContent().getOriginalClassName();
modelerService.call( new RemoteCallback<List<Path>>() {
@Override
public void callback( List<Path> paths ) {
if ( paths != null && paths.size() > 0 ) {
//If usages for this class were detected in project assets
//show the confirmation message to the user.
view.showUsagesPopupForRenaming(
Constants.INSTANCE.modelEditor_confirm_renaming_of_used_class( className ),
paths,
new Command() {
@Override
public void execute() {
rename();
}
},
new Command() {
@Override
public void execute() {
//do nothing.
}
}
);
} else {
//no usages, just proceed with the deletion.
rename();
}
}
} ).findClassUsages( versionRecordManager.getPathToLatest(), className );
} else {
//we couldn't parse the class, so no check can be done. Just proceed with the standard
//file renaming procedure.
rename();
}
}
protected void rename() {
if ( isDirty() ) {
view.showYesNoCancelPopup( CommonConstants.INSTANCE.Information(),
Constants.INSTANCE.modelEditor_confirm_save_before_rename(),
() -> validationService.call( getRenameValidationCallback() ).validateForSave( versionRecordManager.getPathToLatest(),
context.getDataObject() ),
() -> rename( false ) );
} else {
//just rename.
rename( false );
}
}
RemoteCallback<List<ValidationMessage>> getRenameValidationCallback() {
return checkMessages -> {
if ( checkMessages.isEmpty() ) {
rename( true );
} else {
validationPopup.showSaveValidationMessages( () -> rename( true ),
() -> {},
checkMessages );
}
};
}
protected Command onValidate() {
return new Command() {
@Override
public void execute() {
//at validation time we must do the same calculation as if we were about to save.
final DataObject[] modifiedDataObject = new DataObject[ 1 ];
if ( isDirty() ) {
if ( context.isEditorChanged() ) {
//at save time the source has always priority over the model.
//If the source was properly parsed and the editor has changes, we need to send the DataObject
//to the server in order to let the source to be updated prior to save.
modifiedDataObject[ 0 ] = context.getDataObject();
} else {
//if the source has changes, no update form the UI to the source will be performed.
//instead the parsed DataObject must be returned from the server.
modifiedDataObject[ 0 ] = null;
}
}
modelerService.call( new RemoteCallback<List<org.guvnor.common.services.shared.validation.model.ValidationMessage>>() {
@Override
public void callback( final List<org.guvnor.common.services.shared.validation.model.ValidationMessage> results ) {
if ( results == null || results.isEmpty() ) {
notification.fire( new NotificationEvent( org.kie.workbench.common.widgets.client.resources.i18n.CommonConstants.INSTANCE.ItemValidatedSuccessfully(),
NotificationEvent.NotificationType.SUCCESS ) );
} else {
validationPopup.showMessages( results );
}
}
} ).validate( getSource(), versionRecordManager.getCurrentPath(), modifiedDataObject[ 0 ] );
}
};
}
private boolean isDirty() {
return isDataObjectDirty() || isSourceDirty();
}
private boolean isDataObjectDirty() {
return isDirty( context.getDataObject() != null ? context.getDataObject().hashCode() : null );
}
private boolean isSourceDirty() {
return originalSourceHash != null && originalSourceHash != getSource().hashCode();
}
private RemoteCallback<Path> getCopySuccessCallback( final CopyPopUpPresenter.View copyPopupView ) {
return new RemoteCallback<Path>() {
@Override
public void callback( final Path response ) {
copyPopupView.hide();
view.hideBusyIndicator();
notification.fire( new NotificationEvent( org.kie.workbench.common.widgets.client.resources.i18n.CommonConstants.INSTANCE.ItemCopiedSuccessfully(),
NotificationEvent.NotificationType.SUCCESS ) );
}
};
}
private RemoteCallback<Path> getDeleteSuccessCallback() {
return new RemoteCallback<Path>() {
@Override
public void callback( final Path response ) {
view.hideBusyIndicator();
notification.fire( new NotificationEvent( org.kie.workbench.common.widgets.client.resources.i18n.CommonConstants.INSTANCE.ItemDeletedSuccessfully(),
NotificationEvent.NotificationType.SUCCESS ) );
}
};
}
private RemoteCallback<Path> getRenameSuccessCallback( final RenamePopUpPresenter.View renamePopupView ) {
return new RemoteCallback<Path>() {
@Override
public void callback( final Path targetPath ) {
renamePopupView.hide();
view.hideBusyIndicator();
notification.fire( new NotificationEvent( org.kie.workbench.common.widgets.client.resources.i18n.CommonConstants.INSTANCE.ItemRenamedSuccessfully(),
NotificationEvent.NotificationType.SUCCESS ) );
}
};
}
protected void save() {
validationService.call( checkMessages -> {
if ( ( (List<ValidationMessage>) checkMessages ).isEmpty() ) {
checkDirtyAndSaveFile();
} else {
validationPopup.showSaveValidationMessages( () -> checkDirtyAndSaveFile(),
() -> {},
( List<ValidationMessage>) checkMessages );
}
} ).validateForSave( versionRecordManager.getPathToLatest(),
context.getDataObject() );
}
private void checkDirtyAndSaveFile() {
final JavaTypeInfoImpl newTypeInfo = new JavaTypeInfoImpl();
if ( isDirty() ) {
if ( context.isEditorChanged() ) {
newTypeInfo.setPackageName( context.getDataObject().getPackageName() );
newTypeInfo.setName( context.getDataObject().getName() );
saveFile( newTypeInfo );
} else {
view.showLoading();
modelerService.call( new RemoteCallback<TypeInfoResult>() {
@Override
public void callback( TypeInfoResult typeInfoResult ) {
view.hideBusyIndicator();
if ( !typeInfoResult.hasErrors() && typeInfoResult.getJavaTypeInfo() != null ) {
newTypeInfo.setPackageName( typeInfoResult.getJavaTypeInfo().getPackageName() );
newTypeInfo.setName( typeInfoResult.getJavaTypeInfo().getName() );
saveFile( newTypeInfo );
} else {
saveFile( null );
}
}
} ).loadJavaTypeInfo( getSource() );
}
} else {
saveFile( null );
}
}
private void saveFile( final JavaTypeInfo newTypeInfo ) {
String currentFileName = DataModelerUtils.extractSimpleFileName( versionRecordManager.getPathToLatest() );
if ( hasPackageNameChanged( newTypeInfo ) ) {
view.showYesNoCancelPopup( CommonConstants.INSTANCE.Information(),
Constants.INSTANCE.modelEditor_confirm_file_package_refactoring( newTypeInfo.getPackageName() ),
new Command() {
@Override
public void execute() {
savePopUpPresenter.show( versionRecordManager.getPathToLatest(), getSaveCommand( newTypeInfo, versionRecordManager.getPathToLatest() ) );
}
},
Constants.INSTANCE.modelEditor_action_yes_refactor_directory(),
ButtonType.PRIMARY,
new Command() {
@Override
public void execute() {
savePopUpPresenter.show( versionRecordManager.getPathToLatest(), getSaveCommand( versionRecordManager.getPathToLatest() ) );
}
},
Constants.INSTANCE.modelEditor_action_no_dont_refactor_directory(),
ButtonType.DANGER );
} else if ( hasFileNameChanged( newTypeInfo, currentFileName ) ) {
view.showYesNoCancelPopup( CommonConstants.INSTANCE.Information(),
Constants.INSTANCE.modelEditor_confirm_file_name_refactoring( newTypeInfo.getName() ),
new Command() {
@Override
public void execute() {
savePopUpPresenter.show( versionRecordManager.getPathToLatest(), getSaveCommand( newTypeInfo, versionRecordManager.getPathToLatest() ) );
}
},
Constants.INSTANCE.modelEditor_action_yes_refactor_file_name(),
ButtonType.PRIMARY,
new Command() {
@Override
public void execute() {
savePopUpPresenter.show( versionRecordManager.getPathToLatest(), getSaveCommand( versionRecordManager.getPathToLatest() ) );
}
},
Constants.INSTANCE.modelEditor_action_no_dont_refactor_file_name(),
ButtonType.DANGER );
} else {
savePopUpPresenter.show( versionRecordManager.getPathToLatest(), getSaveCommand( versionRecordManager.getPathToLatest() ) );
}
}
private boolean hasFileNameChanged( JavaTypeInfo newTypeInfo,
String currentFileName ) {
return currentFileName != null && newTypeInfo != null && newTypeInfo.getName() != null && !currentFileName.equals( newTypeInfo.getName() );
}
private boolean hasPackageNameChanged( JavaTypeInfo newTypeInfo ) {
return newTypeInfo != null && newTypeInfo.getPackageName() != null && !newTypeInfo.getPackageName().equals( context.getEditorModelContent().getOriginalPackageName() );
}
private ParameterizedCommand<String> getSaveCommand( final Path path ) {
return getSaveCommand( null, path );
}
private ParameterizedCommand<String> getSaveCommand( final JavaTypeInfo newTypeInfo,
final Path path ) {
return new ParameterizedCommand<String>() {
@Override
public void execute( final String commitMessage ) {
final DataObject[] modifiedDataObject = new DataObject[ 1 ];
if ( isDirty() ) {
if ( context.isEditorChanged() ) {
//at save time the source has always priority over the model.
//If the source was properly parsed and the editor has changes, we need to send the DataObject
//to the server in order to let the source to be updated prior to save.
modifiedDataObject[ 0 ] = context.getDataObject();
} else {
//if the source has changes, no update form the UI to the source will be performed.
//instead the parsed DataObject must be returned from the server.
modifiedDataObject[ 0 ] = null;
}
}
view.showSaving();
if ( newTypeInfo != null ) {
modelerService.call( getSaveSuccessCallback( newTypeInfo, path ),
new DataModelerErrorCallback( Constants.INSTANCE.modelEditor_saving_error() ) ).saveSource(
getSource(),
path,
modifiedDataObject[ 0 ],
metadata, commitMessage,
newTypeInfo.getPackageName(), newTypeInfo.getName() );
} else {
modelerService.call( getSaveSuccessCallback( newTypeInfo, path ),
new DataModelerErrorCallback( Constants.INSTANCE.modelEditor_saving_error() ) ).saveSource(
getSource(),
path,
modifiedDataObject[ 0 ],
metadata, commitMessage );
}
}
};
}
private RemoteCallback<GenerationResult> getSaveSuccessCallback( final JavaTypeInfo newTypeInfo,
final Path currentPath ) {
return new RemoteCallback<GenerationResult>() {
@Override
public void callback( GenerationResult result ) {
view.hideBusyIndicator();
if ( newTypeInfo == null ) {
Boolean oldDirtyStatus = isDirty();
if ( result.hasErrors() ) {
context.setParseStatus( DataModelerContext.ParseStatus.PARSE_ERRORS );
updateEditorView( null );
context.setDataObject( null );
if ( isEditorTabSelected() ) {
//un common case
showParseErrorsDialog( Constants.INSTANCE.modelEditor_message_file_parsing_errors(),
true,
result.getErrors(),
getOnSaveParseErrorCommand() );
}
} else {
context.setParseStatus( DataModelerContext.ParseStatus.PARSED );
if ( context.isSourceChanged() ) {
updateEditorView( result.getDataObject() );
context.setDataObject( result.getDataObject() );
}
cleanSystemMessages( getCurrentMessageType() );
}
setSource( result.getSource() );
context.setEditionStatus( DataModelerContext.EditionStatus.NO_CHANGES );
setOriginalHash( context.getDataObject() != null ? context.getDataObject().hashCode() : null );
originalSourceHash = getSource().hashCode();
notification.fire( new NotificationEvent( org.kie.workbench.common.widgets.client.resources.i18n.CommonConstants.INSTANCE.ItemSavedSuccessfully(), NotificationEvent.NotificationType.SUCCESS ) );
dataModelerEvent.fire( new DataModelStatusChangeEvent( context.getContextId(),
DataModelerEvent.DATA_MODEL_BROWSER,
oldDirtyStatus,
false ) );
dataModelerEvent.fire( new DataModelSaved( context.getContextId(), null ) );
versionRecordManager.reloadVersions( currentPath );
} else {
notification.fire( new NotificationEvent(
org.uberfire.ext.editor.commons.client.resources.i18n.CommonConstants.INSTANCE.ItemRenamedSuccessfully(),
NotificationEvent.NotificationType.SUCCESS ) );
//If the file was renamed as part of the file saving, don't do anything.
//A rename event will arrive, the same as for the "Rename" case.
//and the file will be automatically reloaded.
}
}
};
}
@Override
protected void loadContent() {
modelerService.call( getLoadModelSuccessCallback(),
getNoSuchFileExceptionErrorCallback() ).loadContent(
versionRecordManager.getCurrentPath(), loadTypesInfo );
}
private RemoteCallback<EditorModelContent> getLoadModelSuccessCallback() {
return new RemoteCallback<EditorModelContent>() {
@Override
public void callback( EditorModelContent content ) {
//Path is set to null when the Editor is closed (which can happen before async calls complete).
if ( versionRecordManager.getCurrentPath() == null ) {
return;
}
uiStarted = false;
resetEditorPages( content.getOverview() );
addSourceEditorPage();
uiStarted = true;
initContext( content );
javaSourceEditor.setReadonly( isReadOnly || !sourceEditionEnabled );
javaSourceEditor.setContent( content.getSource() );
view.hideBusyIndicator();
if ( content.hasErrors() ) {
publishSystemMessages( getCurrentMessageType(), true, content.getErrors() );
}
if ( content.getDataObject() != null ) {
selectEditorTab();
} else {
showParseErrorsDialog( Constants.INSTANCE.modelEditor_message_file_parsing_errors(),
false,
context.getEditorModelContent().getErrors(),
getOnLoadParseErrorCommand() );
}
showDataModellerDocks();
setOriginalHash( context.getDataObject() != null ? context.getDataObject().hashCode() : null );
originalSourceHash = getSource().hashCode();
loading = false;
}
};
}
/**
* This command is executed when a file with parse errors was initially loaded from server.
*/
protected Command getOnLoadParseErrorCommand() {
return new Command() {
@Override
public void execute() {
selectSourceTab();
}
};
}
/**
* This command is executed when a file that apparently is well is saved and the server returns parse errors.
* Uncommon case.
*/
protected Command getOnSaveParseErrorCommand() {
return new Command() {
@Override
public void execute() {
selectSourceTab();
}
};
}
/**
* This command is executed every time the user changes the file source and the data is sent to server por parsing
* during edition and there are parse errors. Typically when the user e.g. goes to the source tab, modifies the code
* and returns to the editor tab.
*/
protected Command getOnSourceParseErrorCommand() {
return new Command() {
@Override
public void execute() {
selectSourceTab();
}
};
}
/**
* This command is executed when the editor tab is selected but there are parse errors.
*/
protected Command getOnEditorTabSelectedWithParseErrorCommand() {
return new Command() {
@Override
public void execute() {
selectSourceTab();
}
};
}
protected void selectSourceTab() {
setSelectedTab( EDITABLE_SOURCE_TAB );
}
private void addSourceEditorPage() {
addPage( new PageImpl( javaSourceEditor,
org.kie.workbench.common.widgets.client.resources.i18n.CommonConstants.INSTANCE.SourceTabTitle() ) {
@Override
public void onFocus() {
if ( uiStarted ) {
onSourceTabSelected();
}
}
@Override
public void onLostFocus() {
}
} );
}
private void rename( final boolean saveCurrentChanges ) {
final DataObject[] modifiedDataObject = new DataObject[ 1 ];
if ( saveCurrentChanges ) {
if ( isDirty() ) {
if ( context.isEditorChanged() ) {
//at save time the source has always priority over the model.
//If the source was properly parsed and the editor has changes, we need to send the DataObject
//to the server in order to let the source to be updated prior to save.
modifiedDataObject[ 0 ] = context.getDataObject();
} else {
//if the source has changes, no update form the UI to the source will be performed.
//instead the parsed DataObject must be returned from the server.
modifiedDataObject[ 0 ] = null;
}
}
}
renamePopUpPresenter.show( versionRecordManager.getPathToLatest(),
javaFileNameValidator,
new CommandWithFileNameAndCommitMessage() {
@Override
public void execute( final FileNameAndCommitMessage details ) {
view.showBusyIndicator( org.kie.workbench.common.widgets.client.resources.i18n.CommonConstants.INSTANCE.Renaming() );
modelerService.call( getRenameSuccessCallback( renamePopUpPresenter.getView() ),
getRenameErrorCallback( renamePopUpPresenter.getView() ) ).rename( versionRecordManager.getPathToLatest(),
details.getNewFileName(),
details.getCommitMessage(),
true,
saveCurrentChanges,
getSource(), modifiedDataObject[ 0 ], metadata );
}
} );
}
protected DataModelerErrorCallback getRenameErrorCallback( final RenamePopUpPresenter.View renamePopupView ) {
return new DataModelerErrorCallback( Constants.INSTANCE.modelEditor_renaming_error() ) {
@Override
public boolean error( final Message message,
final Throwable throwable ) {
renamePopupView.hide();
return super.error( message, throwable );
}
};
}
public DataModel getDataModel() {
return context.getDataModel();
}
public String getSource() {
return javaSourceEditor.getContent();
}
public void setSource( String source ) {
javaSourceEditor.setContent( source );
context.getEditorModelContent().setSource( source );
}
private void setSourceEditionGrant() {
sourceEditionEnabled = authorizationManager.authorize( DataModelerFeatures.EDIT_SOURCES, sessionInfo.getIdentity() );
}
private void initContext( EditorModelContent content ) {
if ( loadTypesInfo ) {
dataModelerWBContext.setAnnotationDefinitions( content.getAnnotationDefinitions() );
dataModelerWBContext.setPropertyTypes( content.getPropertyTypes() );
}
context.setReadonly( isReadOnly );
context.setEditorModelContent( content );
context.setAnnotationDefinitions( dataModelerWBContext.getAnnotationDefinitions() );
context.init( dataModelerWBContext.getPropertyTypes() );
context.setEditionStatus( DataModelerContext.EditionStatus.NO_CHANGES );
if ( content.getDataObject() != null ) {
context.setParseStatus( DataModelerContext.ParseStatus.PARSED );
context.setEditionMode( DataModelerContext.EditionMode.GRAPHICAL_MODE );
} else {
context.setParseStatus( DataModelerContext.ParseStatus.PARSE_ERRORS );
context.setEditionMode( DataModelerContext.EditionMode.SOURCE_MODE );
}
}
@Override
public void onSourceTabSelected() {
context.setEditionMode( DataModelerContext.EditionMode.SOURCE_MODE );
if ( context.isParsed() && context.isEditorChanged() ) {
//If there are changes in the ui the source must be regenerated on server side.
view.showLoading();
modelerService.call( new RemoteCallback<GenerationResult>() {
@Override
public void callback( GenerationResult result ) {
view.hideBusyIndicator();
setSource( result.getSource() );
updateSource( result.getSource() );
context.setEditionStatus( DataModelerContext.EditionStatus.NO_CHANGES );
setActiveContext();
}
}, new DataModelerErrorCallback( Constants.INSTANCE.modelEditor_loading_error() ) ).updateSource( getSource(), versionRecordManager.getCurrentPath(), context.getDataObject() );
} else {
if ( !isOverviewTabSelected() ) {
context.setEditionStatus( DataModelerContext.EditionStatus.NO_CHANGES );
}
updateSource( javaSourceEditor.getContent() );
setActiveContext();
}
}
@Override
public void onOverviewSelected() {
context.setEditionMode( DataModelerContext.EditionMode.SOURCE_MODE );
setActiveContext();
}
@Override
protected void updateSource( String source ) {
setSource( source );
}
private void updateEditorView( DataObject dataObject ) {
//here we need to check if data object name, or package, changed, etc.
//if this is the likely we can show an alert to the user, etc.
//also the file should be renamed.
if ( context.getDataObject() != null ) {
context.getDataModel().removeDataObject( context.getDataObject().getClassName() );
}
if ( dataObject != null ) {
context.getDataModel().removeDataObject( dataObject.getClassName() );
context.getDataModel().addDataObject( dataObject );
}
}
@Override
public void onEditTabSelected() {
if ( !uiStarted ) {
return;
}
boolean doParsing = false;
if ( context.isSourceChanged() ) {
//if there has been changes in the source we should try to parse the file and build the data object again.
doParsing = true;
} else if ( context.isNotParsed() ) {
//uncommon case, the file wasn't parsed yet.
doParsing = true;
}
if ( doParsing ) {
view.showLoading();
//If there are changes in the source, we must try to parse the file.
modelerService.call( new RemoteCallback<GenerationResult>() {
@Override
public void callback( GenerationResult result ) {
view.hideBusyIndicator();
if ( result.hasErrors() ) {
context.setParseStatus( DataModelerContext.ParseStatus.PARSE_ERRORS );
context.setEditionMode( DataModelerContext.EditionMode.SOURCE_MODE );
updateEditorView( null );
context.setDataObject( null );
showParseErrorsDialog( Constants.INSTANCE.modelEditor_message_file_parsing_errors(),
true,
result.getErrors(),
getOnSourceParseErrorCommand() );
} else {
//ok, we can reload the editor tab.
context.setParseStatus( DataModelerContext.ParseStatus.PARSED );
updateEditorView( result.getDataObject() );
context.setEditionStatus( DataModelerContext.EditionStatus.NO_CHANGES );
context.setDataObject( result.getDataObject() );
context.setObjectProperty( null );
context.setEditionMode( DataModelerContext.EditionMode.GRAPHICAL_MODE );
view.setContext( context );
cleanSystemMessages( getCurrentMessageType() );
setActiveContext();
}
}
}, new DataModelerErrorCallback( Constants.INSTANCE.modelEditor_loading_error() ) ).updateDataObject( context.getDataObject(), getSource(), versionRecordManager.getCurrentPath() );
} else {
//no changes in the source tab
if ( !isOverviewTabSelected() ) {
context.setEditionStatus( DataModelerContext.EditionStatus.NO_CHANGES );
}
if ( context.isParseErrors() ) {
//there are parse errors, the editor tab couldn't be loaded. (errors are already published)
showParseErrorsDialog( Constants.INSTANCE.modelEditor_message_file_parsing_errors(),
false,
null,
getOnEditorTabSelectedWithParseErrorCommand() );
} else {
context.setEditionMode( DataModelerContext.EditionMode.GRAPHICAL_MODE );
view.setContext( context );
setActiveContext();
}
}
}
private void showParseErrorsDialog( final String message,
final boolean publishErrors,
final List<DataModelerError> errors,
final Command command ) {
if ( publishErrors && errors != null && !errors.isEmpty() ) {
publishSystemMessages( getCurrentMessageType(), true, errors );
}
view.showParseErrorsDialog( CommonConstants.INSTANCE.Information(), message, command );
}
private void onDataObjectDeleted( @Observes DataObjectDeletedEvent event ) {
if ( context != null &&
event.isFrom( context.getCurrentProject() ) &&
event.getCurrentDataObject() != null &&
context.isParsed() &&
isEditorTabSelected() &&
context.getDataObject() != null &&
!context.getDataObject().getClassName().equals( event.getCurrentDataObject().getClassName() ) ) {
//check deleted object is referenced by current data object.
if ( validatorService.isReferencedByCurrentObject( event.getCurrentDataObject(), context.getDataObject() ) ) {
notification.fire( new NotificationEvent( Constants.INSTANCE.modelEditor_notification_dataObject_referenced_has_been_deleted( event.getCurrentDataObject().getClassName(), context.getDataObject().getClassName() ) ) );
} else if ( !getDataModel().isExternal( event.getCurrentDataObject().getClassName() ) ) {
getDataModel().removeDataObject( event.getCurrentDataObject().getClassName() );
view.refreshTypeLists( true );
}
}
}
private void onDataObjectCreated( @Observes DataObjectCreatedEvent event ) {
if ( context != null &&
event.isFrom( context.getCurrentProject() ) &&
event.getCurrentDataObject() != null &&
getDataModel() != null &&
getDataModel().getDataObject( event.getCurrentDataObject().getClassName() ) == null ) {
getDataModel().addDataObject( event.getCurrentDataObject() );
view.refreshTypeLists( true );
}
}
private void onDataObjectFieldChangeEvent( @Observes DataObjectFieldChangeEvent event ) {
if ( isFromThisContext( event ) ) {
notifyLock( );
refreshTitle( event.getCurrentDataObject(), event.getCurrentField() );
updateChangeStatus( event );
}
}
private void onDataObjectFieldDeleted( @Observes DataObjectFieldDeletedEvent event ) {
if ( isFromThisContext( event ) ) {
updateChangeStatus( event );
}
}
protected void onDataObjectChangeEvent( @Observes DataObjectChangeEvent event ) {
if ( isFromThisContext( event ) ) {
notifyLock();
refreshTitle( event.getCurrentDataObject() );
updateChangeStatus( event );
}
}
private void onDataObjectFieldCreated( @Observes DataObjectFieldCreatedEvent event ) {
if ( isFromThisContext( event ) ) {
updateChangeStatus( event );
}
}
protected void onDataObjectSelectedEvent( @Observes DataObjectSelectedEvent event ) {
if ( isFromThisContext( event ) ) {
refreshTitle( event.getCurrentDataObject() );
}
}
protected void onDataObjectFieldSelectedEvent( @Observes DataObjectFieldSelectedEvent event ) {
if ( isFromThisContext( event ) ) {
refreshTitle( event.getCurrentDataObject(), event.getCurrentField() );
}
}
private void notifyLock() {
lockRequired.fire( new LockRequiredEvent() );
}
private void cleanSystemMessages( String currentMessageType ) {
UnpublishMessagesEvent unpublishMessage = new UnpublishMessagesEvent();
unpublishMessage.setShowSystemConsole( false );
unpublishMessage.setMessageType( currentMessageType );
unpublishMessage.setUserId( ( sessionInfo != null && sessionInfo.getIdentity() != null ) ? sessionInfo.getIdentity().getIdentifier() : null );
unpublishMessagesEvent.fire( unpublishMessage );
}
private void publishSystemMessages( String messageType,
boolean cleanExisting,
List<DataModelerError> errors ) {
PublishBatchMessagesEvent publishMessage = new PublishBatchMessagesEvent();
publishMessage.setCleanExisting( cleanExisting );
publishMessage.setMessageType( messageType );
publishMessage.setUserId( ( sessionInfo != null && sessionInfo.getIdentity() != null ) ? sessionInfo.getIdentity().getIdentifier() : null );
publishMessage.setPlace( PublishBaseEvent.Place.TOP );
SystemMessage systemMessage;
for ( DataModelerError error : errors ) {
systemMessage = new SystemMessage();
systemMessage.setMessageType( messageType );
systemMessage.setId( error.getId() );
systemMessage.setText( error.getMessage() );
systemMessage.setPath( error.getFile() );
systemMessage.setLevel( error.getLevel() );
systemMessage.setLine( error.getLine() );
systemMessage.setColumn( error.getColumn() );
publishMessage.getMessagesToPublish().add( systemMessage );
}
publishBatchMessagesEvent.fire( publishMessage );
}
protected void makeMenuBar() {
//menus =
menuBuilder
.addSave( versionRecordManager.newSaveMenuItem( new Command() {
@Override
public void execute() {
onSave();
}
} ) )
.addCopy( new Command() {
@Override
public void execute() {
onCopy();
}
} )
.addRename( new Command() {
@Override
public void execute() {
onSafeRename();
}
} )
.addDelete( new Command() {
@Override
public void execute() {
onSafeDelete();
}
} )
.addValidate(
onValidate()
)
.addNewTopLevelMenu( versionRecordManager.buildMenu() );
menus = menuBuilder.build();
}
private void clearContext() {
context.clear();
}
private String getCurrentMessageType() {
return currentMessageType;
}
private boolean isFromThisContext( DataModelerEvent event ) {
return event.isFromContext( context != null ? context.getContextId() : null );
}
private void refreshTitle( DataObject dataObject ) {
if ( dataObject != null ) {
String label = DataModelerUtils.getDataObjectFullLabel( dataObject, false );
String title = "'" + label + "'" + Constants.INSTANCE.modelEditor_general_properties_label();
String tooltip = dataObject.getClassName();
view.setDomainContainerTitle( title, tooltip );
}
}
private void refreshTitle( DataObject dataObject, ObjectProperty objectProperty ) {
if ( dataObject != null && objectProperty != null ) {
String title = "'" + objectProperty.getName() + "'" + Constants.INSTANCE.modelEditor_general_properties_label();
String tooltip = dataObject.getClassName() + "." + objectProperty.getName();
view.setDomainContainerTitle( title, tooltip );
}
}
private void updateChangeStatus( DataModelerEvent event ) {
if ( isFromThisContext( event ) ) {
context.setEditionStatus( DataModelerContext.EditionStatus.EDITOR_CHANGED );
dataModelerEvent.fire( new DataModelStatusChangeEvent( context.getContextId(), null, false, true ) );
}
}
}