Tomas Jelinek has uploaded a new change for review.

Change subject: frontend: created instance image widget
......................................................................

frontend: created instance image widget

Change-Id: I4bcaa1e40841aa12e64708ec82afdb9daec9fb7f
Bug-Url: https://bugzilla.redhat.com/1117489
Signed-off-by: Tomas Jelinek <tjeli...@redhat.com>
---
M 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/CommonApplicationConstants.java
M 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/AddRemoveRowWidget.java
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/uicommon/instanceimages/InstanceImageLineEditor.java
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/uicommon/instanceimages/InstanceImageLineEditor.ui.xml
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/uicommon/instanceimages/InstanceImagesEditor.java
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/uicommon/instanceimages/InstanceImagesEditor.ui.xml
M 
frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/configure/instancetypes/InstanceTypeListModel.java
A 
frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/vms/InstanceImageLineModel.java
A 
frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/vms/InstanceImagesModel.java
M 
frontend/webadmin/modules/uicompat/src/main/java/org/ovirt/engine/ui/uicompat/UIConstants.java
M 
frontend/webadmin/modules/uicompat/src/main/java/org/ovirt/engine/ui/uicompat/UIMessages.java
11 files changed, 955 insertions(+), 16 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/63/36063/1

diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/CommonApplicationConstants.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/CommonApplicationConstants.java
index 68da609..846a607 100644
--- 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/CommonApplicationConstants.java
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/CommonApplicationConstants.java
@@ -562,6 +562,18 @@
     @DefaultStringValue("Instance Type")
     String instanceType();
 
+    @DefaultStringValue("Instance Images")
+    String instanceImages();
+
+    @DefaultStringValue("Edit")
+    String editInstanceImages();
+
+    @DefaultStringValue("Create")
+    String addInstanceImages();
+
+    @DefaultStringValue("Attach")
+    String attachInstanceImages();
+
     @DefaultStringValue("Memory Size")
     String memSizeVmPopup();
 
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/AddRemoveRowWidget.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/AddRemoveRowWidget.java
index aa675b5..418b9b7 100644
--- 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/AddRemoveRowWidget.java
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/AddRemoveRowWidget.java
@@ -231,29 +231,45 @@
 
                     @Override
                     public void onClick(ClickEvent event) {
-                        ListIterator<Pair<T, V>> last = 
items.listIterator(items.size());
-                        if (!last.hasPrevious()) { // just a precaution; if 
there's no item, there should be no button
+                        if (vetoRemoveWidget(item, value, widget)) {
                             return;
                         }
 
-                        if (item == last.previous() && last.hasPrevious()) { 
// add plus button to previous item
-                            Pair<T, V> previousItem = last.previous();
-                            
getEntry(previousItem.getSecond()).appendButton(createButton(previousItem, 
true));
-                        }
-
-                        removeEntry(item);
-                        onRemove(value, widget);
-
-                        if (items.isEmpty()) {
-                            Pair<T, V> item = addGhostEntry();
-                            onAdd(item.getFirst(), item.getSecond());
-                        }
+                        doRemoveItem(item, value, widget);
                     }
                 });
 
         return button;
     }
 
+    protected void doRemoveItem(Pair<T, V> item, T value, V widget) {
+        ListIterator<Pair<T, V>> last = items.listIterator(items.size());
+        if (!last.hasPrevious()) { // just a precaution; if there's no item, 
there should be no button
+            return;
+        }
+
+        if (item == last.previous() && last.hasPrevious()) { // add plus 
button to previous item
+            Pair<T, V> previousItem = last.previous();
+            
getEntry(previousItem.getSecond()).appendButton(createButton(previousItem, 
true));
+        }
+
+        removeEntry(item);
+        onRemove(value, widget);
+
+        if (items.isEmpty()) {
+            Pair<T, V> ghostItem = addGhostEntry();
+            onAdd(ghostItem.getFirst(), ghostItem.getSecond());
+        }
+    }
+
+    /**
+     * Lets to decide if we really want to remove this item or not.
+     * Everything can be removed by default.
+     */
+    protected boolean vetoRemoveWidget(Pair<T, V> item, T value, V widget) {
+        return false;
+    }
+
     @SuppressWarnings("unchecked")
     private AddRemoveRowPanel getEntry(V widget) {
         return (AddRemoveRowPanel) widget.getParent();
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/uicommon/instanceimages/InstanceImageLineEditor.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/uicommon/instanceimages/InstanceImageLineEditor.java
new file mode 100644
index 0000000..915a6bc
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/uicommon/instanceimages/InstanceImageLineEditor.java
@@ -0,0 +1,138 @@
+package org.ovirt.engine.ui.common.widget.uicommon.instanceimages;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.editor.client.SimpleBeanEditorDriver;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.logical.shared.HasValueChangeHandlers;
+import com.google.gwt.event.logical.shared.ValueChangeEvent;
+import com.google.gwt.event.logical.shared.ValueChangeHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.HasEnabled;
+import com.google.gwt.user.client.ui.Label;
+import org.ovirt.engine.ui.common.CommonApplicationConstants;
+import org.ovirt.engine.ui.common.idhandler.ElementIdHandler;
+import org.ovirt.engine.ui.common.idhandler.HasElementId;
+import org.ovirt.engine.ui.common.utils.ElementIdUtils;
+import org.ovirt.engine.ui.common.widget.UiCommandButton;
+import 
org.ovirt.engine.ui.common.widget.uicommon.popup.AbstractModelBoundPopupWidget;
+import org.ovirt.engine.ui.uicommonweb.models.vms.InstanceImageLineModel;
+import org.ovirt.engine.ui.uicompat.Event;
+import org.ovirt.engine.ui.uicompat.EventArgs;
+import org.ovirt.engine.ui.uicompat.IEventListener;
+
+public class InstanceImageLineEditor extends 
AbstractModelBoundPopupWidget<InstanceImageLineModel> implements 
HasValueChangeHandlers<InstanceImageLineModel>, HasEnabled, HasElementId {
+
+    @UiField
+    @Path("name.entity")
+    Label nameLabel;
+
+    @UiField
+    @Ignore
+    UiCommandButton createEditButton;
+
+    @UiField
+    @Ignore
+    UiCommandButton attachButton;
+
+    private String elementId = DOM.createUniqueId();
+
+    public interface Driver extends 
SimpleBeanEditorDriver<InstanceImageLineModel, InstanceImageLineEditor> {
+    }
+
+    private final Driver driver = GWT.create(Driver.class);
+
+    @UiField
+    CommonApplicationConstants constants;
+
+    interface WidgetUiBinder extends UiBinder<FlowPanel, 
InstanceImageLineEditor> {
+        WidgetUiBinder uiBinder = GWT.create(WidgetUiBinder.class);
+    }
+
+    interface WidgetIdHandler extends 
ElementIdHandler<InstanceImageLineEditor> {
+        WidgetIdHandler idHandler = GWT.create(WidgetIdHandler.class);
+    }
+
+    public InstanceImageLineEditor() {
+        initWidget(WidgetUiBinder.uiBinder.createAndBindUi(this));
+        WidgetIdHandler.idHandler.generateAndSetIds(this);
+
+        driver.initialize(this);
+    }
+
+    @Override
+    public void edit(final InstanceImageLineModel model) {
+        driver.edit(model);
+        setupElementIds(model);
+
+        createEditButton.setCommand(model.getCreateEditCommand());
+        attachButton.setCommand(model.getAttachCommand());
+
+        // memory leak maybe?
+        createEditButton.addClickHandler(new ClickHandler() {
+            @Override
+            public void onClick(ClickEvent event) {
+                createEditButton.getCommand().execute();
+            }
+        });
+
+        attachButton.addClickHandler(new ClickHandler() {
+            @Override
+            public void onClick(ClickEvent event) {
+                attachButton.getCommand().execute();
+            }
+        });
+
+        updateButtonText(model);
+
+        model.getDiskModel().getEntityChangedEvent().addListener(new 
IEventListener<EventArgs>() {
+            @Override
+            public void eventRaised(Event<? extends EventArgs> ev, Object 
sender, EventArgs args) {
+                ValueChangeEvent.fire(InstanceImageLineEditor.this, model);
+                updateButtonText(model);
+            }
+        });
+    }
+
+    public void setupElementIds(InstanceImageLineModel model) {
+        String diskAlias = model.getDisk() != null ? 
model.getDisk().getDiskAlias() : ""; //$NON-NLS-1$
+        String composedId = ElementIdUtils.createElementId(elementId, 
diskAlias);
+
+        nameLabel.getElement().setId(composedId);
+        
attachButton.getElement().setId(ElementIdUtils.createElementId(composedId, 
"attach")); //$NON-NLS-1$
+        
createEditButton.getElement().setId(ElementIdUtils.createElementId(composedId, 
"createEdit")); //$NON-NLS-1$
+    }
+
+    private void updateButtonText(InstanceImageLineModel model) {
+        String text = model.getDiskModel().getEntity() != null ? 
constants.editInstanceImages() : constants.addInstanceImages();
+        createEditButton.setLabel(text);
+    }
+
+    @Override
+    public InstanceImageLineModel flush() {
+        return driver.flush();
+    }
+
+    @Override
+    public boolean isEnabled() {
+        return false;
+    }
+
+    @Override
+    public void setEnabled(boolean b) {
+
+    }
+
+    @Override
+    public HandlerRegistration 
addValueChangeHandler(ValueChangeHandler<InstanceImageLineModel> 
valueChangeHandler) {
+        return addHandler(valueChangeHandler, ValueChangeEvent.getType());
+    }
+
+    public void setElementId(String elementId) {
+        this.elementId = elementId;
+    }
+}
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/uicommon/instanceimages/InstanceImageLineEditor.ui.xml
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/uicommon/instanceimages/InstanceImageLineEditor.ui.xml
new file mode 100644
index 0000000..821ddad
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/uicommon/instanceimages/InstanceImageLineEditor.ui.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent";>
+<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
+             xmlns:g="urn:import:com.google.gwt.user.client.ui"
+             xmlns:w="urn:import:org.ovirt.engine.ui.common.widget">
+
+    <ui:with field='constants' 
type='org.ovirt.engine.ui.common.CommonApplicationConstants'/>
+
+    <ui:style>
+        .mainPanel {
+            width: 330px;
+        }
+
+        .buttonStyle {
+            float: right;
+            padding-top: 5px;
+            padding-right: 5px;
+        }
+
+        .labelStyle {
+            float: left;
+        }
+    </ui:style>
+
+    <g:FlowPanel addStyleNames="{style.mainPanel}">
+        <g:Label ui:field="nameLabel" addStyleNames="{style.labelStyle}"/>
+        <w:UiCommandButton ui:field="createEditButton" 
label="{constants.addInstanceImages}" addStyleNames="{style.buttonStyle}"/>
+        <w:UiCommandButton ui:field="attachButton" 
label="{constants.attachInstanceImages}" addStyleNames="{style.buttonStyle}"/>
+    </g:FlowPanel>
+</ui:UiBinder>
\ No newline at end of file
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/uicommon/instanceimages/InstanceImagesEditor.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/uicommon/instanceimages/InstanceImagesEditor.java
new file mode 100644
index 0000000..22c82b7
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/uicommon/instanceimages/InstanceImagesEditor.java
@@ -0,0 +1,80 @@
+package org.ovirt.engine.ui.common.widget.uicommon.instanceimages;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.ui.Widget;
+import org.ovirt.engine.core.common.utils.Pair;
+import org.ovirt.engine.ui.common.idhandler.ElementIdHandler;
+import org.ovirt.engine.ui.common.idhandler.HasElementId;
+import org.ovirt.engine.ui.common.widget.AddRemoveRowWidget;
+import org.ovirt.engine.ui.uicommonweb.models.vms.InstanceImageLineModel;
+import org.ovirt.engine.ui.uicommonweb.models.vms.InstanceImagesModel;
+
+
+public class InstanceImagesEditor extends 
AddRemoveRowWidget<InstanceImagesModel, InstanceImageLineModel, 
InstanceImageLineEditor> implements HasElementId {
+
+    private InstanceImagesModel model;
+
+    private String elementId = DOM.createUniqueId();
+
+    interface WidgetUiBinder extends UiBinder<Widget, InstanceImagesEditor> {
+        WidgetUiBinder uiBinder = GWT.create(WidgetUiBinder.class);
+    }
+
+    interface WidgetIdHandler extends ElementIdHandler<InstanceImagesEditor> {
+        WidgetIdHandler idHandler = GWT.create(WidgetIdHandler.class);
+    }
+
+    public InstanceImagesEditor() {
+        initWidget(WidgetUiBinder.uiBinder.createAndBindUi(this));
+        WidgetIdHandler.idHandler.generateAndSetIds(this);
+    }
+
+    @Override
+    protected InstanceImageLineEditor createWidget(InstanceImageLineModel 
value) {
+        InstanceImageLineEditor editor = new InstanceImageLineEditor();
+        editor.setElementId(elementId);
+        editor.edit(value);
+        return editor;
+    }
+
+    @Override
+    protected InstanceImageLineModel createGhostValue() {
+        InstanceImageLineModel lineModel = new InstanceImageLineModel(model);
+        // the getVm() is null on new VM - that is handled inside the line 
models
+        lineModel.initialize(null, model.getVm());
+        return lineModel;
+    }
+
+    @Override
+    protected boolean isGhost(InstanceImageLineModel value) {
+        return value.isGhost();
+    }
+
+    @Override
+    protected boolean vetoRemoveWidget(final Pair<InstanceImageLineModel, 
InstanceImageLineEditor> item, final InstanceImageLineModel value, final 
InstanceImageLineEditor widget) {
+        model.approveRemoveDisk(item.getFirst(), new 
InstanceImagesModel.RemoveApprovedCallback() {
+            @Override
+            public void removeApproved(boolean approved) {
+                if (approved) {
+                    doRemoveItem(item, value, widget);
+                }
+            }
+        });
+
+        // will be eventually removed from the callback
+        return false;
+    }
+
+    @Override
+    public void edit(final InstanceImagesModel model) {
+        this.model = model;
+        super.edit(model);
+    }
+
+    @Override
+    public void setElementId(String elementId) {
+        this.elementId = elementId;
+    }
+}
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/uicommon/instanceimages/InstanceImagesEditor.ui.xml
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/uicommon/instanceimages/InstanceImagesEditor.ui.xml
new file mode 100644
index 0000000..abd5619
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/uicommon/instanceimages/InstanceImagesEditor.ui.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent";>
+<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" 
xmlns:g="urn:import:com.google.gwt.user.client.ui">
+
+    <ui:with field='constants' 
type='org.ovirt.engine.ui.common.CommonApplicationConstants'/>
+
+    <ui:style 
type="org.ovirt.engine.ui.common.widget.AddRemoveRowWidget.WidgetStyle">
+        .buttonStyle {
+            padding-left: 2px;
+            padding-top: 2px;
+            margin-top: 6px;
+            margin-left: 10px;
+        }
+
+        .titleStyle {
+            padding: 0 5px;
+            margin-left: 5px;
+            float: left;
+            width: 100%;
+        }
+
+        .mainPanel {
+            width: 100%;
+        }
+
+        .contentPanel {
+            padding-right: 10px;
+            margin-left: 5px;
+        }
+
+    </ui:style>
+
+    <g:FlowPanel addStyleNames="{style.mainPanel}">
+        <g:Label addStyleNames="{style.titleStyle}" 
text="{constants.instanceImages}"/>
+        <g:FlowPanel ui:field="contentPanel" 
addStyleNames="{style.contentPanel}"/>
+    </g:FlowPanel>
+</ui:UiBinder>
\ No newline at end of file
diff --git 
a/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/configure/instancetypes/InstanceTypeListModel.java
 
b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/configure/instancetypes/InstanceTypeListModel.java
index f3481f8..710558b 100644
--- 
a/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/configure/instancetypes/InstanceTypeListModel.java
+++ 
b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/configure/instancetypes/InstanceTypeListModel.java
@@ -63,7 +63,7 @@
     private final InstanceTypeInterfaceCreatingManager 
addInstanceTypeNetworkManager =
             new InstanceTypeInterfaceCreatingManager(new 
BaseInterfaceCreatingManager.PostVnicCreatedCallback() {
                 @Override
-                public void vnicCreated(Guid vmId) {
+                public void vnicCreated(Guid vmId, UnitVmModel unitVmModel) {
                     getWindow().stopProgress();
                     cancel();
                     updateActionAvailability();
@@ -311,7 +311,7 @@
             return;
         }
 
-        UnitVmModel model = new UnitVmModel(behavior);
+        UnitVmModel model = new UnitVmModel(behavior, this);
         model.setIsAdvancedModeLocalStorageKey("instance_type_dialog"); 
//$NON-NLS-1$
         setWindow(model);
 
diff --git 
a/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/vms/InstanceImageLineModel.java
 
b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/vms/InstanceImageLineModel.java
new file mode 100644
index 0000000..734c5b2
--- /dev/null
+++ 
b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/vms/InstanceImageLineModel.java
@@ -0,0 +1,346 @@
+package org.ovirt.engine.ui.uicommonweb.models.vms;
+
+import org.ovirt.engine.core.common.businessentities.Disk;
+import org.ovirt.engine.core.common.businessentities.VM;
+import org.ovirt.engine.core.compat.Version;
+import org.ovirt.engine.ui.uicommonweb.UICommand;
+import org.ovirt.engine.ui.uicommonweb.help.HelpTag;
+import org.ovirt.engine.ui.uicommonweb.models.EntityModel;
+import org.ovirt.engine.ui.uicompat.ConstantsManager;
+import org.ovirt.engine.ui.uicompat.UIConstants;
+import org.ovirt.engine.ui.uicompat.UIMessages;
+
+import java.util.List;
+
+public class InstanceImageLineModel extends EntityModel {
+
+    public static final String CANCEL_DISK = "CancelDisk"; //$NON-NLS-1$
+
+    private UIMessages messages = ConstantsManager.getInstance().getMessages();
+
+    private UIConstants constants = 
ConstantsManager.getInstance().getConstants();
+
+    private UICommand attachCommand;
+
+    private UICommand createEditCommand;
+
+    private EntityModel<AbstractDiskModel> diskModel = new EntityModel<>();
+
+    // if the disk already exists in the engine or is just created here but 
not yet submitted
+    private boolean diskExists;
+
+    // a hack because the diskModel from inside of this method might not have 
been inited when the onSave is called
+    private AbstractDiskModel tmpDiskModel;
+
+    private EntityModel<String> name = new EntityModel<>();
+
+    private InstanceImagesModel parentModel;
+
+    private VM vm;
+
+    private boolean active = true;
+
+    public InstanceImageLineModel(InstanceImagesModel parentModel) {
+        this.parentModel = parentModel;
+
+        attachCommand = new UICommand("attachCommand", this); //$NON-NLS-1$
+        createEditCommand = new UICommand("createEditCommand", this); 
//$NON-NLS-1$
+    }
+
+    private void fillData() {
+        if (diskModel.getEntity() == null) {
+            return;
+        }
+
+        if (diskModel.getEntity() instanceof AttachDiskModel) {
+            List<EntityModel<DiskModel>> disks = ((AttachDiskModel) 
diskModel.getEntity()).getSelectedDisks();
+            if (disks.size() != 0) {
+                updateName(disks.get(0).getEntity().getDisk());
+            }
+        } else {
+            updateName(diskModel.getEntity().getDisk());
+        }
+    }
+
+    private void updateName(Disk disk) {
+        if (disk == null) {
+            return;
+        }
+
+        String diskName = disk.getDiskAlias();
+        String size = Long.toString(disk.getSize());
+
+        if (disk.getDiskStorageType() == Disk.DiskStorageType.IMAGE) {
+            size = Long.toString(disk.getSize() / (1024 * 1024 * 1024));
+        }
+
+        String type;
+        if (diskExists) {
+            type = constants.existingDisk();
+        } else if (getDiskModel().getEntity() instanceof AttachDiskModel) {
+            type = constants.attachingDisk();
+        } else {
+            type = constants.creatingDisk();
+        }
+
+        String boot = ""; //$NON-NLS-1$
+        if (disk.isBoot()) {
+            boot = constants.bootDisk();
+        }
+
+        name.setEntity(messages.vmDialogDisk(diskName, size, type, boot));
+    }
+
+
+    public void initialize(Disk disk, VM vm) {
+        this.vm = vm;
+        active = true;
+        diskExists = disk != null;
+
+        attachCommand.setIsAvailable(!diskExists);
+
+        if (disk == null) {
+            return;
+        }
+
+        final AbstractDiskModel model = new EditDiskModel() {
+            @Override
+            public void onSave() {
+                if (validate()) {
+                    flush();
+                    getDiskModel().setEntity(tmpDiskModel);
+
+                    // needed because the "entity" instances are the same so 
the event is not fired
+                    fillData();
+
+                    parentModel.getParentListModel().setWindow(null);
+                    
parentModel.getParentListModel().setWindow(parentModel.getUnitVmModel());
+                }
+            }
+        };
+
+        tmpDiskModel = model;
+
+        model.setDisk(disk);
+        model.setVm(vm);
+
+        setupModelAsDialog(model,
+                
ConstantsManager.getInstance().getConstants().editVirtualDiskTitle(),
+                HelpTag.edit_virtual_disk, "edit_virtual_disk"); //$NON-NLS-1$
+
+        model.initialize();
+        diskModel.setEntity(model);
+        fillData();
+    }
+
+    public EntityModel<AbstractDiskModel> getDiskModel() {
+        return diskModel;
+    }
+
+    public EntityModel<String> getName() {
+        return name;
+    }
+
+    public void setName(EntityModel<String> name) {
+        this.name = name;
+    }
+
+    public boolean isGhost() {
+        return diskModel.getEntity() == null;
+    }
+
+    public void attachDisk() {
+        AttachDiskModel model = new AttachDiskModel() {
+            @Override
+            public void onSave() {
+                if (validate()) {
+                    flush();
+                    List<EntityModel<DiskModel>> selectedDisks = 
((AttachDiskModel) tmpDiskModel).getSelectedDisks();
+                    if (selectedDisks.size() == 1) {
+                        // only 0 or 1 is allowed
+                        
tmpDiskModel.setDisk(selectedDisks.iterator().next().getEntity().getDisk());
+                    }
+
+                    getDiskModel().setEntity(tmpDiskModel);
+                    parentModel.getParentListModel().setWindow(null);
+                    
parentModel.getParentListModel().setWindow(parentModel.getUnitVmModel());
+                    // from now on only editing is possible
+                    attachCommand.setIsAvailable(false);
+
+                    fillData();
+                }
+            }
+        };
+
+        tmpDiskModel = model;
+        VM realOrFakeVm = vm;
+        Version compatibilityVersion = 
parentModel.getUnitVmModel().getSelectedCluster().getcompatibility_version();
+        if (realOrFakeVm == null) {
+            realOrFakeVm = new VM();
+            realOrFakeVm.setId(null);
+            
realOrFakeVm.setVdsGroupId(parentModel.getUnitVmModel().getSelectedCluster().getId());
+            
realOrFakeVm.setStoragePoolId(parentModel.getUnitVmModel().getSelectedDataCenter().getId());
+            realOrFakeVm.setVdsGroupCompatibilityVersion(compatibilityVersion);
+        }
+
+        model.setVm(realOrFakeVm);
+
+        setupModelAsDialog(model,
+                
ConstantsManager.getInstance().getConstants().attachVirtualDiskTitle(),
+                HelpTag.attach_virtual_disk, "attach_virtual_disk"); 
//$NON-NLS-1$
+        showDialog(model);
+        model.initialize(parentModel.getAllCurrentDisks());
+        maybeLoadAttachableDisks(model);
+    }
+
+    private void maybeLoadAttachableDisks(AttachDiskModel model) {
+        if (model.getVm().getId() == null) {
+            Integer osType = 
parentModel.getUnitVmModel().getOSType().getSelectedItem();
+            Version compatibilityVersion = 
parentModel.getUnitVmModel().getSelectedCluster().getcompatibility_version();
+            model.loadAttachableDisks(true, osType, compatibilityVersion, 
getDisk());
+        } else {
+            model.loadAttachableDisks(false, 0, null, getDisk());
+        }
+    }
+
+    public void createEditDisk() {
+        if (parentModel.getUnitVmModel().getSelectedCluster() == null || 
parentModel.getUnitVmModel().getSelectedDataCenter() == null) {
+            return;
+        }
+
+        if (getDiskModel().getEntity() == null) {
+            showNewDialog();
+        } else {
+            showPreviouslyShownDialog();
+        }
+    }
+
+    private void showPreviouslyShownDialog() {
+        
getDiskModel().getEntity().updateBootableFrom(parentModel.getAllCurrentDisks());
+        if (getDiskModel().getEntity() instanceof AttachDiskModel) {
+            // needed to re-filter in case the OS or the compatibility version 
changed
+            maybeLoadAttachableDisks((AttachDiskModel) 
getDiskModel().getEntity());
+        }
+        showDialog(getDiskModel().getEntity());
+    }
+
+    private void showNewDialog() {
+        final AbstractDiskModel model = new NewDiskModel() {
+            @Override
+            public void onSave() {
+                if (validate()) {
+                    flush();
+                    getDiskModel().setEntity(tmpDiskModel);
+                    parentModel.getParentListModel().setWindow(null);
+                    
parentModel.getParentListModel().setWindow(parentModel.getUnitVmModel());
+                    // the "new" turns into "edit" - no need for attach anymore
+                    attachCommand.setIsAvailable(false);
+
+                    fillData();
+                }
+            }
+        };
+
+        tmpDiskModel = model;
+
+        VM vm = new VM();
+        
vm.setVdsGroupId(parentModel.getUnitVmModel().getSelectedCluster().getId());
+        
vm.setStoragePoolId(parentModel.getUnitVmModel().getSelectedDataCenter().getId());
+        
vm.setVdsGroupCompatibilityVersion(parentModel.getUnitVmModel().getSelectedCluster().getcompatibility_version());
+        model.setVm(vm);
+
+        setupModelAsDialog(model,
+                
ConstantsManager.getInstance().getConstants().newVirtualDiskTitle(),
+                HelpTag.new_virtual_disk, "new_virtual_disk"); //$NON-NLS-1$
+
+        showDialog(model);
+        model.initialize(parentModel.getAllCurrentDisks());
+    }
+
+    private void setupModelAsDialog(AbstractDiskModel model, String title, 
HelpTag helpTag, String hashName) {
+        model.setTitle(title);
+        model.setHelpTag(helpTag);
+        model.setHashName(hashName);
+
+        UICommand cancelCommand = new UICommand(CANCEL_DISK, this);
+        
cancelCommand.setTitle(ConstantsManager.getInstance().getConstants().cancel());
+        cancelCommand.setIsCancel(true);
+        model.setCancelCommand(cancelCommand);
+    }
+
+    private void showDialog(AbstractDiskModel model) {
+        parentModel.getParentListModel().setWindow(null);
+        parentModel.getParentListModel().setWindow(model);
+    }
+
+    @Override
+    public void executeCommand(UICommand command) {
+        if (!active) {
+            // don't listen to this commands anymore - no need to show any 
more windows
+            return;
+        }
+        if (CANCEL_DISK.equals(command.getName())) {
+            parentModel.getParentListModel().setWindow(null);
+            
parentModel.getParentListModel().setWindow(parentModel.getUnitVmModel());
+        } else if (command == createEditCommand) {
+            createEditDisk();
+        } else if (command == attachCommand) {
+            attachDisk();
+        } else {
+            super.executeCommand(command);
+        }
+    }
+
+    public boolean isBootable() {
+        if (isGhost()) {
+            return false;
+        }
+
+        return diskModel.getEntity().getIsBootable().getEntity();
+    }
+
+    public Disk getDisk() {
+        AbstractDiskModel diskModel = getDiskModel().getEntity();
+
+        if (diskModel == null) {
+            return null;
+        }
+
+        Disk disk = diskModel.getDisk();
+        if (disk == null) {
+            disk = diskModel.getDiskImage();
+        }
+
+        if (disk == null) {
+            disk = diskModel.getLunDisk();
+        }
+
+        return disk;
+    }
+
+    public boolean isDiskExists() {
+        return diskExists;
+    }
+
+    public VM getVm() {
+        return vm;
+    }
+
+    public UICommand getAttachCommand() {
+        return attachCommand;
+    }
+
+    public UICommand getCreateEditCommand() {
+        return createEditCommand;
+    }
+
+
+    public void setEnabled(boolean enabled) {
+        attachCommand.setIsExecutionAllowed(enabled);
+        createEditCommand.setIsExecutionAllowed(enabled);
+    }
+
+    public void deactivate() {
+        active = false;
+    }
+}
diff --git 
a/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/vms/InstanceImagesModel.java
 
b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/vms/InstanceImagesModel.java
new file mode 100644
index 0000000..2de84fe
--- /dev/null
+++ 
b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/vms/InstanceImagesModel.java
@@ -0,0 +1,265 @@
+package org.ovirt.engine.ui.uicommonweb.models.vms;
+
+import org.ovirt.engine.core.common.businessentities.Disk;
+import org.ovirt.engine.core.common.businessentities.VM;
+import org.ovirt.engine.ui.frontend.AsyncQuery;
+import org.ovirt.engine.ui.frontend.INewAsyncCallback;
+import org.ovirt.engine.ui.uicommonweb.ICommandTarget;
+import org.ovirt.engine.ui.uicommonweb.UICommand;
+import org.ovirt.engine.ui.uicommonweb.dataprovider.AsyncDataProvider;
+import org.ovirt.engine.ui.uicommonweb.models.ListModel;
+import org.ovirt.engine.ui.uicommonweb.models.Model;
+import org.ovirt.engine.ui.uicompat.FrontendActionAsyncResult;
+import org.ovirt.engine.ui.uicompat.IFrontendActionAsyncCallback;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+public class InstanceImagesModel extends ListModel<InstanceImageLineModel> {
+
+    private Model parentListModel;
+
+    private UnitVmModel unitVmModel;
+
+    private List<RemoveDiskModel> removeDiskModels = new ArrayList<>();
+
+    private RemoveDiskModel removeDiskModel;
+
+    private RemoveApprovedCallback callback;
+
+    private VM vm;
+
+    public InstanceImagesModel(UnitVmModel unitVmModel, Model parentListModel) 
{
+        this.parentListModel = parentListModel;
+        this.unitVmModel = unitVmModel;
+    }
+
+    public Model getParentListModel() {
+        return parentListModel;
+    }
+
+    public UnitVmModel getUnitVmModel() {
+        return unitVmModel;
+    }
+
+    public void approveRemoveDisk(InstanceImageLineModel lineModel, 
RemoveApprovedCallback callback) {
+        if (!lineModel.isDiskExists() || lineModel.getVm() == null) {
+            // no problem, the item can be removed without explicitly asking 
the user
+            callback.removeApproved(true);
+            return;
+        }
+
+        this.callback = callback;
+        removeDiskModel = new RemoveDiskModel();
+
+        List<Disk> disksToRemove = 
Arrays.asList(lineModel.getDiskModel().getEntity().getDisk());
+        VM vm = lineModel.getVm();
+
+        getParentListModel().setWindow(null);
+        getParentListModel().setWindow(removeDiskModel);
+
+        removeDiskModel.initialize(vm, disksToRemove, this);
+    }
+
+    private void onRemove() {
+        if (!removeDiskModel.validate()) {
+            return;
+        }
+
+        removeDiskModels.add(removeDiskModel);
+        hideRemoveDiskAndShowEditVm();
+        callback.removeApproved(true);
+    }
+
+    private void onCancel() {
+        hideRemoveDiskAndShowEditVm();
+        callback.removeApproved(false);
+    }
+
+    private void hideRemoveDiskAndShowEditVm() {
+        getParentListModel().setWindow(null);
+        getParentListModel().setWindow(getUnitVmModel());
+    }
+
+    @Override
+    public void executeCommand(UICommand command) {
+        super.executeCommand(command);
+
+        if (RemoveDiskModel.ON_REMOVE.equals(command.getName())) {
+            onRemove();
+        } else if (RemoveDiskModel.CANCEL_REMOVE.equals(command.getName())) {
+            onCancel();
+        }
+    }
+
+    public void setVm(VM vm) {
+        this.vm = vm;
+    }
+
+    public VM getVm() {
+        return vm;
+    }
+
+    public static interface RemoveApprovedCallback {
+        void removeApproved(boolean approved);
+    }
+
+    public void executeDiskModifications(VM vm) {
+        // this is done on the background - the window is not visible anymore
+        disableLineModels();
+        executeDeleteAndCallNew(vm);
+    }
+
+    private void disableLineModels() {
+        for (InstanceImageLineModel model : getItems()) {
+            model.deactivate();
+        }
+    }
+
+    private void executeDeleteAndCallNew(final VM vm) {
+        if (removeDiskModels.size() == 0) {
+            executeNewAndEdit(vm);
+            return;
+        }
+
+        for (RemoveDiskModel removeDisk : removeDiskModels ) {
+            removeDisk.store(new ICommandTarget() {
+                @Override
+                public void executeCommand(UICommand command) {
+                    executeNewAndEdit(vm);
+                }
+
+                @Override
+                public void executeCommand(UICommand uiCommand, Object... 
parameters) {
+                    executeNewAndEdit(vm);
+                }
+            });
+        }
+    }
+
+    private void executeNewAndEdit(final VM vm) {
+        if (getItems() == null) {
+            return;
+        }
+
+        AsyncDataProvider.getInstance().getVmDiskList(new AsyncQuery(this, new 
INewAsyncCallback() {
+            @Override
+            public void onSuccess(Object target, Object returnValue) {
+                Iterator<InstanceImageLineModel> lineModelIterator = 
orderedDisksIterator((List<Disk>) returnValue);
+                storeNextDisk(lineModelIterator, vm);
+            }
+        }), vm.getId());
+
+    }
+
+    /**
+     * Finds the disk which is boot on the VM but has been configured to be 
non boot. If finds such a disk, the resulting
+     * list will contain as a first command the one which executes this 
operation.
+     *
+     * It is needed because they can be other which make an another disk boot 
and the VM can not have more than one boot
+     * disk - so the validation on server would fail.
+     */
+    private Iterator<InstanceImageLineModel> orderedDisksIterator(List<Disk> 
disks) {
+        if (disks.size() == 0) {
+            return getItems().iterator();
+        }
+
+        Disk previouslyBootDisk = findBoot(disks);
+        if (previouslyBootDisk == null) {
+            return getItems().iterator();
+        }
+
+        InstanceImageLineModel fromBootToNonBoot = 
findBecomeNonBoot(previouslyBootDisk);
+        if (fromBootToNonBoot == null) {
+            return getItems().iterator();
+        }
+
+        // now we know that the disk changed from boot to non boot so this 
command has to be executed as first
+        Set<InstanceImageLineModel> res = new LinkedHashSet<>();
+        res.add(fromBootToNonBoot);
+        res.addAll(getItems());
+        return res.iterator();
+    }
+
+    private InstanceImageLineModel findBecomeNonBoot(Disk bootDisk) {
+        for (InstanceImageLineModel model : getItems()) {
+            Disk disk = model.getDiskModel().getEntity().getDisk();
+            if (disk.getId().equals(bootDisk.getId())) {
+                if (disk.isBoot()) {
+                    return null;
+                } else {
+                    // removed boot flag, this command has to be executed 
first so if other disk is marked as boot,
+                    // it will not fail with the message that you can have 
only one boot
+                    return model;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    private Disk findBoot(List<Disk> disks) {
+        for (Disk disk : disks) {
+            if (disk.isBoot()) {
+                return disk;
+            }
+        }
+
+        return null;
+    }
+
+    private void storeNextDisk(final Iterator<InstanceImageLineModel> 
lineModelIterator, final VM vm) {
+        if (!lineModelIterator.hasNext()) {
+            return;
+        }
+
+        AbstractDiskModel diskModel = 
lineModelIterator.next().getDiskModel().getEntity();
+
+        if (diskModel == null) {
+            storeNextDisk(lineModelIterator, vm);
+        } else {
+            diskModel.setVm(vm);
+
+            diskModel.store(new IFrontendActionAsyncCallback() {
+                @Override
+                public void executed(FrontendActionAsyncResult result) {
+                    // have to wait until the previous returned because the 
operation needs a lock on the VM
+                    storeNextDisk(lineModelIterator, vm);
+                }
+            });
+        }
+
+    }
+
+    public List<Disk> getAllCurrentDisks() {
+        List<Disk> res = new ArrayList<>();
+        for (InstanceImageLineModel line : getItems()) {
+            if (line.isGhost()) {
+                continue;
+            }
+
+            res.add(line.getDisk());
+        }
+
+        return res;
+    }
+
+    public void updateActionsAvailability() {
+        boolean clusterSelected = unitVmModel.getSelectedCluster() != null;
+        boolean osSelected = unitVmModel.getOSType().getSelectedItem() != null;
+
+        for (InstanceImageLineModel model : getItems()) {
+            if (model.isGhost()) {
+                continue;
+            }
+
+            model.setEnabled(clusterSelected && osSelected);
+        }
+
+        setIsChangable(clusterSelected && osSelected);
+    }
+}
diff --git 
a/frontend/webadmin/modules/uicompat/src/main/java/org/ovirt/engine/ui/uicompat/UIConstants.java
 
b/frontend/webadmin/modules/uicompat/src/main/java/org/ovirt/engine/ui/uicompat/UIConstants.java
index fde7b44..3293252 100644
--- 
a/frontend/webadmin/modules/uicompat/src/main/java/org/ovirt/engine/ui/uicompat/UIConstants.java
+++ 
b/frontend/webadmin/modules/uicompat/src/main/java/org/ovirt/engine/ui/uicompat/UIConstants.java
@@ -2461,4 +2461,16 @@
 
     @DefaultStringValue("Click on Numa Pinning to configure VM's virtual node 
span on top of physical host NUMA nodes")
     String numaInfoMessage();
+
+    @DefaultStringValue("existing")
+    String existingDisk();
+
+    @DefaultStringValue("creating")
+    String creatingDisk();
+
+    @DefaultStringValue("attaching")
+    String attachingDisk();
+
+    @DefaultStringValue("boot")
+    String bootDisk();
 }
diff --git 
a/frontend/webadmin/modules/uicompat/src/main/java/org/ovirt/engine/ui/uicompat/UIMessages.java
 
b/frontend/webadmin/modules/uicompat/src/main/java/org/ovirt/engine/ui/uicompat/UIMessages.java
index cb3329d..b40cdfd 100644
--- 
a/frontend/webadmin/modules/uicompat/src/main/java/org/ovirt/engine/ui/uicompat/UIMessages.java
+++ 
b/frontend/webadmin/modules/uicompat/src/main/java/org/ovirt/engine/ui/uicompat/UIMessages.java
@@ -403,4 +403,7 @@
 
     @DefaultMessage("Default ({0})")
     String defaultMtu(int mtu);
+
+    @DefaultMessage("{0}: ({1} GB) {2} {3}")
+    String vmDialogDisk(String name, String sizeInGb, String type, String 
boot);
 }


-- 
To view, visit http://gerrit.ovirt.org/36063
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I4bcaa1e40841aa12e64708ec82afdb9daec9fb7f
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-engine
Gerrit-Branch: master
Gerrit-Owner: Tomas Jelinek <tjeli...@redhat.com>
_______________________________________________
Engine-patches mailing list
Engine-patches@ovirt.org
http://lists.ovirt.org/mailman/listinfo/engine-patches

Reply via email to