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 }