/*
* Copyright 2015 JBoss, by Red Hat, Inc
*
* 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.uberfire.ext.editor.commons.client.menu;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.enterprise.event.Event;
import javax.enterprise.event.Observes;
import javax.inject.Inject;
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.uberfire.backend.vfs.Path;
import org.uberfire.client.mvp.UpdatedLockStatusEvent;
import org.uberfire.commons.data.Pair;
import org.uberfire.commons.validation.PortablePreconditions;
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.DeletePopUpPresenter;
import org.uberfire.ext.editor.commons.client.file.popups.RenamePopUpPresenter;
import org.uberfire.ext.editor.commons.client.menu.HasLockSyncMenuStateHelper.LockSyncMenuStateHelper.Operation;
import org.uberfire.ext.editor.commons.client.resources.i18n.CommonConstants;
import org.uberfire.ext.editor.commons.client.validation.Validator;
import org.uberfire.ext.editor.commons.service.support.SupportsCopy;
import org.uberfire.ext.editor.commons.service.support.SupportsDelete;
import org.uberfire.ext.editor.commons.service.support.SupportsRename;
import org.uberfire.ext.widgets.common.client.callbacks.HasBusyIndicatorDefaultErrorCallback;
import org.uberfire.ext.widgets.common.client.common.BusyIndicatorView;
import org.uberfire.mvp.Command;
import org.uberfire.workbench.events.NotificationEvent;
import org.uberfire.workbench.model.menu.MenuFactory;
import org.uberfire.workbench.model.menu.MenuItem;
import org.uberfire.workbench.model.menu.MenuVisitor;
import org.uberfire.workbench.model.menu.Menus;
import static org.uberfire.workbench.model.menu.MenuFactory.newSimpleItem;
public class BasicFileMenuBuilderImpl implements BasicFileMenuBuilder {
private RestoreVersionCommandProvider restoreVersionCommandProvider;
private Event<NotificationEvent> notification;
private BusyIndicatorView busyIndicatorView;
private DeletePopUpPresenter deletePopUpPresenter;
private CopyPopUpPresenter copyPopUpPresenter;
private RenamePopUpPresenter renamePopUpPresenter;
private Command saveCommand = null;
private MenuItem saveMenuItem;
private Command deleteCommand = null;
private MenuItem deleteMenuItem;
private Command renameCommand = null;
private MenuItem renameMenuItem;
private Command copyCommand = null;
private Command validateCommand = null;
private Command restoreCommand = null;
private MenuItem restoreMenuItem;
private List<Pair<String, Command>> otherCommands = new ArrayList<Pair<String, Command>>();
private List<MenuItem> topLevelMenus = new ArrayList<MenuItem>();
private List<MenuItem> menuItemsSyncedWithLockState = new ArrayList<MenuItem>();
private LockSyncMenuStateHelper lockSyncMenuStateHelper = new BasicFileMenuBuilder.BasicLockSyncMenuStateHelper();
@Inject
public BasicFileMenuBuilderImpl(final DeletePopUpPresenter deletePopUpPresenter,
final CopyPopUpPresenter copyPopUpPresenter,
final RenamePopUpPresenter renamePopUpPresenter,
final BusyIndicatorView busyIndicatorView,
final Event<NotificationEvent> notification,
final RestoreVersionCommandProvider restoreVersionCommandProvider) {
this.deletePopUpPresenter = deletePopUpPresenter;
this.copyPopUpPresenter = copyPopUpPresenter;
this.renamePopUpPresenter = renamePopUpPresenter;
this.busyIndicatorView = busyIndicatorView;
this.notification = notification;
this.restoreVersionCommandProvider = restoreVersionCommandProvider;
}
@Override
public BasicFileMenuBuilder addSave(final MenuItem menuItem) {
saveMenuItem = menuItem;
return this;
}
@Override
public BasicFileMenuBuilder addSave(final Command command) {
this.saveCommand = command;
return this;
}
@Override
public BasicFileMenuBuilder addDelete(final Path path,
final Caller<? extends SupportsDelete> deleteCaller) {
return addDelete(() -> {
deletePopUpPresenter.show((String comment) -> {
busyIndicatorView.showBusyIndicator(CommonConstants.INSTANCE.Deleting());
deleteCaller.call(getDeleteSuccessCallback(),
new HasBusyIndicatorDefaultErrorCallback(busyIndicatorView)).delete(path,
comment);
});
});
}
@Override
public BasicFileMenuBuilder addDelete(final PathProvider provider,
final Caller<? extends SupportsDelete> deleteCaller) {
return addDelete(() -> {
final Path path = provider.getPath();
deletePopUpPresenter.show((String comment) -> {
busyIndicatorView.showBusyIndicator(CommonConstants.INSTANCE.Deleting());
deleteCaller.call(getDeleteSuccessCallback(),
new HasBusyIndicatorDefaultErrorCallback(busyIndicatorView)).delete(path,
comment);
});
});
}
private RemoteCallback<Void> getDeleteSuccessCallback() {
return (Void v) -> {
busyIndicatorView.hideBusyIndicator();
notification.fire(new NotificationEvent(CommonConstants.INSTANCE.ItemDeletedSuccessfully()));
};
}
@Override
public BasicFileMenuBuilder addDelete(final Command command) {
this.deleteCommand = command;
return this;
}
@Override
public BasicFileMenuBuilder addRename(final Command command) {
this.renameCommand = command;
return this;
}
@Override
public BasicFileMenuBuilder addRename(final Path path,
final Caller<? extends SupportsRename> renameCaller) {
return addRename(() -> {
CommandWithFileNameAndCommitMessage command = getRenamePopupCommand(renameCaller,
path,
renamePopUpPresenter.getView());
renamePopUpPresenter.show(path,
command);
});
}
@Override
public BasicFileMenuBuilder addRename(final Path path,
final Validator validator,
final Caller<? extends SupportsRename> renameCaller) {
return addRename(() -> {
CommandWithFileNameAndCommitMessage command = getRenamePopupCommand(renameCaller,
path,
renamePopUpPresenter.getView());
renamePopUpPresenter.show(path,
validator,
command);
});
}
@Override
public BasicFileMenuBuilder addRename(final PathProvider provider,
final Validator validator,
final Caller<? extends SupportsRename> renameCaller) {
return addRename(() -> {
final Path path = provider.getPath();
final CommandWithFileNameAndCommitMessage command = getRenamePopupCommand(renameCaller,
path,
renamePopUpPresenter.getView());
renamePopUpPresenter.show(path,
validator,
command);
});
}
private CommandWithFileNameAndCommitMessage getRenamePopupCommand(final Caller<? extends SupportsRename> renameCaller,
final Path path,
final RenamePopUpPresenter.View renamePopupView) {
return (FileNameAndCommitMessage details) -> {
busyIndicatorView.showBusyIndicator(CommonConstants.INSTANCE.Renaming());
renameCaller.call(getRenameSuccessCallback(renamePopupView),
getRenameErrorCallback(renamePopupView,
busyIndicatorView)).rename(path,
details.getNewFileName(),
details.getCommitMessage());
};
}
private RemoteCallback<Path> getRenameSuccessCallback(final RenamePopUpPresenter.View renamePopupView) {
return (Path path) -> {
renamePopupView.hide();
busyIndicatorView.hideBusyIndicator();
notification.fire(new NotificationEvent(CommonConstants.INSTANCE.ItemRenamedSuccessfully()));
};
}
private HasBusyIndicatorDefaultErrorCallback getRenameErrorCallback(final RenamePopUpPresenter.View renamePopupView,
BusyIndicatorView busyIndicatorView) {
return new HasBusyIndicatorDefaultErrorCallback(busyIndicatorView) {
@Override
public boolean error(final Message message,
final Throwable throwable) {
if (fileAlreadyExists(throwable)) {
hideBusyIndicator();
renamePopupView.handleDuplicatedFileName();
return false;
}
renamePopupView.hide();
return super.error(message,
throwable);
}
};
}
@Override
public BasicFileMenuBuilder addCopy(final Command command) {
this.copyCommand = command;
return this;
}
@Override
public BasicFileMenuBuilder addCopy(final Path path,
final Caller<? extends SupportsCopy> copyCaller) {
return addCopy(() -> copyPopUpPresenter.show(path,
getCopyPopupCommand(copyCaller,
path,
copyPopUpPresenter.getView())));
}
@Override
public BasicFileMenuBuilder addCopy(final Path path,
final Validator validator,
final Caller<? extends SupportsCopy> copyCaller) {
return addCopy(() -> copyPopUpPresenter.show(path,
validator,
getCopyPopupCommand(copyCaller,
path,
copyPopUpPresenter.getView())));
}
public BasicFileMenuBuilder addCopy(final PathProvider provider,
final Validator validator,
final Caller<? extends SupportsCopy> copyCaller) {
return addCopy(() -> {
final Path path = provider.getPath();
copyPopUpPresenter.show(path,
validator,
getCopyPopupCommand(copyCaller,
path,
copyPopUpPresenter.getView()));
});
}
private CommandWithFileNameAndCommitMessage getCopyPopupCommand(final Caller<? extends SupportsCopy> copyCaller,
final Path path,
final CopyPopUpPresenter.View copyPopupView) {
return (FileNameAndCommitMessage details) -> {
busyIndicatorView.showBusyIndicator(CommonConstants.INSTANCE.Copying());
copyCaller.call(getCopySuccessCallback(copyPopupView),
getCopyErrorCallback(copyPopupView,
busyIndicatorView)).copy(path,
details.getNewFileName(),
copyPopupView.getTargetPath(),
details.getCommitMessage());
};
}
private RemoteCallback<Path> getCopySuccessCallback(final CopyPopUpPresenter.View copyPopupView) {
return (final Path path) -> {
copyPopupView.hide();
busyIndicatorView.hideBusyIndicator();
notification.fire(new NotificationEvent(CommonConstants.INSTANCE.ItemCopiedSuccessfully()));
};
}
public HasBusyIndicatorDefaultErrorCallback getCopyErrorCallback(final CopyPopUpPresenter.View copyPopupView,
BusyIndicatorView busyIndicatorView) {
return new HasBusyIndicatorDefaultErrorCallback(busyIndicatorView) {
@Override
public boolean error(final Message message,
final Throwable throwable) {
if (fileAlreadyExists(throwable)) {
hideBusyIndicator();
copyPopupView.handleDuplicatedFileName();
return false;
}
copyPopupView.hide();
return super.error(message,
throwable);
}
};
}
private boolean fileAlreadyExists(final Throwable throwable) {
return throwable != null && throwable.getMessage() != null && throwable.getMessage().contains("FileAlreadyExistsException");
}
@Override
public BasicFileMenuBuilder addValidate(final Command validateCommand) {
this.validateCommand = validateCommand;
return this;
}
@Override
public BasicFileMenuBuilder addRestoreVersion(final Path path) {
this.restoreCommand = restoreVersionCommandProvider.getCommand(path);
return this;
}
@Override
public BasicFileMenuBuilder addCommand(final String caption,
final Command command) {
this.otherCommands.add(new Pair<String, Command>(caption,
command));
return this;
}
@Override
public Menus build() {
final Map<Object, MenuItem> menuItems = new LinkedHashMap<Object, MenuItem>();
if (saveCommand != null) {
menuItems.put(MenuItems.SAVE,
MenuFactory.newTopLevelMenu(CommonConstants.INSTANCE.Save())
.respondsWith(saveCommand)
.endMenu()
.build().getItems().get(0));
} else if (saveMenuItem != null) {
menuItems.put(MenuItems.SAVE,
saveMenuItem);
menuItemsSyncedWithLockState.add(saveMenuItem);
}
if (deleteCommand != null) {
if (deleteMenuItem == null) {
deleteMenuItem = MenuFactory.newTopLevelMenu(CommonConstants.INSTANCE.Delete())
.respondsWith(deleteCommand)
.endMenu()
.build().getItems().get(0);
}
menuItems.put(MenuItems.DELETE,
deleteMenuItem);
menuItemsSyncedWithLockState.add(deleteMenuItem);
}
if (renameCommand != null) {
if (renameMenuItem == null) {
renameMenuItem = MenuFactory.newTopLevelMenu(CommonConstants.INSTANCE.Rename())
.respondsWith(renameCommand)
.endMenu()
.build().getItems().get(0);
}
menuItems.put(MenuItems.RENAME,
renameMenuItem);
menuItemsSyncedWithLockState.add(renameMenuItem);
}
if (copyCommand != null) {
menuItems.put(MenuItems.COPY,
MenuFactory.newTopLevelMenu(CommonConstants.INSTANCE.Copy())
.respondsWith(copyCommand)
.endMenu()
.build().getItems().get(0));
}
if (validateCommand != null) {
menuItems.put(MenuItems.VALIDATE,
MenuFactory.newTopLevelMenu(CommonConstants.INSTANCE.Validate())
.respondsWith(validateCommand)
.endMenu()
.build().getItems().get(0));
}
if (restoreCommand != null) {
if (restoreMenuItem == null) {
restoreMenuItem = MenuFactory.newTopLevelMenu(CommonConstants.INSTANCE.Restore())
.respondsWith(restoreCommand)
.endMenu()
.build().getItems().get(0);
}
menuItemsSyncedWithLockState.add(restoreMenuItem);
}
if (!(otherCommands == null || otherCommands.isEmpty())) {
final List<MenuItem> otherMenuItems = new ArrayList<MenuItem>();
for (Pair<String, Command> other : otherCommands) {
otherMenuItems.add(newSimpleItem(other.getK1())
.respondsWith(other.getK2())
.endMenu().build().getItems().get(0));
}
final MenuItem item = MenuFactory.newTopLevelMenu(CommonConstants.INSTANCE.Other())
.withItems(otherMenuItems)
.endMenu()
.build().getItems().get(0);
menuItems.put(item,
item);
}
for (MenuItem menuItem : topLevelMenus) {
menuItems.put(menuItem,
menuItem);
}
return new Menus() {
@Override
public List<MenuItem> getItems() {
return new ArrayList<MenuItem>() {{
for (final MenuItem menuItem : menuItems.values()) {
add(menuItem);
}
}};
}
@Override
public Map<Object, MenuItem> getItemsMap() {
return menuItems;
}
@Override
public void accept(MenuVisitor visitor) {
if (visitor.visitEnter(this)) {
for (final MenuItem item : menuItems.values()) {
item.accept(visitor);
}
visitor.visitLeave(this);
}
}
@Override
public int getOrder() {
return 0;
}
};
}
@Override
public BasicFileMenuBuilder addNewTopLevelMenu(MenuItem menu) {
topLevelMenus.add(menu);
return this;
}
@Override
public void setLockSyncMenuStateHelper(final LockSyncMenuStateHelper lockSyncMenuStateHelper) {
this.lockSyncMenuStateHelper = PortablePreconditions.checkNotNull("lockSyncMenuStateHelper",
lockSyncMenuStateHelper);
}
void onEditorLockInfo(@Observes UpdatedLockStatusEvent lockInfo) {
final Operation op = lockSyncMenuStateHelper.enable(lockInfo.getFile(),
lockInfo.isLocked(),
lockInfo.isLockedByCurrentUser());
switch (op) {
case ENABLE:
case DISABLE:
for (MenuItem menuItem : menuItemsSyncedWithLockState) {
menuItem.setEnabled(op == Operation.ENABLE);
}
break;
case VETO:
//Do nothing
}
}
}