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