package ilarkesto.gwt.client; import ilarkesto.core.base.Str; import ilarkesto.core.logging.Log; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.dom.client.KeyPressEvent; import com.google.gwt.event.dom.client.KeyPressHandler; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.FocusListener; import com.google.gwt.user.client.ui.FocusPanel; import com.google.gwt.user.client.ui.SimplePanel; import com.google.gwt.user.client.ui.Widget; public abstract class AViewEditWidget extends AWidget { private static AViewEditWidget currentEditor; private static ModeSwitchHandler globalModeSwitchHandler; private boolean viewMode = true; private ModeSwitchHandler modeSwitchHandler; private FocusPanel masterWrapper; private FocusPanel viewerWrapper; private FlowPanel editorWrapper; private SimplePanel errorWrapper; private boolean viewerInitialized; private boolean viewerInitializing; private boolean editorInitialized; private boolean editorInitializing; protected abstract void onViewerUpdate(); protected abstract Widget onViewerInitialization(); protected abstract void onEditorUpdate(); protected abstract Widget onEditorInitialization(); protected abstract void onEditorSubmit(); @Override protected final Widget onInitialization() { masterWrapper = new FocusPanel(); masterWrapper.setStyleName("AViewEditWidget"); Gwt.addHtmlTooltip(masterWrapper, getTooltip()); return masterWrapper; } @Override protected final void onUpdate() { if (isViewMode()) { updateViewer(); } else { focusEditor(); // updateEditor(); } } protected void focusEditor() {} public void switchToEditMode() { if (isEditMode()) return; if (!isEditable()) return; Log.DEBUG("Switching to edit mode: " + toString()); ensureEditorInitialized(); viewMode = false; if (currentEditor != null) { currentEditor.closeEditor(); } currentEditor = this; updateEditor(); focusEditor(); if (modeSwitchHandler != null) modeSwitchHandler.onEditorActivated(this); if (globalModeSwitchHandler != null) globalModeSwitchHandler.onEditorActivated(this); onSwitchToEditModeCompleted(); } protected void onSwitchToEditModeCompleted() {} public abstract boolean isEditable(); public String getTooltip() { return null; } public void switchToViewMode() { if (isViewMode()) return; Log.DEBUG("Switching to view mode: " + toString()); viewMode = true; if (currentEditor == this) currentEditor = null; if (modeSwitchHandler != null) modeSwitchHandler.onViewerActivated(this); if (globalModeSwitchHandler != null) globalModeSwitchHandler.onViewerActivated(this); update(); } protected final boolean submitEditor() { if (!isEditMode()) throw new RuntimeException("submitEditor() not allowed. Not in edit mode: " + toString()); try { onEditorSubmit(); } catch (Throwable ex) { setEditorError(ex.getMessage()); return false; } setEditorError(null); switchToViewMode(); updateAutoUpdateWidget(); return true; } protected void updateAutoUpdateWidget() { Gwt.update(Gwt.getRootWidget()); } protected final void cancelEditor() { if (!isEditMode()) throw new RuntimeException("cancelEditor() not allowed. Not in edit mode: " + toString()); switchToViewMode(); } protected void closeEditor() { cancelEditor(); } private void initializeViewer() { if (viewerInitialized) throw new RuntimeException("Viewer already initialized: " + toString()); if (viewerInitializing) throw new RuntimeException("Viewer already initializing: " + toString()); viewerInitializing = true; // GwtLogger.DEBUG("Initializing Viewer: " + toString()); viewerWrapper = new FocusPanel(); viewerWrapper.getElement().setId(getViewerId()); viewerWrapper.setStyleName("AViewEditWidget-viewer"); viewerWrapper.addClickHandler(new ViewerClickListener()); viewerWrapper.setWidget(onViewerInitialization()); viewerInitialized = true; viewerInitializing = false; } private void updateViewer() { if (viewerInitializing) throw new RuntimeException("Viewer initializing. Don't call update() within onViewerInitailization(): " + toString()); if (!viewerInitialized) initializeViewer(); // GwtLogger.DEBUG("Updating viewer: " + toString()); onViewerUpdate(); if (isEditable()) { viewerWrapper.addStyleDependentName("editable"); } else { viewerWrapper.removeStyleDependentName("editable"); } masterWrapper.setWidget(viewerWrapper); } private void initializeEditor() { if (editorInitialized) throw new RuntimeException("Editor already initialized: " + toString()); if (editorInitializing) throw new RuntimeException("Editor already initializing: " + toString()); editorInitializing = true; // GwtLogger.DEBUG("Initializing Editor: " + toString()); errorWrapper = new SimplePanel(); editorWrapper = new FlowPanel(); editorWrapper.setStyleName("AViewEditWidget-editor"); editorWrapper.add(errorWrapper); Widget editor = onEditorInitialization(); editor.getElement().setId(getEditroId()); editorWrapper.add(editor); editorInitialized = true; editorInitializing = false; } protected void setEditorError(String text) { if (Str.isBlank(text)) { errorWrapper.clear(); } else { errorWrapper.setWidget(Gwt.createDiv("AViewEditWidget-error", text)); } } public void setModeSwitchHandler(ModeSwitchHandler modeSwitchHandler) { this.modeSwitchHandler = modeSwitchHandler; } protected final void ensureEditorInitialized() { if (editorInitializing) throw new RuntimeException("Editor initializing. Don't call update() within onEditorInitailization(): " + toString()); if (!editorInitialized) initializeEditor(); } private void updateEditor() { initialize(); masterWrapper.setWidget(editorWrapper); onEditorUpdate(); getElement().scrollIntoView(); } public final boolean isViewMode() { return viewMode; } public final boolean isEditMode() { return !viewMode; } @Override public String getId() { return Str.getSimpleName(getClass()).replace('$', '_'); } protected String getViewerId() { return "viewer_" + getId(); } protected String getEditroId() { return "editor_" + getId(); } public static AViewEditWidget getCurrentEditor() { return currentEditor; } public static void setGlobalModeSwitchHandler(ModeSwitchHandler globalModeSwitchHandler) { AViewEditWidget.globalModeSwitchHandler = globalModeSwitchHandler; } private class ViewerClickListener implements ClickHandler { @Override public void onClick(ClickEvent event) { if (isEditable()) switchToEditMode(); event.stopPropagation(); } } protected class SubmitEditorFocusListener implements FocusListener { public SubmitEditorFocusListener() {} @Override public void onFocus(Widget sender) {} @Override public void onLostFocus(Widget sender) { submitEditor(); } } public class CancelKeyPressHandler implements KeyPressHandler { @Override public void onKeyPress(KeyPressEvent event) { char keyCode = event.getCharCode(); if (keyCode == KeyCodes.KEY_ESCAPE) { cancelEditor(); } } } public static interface ModeSwitchHandler { void onViewerActivated(AViewEditWidget widget); void onEditorActivated(AViewEditWidget widget); } }