package org.ovirt.engine.ui.uicommonweb.models; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; import org.ovirt.engine.core.common.mode.ApplicationMode; import org.ovirt.engine.core.common.queries.ConfigurationValues; import org.ovirt.engine.core.compat.Version; import org.ovirt.engine.ui.frontend.AsyncCallback; import org.ovirt.engine.ui.uicommonweb.Configurator; import org.ovirt.engine.ui.uicommonweb.ICommandTarget; import org.ovirt.engine.ui.uicommonweb.ILogger; import org.ovirt.engine.ui.uicommonweb.TypeResolver; import org.ovirt.engine.ui.uicommonweb.UICommand; import org.ovirt.engine.ui.uicommonweb.dataprovider.AsyncDataProvider; import org.ovirt.engine.ui.uicommonweb.help.HelpTag; import org.ovirt.engine.ui.uicommonweb.models.common.ProgressModel; import org.ovirt.engine.ui.uicompat.ConstantsManager; import org.ovirt.engine.ui.uicompat.Event; import org.ovirt.engine.ui.uicompat.EventArgs; import org.ovirt.engine.ui.uicompat.IEventListener; import org.ovirt.engine.ui.uicompat.IProvidePropertyChangedEvent; import org.ovirt.engine.ui.uicompat.ObservableCollection; import org.ovirt.engine.ui.uicompat.PropertyChangedEventArgs; import org.ovirt.engine.ui.uicompat.ProvidePropertyChangedEvent; import com.google.gwt.event.shared.EventBus; import com.google.gwt.event.shared.GwtEvent; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.event.shared.HasHandlers; import com.google.inject.Inject; public class Model implements IEventListener<EventArgs>, ICommandTarget, IProvidePropertyChangedEvent, HasHandlers, IModel { /** * The GWT event bus. */ private EventBus eventBus; /** * Set of invalid tabs, empty if the model doesn't support tabs. */ private final Set<TabName> invalidTabs = new HashSet<>(); private final List<HandlerRegistration> handlerRegistrations = new ArrayList<>(); public static final String CANCEL_COMMAND = "Cancel"; //$NON-NLS-1$ private Event<PropertyChangedEventArgs> propertyChangedEvent; @Override public Event<PropertyChangedEventArgs> getPropertyChangedEvent() { return propertyChangedEvent; } private void setPropertyChangedEvent(Event<PropertyChangedEventArgs> value) { propertyChangedEvent = value; } @Override public void cleanup() { if (hasEventBusSet()) { unsetEventBus(); } cleanupEvents(getPropertyChangedEvent()); for (UICommand command : getCommands()) { command.cleanup(); } invalidTabs.clear(); } protected void cleanupEvents(Event<?>... events) { for (Event<?> event : events) { if (event != null) { event.clearListeners(); } } } private Model window; @Override public Model getWindow() { return window; } @Override public void setWindow(Model value) { if (window != value) { window = value; onPropertyChanged(new PropertyChangedEventArgs("Window")); //$NON-NLS-1$ } } private Model confirmWindow; @Override public Model getConfirmWindow() { return confirmWindow; } @Override public void setConfirmWindow(Model value) { if (confirmWindow != value) { confirmWindow = value; onPropertyChanged(new PropertyChangedEventArgs("ConfirmWindow")); //$NON-NLS-1$ } } private Model widgetModel; @Override public Model getWidgetModel() { return widgetModel; } public void setWidgetModel(Model value) { if (widgetModel != value) { widgetModel = value; onPropertyChanged(new PropertyChangedEventArgs("WidgetModel")); //$NON-NLS-1$ } } private Configurator configurator; public Configurator getConfigurator() { return configurator; } private void setConfigurator(Configurator value) { configurator = value; } private ILogger logger; protected ILogger getLogger() { return logger; } private void setLogger(ILogger value) { logger = value; } private UICommand lastExecutedCommand; @Override public UICommand getLastExecutedCommand() { return lastExecutedCommand; } private void setLastExecutedCommand(UICommand value) { lastExecutedCommand = value; } private ProgressModel progress; /** * Represents a progress operation on the model. */ @Override public ProgressModel getProgress() { return progress; } private void setProgress(ProgressModel value) { if (progress != value) { progress = value; onPropertyChanged(new PropertyChangedEventArgs(PropertyChangedEventArgs.PROGRESS)); } } private EntityModel<Boolean> advancedMode; public EntityModel<Boolean> getAdvancedMode() { return advancedMode; } public void setAdvancedMode(EntityModel<Boolean> advancedMode) { this.advancedMode = advancedMode; } private String hashName; @Override public String getHashName() { return hashName; } public void setHashName(String value) { hashName = value; onPropertyChanged(new PropertyChangedEventArgs("HashName")); //$NON-NLS-1$ } private HelpTag helpTag; /** * Set the help tag for this model. This is used to connect context-sensitive help to a model/dialog. * <b>IMPORTANT</b>: only use values from {@code HelpTag}. * @param helpTag unique id from {@code HelpTag} */ public void setHelpTag(HelpTag helpTag) { this.helpTag = helpTag; setOpenDocumentationCommand(new UICommand("OpenDocumentation", this)); //$NON-NLS-1$ onPropertyChanged(new PropertyChangedEventArgs("HelpTag")); //$NON-NLS-1$ } public HelpTag getHelpTag() { return helpTag; } private String applicationPlace; /** * Returns the logical application place associated with this model or {@code null} if this model * has no such place associated. */ public String getApplicationPlace() { return applicationPlace; } protected void setApplicationPlace(String applicationPlace) { this.applicationPlace = applicationPlace; } /** * Gets or sets the title of this model. There is no specific purpose for this property, use it on your convenience. */ private String title; public String getTitle() { return title; } public Model setTitle(String value) { if (!Objects.equals(title, value)) { title = value; onPropertyChanged(new PropertyChangedEventArgs("Title")); //$NON-NLS-1$ } return this; } private boolean isValid; public boolean getIsValid() { return isValid; } public void setIsValid(boolean value) { if (isValid != value) { isValid = value; onPropertyChanged(new PropertyChangedEventArgs("IsValid")); //$NON-NLS-1$ if (isValid) { getInvalidityReasons().clear(); } } } private List<String> invalidityReasons; public List<String> getInvalidityReasons() { return invalidityReasons; } public void setInvalidityReasons(List<String> value) { invalidityReasons = value; } private int availableInModes; public int getAvailableInModes() { return availableInModes; } public void setAvailableInModes(int value) { if (availableInModes != value) { availableInModes = value; onPropertyChanged(new PropertyChangedEventArgs("AvailableInModes")); //$NON-NLS-1$ } } public void setAvailableInModes(ApplicationMode uiMode) { int value = uiMode.getValue(); setAvailableInModes(value); } private boolean isAvailable; @Override public boolean getIsAvailable() { return isAvailable && ApplicationModeHelper.isAvailableInMode(getAvailableInModes()); } public void setIsAvailable(boolean value) { if (isAvailable != value) { isAvailable = value; onIsAvailableChanged(); onPropertyChanged(new PropertyChangedEventArgs("IsAvailable")); //$NON-NLS-1$ } } private boolean isChangable; public boolean getIsChangable() { return isChangable; } public Model setIsChangeable(boolean value) { return setIsChangeable(value, null); } /** * If {@code value} parameter is true, {@code reason} parameter is ignored and prohibition reason is set to * {@code null}. */ public Model setIsChangeable(boolean value, String reason) { if (isChangable != value) { isChangable = value; onPropertyChanged(new PropertyChangedEventArgs("IsChangable")); //$NON-NLS-1$ } setChangeProhibitionReason(value ? null : reason); return this; } private String changeProhibitionReason; public String getChangeProhibitionReason() { return changeProhibitionReason; } public void setChangeProhibitionReason(String value) { if (!Objects.equals(changeProhibitionReason, value)) { changeProhibitionReason = value; onPropertyChanged(new PropertyChangedEventArgs("ChangeProhibitionReason")); //$NON-NLS-1$ } } private boolean isSelected; public boolean getIsSelected() { return isSelected; } public void setIsSelected(boolean value) { if (isSelected != value) { isSelected = value; onPropertyChanged(new PropertyChangedEventArgs("IsSelected")); //$NON-NLS-1$ } } private boolean isSelectable; public boolean getIsSelectable() { return isSelectable; } public void setIsSelectable(boolean value) { if (isSelectable != value) { isSelectable = value; onPropertyChanged(new PropertyChangedEventArgs("IsSelectable")); //$NON-NLS-1$ } } private List<UICommand> commands; public List<UICommand> getCommands() { return commands; } public void setCommands(List<UICommand> value) { commands = value; } public UICommand getDefaultCommand() { List<UICommand> commands = getCommands(); if (commands != null) { for (UICommand c : commands) { if (c.getIsDefault()) { return c; } } } return null; } public UICommand getCancelCommand() { List<UICommand> commands = getCommands(); if (commands != null) { for (UICommand c : commands) { if (c.getIsCancel()) { return c; } } } return null; } private UICommand openDocumentationCommand; public UICommand getOpenDocumentationCommand() { return openDocumentationCommand; } public void setOpenDocumentationCommand(UICommand value) { openDocumentationCommand = value; } private String message; public String getMessage() { return message; } public void setMessage(String value) { if (!Objects.equals(message, value)) { message = value; onPropertyChanged(new PropertyChangedEventArgs("Message")); //$NON-NLS-1$ } } public Model() { setPropertyChangedEvent(new Event<PropertyChangedEventArgs>(ProvidePropertyChangedEvent.definition)); // Resolve commonly used types. setConfigurator(lookupConfigurator()); setLogger(lookupLogger()); setInvalidityReasons(new ObservableCollection<String>()); setIsValid(true); setIsChangeable(true); setAvailableInModes(ApplicationMode.AllModes); setIsAvailable(true); setIsSelectable(true); setCommands(new ObservableCollection<UICommand>()); } protected ILogger lookupLogger() { return (ILogger) TypeResolver.getInstance().resolve(ILogger.class); } protected Configurator lookupConfigurator() { return (Configurator) TypeResolver.getInstance().resolve(Configurator.class); } /** * Override this method to initialize model, for example populate some properties with data here rather than in * constructor. But instantiation still should be done in constructor. */ public void initialize() { } protected void onIsAvailableChanged() { } protected void onPropertyChanged(PropertyChangedEventArgs e) { getPropertyChangedEvent().raise(this, e); } @Override public void eventRaised(Event<? extends EventArgs> ev, Object sender, EventArgs args) { } @Override public void executeCommand(UICommand command) { setLastExecutedCommand(command); if (command == getOpenDocumentationCommand()) { onPropertyChanged(new PropertyChangedEventArgs("OpenDocumentation")); //$NON-NLS-1$ } } @Override public void executeCommand(UICommand uiCommand, Object... parameters) { executeCommand(uiCommand); } public void startProgress() { startProgress(null); } /** * Assigns a new instance to the Progress property, indicating start of some operation on the model. */ public void startProgress(String operation) { ProgressModel tempVar = new ProgressModel(); tempVar.setCurrentOperation(operation); setProgress(tempVar); } /** * Assigns null to the Progress property, indicating end of some operation on the model. */ public void stopProgress() { setProgress(null); } /** * Get the GWT event bus. * @return The {@code EventBus}, can be null. */ protected final EventBus getEventBus() { return eventBus; } /** * Set the GWT event bus. * @param eventBus The {@code EventBus}, can be null. */ @Inject public final void setEventBus(EventBus eventBus) { this.eventBus = eventBus; registerHandlers(); } /** * Unset the GWT event bus, use this when cleaning up models. */ public final void unsetEventBus() { unregisterHandlers(); this.eventBus = null; } /** * Allows one to check if the event bus has been set. * @return {@code true} if the event bus is set already, {@code false} otherwise. */ public final boolean hasEventBusSet() { return this.eventBus != null; } /** * Register handlers after the {@code EventBus} has been set. * <p> * Make sure to use {@link #registerHandler} to ensure proper * handler cleanup when {@link #unsetEventBus} is called. */ protected void registerHandlers() { // No-op, override as necessary } /** * Register a handler. * @param reg The {@code HandlerRegistration} returned from registering a handler. */ public final void registerHandler(HandlerRegistration reg) { if (reg != null && !handlerRegistrations.contains(reg)) { handlerRegistrations.add(reg); } } /** * Unregister all registered handlers. */ public final void unregisterHandlers() { for (HandlerRegistration reg: handlerRegistrations) { reg.removeHandler(); // can't call unregisterHandler(reg) as that would modify the list during iteration } handlerRegistrations.clear(); } /** * Unregister a specific handler using its {@code HandlerRegistration}. * @param reg The {@code HandlerRegistration} to use to remove the handler. */ public final void unregisterHandler(HandlerRegistration reg) { if (reg != null) { reg.removeHandler(); handlerRegistrations.remove(reg); } } @Override public void fireEvent(GwtEvent<?> event) { getEventBus().fireEventFromSource(event, this); } public Set<TabName> getInvalidTabs() { return invalidTabs; } public void setValidTab(TabName tab, boolean value) { if (value) { invalidTabs.remove(tab); } else { invalidTabs.add(tab); } } public boolean isValidTab(TabName tab) { return !invalidTabs.contains(tab); } public boolean allTabsValid() { return invalidTabs.isEmpty(); } /** * Update Model's changeability based on the support of given feature in given version. * * @param feature {@link org.ovirt.engine.core.common.queries.ConfigurationValues} [SomeFeature]Supported value * @param version compatibility version to check the feature against */ public void updateChangeability(ConfigurationValues feature, Version version) { boolean featureSupported = (Boolean) AsyncDataProvider.getInstance().getConfigValuePreConverted(feature, version.getValue()); setIsChangeable(featureSupported); setChangeProhibitionReason(ConstantsManager.getInstance().getMessages().optionNotSupportedClusterVersionTooOld(version.getValue())); } public class AsyncQuery<T> extends org.ovirt.engine.ui.frontend.AsyncQuery<T> { public AsyncQuery(){ } public AsyncQuery(AsyncCallback<T> callback) { super(Model.this, callback); } public AsyncQuery(AsyncCallback<T> callback, boolean handleFailure) { super(Model.this, callback, handleFailure); } } public <T> AsyncQuery<T> asyncQuery(AsyncCallback<T> callback) { return new AsyncQuery<>(callback); } }