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.widgets;
021    
022    import com.google.gwt.core.client.JavaScriptObject;
023    import com.google.gwt.user.client.ui.Composite;
024    import com.google.gwt.user.client.ui.HTML;
025    import com.google.gwt.user.client.ui.Panel;
026    import com.google.gwt.user.client.ui.VerticalPanel;
027    import com.google.gwt.widgetideas.table.client.PreloadedTable;
028    import org.sonar.api.web.gwt.client.webservices.BaseQueryCallback;
029    import org.sonar.api.web.gwt.client.webservices.FileSource;
030    import org.sonar.api.web.gwt.client.webservices.Resource;
031    import org.sonar.api.web.gwt.client.webservices.SourcesQuery;
032    
033    import java.util.Arrays;
034    import java.util.List;
035    import java.util.Map;
036    
037    public abstract class AbstractSourcePanel extends Composite {
038    
039      private final Panel panel = new VerticalPanel();
040      private FileSource sourceLines;
041      private final LoadingLabel loading = new LoadingLabel();
042      private int from = 0;
043      private int length = 0;
044    
045      private boolean started = false;
046      private Resource resource;
047      private boolean hasNoSources = false;
048    
049      public AbstractSourcePanel(Resource resource) {
050        this(resource, 0, 0);
051      }
052    
053      public Resource getResource() {
054        return resource;
055      }
056    
057      public AbstractSourcePanel(Resource resource, int from, int length) {
058        this.from = from;
059        this.length = length;
060        this.resource = resource;
061    
062        panel.add(loading);
063        panel.getElement().setId("sourcePanel");
064        initWidget(panel);
065        setStyleName("gwt-SourcePanel");
066    
067        loadSources();
068      }
069    
070      private void loadSources() {
071        SourcesQuery.get(resource.getId().toString())
072            .setFrom(from)
073            .setLength(length)
074            .execute(new BaseQueryCallback<FileSource>(loading) {
075              public void onResponse(FileSource response, JavaScriptObject jsonResponse) {
076                sourceLines = response;
077                decorate();
078              }
079    
080              @Override
081              public void onError(int errorCode, String errorMessage) {
082                if (errorCode == 404) {
083                  panel.add(new HTML("No sources"));
084                  hasNoSources = true;
085                  loading.removeFromParent();
086                } else {
087                  super.onError(errorCode, errorMessage);
088                }
089              }
090            });
091      }
092    
093      protected void setStarted() {
094        started = true;
095        decorate();
096      }
097    
098      public void refresh() {
099        if (!hasNoSources) {
100          panel.clear();
101          panel.add(loading);
102          decorate();
103        }
104      }
105    
106      private void decorate() {
107        if (started && sourceLines != null) {
108          PreloadedTable table = new PreloadedTable();
109          table.setStyleName("sources");
110    
111          int rowIndex = 0;
112          if (shouldDecorateLine(0)) {
113            List<Row> rows = decorateLine(0, null);
114            if (rows != null) {
115              for (Row row : rows) {
116                table.setPendingHTML(rowIndex, 0, row.getColumn1());
117                table.setPendingHTML(rowIndex, 1, row.getColumn2());
118                table.setPendingHTML(rowIndex, 2, row.getColumn3());
119                table.setPendingHTML(rowIndex, 3, row.getColumn4());
120                rowIndex++;
121              }
122            }
123          }
124    
125          Map<Integer, String> lines = sourceLines.getLines();
126          boolean previousLineIsDecorated = true;
127          boolean firstDecoratedLine = true;
128          for (Map.Entry<Integer, String> entry : lines.entrySet()) {
129            Integer lineIndex = entry.getKey();
130            if (shouldDecorateLine(lineIndex)) {
131              if (!previousLineIsDecorated && !firstDecoratedLine) {
132                table.setPendingHTML(rowIndex, 0, "<div class='src' style='background-color: #fff;height: 3em; border-top: 1px dashed silver;border-bottom: 1px dashed silver;'> </div>");
133                table.setPendingHTML(rowIndex, 1, " ");
134                table.setPendingHTML(rowIndex, 2, " ");
135                table.setPendingHTML(rowIndex, 3, "<div class='src' style='background-color: #fff;height: 3em; border-top: 1px dashed silver;border-bottom: 1px dashed silver;'> </div>");
136                rowIndex++;
137              }
138    
139              List<Row> rows = decorateLine(lineIndex, entry.getValue());
140              if (rows != null) {
141                for (Row row : rows) {
142                  table.setPendingHTML(rowIndex, 0, row.getColumn1());
143                  table.setPendingHTML(rowIndex, 1, row.getColumn2());
144                  table.setPendingHTML(rowIndex, 2, row.getColumn3());
145                  table.setPendingHTML(rowIndex, 3, row.getColumn4());
146                  rowIndex++;
147                }
148                previousLineIsDecorated = true;
149                firstDecoratedLine = false;
150              }
151    
152            } else {
153              previousLineIsDecorated = false;
154            }
155          }
156          panel.clear();
157          panel.add(table);
158        }
159      }
160    
161      protected boolean shouldDecorateLine(int index) {
162        return true;
163      }
164    
165      protected List<Row> decorateLine(int index, String source) {
166        if (index > 0) {
167          return Arrays.asList(new Row(index, source));
168        }
169        return null;
170      }
171    
172      public static class Row {
173        protected String column1;
174        protected String column2;
175        protected String column3;
176        protected String column4;
177    
178        public Row(String column1, String column2, String column3) {
179          this.column1 = column1;
180          this.column2 = column2;
181          this.column3 = column3;
182          this.column4 = "";
183        }
184    
185        public Row(String column1, String column2, String column3, String column4) {
186          this.column1 = column1;
187          this.column2 = column2;
188          this.column3 = column3;
189          this.column4 = column4;
190        }
191    
192        public Row(int lineIndex, String source) {
193          setLineIndex(lineIndex, "");
194          unsetValue();
195          setSource(source, "");
196        }
197    
198        public Row() {
199        }
200    
201        public Row setLineIndex(int index, String style) {
202          column1 = "<div class='ln " + style + "'>" + index + "</div>";
203          return this;
204        }
205    
206        public Row setValue(String value, String style) {
207          column2 = "<div class='val " + style + "'>" + value + "</div>";
208          return this;
209        }
210    
211        public Row setValue2(String value, String style) {
212          column3 = "<div class='val " + style + "'>" + value + "</div>";
213          return this;
214        }
215    
216        public Row unsetValue() {
217          column2 = "";
218          column3 = "";
219          return this;
220        }
221    
222        public Row setSource(String source, String style) {
223          column4 = "<div class='src " + style + "'><pre>" + source + "</pre></div>";
224          return this;
225        }
226    
227        public String getColumn1() {
228          return column1;
229        }
230    
231        public void setColumn1(String column1) {
232          this.column1 = column1;
233        }
234    
235        public String getColumn2() {
236          return column2;
237        }
238    
239        public void setColumn2(String column2) {
240          this.column2 = column2;
241        }
242    
243        public String getColumn3() {
244          return column3;
245        }
246    
247        public void setColumn3(String column3) {
248          this.column3 = column3;
249        }
250    
251        public String getColumn4() {
252          return column4;
253        }
254    
255        public void setColumn4(String column4) {
256          this.column4 = column4;
257        }
258      }
259    }