26097d26e035023bd987015367f73bc3275f9c32
[idea/community.git] / platform / dvcs-impl / src / com / intellij / dvcs / push / ui / RepositoryNode.java
1 /*
2  * Copyright 2000-2014 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 package com.intellij.dvcs.push.ui;
17
18 import com.intellij.dvcs.push.OutgoingResult;
19 import com.intellij.dvcs.push.PushTargetPanel;
20 import com.intellij.ui.CheckedTreeNode;
21 import com.intellij.ui.ColoredTreeCellRenderer;
22 import com.intellij.ui.SimpleTextAttributes;
23 import com.intellij.util.ui.GraphicsUtil;
24 import com.intellij.util.ui.UIUtil;
25 import com.intellij.util.ui.tree.TreeUtil;
26 import org.jetbrains.annotations.NotNull;
27 import org.jetbrains.annotations.Nullable;
28
29 import javax.swing.*;
30 import javax.swing.border.EmptyBorder;
31 import java.awt.event.ActionEvent;
32 import java.awt.event.ActionListener;
33 import java.util.concurrent.Future;
34 import java.util.concurrent.atomic.AtomicBoolean;
35 import java.util.concurrent.atomic.AtomicReference;
36
37 public class RepositoryNode extends CheckedTreeNode implements EditableTreeNode, Comparable<RepositoryNode> {
38
39   private static final int PROGRESS_DELAY = 100;
40   private static final int START_DELAY = 500;
41   @NotNull protected final LoadingIcon myLoadingIcon;
42   @NotNull protected final AtomicBoolean myLoading = new AtomicBoolean();
43   @NotNull private final CheckBoxModel myCheckBoxModel;
44
45   @NotNull private final RepositoryWithBranchPanel myRepositoryPanel;
46   @Nullable private Future<AtomicReference<OutgoingResult>> myFuture;
47   protected final int myCheckBoxHGap;
48   private final int myCheckBoxVGap;
49
50   public RepositoryNode(@NotNull RepositoryWithBranchPanel repositoryPanel, @NotNull CheckBoxModel model, boolean enabled) {
51     super(repositoryPanel);
52     myCheckBoxModel = model;
53     setChecked(false);
54     setEnabled(enabled);
55     myRepositoryPanel = repositoryPanel;
56     myLoadingIcon = myRepositoryPanel.getLoadingIcon();
57     myCheckBoxHGap = myRepositoryPanel.getLoadingIconAndCheckBoxGapH();
58     myCheckBoxVGap = myRepositoryPanel.getLoadingIconAndCheckBoxGapV();
59   }
60
61   @Override
62   public boolean isChecked() {
63     return myCheckBoxModel.isChecked();
64   }
65
66   @Override
67   public void setChecked(boolean checked) {
68     myCheckBoxModel.setChecked(checked);
69   }
70
71   public boolean isCheckboxVisible() {
72     return !myLoading.get();
73   }
74
75   @Override
76   public void render(@NotNull ColoredTreeCellRenderer renderer) {
77     int repoFixedWidth = 120;
78     int borderHOffset = myRepositoryPanel.getHBorderOffset(renderer);
79     if (myLoading.get()) {
80       renderer.setIcon(myLoadingIcon);
81       renderer.setIconOnTheRight(false);
82       int checkBoxWidth = myRepositoryPanel.getCheckBoxWidth();
83       repoFixedWidth += checkBoxWidth;
84       if (myCheckBoxHGap > 0) {
85         renderer.append("");
86         renderer.appendFixedTextFragmentWidth(checkBoxWidth + renderer.getIconTextGap() + borderHOffset);
87       }
88     }
89     else {
90       if (myCheckBoxHGap <= 0) {
91         renderer.append("");
92         renderer.appendFixedTextFragmentWidth(myRepositoryPanel.calculateRendererShiftH(renderer));
93       }
94     }
95     SimpleTextAttributes repositoryDetailsTextAttributes = PushLogTreeUtil
96       .addTransparencyIfNeeded(SimpleTextAttributes.REGULAR_ATTRIBUTES, isChecked());
97
98     renderer.append(getRepoName(renderer, repoFixedWidth), repositoryDetailsTextAttributes);
99     renderer.appendFixedTextFragmentWidth(repoFixedWidth);
100     renderer.append(myRepositoryPanel.getSourceName(), repositoryDetailsTextAttributes);
101     renderer.append(myRepositoryPanel.getArrow(), repositoryDetailsTextAttributes);
102     PushTargetPanel pushTargetPanel = myRepositoryPanel.getTargetPanel();
103     pushTargetPanel.render(renderer, renderer.getTree().isPathSelected(TreeUtil.getPathFromRoot(this)), isChecked());
104
105     int maxSize = Math.max(myRepositoryPanel.getCheckBoxHeight(), myLoadingIcon.getIconHeight());
106     int rendererHeight = renderer.getPreferredSize().height;
107     if (maxSize > rendererHeight) {
108       if (myCheckBoxVGap > 0 && isLoading() || myCheckBoxVGap < 0 && !isLoading()) {
109         int vShift = maxSize - rendererHeight;
110         renderer.setBorder(new EmptyBorder((vShift + 1) / 2, 0, (vShift) / 2, 0));
111       }
112     }
113   }
114
115   @NotNull
116   private String getRepoName(@NotNull ColoredTreeCellRenderer renderer, int maxWidth) {
117     String name = myRepositoryPanel.getRepositoryName();
118     return GraphicsUtil.stringWidth(name, renderer.getFont()) > maxWidth - UIUtil.DEFAULT_HGAP ? name + "  " : name;
119   }
120
121   @Override
122   public Object getUserObject() {
123     return myRepositoryPanel;
124   }
125
126   @Override
127   public void fireOnChange() {
128     myRepositoryPanel.fireOnChange();
129   }
130
131   @Override
132   public void fireOnCancel() {
133     myRepositoryPanel.fireOnCancel();
134   }
135
136   @Override
137   public void fireOnSelectionChange(boolean isSelected) {
138     myRepositoryPanel.fireOnSelectionChange(isSelected);
139   }
140
141   @Override
142   public void cancelLoading() {
143     if (myFuture != null && !myFuture.isDone()) {
144       myFuture.cancel(true);
145     }
146   }
147
148   @Override
149   public void startLoading(@NotNull final JTree tree, @NotNull Future<AtomicReference<OutgoingResult>> future, boolean initial) {
150     myFuture = future;
151     final Timer t = new Timer(initial ? START_DELAY : PROGRESS_DELAY, new ActionListener() {
152       @Override
153       public void actionPerformed(ActionEvent e) {
154         if (!myFuture.isDone()) {
155           myLoading.set(true);
156           myLoadingIcon.setObserver(tree, RepositoryNode.this);
157           tree.repaint();
158         }
159       }
160     });
161     t.setRepeats(false);
162     t.start();
163   }
164
165
166   public int compareTo(@NotNull RepositoryNode repositoryNode) {
167     String name = myRepositoryPanel.getRepositoryName();
168     RepositoryWithBranchPanel panel = (RepositoryWithBranchPanel)repositoryNode.getUserObject();
169     return name.compareTo(panel.getRepositoryName());
170   }
171
172   public void stopLoading() {
173     myLoading.set(false);
174     myLoadingIcon.setImageObserver(null);
175   }
176
177   public boolean isLoading() {
178     return myLoading.get();
179   }
180 }