001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.ruby.debugger.model;
043:
044: import java.awt.datatransfer.Transferable;
045: import java.io.IOException;
046: import java.util.List;
047: import java.util.concurrent.CopyOnWriteArrayList;
048: import org.netbeans.modules.ruby.debugger.ContextProviderWrapper;
049: import org.netbeans.modules.ruby.debugger.RubySession;
050: import org.netbeans.spi.debugger.ContextProvider;
051: import org.netbeans.spi.viewmodel.ExtendedNodeModel;
052: import org.netbeans.spi.viewmodel.ModelEvent;
053: import org.netbeans.spi.viewmodel.ModelListener;
054: import org.netbeans.spi.viewmodel.TableModel;
055: import org.netbeans.spi.viewmodel.TreeModel;
056: import org.netbeans.spi.viewmodel.UnknownTypeException;
057: import org.openide.util.NbBundle;
058: import org.openide.util.datatransfer.PasteType;
059: import org.rubyforge.debugcommons.model.RubyValue;
060: import org.rubyforge.debugcommons.model.RubyVariable;
061: import static org.netbeans.spi.debugger.ui.Constants.LOCALS_TO_STRING_COLUMN_ID;
062: import static org.netbeans.spi.debugger.ui.Constants.LOCALS_TYPE_COLUMN_ID;
063: import static org.netbeans.spi.debugger.ui.Constants.LOCALS_VALUE_COLUMN_ID;
064:
065: public class VariablesModel implements TreeModel, ExtendedNodeModel,
066: TableModel {
067:
068: private static final String GLOBAL = "Global Variables"; // NOI18N
069: public static final String LOCAL = "org/netbeans/modules/debugger/resources/localsView/local_variable_16.png"; // NOI18N
070: public static final String CLASS = "org/netbeans/modules/debugger/resources/watchesView/SuperVariable.gif"; // NOI18N
071:
072: protected final RubySession rubySession;
073: protected final List<ModelListener> listeners = new CopyOnWriteArrayList<ModelListener>();
074:
075: public VariablesModel(ContextProvider contextProvider) {
076: this .rubySession = new ContextProviderWrapper(contextProvider)
077: .getRubySession();
078: }
079:
080: // TreeModel implementation ................................................
081:
082: public Object getRoot() {
083: return ROOT;
084: }
085:
086: public Object[] getChildren(Object parent, int from, int to)
087: throws UnknownTypeException {
088: // TODO: why this is called when #getChildrenCount() return 0?
089: if (!rubySession.isSessionSuspended()) {
090: return new Object[0];
091: }
092: if (parent == ROOT) {
093: RubyVariable[] frameVars = rubySession.getVariables();
094: Object[] vars = new Object[frameVars.length + 1]; // 1 - Global Variables node
095: vars[0] = GLOBAL;
096: System.arraycopy(frameVars, 0, vars, 1, frameVars.length);
097: return vars;
098: } else if (parent == GLOBAL) {
099: return rubySession.getGlobalVariables();
100: } else if (parent instanceof RubyVariable) {
101: return rubySession.getChildren((RubyVariable) parent);
102: } else {
103: throw new UnknownTypeException(parent);
104: }
105: }
106:
107: public boolean isLeaf(Object node) throws UnknownTypeException {
108: if (node == ROOT || node == GLOBAL) {
109: return false;
110: } else if (node instanceof RubyVariable) {
111: RubyValue val = ((RubyVariable) node).getValue();
112: return val == null || !val.hasVariables();
113: } else {
114: throw new UnknownTypeException(node);
115: }
116: }
117:
118: public int getChildrenCount(Object parent)
119: throws UnknownTypeException {
120: if (!rubySession.isSessionSuspended()) {
121: return 0;
122: }
123: if (parent == ROOT) {
124: return rubySession.getVariables().length + 1; // 1 - Global Variables node
125: } else if (parent == GLOBAL) {
126: return rubySession.getGlobalVariables().length;
127: } else if (parent instanceof RubyVariable) {
128: return rubySession.getChildren((RubyVariable) parent).length;
129: } else {
130: throw new UnknownTypeException(parent);
131: }
132: }
133:
134: public void addModelListener(ModelListener l) {
135: listeners.add(l);
136: }
137:
138: public void removeModelListener(ModelListener l) {
139: listeners.remove(l);
140: }
141:
142: public void fireChanges() {
143: for (ModelListener listener : listeners) {
144: listener.modelChanged(new ModelEvent.TreeChanged(this ));
145: }
146: }
147:
148: // NodeModel implementation ................................................
149:
150: public String getDisplayName(Object node)
151: throws UnknownTypeException {
152: if (node == ROOT) {
153: return getMessage("CTL_VariablesModel.Column.Name.Name");
154: } else if (node == GLOBAL) {
155: return getMessage("CTL_VariablesModel.Global.Variables");
156: } else if (node instanceof RubyVariable) {
157: String name = ((RubyVariable) node).getName();
158: assert name != null : "null name for the RubyVariable: "
159: + node;
160: return name;
161: } else {
162: assert node != null : "null node passed to VariablesModel.getDisplayName()";
163: throw new UnknownTypeException(node);
164: }
165: }
166:
167: public String getIconBase(Object node) throws UnknownTypeException {
168: throw new UnsupportedOperationException("Not supported yet."); // NOI18N
169: }
170:
171: public String getIconBaseWithExtension(Object node)
172: throws UnknownTypeException {
173: assert node != ROOT;
174: // TODO use different icons
175: if (node == GLOBAL) {
176: return CLASS;
177: } else if (node instanceof RubyVariable) {
178: if (((RubyVariable) node).isClass()) {
179: return CLASS;
180: } else {
181: return LOCAL;
182: }
183: } else {
184: throw new UnknownTypeException(node);
185: }
186: }
187:
188: public String getShortDescription(Object node)
189: throws UnknownTypeException {
190: if (node == GLOBAL) {
191: return getMessage("CTL_VariablesModel.Global.Variables.Short.Description");
192: } else if (node == ROOT) {
193: return getMessage("CTL_VariablesModel.Column.Name.Desc");
194: } else if (node instanceof RubyVariable) {
195: RubyValue value = ((RubyVariable) node).getValue();
196: return '(' + value.getReferenceTypeName() + ") "
197: + value.getValueString(); // NOI18N
198: } else {
199: throw new UnknownTypeException(node);
200: }
201: }
202:
203: // TableModel implementation ...............................................
204:
205: public Object getValueAt(Object node, String columnID)
206: throws UnknownTypeException {
207: if (node == GLOBAL) {
208: return "";
209: } else if (node instanceof RubyVariable) {
210: RubyVariable var = (RubyVariable) node;
211: if (var.getValue() == null) {
212: return "<nil>"; // NOI18N
213: } else if (LOCALS_VALUE_COLUMN_ID.equals(columnID)
214: || LOCALS_TO_STRING_COLUMN_ID.equals(columnID)) {
215: return var.getValue().getValueString();
216: } else if (LOCALS_TYPE_COLUMN_ID.equals(columnID)) {
217: return var.getValue().getReferenceTypeName();
218: }
219: }
220: throw new UnknownTypeException(node);
221: }
222:
223: public boolean isReadOnly(Object node, String columnID)
224: throws UnknownTypeException {
225: return true;
226: }
227:
228: public void setValueAt(Object node, String columnID, Object value)
229: throws UnknownTypeException {
230: throw new UnknownTypeException(node);
231: }
232:
233: public boolean canRename(Object node) throws UnknownTypeException {
234: return false;
235: }
236:
237: public boolean canCopy(Object node) throws UnknownTypeException {
238: return false;
239: }
240:
241: public boolean canCut(Object node) throws UnknownTypeException {
242: return false;
243: }
244:
245: public Transferable clipboardCopy(Object node) throws IOException,
246: UnknownTypeException {
247: throw new UnsupportedOperationException("Not supported yet."); // NOI18N
248: }
249:
250: public Transferable clipboardCut(Object node) throws IOException,
251: UnknownTypeException {
252: throw new UnsupportedOperationException("Not supported yet."); // NOI18N
253: }
254:
255: public PasteType[] getPasteTypes(Object node, Transferable t)
256: throws UnknownTypeException {
257: return null;
258: }
259:
260: public void setName(Object node, String name)
261: throws UnknownTypeException {
262: throw new UnsupportedOperationException("Not supported yet."); // NOI18N
263: }
264:
265: private static String getMessage(final String key) {
266: return NbBundle.getMessage(VariablesModel.class, key);
267: }
268: }
|