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
;
47 import javax
.swing
.border
.Border
;
48 import javax
.swing
.border
.EmptyBorder
;
49 import javax
.swing
.event
.HyperlinkListener
;
51 import java
.util
.ArrayList
;
52 import java
.util
.List
;
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
;
85 myUISettingsListener
=new MyUISettingsListener();
88 private void constructUI() {
89 setLayout(new BorderLayout());
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
);
117 public IdeNotificationArea
getNotificationArea() {
118 return myNotificationArea
;
121 private void recreatePatches() {
122 myPatchesPanel
.removeAll();
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() {
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() {
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);
197 addAppLevelCustomIndicationComponent(c
);
202 private void setRefreshVisible(final boolean visible
) {
204 myRefreshIcon
.resume();
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
,
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
) {
238 patch
.updateStatusBar(editor
, null);
240 catch (Exception e
) {
246 public void dispose() {
247 disposeAppLevelCustomComponents();
250 private void disposeAppLevelCustomComponents() {
251 if (myCustomComponentsFactoryList
!= null) {
252 for (StatusBarCustomComponentFactory
<JComponent
> factory
: myCustomComponentsFactoryList
) {
254 JComponent c
= myFactory2Component
.get(factory
);
256 factory
.disposeComponent(this, c
);
260 myFactory2Component
.remove(factory
);
265 myCustomComponentsFactoryList
= null;
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();
293 g
.drawLine(0, 0, getWidth(), 0);
295 final Color lighter
= new Color(dark
.getRed(), dark
.getGreen(), dark
.getBlue(), 75);
297 g
.drawLine(0, 1, getWidth(), 1);
299 g
.drawLine(0, getHeight() - 1, getWidth(), getHeight() - 1);
302 public final void 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() {
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() {
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
) {
370 public void addFileStatusComponent(StatusBarPatch component
) {
371 myFileStatusComponents
.add(component
);
375 public void removeFileStatusComponent(StatusBarPatch component
) {
376 myFileStatusComponents
.remove(component
);
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
) {
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
);
421 g
.drawLine(0, inset
, 0, c
.getHeight() - inset
- 1);
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() {
436 public static class Left
extends SeparatorBorder
{
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();
458 component
.setBorder(separatorLeft
);
461 component
.setBorder(emptyBorder
);
463 component
.setOpaque(false);