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