ComponentWithBrowseButton - optional remove listener on hide
[fedora-idea.git] / platform / platform-impl / src / com / intellij / openapi / wm / impl / status / StatusBarImpl.java
blob2d235a55ed70301067f10f2d23f2ea45feb7f5e1
1 /*
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.openapi.wm.impl.status;
18 import com.intellij.diagnostic.IdeMessagePanel;
19 import com.intellij.diagnostic.MessagePool;
20 import com.intellij.ide.DataManager;
21 import com.intellij.ide.ui.UISettings;
22 import com.intellij.ide.ui.UISettingsListener;
23 import com.intellij.notification.impl.IdeNotificationArea;
24 import com.intellij.openapi.actionSystem.PlatformDataKeys;
25 import com.intellij.openapi.diagnostic.Logger;
26 import com.intellij.openapi.editor.Document;
27 import com.intellij.openapi.editor.Editor;
28 import com.intellij.openapi.editor.ex.DocumentEx;
29 import com.intellij.openapi.fileEditor.FileEditorManager;
30 import com.intellij.openapi.progress.TaskInfo;
31 import com.intellij.openapi.project.Project;
32 import com.intellij.openapi.ui.MessageType;
33 import com.intellij.openapi.ui.popup.BalloonHandler;
34 import com.intellij.openapi.wm.StatusBarCustomComponentFactory;
35 import com.intellij.openapi.wm.ex.ProgressIndicatorEx;
36 import com.intellij.openapi.wm.ex.StatusBarEx;
37 import com.intellij.ui.components.panels.NonOpaquePanel;
38 import com.intellij.ui.popup.NotificationPopup;
39 import com.intellij.util.containers.HashMap;
40 import com.intellij.util.ui.AsyncProcessIcon;
41 import com.intellij.util.ui.EmptyIcon;
42 import com.intellij.util.ui.UIUtil;
43 import org.jetbrains.annotations.NotNull;
44 import org.jetbrains.annotations.Nullable;
46 import javax.swing.*;
47 import javax.swing.border.Border;
48 import javax.swing.border.EmptyBorder;
49 import javax.swing.event.HyperlinkListener;
50 import java.awt.*;
51 import java.util.ArrayList;
52 import java.util.List;
53 import java.util.Map;
55 public class StatusBarImpl extends JPanel implements StatusBarEx {
56 private final PositionPanel myPositionPanel = new PositionPanel(this);
57 private final ToggleReadOnlyAttributePanel myToggleReadOnlyAttributePanel = new ToggleReadOnlyAttributePanel(this);
58 private final EncodingPanel myEncodingPanel = new EncodingPanel(this);
59 private final IdeNotificationArea myNotificationArea = new IdeNotificationArea(this);
60 private final MemoryUsagePanel myMemoryUsagePanel = new MemoryUsagePanel();
61 private final InsertOverwritePanel myInsertOverwritePanel = new InsertOverwritePanel();
62 private final IdeMessagePanel myMessagePanel = new IdeMessagePanel(MessagePool.getInstance());
63 private final JPanel myCustomIndicationsPanel = new JPanel(new GridBagLayout());
64 private final JPanel myAppLevelCustomIndicationsPanel = new JPanel(new GridBagLayout());
65 private String myInfo = "";
67 private final MyUISettingsListener myUISettingsListener;
68 private InfoAndProgressPanel myInfoAndProgressPanel;
70 private final UISettings myUISettings;
71 private AsyncProcessIcon myRefreshIcon;
72 private EmptyIcon myEmptyRefreshIcon;
73 private final List<StatusBarPatch> myFileStatusComponents = new ArrayList<StatusBarPatch>();
74 private final List<StatusBarPatch> myPatches = new ArrayList<StatusBarPatch>();
75 private JPanel myPatchesPanel;
76 private List<StatusBarCustomComponentFactory> myCustomComponentsFactoryList;
77 private final Map<StatusBarCustomComponentFactory, JComponent> myFactory2Component = new HashMap<StatusBarCustomComponentFactory, JComponent>();
79 private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.wm.impl.status.StatusBarImpl");
81 public StatusBarImpl(UISettings uiSettings) {
82 myUISettings = uiSettings;
83 constructUI();
85 myUISettingsListener=new MyUISettingsListener();
88 private void constructUI() {
89 setLayout(new BorderLayout());
90 setOpaque(true);
92 myRefreshIcon = new AsyncProcessIcon("Refreshing filesystem") {
93 protected Icon getPassiveIcon() {
94 return myEmptyRefreshIcon;
97 myEmptyRefreshIcon = new EmptyIcon(myRefreshIcon.getPreferredSize().width, myRefreshIcon.getPreferredSize().height);
98 myInfoAndProgressPanel = new InfoAndProgressPanel(this);
99 setRefreshVisible(false);
101 final NonOpaquePanel center = new NonOpaquePanel(new BorderLayout());
102 center.add(myRefreshIcon, BorderLayout.WEST);
103 center.add(myInfoAndProgressPanel, BorderLayout.CENTER);
106 myPatchesPanel = new JPanel(new GridBagLayout());
107 myPatchesPanel.setOpaque(false);
108 setBorder(new EmptyBorder(2, 0, 1, 0));
111 add(center, BorderLayout.CENTER);
112 add(myPatchesPanel, BorderLayout.EAST);
114 recreatePatches();
117 public IdeNotificationArea getNotificationArea() {
118 return myNotificationArea;
121 private void recreatePatches() {
122 myPatchesPanel.removeAll();
123 myPatches.clear();
125 addPatch(myPositionPanel, true);
126 addPatch(myToggleReadOnlyAttributePanel, true);
127 addPatch(myInsertOverwritePanel, true);
128 addPatch(myEncodingPanel, true);
129 for (int i = 0; i < myFileStatusComponents.size(); i++) {
130 StatusBarPatch component = myFileStatusComponents.get(i);
131 addPatch(component, i==0);
134 addPatch(new StatusBarPatch() {
135 public JComponent getComponent() {
136 return myCustomIndicationsPanel;
139 public String updateStatusBar(final Editor selected, final JComponent componentSelected) {
140 return componentSelected == null ? null : componentSelected.getToolTipText();
143 public void clear() {
146 }, true);
148 addPatch(new StatusBarPatch() {
149 public JComponent getComponent() {
150 return myAppLevelCustomIndicationsPanel;
153 public String updateStatusBar(final Editor selected, final JComponent componentSelected) {
154 return componentSelected == null ? null : componentSelected.getToolTipText();
157 public void clear() {
160 }, true);
162 addPatch(myMessagePanel, false);
163 addPatch(myNotificationArea, true);
164 addPatch(myMemoryUsagePanel, true);
166 final GridBagConstraints gbConstraints = new GridBagConstraints();
167 gbConstraints.fill = GridBagConstraints.BOTH;
168 gbConstraints.weightx = 1;
169 gbConstraints.weighty = 1;
170 gbConstraints.gridx = 0;
171 gbConstraints.gridy = 0;
172 gbConstraints.gridwidth = 1;
173 gbConstraints.gridheight = 1;
174 gbConstraints.anchor = GridBagConstraints.WEST;
176 for (int i = 0; i < myPatches.size(); i++) {
177 StatusBarPatch patch = myPatches.get(i);
178 JComponent component = patch.getComponent();
179 if (i == myPatches.size() - 1) {
180 gbConstraints.fill = GridBagConstraints.VERTICAL;
181 gbConstraints.gridwidth = GridBagConstraints.REMAINDER;
183 myPatchesPanel.add(component, gbConstraints);
184 gbConstraints.fill = GridBagConstraints.VERTICAL;
185 gbConstraints.weightx = 0;
186 gbConstraints.gridx++;
191 public void setCustomComponentsFactory(final List<StatusBarCustomComponentFactory> customComponentsFactory) {
192 disposeAppLevelCustomComponents();
193 myCustomComponentsFactoryList = customComponentsFactory;
194 for (StatusBarCustomComponentFactory factory : myCustomComponentsFactoryList) {
195 JComponent c = factory.createComponent(this);
196 if (c != null) {
197 addAppLevelCustomIndicationComponent(c);
202 private void setRefreshVisible(final boolean visible) {
203 if (visible) {
204 myRefreshIcon.resume();
206 else {
207 myRefreshIcon.suspend();
211 public void add(final ProgressIndicatorEx indicator, TaskInfo info) {
212 myInfoAndProgressPanel.addProgress(indicator, info);
215 public void setProcessWindowOpen(final boolean open) {
216 myInfoAndProgressPanel.setProcessWindowOpen(open);
219 public BalloonHandler notifyProgressByBalloon(@NotNull MessageType type, @NotNull String htmlBody) {
220 return notifyProgressByBalloon(type, htmlBody, null, null);
223 public BalloonHandler notifyProgressByBalloon(@NotNull MessageType type,
224 @NotNull String htmlBody,
225 @Nullable Icon icon,
226 @Nullable HyperlinkListener listener) {
227 return myInfoAndProgressPanel.notifyByBalloon(type, htmlBody, icon, listener);
230 public void update(final Editor editor) {
231 if (editor != null) {
232 final Document document = editor.getDocument();
233 if (document instanceof DocumentEx && ((DocumentEx)document).isInBulkUpdate()) return;
236 for (StatusBarPatch patch : myPatches) {
237 try {
238 patch.updateStatusBar(editor, null);
240 catch (Exception e) {
241 LOG.error(e);
246 public void dispose() {
247 disposeAppLevelCustomComponents();
250 private void disposeAppLevelCustomComponents() {
251 if (myCustomComponentsFactoryList != null) {
252 for (StatusBarCustomComponentFactory<JComponent> factory : myCustomComponentsFactoryList) {
253 try {
254 JComponent c = myFactory2Component.get(factory);
255 if (c != null) {
256 factory.disposeComponent(this, c);
259 finally {
260 myFactory2Component.remove(factory);
265 myCustomComponentsFactoryList = null;
268 Editor getEditor() {
269 final Project project = getProject();
270 if (project == null) return null;
271 return getEditor(project);
274 private static Editor getEditor(final Project project) {
275 return FileEditorManager.getInstance(project).getSelectedTextEditor();
278 private Project getProject() {
279 return PlatformDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(this));
282 public boolean isProcessWindowOpen() {
283 return myInfoAndProgressPanel.isProcessWindowOpen();
286 protected final void paintComponent(final Graphics g) {
287 g.setColor(getBackground());
288 g.fillRect(0, 0, getWidth(), getHeight());
290 final Color dark = getBackground().darker();
292 g.setColor(dark);
293 g.drawLine(0, 0, getWidth(), 0);
295 final Color lighter = new Color(dark.getRed(), dark.getGreen(), dark.getBlue(), 75);
296 g.setColor(lighter);
297 g.drawLine(0, 1, getWidth(), 1);
299 g.drawLine(0, getHeight() - 1, getWidth(), getHeight() - 1);
302 public final void addNotify() {
303 super.addNotify();
304 setMemoryIndicatorVisible(myUISettings.SHOW_MEMORY_INDICATOR);
305 myUISettings.addUISettingsListener(myUISettingsListener);
308 public final void removeNotify() {
309 UISettings.getInstance().removeUISettingsListener(myUISettingsListener);
310 super.removeNotify();
313 public final void setInfo(@Nullable final String s) {
314 UIUtil.invokeLaterIfNeeded(new Runnable() {
315 public void run() {
316 myInfo = s;
317 myInfoAndProgressPanel.setText(s != null ? s : " ");
322 public void fireNotificationPopup(@NotNull JComponent content, final Color backgroundColor) {
323 new NotificationPopup(this, content, backgroundColor);
326 public final String getInfo() {
327 return myInfo;
330 private void addAppLevelCustomIndicationComponent(@NotNull final JComponent c) {
331 addCustomIndicationComponent(c, myAppLevelCustomIndicationsPanel);
334 public final void addCustomIndicationComponent(@NotNull JComponent c) {
335 addCustomIndicationComponent(c, myCustomIndicationsPanel);
338 private static void addCustomIndicationComponent(final JComponent c, final JPanel indicationsPanel) {
339 final GridBagConstraints gbConstraints = new GridBagConstraints();
340 gbConstraints.fill = GridBagConstraints.BOTH;
341 gbConstraints.weightx = 0;
342 gbConstraints.weighty = 1;
343 gbConstraints.insets = new Insets(0, 0, 0, 2);
346 indicationsPanel.setVisible(true);
347 indicationsPanel.add(c, gbConstraints);
350 public void removeCustomIndicationComponent(@NotNull final JComponent component) {
351 removeCustomIndicationComponent(component, myCustomIndicationsPanel);
354 private static void removeCustomIndicationComponent(final JComponent component, final JPanel indicationsPanel) {
355 indicationsPanel.remove(component);
356 if (indicationsPanel.getComponentCount() == 0) {
357 indicationsPanel.setVisible(false);
362 * Clears all sections in status bar
364 public final void clear(){
365 for (StatusBarPatch patch : myPatches) {
366 patch.clear();
370 public void addFileStatusComponent(StatusBarPatch component) {
371 myFileStatusComponents.add(component);
372 recreatePatches();
375 public void removeFileStatusComponent(StatusBarPatch component) {
376 myFileStatusComponents.remove(component);
377 recreatePatches();
380 public void cleanupCustomComponents() {
381 myCustomIndicationsPanel.removeAll();
384 public final Dimension getMinimumSize() {
385 final Dimension p = super.getPreferredSize();
386 final Dimension m = super.getMinimumSize();
387 return new Dimension(m.width, p.height);
390 public final Dimension getMaximumSize() {
391 final Dimension p = super.getPreferredSize();
392 final Dimension m = super.getMaximumSize();
393 return new Dimension(m.width, p.height);
396 private void setMemoryIndicatorVisible(final boolean state) {
397 if (myMemoryUsagePanel != null) {
398 myMemoryUsagePanel.setVisible(state);
402 private final class MyUISettingsListener implements UISettingsListener{
403 public void uiSettingsChanged(final UISettings uiSettings) {
404 setMemoryIndicatorVisible(uiSettings.SHOW_MEMORY_INDICATOR);
408 public static class SeparatorBorder implements Border {
410 private final boolean myLeft;
412 public SeparatorBorder(final boolean left) {
413 myLeft = left;
416 public void paintBorder(final Component c, final Graphics g, final int x, final int y, final int width, final int height) {
417 final Color bg = c.getBackground();
418 g.setColor(bg != null ? bg.darker() : Color.darkGray);
419 final int inset = 1;
420 if (myLeft) {
421 g.drawLine(0, inset, 0, c.getHeight() - inset - 1);
422 } else {
423 g.drawLine(c.getWidth() - 1, inset, c.getWidth() - 1, c.getHeight() - inset - 1);
427 public Insets getBorderInsets(final Component c) {
428 return new Insets(0, 1, 0, 1);
431 public boolean isBorderOpaque() {
432 return false;
436 public static class Left extends SeparatorBorder {
437 public Left() {
438 super(true);
443 public void startRefreshIndication(String tooltipText) {
444 myRefreshIcon.setToolTipText(tooltipText);
445 setRefreshVisible(true);
448 public void stopRefreshIndication() {
449 setRefreshVisible(false);
452 private void addPatch(StatusBarPatch panel, boolean separator) {
453 final Border emptyBorder = BorderFactory.createEmptyBorder(0, 2, 0, 2);
454 final Border separatorLeft = BorderFactory.createCompoundBorder(emptyBorder, new SeparatorBorder.Left());
455 myPatches.add(panel);
456 JComponent component = panel.getComponent();
457 if (separator) {
458 component.setBorder(separatorLeft);
460 else {
461 component.setBorder(emptyBorder);
463 component.setOpaque(false);