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 .setColor(true) 075 .execute(new BaseQueryCallback<FileSource>(loading) { 076 public void onResponse(FileSource response, JavaScriptObject jsonResponse) { 077 sourceLines = response; 078 decorate(); 079 } 080 081 @Override 082 public void onError(int errorCode, String errorMessage) { 083 if (errorCode == 404) { 084 panel.add(new HTML("<p style=\"padding: 5px\">No sources</p>")); 085 hasNoSources = true; 086 loading.removeFromParent(); 087 } else if (errorCode == 401) { 088 panel.add(new HTML("<p style=\"padding: 5px\">You're not authorized to view source code</p>")); 089 hasNoSources = true; 090 loading.removeFromParent(); 091 } else { 092 super.onError(errorCode, errorMessage); 093 } 094 } 095 }); 096 } 097 098 protected void setStarted() { 099 started = true; 100 decorate(); 101 } 102 103 public void refresh() { 104 if (!hasNoSources) { 105 panel.clear(); 106 panel.add(loading); 107 decorate(); 108 } 109 } 110 111 private void decorate() { 112 if (started && sourceLines != null) { 113 PreloadedTable table = new PreloadedTable(); 114 table.setStyleName("sources code"); 115 116 int rowIndex = 0; 117 if (shouldDecorateLine(0)) { 118 List<Row> rows = decorateLine(0, null); 119 if (rows != null) { 120 for (Row row : rows) { 121 table.setPendingHTML(rowIndex, 0, row.getColumn1()); 122 table.setPendingHTML(rowIndex, 1, row.getColumn2()); 123 table.setPendingHTML(rowIndex, 2, row.getColumn3()); 124 table.setPendingHTML(rowIndex, 3, row.getColumn4()); 125 rowIndex++; 126 } 127 } 128 } 129 130 Map<Integer, String> lines = sourceLines.getLines(); 131 boolean previousLineIsDecorated = true; 132 boolean firstDecoratedLine = true; 133 for (Map.Entry<Integer, String> entry : lines.entrySet()) { 134 Integer lineIndex = entry.getKey(); 135 if (shouldDecorateLine(lineIndex)) { 136 if (!previousLineIsDecorated && !firstDecoratedLine) { 137 table.setPendingHTML(rowIndex, 0, "<div class='src' style='background-color: #fff;height: 3em; border-top: 1px dashed silver;border-bottom: 1px dashed silver;'> </div>"); 138 table.setPendingHTML(rowIndex, 1, " "); 139 table.setPendingHTML(rowIndex, 2, " "); 140 table.setPendingHTML(rowIndex, 3, "<div class='src' style='background-color: #fff;height: 3em; border-top: 1px dashed silver;border-bottom: 1px dashed silver;'> </div>"); 141 rowIndex++; 142 } 143 144 List<Row> rows = decorateLine(lineIndex, entry.getValue()); 145 if (rows != null) { 146 for (Row row : rows) { 147 table.setPendingHTML(rowIndex, 0, row.getColumn1()); 148 table.setPendingHTML(rowIndex, 1, row.getColumn2()); 149 table.setPendingHTML(rowIndex, 2, row.getColumn3()); 150 table.setPendingHTML(rowIndex, 3, row.getColumn4()); 151 rowIndex++; 152 } 153 previousLineIsDecorated = true; 154 firstDecoratedLine = false; 155 } 156 157 } else { 158 previousLineIsDecorated = false; 159 } 160 } 161 panel.clear(); 162 panel.add(table); 163 } 164 } 165 166 protected boolean shouldDecorateLine(int index) { 167 return true; 168 } 169 170 protected List<Row> decorateLine(int index, String source) { 171 if (index > 0) { 172 return Arrays.asList(new Row(index, source)); 173 } 174 return null; 175 } 176 177 public static class Row { 178 protected String column1; 179 protected String column2; 180 protected String column3; 181 protected String column4; 182 183 public Row(String column1, String column2, String column3) { 184 this.column1 = column1; 185 this.column2 = column2; 186 this.column3 = column3; 187 this.column4 = ""; 188 } 189 190 public Row(String column1, String column2, String column3, String column4) { 191 this.column1 = column1; 192 this.column2 = column2; 193 this.column3 = column3; 194 this.column4 = column4; 195 } 196 197 public Row(int lineIndex, String source) { 198 setLineIndex(lineIndex, ""); 199 unsetValue(); 200 setSource(source, ""); 201 } 202 203 public Row() { 204 } 205 206 public Row setLineIndex(int index, String style) { 207 column1 = "<div class='ln " + style + "'>" + index + "</div>"; 208 return this; 209 } 210 211 public Row setValue(String value, String style) { 212 column2 = "<div class='val " + style + "'>" + value + "</div>"; 213 return this; 214 } 215 216 public Row setValue2(String value, String style) { 217 column3 = "<div class='val " + style + "'>" + value + "</div>"; 218 return this; 219 } 220 221 public Row unsetValue() { 222 column2 = ""; 223 column3 = ""; 224 return this; 225 } 226 227 public Row setSource(String source, String style) { 228 column4 = "<div class='src " + style + "'><pre>" + source + "</pre></div>"; 229 return this; 230 } 231 232 public String getColumn1() { 233 return column1; 234 } 235 236 public void setColumn1(String column1) { 237 this.column1 = column1; 238 } 239 240 public String getColumn2() { 241 return column2; 242 } 243 244 public void setColumn2(String column2) { 245 this.column2 = column2; 246 } 247 248 public String getColumn3() { 249 return column3; 250 } 251 252 public void setColumn3(String column3) { 253 this.column3 = column3; 254 } 255 256 public String getColumn4() { 257 return column4; 258 } 259 260 public void setColumn4(String column4) { 261 this.column4 = column4; 262 } 263 } 264 }