001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2009 SonarSource SA
004     * mailto:contact AT sonarsource DOT com
005     *
006     * Sonar is free software; you can redistribute it and/or
007     * modify it under the terms of the GNU Lesser General Public
008     * License as published by the Free Software Foundation; either
009     * version 3 of the License, or (at your option) any later version.
010     *
011     * Sonar is distributed in the hope that it will be useful,
012     * but WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014     * Lesser General Public License for more details.
015     *
016     * You should have received a copy of the GNU Lesser General Public
017     * License along with Sonar; if not, write to the Free Software
018     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
019     */
020    package org.sonar.api.web.gwt.client;
021    
022    import com.google.gwt.core.client.EntryPoint;
023    import com.google.gwt.core.client.JavaScriptObject;
024    import com.google.gwt.user.client.ui.FlowPanel;
025    import com.google.gwt.user.client.ui.Panel;
026    import com.google.gwt.user.client.ui.RootPanel;
027    import com.google.gwt.user.client.ui.Widget;
028    import org.sonar.api.web.gwt.client.webservices.*;
029    
030    import java.util.Arrays;
031    
032    public abstract class AbstractViewer implements EntryPoint {
033    
034      public static final String HTML_ROOT_ID = "resource_viewers";
035    
036      private Resource resource;
037      private String renderedResourceKey = "";
038      private Panel widgetPanel = null;
039      private boolean standAloneMode = true;
040    
041      public void onModuleLoad() {
042        exportJavascript();
043      }
044    
045      /**
046       * Export GWT javascript methods to load and control the plugin, must export currently 2 method :
047       * I.E for plugin GWT id : foo.bar.MyPlugin, class foo.bar.client.MyPlugin :
048       * <p/>
049       * $wnd.load_foo_bar_MyPlugin = function() {
050       * called to the plugin init from JS
051       * obj.@foo.bar.client.MyPlugin::loadContainer()();
052       * }
053       * $wnd.on_resource_loaded_foo_bar_MyPlugin = function() {
054       * called when a resource JSON object has been refreshed within the page
055       * obj.@foo.bar.client.MyPlugin::onResourceLoaded()();
056       * }
057       */
058      protected abstract void exportJavascript();
059    
060      /**
061       * When multiple widgets are bound to the same HTML div, this method will indicate
062       * If the resource widget is the default one to show when the widget is initialized
063       *
064       * @param metric   the metric for which the widget is shown, cannot be null
065       * @param resource the resource bound to the widget
066       * @return true or false
067       */
068      protected abstract boolean isDefault(WSMetrics.Metric metric, Resource resource);
069    
070      /**
071       * Finds if a given metric is in the provided metrics list
072       *
073       * @param metric      the metric to search
074       * @param metricsList the metric list
075       * @return true or false if not found
076       */
077      protected boolean isMetricInList(WSMetrics.Metric metric, WSMetrics.Metric... metricsList) {
078        return Arrays.asList(metricsList).contains(metric);
079      }
080    
081      /**
082       * When multiple widgets are in the same page, this method will indicate if the widget
083       * can be shown for the given resource
084       *
085       * @param resource the resource bound to the page
086       * @return true or false
087       */
088      protected abstract boolean isForResource(Resource resource);
089    
090    
091      public Resource getResource() {
092        return resource;
093      }
094    
095      private Resource loadResource() {
096        JavaScriptObject resourceJson = getResourceJSONObject();
097        if (resourceJson != null) {
098          Resource resourceLoaded = ResourcesQuery.parseResources(resourceJson).get(0);
099          String currentMetricKey = ResourceDictionary.getViewerMetricKey();
100          Boolean isDefaultForMetric = false;
101          if (currentMetricKey != null) {
102            isDefaultForMetric = isDefault(WSMetrics.get(currentMetricKey), resourceLoaded);
103          }
104          exportJSBooleanVariable("is_default_for_metric", Utils.widgetGWTIdJSEncode(getGwtId()), isDefaultForMetric);
105          exportJSBooleanVariable("is_for_resource", Utils.widgetGWTIdJSEncode(getGwtId()), isForResource(resourceLoaded));
106          return resourceLoaded;
107        }
108        return null;
109      }
110    
111      /**
112       * Called when a resource JSON object has been loaded within the page
113       */
114      public final void onResourceLoaded() {
115        resource = loadResource();
116        standAloneMode = false;
117      }
118    
119      /**
120       * Called to render the widget for the given resource object loaded via the onResourceLoaded() method call
121       */
122      public final void loadContainer() {
123        String resourceKey = ResourceDictionary.getViewerResourceKey();
124        if (resourceKey != null) {
125          if (!standAloneMode && resource == null) {
126            Utils.showError("Unable to find JSON resource object, unable to render widget");
127            return;
128          } else if (standAloneMode && resource == null) {
129            getResourceJsonObject(resourceKey);
130            return;
131          }
132          String currentResourceKey = isANumber(resourceKey) ? resource.getId().toString() : resource.getKey();
133          if (!renderedResourceKey.equals(currentResourceKey)) {
134            // resource key has changed reload if not in standalone mode
135            if (!standAloneMode) {
136              resource = loadResource();
137            }
138    
139            if (widgetPanel == null) {
140              RootPanel rootPanel = RootPanel.get(HTML_ROOT_ID);
141              if (rootPanel == null) {
142                Utils.showError("Unable to find root panel " + HTML_ROOT_ID + " in page");
143              }
144              widgetPanel = new FlowPanel();
145              widgetPanel.setStyleName("gwt-ResourceTab");
146              String panelId = "tab-" + Utils.widgetGWTIdJSEncode(getGwtId());
147              widgetPanel.getElement().setId(panelId);
148              registerTab(panelId);
149              widgetPanel.setVisible(false);
150              rootPanel.add(widgetPanel);
151            }
152    
153            renderedResourceKey = resourceKey;
154    
155            if (widgetPanel != null) {
156              widgetPanel.clear();
157              widgetPanel.add(render(resource));
158            }
159          }
160        }
161    
162        if (widgetPanel != null) {
163          widgetPanel.setVisible(true);
164        }
165      }
166    
167      private static native void registerTab(Object tabId) /*-{
168        $wnd.registeredTabs.push(tabId);
169      }-*/;
170    
171    
172      private native void exportJSBooleanVariable(String varPrefix, String encodedGWTId, boolean value)/*-{
173        $wnd.config[varPrefix + "_" + encodedGWTId] = value;
174      }-*/;
175    
176      /**
177       * Return the GWT id of the widget
178       */
179      protected abstract String getGwtId();
180    
181      /**
182       * Renders the widget for the current resource
183       */
184      protected abstract Widget render(Resource resource);
185    
186      /**
187       * Return a JavaScriptObject object containing all the measure available for the current resource key
188       *
189       * @return the JavaScriptObject instance, should never be null
190       */
191      protected native JavaScriptObject getResourceJSONObject()/*-{
192        return $wnd.config['current_resource'];
193      }-*/;
194    
195    
196      private boolean isANumber(String resourceKey) {
197        boolean isIdResourceKey = true;
198        try {
199          Integer.parseInt(resourceKey);
200        } catch (NumberFormatException ex) {
201          isIdResourceKey = false;
202        }
203        return isIdResourceKey;
204      }
205    
206      private void getResourceJsonObject(String resourceKey) {
207        ResourcesQuery.get(resourceKey).execute(new StandAloneResourceHandler());
208      }
209    
210      public class StandAloneResourceHandler extends BaseQueryCallback<Resources> {
211        public void onResponse(Resources resources, JavaScriptObject jsonResponse) {
212          resource = resources.firstResource();
213          loadContainer();
214        }
215      }
216    }