/**
* Copyright 2013 European Parliament
*
* Licensed under the EUPL, Version 1.1 or - as soon they will be approved by the European Commission - subsequent versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* http://joinup.ec.europa.eu/software/page/eupl
*
* Unless required by applicable law or agreed to in writing, software distributed under the Licence is distributed on an "AS IS" basis,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Licence for the specific language governing permissions and limitations under the Licence.
*/
package org.nsesa.editor.gwt.an.drafting.client.ui.main.document;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Node;
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.user.client.DOM;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.FocusPanel;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.RootLayoutPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import com.google.web.bindery.event.shared.HandlerRegistration;
import org.nsesa.editor.gwt.an.common.client.ui.overlay.document.gen.akomantoso20.BasehierarchyComplexType;
import org.nsesa.editor.gwt.an.drafting.client.event.DocumentToggleStructureEvent;
import org.nsesa.editor.gwt.an.drafting.client.event.DocumentToggleStructureEventHandler;
import org.nsesa.editor.gwt.an.drafting.client.mode.StructureViewMode;
import org.nsesa.editor.gwt.an.drafting.client.ui.main.document.outline.OutlineController;
import org.nsesa.editor.gwt.core.client.ClientFactory;
import org.nsesa.editor.gwt.core.client.ServiceFactory;
import org.nsesa.editor.gwt.core.client.event.*;
import org.nsesa.editor.gwt.core.client.event.document.DocumentScrollToEvent;
import org.nsesa.editor.gwt.core.client.event.document.DocumentScrollToEventHandler;
import org.nsesa.editor.gwt.core.client.event.visualstructure.*;
import org.nsesa.editor.gwt.core.client.event.widget.*;
import org.nsesa.editor.gwt.core.client.keyboard.KeyboardListener;
import org.nsesa.editor.gwt.core.client.mode.ActiveState;
import org.nsesa.editor.gwt.core.client.ui.document.DefaultDocumentController;
import org.nsesa.editor.gwt.core.client.ui.document.DocumentInjector;
import org.nsesa.editor.gwt.core.client.ui.document.sourcefile.actionbar.ActionBarController;
import org.nsesa.editor.gwt.core.client.ui.document.sourcefile.actionbar.create.ActionBarCreatePanelController;
import org.nsesa.editor.gwt.core.client.ui.overlay.*;
import org.nsesa.editor.gwt.core.client.ui.overlay.document.*;
import org.nsesa.editor.gwt.core.client.ui.rte.RichTextEditor;
import org.nsesa.editor.gwt.core.shared.DocumentDTO;
import org.nsesa.editor.gwt.inline.client.event.AttachInlineEditorEvent;
import org.nsesa.editor.gwt.inline.client.event.DetachInlineEditorEvent;
import org.nsesa.editor.gwt.inline.client.ui.inline.InlineEditorController;
import java.util.List;
import java.util.logging.Logger;
/**
* Date: 05/02/13 09:32
*
* @author <a href="philip.luppens@gmail.com">Philip Luppens</a>
* @version $Id$
*/
public class DraftingDocumentController extends DefaultDocumentController {
private static final Logger LOG = Logger.getLogger(DraftingDocumentController.class.getName());
public static final int SCROLL_TO_OFFSET = 200;
private final OverlaySnippetFactory overlaySnippetFactory;
private final OverlaySnippetEvaluator overlaySnippetEvaluator;
private final InlineEditorController inlineEditorController;
private final Transformer transformer;
private OutlineController outlineController;
private ActionBarController actionBarController;
// popup with available child controllers
private ActionBarCreatePanelController actionBarCreatePanelController;
private FocusPanel actionBarCreatePanelFocusPanel = new FocusPanel();
private PopupPanel actionBarCreatePanelControllerPopup = new PopupPanel();
// ------------- selector ------------------------
private final OverlayWidgetSelector overlayWidgetSelector = new OverlayWidgetSelector() {
@Override
public boolean select(OverlayWidget toSelect) {
return toSelect instanceof BasehierarchyComplexType || toSelect.getOverlayElement().getClassName().contains("nsesa-inline");
}
};
// ------------- event handler registration -----------
private HandlerRegistration documentToggleStructureEventHandler;
private HandlerRegistration switchTabEventHandlerRegistration;
private HandlerRegistration notificationEventHandlerRegistration;
private HandlerRegistration confirmationEventHandlerRegistration;
private HandlerRegistration criticalEventHandlerRegistration;
private HandlerRegistration overlayWidgetSelectEventHandlerRegistration;
private HandlerRegistration resizeEventHandlerRegistration;
private HandlerRegistration documentScrollToEventHandlerRegistration;
private HandlerRegistration keyComboHandlerRegistration;
private HandlerRegistration draftingToggleEventHandlerRegistration;
private HandlerRegistration draftingAttributesToggleEventHandlerRegistration;
// ----------------- keyboard shortcuts ---------------------
private KeyboardListener.KeyCombo ctrlEnter = new KeyboardListener.KeyCombo(false, false, true, KeyCodes.KEY_ENTER);
private KeyboardListener.KeyCombo enter = new KeyboardListener.KeyCombo(false, false, false, KeyCodes.KEY_ENTER);
private KeyboardListener.KeyCombo tab = new KeyboardListener.KeyCombo(false, false, false, KeyCodes.KEY_TAB);
private KeyboardListener.KeyCombo escape = new KeyboardListener.KeyCombo(false, false, false, KeyCodes.KEY_ESCAPE);
private KeyboardListener.KeyCombo delete = new KeyboardListener.KeyCombo(false, false, false, KeyCodes.KEY_DELETE);
private KeyboardListener.KeyCombo ctrlS = new KeyboardListener.KeyCombo(false, false, true, 83); // 83 is 's' key
private KeyboardListener.KeyCombo upArrow = new KeyboardListener.KeyCombo(false, false, false, KeyCodes.KEY_UP);
private KeyboardListener.KeyCombo downArrow = new KeyboardListener.KeyCombo(false, false, false, KeyCodes.KEY_DOWN);
private KeyboardListener.KeyCombo altUpArrow = new KeyboardListener.KeyCombo(false, true, false, KeyCodes.KEY_UP);
private KeyboardListener.KeyCombo altDownArrow = new KeyboardListener.KeyCombo(false, true, false, KeyCodes.KEY_DOWN);
private HandlerRegistration overlayWidgetModifyHandlerRegistration;
private HandlerRegistration overlayWidgetDeleteHandlerRegistration;
private HandlerRegistration overlayWidgetNewEventHandlerRegistration;
private com.google.gwt.event.shared.HandlerRegistration inlineEditorControllerSaveHandlerRegistration;
private com.google.gwt.event.shared.HandlerRegistration inlineEditorControllerCancelHandlerRegistration;
@Inject
public DraftingDocumentController(final ClientFactory clientFactory,
final ServiceFactory serviceFactory,
final OverlayFactory overlayFactory,
final Locator locator,
final Creator creator,
final Mover mover,
final InlineEditorController inlineEditorController,
final OverlaySnippetFactory overlaySnippetFactory,
final OverlaySnippetEvaluator overlaySnippetEvaluator,
final @Named("xml") Transformer transformer) {
super(clientFactory, serviceFactory, overlayFactory, locator, creator, mover);
this.inlineEditorController = inlineEditorController;
this.overlaySnippetFactory = overlaySnippetFactory;
this.overlaySnippetEvaluator = overlaySnippetEvaluator;
this.transformer = transformer;
}
@Override
public void registerKeyCombos() {
super.registerKeyCombos();
clientFactory.getKeyboardListener().register(ctrlEnter, enter, tab, escape, delete, ctrlS, upArrow, downArrow, altUpArrow, altDownArrow);
}
@Override
public void registerModes() {
super.registerModes();
registerMode(StructureViewMode.KEY, new StructureViewMode(this));
}
@Override
public void registerListeners() {
documentScrollToEventHandlerRegistration = clientFactory.getEventBus().addHandler(DocumentScrollToEvent.TYPE, new DocumentScrollToEventHandler() {
@Override
public void onEvent(DocumentScrollToEvent event) {
sourceFileController.scrollTo(event.getTarget(), event.getOffset());
}
});
// forward the resize event
resizeEventHandlerRegistration = clientFactory.getEventBus().addHandler(ResizeEvent.TYPE, new ResizeEventHandler() {
@Override
public void onEvent(ResizeEvent event) {
documentEventBus.fireEvent(event);
view.setDocumentHeight(event.getHeight());
}
});
overlayWidgetSelectEventHandlerRegistration = documentEventBus.addHandler(OverlayWidgetSelectEvent.TYPE, new OverlayWidgetSelectEventHandler() {
@Override
public void onEvent(OverlayWidgetSelectEvent event) {
final OverlayWidget activeOverlayWidget = event.getOverlayWidget();
sourceFileController.setActiveOverlayWidget(activeOverlayWidget);
if (activeOverlayWidget != null) {
actionBarCreatePanelController.setOverlayWidget(activeOverlayWidget);
actionBarController.attach(activeOverlayWidget, DraftingDocumentController.this);
actionBarController.setLocation(locator.getLocation(activeOverlayWidget, document.getLanguageIso(), true));
// check if the sender has the nsesa-inline class element
if (activeOverlayWidget.getOverlayElement().getClassName().contains("nsesa-inline")) {
// if so, immediately add the inline editor (don't wait for a enter)
// clientFactory.getEventBus().fireEvent(new DocumentScrollToEvent(activeOverlayWidget.asWidget(), DraftingDocumentController.this, false, 100));
clientFactory.getScheduler().scheduleDeferred(new Scheduler.ScheduledCommand() {
@Override
public void execute() {
handleOverlayWidgetModify(activeOverlayWidget);
}
});
}
}
}
});
// forward the critical error event
criticalEventHandlerRegistration = documentEventBus.addHandler(CriticalErrorEvent.TYPE, new CriticalErrorEventHandler() {
@Override
public void onEvent(CriticalErrorEvent event) {
clientFactory.getEventBus().fireEvent(event);
}
});
// forward the confirmation event
confirmationEventHandlerRegistration = documentEventBus.addHandler(ConfirmationEvent.TYPE, new ConfirmationEventHandler() {
@Override
public void onEvent(ConfirmationEvent event) {
clientFactory.getEventBus().fireEvent(event);
}
});
// forward the notification event to the parent event bus
notificationEventHandlerRegistration = documentEventBus.addHandler(NotificationEvent.TYPE, new NotificationEventHandler() {
@Override
public void onEvent(NotificationEvent event) {
clientFactory.getEventBus().fireEvent(event);
}
});
// handle requests to switch the document tabs
switchTabEventHandlerRegistration = documentEventBus.addHandler(SwitchTabEvent.TYPE, new SwitchTabEventHandler() {
@Override
public void onEvent(SwitchTabEvent event) {
view.switchToTab(event.getTabIndex());
}
});
documentToggleStructureEventHandler = documentEventBus.addHandler(DocumentToggleStructureEvent.TYPE, new DocumentToggleStructureEventHandler() {
@Override
public void onEvent(DocumentToggleStructureEvent event) {
applyState(StructureViewMode.KEY, new ActiveState(event.isToggle()));
}
});
overlayWidgetModifyHandlerRegistration = documentEventBus.addHandler(OverlayWidgetModifyEvent.TYPE, new OverlayWidgetModifyEventHandler() {
@Override
public void onEvent(OverlayWidgetModifyEvent event) {
documentEventBus.fireEvent(new OverlayWidgetSelectEvent(event.getOverlayWidget(), DraftingDocumentController.this));
clientFactory.getEventBus().fireEvent(new AttachInlineEditorEvent(event.getOverlayWidget(), DraftingDocumentController.this));
}
});
overlayWidgetDeleteHandlerRegistration = documentEventBus.addHandler(OverlayWidgetDeleteEvent.TYPE, new OverlayWidgetDeleteEventHandler() {
@Override
public void onEvent(OverlayWidgetDeleteEvent event) {
handleOverlayWidgetDelete(event.getOverlayWidget());
}
});
overlayWidgetNewEventHandlerRegistration = documentEventBus.addHandler(OverlayWidgetNewEvent.TYPE, new OverlayWidgetNewEventHandler() {
@Override
public void onEvent(final OverlayWidgetNewEvent event) {
final OverlayWidget child = event.getChild();
if (event.getReference() == event.getParentOverlayWidget()) {
// this is a new child
event.getParentOverlayWidget().addOverlayWidget(child);
DOM.appendChild(event.getParentOverlayWidget().asWidget().getElement(), child.asWidget().getElement());
if (!child.isAttached()) child.onAttach();
} else {
// this is a sibling
event.getParentOverlayWidget().addOverlayWidget(child, event.getReference().getIndex() + 1, true);
DOM.insertChild(event.getParentOverlayWidget().asWidget().getElement(), child.asWidget().getElement(), event.getReference().getDomIndex());
if (!child.isAttached()) child.onAttach();
}
clientFactory.getScheduler().scheduleDeferred(new Scheduler.ScheduledCommand() {
@Override
public void execute() {
documentEventBus.fireEvent(new OverlayWidgetSelectEvent(child, DraftingDocumentController.this));
clientFactory.getEventBus().fireEvent(new AttachInlineEditorEvent(child, DraftingDocumentController.this));
final OverlaySnippet overlaySnippet = overlaySnippetFactory.getSnippet(child);
if (overlaySnippet != null) {
overlaySnippetEvaluator.addEvaluator(new OverlaySnippetEvaluator.Evaluator() {
@Override
public String getPlaceHolder() {
return "${widget.num}";
}
@Override
public String evaluate() {
if (child.getNumberingType() == null || child.getFormat() == null) {
if (child.getType().equalsIgnoreCase(event.getReference().getType())) {
// we're the same type, so inherit the numbering type
child.setNumberingType(event.getReference().getNumberingType());
child.setFormat(event.getReference().getFormat());
} else {
// find similar type, if any
final OverlayWidget previous = event.getReference().getPreviousSibling(new OverlayWidgetSelector() {
@Override
public boolean select(OverlayWidget toSelect) {
return !toSelect.isIntroducedByAnAmendment() && event.getReference().getType().equalsIgnoreCase(toSelect.getType());
}
});
if (previous != null) {
child.setNumberingType(previous.getNumberingType());
child.setFormat(previous.getFormat());
} else {
final OverlayWidget next = event.getReference().getNextSibling(new OverlayWidgetSelector() {
@Override
public boolean select(OverlayWidget toSelect) {
return !toSelect.isIntroducedByAnAmendment() && event.getReference().getType().equalsIgnoreCase(toSelect.getType());
}
});
if (next != null) {
child.setNumberingType(next.getNumberingType());
child.setFormat(next.getFormat());
} else {
// free to choose, but should be different from parent
child.setNumberingType(NumberingType.ROMANITO);
child.setFormat(Format.BRACKET);
}
}
}
}
child.setParentOverlayWidget(event.getParentOverlayWidget());
//add the overlay widget in the parent children collection to compute the num
String num = locator.getNum(child, document.getLanguageIso(), true);
return num == null ? "" : num;
}
});
child.getOverlayElement().setInnerHTML(overlaySnippet.getContent(overlaySnippetEvaluator));
} else {
child.getOverlayElement().setInnerHTML("");
}
inlineEditorController.getRichTextEditor().setHTML(child.getInnerHTML());
}
});
}
});
// listen for keyboard combos
keyComboHandlerRegistration = clientFactory.getEventBus().addHandler(KeyComboEvent.TYPE, new KeyComboEventHandler() {
@Override
public void onEvent(KeyComboEvent event) {
event.getNativeEvent().preventDefault();
final OverlayWidget activeOverlayWidget = sourceFileController.getActiveOverlayWidget();
if (ctrlEnter.equals(event.getKeyCombo())) {
// ------------- CTRL + ENTER -------------
if (!actionBarCreatePanelControllerPopup.isShowing()) {
if (activeOverlayWidget != null) {
actionBarCreatePanelController.setOverlayWidget(activeOverlayWidget);
if (inlineEditorController.isShowing()) {
final RichTextEditor.CaretPosition caretPosition = inlineEditorController.getRichTextEditor().getCaretPosition();
if (caretPosition != null) {
actionBarCreatePanelControllerPopup.setPopupPosition(caretPosition.getLeft(), caretPosition.getTop());
}
} else {
actionBarCreatePanelControllerPopup.showRelativeTo(actionBarController.getView().getChildHandler());
}
actionBarCreatePanelController.getView().asWidget().setVisible(true);
actionBarCreatePanelControllerPopup.show();
actionBarCreatePanelFocusPanel.setFocus(true);
}
}
} else if (escape.equals(event.getKeyCombo())) {
// ------------- Escape -------------
if (actionBarCreatePanelControllerPopup.isShowing()) {
actionBarCreatePanelControllerPopup.hide();
actionBarCreatePanelFocusPanel.setFocus(false);
inlineEditorController.getRichTextEditor().setFocus(true);
} else if (inlineEditorController.isShowing()) {
cancelModify();
}
} else if (ctrlS.equals(event.getKeyCombo())) {
// ------------- CTRL + s -------------
final String content = transformer.transform(sourceFileController.getOverlayWidgets().get(0));
serviceFactory.getGwtDocumentService().saveDocumentContent(clientFactory.getClientContext(), document.getDocumentID(), content, new AsyncCallback<Void>() {
@Override
public void onFailure(Throwable caught) {
clientFactory.getEventBus().fireEvent(new CriticalErrorEvent("Could not save document.", caught));
}
@Override
public void onSuccess(Void result) {
// all fine!
clientFactory.getEventBus().fireEvent(new NotificationEvent("Document successfully saved."));
}
});
} else if (downArrow.equals(event.getKeyCombo())) {
// ------------- Down arrow -------------
if (actionBarCreatePanelControllerPopup.isShowing()) {
actionBarCreatePanelFocusPanel.setFocus(true);
actionBarCreatePanelController.highlightNext();
} else if (!inlineEditorController.isShowing()) {
final OverlayWidget next = activeOverlayWidget != null ? activeOverlayWidget.next(overlayWidgetSelector) : sourceFileController.getOverlayWidgets().get(0);
if (next != null) {
documentEventBus.fireEvent(new OverlayWidgetSelectEvent(next, DraftingDocumentController.this));
clientFactory.getEventBus().fireEvent(new DocumentScrollToEvent(next.asWidget(), DraftingDocumentController.this, false, SCROLL_TO_OFFSET));
}
}
} else if (upArrow.equals(event.getKeyCombo())) {
// ------------- Up arrow -------------
if (actionBarCreatePanelControllerPopup.isShowing()) {
actionBarCreatePanelFocusPanel.setFocus(true);
actionBarCreatePanelController.highlightPrevious();
} else if (!inlineEditorController.isShowing()) {
if (activeOverlayWidget != null) {
final OverlayWidget previous = activeOverlayWidget.previous(overlayWidgetSelector);
if (previous != null) {
documentEventBus.fireEvent(new OverlayWidgetSelectEvent(previous, DraftingDocumentController.this));
clientFactory.getEventBus().fireEvent(new DocumentScrollToEvent(previous.asWidget(), DraftingDocumentController.this, false, SCROLL_TO_OFFSET));
}
}
}
} else if (enter.equals(event.getKeyCombo())) {
// ------------- Single ENTER -------------
if (actionBarCreatePanelControllerPopup.isShowing()) {
actionBarCreatePanelControllerPopup.hide();
// there is no need to scroll into document
// clientFactory.getEventBus().fireEvent(new DocumentScrollToEvent(activeOverlayWidget.asWidget(), DraftingDocumentController.this, false, SCROLL_TO_OFFSET));
final OverlayWidget selectedSibling = actionBarCreatePanelController.getSelectedSibling();
if (selectedSibling != null) {
LOG.info("Selected as sibling: " + selectedSibling);
final com.google.gwt.user.client.Element clone = DOM.clone(selectedSibling.asWidget().getElement(), true);
final OverlayWidget cloneSibling = overlayFactory.getAmendableWidget(clone);
// number and format get given by the siblings
// but they need to be explicitly set to null
cloneSibling.setOverlayStrategy(null);
cloneSibling.setFormat(null);
cloneSibling.setNumberingType(null);
// get the correct index
if (inlineEditorController.isShowing()) {
clientFactory.getEventBus().fireEvent(new VisualStructureInsertionEvent(cloneSibling));
} else {
documentEventBus.fireEvent(new OverlayWidgetNewEvent(activeOverlayWidget.getParentOverlayWidget(), activeOverlayWidget, cloneSibling));
}
}
final OverlayWidget selectedChild = actionBarCreatePanelController.getSelectedChild();
if (selectedChild != null) {
LOG.info("Selected as child: " + selectedChild);
final com.google.gwt.user.client.Element clone = DOM.clone(selectedChild.asWidget().getElement(), true);
final OverlayWidget cloneChild = overlayFactory.getAmendableWidget(clone);
cloneChild.setNumberingType(actionBarCreatePanelController.getSelectedChild().getNumberingType());
cloneChild.setFormat(actionBarCreatePanelController.getSelectedChild().getFormat());
if (inlineEditorController.isShowing()) {
clientFactory.getEventBus().fireEvent(new VisualStructureInsertionEvent(cloneChild));
} else {
documentEventBus.fireEvent(new OverlayWidgetNewEvent(activeOverlayWidget, activeOverlayWidget, cloneChild));
}
}
// TODO
} else if (activeOverlayWidget != null || !(inlineEditorController.getOverlayWidget().equals(activeOverlayWidget))) {
handleOverlayWidgetModify(activeOverlayWidget);
}
} else if (tab.equals(event.getKeyCombo())) {
// ------------- Single TAB -------------
if (inlineEditorController.isShowing()) {
// close the editor, copy the value into the overlay widget
modifyOverlayWidget(activeOverlayWidget, inlineEditorController.getRichTextEditor().getHTML());
// and finally destroy the instance
clientFactory.getEventBus().fireEvent(new DetachInlineEditorEvent(DraftingDocumentController.this));
inlineEditorController.getRichTextEditor().setFocus(false);
restoreFocusOnViewPort();
}
} else if (delete.equals(event.getKeyCombo())) {
// ------------- DELETE -------------
if (!inlineEditorController.isShowing() && activeOverlayWidget != null) {
handleOverlayWidgetDelete(activeOverlayWidget);
restoreFocusOnViewPort();
}
} else if (altUpArrow.equals(event.getKeyCombo())) {
// ------------- CTRL + Up arrow -------------
if (activeOverlayWidget != null) {
if (mover.canMoveUp(activeOverlayWidget)) {
activeOverlayWidget.moveUp();
clientFactory.getScheduler().scheduleDeferred(new Scheduler.ScheduledCommand() {
@Override
public void execute() {
documentEventBus.fireEvent(new OverlayWidgetSelectEvent(activeOverlayWidget, DraftingDocumentController.this));
clientFactory.getEventBus().fireEvent(new DocumentScrollToEvent(activeOverlayWidget.asWidget(), DraftingDocumentController.this, false, 100));
// TODO schedule via timer
redrawOutline(activeOverlayWidget.getRoot());
}
});
}
}
} else if (altDownArrow.equals(event.getKeyCombo())) {
// ------------- CTRL + Down arrow -------------
if (activeOverlayWidget != null) {
if (mover.canMoveDown(activeOverlayWidget)) {
activeOverlayWidget.moveDown();
clientFactory.getScheduler().scheduleDeferred(new Scheduler.ScheduledCommand() {
@Override
public void execute() {
documentEventBus.fireEvent(new OverlayWidgetSelectEvent(activeOverlayWidget, DraftingDocumentController.this));
clientFactory.getEventBus().fireEvent(new DocumentScrollToEvent(activeOverlayWidget.asWidget(), DraftingDocumentController.this, false, 100));
// TODO schedule via timer
redrawOutline(activeOverlayWidget.getRoot());
}
});
}
}
}
}
});
draftingToggleEventHandlerRegistration = clientFactory.getEventBus().addHandler(VisualStructureToggleEvent.TYPE, new VisualStructureToggleEventHandler() {
@Override
public void onEvent(VisualStructureToggleEvent event) {
inlineEditorController.getRichTextEditor().toggleVisualStructure(event.isShown());
}
});
draftingAttributesToggleEventHandlerRegistration = clientFactory.getEventBus().addHandler(VisualStructureAttributesToggleEvent.TYPE, new VisualStructureAttributesToggleEventHandler() {
@Override
public void onEvent(VisualStructureAttributesToggleEvent event) {
inlineEditorController.getRichTextEditor().toggleVisualStructureAttributes(event.isShown());
}
});
inlineEditorControllerSaveHandlerRegistration = inlineEditorController.getView().getSaveButton().addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
modifyOverlayWidget(sourceFileController.getActiveOverlayWidget(), inlineEditorController.getRichTextEditor().getHTML());
// and finally destroy the instance
clientFactory.getEventBus().fireEvent(new DetachInlineEditorEvent(DraftingDocumentController.this));
inlineEditorController.getRichTextEditor().setFocus(false);
restoreFocusOnViewPort();
}
});
inlineEditorControllerCancelHandlerRegistration = inlineEditorController.getView().getCancelAnchor().addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
cancelModify();
}
});
}
public void handleOverlayWidgetDelete(final OverlayWidget overlayWidget) {
final OverlayWidget parentOverlayWidget = overlayWidget.getParentOverlayWidget();
if (parentOverlayWidget != null) {
// find the target to make active after the deletion
OverlayWidget target = overlayWidget.next(overlayWidgetSelector);
if (target == null) target = overlayWidget.previous(overlayWidgetSelector);
parentOverlayWidget.removeOverlayWidget(overlayWidget);
overlayWidget.getOverlayElement().removeFromParent();
if (target != null) {
documentEventBus.fireEvent(new OverlayWidgetSelectEvent(target, DraftingDocumentController.this));
}
// redraw the outline
redrawOutline(parentOverlayWidget.getRoot());
}
}
public void handleOverlayWidgetModify(final OverlayWidget overlayWidget) {
if (!inlineEditorController.isShowing()) {
// first scroll to the widget
clientFactory.getScheduler().scheduleDeferred(new Scheduler.ScheduledCommand() {
@Override
public void execute() {
clientFactory.getEventBus().fireEvent(new DocumentScrollToEvent(overlayWidget.asWidget(), DraftingDocumentController.this));
// then attach the inline editor
clientFactory.getScheduler().scheduleDeferred(new Scheduler.ScheduledCommand() {
@Override
public void execute() {
clientFactory.getEventBus().fireEvent(new AttachInlineEditorEvent(overlayWidget, DraftingDocumentController.this));
}
});
}
});
}
}
public void cancelModify() {
clientFactory.getEventBus().fireEvent(new DetachInlineEditorEvent(DraftingDocumentController.this));
inlineEditorController.getRichTextEditor().setFocus(false);
restoreFocusOnViewPort();
}
public void modifyOverlayWidget(final OverlayWidget overlayWidget, final String innerHTML) {
final Element overlayElement = inlineEditorController.getOverlayWidget().getOverlayElement();
// TODO overlay again, and correct the tree
for (OverlayWidget child : inlineEditorController.getOverlayWidget().getChildOverlayWidgets()) {
child.onDetach();
}
inlineEditorController.getOverlayWidget().getChildOverlayWidgets().clear();
overlayElement.setInnerHTML(innerHTML);
for (int i = 0; i < overlayElement.getChildCount(); i++) {
final Node child = overlayElement.getChild(i);
if (Node.ELEMENT_NODE == child.getNodeType()) {
final OverlayWidget amendableWidget = overlayFactory.getAmendableWidget((Element) child);
if (amendableWidget != null) {
overlayWidget.addOverlayWidget(amendableWidget);
} else {
LOG.warning("Could not get overlay for " + child);
}
}
}
overlayWidget.walk(new OverlayWidgetWalker.DefaultOverlayWidgetVisitor() {
@Override
public boolean visit(OverlayWidget visited) {
// if the widget is amendable, register a listener for its events
if (visited != null && visited.isAmendable() != null && visited.isAmendable()) {
visited.setUIListener(sourceFileController);
} else {
LOG.info(visited + " is NOT amendable.");
}
return true;
}
});
// remove the nsesa-inline class name if it's there
// so the next time we don't automatically attach the inline editor
final String className = overlayElement.getClassName();
if (className.contains("nsesa-inline")) {
overlayElement.setClassName(className.replace("nsesa-inline", ""));
}
// highlight
sourceFileController.highlight(overlayWidget.asWidget(), "black", 1);
redrawOutline(overlayWidget.getRoot());
}
public void redrawOutline(OverlayWidget root) {
outlineController.setRootOverlayWidget(root);
}
@Override
public void onDocumentContentLoaded(String content) {
showLoadingIndicator(true, "Parsing document.");
sourceFileController.setContent(content);
showLoadingIndicator(true, "Building document tree.");
clientFactory.getScheduler().scheduleDeferred(new Scheduler.ScheduledCommand() {
@Override
public void execute() {
sourceFileController.overlay();
showLoadingIndicator(true, "Done overlaying document.");
clientFactory.getScheduler().scheduleDeferred(new Scheduler.ScheduledCommand() {
@Override
public void execute() {
clientFactory.getEventBus().fireEvent(new ResizeEvent(Window.getClientHeight(), Window.getClientWidth()));
showLoadingIndicator(false, "Done retrieving document.");
clientFactory.getScheduler().scheduleDeferred(new Scheduler.ScheduledCommand() {
@Override
public void execute() {
final List<OverlayWidget> overlayWidgets = sourceFileController.getOverlayWidgets();
if (overlayWidgets != null && !overlayWidgets.isEmpty()) {
// only display the first one
redrawOutline(overlayWidgets.get(0));
}
}
});
// find the first element that has the nsesa-inline class name, and select it
clientFactory.getScheduler().scheduleDeferred(new Scheduler.ScheduledCommand() {
@Override
public void execute() {
final List<OverlayWidget> overlayWidgets = sourceFileController.getOverlayWidgets();
if (overlayWidgets != null && !overlayWidgets.isEmpty()) {
// only display the first one
overlayWidgets.get(0).walk(new OverlayWidgetWalker.DefaultOverlayWidgetVisitor() {
@Override
public boolean visit(OverlayWidget visited) {
if (visited.getOverlayElement().getClassName().contains("nsesa-select")) {
documentEventBus.fireEvent(new OverlayWidgetSelectEvent(visited, DraftingDocumentController.this));
return false;
}
return true;
}
});
}
}
});
}
});
}
});
}
@Override
public void setDocument(DocumentDTO document) {
this.document = document;
this.documentID = document.getDocumentID();
// update the document title
this.view.setDocumentTitle(document.getName());
// set the deadline
this.deadlineController.setDeadline(document.getDeadline());
}
@Override
public void removeListeners() {
switchTabEventHandlerRegistration.removeHandler();
notificationEventHandlerRegistration.removeHandler();
confirmationEventHandlerRegistration.removeHandler();
criticalEventHandlerRegistration.removeHandler();
overlayWidgetSelectEventHandlerRegistration.removeHandler();
resizeEventHandlerRegistration.removeHandler();
documentScrollToEventHandlerRegistration.removeHandler();
documentToggleStructureEventHandler.removeHandler();
keyComboHandlerRegistration.removeHandler();
draftingToggleEventHandlerRegistration.removeHandler();
draftingAttributesToggleEventHandlerRegistration.removeHandler();
overlayWidgetDeleteHandlerRegistration.removeHandler();
overlayWidgetModifyHandlerRegistration.removeHandler();
overlayWidgetNewEventHandlerRegistration.removeHandler();
inlineEditorControllerSaveHandlerRegistration.removeHandler();
inlineEditorControllerCancelHandlerRegistration.removeHandler();
}
public void setInjector(DocumentInjector injector) {
this.documentEventBus = injector.getDocumentEventBus();
this.view = injector.getDocumentView();
this.deadlineController = injector.getDeadlineController();
this.deadlineController.setDocumentController(this);
this.sourceFileController = injector.getSourceFileController();
this.sourceFileController.setDocumentController(this);
// TODO this is ugly ...
if (injector instanceof DraftingDocumentInjector) {
final DraftingDocumentInjector draftingDocumentInjector = (DraftingDocumentInjector) injector;
this.outlineController = draftingDocumentInjector.getOutlineController();
this.outlineController.setDocumentController(this);
this.actionBarController = draftingDocumentInjector.getActionBarController();
this.actionBarController.setSourceFileController(sourceFileController);
this.actionBarCreatePanelController = draftingDocumentInjector.getActionBarCreatePanelController();
this.actionBarCreatePanelController.setSourceFileController(sourceFileController);
this.actionBarCreatePanelFocusPanel.setWidget(actionBarCreatePanelController.getView());
this.actionBarCreatePanelControllerPopup.setWidget(actionBarCreatePanelFocusPanel);
}
}
@Override
public DocumentInjector getInjector() {
return GWT.create(DraftingDocumentInjector.class);
}
/**
* Force focus on the page since when we are using keyboards in the editor we are loosing the focus
* on the document
*/
private void restoreFocusOnViewPort() {
TextBox dummyBox = new TextBox();
RootLayoutPanel.get().add(dummyBox);
dummyBox.setFocus(true);
dummyBox.removeFromParent();
}
}