Vojtech Szocs has posted comments on this change.

Change subject: webadmin: auto select dialog tab
......................................................................


Patch Set 2:

(17 comments)

This is a very nice patch, please find my comments inline.

This patch is VERY important as it touches UiCommon models and GWT code that 
binds to it. After it's merged, I _strongly_ suggest to announce changes done 
in this patch to all UI maintainers. (So that when development continues on 
UiCommon layer, new changes will be consistent with this patch.)

(I'd even say you could do some quick public session about it, showing code 
changes and their purpose, because people might not read email announcements.)

http://gerrit.ovirt.org/#/c/27781/2/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/presenter/AbstractModelBoundPopupPresenterWidget.java
File 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/presenter/AbstractModelBoundPopupPresenterWidget.java:

Line 193:         // Initialize popup contents from the model
Line 194:         getView().edit(model);
Line 195:         getView().updateTabIndexes();
Line 196: 
Line 197:         model.setEventBus((EventBus) getEventBus());
Nice!

Dialog models don't have model providers associated, this code ensures that 
they benefit from EventBus just like other non-dialog models.

One small thing - EntityModel.setEventBus has:

 assert this.eventBus == null : "EventBus is already set";

even though this is very unlikely to happen (typically we receive freshly 
created model instance here, triggered by "Window" property change) - I suggest 
to do following:

 // Re-initialize event bus on the model
 model.unsetEventBus();
 model.setEventBus((EventBus) getEventBus());

Or even better, we could have some hasEventBus method on the model (returning 
true if model's eventBus != null) and do following:

 // Initialize event bus on the model
 if (!model.hasEventBus()) {
     model.setEventBus((EventBus) getEventBus());
 }
Line 198: 
Line 199:     }
Line 200: 
Line 201:     @Override


http://gerrit.ovirt.org/#/c/27781/2/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/utils/ValidationTabSwitchHelper.java
File 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/utils/ValidationTabSwitchHelper.java:

Line 27:      * @param view The {@code View} to update based on state of the 
model.
Line 28:      * @return The {@code HandlerRegistration} so the caller can 
manage the handlers.
Line 29:      */
Line 30:     public static HandlerRegistration registerValidationHandler(final 
EventBus eventBus,
Line 31:             final AbstractModelBoundPopupPresenterWidget<?, ?> 
presenterWidget, final TabbedView view) {
Note, presenterWidget and view arguments will be typically short-lived, i.e. 
they will represent a one-time-use, non-singleton PresenterWidget/View 
component.

I think that current implementation via static helper method is OK, because 
HandlerRegistration returned by this method should be removed when un-binding 
corresponding PresenterWidget by GWTP infra.
Line 32:         return eventBus.addHandler(ValidationCompleteEvent.getType(),
Line 33:                 new ValidationCompleteEventHandler() {
Line 34: 
Line 35:             @Override


Line 38:                 if (event.getModel() != null && 
event.getModel().equals(presenterWidget.getModel())) {
Line 39:                     //Get the invalid tab names from the model.
Line 40:                     Set<TabName> invalidTabs = ((HasValidatedTabs) 
presenterWidget.getModel()).getInvalidTabs();
Line 41:                     //Get the tab names to dialog tab widget map from 
the view.
Line 42:                     Map<TabName, DialogTab> mapping = 
view.getTabNameMapping();
I really like the concept of letting the view declare tabName-to-DialogTab 
mapping.
Line 43:                     markTabs(invalidTabs, mapping);
Line 44:                     //Check if the current active tab is invalid, if 
so don't do anything.
Line 45:                     for (TabName invalidTabName: invalidTabs) {
Line 46:                         if 
(view.getTabPanel().getActiveTab().equals(mapping.get(invalidTabName))) {


Line 61:      * @param mapping The TabName to DialogTab mapping.
Line 62:      */
Line 63:     private static void markTabs(Set<TabName> invalidTabs, 
Map<TabName, DialogTab> mapping) {
Line 64:         for (Map.Entry<TabName, DialogTab> entry: mapping.entrySet()) {
Line 65:             if(invalidTabs.contains(entry.getKey())) {
Please use space between "if" and "(" for better readability.
Line 66:                 entry.getValue().markAsInvalid(null);
Line 67:             } else {
Line 68:                 entry.getValue().markAsValid();
Line 69:             }


http://gerrit.ovirt.org/#/c/27781/2/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/AbstractTabbedModelBoundPopupView.java
File 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/AbstractTabbedModelBoundPopupView.java:

Line 29:             }
Line 30:         });
Line 31:     }
Line 32: 
Line 33:     abstract protected void populateTabMap();
Minor thing, please consider putting "protected" in front of "abstract" for 
consistency. (I wish Java modifier rules were more strict to promote consistent 
style.)

Also, it would be nice if this class managed the actual mapping instead of 
subclasses. For example:

 protected abstract void populateTabMap(Map<TabName, DialogTab> tabMap) {
     // tabMap managed by AbstractTabbedModelBoundPopupView, initially empty
     // subclasses just need to update tabMap, no need to create one on their 
own
 }
Line 34: 
Line 35:     @Override
Line 36:     public Map<TabName, DialogTab> getTabNameMapping() {
Line 37:         return tabMap;


http://gerrit.ovirt.org/#/c/27781/2/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/uicommon/popup/AbstractVmPopupWidget.java
File 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/uicommon/popup/AbstractVmPopupWidget.java:

Line 768:     private final CommonApplicationTemplates applicationTemplates;
Line 769: 
Line 770:     private final CommonApplicationConstants constants;
Line 771: 
Line 772:     private final Map<TabName, DialogTab> tabMap = new 
HashMap<TabName, DialogTab>();
Please see my comment in AbstractTabbedModelBoundPopupView.java - we could 
avoid the need to manage tabMap here.
Line 773: 
Line 774:     @SuppressWarnings({ "unchecked", "rawtypes" })
Line 775:     public AbstractVmPopupWidget(CommonApplicationConstants constants,
Line 776:             CommonApplicationResources resources,


Line 856: 
Line 857:         driver.initialize(this);
Line 858: 
Line 859:         initialize();
Line 860:         populateTabMap();
This call could be performed in AbstractTabbedModelBoundPopupView so that 
subclasses only implement populateTabMap method, without caring about calling 
this method.
Line 861:     }
Line 862: 
Line 863:     protected void populateTabMap() {
Line 864:         
getTabNameMapping().put(UnitVmModel.UnitVmTabNames.GENERAL_TAB, generalTab);


Line 859:         initialize();
Line 860:         populateTabMap();
Line 861:     }
Line 862: 
Line 863:     protected void populateTabMap() {
Please see my comment in AbstractTabbedModelBoundPopupView.java - we could 
simply pass tabMap as argument here.

Also, shouldn't this method be marked with @Override as it implements abstract 
method defined in parent View class?
Line 864:         
getTabNameMapping().put(UnitVmModel.UnitVmTabNames.GENERAL_TAB, generalTab);
Line 865:         
getTabNameMapping().put(UnitVmModel.UnitVmTabNames.BOOT_OPTIONS_TAB, 
this.bootOptionsTab);
Line 866:         
getTabNameMapping().put(UnitVmModel.UnitVmTabNames.CONSOLE_TAB, 
this.consoleTab);
Line 867:         
getTabNameMapping().put(UnitVmModel.UnitVmTabNames.CUSTOM_PROPERTIES_TAB, 
this.customPropertiesTab);


Line 1868:         return mainTabPanel;
Line 1869:     }
Line 1870: 
Line 1871:     @Override
Line 1872:     public Map<TabName, DialogTab> getTabNameMapping() {
Please see my comments above, tabMap could be managed simply via 
AbstractTabbedModelBoundPopupView so there would be no need to override this 
method.
Line 1873:         return tabMap;
Line 1874:     }


http://gerrit.ovirt.org/#/c/27781/2/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/Model.java
File 
frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/Model.java:

Line 31: {
Line 32:     /**
Line 33:      * The GWT event bus.
Line 34:      */
Line 35:     private EventBus eventBus;
+1 on moving event bus handling right into Model class.
Line 36: 
Line 37:     private final List<HandlerRegistration> handlerRegistrations = new 
ArrayList<HandlerRegistration>();
Line 38: 
Line 39:     public static final String CANCEL_COMMAND = "Cancel"; //$NON-NLS-1$


http://gerrit.ovirt.org/#/c/27781/2/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/TabName.java
File 
frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/TabName.java:

Line 2: 
Line 3: /**
Line 4:  * All classes implementing {@code HasValidatedTabs} should create an 
enum that implements this interface.
Line 5:  */
Line 6: public interface TabName {
Hm, I don't see any getValue method here so I assume the comparison between 
TabName instances is done simply via reference comparison, relying on the fact 
that enum instances are singletons.

I understand that adding some getValue method here would complicate usage of 
this interface, but please consider updating Javadoc according to my assumption 
above (if it's correct, that is).


http://gerrit.ovirt.org/#/c/27781/2/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/clusters/ClusterModel.java
File 
frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/clusters/ClusterModel.java:

Line 58:     }
Line 59: 
Line 60:     private Map<Guid, PolicyUnit> policyUnitMap;
Line 61:     private ListModel<ClusterPolicy> clusterPolicy;
Line 62:     private final Set<TabName> invalidTabs = new HashSet<TabName>();
Can't we make this protected final field in some model superclass, so that we 
don't have to declare it within each specific model?
Line 63: 
Line 64:     public ListModel<ClusterPolicy> getClusterPolicy() {
Line 65:         return clusterPolicy;
Line 66:     }


Line 562:     public void setSerialNumberPolicy(SerialNumberPolicyModel 
serialNumberPolicy) {
Line 563:         this.serialNumberPolicy = serialNumberPolicy;
Line 564:     }
Line 565: 
Line 566:     public boolean getIsGeneralTabValid()
I _strongly_ suggest to do "round two" refactoring, where we get rid of methods 
like get/setIsXxxTabValid, replacing them with get/setIsTabValid(TabName tab) 
method.

In turn, this will simplify GWT code which uses such "IsTabValid" methods.
Line 567:     {
Line 568:         return !invalidTabs.contains(ClusterTabNames.GENERAL_TAB);
Line 569:     }
Line 570: 


Line 1654: 
Line 1655:     }
Line 1656: 
Line 1657:     @Override
Line 1658:     public Set<TabName> getInvalidTabs() {
Please see my comment above, this could be moved to some model superclass as 
well.
Line 1659:         return invalidTabs;
Line 1660:     }


http://gerrit.ovirt.org/#/c/27781/2/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/hosts/HostModel.java
File 
frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/hosts/HostModel.java:

Line 57: 
Line 58: public abstract class HostModel extends Model implements 
HasValidatedTabs
Line 59: {
Line 60:     public enum HostTabNames implements TabName {
Line 61:         GENERAL_TAB, POWER_MANAGEMENT_TAB, SPM_TAB, CONSOLE_TAB, 
NETWORK_PROVIDER_TAB
> Maybe consolidate this enum in an external enum for all the models. There s
It is possible, but I'm OK with current approach as well. It's up to you :-)
Line 62:     }
Line 63: 
Line 64:     public static final int HostNameMaxLength = 255;
Line 65:     public static final String PmSecureKey = "secure"; //$NON-NLS-1$


http://gerrit.ovirt.org/#/c/27781/2/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/vms/UnitVmModel.java
File 
frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/vms/UnitVmModel.java:

Line 350:             onPropertyChanged(new 
PropertyChangedEventArgs("IsCPUsAmountValid")); //$NON-NLS-1$
Line 351:         }
Line 352:     }
Line 353: 
Line 354:     public boolean getIsGeneralTabValid() {
Hm, we could really get rid of all those get/setIsXxxTabValid methods in some 
"round two" refactoring :-)
Line 355:         return !invalidTabs.contains(UnitVmTabNames.GENERAL_TAB);
Line 356:     }
Line 357: 
Line 358:     public void setIsGeneralTabValid(boolean value) {


http://gerrit.ovirt.org/#/c/27781/2/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/popup/host/HostPopupView.java
File 
frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/popup/host/HostPopupView.java:

Line 594
Line 595
Line 596
Line 597
Line 598
Excellent! I love to see such code removed (and I think it was me who wrote it) 
:-)


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

Gerrit-MessageType: comment
Gerrit-Change-Id: I2e9c5ad0cd3ee7f54606958b1fc8abd2bbd972ed
Gerrit-PatchSet: 2
Gerrit-Project: ovirt-engine
Gerrit-Branch: master
Gerrit-Owner: Alexander Wels <aw...@redhat.com>
Gerrit-Reviewer: Alexander Wels <aw...@redhat.com>
Gerrit-Reviewer: Einav Cohen <eco...@redhat.com>
Gerrit-Reviewer: Greg Sheremeta <gsher...@redhat.com>
Gerrit-Reviewer: Vojtech Szocs <vsz...@redhat.com>
Gerrit-Reviewer: automat...@ovirt.org
Gerrit-Reviewer: oVirt Jenkins CI Server
Gerrit-HasComments: Yes
_______________________________________________
Engine-patches mailing list
Engine-patches@ovirt.org
http://lists.ovirt.org/mailman/listinfo/engine-patches

Reply via email to