ErrorConsoleView.java revision bff2d603c022691237c31d9a57ad8c217c6e7e11
1/* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.browser; 18 19import android.content.Context; 20import android.database.DataSetObserver; 21import android.util.AttributeSet; 22import android.view.LayoutInflater; 23import android.view.View; 24import android.view.ViewGroup; 25import android.view.View.OnClickListener; 26import android.webkit.WebView; 27import android.widget.Button; 28import android.widget.EditText; 29import android.widget.LinearLayout; 30import android.widget.ListView; 31import android.widget.TextView; 32import android.widget.TwoLineListItem; 33 34import java.util.Vector; 35 36/* package */ class ErrorConsoleView extends LinearLayout { 37 38 /** 39 * Define some constants to describe the visibility of the error console. 40 */ 41 public static final int SHOW_MINIMIZED = 0; 42 public static final int SHOW_MAXIMIZED = 1; 43 public static final int SHOW_NONE = 2; 44 45 private TextView mConsoleHeader; 46 private ErrorConsoleListView mErrorList; 47 private LinearLayout mEvalJsViewGroup; 48 private EditText mEvalEditText; 49 private Button mEvalButton; 50 private WebView mWebView; 51 private int mCurrentShowState = SHOW_NONE; 52 53 private boolean mSetupComplete = false; 54 55 // Before we've been asked to display the console, cache any messages that should 56 // be added to the console. Then when we do display the console, add them to the view 57 // then. 58 private Vector<ErrorConsoleMessage> mErrorMessageCache; 59 60 public ErrorConsoleView(Context context) { 61 super(context); 62 } 63 64 public ErrorConsoleView(Context context, AttributeSet attributes) { 65 super(context, attributes); 66 } 67 68 private void commonSetupIfNeeded() { 69 if (mSetupComplete) { 70 return; 71 } 72 73 LayoutInflater inflater = (LayoutInflater) getContext().getSystemService( 74 Context.LAYOUT_INFLATER_SERVICE); 75 inflater.inflate(R.layout.error_console, this); 76 77 // Get references to each ui element. 78 mConsoleHeader = (TextView) findViewById(R.id.error_console_header_id); 79 mErrorList = (ErrorConsoleListView) findViewById(R.id.error_console_list_id); 80 mEvalJsViewGroup = (LinearLayout) findViewById(R.id.error_console_eval_view_group_id); 81 mEvalEditText = (EditText) findViewById(R.id.error_console_eval_text_id); 82 mEvalButton = (Button) findViewById(R.id.error_console_eval_button_id); 83 84 mEvalButton.setOnClickListener(new OnClickListener() { 85 public void onClick(View v) { 86 // Send the javascript to be evaluated to webkit as a javascript: url 87 // TODO: Can we expose access to webkit's JS interpreter here and evaluate it that 88 // way? Note that this is called on the UI thread so we will need to post a message 89 // to the WebCore thread to implement this. 90 if (mWebView != null) { 91 mWebView.loadUrl("javascript:" + mEvalEditText.getText()); 92 } 93 94 mEvalEditText.setText(""); 95 } 96 }); 97 98 // Make clicking on the console title bar min/maximse it. 99 mConsoleHeader.setOnClickListener(new OnClickListener() { 100 public void onClick(View v) { 101 if (mCurrentShowState == SHOW_MINIMIZED) { 102 showConsole(SHOW_MAXIMIZED); 103 } else { 104 showConsole(SHOW_MINIMIZED); 105 } 106 } 107 }); 108 109 // Add any cached messages to the list now that we've assembled the view. 110 if (mErrorMessageCache != null) { 111 for (ErrorConsoleMessage msg : mErrorMessageCache) { 112 mErrorList.addErrorMessage(msg.getMessage(), msg.getSourceID(), msg.getLineNumber()); 113 } 114 mErrorMessageCache.clear(); 115 } 116 117 mSetupComplete = true; 118 } 119 120 /** 121 * Adds a message to the set of messages the console uses. 122 */ 123 public void addErrorMessage(String msg, String sourceId, int lineNumber) { 124 if (mSetupComplete) { 125 mErrorList.addErrorMessage(msg, sourceId, lineNumber); 126 } else { 127 if (mErrorMessageCache == null) { 128 mErrorMessageCache = new Vector<ErrorConsoleMessage>(); 129 } 130 mErrorMessageCache.add(new ErrorConsoleMessage(msg, sourceId, lineNumber)); 131 } 132 } 133 134 /** 135 * Removes all error messages from the console. 136 */ 137 public void clearErrorMessages() { 138 if (mSetupComplete) { 139 mErrorList.clearErrorMessages(); 140 } else if (mErrorMessageCache != null) { 141 mErrorMessageCache.clear(); 142 } 143 } 144 145 /** 146 * Returns the current number of errors displayed in the console. 147 */ 148 public int numberOfErrors() { 149 if (mSetupComplete) { 150 return mErrorList.getCount(); 151 } else { 152 return (mErrorMessageCache == null) ? 0 : mErrorMessageCache.size(); 153 } 154 } 155 156 /** 157 * Sets the webview that this console is associated with. Currently this is used so 158 * we can call into webkit to evaluate JS expressions in the console. 159 */ 160 public void setWebView(WebView webview) { 161 mWebView = webview; 162 } 163 164 /** 165 * Sets the visibility state of the console. 166 */ 167 public void showConsole(int show_state) { 168 commonSetupIfNeeded(); 169 switch (show_state) { 170 case SHOW_MINIMIZED: 171 mConsoleHeader.setVisibility(View.VISIBLE); 172 mConsoleHeader.setText(R.string.error_console_header_text_minimized); 173 mErrorList.setVisibility(View.GONE); 174 mEvalJsViewGroup.setVisibility(View.GONE); 175 break; 176 177 case SHOW_MAXIMIZED: 178 mConsoleHeader.setVisibility(View.VISIBLE); 179 mConsoleHeader.setText(R.string.error_console_header_text_maximized); 180 mErrorList.setVisibility(View.VISIBLE); 181 mEvalJsViewGroup.setVisibility(View.VISIBLE); 182 break; 183 184 case SHOW_NONE: 185 mConsoleHeader.setVisibility(View.GONE); 186 mErrorList.setVisibility(View.GONE); 187 mEvalJsViewGroup.setVisibility(View.GONE); 188 break; 189 } 190 mCurrentShowState = show_state; 191 } 192 193 /** 194 * Returns the current visibility state of the console. 195 */ 196 public int getShowState() { 197 if (mSetupComplete) { 198 return mCurrentShowState; 199 } else { 200 return SHOW_NONE; 201 } 202 } 203 204 /** 205 * This class extends ListView to implement the View that will actually display the set of 206 * errors encountered on the current page. 207 */ 208 private static class ErrorConsoleListView extends ListView { 209 // An adapter for this View that contains a list of error messages. 210 private ErrorConsoleMessageList mConsoleMessages; 211 212 public ErrorConsoleListView(Context context, AttributeSet attributes) { 213 super(context, attributes); 214 mConsoleMessages = new ErrorConsoleMessageList(context); 215 setAdapter(mConsoleMessages); 216 } 217 218 public void addErrorMessage(String msg, String sourceId, int lineNumber) { 219 mConsoleMessages.add(msg, sourceId, lineNumber); 220 setSelection(mConsoleMessages.getCount()); 221 } 222 223 public void clearErrorMessages() { 224 mConsoleMessages.clear(); 225 } 226 227 /** 228 * This class is an adapter for ErrorConsoleListView that contains the error console 229 * message data. 230 */ 231 private class ErrorConsoleMessageList extends android.widget.BaseAdapter 232 implements android.widget.ListAdapter { 233 234 private Vector<ErrorConsoleMessage> mMessages; 235 private LayoutInflater mInflater; 236 237 public ErrorConsoleMessageList(Context context) { 238 mMessages = new Vector<ErrorConsoleMessage>(); 239 mInflater = (LayoutInflater)context.getSystemService( 240 Context.LAYOUT_INFLATER_SERVICE); 241 } 242 243 /** 244 * Add a new message to the list and update the View. 245 */ 246 public void add(String msg, String sourceID, int lineNumber) { 247 mMessages.add(new ErrorConsoleMessage(msg, sourceID, lineNumber)); 248 notifyDataSetChanged(); 249 } 250 251 /** 252 * Remove all messages from the list and update the view. 253 */ 254 public void clear() { 255 mMessages.clear(); 256 notifyDataSetChanged(); 257 } 258 259 @Override 260 public boolean areAllItemsEnabled() { 261 return false; 262 } 263 264 @Override 265 public boolean isEnabled(int position) { 266 return false; 267 } 268 269 public long getItemId(int position) { 270 return position; 271 } 272 273 public Object getItem(int position) { 274 return mMessages.get(position); 275 } 276 277 public int getCount() { 278 return mMessages.size(); 279 } 280 281 @Override 282 public boolean hasStableIds() { 283 return true; 284 } 285 286 /** 287 * Constructs a TwoLineListItem for the error at position. 288 */ 289 public View getView(int position, View convertView, ViewGroup parent) { 290 View view; 291 ErrorConsoleMessage error = mMessages.get(position); 292 293 if (error == null) { 294 return null; 295 } 296 297 if (convertView == null) { 298 view = mInflater.inflate(android.R.layout.two_line_list_item, parent, false); 299 } else { 300 view = convertView; 301 } 302 303 TextView headline = (TextView) view.findViewById(android.R.id.text1); 304 TextView subText = (TextView) view.findViewById(android.R.id.text2); 305 headline.setText(error.getSourceID() + ":" + error.getLineNumber()); 306 subText.setText(error.getMessage()); 307 return view; 308 } 309 310 } 311 } 312 313 /** 314 * This class holds the data for a single error message in the console. 315 */ 316 private static class ErrorConsoleMessage { 317 private String mMessage; 318 private String mSourceID; 319 private int mLineNumber; 320 321 public ErrorConsoleMessage(String msg, String sourceID, int lineNumber) { 322 mMessage = msg; 323 mSourceID = sourceID; 324 mLineNumber = lineNumber; 325 } 326 327 public String getMessage() { 328 return mMessage; 329 } 330 331 public String getSourceID() { 332 return mSourceID; 333 } 334 335 public int getLineNumber() { 336 return mLineNumber; 337 } 338 } 339} 340