b336d791e5047d2b1cf40381e6513bdd719a169f
[idea/community.git] / platform / lang-impl / src / com / intellij / execution / ui / layout / impl / RunnerLayout.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
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
17 package com.intellij.execution.ui.layout.impl;
18
19 import com.intellij.execution.ui.layout.LayoutAttractionPolicy;
20 import com.intellij.execution.ui.layout.PlaceInGrid;
21 import com.intellij.execution.ui.layout.Tab;
22 import com.intellij.openapi.util.Comparing;
23 import com.intellij.openapi.util.Key;
24 import com.intellij.openapi.util.Pair;
25 import com.intellij.openapi.util.text.StringUtil;
26 import com.intellij.ui.content.Content;
27 import com.intellij.util.xmlb.XmlSerializer;
28 import org.jdom.Element;
29 import org.jetbrains.annotations.NonNls;
30 import org.jetbrains.annotations.NotNull;
31 import org.jetbrains.annotations.Nullable;
32
33 import javax.swing.*;
34 import java.util.*;
35
36 public class RunnerLayout  {
37   public static final Key<Integer> DEFAULT_INDEX = Key.create("RunnerLayoutDefaultIndex");
38   public static final Key<Integer> DROP_INDEX = Key.create("RunnerLayoutDropIndex");  
39   private final String myID;
40
41   protected Map<String, ViewImpl> myViews = new HashMap<String, ViewImpl>();
42   private final Map<String, ViewImpl.Default> myDefaultViews = new HashMap<String, ViewImpl.Default>();
43
44   protected Set<TabImpl> myTabs = new TreeSet<TabImpl>(new Comparator<TabImpl>() {
45     public int compare(final TabImpl o1, final TabImpl o2) {
46       return o1.getIndex() - o2.getIndex();
47     }
48   });
49   private final Map<Integer, TabImpl.Default> myDefaultTabs = new HashMap<Integer, TabImpl.Default>();
50
51   protected General myGeneral = new General();
52   private final Map<String, Pair<String, LayoutAttractionPolicy>> myDefaultFocus = new HashMap<String, Pair<String, LayoutAttractionPolicy>>();
53
54
55   public RunnerLayout(final String ID) {
56     myID = ID;
57   }
58
59   @NotNull
60   public TabImpl getOrCreateTab(final int index) {
61     TabImpl tab = findTab(index);
62     if (tab != null) return tab;
63
64     tab = createNewTab(index);
65
66     return tab;
67   }
68
69   private TabImpl createNewTab(final int index) {
70     final TabImpl tab;
71
72     final TabImpl.Default defaultTab = getOrCreateDefaultTab(index);
73     tab = defaultTab.createTab();
74
75     myTabs.add(tab);
76
77     return tab;
78   }
79
80   private TabImpl.Default getOrCreateDefaultTab(final int index) {
81     TabImpl.Default tab = myDefaultTabs.get(index);
82     if (tab == null) {
83       tab = new TabImpl.Default(index, null, null);
84       myDefaultTabs.put(index, tab);
85     }
86     return tab;
87   }
88
89   public TabImpl createNewTab() {
90     int index = 0;
91     for (TabImpl each : myTabs) {
92       if (!isUsed(each)) return each;
93
94       if (each.getIndex() < Integer.MAX_VALUE) {
95         index = each.getIndex() + 1;
96       }
97       else {
98         break;
99       }
100     }
101
102     return createNewTab(index);
103   }
104
105   private boolean isUsed(TabImpl tab) {
106     for (ViewImpl each : myViews.values()) {
107       if (each.getTab() == tab) return true;
108     }
109
110     return false;
111   }
112
113   @Nullable
114   protected TabImpl findTab(int index) {
115     for (TabImpl each : myTabs) {
116       if (index == each.getIndex()) return each;
117     }
118
119     return null;
120   }
121
122   public Element getState() {
123     return write(new Element("layout"));
124   }
125
126   public void loadState(final Element state) {
127     read(state);
128   }
129
130   public Element read(final Element parentNode) {
131     List tabs = parentNode.getChildren(StringUtil.getShortName(TabImpl.class.getName()));
132     for (Object eachTabElement : tabs) {
133       TabImpl eachTab = new TabImpl((Element)eachTabElement);
134       getOrCreateTab(eachTab.getIndex()).read((Element)eachTabElement);
135     }
136
137     final List views = parentNode.getChildren(StringUtil.getShortName(ViewImpl.class.getName()));
138     for (Object content : views) {
139       final ViewImpl state = new ViewImpl(this, (Element)content);
140       myViews.put(state.getID(), state);
141     }
142
143     XmlSerializer.deserializeInto(myGeneral, parentNode.getChild(StringUtil.getShortName(myGeneral.getClass().getName(), '$')));
144
145     return parentNode;
146   }
147
148   public Element write(final Element parentNode) {
149     for (ViewImpl eachState : myViews.values()) {
150       eachState.write(parentNode);
151     }
152
153     for (TabImpl eachTab : myTabs) {
154       if (isUsed(eachTab)) {
155         eachTab.write(parentNode);
156       }
157     }
158
159     parentNode.addContent(XmlSerializer.serialize(myGeneral));
160
161     return parentNode;
162   }
163
164
165   public void resetToDefault() {
166     myViews.clear();
167
168     for (TabImpl each : myTabs) {
169       final TabImpl.Default defaultTab = getOrCreateDefaultTab(each.getDefaultIndex());
170       each.copyFrom(defaultTab);
171     }
172   }
173
174   public boolean isToolbarHorizontal() {
175     return false;
176   }
177
178   public void setToolbarHorizontal(boolean horizontal) {
179     myGeneral.horizontalToolbar = horizontal;
180   }
181
182   public ViewImpl getStateFor(Content content) {
183     return getOrCreateView(getOrCreateContentId(content));
184   }
185
186   public void clearStateFor(Content content) {
187     final ViewImpl view = myViews.remove(getOrCreateContentId(content));
188     if (view != null) {
189       final Tab tab = view.getTab();
190       if (tab instanceof TabImpl) {
191         myTabs.remove(tab);
192       }
193     }
194   }
195
196   private static String getOrCreateContentId(final Content content) {
197     @NonNls String id = content.getUserData(ViewImpl.ID);
198     if (id == null) {
199       id = "UnknownView-" + content.getDisplayName();
200       content.putUserData(ViewImpl.ID, id);
201     }
202     return id;
203   }
204
205   private ViewImpl getOrCreateView(String id) {
206     if (myViews.containsKey(id)) {
207       return myViews.get(id);
208     } else {
209       final ViewImpl.Default defaultView = getOrCreateDefault(id);
210       final ViewImpl view = defaultView.createView(this);
211       myViews.put(id, view);
212       return view;
213     }
214   }
215
216   private ViewImpl.Default getOrCreateDefault(String id) {
217     if (myDefaultViews.containsKey(id)) {
218       return myDefaultViews.get(id);
219     } else {
220       return setDefault(id, Integer.MAX_VALUE, PlaceInGrid.bottom, false);
221     }
222   }
223
224
225   public TabImpl.Default setDefault(int tabID, String displayName, Icon icon) {
226     final TabImpl.Default tab = new TabImpl.Default(tabID, displayName, icon);
227     myDefaultTabs.put(tabID, tab);
228     return tab;
229   }
230
231   public ViewImpl.Default setDefault(String id, int tabIndex, PlaceInGrid placeInGrid, boolean isMinimized) {
232     final ViewImpl.Default view = new ViewImpl.Default(id, tabIndex, placeInGrid, isMinimized);
233     myDefaultViews.put(id, view);
234     return view;
235   }
236
237   public PlaceInGrid getDefaultGridPlace(final Content content) {
238     return getOrCreateDefault(getOrCreateContentId(content)).getPlaceInGrid();
239   }
240
241   public int getDefaultSelectedTabIndex() {
242     return 0;
243   }
244
245   public boolean isToFocus(final String id, final String condition) {
246     return Comparing.equal(id, getToFocus(condition));
247   }
248
249   public void setToFocus(final String id, final String condition) {
250     myGeneral.focusOnCondition.put(condition, id);
251   }
252
253   public void setDefaultToFocus(String id, final String condition, @NotNull final LayoutAttractionPolicy policy) {
254     myDefaultFocus.put(condition, Pair.create(id, policy));
255   }
256
257   @Nullable
258   public String getToFocus(final String condition) {
259     return myGeneral.focusOnCondition.containsKey(condition) ? myGeneral.focusOnCondition.get(condition) : (myDefaultFocus.containsKey(condition) ? myDefaultFocus.get(condition).getFirst() : null);
260   }
261
262   public LayoutAttractionPolicy getAttractionPolicy(final String condition) {
263     final Pair<String, LayoutAttractionPolicy> pair = myDefaultFocus.get(condition);
264     return pair == null ? new LayoutAttractionPolicy.FocusOnce() : pair.getSecond();
265   }
266
267   public static class General {
268     public volatile boolean horizontalToolbar = false;
269     public volatile int selectedTab = 0;
270     public volatile Map<String, String> focusOnCondition = new HashMap<String, String>();
271   }
272 }