mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Appropriate borders, gaps and icons modified for different LaF to avoid ui shifts and movements between loading, edit_mode and normal state.
This commit is contained in:
@@ -34,19 +34,8 @@ class LoadingIcon extends JBImageIcon {
|
||||
private static final String LOADING_ICON = "/icons/loading.gif";
|
||||
private static final Logger LOG = Logger.getInstance(LoadingIcon.class);
|
||||
|
||||
private final int myWidth;
|
||||
private final int myHeight;
|
||||
private final int myDeltaX;
|
||||
private final int myDeltaY;
|
||||
|
||||
LoadingIcon(@NotNull Image image, int width, int height) {
|
||||
LoadingIcon(@NotNull Image image) {
|
||||
super(image);
|
||||
int myOriginalWidth = image.getWidth(null);
|
||||
int myOriginalHeight = image.getHeight(null);
|
||||
myWidth = Math.max(width, myOriginalWidth);
|
||||
myHeight = Math.max(height, myOriginalHeight);
|
||||
myDeltaX = (myWidth - myOriginalWidth) / 2 - 2;
|
||||
myDeltaY = (myHeight - myOriginalHeight) / 2 + 2;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -56,33 +45,18 @@ class LoadingIcon extends JBImageIcon {
|
||||
LOG.error("Couldn't load image: " + LOADING_ICON);
|
||||
return createEmpty(width, height);
|
||||
}
|
||||
return new LoadingIcon(image, width, height);
|
||||
return new LoadingIcon(image);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static LoadingIcon createEmpty(int width, int height) {
|
||||
return new LoadingIcon(UIUtil.createImage(width, height, Transparency.TRANSLUCENT), width, height);
|
||||
return new LoadingIcon(UIUtil.createImage(width, height, Transparency.TRANSLUCENT));
|
||||
}
|
||||
|
||||
void setObserver(@NotNull JTree tree, @NotNull TreeNode treeNode) {
|
||||
setImageObserver(new NodeImageObserver(tree, treeNode));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final synchronized void paintIcon(final Component c, final Graphics g, final int x, final int y) {
|
||||
super.paintIcon(c, g, x + myDeltaX, y + myDeltaY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconHeight() {
|
||||
return myHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconWidth() {
|
||||
return myWidth;
|
||||
}
|
||||
|
||||
private static class NodeImageObserver implements ImageObserver {
|
||||
@NotNull private final JTree myTree;
|
||||
@NotNull private final DefaultTreeModel myModel;
|
||||
|
||||
@@ -355,6 +355,9 @@ public class PushLog extends JPanel implements TypeSafeDataProvider {
|
||||
if (!(value instanceof DefaultMutableTreeNode)) {
|
||||
return;
|
||||
}
|
||||
myCheckbox.setBorder(null); //checkBox may have no border by default, but insets are not null,
|
||||
// it depends on LaF, OS and isItRenderedPane, see com.intellij.ide.ui.laf.darcula.ui.DarculaCheckBoxBorder.
|
||||
// null border works as expected always.
|
||||
if (value instanceof RepositoryNode) {
|
||||
//todo simplify, remove instance of
|
||||
myCheckbox.setVisible(((RepositoryNode)value).isCheckboxVisible());
|
||||
|
||||
@@ -27,7 +27,6 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import java.awt.*;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
@@ -40,7 +39,8 @@ public class RepositoryNode extends CheckedTreeNode implements EditableTreeNode,
|
||||
|
||||
@NotNull private final RepositoryWithBranchPanel myRepositoryPanel;
|
||||
@Nullable private Future<AtomicReference<OutgoingResult>> myFuture;
|
||||
protected final int myLoadingIconWidth;
|
||||
protected final int myCheckBoxHGap;
|
||||
private final int myCheckBoxVGap;
|
||||
|
||||
public RepositoryNode(@NotNull RepositoryWithBranchPanel repositoryPanel, @NotNull CheckBoxModel model, boolean enabled) {
|
||||
super(repositoryPanel);
|
||||
@@ -48,10 +48,9 @@ public class RepositoryNode extends CheckedTreeNode implements EditableTreeNode,
|
||||
setChecked(false);
|
||||
setEnabled(enabled);
|
||||
myRepositoryPanel = repositoryPanel;
|
||||
|
||||
Dimension size = new JCheckBox().getPreferredSize();
|
||||
myLoadingIconWidth = size.width;
|
||||
myLoadingIcon = LoadingIcon.create(myLoadingIconWidth, size.height);
|
||||
myLoadingIcon = myRepositoryPanel.getLoadingIcon();
|
||||
myCheckBoxHGap = myRepositoryPanel.getLoadingIconAndCheckBoxGapH();
|
||||
myCheckBoxVGap = myRepositoryPanel.getLoadingIconAndCheckBoxGapV();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -71,25 +70,44 @@ public class RepositoryNode extends CheckedTreeNode implements EditableTreeNode,
|
||||
@Override
|
||||
public void render(@NotNull ColoredTreeCellRenderer renderer) {
|
||||
int repoFixedWidth = 120;
|
||||
int borderHOffset = myRepositoryPanel.getHBorderOffset(renderer);
|
||||
int borderVOffset = myRepositoryPanel.getVBorderOffset(renderer);
|
||||
if (myLoading.get()) {
|
||||
renderer.setIcon(myLoadingIcon);
|
||||
renderer.setIconOnTheRight(false);
|
||||
repoFixedWidth += myLoadingIconWidth;
|
||||
int checkBoxWidth = myRepositoryPanel.getCheckBoxWidth();
|
||||
repoFixedWidth += checkBoxWidth;
|
||||
if (myCheckBoxHGap > 0) {
|
||||
renderer.append("");
|
||||
renderer.appendFixedTextFragmentWidth(checkBoxWidth + renderer.getIconTextGap() + borderHOffset);
|
||||
}
|
||||
if (myCheckBoxVGap > 0) {
|
||||
int shiftV = myCheckBoxVGap - borderVOffset;
|
||||
renderer.setBorder(new EmptyBorder(shiftV / 2, 0, shiftV / 2, 0));
|
||||
}
|
||||
}
|
||||
renderer.append(getRepoName(renderer, repoFixedWidth), SimpleTextAttributes.GRAY_ATTRIBUTES);
|
||||
else {
|
||||
if (myCheckBoxHGap <= 0) {
|
||||
renderer.append("");
|
||||
renderer.appendFixedTextFragmentWidth(myRepositoryPanel.calculateRendererShiftH(renderer));
|
||||
}
|
||||
if (myCheckBoxVGap <= 0) {
|
||||
int shiftV = -myCheckBoxVGap + borderVOffset;
|
||||
renderer.setBorder(new EmptyBorder(shiftV / 2, 0, shiftV / 2, 0));
|
||||
}
|
||||
}
|
||||
renderer.append(getRepoName(renderer, repoFixedWidth), isChecked() ? SimpleTextAttributes.REGULAR_ATTRIBUTES : SimpleTextAttributes.GRAY_ATTRIBUTES);
|
||||
renderer.appendFixedTextFragmentWidth(repoFixedWidth);
|
||||
renderer.append(myRepositoryPanel.getSourceName(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
|
||||
renderer.append(myRepositoryPanel.getArrow(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
|
||||
renderer.append(myRepositoryPanel.getSourceName(), isChecked() ? SimpleTextAttributes.REGULAR_ATTRIBUTES : SimpleTextAttributes.GRAY_ATTRIBUTES);
|
||||
renderer.append(myRepositoryPanel.getArrow(), isChecked() ? SimpleTextAttributes.REGULAR_ATTRIBUTES : SimpleTextAttributes.GRAY_ATTRIBUTES);
|
||||
PushTargetPanel pushTargetPanel = myRepositoryPanel.getTargetPanel();
|
||||
pushTargetPanel.render(renderer);
|
||||
Insets insets = BorderFactory.createEmptyBorder().getBorderInsets(pushTargetPanel);
|
||||
renderer.setBorder(new EmptyBorder(insets));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String getRepoName(@NotNull ColoredTreeCellRenderer renderer, int maxWidth) {
|
||||
String name = myRepositoryPanel.getRepositoryName();
|
||||
return GraphicsUtil.stringWidth(name, renderer.getFont()) > maxWidth - UIUtil.DEFAULT_VGAP ? name + " " : name;
|
||||
return GraphicsUtil.stringWidth(name, renderer.getFont()) > maxWidth - UIUtil.DEFAULT_HGAP ? name + " " : name;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.intellij.openapi.ui.MessageType;
|
||||
import com.intellij.openapi.ui.ValidationInfo;
|
||||
import com.intellij.openapi.ui.popup.util.PopupUtil;
|
||||
import com.intellij.ui.ColoredTreeCellRenderer;
|
||||
import com.intellij.ui.SimpleColoredComponent;
|
||||
import com.intellij.ui.SimpleTextAttributes;
|
||||
import com.intellij.ui.components.JBCheckBox;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
@@ -32,6 +33,7 @@ import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.Border;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
@@ -46,6 +48,11 @@ public class RepositoryWithBranchPanel<T extends PushTarget> extends NonOpaquePa
|
||||
private final JLabel myRepositoryLabel;
|
||||
private final ColoredTreeCellRenderer myTextRenderer;
|
||||
@NotNull private final List<RepositoryNodeListener<T>> myListeners = ContainerUtil.createLockFreeCopyOnWriteList();
|
||||
private final int myCheckBoxLoadingIconGapH;
|
||||
private final int myCheckBoxLoadingIconGapV;
|
||||
private final LoadingIcon myLoadingIcon;
|
||||
private final int myCheckBoxWidth;
|
||||
|
||||
|
||||
public RepositoryWithBranchPanel(@NotNull final Project project, @NotNull String repoName,
|
||||
@NotNull String sourceName, @NotNull PushTargetPanel<T> destPushTargetPanelComponent) {
|
||||
@@ -54,6 +61,7 @@ public class RepositoryWithBranchPanel<T extends PushTarget> extends NonOpaquePa
|
||||
myRepositoryCheckbox = new JBCheckBox();
|
||||
myRepositoryCheckbox.setFocusable(false);
|
||||
myRepositoryCheckbox.setOpaque(false);
|
||||
myRepositoryCheckbox.setBorder(null);
|
||||
myRepositoryCheckbox.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(@NotNull ActionEvent e) {
|
||||
@@ -89,6 +97,14 @@ public class RepositoryWithBranchPanel<T extends PushTarget> extends NonOpaquePa
|
||||
return error == null;
|
||||
}
|
||||
});
|
||||
|
||||
JCheckBox emptyBorderCheckBox = new JCheckBox();
|
||||
emptyBorderCheckBox.setBorder(null);
|
||||
Dimension size = emptyBorderCheckBox.getPreferredSize();
|
||||
myCheckBoxWidth = size.width;
|
||||
myLoadingIcon = LoadingIcon.create(myCheckBoxWidth, size.height);
|
||||
myCheckBoxLoadingIconGapH = myCheckBoxWidth - myLoadingIcon.getIconWidth();
|
||||
myCheckBoxLoadingIconGapV = size.height - myLoadingIcon.getIconHeight();
|
||||
}
|
||||
|
||||
private void layoutComponents() {
|
||||
@@ -122,17 +138,24 @@ public class RepositoryWithBranchPanel<T extends PushTarget> extends NonOpaquePa
|
||||
boolean hasFocus) {
|
||||
Rectangle bounds = tree.getPathBounds(tree.getPathForRow(row));
|
||||
invalidate();
|
||||
myTextRenderer.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
|
||||
if (!(value instanceof SingleRepositoryNode)) {
|
||||
RepositoryNode node = (RepositoryNode)value;
|
||||
myRepositoryCheckbox.setSelected(node.isChecked());
|
||||
myRepositoryCheckbox.setVisible(true);
|
||||
myTextRenderer.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
|
||||
if (myCheckBoxLoadingIconGapH < 0) {
|
||||
myTextRenderer.append("");
|
||||
myTextRenderer.appendFixedTextFragmentWidth(calculateRendererShiftH(myTextRenderer));
|
||||
}
|
||||
myTextRenderer.append(getRepositoryName(), SimpleTextAttributes.GRAY_ATTRIBUTES);
|
||||
myTextRenderer.appendFixedTextFragmentWidth(120);
|
||||
}
|
||||
else {
|
||||
myTextRenderer.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
|
||||
SingleRepositoryNode singleRepositoryNode = ((SingleRepositoryNode)value);
|
||||
myRepositoryCheckbox.setVisible(false);
|
||||
myTextRenderer.setIcon(singleRepositoryNode.getEmptyIcon());
|
||||
myTextRenderer.setIconOnTheRight(false);
|
||||
myTextRenderer.append("");
|
||||
}
|
||||
myTextRenderer.append(getSourceName(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
|
||||
myTextRenderer.append(getArrow(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
|
||||
@@ -168,6 +191,38 @@ public class RepositoryWithBranchPanel<T extends PushTarget> extends NonOpaquePa
|
||||
public PushTargetPanel getTargetPanel() {
|
||||
return myDestPushTargetPanelComponent;
|
||||
}
|
||||
|
||||
public LoadingIcon getLoadingIcon() {
|
||||
return myLoadingIcon;
|
||||
}
|
||||
|
||||
public int getCheckBoxWidth() {
|
||||
return myCheckBoxWidth;
|
||||
}
|
||||
|
||||
|
||||
public int getLoadingIconAndCheckBoxGapH() {
|
||||
return myCheckBoxLoadingIconGapH;
|
||||
}
|
||||
|
||||
public int calculateRendererShiftH(@NotNull SimpleColoredComponent coloredRenderer) {
|
||||
int borderOffset = getHBorderOffset(coloredRenderer);
|
||||
return -myCheckBoxLoadingIconGapH + coloredRenderer.getIconTextGap() + coloredRenderer.getIpad().left + borderOffset;
|
||||
}
|
||||
|
||||
public int getHBorderOffset(@NotNull SimpleColoredComponent coloredRenderer) {
|
||||
Border border = coloredRenderer.getMyBorder();
|
||||
return border != null ? border.getBorderInsets(coloredRenderer).left : 0;
|
||||
}
|
||||
|
||||
public int getLoadingIconAndCheckBoxGapV() {
|
||||
return myCheckBoxLoadingIconGapV;
|
||||
}
|
||||
|
||||
public int getVBorderOffset(@NotNull SimpleColoredComponent coloredRenderer) {
|
||||
Border border = coloredRenderer.getMyBorder();
|
||||
return border != null ? border.getBorderInsets(coloredRenderer).top : 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -28,7 +28,8 @@ public class SingleRepositoryNode extends RepositoryNode {
|
||||
public SingleRepositoryNode(@NotNull RepositoryWithBranchPanel repositoryPanel, @NotNull CheckBoxModel model) {
|
||||
super(repositoryPanel, model, true);
|
||||
myRepositoryPanel = repositoryPanel;
|
||||
myEmptyIcon = LoadingIcon.createEmpty(myLoadingIcon.getIconWidth(), myLoadingIcon.getIconHeight());
|
||||
myEmptyIcon =
|
||||
LoadingIcon.createEmpty(repositoryPanel.getLoadingIcon().getIconWidth(), repositoryPanel.getLoadingIcon().getIconHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -36,17 +37,18 @@ public class SingleRepositoryNode extends RepositoryNode {
|
||||
return false;
|
||||
}
|
||||
|
||||
public LoadingIcon getEmptyIcon() {
|
||||
return myEmptyIcon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fireOnSelectionChange(boolean isSelected) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(@NotNull ColoredTreeCellRenderer renderer) {
|
||||
renderer.setIcon(myLoading.get() ? myLoadingIcon : myEmptyIcon);
|
||||
renderer.setIcon(myLoading.get() ? myRepositoryPanel.getLoadingIcon() : myEmptyIcon);
|
||||
renderer.setIconOnTheRight(false);
|
||||
|
||||
renderer.append("");
|
||||
renderer.appendFixedTextFragmentWidth(myLoadingIconWidth);
|
||||
renderer.append(myRepositoryPanel.getSourceName(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
|
||||
renderer.append(myRepositoryPanel.getArrow(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
|
||||
PushTargetPanel pushTargetPanel = myRepositoryPanel.getTargetPanel();
|
||||
|
||||
Reference in New Issue
Block a user