2 * Copyright 2000-2009 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com
.intellij
.xdebugger
.impl
.frame
;
18 import com
.intellij
.openapi
.Disposable
;
19 import com
.intellij
.openapi
.application
.ApplicationManager
;
20 import com
.intellij
.ui
.ScrollPaneFactory
;
21 import com
.intellij
.util
.containers
.HashMap
;
22 import com
.intellij
.xdebugger
.XDebugSession
;
23 import com
.intellij
.xdebugger
.frame
.XExecutionStack
;
24 import com
.intellij
.xdebugger
.frame
.XStackFrame
;
25 import com
.intellij
.xdebugger
.frame
.XSuspendContext
;
26 import org
.jetbrains
.annotations
.NotNull
;
29 import javax
.swing
.event
.ListSelectionEvent
;
30 import javax
.swing
.event
.ListSelectionListener
;
32 import java
.awt
.event
.ItemEvent
;
33 import java
.awt
.event
.ItemListener
;
34 import java
.awt
.event
.MouseAdapter
;
35 import java
.awt
.event
.MouseEvent
;
36 import java
.util
.ArrayList
;
37 import java
.util
.Collections
;
38 import java
.util
.List
;
44 public class XFramesView
extends XDebugViewBase
{
45 private final JPanel myMainPanel
;
46 private final XDebuggerFramesList myFramesList
;
47 private final JComboBox myThreadComboBox
;
48 private XExecutionStack mySelectedStack
;
49 private boolean myListenersEnabled
;
50 private final Map
<XExecutionStack
, StackFramesListBuilder
> myBuilders
= new HashMap
<XExecutionStack
, StackFramesListBuilder
>();
52 public XFramesView(final XDebugSession session
, final Disposable parentDisposable
) {
53 super(session
, parentDisposable
);
55 myMainPanel
= new JPanel(new BorderLayout());
57 myThreadComboBox
= new JComboBox();
58 myThreadComboBox
.setRenderer(new ThreadComboBoxRenderer());
59 myThreadComboBox
.addItemListener(new MyItemListener());
60 myMainPanel
.add(myThreadComboBox
, BorderLayout
.NORTH
);
62 myFramesList
= new XDebuggerFramesList();
63 myFramesList
.addListSelectionListener(new ListSelectionListener() {
64 public void valueChanged(final ListSelectionEvent e
) {
65 if (e
.getValueIsAdjusting()) return;
66 processFrameSelection();
69 myFramesList
.addMouseListener(new MouseAdapter() {
71 public void mousePressed(final MouseEvent e
) {
72 int i
= myFramesList
.locationToIndex(e
.getPoint());
73 if (i
!= -1 && myFramesList
.isSelectedIndex(i
)) {
74 processFrameSelection();
78 myMainPanel
.add(ScrollPaneFactory
.createScrollPane(myFramesList
), BorderLayout
.CENTER
);
79 rebuildView(SessionEvent
.RESUMED
);
82 private StackFramesListBuilder
getOrCreateBuilder(XExecutionStack executionStack
) {
83 StackFramesListBuilder builder
= myBuilders
.get(executionStack
);
84 if (builder
== null) {
85 builder
= new StackFramesListBuilder(executionStack
);
86 myBuilders
.put(executionStack
, builder
);
91 protected void rebuildView(final SessionEvent event
) {
92 if (event
== SessionEvent
.BEFORE_RESUME
) return;
93 if (event
== SessionEvent
.FRAME_CHANGED
) {
94 XStackFrame currentStackFrame
= mySession
.getCurrentStackFrame();
95 if (currentStackFrame
!= null) {
96 myFramesList
.setSelectedValue(currentStackFrame
, true);
101 myListenersEnabled
= false;
102 for (StackFramesListBuilder builder
: myBuilders
.values()) {
106 XSuspendContext suspendContext
= mySession
.getSuspendContext();
107 if (suspendContext
== null) {
108 myThreadComboBox
.removeAllItems();
109 myFramesList
.clear();
113 XExecutionStack
[] executionStacks
= suspendContext
.getExecutionStacks();
114 for (XExecutionStack executionStack
: executionStacks
) {
115 myThreadComboBox
.addItem(executionStack
);
117 XExecutionStack activeExecutionStack
= suspendContext
.getActiveExecutionStack();
118 myThreadComboBox
.setSelectedItem(activeExecutionStack
);
119 myThreadComboBox
.setVisible(executionStacks
.length
!= 1);
120 updateFrames(activeExecutionStack
);
121 myListenersEnabled
= true;
124 private void updateFrames(final XExecutionStack executionStack
) {
125 if (mySelectedStack
== executionStack
) {
128 if (mySelectedStack
!= null) {
129 getOrCreateBuilder(mySelectedStack
).stop();
132 mySelectedStack
= executionStack
;
133 if (executionStack
!= null) {
134 StackFramesListBuilder builder
= getOrCreateBuilder(executionStack
);
135 builder
.initModel(myFramesList
.getModel());
137 XStackFrame topFrame
= executionStack
.getTopFrame();
138 if (topFrame
!= null) {
139 myFramesList
.setSelectedValue(topFrame
, true);
140 onFrameSelected(topFrame
);
145 public XDebuggerFramesList
getFramesList() {
149 private void onFrameSelected(final @NotNull XStackFrame stackFrame
) {
150 mySession
.setCurrentStackFrame(stackFrame
);
153 public JPanel
getMainPanel() {
157 private void processFrameSelection() {
158 if (!myListenersEnabled
) return;
159 Object selected
= myFramesList
.getSelectedValue();
160 if (selected
instanceof XStackFrame
) {
161 onFrameSelected((XStackFrame
)selected
);
165 private class MyItemListener
implements ItemListener
{
166 public void itemStateChanged(final ItemEvent e
) {
167 if (!myListenersEnabled
) return;
169 if (e
.getStateChange() == ItemEvent
.SELECTED
) {
170 Object item
= e
.getItem();
171 if (item
instanceof XExecutionStack
) {
172 updateFrames((XExecutionStack
)item
);
178 private class StackFramesListBuilder
implements XExecutionStack
.XStackFrameContainer
{
179 private XExecutionStack myExecutionStack
;
180 private final List
<XStackFrame
> myStackFrames
;
181 private String myErrorMessage
;
182 private int myNextFrameIndex
;
183 private boolean myRunning
;
184 private boolean myAllFramesLoaded
;
186 private StackFramesListBuilder(final XExecutionStack executionStack
) {
187 myExecutionStack
= executionStack
;
188 myStackFrames
= new ArrayList
<XStackFrame
>();
189 myStackFrames
.add(executionStack
.getTopFrame());
190 myNextFrameIndex
= 1;
193 public void addStackFrames(@NotNull final List
<?
extends XStackFrame
> stackFrames
, final boolean last
) {
194 ApplicationManager
.getApplication().invokeLater(new Runnable() {
196 myStackFrames
.addAll(stackFrames
);
197 addFrameListElements(stackFrames
, last
);
198 myNextFrameIndex
+= stackFrames
.size();
199 myAllFramesLoaded
= last
;
207 private void addFrameListElements(final List
<?
> values
, final boolean last
) {
208 if (myExecutionStack
!= null && myExecutionStack
== mySelectedStack
) {
209 DefaultListModel model
= myFramesList
.getModel();
210 if (model
.getElementAt(model
.getSize() - 1) == null) {
211 model
.removeElementAt(model
.getSize() - 1);
213 for (Object value
: values
) {
214 model
.addElement(value
);
217 model
.addElement(null);
219 myFramesList
.repaint();
223 public boolean isObsolete() {
227 public void errorOccured(final String errorMessage
) {
228 ApplicationManager
.getApplication().invokeLater(new Runnable() {
230 myErrorMessage
= errorMessage
;
231 addFrameListElements(Collections
.singletonList(errorMessage
), true);
237 public void dispose() {
239 myExecutionStack
= null;
242 public void start() {
243 if (myExecutionStack
== null) {
247 myExecutionStack
.computeStackFrames(myNextFrameIndex
, this);
254 public void initModel(final DefaultListModel model
) {
255 model
.removeAllElements();
256 for (XStackFrame stackFrame
: myStackFrames
) {
257 model
.addElement(stackFrame
);
259 if (myErrorMessage
!= null) {
260 model
.addElement(myErrorMessage
);
262 else if (!myAllFramesLoaded
) {
263 model
.addElement(null);