Browse Source

Added DnD support to JTabFrame.

pull/15/head
weisj 5 years ago
parent
commit
ae53ad6e4e
  1. 10
      src/main/java/com/weis/darklaf/components/ScrollPopupMenu.java
  2. 100
      src/main/java/com/weis/darklaf/components/TextFieldHistory.java
  3. 80
      src/main/java/com/weis/darklaf/components/tabframe/JTabFrame.java
  4. 8
      src/main/java/com/weis/darklaf/components/tabframe/PanelPopup.java
  5. 2
      src/main/java/com/weis/darklaf/components/tabframe/TabFrameContentPane.java
  6. 30
      src/main/java/com/weis/darklaf/components/tabframe/TabFramePopup.java
  7. 4
      src/main/java/com/weis/darklaf/components/tabframe/TabFrameTab.java
  8. 8
      src/main/java/com/weis/darklaf/components/tabframe/TabFrameTabContainer.java
  9. 12
      src/main/java/com/weis/darklaf/components/tabframe/TabFrameTabLabel.java
  10. 29
      src/main/java/com/weis/darklaf/components/tabframe/TabFrameUI.java
  11. 2
      src/main/java/com/weis/darklaf/components/tabframe/TabbedPopup.java
  12. 40
      src/main/java/com/weis/darklaf/components/text/SearchEvent.java
  13. 31
      src/main/java/com/weis/darklaf/components/text/SearchListener.java
  14. 119
      src/main/java/com/weis/darklaf/components/text/SearchTextField.java
  15. 174
      src/main/java/com/weis/darklaf/components/text/SearchTextFieldWithHistory.java
  16. 157
      src/main/java/com/weis/darklaf/components/text/TextFieldHistoryPopup.java
  17. 1
      src/main/java/com/weis/darklaf/components/tooltip/ToolTipContext.java
  18. 2
      src/main/java/com/weis/darklaf/components/uiresource/Insets2D.java
  19. 2
      src/main/java/com/weis/darklaf/components/uiresource/JLabelUIResource.java
  20. 2
      src/main/java/com/weis/darklaf/components/uiresource/JPanelUIResource.java
  21. 2
      src/main/java/com/weis/darklaf/components/uiresource/UIResourceWrapper.java
  22. 2
      src/main/java/com/weis/darklaf/ui/colorchooser/DarkColorChooserPanel.java
  23. 13
      src/main/java/com/weis/darklaf/ui/tabbedpane/DarkTabbedPaneUI.java
  24. 4
      src/main/java/com/weis/darklaf/ui/tabbedpane/TabbedPaneTransferHandler.java
  25. 24
      src/main/java/com/weis/darklaf/ui/tabframe/DarkPanelPopupUI.java
  26. 3
      src/main/java/com/weis/darklaf/ui/tabframe/DarkTabFrameComponentPopupMenu.java
  27. 130
      src/main/java/com/weis/darklaf/ui/tabframe/DarkTabFrameTabContainerUI.java
  28. 90
      src/main/java/com/weis/darklaf/ui/tabframe/DarkTabFrameTabLabelUI.java
  29. 437
      src/main/java/com/weis/darklaf/ui/tabframe/DarkTabFrameUI.java
  30. 2
      src/main/java/com/weis/darklaf/ui/tabframe/DarkTabbedPopupUI.java
  31. 60
      src/main/java/com/weis/darklaf/ui/tabframe/TabDragListener.java
  32. 232
      src/main/java/com/weis/darklaf/ui/tabframe/TabFrameLayout.java
  33. 508
      src/main/java/com/weis/darklaf/ui/tabframe/TabFrameTransferHandler.java
  34. 3
      src/main/java/com/weis/darklaf/ui/tooltip/DarkTooltipBorder.java
  35. 35
      src/main/java/com/weis/darklaf/util/PropertyLoader.java
  36. 48
      src/main/java/com/weis/darklaf/util/SwingXUtilities.java
  37. 10
      src/main/java/org/pbjar/jxlayer/plaf/ext/MouseEventUI.java
  38. 1
      src/main/java/org/pbjar/jxlayer/repaint/RepaintManagerUtils.java
  39. 2
      src/main/resources/com/weis/darklaf/properties/ui/tabFrame.properties
  40. 2
      src/main/resources/com/weis/darklaf/theme/intellij/intellij_defaults.properties
  41. 5
      src/test/java/TabFrameDemo.java
  42. 2
      src/test/java/ToolBarDemo.java
  43. 13
      src/test/java/UIDemo.java

10
src/main/java/com/weis/darklaf/components/ScrollPopupMenu.java

@ -93,6 +93,14 @@ public class ScrollPopupMenu extends JPopupMenu {
return overlayScrollPane; return overlayScrollPane;
} }
/**
* Set the maximum height of the popup. If the size is larger than the specified maximum height the content will be
* wrapped inside a scroll pane.
* <p>
* Note: A value of <= 0 indicates that the height should not be limited.
*
* @param maxHeight the max height to use.
*/
public void setMaxHeight(final int maxHeight) { public void setMaxHeight(final int maxHeight) {
this.maxHeight = maxHeight; this.maxHeight = maxHeight;
} }
@ -109,7 +117,7 @@ public class ScrollPopupMenu extends JPopupMenu {
return; return;
} }
final Dimension prefSize = getPreferredSize(); final Dimension prefSize = getPreferredSize();
if (maxHeight == 0 || prefSize.height <= maxHeight) { if (maxHeight <= 0 || prefSize.height <= maxHeight) {
setBounds(0, 0, prefSize.width, prefSize.height); setBounds(0, 0, prefSize.width, prefSize.height);
popWin.setContentPane(this); popWin.setContentPane(this);
setBorderPainted(true); setBorderPainted(true);

100
src/main/java/com/weis/darklaf/components/TextFieldHistory.java

@ -1,100 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2019 Jannis Weis
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.weis.darklaf.components;
import com.weis.darklaf.decorators.PlainAction;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
/**
* @author Jannis Weis
*/
public class TextFieldHistory extends ScrollPopupMenu implements ActionListener {
private final LinkedHashSet<String> history;
private JTextField textField;
/**
* Create Scroll Popup Menu.
*
* @param textField the text field.
* @param length the length of the history.
* @param maxH maximum height.
*/
public TextFieldHistory(final JTextField textField, final int length, final int maxH) {
super(maxH);
this.history = new LinkedHashSet<>(length);
this.textField = textField;
if (textField != null) {
textField.addActionListener(this);
}
}
public void setTextField(final JTextField textField) {
if (this.textField != null) {
textField.removeActionListener(this);
}
this.textField = textField;
if (this.textField != null) {
textField.addActionListener(this);
}
}
@Override
public void actionPerformed(final ActionEvent e) {
var text = textField.getText();
if (!text.isBlank()) {
history.remove(text);
history.add(text);
}
}
@Override
public void show(final Component invoker, final int x, final int y) {
if (history.size() == 0) return;
super.show(invoker, x, y);
}
@Override
protected void showPopup() {
if (history.size() == 0) {
firePopupMenuCanceled();
return;
}
this.removeAll();
LinkedList<String> list = new LinkedList<>(history);
Iterator<String> itr = list.descendingIterator();
while (itr.hasNext()) {
String item = itr.next();
add(new JMenuItem(new PlainAction(item, () -> textField.setText(item))));
}
super.showPopup();
}
}

80
src/main/java/com/weis/darklaf/components/tabframe/TabFrame.java → src/main/java/com/weis/darklaf/components/tabframe/JTabFrame.java

@ -24,6 +24,7 @@
package com.weis.darklaf.components.tabframe; package com.weis.darklaf.components.tabframe;
import com.weis.darklaf.components.alignment.Alignment; import com.weis.darklaf.components.alignment.Alignment;
import com.weis.darklaf.ui.tabframe.TabFrameTransferHandler;
import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -39,7 +40,7 @@ import java.util.Objects;
* *
* @author Jannis Weis * @author Jannis Weis
*/ */
public class TabFrame extends JComponent { public class JTabFrame extends JComponent {
private final JComponent bottomTabs = createTabContainer(); private final JComponent bottomTabs = createTabContainer();
private final JComponent topTabs = createTabContainer(); private final JComponent topTabs = createTabContainer();
@ -54,13 +55,17 @@ public class TabFrame extends JComponent {
private int tabSize = -1; private int tabSize = -1;
private int maxTabWidth = -1; private int maxTabWidth = -1;
private boolean inTransfer;
private Alignment transferAlign;
private int transferIndex;
private boolean dndEnabled;
/** /**
* Creates new {@link TabFrame}. * Creates new {@link JTabFrame}.
* A TabFrame displays one center component and multiple popups around * A TabFrame displays one center component and multiple popups around
* that can be toggles with a TabbedPane like tabArea along the border. * that can be toggles with a TabbedPane like tabArea along the border.
*/ */
public TabFrame() { public JTabFrame() {
super(); super();
updateUI(); updateUI();
add(content.getComponent()); add(content.getComponent());
@ -75,6 +80,7 @@ public class TabFrame extends JComponent {
popupLists[i] = new ArrayList<>(); popupLists[i] = new ArrayList<>();
} }
selectedIndices = new int[count]; selectedIndices = new int[count];
setDndEnabled(true);
} }
@Override @Override
@ -850,12 +856,48 @@ public class TabFrame extends JComponent {
return a; return a;
} }
public boolean isInTransfer() {
return inTransfer;
}
public void initTransfer(final Alignment a, final int index) {
getContentPane().getComponent().setEnabled(false);
this.inTransfer = true;
this.transferAlign = a;
this.transferIndex = index;
}
public void endTransfer() {
getContentPane().getComponent().setEnabled(true);
inTransfer = false;
transferAlign = null;
transferIndex = -10;
}
public TabFramePosition getTransferInfo() {
return new TabFramePosition(transferAlign, transferIndex);
}
public boolean isDndEnabled() {
return dndEnabled && getTransferHandler() instanceof TabFrameTransferHandler;
}
public void setDndEnabled(final boolean dndEnabled) {
var old = this.dndEnabled;
this.dndEnabled = dndEnabled;
if (getDropTarget() != null) {
getDropTarget().setActive(dndEnabled);
}
firePropertyChange("dndEnabled", old, dndEnabled);
}
/** /**
* This class represents a position inside the tabFrame. * This class represents a position inside the tabFrame.
*/ */
public static class TabFramePosition { public static class TabFramePosition {
private final Alignment a; private Alignment a;
private final int index; private int index;
private Point point;
@Contract(pure = true) @Contract(pure = true)
public TabFramePosition(final Alignment a, final int index) { public TabFramePosition(final Alignment a, final int index) {
@ -863,6 +905,29 @@ public class TabFrame extends JComponent {
this.index = index; this.index = index;
} }
@Contract(pure = true)
public TabFramePosition(final Alignment a, final int index, final Point p) {
this.a = a;
this.index = index;
this.point = p;
}
public void setAlignment(final Alignment a) {
this.a = a;
}
public void setIndex(final int index) {
this.index = index;
}
public Point getPoint() {
return point;
}
public void setPoint(final Point point) {
this.point = point;
}
/** /**
* The alignment position. * The alignment position.
* This specifies at what location the tab is placed. * This specifies at what location the tab is placed.
@ -881,5 +946,10 @@ public class TabFrame extends JComponent {
public int getIndex() { public int getIndex() {
return index; return index;
} }
@Override
public String toString() {
return "[" + a + "," + index + "]";
}
} }
} }

8
src/main/java/com/weis/darklaf/components/tabframe/PanelPopup.java

@ -30,7 +30,7 @@ import javax.swing.*;
import java.awt.*; import java.awt.*;
/** /**
* Popup Component for {@link TabFrame}. * Popup Component for {@link JTabFrame}.
* *
* @author Jannis Weis * @author Jannis Weis
* @since 2019 * @since 2019
@ -39,7 +39,7 @@ public class PanelPopup extends JPanel implements TabFramePopup {
private Component content; private Component content;
private boolean open; private boolean open;
private TabFrame parent; private JTabFrame parent;
private String title; private String title;
private Icon icon; private Icon icon;
private Alignment alignment; private Alignment alignment;
@ -137,12 +137,12 @@ public class PanelPopup extends JPanel implements TabFramePopup {
} }
@Override @Override
public TabFrame getTabFrame() { public JTabFrame getTabFrame() {
return parent; return parent;
} }
@Override @Override
public void setTabFrame(final TabFrame parent) { public void setTabFrame(final JTabFrame parent) {
var old = this.parent; var old = this.parent;
this.parent = parent; this.parent = parent;
firePropertyChange("tabFrame", old, parent); firePropertyChange("tabFrame", old, parent);

2
src/main/java/com/weis/darklaf/components/tabframe/TabFrameContentPane.java

@ -34,7 +34,7 @@ import java.awt.*;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
/** /**
* Content pane for {@link TabFrame}. * Content pane for {@link JTabFrame}.
* *
* @author Jannis Weis * @author Jannis Weis
*/ */

30
src/main/java/com/weis/darklaf/components/tabframe/TabFramePopup.java

@ -62,21 +62,21 @@ public interface TabFramePopup {
} }
/** /**
* Get the {{@link TabFrame}} this popup belongs to. * Get the {{@link JTabFrame}} this popup belongs to.
* *
* @return the {{@link TabFrame}}. * @return the {{@link JTabFrame}}.
*/ */
TabFrame getTabFrame(); JTabFrame getTabFrame();
/** /**
* Sets the {{@link TabFrame}} this popup belongs to. * Sets the {{@link JTabFrame}} this popup belongs to.
* *
* @param tabFrame the {{@link TabFrame}}. * @param tabFrame the {{@link JTabFrame}}.
*/ */
void setTabFrame(TabFrame tabFrame); void setTabFrame(JTabFrame tabFrame);
/** /**
* Gets the alignment position in the {{@link TabFrame}}. * Gets the alignment position in the {{@link JTabFrame}}.
* *
* @return the alignment position. * @return the alignment position.
*/ */
@ -90,20 +90,20 @@ public interface TabFramePopup {
int getIndex(); int getIndex();
/** /**
* Set the index of the popup. * Sets the alignment position in the {{@link JTabFrame}}. This method should only be called from {{@link
* This method should only be called from {{@link TabFrame}}. * JTabFrame}}.
* *
* @param index the index. * @param alignment the alignment position.
*/ */
void setIndex(int index); void setAlignment(Alignment alignment);
/** /**
* Sets the alignment position in the {{@link TabFrame}}. * Set the index of the popup.
* This method should only be called from {{@link TabFrame}}. * This method should only be called from {{@link JTabFrame}}.
* *
* @param alignment the alignment position. * @param index the index.
*/ */
void setAlignment(Alignment alignment); void setIndex(int index);
/** /**
* Open the popup. * Open the popup.

4
src/main/java/com/weis/darklaf/components/tabframe/TabFrameTab.java

@ -97,13 +97,13 @@ public interface TabFrameTab {
* *
* @return the TabFrame. * @return the TabFrame.
*/ */
TabFrame getTabFrame(); JTabFrame getTabFrame();
/** /**
* Set the tab frame this tab currently belongs to. * Set the tab frame this tab currently belongs to.
* *
* @param tabFrame the TabFrame. * @param tabFrame the TabFrame.
*/ */
void setTabFrame(TabFrame tabFrame); void setTabFrame(JTabFrame tabFrame);
} }

8
src/main/java/com/weis/darklaf/components/tabframe/TabFrameTabContainer.java

@ -31,14 +31,14 @@ import java.awt.*;
public class TabFrameTabContainer extends JPanel implements TabFrameTab { public class TabFrameTabContainer extends JPanel implements TabFrameTab {
protected final TabFrameTab oldTab; protected final TabFrameTab oldTab;
private TabFrame parent; private JTabFrame parent;
private Component content; private Component content;
private Alignment orientation; private Alignment orientation;
private boolean selected; private boolean selected;
private int index; private int index;
private int accelerator; private int accelerator;
public TabFrameTabContainer(final TabFrame parent, final JComponent content, final TabFrameTab oldTab, public TabFrameTabContainer(final JTabFrame parent, final JComponent content, final TabFrameTab oldTab,
final Alignment alignment, final int index) { final Alignment alignment, final int index) {
super(new BorderLayout()); super(new BorderLayout());
this.parent = parent; this.parent = parent;
@ -140,12 +140,12 @@ public class TabFrameTabContainer extends JPanel implements TabFrameTab {
} }
@Override @Override
public TabFrame getTabFrame() { public JTabFrame getTabFrame() {
return parent; return parent;
} }
@Override @Override
public void setTabFrame(final TabFrame parent) { public void setTabFrame(final JTabFrame parent) {
var old = this.parent; var old = this.parent;
this.parent = parent; this.parent = parent;
firePropertyChange("tabFrame", old, parent); firePropertyChange("tabFrame", old, parent);

12
src/main/java/com/weis/darklaf/components/tabframe/TabFrameTabLabel.java

@ -34,13 +34,13 @@ import java.awt.*;
import java.util.Objects; import java.util.Objects;
/** /**
* Tab Component for {@link TabFrame}. * Tab Component for {@link JTabFrame}.
* *
* @author Jannis Weis * @author Jannis Weis
*/ */
public class TabFrameTabLabel extends JLabel implements TabFrameTab { public class TabFrameTabLabel extends JLabel implements TabFrameTab {
private TabFrame parent; private JTabFrame parent;
private Alignment orientation; private Alignment orientation;
private String title; private String title;
private boolean selected; private boolean selected;
@ -48,7 +48,7 @@ public class TabFrameTabLabel extends JLabel implements TabFrameTab {
private int index; private int index;
/** /**
* Create new TabComponent for the frame of {@link TabFrame}. * Create new TabComponent for the frame of {@link JTabFrame}.
* *
* @param title the title. * @param title the title.
* @param icon the icon. * @param icon the icon.
@ -57,7 +57,7 @@ public class TabFrameTabLabel extends JLabel implements TabFrameTab {
* @param parent the parent layout manager. * @param parent the parent layout manager.
*/ */
public TabFrameTabLabel(final String title, final Icon icon, final Alignment orientation, public TabFrameTabLabel(final String title, final Icon icon, final Alignment orientation,
final int index, @NotNull final TabFrame parent) { final int index, @NotNull final JTabFrame parent) {
this.index = index; this.index = index;
this.accelerator = -1; this.accelerator = -1;
this.parent = parent; this.parent = parent;
@ -131,12 +131,12 @@ public class TabFrameTabLabel extends JLabel implements TabFrameTab {
} }
@Override @Override
public TabFrame getTabFrame() { public JTabFrame getTabFrame() {
return parent; return parent;
} }
@Override @Override
public void setTabFrame(final TabFrame parent) { public void setTabFrame(final JTabFrame parent) {
var old = this.parent; var old = this.parent;
this.parent = parent; this.parent = parent;
firePropertyChange("tabFrame", old, parent); firePropertyChange("tabFrame", old, parent);

29
src/main/java/com/weis/darklaf/components/tabframe/TabFrameUI.java

@ -23,9 +23,36 @@
*/ */
package com.weis.darklaf.components.tabframe; package com.weis.darklaf.components.tabframe;
import com.weis.darklaf.components.alignment.Alignment;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import java.awt.*;
public abstract class TabFrameUI extends ComponentUI { public abstract class TabFrameUI extends ComponentUI {
public abstract int getTabSize(TabFrame tabFrame); public abstract int getTabSize(JTabFrame tabFrame);
public abstract void clearTargetIndicator();
public abstract void clearSourceIndicator();
public abstract Color getDragBorderColor();
public abstract void setSourceIndicator(Alignment a, int tabIndex);
public abstract void setTargetIndicator(Alignment a, int tabIndex);
public abstract JTabFrame.TabFramePosition getTabIndexAt(JTabFrame tabFrame, Point p);
public abstract JTabFrame.TabFramePosition getNearestTabIndexAt(JTabFrame tabFrame, Point p);
public abstract void setDropSize(final int width, final int height);
public abstract int getTabWidth(JTabFrame tabFrame, Alignment a, int index);
public abstract int getTabHeight(JTabFrame tabFrame, Alignment a, int index);
public abstract Rectangle getTabContainerBounds(JTabFrame tabFrame, Alignment a);
public abstract JTabFrame.TabFramePosition getDropPosition(JTabFrame tabFrame, Point p);
} }

2
src/main/java/com/weis/darklaf/components/tabframe/TabbedPopup.java

@ -30,7 +30,7 @@ import java.util.Collection;
import java.util.List; import java.util.List;
/** /**
* Tabbed Popup Component for {@link TabFrame}. * Tabbed Popup Component for {@link JTabFrame}.
* *
* @author Jannis Weis * @author Jannis Weis
*/ */

40
src/main/java/com/weis/darklaf/components/text/SearchEvent.java

@ -0,0 +1,40 @@
/*
* MIT License
*
* Copyright (c) 2019 Jannis Weis
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.weis.darklaf.components.text;
import java.awt.event.ActionEvent;
public class SearchEvent extends ActionEvent {
private final String text;
public SearchEvent(final Object source, final int id, final String command, final String text) {
super(source, id, command);
this.text = text;
}
public String getText() {
return text;
}
}

31
src/main/java/com/weis/darklaf/components/text/SearchListener.java

@ -0,0 +1,31 @@
/*
* MIT License
*
* Copyright (c) 2019 Jannis Weis
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.weis.darklaf.components.text;
import java.util.EventListener;
public interface SearchListener extends EventListener {
void searchPerformed(final SearchEvent e);
}

119
src/main/java/com/weis/darklaf/components/text/SearchTextField.java

@ -0,0 +1,119 @@
/*
* MIT License
*
* Copyright (c) 2019 Jannis Weis
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.weis.darklaf.components.text;
import javax.swing.*;
import javax.swing.text.Document;
public class SearchTextField extends JTextField {
public static final int SEARCH = 0;
/**
* Constructs a new <code>TextField</code>. A default model is created, the initial string is <code>null</code>,
* and the number of columns is set to 0.
*/
public SearchTextField() {
this(null, null, 0);
}
/**
* Constructs a new <code>JTextField</code> that uses the given text storage model and the given number of columns.
* This is the constructor through which the other constructors feed. If the document is <code>null</code>, a
* default model is created.
*
* @param doc the text storage to use; if this is <code>null</code>, a default will be provided by calling the
* <code>createDefaultModel</code> method
* @param text the initial string to display, or <code>null</code>
* @param columns the number of columns to use to calculate the preferred width &gt;= 0; if <code>columns</code> is
* set to zero, the preferred width will be whatever naturally results from the component
* implementation
* @throws IllegalArgumentException if <code>columns</code> &lt; 0
*/
public SearchTextField(final Document doc, final String text, final int columns) {
super(doc, text, columns);
putClientProperty("JTextField.variant", "search");
addActionListener(e -> {
var list = listenerList.getListeners(SearchListener.class);
var evt = new SearchEvent(SearchTextField.this, SEARCH, "search", getText());
for (var listener : list) {
if (listener != null) {
listener.searchPerformed(evt);
}
}
});
}
/**
* Constructs a new <code>TextField</code> initialized with the specified text. A default model is created and the
* number of columns is 0.
*
* @param text the text to be displayed, or <code>null</code>
*/
public SearchTextField(final String text) {
this(null, text, 0);
}
/**
* Constructs a new empty <code>TextField</code> with the specified number of columns. A default model is created
* and the initial string is set to
* <code>null</code>.
*
* @param columns the number of columns to use to calculate the preferred width; if columns is set to zero, the
* preferred width will be whatever naturally results from the component implementation
*/
public SearchTextField(final int columns) {
this(null, null, columns);
}
/**
* Constructs a new <code>TextField</code> initialized with the specified text and columns. A default model is
* created.
*
* @param text the text to be displayed, or <code>null</code>
* @param columns the number of columns to use to calculate the preferred width; if columns is set to zero, the
* preferred width will be whatever naturally results from the component implementation
*/
public SearchTextField(final String text, final int columns) {
this(null, text, columns);
}
/**
* Add a {@link SearchListener} to this search text field.
*
* @param listener the listen to add.
*/
public void addSearchListener(final SearchListener listener) {
listenerList.add(SearchListener.class, listener);
}
/**
* Remove a {@link SearchListener} from this search text field.
*
* @param listener the listener to remove
*/
public void removeSearchListener(final SearchListener listener) {
listenerList.remove(SearchListener.class, listener);
}
}

174
src/main/java/com/weis/darklaf/components/text/SearchTextFieldWithHistory.java

@ -0,0 +1,174 @@
/*
* MIT License
*
* Copyright (c) 2019 Jannis Weis
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.weis.darklaf.components.text;
import javax.swing.text.Document;
import java.util.List;
/**
* {@link SearchTextField} that has a popup that displays the search history. A search entry is added
*
* @author Jannis Weis
*/
public class SearchTextFieldWithHistory extends SearchTextField {
protected TextFieldHistoryPopup history;
/**
* Constructs a new <code>TextField</code>. A default model is created, the initial string is <code>null</code>,
* and the number of columns is set to 0.
*/
public SearchTextFieldWithHistory() {
this(null, null, 0);
}
/**
* Constructs a new <code>JTextField</code> that uses the given text storage model and the given number of columns.
* This is the constructor through which the other constructors feed. If the document is <code>null</code>, a
* default model is created.
*
* @param doc the text storage to use; if this is <code>null</code>, a default will be provided by calling the
* <code>createDefaultModel</code> method
* @param text the initial string to display, or <code>null</code>
* @param columns the number of columns to use to calculate the preferred width &gt;= 0; if <code>columns</code> is
* set to zero, the preferred width will be whatever naturally results from the component
* implementation
* @throws IllegalArgumentException if <code>columns</code> &lt; 0
*/
public SearchTextFieldWithHistory(final Document doc, final String text, final int columns) {
super(doc, text, columns);
history = new TextFieldHistoryPopup(this, 100, 800);
putClientProperty("JTextField.Search.FindPopup", history);
}
/**
* Constructs a new <code>TextField</code> initialized with the specified text. A default model is created and the
* number of columns is 0.
*
* @param text the text to be displayed, or <code>null</code>
*/
public SearchTextFieldWithHistory(final String text) {
this(null, text, 0);
}
/**
* Constructs a new empty <code>TextField</code> with the specified number of columns. A default model is created
* and the initial string is set to
* <code>null</code>.
*
* @param columns the number of columns to use to calculate the preferred width; if columns is set to zero, the
* preferred width will be whatever naturally results from the component implementation
*/
public SearchTextFieldWithHistory(final int columns) {
this(null, null, columns);
}
/**
* Constructs a new <code>TextField</code> initialized with the specified text and columns. A default model is
* created.
*
* @param text the text to be displayed, or <code>null</code>
* @param columns the number of columns to use to calculate the preferred width; if columns is set to zero, the
* preferred width will be whatever naturally results from the component implementation
*/
public SearchTextFieldWithHistory(final String text, final int columns) {
this(null, text, columns);
}
/**
* Set the maximum height of the popup. If the size is larger than the specified maximum height the content will be
* wrapped inside a scroll pane.
* <p>
* Note: A value of <= 0 indicates that the height should not be limited.
*
* @param maximumHeight the max height to use.
*/
public void setMaximumHeight(final int maximumHeight) {
history.setMaxHeight(maximumHeight);
}
/**
* Get the history as a list.
*
* @return the history.
*/
public List<String> getHistory() {
return history.getHistory();
}
/**
* Clear all entries from the history.
*/
public void clearHistory() {
history.clearHistory();
}
/**
* Add entry to the history. If the size is greater than the capacity the oldest entry will be deleted.
*
* @param entry the entry to add.
* @see #getLength() getLength
* @see #setCapacity(int) setCapacity
* @see #getCapacity() getCapacity
*/
public void addEntry(final String entry) {
history.addEntry(entry);
}
/**
* Get the capacity of the history.
*
* @return the capacity.
* @see #setCapacity(int) setCapacity()
*/
public int getCapacity() {
return history.getCapacity();
}
/**
* Set the capacity of the history. If the size grows larger than the capacity the oldest entry will be deleted.
*
* @param capacity the capacity.
* @throws IllegalArgumentException if capacity < 0
*/
public void setCapacity(final int capacity) throws IllegalArgumentException {
history.setCapacity(capacity);
}
/**
* Get the current length of the history.
*
* @return the current length of the history.
*/
public int getLength() {
return history.getLength();
}
public void setHistoryLength(final int length) {
if (length < 0) throw new IllegalArgumentException("History can't have negative size");
if (length == 0) {
putClientProperty("JTextField.Search.FindPopup", null);
}
}
}

157
src/main/java/com/weis/darklaf/components/text/TextFieldHistoryPopup.java

@ -0,0 +1,157 @@
/*
* MIT License
*
* Copyright (c) 2019 Jannis Weis
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.weis.darklaf.components.text;
import com.weis.darklaf.components.ScrollPopupMenu;
import com.weis.darklaf.decorators.PlainAction;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author Jannis Weis
*/
public class TextFieldHistoryPopup extends ScrollPopupMenu implements SearchListener {
private final Set<String> history;
private final JTextField textField;
private int capacity;
/**
* Create a search popup Menu.
*
* @param textField the text field.
* @param capacity the length of the history.
* @param maxH maximum height.
*/
public TextFieldHistoryPopup(@NotNull final SearchTextField textField, final int capacity, final int maxH) {
super(maxH);
this.textField = textField;
textField.addSearchListener(this);
setCapacity(capacity);
this.history = Collections.newSetFromMap(new LinkedHashMap<>() {
protected boolean removeEldestEntry(final Map.Entry<String, Boolean> eldest) {
return size() > capacity;
}
});
}
/**
* Get the history as a list.
*
* @return the history.
*/
public List<String> getHistory() {
return new ArrayList<>(history);
}
/**
* Get the capacity of the history.
*
* @return the capacity.
* @see #setCapacity(int) setCapacity()
*/
public int getCapacity() {
return capacity;
}
/**
* Set the capacity of the history. If the size grows larger than the capacity the oldest entry will be deleted.
*
* @param capacity the capacity.
* @throws IllegalArgumentException if capacity < 0
*/
public void setCapacity(final int capacity) throws IllegalArgumentException {
if (capacity < 0) throw new IllegalArgumentException("Negative history size is not supported");
this.capacity = capacity;
}
/**
* Get the current length of the history.
*
* @return the current length of the history.
*/
public int getLength() {
return history.size();
}
@Override
public void searchPerformed(@NotNull final SearchEvent e) {
var text = e.getText();
if (!text.isBlank()) {
addEntry(text);
}
}
@Override
public void show(final Component invoker, final int x, final int y) {
if (history.size() == 0) return;
super.show(invoker, x, y);
}
@Override
protected void showPopup() {
if (history.size() == 0) {
firePopupMenuCanceled();
return;
}
this.removeAll();
LinkedList<String> list = new LinkedList<>(history);
Iterator<String> itr = list.descendingIterator();
while (itr.hasNext()) {
String item = itr.next();
add(new JMenuItem(new PlainAction(item, () -> textField.setText(item))));
}
super.showPopup();
}
/**
* Add entry to the history. If the size is greater than the capacity the oldest entry will be deleted.
*
* @param entry the entry to add.
* @see #getLength() getLength
* @see #setCapacity(int) setCapacity
* @see #getCapacity() getCapacity
*/
public void addEntry(final String entry) {
history.remove(entry);
history.add(entry);
}
/**
* Clear all entries from the history.
*/
public void clearHistory() {
history.clear();
}
}

1
src/main/java/com/weis/darklaf/components/tooltip/ToolTipContext.java

@ -429,6 +429,7 @@ public class ToolTipContext implements ToolTipListener {
if (valid && !updatePosition if (valid && !updatePosition
&& lastPos != null && lastPos != null
&& !Objects.equals(rect, lastRect)) { && !Objects.equals(rect, lastRect)) {
System.out.println("here");
return lastPos; return lastPos;
} }
getToolTip().setTipText(c.getToolTipText(event)); getToolTip().setTipText(c.getToolTipText(event));

2
src/main/java/com/weis/darklaf/components/Insets2D.java → src/main/java/com/weis/darklaf/components/uiresource/Insets2D.java

@ -21,7 +21,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. * SOFTWARE.
*/ */
package com.weis.darklaf.components; package com.weis.darklaf.components.uiresource;
import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;

2
src/main/java/com/weis/darklaf/components/JLabelUIResource.java → src/main/java/com/weis/darklaf/components/uiresource/JLabelUIResource.java

@ -21,7 +21,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. * SOFTWARE.
*/ */
package com.weis.darklaf.components; package com.weis.darklaf.components.uiresource;
import javax.swing.*; import javax.swing.*;
import javax.swing.plaf.UIResource; import javax.swing.plaf.UIResource;

2
src/main/java/com/weis/darklaf/components/JPanelUIResource.java → src/main/java/com/weis/darklaf/components/uiresource/JPanelUIResource.java

@ -21,7 +21,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. * SOFTWARE.
*/ */
package com.weis.darklaf.components; package com.weis.darklaf.components.uiresource;
import javax.swing.*; import javax.swing.*;
import javax.swing.plaf.UIResource; import javax.swing.plaf.UIResource;

2
src/main/java/com/weis/darklaf/components/UIResourceWrapper.java → src/main/java/com/weis/darklaf/components/uiresource/UIResourceWrapper.java

@ -21,7 +21,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. * SOFTWARE.
*/ */
package com.weis.darklaf.components; package com.weis.darklaf.components.uiresource;
import javax.swing.border.Border; import javax.swing.border.Border;
import java.awt.*; import java.awt.*;

2
src/main/java/com/weis/darklaf/ui/colorchooser/DarkColorChooserPanel.java

@ -201,7 +201,6 @@ public class DarkColorChooserPanel extends AbstractColorChooserPanel implements
protected void update() { protected void update() {
try { try {
if (isChanging) return; if (isChanging) return;
System.out.println("here");
var hexStr = String.format("%1$-" + 8 + "s", field.getText()).replaceAll(" ", "F"); var hexStr = String.format("%1$-" + 8 + "s", field.getText()).replaceAll(" ", "F");
var alpha = isColorTransparencySelectionEnabled() var alpha = isColorTransparencySelectionEnabled()
? Integer.valueOf(hexStr.substring(6, 8), 16) : 255; ? Integer.valueOf(hexStr.substring(6, 8), 16) : 255;
@ -210,7 +209,6 @@ public class DarkColorChooserPanel extends AbstractColorChooserPanel implements
Integer.valueOf(hexStr.substring(2, 4), 16), Integer.valueOf(hexStr.substring(2, 4), 16),
Integer.valueOf(hexStr.substring(4, 6), 16), Integer.valueOf(hexStr.substring(4, 6), 16),
alpha); alpha);
System.out.println(c);
colorWheelPanel.setColor(c, textHex); colorWheelPanel.setColor(c, textHex);
} catch (NumberFormatException | IndexOutOfBoundsException ignore) {} } catch (NumberFormatException | IndexOutOfBoundsException ignore) {}
} }

13
src/main/java/com/weis/darklaf/ui/tabbedpane/DarkTabbedPaneUI.java

@ -1,6 +1,6 @@
package com.weis.darklaf.ui.tabbedpane; package com.weis.darklaf.ui.tabbedpane;
import com.weis.darklaf.components.UIResourceWrapper; import com.weis.darklaf.components.uiresource.UIResourceWrapper;
import com.weis.darklaf.util.DarkUIUtil; import com.weis.darklaf.util.DarkUIUtil;
import com.weis.darklaf.util.GraphicsContext; import com.weis.darklaf.util.GraphicsContext;
import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Contract;
@ -20,7 +20,7 @@ import java.util.TooManyListenersException;
*/ */
public class DarkTabbedPaneUI extends DarkTabbedPaneUIBridge { public class DarkTabbedPaneUI extends DarkTabbedPaneUIBridge {
protected static final TabbedPaneTransferHandler TRANSFER_HANDLER = new TabbedPaneTransferHandler(); protected static final TabbedPaneTransferHandler TRANSFER_HANDLER = new TabbedPaneTransferHandler.UIResource();
protected final FocusListener focusListener = new FocusListener() { protected final FocusListener focusListener = new FocusListener() {
@Override @Override
public void focusGained(final FocusEvent e) { public void focusGained(final FocusEvent e) {
@ -110,8 +110,15 @@ public class DarkTabbedPaneUI extends DarkTabbedPaneUIBridge {
@Override @Override
public void uninstallUI(final JComponent c) { public void uninstallUI(final JComponent c) {
super.uninstallUI(c);
scrollableTabSupport = null; scrollableTabSupport = null;
if (tabPane.getTransferHandler() instanceof TabbedPaneTransferHandler.UIResource) {
tabPane.setTransferHandler(null);
if (tabPane.getDropTarget() != null) {
tabPane.getDropTarget().removeDropTargetListener(TRANSFER_HANDLER);
tabPane.getDropTarget().setActive(false);
}
}
super.uninstallUI(c);
} }
@Override @Override

4
src/main/java/com/weis/darklaf/ui/tabbedpane/TabbedPaneTransferHandler.java

@ -450,4 +450,8 @@ public class TabbedPaneTransferHandler extends TransferHandler implements DropTa
currentTransferable = null; currentTransferable = null;
} }
} }
public static class UIResource extends TabbedPaneTransferHandler {
}
} }

24
src/main/java/com/weis/darklaf/ui/tabframe/DarkPanelPopupUI.java

@ -23,12 +23,12 @@
*/ */
package com.weis.darklaf.ui.tabframe; package com.weis.darklaf.ui.tabframe;
import com.weis.darklaf.components.JLabelUIResource;
import com.weis.darklaf.components.alignment.Alignment; import com.weis.darklaf.components.alignment.Alignment;
import com.weis.darklaf.components.border.MutableLineBorder; import com.weis.darklaf.components.border.MutableLineBorder;
import com.weis.darklaf.components.tabframe.JTabFrame;
import com.weis.darklaf.components.tabframe.PanelPopup; import com.weis.darklaf.components.tabframe.PanelPopup;
import com.weis.darklaf.components.tabframe.TabFrame;
import com.weis.darklaf.components.tooltip.ToolTipContext; import com.weis.darklaf.components.tooltip.ToolTipContext;
import com.weis.darklaf.components.uiresource.JLabelUIResource;
import com.weis.darklaf.ui.panel.DarkPanelUI; import com.weis.darklaf.ui.panel.DarkPanelUI;
import com.weis.darklaf.util.DarkUIUtil; import com.weis.darklaf.util.DarkUIUtil;
import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Contract;
@ -250,19 +250,19 @@ public class DarkPanelPopupUI extends DarkPanelUI implements PropertyChangeListe
label.setIcon((Icon) evt.getNewValue()); label.setIcon((Icon) evt.getNewValue());
label.repaint(); label.repaint();
} else if ("visibleTab".equals(key)) { } else if ("visibleTab".equals(key)) {
if (evt.getNewValue() instanceof TabFrame.TabFramePosition) { if (evt.getNewValue() instanceof JTabFrame.TabFramePosition) {
if (((TabFrame.TabFramePosition) evt.getNewValue()).getAlignment() == popupComponent.getAlignment()) { if (((JTabFrame.TabFramePosition) evt.getNewValue()).getAlignment() == popupComponent.getAlignment()) {
updateBorder(true); updateBorder(true);
} }
} }
} else if ("tabFrame".equals(key)) { } else if ("tabFrame".equals(key)) {
var oldVal = evt.getOldValue(); var oldVal = evt.getOldValue();
var newVal = evt.getNewValue(); var newVal = evt.getNewValue();
if (oldVal instanceof TabFrame) { if (oldVal instanceof JTabFrame) {
((TabFrame) oldVal).removePropertyChangeListener(this); ((JTabFrame) oldVal).removePropertyChangeListener(this);
} }
if (newVal instanceof TabFrame) { if (newVal instanceof JTabFrame) {
((TabFrame) newVal).addPropertyChangeListener(this); ((JTabFrame) newVal).addPropertyChangeListener(this);
} }
} else if ("peerInsets".equals(key)) { } else if ("peerInsets".equals(key)) {
updateBorder(false); updateBorder(false);
@ -289,8 +289,10 @@ public class DarkPanelPopupUI extends DarkPanelUI implements PropertyChangeListe
popupComponent.doLayout(); popupComponent.doLayout();
popupComponent.repaint(); popupComponent.repaint();
if (notifyPeer) { if (notifyPeer) {
var peer = tabFrame.getPopupComponentAt(tabFrame.getPeer(popupComponent.getAlignment())); try {
peer.firePropertyChange("peerInsets", 0, 1); var peer = tabFrame.getPopupComponentAt(tabFrame.getPeer(popupComponent.getAlignment()));
peer.firePropertyChange("peerInsets", 0, 1);
} catch (IndexOutOfBoundsException ignored) {/*may happen during transfer*/}
} }
} }
} }
@ -353,7 +355,7 @@ public class DarkPanelPopupUI extends DarkPanelUI implements PropertyChangeListe
public void eventDispatched(@NotNull final AWTEvent event) { public void eventDispatched(@NotNull final AWTEvent event) {
if (event.getID() == FocusEvent.FOCUS_GAINED) { if (event.getID() == FocusEvent.FOCUS_GAINED) {
var focusOwner = FocusManager.getCurrentManager().getFocusOwner(); var focusOwner = FocusManager.getCurrentManager().getFocusOwner();
if (focusOwner instanceof TabFrame) return; if (focusOwner instanceof JTabFrame) return;
if (focusOwner instanceof JRootPane) return; if (focusOwner instanceof JRootPane) return;
boolean focus = DarkUIUtil.hasFocus(popupComponent); boolean focus = DarkUIUtil.hasFocus(popupComponent);
setHeaderBackground(focus); setHeaderBackground(focus);

3
src/main/java/com/weis/darklaf/ui/tabframe/DarkTabFrameComponentPopupMenu.java

@ -30,10 +30,11 @@ import com.weis.darklaf.icons.EmptyIcon;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import javax.swing.*; import javax.swing.*;
import javax.swing.plaf.UIResource;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
public class DarkTabFrameComponentPopupMenu extends JXPopupMenu implements PropertyChangeListener { public class DarkTabFrameComponentPopupMenu extends JXPopupMenu implements PropertyChangeListener, UIResource {
private final TabFrameTab tab; private final TabFrameTab tab;
private JMenuItem[] actions; private JMenuItem[] actions;

130
src/main/java/com/weis/darklaf/ui/tabframe/DarkTabFrameTabContainerUI.java

@ -23,7 +23,7 @@
*/ */
package com.weis.darklaf.ui.tabframe; package com.weis.darklaf.ui.tabframe;
import com.weis.darklaf.components.tabframe.TabFrame; import com.weis.darklaf.components.tabframe.JTabFrame;
import com.weis.darklaf.components.tabframe.TabFrameTabContainer; import com.weis.darklaf.components.tabframe.TabFrameTabContainer;
import com.weis.darklaf.decorators.HoverListener; import com.weis.darklaf.decorators.HoverListener;
import com.weis.darklaf.ui.panel.DarkPanelUI; import com.weis.darklaf.ui.panel.DarkPanelUI;
@ -38,6 +38,7 @@ import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter; import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.awt.event.MouseListener; import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
@ -53,6 +54,7 @@ public class DarkTabFrameTabContainerUI extends DarkPanelUI implements PropertyC
} }
} }
}; };
private MouseMotionListener dragListener;
private HoverListener hoverListener; private HoverListener hoverListener;
private Color selectedColor; private Color selectedColor;
private Color hoverColor; private Color hoverColor;
@ -73,90 +75,50 @@ public class DarkTabFrameTabContainerUI extends DarkPanelUI implements PropertyC
} }
protected void installListeners() { protected void installListeners() {
dragListener = new TabDragListener(tabContainer);
hoverListener = new HoverListener(tabContainer); hoverListener = new HoverListener(tabContainer);
tabContainer.addMouseListener(hoverListener); tabContainer.addMouseListener(hoverListener);
tabContainer.addPropertyChangeListener(this); tabContainer.addPropertyChangeListener(this);
tabContainer.addMouseListener(mouseListener); tabContainer.addMouseListener(mouseListener);
tabContainer.addMouseMotionListener(dragListener);
var cont = tabContainer.getContent(); var cont = tabContainer.getContent();
if (cont != null) { if (cont != null) {
cont.addMouseListener(hoverListener); cont.addMouseListener(hoverListener);
cont.addMouseListener(mouseListener); cont.addMouseListener(mouseListener);
cont.addMouseMotionListener(dragListener);
} }
} }
protected void installAccelerator(final TabFrame tabFrame) {
if (tabFrame == null) return;
int acc = tabContainer.getAccelerator();
if (acc < 0) return;
tabFrame.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
.put(KeyStroke.getKeyStroke(UIManager.getString("TabFrame.acceleratorKeyCode") + " " + acc),
"accelerator_" + acc);
tabFrame.getActionMap().put("accelerator_" + acc, createAcceleratorAction(tabFrame));
}
protected Action createAcceleratorAction(final TabFrame tabFrame) {
return new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
var a = tabContainer.getOrientation();
var index = tabContainer.getIndex();
if (!tabContainer.isSelected()) {
tabFrame.toggleTab(a, index, true);
} else {
var popup = tabFrame.getPopupComponentAt(a, index);
if (!DarkUIUtil.hasFocus(popup)) {
popup.requestFocus();
} else {
tabFrame.toggleTab(a, index, false);
}
}
}
};
}
@Override @Override
public void uninstallUI(final JComponent c) { public void uninstallUI(final JComponent c) {
super.uninstallUI(c); super.uninstallUI(c);
uninstallListeners();
uninstallAccelerator(tabContainer.getTabFrame());
tabContainer = null;
}
protected void uninstallListeners() {
tabContainer.removeMouseListener(hoverListener); tabContainer.removeMouseListener(hoverListener);
tabContainer.removeMouseListener(mouseListener); tabContainer.removeMouseListener(mouseListener);
tabContainer.removePropertyChangeListener(this); tabContainer.removePropertyChangeListener(this);
tabContainer.removeMouseMotionListener(dragListener);
var cont = tabContainer.getContent(); var cont = tabContainer.getContent();
if (cont != null) { if (cont != null) {
cont.removeMouseListener(hoverListener); cont.removeMouseListener(hoverListener);
cont.removeMouseListener(mouseListener); cont.removeMouseListener(mouseListener);
cont.removeMouseMotionListener(dragListener);
} }
dragListener = null;
hoverListener = null; hoverListener = null;
uninstallAccelerator(tabContainer.getTabFrame());
tabContainer = null;
} }
protected void installDefaults(final JPanel p) { protected void uninstallAccelerator(final JTabFrame tabFrame) {
super.installDefaults(p);
tabContainer.setOpaque(true);
selectedColor = UIManager.getColor("TabFrameTab.selectedBackground");
hoverColor = UIManager.getColor("TabFrameTab.hoverBackground");
}
protected void uninstallAccelerator(final TabFrame tabFrame) {
if (tabFrame == null) return; if (tabFrame == null) return;
int acc = tabContainer.getAccelerator(); int acc = tabContainer.getAccelerator();
String accAction = "accelerator_" + acc; String accAction = "accelerator_" + acc;
tabFrame.getActionMap().remove(accAction); tabFrame.getActionMap().remove(accAction);
} }
@Override
public void paint(@NotNull final Graphics g, @NotNull final JComponent c) {
g.setColor(getBackground(tabContainer));
g.fillRect(0, 0, c.getWidth(), c.getHeight());
super.paint(g, c);
}
public Color getBackground(@NotNull final TabFrameTabContainer tab) {
return tab.isSelected()
? selectedColor
: hoverListener.isHover() ? hoverColor : tab.getBackground();
}
@Override @Override
public void propertyChange(@NotNull final PropertyChangeEvent evt) { public void propertyChange(@NotNull final PropertyChangeEvent evt) {
var key = evt.getPropertyName(); var key = evt.getPropertyName();
@ -166,10 +128,12 @@ public class DarkTabFrameTabContainerUI extends DarkPanelUI implements PropertyC
if (oldVal instanceof Component) { if (oldVal instanceof Component) {
((Component) oldVal).removeMouseListener(mouseListener); ((Component) oldVal).removeMouseListener(mouseListener);
((Component) oldVal).removeMouseListener(hoverListener); ((Component) oldVal).removeMouseListener(hoverListener);
((Component) oldVal).removeMouseMotionListener(dragListener);
} }
if (newVal instanceof Component) { if (newVal instanceof Component) {
((Component) newVal).addMouseListener(mouseListener); ((Component) newVal).addMouseListener(mouseListener);
((Component) newVal).addMouseListener(hoverListener); ((Component) newVal).addMouseListener(hoverListener);
((Component) newVal).addMouseMotionListener(dragListener);
} }
} else if ("selected".equals(key)) { } else if ("selected".equals(key)) {
if (tabContainer == null) return; if (tabContainer == null) return;
@ -179,12 +143,62 @@ public class DarkTabFrameTabContainerUI extends DarkPanelUI implements PropertyC
uninstallAccelerator(tabContainer.getTabFrame()); uninstallAccelerator(tabContainer.getTabFrame());
installAccelerator(tabContainer.getTabFrame()); installAccelerator(tabContainer.getTabFrame());
} else if ("tabFrame".equals(key)) { } else if ("tabFrame".equals(key)) {
if (evt.getOldValue() instanceof TabFrame) { if (evt.getOldValue() instanceof JTabFrame) {
uninstallAccelerator((TabFrame) evt.getOldValue()); uninstallAccelerator((JTabFrame) evt.getOldValue());
} }
if (evt.getNewValue() instanceof TabFrame) { if (evt.getNewValue() instanceof JTabFrame) {
installAccelerator((TabFrame) evt.getNewValue()); installAccelerator((JTabFrame) evt.getNewValue());
} }
} }
} }
protected void installDefaults(final JPanel p) {
super.installDefaults(p);
tabContainer.setOpaque(true);
selectedColor = UIManager.getColor("TabFrameTab.selectedBackground");
hoverColor = UIManager.getColor("TabFrameTab.hoverBackground");
}
protected void installAccelerator(final JTabFrame tabFrame) {
if (tabFrame == null) return;
int acc = tabContainer.getAccelerator();
if (acc < 0) return;
tabFrame.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
.put(KeyStroke.getKeyStroke(UIManager.getString("TabFrame.acceleratorKeyCode") + " " + acc),
"accelerator_" + acc);
tabFrame.getActionMap().put("accelerator_" + acc, createAcceleratorAction(tabFrame));
}
@Override
public void paint(@NotNull final Graphics g, @NotNull final JComponent c) {
g.setColor(getBackground(tabContainer));
g.fillRect(0, 0, c.getWidth(), c.getHeight());
super.paint(g, c);
}
public Color getBackground(@NotNull final TabFrameTabContainer tab) {
return tab.isSelected()
? selectedColor
: hoverListener.isHover() ? hoverColor : tab.getBackground();
}
protected Action createAcceleratorAction(final JTabFrame tabFrame) {
return new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
var a = tabContainer.getOrientation();
var index = tabContainer.getIndex();
if (!tabContainer.isSelected()) {
tabFrame.toggleTab(a, index, true);
} else {
var popup = tabFrame.getPopupComponentAt(a, index);
if (!DarkUIUtil.hasFocus(popup)) {
popup.requestFocus();
} else {
tabFrame.toggleTab(a, index, false);
}
}
}
};
}
} }

90
src/main/java/com/weis/darklaf/ui/tabframe/DarkTabFrameTabLabelUI.java

@ -24,7 +24,7 @@
package com.weis.darklaf.ui.tabframe; package com.weis.darklaf.ui.tabframe;
import com.weis.darklaf.components.alignment.Alignment; import com.weis.darklaf.components.alignment.Alignment;
import com.weis.darklaf.components.tabframe.TabFrame; import com.weis.darklaf.components.tabframe.JTabFrame;
import com.weis.darklaf.components.tabframe.TabFrameTabLabel; import com.weis.darklaf.components.tabframe.TabFrameTabLabel;
import com.weis.darklaf.decorators.HoverListener; import com.weis.darklaf.decorators.HoverListener;
import com.weis.darklaf.icons.RotatableIcon; import com.weis.darklaf.icons.RotatableIcon;
@ -36,6 +36,7 @@ import sun.swing.SwingUtilities2;
import javax.swing.*; import javax.swing.*;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicHTML; import javax.swing.plaf.basic.BasicHTML;
import javax.swing.text.View; import javax.swing.text.View;
import java.awt.*; import java.awt.*;
@ -43,6 +44,7 @@ import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter; import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.awt.event.MouseListener; import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
@ -51,13 +53,14 @@ public class DarkTabFrameTabLabelUI extends DarkLabelUI implements PropertyChang
private TabFrameTabLabel tabComponent; private TabFrameTabLabel tabComponent;
private final MouseListener mouseListener = new MouseAdapter() { private final MouseListener mouseListener = new MouseAdapter() {
@Override @Override
public void mousePressed(final MouseEvent e) { public void mouseClicked(final MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e)) { if (SwingUtilities.isLeftMouseButton(e)) {
tabComponent.getTabFrame().toggleTab(tabComponent.getOrientation(), tabComponent.getIndex(), tabComponent.getTabFrame().toggleTab(tabComponent.getOrientation(), tabComponent.getIndex(),
!tabComponent.isSelected()); !tabComponent.isSelected());
} }
} }
}; };
private MouseMotionListener dragListener;
private HoverListener hoverListener; private HoverListener hoverListener;
private Color defaultFontColor; private Color defaultFontColor;
private Color selectedFontColor; private Color selectedFontColor;
@ -66,6 +69,7 @@ public class DarkTabFrameTabLabelUI extends DarkLabelUI implements PropertyChang
private RotatableIcon rotatableIcon = new RotatableIcon(); private RotatableIcon rotatableIcon = new RotatableIcon();
private Rectangle paintIconR = new Rectangle(); private Rectangle paintIconR = new Rectangle();
private Rectangle paintTextR = new Rectangle(); private Rectangle paintTextR = new Rectangle();
private boolean printing;
@NotNull @NotNull
@Contract("_ -> new") @Contract("_ -> new")
@ -119,9 +123,10 @@ public class DarkTabFrameTabLabelUI extends DarkLabelUI implements PropertyChang
@Override @Override
public void uninstallUI(final JComponent c) { public void uninstallUI(final JComponent c) {
super.uninstallUI(c); super.uninstallUI(c);
uninstallAccelerator(tabComponent.getTabFrame()); uninstallListeners(tabComponent);
tabComponent.removeMouseListener(hoverListener); if (tabComponent.getComponentPopupMenu() instanceof UIResource) {
tabComponent.removeMouseListener(mouseListener); tabComponent.setComponentPopupMenu(null);
}
hoverListener = null; hoverListener = null;
tabComponent = null; tabComponent = null;
} }
@ -142,13 +147,54 @@ public class DarkTabFrameTabLabelUI extends DarkLabelUI implements PropertyChang
@Override @Override
protected void installListeners(final JLabel c) { protected void installListeners(final JLabel c) {
super.installListeners(c); super.installListeners(c);
dragListener = new TabDragListener(tabComponent);
hoverListener = new HoverListener(tabComponent); hoverListener = new HoverListener(tabComponent);
tabComponent.addMouseListener(hoverListener); tabComponent.addMouseListener(hoverListener);
tabComponent.addMouseListener(mouseListener); tabComponent.addMouseListener(mouseListener);
installAccelerator(tabComponent.getTabFrame()); installAccelerator(tabComponent.getTabFrame());
tabComponent.addMouseMotionListener(dragListener);
}
@Override
protected void uninstallListeners(final JLabel c) {
super.uninstallListeners(c);
tabComponent.removeMouseListener(hoverListener);
tabComponent.removeMouseListener(mouseListener);
uninstallAccelerator(tabComponent.getTabFrame());
tabComponent.removeMouseMotionListener(dragListener);
dragListener = null;
}
@Override
public void propertyChange(final PropertyChangeEvent e) {
super.propertyChange(e);
var key = e.getPropertyName();
if ("selected".equals(key)) {
tabComponent.setForeground(Boolean.TRUE.equals(e.getNewValue())
? selectedFontColor : defaultFontColor);
tabComponent.repaint();
} else if ("title".equals(key)) {
updateText();
} else if ("accelerator".equals(key)) {
updateText();
if (tabComponent == null) return;
uninstallAccelerator(tabComponent.getTabFrame());
installAccelerator(tabComponent.getTabFrame());
} else if ("orientation".equals(key)) {
rotatableIcon.setOrientation(mapOrientation(tabComponent.getOrientation()));
} else if ("tabFrame".equals(key)) {
if (e.getOldValue() instanceof JTabFrame) {
uninstallAccelerator((JTabFrame) e.getOldValue());
}
if (e.getNewValue() instanceof JTabFrame) {
installAccelerator((JTabFrame) e.getNewValue());
}
} else if ("paintingForPrint".equals(key)) {
printing = Boolean.TRUE.equals(e.getNewValue());
}
} }
protected void installAccelerator(final TabFrame tabFrame) { protected void installAccelerator(final JTabFrame tabFrame) {
if (tabFrame == null) return; if (tabFrame == null) return;
int acc = tabComponent.getAccelerator(); int acc = tabComponent.getAccelerator();
if (acc < 0) return; if (acc < 0) return;
@ -158,7 +204,7 @@ public class DarkTabFrameTabLabelUI extends DarkLabelUI implements PropertyChang
tabFrame.getActionMap().put("accelerator_" + acc, createAcceleratorAction(tabFrame)); tabFrame.getActionMap().put("accelerator_" + acc, createAcceleratorAction(tabFrame));
} }
protected Action createAcceleratorAction(final TabFrame tabFrame) { protected Action createAcceleratorAction(final JTabFrame tabFrame) {
return new AbstractAction() { return new AbstractAction() {
@Override @Override
public void actionPerformed(final ActionEvent e) { public void actionPerformed(final ActionEvent e) {
@ -178,33 +224,6 @@ public class DarkTabFrameTabLabelUI extends DarkLabelUI implements PropertyChang
}; };
} }
@Override
public void propertyChange(final PropertyChangeEvent e) {
super.propertyChange(e);
var key = e.getPropertyName();
if ("selected".equals(key)) {
tabComponent.setForeground(Boolean.TRUE.equals(e.getNewValue())
? selectedFontColor : defaultFontColor);
tabComponent.repaint();
} else if ("title".equals(key)) {
updateText();
} else if ("accelerator".equals(key)) {
updateText();
if (tabComponent == null) return;
uninstallAccelerator(tabComponent.getTabFrame());
installAccelerator(tabComponent.getTabFrame());
} else if ("orientation".equals(key)) {
rotatableIcon.setOrientation(mapOrientation(tabComponent.getOrientation()));
} else if ("tabFrame".equals(key)) {
if (e.getOldValue() instanceof TabFrame) {
uninstallAccelerator((TabFrame) e.getOldValue());
}
if (e.getNewValue() instanceof TabFrame) {
installAccelerator((TabFrame) e.getNewValue());
}
}
}
protected void updateText() { protected void updateText() {
var title = tabComponent.getTitle(); var title = tabComponent.getTitle();
title = title == null ? "" : title; title = title == null ? "" : title;
@ -218,7 +237,7 @@ public class DarkTabFrameTabLabelUI extends DarkLabelUI implements PropertyChang
} }
} }
protected void uninstallAccelerator(final TabFrame tabFrame) { protected void uninstallAccelerator(final JTabFrame tabFrame) {
if (tabFrame == null) return; if (tabFrame == null) return;
int acc = tabComponent.getAccelerator(); int acc = tabComponent.getAccelerator();
String accAction = "accelerator_" + acc; String accAction = "accelerator_" + acc;
@ -226,6 +245,7 @@ public class DarkTabFrameTabLabelUI extends DarkLabelUI implements PropertyChang
} }
public Color getBackground(@NotNull final TabFrameTabLabel tab) { public Color getBackground(@NotNull final TabFrameTabLabel tab) {
if (printing || tab.getTabFrame().isInTransfer()) return tab.getBackground();
return tab.isSelected() return tab.isSelected()
? selectedColor ? selectedColor
: hoverListener.isHover() ? hoverColor : tab.getBackground(); : hoverListener.isHover() ? hoverColor : tab.getBackground();

437
src/main/java/com/weis/darklaf/ui/tabframe/DarkTabFrameUI.java

@ -23,11 +23,14 @@
*/ */
package com.weis.darklaf.ui.tabframe; package com.weis.darklaf.ui.tabframe;
import com.weis.darklaf.components.alignment.Alignment;
import com.weis.darklaf.components.border.MutableLineBorder; import com.weis.darklaf.components.border.MutableLineBorder;
import com.weis.darklaf.components.tabframe.JTabFrame;
import com.weis.darklaf.components.tabframe.PopupContainer; import com.weis.darklaf.components.tabframe.PopupContainer;
import com.weis.darklaf.components.tabframe.TabFrame;
import com.weis.darklaf.components.tabframe.TabFramePopup; import com.weis.darklaf.components.tabframe.TabFramePopup;
import com.weis.darklaf.components.tabframe.TabFrameTab;
import com.weis.darklaf.components.tabframe.TabFrameUI; import com.weis.darklaf.components.tabframe.TabFrameUI;
import com.weis.darklaf.components.uiresource.JPanelUIResource;
import com.weis.darklaf.util.DarkUIUtil; import com.weis.darklaf.util.DarkUIUtil;
import org.jdesktop.jxlayer.JXLayer; import org.jdesktop.jxlayer.JXLayer;
import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Contract;
@ -40,27 +43,39 @@ import javax.swing.plaf.ComponentUI;
import java.awt.*; import java.awt.*;
import java.awt.event.AWTEventListener; import java.awt.event.AWTEventListener;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.util.TooManyListenersException;
/** /**
* UI class for {@link TabFrame}. * UI class for {@link JTabFrame}.
* *
* @author Jannis Weis * @author Jannis Weis
* @since 2018 * @since 2018
*/ */
public class DarkTabFrameUI extends TabFrameUI implements AWTEventListener { public class DarkTabFrameUI extends TabFrameUI implements AWTEventListener {
private TabFrame tabFrame; protected static final TabFrameTransferHandler TRANSFER_HANDLER = new TabFrameTransferHandler.UIResource();
private final Rectangle calcRect = new Rectangle();
private JXLayer<JComponent> rotatePaneLeft; private JXLayer<JComponent> rotatePaneLeft;
private JXLayer<JComponent> rotatePaneRight; private JXLayer<JComponent> rotatePaneRight;
private JTabFrame tabFrame;
private LayoutManager layout; private JComponent dropComponentTop;
private JComponent dropComponentBottom;
private JComponent dropComponentRight;
private JComponent dropComponentLeft;
private MutableLineBorder topBorder; private MutableLineBorder topBorder;
private MutableLineBorder bottomBorder; private MutableLineBorder bottomBorder;
private MutableLineBorder leftBorder; private MutableLineBorder leftBorder;
private MutableLineBorder rightBorder; private MutableLineBorder rightBorder;
private Color lineColor; private Color lineColor;
private TabFrameLayout layout;
private int tabHeight; private int tabHeight;
private Color dragBorderColor;
private Dimension dropSize = new Dimension();
private Alignment sourceAlign;
private int sourceIndex;
private Alignment destAlign;
private int destIndex;
@NotNull @NotNull
@Contract("_ -> new") @Contract("_ -> new")
@ -70,10 +85,11 @@ public class DarkTabFrameUI extends TabFrameUI implements AWTEventListener {
@Override @Override
public void installUI(@NotNull final JComponent c) { public void installUI(@NotNull final JComponent c) {
tabFrame = (TabFrame) c; tabFrame = (JTabFrame) c;
installDefaults(); installDefaults();
installComponents(); installComponents();
installListeners(); installListeners();
installDnD();
} }
protected void installDefaults() { protected void installDefaults() {
@ -86,6 +102,19 @@ public class DarkTabFrameUI extends TabFrameUI implements AWTEventListener {
rightBorder = new MutableLineBorder.UIResource(0, 0, 1, 0, lineColor); rightBorder = new MutableLineBorder.UIResource(0, 0, 1, 0, lineColor);
leftBorder = new MutableLineBorder.UIResource(0, 0, 1, 0, lineColor); leftBorder = new MutableLineBorder.UIResource(0, 0, 1, 0, lineColor);
dropComponentTop = new JPanelUIResource();
dropComponentBottom = new JPanelUIResource();
dropComponentLeft = new JPanelUIResource();
dropComponentRight = new JPanelUIResource();
dragBorderColor = UIManager.getColor("TabFrame.dragBorderColor");
Color dropColor = UIManager.getColor("TabFrame.dropBackground");
dropComponentTop.setBackground(dropColor);
dropComponentBottom.setBackground(dropColor);
dropComponentLeft.setBackground(dropColor);
dropComponentRight.setBackground(dropColor);
tabFrame.getTopTabContainer().setBorder(topBorder); tabFrame.getTopTabContainer().setBorder(topBorder);
tabFrame.getBottomTabContainer().setBorder(bottomBorder); tabFrame.getBottomTabContainer().setBorder(bottomBorder);
tabFrame.getRightTabContainer().setBorder(rightBorder); tabFrame.getRightTabContainer().setBorder(rightBorder);
@ -107,13 +136,28 @@ public class DarkTabFrameUI extends TabFrameUI implements AWTEventListener {
tabFrame.add(tabFrame.getBottomTabContainer()); tabFrame.add(tabFrame.getBottomTabContainer());
tabFrame.add(rotatePaneLeft); tabFrame.add(rotatePaneLeft);
tabFrame.add(rotatePaneRight); tabFrame.add(rotatePaneRight);
tabFrame.getTopTabContainer().add(dropComponentTop);
tabFrame.getBottomTabContainer().add(dropComponentBottom);
tabFrame.getLeftTabContainer().add(dropComponentLeft);
tabFrame.getRightTabContainer().add(dropComponentRight);
}
protected void installDnD() {
tabFrame.setTransferHandler(TRANSFER_HANDLER);
try {
tabFrame.getDropTarget().addDropTargetListener(TRANSFER_HANDLER);
tabFrame.getDropTarget().setActive(tabFrame.isDndEnabled());
} catch (TooManyListenersException e) {
e.printStackTrace();
}
} }
protected void installListeners() { protected void installListeners() {
Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.MOUSE_EVENT_MASK); Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.MOUSE_EVENT_MASK);
} }
protected LayoutManager createLayout() { protected TabFrameLayout createLayout() {
return new TabFrameLayout(tabFrame, this); return new TabFrameLayout(tabFrame, this);
} }
@ -132,22 +176,344 @@ public class DarkTabFrameUI extends TabFrameUI implements AWTEventListener {
rotatePaneLeft = null; rotatePaneLeft = null;
rotatePaneRight = null; rotatePaneRight = null;
uninstallListeners(); uninstallListeners();
if (tabFrame.getTransferHandler() instanceof TabFrameTransferHandler.UIResource) {
tabFrame.setTransferHandler(null);
if (tabFrame.getDropTarget() != null) {
tabFrame.getDropTarget().removeDropTargetListener(TRANSFER_HANDLER);
tabFrame.getDropTarget().setActive(false);
}
}
} }
protected void uninstallListeners() { protected void uninstallListeners() {
Toolkit.getDefaultToolkit().removeAWTEventListener(this); Toolkit.getDefaultToolkit().removeAWTEventListener(this);
} }
public void updateBorders(final int topCount, final int bottomCount, public int getTabSize(final JTabFrame tabFrame) {
final int leftCount, final int rightCount) { return tabHeight;
leftBorder.setRight(topCount > 0 ? 0 : 1);
leftBorder.setLeft(bottomCount > 0 ? 0 : 1);
rightBorder.setLeft(topCount > 0 ? 0 : 1);
rightBorder.setRight(bottomCount > 0 ? 0 : 1);
} }
public int getTabSize(final TabFrame tabFrame) {
return tabHeight; @Override
public void clearTargetIndicator() {
destIndex = -10;
destAlign = null;
dropSize.setSize(0, 0);
tabFrame.doLayout();
}
@Override
public void clearSourceIndicator() {
sourceIndex = -10;
sourceAlign = null;
tabFrame.doLayout();
}
@Override
public Color getDragBorderColor() {
return dragBorderColor;
}
@Override
public void setSourceIndicator(final Alignment a, final int tabIndex) {
sourceAlign = a;
sourceIndex = tabIndex;
tabFrame.doLayout();
}
@Override
public void setTargetIndicator(final Alignment a, final int tabIndex) {
destAlign = a;
destIndex = tabIndex;
tabFrame.doLayout();
}
@Override
public JTabFrame.TabFramePosition getTabIndexAt(final JTabFrame tabFrame, @NotNull final Point p) {
Component tabComp = null;
Alignment a = null;
Point pos = null;
if (!layout.isDraggedOver(Alignment.NORTH)) {
getTopContainer().getBounds(calcRect);
if (p.y >= calcRect.y && p.y <= calcRect.y + calcRect.height) {
tabComp = getTopContainer();
a = Alignment.NORTH;
pos = SwingUtilities.convertPoint(tabFrame, p, tabComp);
if (pos.x > tabComp.getWidth() / 2) {
a = Alignment.NORTH_EAST;
}
}
}
if (tabComp == null && !layout.isDraggedOver(Alignment.SOUTH)) {
getBottomContainer().getBounds(calcRect);
if (p.y >= calcRect.y && p.y <= calcRect.y + calcRect.height) {
tabComp = getBottomContainer();
a = Alignment.SOUTH;
pos = SwingUtilities.convertPoint(tabFrame, p, tabComp);
if (pos.x <= tabComp.getWidth() / 2) {
a = Alignment.SOUTH_WEST;
}
}
}
if (tabComp == null && !layout.isDraggedOver(Alignment.WEST)) {
getLeftContainer().getBounds(calcRect);
if (p.x >= calcRect.x && p.x <= calcRect.x + calcRect.width) {
tabComp = getLeftContainer();
a = Alignment.WEST;
pos = SwingUtilities.convertPoint(tabFrame, p, tabComp);
if (pos.y < tabComp.getHeight() / 2) {
a = Alignment.NORTH_WEST;
}
int tmp = pos.x;
pos.x = tabComp.getHeight() - pos.y;
pos.y = tmp;
}
}
if (tabComp == null && !layout.isDraggedOver(Alignment.EAST)) {
getRightContainer().getBounds(calcRect);
if (p.x >= calcRect.x && p.x <= calcRect.x + calcRect.width) {
tabComp = getRightContainer();
a = Alignment.EAST;
pos = SwingUtilities.convertPoint(tabFrame, p, tabComp);
if (pos.y > tabComp.getHeight() / 2) {
a = Alignment.SOUTH_EAST;
}
int tmp = pos.x;
//noinspection SuspiciousNameCombination
pos.x = pos.y;
pos.y = tmp;
}
}
if (tabComp == null) {
var tab = maybeRestoreTabContainer(tabFrame, p);
if (tab.getAlignment() != null) {
return tab;
}
} else {
layout.setDraggedOver(false);
}
if (tabComp == null) {
return new JTabFrame.TabFramePosition(null, -1);
}
var tabs = tabFrame.tabsForAlignment(a);
for (var tab : tabs) {
var rect = getTabRect(tab, a, tabComp, true);
if (rect.contains(pos)) {
return new JTabFrame.TabFramePosition(a, tab.getIndex(), pos);
}
}
return new JTabFrame.TabFramePosition(a, -1, pos);
}
@Override
public JTabFrame.TabFramePosition getNearestTabIndexAt(final JTabFrame tabFrame, final Point pos) {
var tab = getTabIndexAt(tabFrame, pos);
if (tab.getAlignment() != null && tab.getIndex() == -1) {
var p = tab.getPoint();
var a = tab.getAlignment();
if (tabFrame.getTabCountAt(a) == 0) {
tab.setIndex(-1);
return tab;
}
int w = a == destAlign && destIndex == -1 ? dropSize.width : 0;
var comp = getTabContainer(a);
switch (a) {
case NORTH:
case SOUTH_WEST:
if (p.x > getLeftContainer().getWidth() + w) {
tab.setIndex(tabFrame.getTabCountAt(a) - 1);
}
break;
case NORTH_EAST:
case SOUTH:
if (p.x < comp.getWidth() - getRightContainer().getWidth() - w) {
tab.setIndex(tabFrame.getTabCountAt(a) - 1);
}
break;
case EAST:
case WEST:
if (p.x > w) {
tab.setIndex(tabFrame.getTabCountAt(a) - 1);
}
break;
case SOUTH_EAST:
case NORTH_WEST:
if (p.x < comp.getHeight() - w) {
tab.setIndex(tabFrame.getTabCountAt(a) - 1);
}
break;
}
}
return tab;
}
public void setDropSize(final int width, final int height) {
dropSize.setSize(width, height);
}
@Override
public int getTabWidth(@NotNull final JTabFrame tabFrame, final Alignment a, final int index) {
return layout.getTabWidth(tabFrame.getTabComponentAt(a, index).getComponent());
}
@Override
public int getTabHeight(@NotNull final JTabFrame tabFrame, final Alignment a, final int index) {
return tabFrame.getTabSize();
}
public Rectangle getTabContainerBounds(final JTabFrame tabFrame, @NotNull final Alignment a) {
switch (a) {
case NORTH:
case NORTH_EAST:
var rect = getTopContainer().getBounds();
rect.x = 0;
rect.width = tabFrame.getWidth();
return rect;
case EAST:
case SOUTH_EAST:
return getRightContainer().getBounds();
case SOUTH:
case SOUTH_WEST:
var rect2 = getTopContainer().getBounds();
rect2.x = 0;
rect2.width = tabFrame.getWidth();
return rect2;
case WEST:
case NORTH_WEST:
return getLeftContainer().getBounds();
default:
case CENTER:
return tabFrame.getContentPane().getComponent().getBounds();
}
}
public JTabFrame.TabFramePosition getDropPosition(final JTabFrame tabFrame, final Point p) {
var tab = getNearestTabIndexAt(tabFrame, p);
if (tab.getAlignment() != null) {
var a = tab.getAlignment();
int index = tab.getIndex();
if (index >= 0) {
var rect = getTabRect(tabFrame.getTabComponentAt(a, index), a, tabFrame.getTabContainer(a), false);
var pos = tab.getPoint();
if (isForward(a)) {
if (pos.x <= rect.x + rect.width / 2 && pos.x >= rect.x) {
tab.setIndex(tab.getIndex() - 1);
}
} else {
if (pos.x >= rect.x + rect.width / 2) {
tab.setIndex(tab.getIndex() - 1);
}
}
}
}
return tab;
}
public Alignment getSourceAlign() {
return sourceAlign;
}
public int getSourceIndex() {
return sourceIndex;
}
public Alignment getDestAlign() {
return destAlign;
}
public int getDestIndex() {
return destIndex;
}
protected JTabFrame.TabFramePosition maybeRestoreTabContainer(@NotNull final JTabFrame tabFrame, final Point p) {
Alignment a = null;
int size = tabFrame.getTabSize();
int threshold = size;
int index = -10;
if (tabFrame.getTopTabCount() == 0) {
if (layout.isDraggedOver(Alignment.NORTH)) threshold *= 2;
if (p.y < threshold) {
a = p.x >= tabFrame.getWidth() / 2 ? Alignment.NORTH_EAST : Alignment.NORTH;
}
if (p.y < size) index = -1;
}
if (a == null && tabFrame.getBottomTabCount() == 0) {
if (layout.isDraggedOver(Alignment.SOUTH)) threshold *= 2;
if (p.y > tabFrame.getHeight() - threshold) {
a = p.x >= tabFrame.getWidth() / 2 ? Alignment.SOUTH : Alignment.SOUTH_WEST;
}
if (p.y > tabFrame.getHeight() - size) index = -1;
}
if (a == null && tabFrame.getLeftTabCount() == 0) {
if (layout.isDraggedOver(Alignment.WEST)) threshold *= 2;
if (p.x < threshold) {
a = p.y >= tabFrame.getHeight() / 2 ? Alignment.WEST : Alignment.NORTH_WEST;
}
if (p.x < size) index = -1;
}
if (a == null && tabFrame.getRightTabCount() == 0) {
if (layout.isDraggedOver(Alignment.EAST)) threshold *= 2;
if (p.x > tabFrame.getWidth() - threshold) {
a = p.y >= tabFrame.getHeight() / 2 ? Alignment.SOUTH_EAST : Alignment.EAST;
}
if (p.x > tabFrame.getWidth() - size) index = -1;
}
layout.setDraggedOver(false);
if (a != null) {
layout.setDraggedOver(a, true);
}
return new JTabFrame.TabFramePosition(a, index);
}
protected Rectangle getTabRect(@NotNull final TabFrameTab tab, final Alignment a, final Component tabComp,
final boolean includeDropRect) {
tab.getComponent().getBounds(calcRect);
SwingUtilities.convertRectangle(tab.getComponent(), calcRect, tabComp);
if (includeDropRect && a == destAlign) {
if (tab.getIndex() == destIndex && destIndex >= 0) {
if (isForward(a)) {
calcRect.width += dropSize.width;
} else {
calcRect.x -= dropSize.width;
calcRect.width += dropSize.width;
}
}
}
return calcRect;
}
protected boolean isForward(@NotNull final Alignment a) {
switch (a) {
case NORTH:
case EAST:
case WEST:
case SOUTH_WEST:
return true;
case NORTH_WEST:
case SOUTH:
case NORTH_EAST:
case SOUTH_EAST:
default:
return false;
}
}
protected Component getTabContainer(@NotNull final Alignment a) {
switch (a) {
case NORTH:
case NORTH_EAST:
return getTopContainer();
case EAST:
case SOUTH_EAST:
return getRightContainer();
case SOUTH:
case SOUTH_WEST:
return getBottomContainer();
case WEST:
case NORTH_WEST:
return getLeftContainer();
}
return null;
} }
public JComponent getLeftContainer() { public JComponent getLeftContainer() {
@ -181,10 +547,49 @@ public class DarkTabFrameUI extends TabFrameUI implements AWTEventListener {
parent2.getPopup().requestFocus(); parent2.getPopup().requestFocus();
return; return;
} }
var parent3 = DarkUIUtil.getParentOfType(TabFrame.class, comp); var parent3 = DarkUIUtil.getParentOfType(JTabFrame.class, comp);
if (parent3 != null && comp != null && !comp.hasFocus()) { if (parent3 != null && comp != null && !comp.hasFocus()) {
parent3.requestFocus(); parent3.requestFocus();
} }
} }
} }
public Dimension getDropSize() {
return dropSize;
}
public JComponent getDropComponent(@NotNull final Alignment a) {
switch (a) {
default:
case CENTER:
case NORTH:
case NORTH_EAST:
return getDropComponentTop();
case EAST:
case SOUTH_EAST:
return getDropComponentRight();
case SOUTH:
case SOUTH_WEST:
return getDropComponentBottom();
case WEST:
case NORTH_WEST:
return getDropComponentLeft();
}
}
public JComponent getDropComponentTop() {
return dropComponentTop;
}
public JComponent getDropComponentRight() {
return dropComponentRight;
}
public JComponent getDropComponentBottom() {
return dropComponentBottom;
}
public JComponent getDropComponentLeft() {
return dropComponentLeft;
}
} }

2
src/main/java/com/weis/darklaf/ui/tabframe/DarkTabbedPopupUI.java

@ -23,9 +23,9 @@
*/ */
package com.weis.darklaf.ui.tabframe; package com.weis.darklaf.ui.tabframe;
import com.weis.darklaf.components.JPanelUIResource;
import com.weis.darklaf.components.border.MutableLineBorder; import com.weis.darklaf.components.border.MutableLineBorder;
import com.weis.darklaf.components.tabframe.TabbedPopup; import com.weis.darklaf.components.tabframe.TabbedPopup;
import com.weis.darklaf.components.uiresource.JPanelUIResource;
import com.weis.darklaf.ui.tabbedpane.DarkTabbedPaneUI; import com.weis.darklaf.ui.tabbedpane.DarkTabbedPaneUI;
import com.weis.darklaf.ui.tabbedpane.MoreTabsButton; import com.weis.darklaf.ui.tabbedpane.MoreTabsButton;
import com.weis.darklaf.ui.tabbedpane.NewTabButton; import com.weis.darklaf.ui.tabbedpane.NewTabButton;

60
src/main/java/com/weis/darklaf/ui/tabframe/TabDragListener.java

@ -0,0 +1,60 @@
/*
* MIT License
*
* Copyright (c) 2019 Jannis Weis
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.weis.darklaf.ui.tabframe;
import com.weis.darklaf.components.tabframe.TabFrameTab;
import com.weis.darklaf.util.DarkUIUtil;
import com.weis.darklaf.util.SwingXUtilities;
import org.jdesktop.jxlayer.JXLayer;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class TabDragListener extends MouseAdapter {
private final TabFrameTab tabComponent;
public TabDragListener(final TabFrameTab tabComponent) {
this.tabComponent = tabComponent;
}
@Override
public void mouseDragged(@NotNull final MouseEvent e) {
var th = tabComponent.getTabFrame().getTransferHandler();
if (th != null && tabComponent.getTabFrame().isDndEnabled()) {
var p = e.getPoint();
p = SwingXUtilities.convertPointToParent(tabComponent.getComponent(), p);
JXLayer layer = DarkUIUtil.getParentOfType(JXLayer.class, tabComponent.getComponent());
p = SwingUtilities.convertPoint(layer != null ? layer : tabComponent.getComponent().getParent(),
p, tabComponent.getTabFrame());
tabComponent.getTabFrame().initTransfer(tabComponent.getOrientation(), tabComponent.getIndex());
th.exportAsDrag(tabComponent.getTabFrame(),
new MouseEvent(tabComponent.getTabFrame(), e.getID(), e.getWhen(), e.getModifiersEx(),
p.x, p.y, e.getClickCount(), e.isPopupTrigger(), e.getButton()),
TransferHandler.MOVE);
}
}
}

232
src/main/java/com/weis/darklaf/ui/tabframe/TabFrameLayout.java

@ -24,11 +24,12 @@
package com.weis.darklaf.ui.tabframe; package com.weis.darklaf.ui.tabframe;
import com.weis.darklaf.components.alignment.Alignment; import com.weis.darklaf.components.alignment.Alignment;
import com.weis.darklaf.components.tabframe.TabFrame; import com.weis.darklaf.components.tabframe.JTabFrame;
import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.awt.*; import java.awt.*;
import java.util.Arrays;
/** /**
* @author Jannis Weis * @author Jannis Weis
@ -36,15 +37,21 @@ import java.awt.*;
*/ */
public class TabFrameLayout implements LayoutManager { public class TabFrameLayout implements LayoutManager {
private final TabFrame tabFrame; private final JTabFrame tabFrame;
private DarkTabFrameUI ui; private DarkTabFrameUI ui;
private int maxTabHeight; private int[] shift;
private int maxTabWidth; private boolean[] draggedOver;
private int topHeight;
private int leftHeight;
private int rightHeight;
private int bottomHeight;
@Contract(pure = true) @Contract(pure = true)
public TabFrameLayout(@NotNull final TabFrame tabFrame, final DarkTabFrameUI ui) { public TabFrameLayout(@NotNull final JTabFrame tabFrame, final DarkTabFrameUI ui) {
this.tabFrame = tabFrame; this.tabFrame = tabFrame;
this.ui = ui; this.ui = ui;
shift = new int[4];
draggedOver = new boolean[4];
} }
@Override @Override
@ -82,13 +89,27 @@ public class TabFrameLayout implements LayoutManager {
int bottomSize = tabFrame.getBottomTabCount(); int bottomSize = tabFrame.getBottomTabCount();
int leftSize = tabFrame.getLeftTabCount(); int leftSize = tabFrame.getLeftTabCount();
int rightSize = tabFrame.getRightTabCount(); int rightSize = tabFrame.getRightTabCount();
if (isDraggedOver(Alignment.NORTH)) topSize++;
if (isDraggedOver(Alignment.SOUTH)) bottomSize++;
if (isDraggedOver(Alignment.EAST)) rightSize++;
if (isDraggedOver(Alignment.WEST)) leftSize++;
ui.getDropComponentBottom().setSize(0, 0);
ui.getDropComponentLeft().setSize(0, 0);
ui.getDropComponentRight().setSize(0, 0);
ui.getDropComponentTop().setSize(0, 0);
topHeight = calculateMaxTabSize(Alignment.NORTH);
bottomHeight = calculateMaxTabSize(Alignment.SOUTH);
leftHeight = calculateMaxTabSize(Alignment.WEST);
rightHeight = calculateMaxTabSize(Alignment.EAST);
layoutTopTab(dim, topSize, leftSize, rightSize); layoutTopTab(dim, topSize, leftSize, rightSize);
layoutBottomTab(dim, bottomSize, leftSize, rightSize); layoutBottomTab(dim, bottomSize, leftSize, rightSize);
layoutLeftTab(dim, leftSize); layoutLeftTab(dim, leftSize);
layoutRightTab(dim, rightSize); layoutRightTab(dim, rightSize);
ui.updateBorders(topSize, bottomSize, leftSize, rightSize);
var leftPane = ui.getLeftContainer(); var leftPane = ui.getLeftContainer();
var rightPane = ui.getRightContainer(); var rightPane = ui.getRightContainer();
var topPane = ui.getTopContainer(); var topPane = ui.getTopContainer();
@ -99,33 +120,63 @@ public class TabFrameLayout implements LayoutManager {
} }
protected void layoutTopTab(final Dimension dim, final int topSize, final int leftSize, final int rightSize) { protected void layoutTopTab(final Dimension dim, final int topSize, final int leftSize, final int rightSize) {
var topComp = tabFrame.getTopTabContainer();
if (topSize > 0) { if (topSize > 0) {
tabFrame.getTopTabContainer().setBounds(0, 0, dim.width, tabFrame.getTabSize()); topComp.setBounds(0, 0, dim.width, tabFrame.getTabSize());
layoutHorizontal(dim, Alignment.NORTH, Alignment.NORTH_EAST, 0, leftSize, rightSize); layoutHorizontal(dim, Alignment.NORTH, Alignment.NORTH_EAST, 0, leftSize, rightSize, topHeight);
} else if (draggedOver[getIndex(Alignment.NORTH)]) {
int size = tabFrame.getTabSize();
topComp.setBounds(0, 0, dim.width, size);
if (ui.getDestIndex() >= -1) {
layoutHorizontalDrop(Alignment.NORTH, leftSize, rightSize, size, 0);
}
} else { } else {
tabFrame.getTopTabContainer().setBounds(0, 0, 0, 0); topComp.setBounds(0, 0, 0, 0);
} }
} }
protected void layoutBottomTab(final Dimension dim, final int bottomSize, final int leftSize, final int rightSize) { protected void layoutBottomTab(final Dimension dim, final int bottomSize, final int leftSize, final int rightSize) {
var bottomComp = tabFrame.getBottomTabContainer();
if (bottomSize > 0) { if (bottomSize > 0) {
bottomComp.setBounds(0, dim.height - bottomHeight, dim.width, bottomHeight);
layoutHorizontal(dim, Alignment.SOUTH_WEST, Alignment.SOUTH, 1, leftSize, rightSize, bottomHeight);
} else if (draggedOver[getIndex(Alignment.SOUTH)]) {
int size = tabFrame.getTabSize(); int size = tabFrame.getTabSize();
tabFrame.getBottomTabContainer().setBounds(0, dim.height - size, dim.width, size); bottomComp.setBounds(0, dim.height - size, dim.width, size);
layoutHorizontal(dim, Alignment.SOUTH_WEST, Alignment.SOUTH, 1, leftSize, rightSize); if (ui.getDestIndex() >= -1) {
layoutHorizontalDrop(Alignment.SOUTH_WEST, leftSize, rightSize, size, 1);
}
} else {
bottomComp.setBounds(0, 0, 0, 0);
}
}
protected void layoutHorizontalDrop(final Alignment left, final int leftSize, final int rightSize,
final int size, final int yOff) {
var a = ui.getDestAlign();
var dropSize = ui.getDropSize();
var dropComp = ui.getDropComponent(left);
var tabComp = ui.getTabContainer(left);
if (a == left) {
int x = leftSize > 0 ? leftHeight : 0;
dropComp.setBounds(x, yOff, dropSize.width, size);
} else { } else {
tabFrame.getBottomTabContainer().setBounds(0, 0, 0, 0); int x = rightSize > 0 ? tabComp.getWidth() - rightHeight : tabComp.getWidth();
dropComp.setBounds(x - dropSize.width, yOff, dropSize.width, size);
} }
} }
protected void layoutHorizontal(final Dimension dim, final Alignment left, final Alignment right, protected void layoutHorizontal(final Dimension dim, final Alignment left, final Alignment right,
final int yOff, final int leftSize, final int rightSize) { final int yOff, final int leftSize, final int rightSize, final int tabHeight) {
int tabHeight = calculateMaxTabSize(left); var start = new Point(leftSize > 0 ? leftHeight : 0, yOff);
var start = new Point(leftSize > 0 ? tabHeight : 0, yOff);
int leftEnd = layoutTabArea(start, left, true, tabHeight - 1); int leftEnd = layoutTabArea(start, left, true, tabHeight - 1);
start.x = rightSize > 0 ? dim.width - tabHeight : dim.width; start.x = rightSize > 0 ? dim.width - rightHeight : dim.width;
int rightStart = layoutTabArea(start, right, false, tabHeight - 1); int rightStart = layoutTabArea(start, right, false, tabHeight - 1);
if (rightStart < leftEnd) { if (rightStart < leftEnd) {
shift[getIndex(left)] = leftEnd - rightStart;
shift(leftEnd - rightStart, right); shift(leftEnd - rightStart, right);
} else {
shift[getIndex(left)] = 0;
} }
} }
@ -133,19 +184,26 @@ public class TabFrameLayout implements LayoutManager {
var leftPane = ui.getLeftContainer(); var leftPane = ui.getLeftContainer();
var topPane = tabFrame.getTopTabContainer(); var topPane = tabFrame.getTopTabContainer();
var bottomPane = tabFrame.getBottomTabContainer(); var bottomPane = tabFrame.getBottomTabContainer();
int tabWidth = calculateMaxTabSize(Alignment.WEST); if (leftSize > 0 || draggedOver[getIndex(Alignment.WEST)]) {
if (leftSize > 0) { int size = leftSize > 0 ? leftHeight : tabFrame.getTabSize();
int height = dim.height - topPane.getHeight() - bottomPane.getHeight(); int height = dim.height - topPane.getHeight() - bottomPane.getHeight();
leftPane.setBounds(0, topPane.getHeight(), tabWidth, height + (height % 2)); leftPane.setBounds(0, topPane.getHeight(), size, height + (height % 2));
tabFrame.getLeftTabContainer().setPreferredSize(new Dimension(leftPane.getHeight(), tabFrame.getLeftTabContainer().setPreferredSize(new Dimension(leftPane.getHeight(),
leftPane.getWidth())); leftPane.getWidth()));
tabFrame.getLeftTabContainer().setSize(tabFrame.getLeftTabContainer().getPreferredSize()); tabFrame.getLeftTabContainer().setSize(tabFrame.getLeftTabContainer().getPreferredSize());
var start = new Point(leftPane.getHeight(), 0); if (leftSize > 0) {
int topStart = layoutTabArea(start, Alignment.NORTH_WEST, false, tabWidth - 1); var start = new Point(leftPane.getHeight(), 0);
start.x = 0; int topStart = layoutTabArea(start, Alignment.NORTH_WEST, false, size - 1);
int bottomEnd = layoutTabArea(start, Alignment.WEST, true, tabWidth - 1); start.x = 0;
if (bottomEnd > topStart) { int bottomEnd = layoutTabArea(start, Alignment.WEST, true, size - 1);
shift(topStart - bottomEnd, Alignment.WEST); if (bottomEnd > topStart) {
shift[getIndex(Alignment.WEST)] = topStart - bottomEnd;
shift(topStart - bottomEnd, Alignment.WEST);
} else {
shift[getIndex(Alignment.WEST)] = 0;
}
} else if (ui.getDestIndex() >= -1) {
layoutVerticalDrop(Alignment.WEST, size);
} }
} else { } else {
tabFrame.getLeftTabContainer().setBounds(0, 0, 0, 0); tabFrame.getLeftTabContainer().setBounds(0, 0, 0, 0);
@ -153,26 +211,45 @@ public class TabFrameLayout implements LayoutManager {
} }
} }
protected void layoutVerticalDrop(final Alignment left, final int size) {
var comp = ui.getDropComponent(left);
var a = ui.getDestAlign();
var dropSize = ui.getDropSize();
var tabComp = tabFrame.getTabContainer(left);
if (a == left) {
comp.setBounds(0, 0, dropSize.width, size);
} else {
comp.setBounds(tabComp.getWidth() - dropSize.width, 0, dropSize.width, size);
}
}
protected void layoutRightTab(final Dimension dim, final int rightSize) { protected void layoutRightTab(final Dimension dim, final int rightSize) {
var rightPane = ui.getRightContainer(); var rightPane = ui.getRightContainer();
var topPane = tabFrame.getTopTabContainer(); var topPane = tabFrame.getTopTabContainer();
var bottomPane = tabFrame.getBottomTabContainer(); var bottomPane = tabFrame.getBottomTabContainer();
int tabWidth = calculateMaxTabSize(Alignment.EAST); if (rightSize > 0 || draggedOver[getIndex(Alignment.EAST)]) {
if (rightSize > 0) { int size = rightSize > 0 ? rightHeight : tabFrame.getTabSize();
int height = dim.height - topPane.getHeight() - bottomPane.getHeight(); int height = dim.height - topPane.getHeight() - bottomPane.getHeight();
rightPane.setBounds(dim.width - tabWidth, topPane.getHeight(), tabWidth, height + (height % 2)); rightPane.setBounds(dim.width - rightHeight, topPane.getHeight(), size, height + (height % 2));
tabFrame.getRightTabContainer().setPreferredSize(new Dimension(rightPane.getHeight(), rightPane.getWidth())); tabFrame.getRightTabContainer().setPreferredSize(new Dimension(rightPane.getHeight(), rightPane.getWidth()));
tabFrame.getRightTabContainer().setSize(tabFrame.getRightTabContainer().getPreferredSize()); tabFrame.getRightTabContainer().setSize(tabFrame.getRightTabContainer().getPreferredSize());
var start = new Point(0, 0); if (rightSize > 0) {
int topEnd = layoutTabArea(start, Alignment.EAST, true, tabWidth - 1); var start = new Point(0, 0);
start.x = tabFrame.getRightTabContainer().getWidth(); int topEnd = layoutTabArea(start, Alignment.EAST, true, size - 1);
var bottomStart = layoutTabArea(start, Alignment.SOUTH_EAST, false, tabWidth - 1); start.x = tabFrame.getRightTabContainer().getWidth();
if (bottomStart < topEnd) { var bottomStart = layoutTabArea(start, Alignment.SOUTH_EAST, false, size - 1);
shift(topEnd - bottomStart, Alignment.SOUTH_EAST); if (bottomStart < topEnd) {
shift[getIndex(Alignment.EAST)] = topEnd - bottomStart;
shift(topEnd - bottomStart, Alignment.SOUTH_EAST);
} else {
shift[getIndex(Alignment.EAST)] = 0;
}
} else if (ui.getDestIndex() >= -1) {
layoutVerticalDrop(Alignment.EAST, size);
} }
} else { } else {
tabFrame.getRightTabContainer().setBounds(0, 0, 0, 0); tabFrame.getRightTabContainer().setBounds(0, 0, 0, 0);
topPane.setBounds(0, 0, 0, 0); rightPane.setBounds(0, 0, 0, 0);
} }
} }
@ -182,31 +259,102 @@ public class TabFrameLayout implements LayoutManager {
pos.x += shift; pos.x += shift;
c.getComponent().setLocation(pos); c.getComponent().setLocation(pos);
} }
if (a == ui.getDestAlign()) {
var dropComp = ui.getDropComponent(a);
var pos = dropComp.getLocation();
pos.x += shift;
dropComp.setLocation(pos);
}
}
public int getShift(@NotNull final Alignment a) {
switch (a) {
case NORTH:
case EAST:
case SOUTH_WEST:
case NORTH_WEST:
return 0;
}
return shift[getIndex(a)];
}
protected int getIndex(@NotNull final Alignment a) {
switch (a) {
case NORTH:
case NORTH_EAST:
return 0;
case EAST:
case SOUTH_EAST:
return 1;
case SOUTH:
case SOUTH_WEST:
return 2;
case WEST:
case NORTH_WEST:
return 3;
}
return 0;
}
public void setDraggedOver(final Alignment a, final boolean b) {
draggedOver[getIndex(a)] = b;
} }
protected int layoutTabArea(@NotNull final Point start, @NotNull final Alignment a, protected int layoutTabArea(@NotNull final Point start, @NotNull final Alignment a,
final boolean forward, final int size) { final boolean forward, final int size) {
int x = start.x; int x = start.x;
int y = start.y; int y = start.y;
int sourceIndex = a == ui.getSourceAlign() ? ui.getSourceIndex() : -10;
int destIndex = a == ui.getDestAlign() ? ui.getDestIndex() : -10;
var bounds = new Rectangle(0, 0, 0, 0); var bounds = new Rectangle(0, 0, 0, 0);
int index = 0;
var dropComp = ui.getDropComponent(a);
if (destIndex == -1) {
if (forward) {
dropComp.setBounds(x, y, ui.getDropSize().width, size);
x += ui.getDropSize().width;
} else {
x -= ui.getDropSize().width;
dropComp.setBounds(x, y, ui.getDropSize().width, size);
}
}
for (var c : tabFrame.tabsForAlignment(a)) { for (var c : tabFrame.tabsForAlignment(a)) {
bounds.width = getTabWidth(c.getComponent()); index = c.getIndex();
bounds.width = index == sourceIndex ? 0 : getTabWidth(c.getComponent());
bounds.height = size; bounds.height = size;
if (forward) { if (forward) {
bounds.x = x; bounds.x = x;
bounds.y = y; bounds.y = y;
x += bounds.width; x += bounds.width;
if (index == destIndex) {
dropComp.setBounds(x, y, ui.getDropSize().width, size);
x += ui.getDropSize().width;
}
} else { } else {
x -= bounds.width; x -= bounds.width;
bounds.x = x; bounds.x = x;
bounds.y = y; bounds.y = y;
if (index == destIndex) {
x -= ui.getDropSize().width;
dropComp.setBounds(x, y, ui.getDropSize().width, size);
}
} }
c.getComponent().setBounds(bounds); c.getComponent().setBounds(bounds);
} }
if (destIndex == index + 1) {
if (forward) {
dropComp.setBounds(x, y, ui.getDropSize().width, size);
x += ui.getDropSize().width;
} else {
x -= ui.getDropSize().width;
dropComp.setBounds(x, y, ui.getDropSize().width, size);
}
}
return x; return x;
} }
protected int getTabWidth(@NotNull final Component c) { public int getTabWidth(@NotNull final Component c) {
int maxWidth = tabFrame.getMaxTabWidth(); int maxWidth = tabFrame.getMaxTabWidth();
int width = c.getPreferredSize().width; int width = c.getPreferredSize().width;
if (maxWidth < 0) { if (maxWidth < 0) {
@ -226,4 +374,12 @@ public class TabFrameLayout implements LayoutManager {
} }
return max; return max;
} }
public void setDraggedOver(final boolean b) {
Arrays.fill(draggedOver, b);
}
public boolean isDraggedOver(final Alignment a) {
return draggedOver[getIndex(a)];
}
} }

508
src/main/java/com/weis/darklaf/ui/tabframe/TabFrameTransferHandler.java

@ -0,0 +1,508 @@
/*
* MIT License
*
* Copyright (c) 2019 Jannis Weis
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.weis.darklaf.ui.tabframe;
import com.weis.darklaf.components.alignment.Alignment;
import com.weis.darklaf.components.tabframe.JTabFrame;
import com.weis.darklaf.components.tabframe.TabFramePopup;
import com.weis.darklaf.components.tabframe.TabFrameTab;
import com.weis.darklaf.components.tabframe.TabFrameUI;
import com.weis.darklaf.util.ImageUtil;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragGestureRecognizer;
import java.awt.dnd.DragSource;
import java.awt.dnd.DragSourceContext;
import java.awt.dnd.DragSourceDragEvent;
import java.awt.dnd.DragSourceDropEvent;
import java.awt.dnd.DragSourceEvent;
import java.awt.dnd.DragSourceListener;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
/**
* @author Robert Futrell
* @author Jannis Weis
*/
public class TabFrameTransferHandler extends TransferHandler implements DropTargetListener, SwingConstants {
private static final String MIME_TYPE = DataFlavor.javaJVMLocalObjectMimeType
+ ";class=com.weis.darklaf.components.tabframe.TabFrame";
private static TabbedPaneDragGestureRecognizer recognizer = null;
private final Timer timer;
private final Timer startTimer;
/**
* The location of the mouse cursor throughout the drag-and-drop. This is here because of a deficiency in
* TransferHandler's design; you have no way of knowing the exact drop location in the component with a plain
* TransferHandler unless you implement DropTargetListener and get it that way.
*/
protected Point mouseLocation;
private DataFlavor tabFlavor;
private TabTransferable currentTransferable;
private JTabFrame lastTabFrame;
public TabFrameTransferHandler() {
try {
tabFlavor = new DataFlavor(MIME_TYPE);
} catch (ClassNotFoundException ignored) {
}
timer = new Timer(100, e -> {
if (lastTabFrame != null) {
var p = MouseInfo.getPointerInfo().getLocation();
SwingUtilities.convertPointFromScreen(p, lastTabFrame);
var evt = new DropTargetDragEvent(lastTabFrame.getDropTarget().getDropTargetContext(), p, MOVE, MOVE);
dragOver(evt);
}
});
timer.setRepeats(true);
startTimer = new Timer(200, e -> {
/*
* Drag Exit can be funky. Ensure that the timer is really running.
*/
if (!timer.isRunning()) {
timer.start();
}
});
startTimer.setRepeats(false);
}
@Contract("null -> null")
private TabFrameUI getUI(final Component c) {
if (c instanceof JTabFrame) return ((JTabFrame) c).getUI();
return null;
}
protected JTabFrame.TabFramePosition getDropPosition(final Point p, final JTabFrame tabFrame) {
return getUI(tabFrame).getDropPosition(tabFrame, p);
}
public void exportAsDrag(final JComponent comp, final InputEvent e, final int a) {
int srcActions = getSourceActions(comp);
int action = a;
// only mouse events supported for drag operations
if (!(e instanceof MouseEvent)
// only support known actions
|| !(action == COPY || action == MOVE || action == LINK)
// only support valid source actions
|| (srcActions & action) == 0) {
action = NONE;
}
if (action != NONE && !GraphicsEnvironment.isHeadless()) {
if (recognizer == null) {
recognizer = new TabbedPaneDragGestureRecognizer(new TabbedPaneDragHandler());
}
recognizer.gestured(comp, (MouseEvent) e, srcActions, action);
} else {
exportDone(comp, null, NONE);
}
}
/**
* Called when the drag-and-drop operation has just completed. This creates a new tab identical to the one
* "dragged" and places it in the destination <code>JTabbedPane</code>.
*
* @param c The component receiving the "drop" (the instance of
* <code>JTabbedPane</code>).
* @param t The data being transfered (information about the tab and the component contained by the tab).
* @return Whether or not the import was successful.
*/
@Override
public boolean importData(final JComponent c, @NotNull final Transferable t) {
boolean successful = false;
if (hasTabFlavor(t.getTransferDataFlavors()) && mouseLocation != null) {
try {
JTabFrame tabFrame = (JTabFrame) c;
var tab = getDropPosition(mouseLocation, tabFrame);
Alignment a = tab.getAlignment();
int index = tab.getIndex();
TabTransferable.TabTransferData td = (TabTransferable.TabTransferData) t.getTransferData(tabFlavor);
if (tabFrame == td.sourceTabFrame && td.tabAlignment == a) {
if (index >= td.tabIndex) {
index--;
}
}
index++;
if (tabFrame == td.sourceTabFrame && a == td.tabAlignment && index == td.tabIndex) {
//Nothing to do. Just select the tab to be sure.
if (td.wasSelected) {
selectTab(td.sourceTabFrame, a, index);
}
return false;
}
if (a == null || index < 0 || index > tabFrame.getTabCountAt(a)) {
return false;
}
var tabComp = td.sourceTabFrame.getTabComponentAt(td.tabAlignment, td.tabIndex);
var popupComp = td.sourceTabFrame.getPopupComponentAt(td.tabAlignment, td.tabIndex);
td.sourceTabFrame.removeTab(td.tabAlignment, td.tabIndex);
tabFrame.insertTab((TabFramePopup) popupComp, tabComp, a, index);
tabFrame.toggleTab(a, index, td.wasSelected);
SwingUtilities.invokeLater(() -> td.tab.getComponent().repaint());
successful = true;
var ui = getUI(c);
if (ui != null) {
ui.clearTargetIndicator();
}
} catch (Exception e) {
e.printStackTrace();
}
}
return successful;
}
/**
* Overridden to include a check for a TabData flavor.
*/
@Override
public boolean canImport(final JComponent c, final DataFlavor[] flavors) {
return hasTabFlavor(flavors);
}
/**
* We can only move tabs, we cannot copy them.
*
* @param c This parameter is ignored.
* @return <code>TransferHandler.MOVE</code>, as we can only move tabs.
*/
@Override
public int getSourceActions(final JComponent c) {
return MOVE;
}
protected boolean hasTabFlavor(final DataFlavor[] flavors) {
if (tabFlavor == null) {
return false;
}
for (DataFlavor flavor : flavors) {
if (tabFlavor.equals(flavor)) {
return true;
}
}
return false;
}
protected void selectTab(final JTabFrame tabbedPane, final Alignment a, final int index) {
SwingUtilities.invokeLater(() -> tabbedPane.toggleTab(a, index, true));
}
protected Transferable createTransferable(final JComponent c, @NotNull final DragGestureEvent dge) {
JTabFrame tabFrame = (JTabFrame) c;
if (tabFrame.isInTransfer()) {
currentTransferable = new TabTransferable(tabFrame, tabFrame.getTransferInfo());
} else {
var ind = getUI(tabFrame).getTabIndexAt(tabFrame, dge.getDragOrigin());
tabFrame.initTransfer(ind.getAlignment(), ind.getIndex());
currentTransferable = new TabTransferable(tabFrame, ind);
}
var ui = getUI(c);
createDragImage(ui);
var a = currentTransferable.transferData.tabAlignment;
int index = currentTransferable.transferData.tabIndex;
ui.setSourceIndicator(a, index);
startTimer.start();
lastTabFrame = currentTransferable.transferData.sourceTabFrame;
return currentTransferable;
}
protected void createDragImage(@NotNull final TabFrameUI ui) {
var comp = currentTransferable.transferData.tab.getComponent();
Image tabImage = ImageUtil.scaledImageFromComponent(comp, new Rectangle(0, 0, comp.getWidth(),
comp.getHeight()));
int w = tabImage.getWidth(null);
int h = tabImage.getHeight(null);
var g = tabImage.getGraphics();
g.setColor(ui.getDragBorderColor());
int lw = 2;
g.fillRect(0, 0, w, lw);
g.fillRect(0, 0, lw, h);
g.fillRect(w - lw, 0, lw, h);
g.fillRect(0, h - lw, w, lw);
g.dispose();
setDragImageOffset(new Point(w / 2, h / 2));
setDragImage(tabImage);
}
@Override
public void dragEnter(final DropTargetDragEvent e) {
timer.stop();
startTimer.stop();
}
@Override
public void dragOver(@NotNull final DropTargetDragEvent e) {
e.getDropTargetContext().getComponent().setCursor(Cursor.getDefaultCursor());
mouseLocation = e.getLocation();
Component c = e.getDropTargetContext().getComponent();
JTabFrame destTabFrame = (JTabFrame) c;
var ui = getUI(destTabFrame);
if (ui != null) {
TabTransferable t = currentTransferable;
if (t != null) {
var tab = getDropPosition(mouseLocation, destTabFrame);
if (tab.getAlignment() == null) {
ui.clearTargetIndicator();
} else {
try {
var sourceTab = currentTransferable.transferData.sourceTabFrame;
var sourceIndex = currentTransferable.transferData.tabIndex;
var sourceAlign = currentTransferable.transferData.tabAlignment;
int w = getUI(sourceTab).getTabWidth(sourceTab, sourceAlign, sourceIndex);
int h = getUI(sourceTab).getTabHeight(sourceTab, sourceAlign, sourceIndex);
ui.setDropSize(w, h);
ui.setTargetIndicator(tab.getAlignment(), tab.getIndex());
} catch (IndexOutOfBoundsException ex) {
ui.clearTargetIndicator();
}
}
}
}
lastTabFrame = destTabFrame;
startTimer.restart();
}
@Override
public void dropActionChanged(final DropTargetDragEvent e) {
}
@Override
public void dragExit(@NotNull final DropTargetEvent e) {
Component c = e.getDropTargetContext().getComponent();
var ui = getUI(c);
if (ui != null) {
ui.clearTargetIndicator();
}
lastTabFrame = (JTabFrame) c;
startTimer.start();
}
@Override
public void drop(@NotNull final DropTargetDropEvent e) {
Component c = e.getDropTargetContext().getComponent();
var ui = getUI(c);
if (ui != null) {
ui.clearTargetIndicator();
}
timer.stop();
startTimer.stop();
}
protected static class TabbedPaneDragGestureRecognizer extends DragGestureRecognizer {
protected TabbedPaneDragGestureRecognizer(final DragGestureListener dgl) {
super(DragSource.getDefaultDragSource(), null, NONE, dgl);
}
void gestured(final JComponent c, final MouseEvent e, final int srcActions, final int action) {
setComponent(c);
setSourceActions(srcActions);
appendEvent(e);
fireDragGestureRecognized(action, e.getPoint());
}
/**
* register this DragGestureRecognizer's Listeners with the Component
*/
protected void registerListeners() {
}
/**
* unregister this DragGestureRecognizer's Listeners with the Component
* <p>
* subclasses must override this method
*/
protected void unregisterListeners() {
}
}
public static class UIResource extends TabFrameTransferHandler {
}
/**
* Transferable representing a tab from a tabbed pane and its contents.
*/
public class TabTransferable implements Transferable {
private final TabTransferData transferData;
public TabTransferable(@NotNull final JTabFrame tabFrame, @NotNull final JTabFrame.TabFramePosition ind) {
transferData = new TabTransferData(tabFrame, ind.getAlignment(), ind.getIndex());
}
public TabFrameTab getTab() {
return transferData.tab;
}
@Override
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[]{tabFlavor};
}
@Override
public boolean isDataFlavorSupported(final DataFlavor flavor) {
return tabFlavor.equals(flavor);
}
@NotNull
@Override
public Object getTransferData(final DataFlavor flavor) throws UnsupportedFlavorException {
if (!isDataFlavorSupported(flavor)) {
throw new UnsupportedFlavorException(flavor);
}
return transferData;
}
/**
* The data remembered about the tab.
*/
public class TabTransferData {
private final JTabFrame sourceTabFrame;
private final int tabIndex;
private final Alignment tabAlignment;
private final TabFrameTab tab;
private final boolean wasSelected;
@Contract(pure = true)
public TabTransferData(@NotNull final JTabFrame tabbedPane, final Alignment tabAlignment,
final int tabIndex) {
this.sourceTabFrame = tabbedPane;
this.tabAlignment = tabAlignment;
this.tabIndex = tabIndex;
this.tab = tabbedPane.getTabComponentAt(tabAlignment, tabIndex);
this.wasSelected = tab.isSelected();
}
}
}
protected class TabbedPaneDragHandler implements DragGestureListener, DragSourceListener {
private boolean scrolls;
// --- DragGestureListener methods -----------------------------------
/**
* a Drag gesture has been recognized
*/
public void dragGestureRecognized(@NotNull final DragGestureEvent dge) {
JComponent c = (JComponent) dge.getComponent();
TabFrameTransferHandler th = (TabFrameTransferHandler) c.getTransferHandler();
Transferable t = th.createTransferable(c, dge);
if (t != null) {
scrolls = c.getAutoscrolls();
c.setAutoscrolls(false);
try {
Image im = th.getDragImage();
if (im == null) {
dge.startDrag(Cursor.getDefaultCursor(), t, this);
} else {
dge.startDrag(Cursor.getDefaultCursor(), im, th.getDragImageOffset(), t, this);
}
return;
} catch (RuntimeException re) {
c.setAutoscrolls(scrolls);
}
}
th.exportDone(c, t, NONE);
}
// --- DragSourceListener methods -----------------------------------
/**
* as the hotspot enters a platform dependent drop site
*/
public void dragEnter(final DragSourceDragEvent dsde) {
}
/**
* as the hotspot moves over a platform dependent drop site
*/
public void dragOver(final DragSourceDragEvent dsde) {
}
public void dropActionChanged(final DragSourceDragEvent dsde) {
}
/**
* as the hotspot exits a platform dependent drop site
*/
public void dragExit(final DragSourceEvent dsde) {
}
/**
* as the operation completes
*/
public void dragDropEnd(@NotNull final DragSourceDropEvent dsde) {
DragSourceContext dsc = dsde.getDragSourceContext();
JComponent c = (JComponent) dsc.getComponent();
if (dsde.getDropSuccess()) {
((TabFrameTransferHandler) c.getTransferHandler()).exportDone(c, dsc.getTransferable(),
dsde.getDropAction());
} else {
((TabFrameTransferHandler) c.getTransferHandler()).exportDone(c, dsc.getTransferable(), NONE);
}
c.setAutoscrolls(scrolls);
var ui = getUI(currentTransferable.transferData.sourceTabFrame);
if (ui != null) {
ui.clearSourceIndicator();
}
if (!dsde.getDropSuccess() && currentTransferable.transferData.wasSelected) {
selectTab(currentTransferable.transferData.sourceTabFrame,
currentTransferable.transferData.tabAlignment,
currentTransferable.transferData.tabIndex);
}
currentTransferable.transferData.sourceTabFrame.endTransfer();
currentTransferable = null;
}
}
}

3
src/main/java/com/weis/darklaf/ui/tooltip/DarkTooltipBorder.java

@ -55,8 +55,7 @@ public class DarkTooltipBorder implements Border, UIResource {
return; return;
} }
if (c instanceof JToolTip && ((JToolTip) c).getTipText() == null) return; if (c instanceof JToolTip && ((JToolTip) c).getTipText() == null) return;
g.setColor(Color.RED); System.out.println(bubbleBorder.getPointerSide());
g.drawRect(x, y, width, height);
var ins = shadowBorder.getBorderInsets(c); var ins = shadowBorder.getBorderInsets(c);
adjustInsets(ins); adjustInsets(ins);
var bubbleArea = bubbleBorder.getInnerArea(x + ins.left, y + ins.top, var bubbleArea = bubbleBorder.getInnerArea(x + ins.left, y + ins.top,

35
src/main/java/com/weis/darklaf/util/PropertyLoader.java

@ -40,6 +40,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -62,13 +63,15 @@ public final class PropertyLoader {
private static final Collection<ObjectRequest> objectsToLoad = new HashSet<>(); private static final Collection<ObjectRequest> objectsToLoad = new HashSet<>();
public static void finish() { public static void finish() {
var cache = new HashMap<String, Object>();
for (var request : objectsToLoad) { for (var request : objectsToLoad) {
try { try {
request.resolve(); request.resolve(cache);
} catch (RuntimeException e) { } catch (RuntimeException e) {
LOGGER.log(Level.SEVERE, "Could not load" + request, e.getMessage()); LOGGER.log(Level.SEVERE, "Could not load" + request, e.getMessage());
} }
} }
cache.clear();
reset(); reset();
} }
@ -268,20 +271,26 @@ public final class PropertyLoader {
this.value = value; this.value = value;
} }
private void resolve() { private void resolve(@NotNull final Map<String, Object> cache) {
Object obj = parseObject(value);
var defaults = UIManager.getLookAndFeelDefaults(); var defaults = UIManager.getLookAndFeelDefaults();
if (obj == null) { if (cache.containsKey(value)) {
obj = parseValue(key, value, true, defaults); defaults.put(key, cache.get(value));
if (obj instanceof ObjectRequest) {
LOGGER.severe("Failed to resolve object. " + this);
return;
}
}
if (obj == null) {
defaults.remove(key);
} else { } else {
defaults.put(key, obj); Object obj = parseObject(value);
if (obj == null) {
obj = parseValue(key, value, true, defaults);
if (obj instanceof ObjectRequest) {
LOGGER.severe("Failed to resolve object. " + this);
return;
}
} else {
cache.put(value, obj);
}
if (obj == null) {
defaults.remove(key);
} else {
defaults.put(key, obj);
}
} }
} }

48
src/main/java/com/weis/darklaf/util/SwingXUtilities.java

@ -0,0 +1,48 @@
/*
* MIT License
*
* Copyright (c) 2019 Jannis Weis
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.weis.darklaf.util;
import org.jdesktop.jxlayer.JXLayer;
import org.jetbrains.annotations.NotNull;
import org.pbjar.jxlayer.plaf.ext.TransformUI;
import javax.swing.*;
import java.awt.*;
public class SwingXUtilities {
@NotNull
public static Point convertPointToParent(final Component source, final Point p) {
JXLayer layer = DarkUIUtil.getParentOfType(JXLayer.class, source);
if (layer != null && layer.getUI() instanceof TransformUI) {
var ui = (TransformUI) layer.getUI();
var pos = SwingUtilities.convertPoint(source, p, layer);
//noinspection unchecked
var transform = ui.getPreferredTransform(layer.getSize(), layer);
transform.transform(pos, pos);
return pos;
}
return SwingUtilities.convertPoint(source, p, source.getParent());
}
}

10
src/main/java/org/pbjar/jxlayer/plaf/ext/MouseEventUI.java

@ -244,16 +244,6 @@ public class MouseEventUI<V extends JComponent> extends AbstractLayerUI<V> {
if (mouseEvent != null) { if (mouseEvent != null) {
Component target = mouseEvent.getComponent(); Component target = mouseEvent.getComponent();
target.dispatchEvent(mouseEvent); target.dispatchEvent(mouseEvent);
/*
* Used to check the re dispatching behavior
*/
// switch (mouseEvent.getID()) {
// case (MouseEvent.MOUSE_PRESSED):
// System.out.println();
// case (MouseEvent.MOUSE_RELEASED):
// case (MouseEvent.MOUSE_CLICKED):
// System.out.println("Dispatched mouse event " + mouseEvent);
// }
} }
} }

1
src/main/java/org/pbjar/jxlayer/repaint/RepaintManagerUtils.java

@ -133,7 +133,6 @@ public final class RepaintManagerUtils {
@NotNull final Class<? extends RepaintManager> clazz, final RepaintManager delegate) { @NotNull final Class<? extends RepaintManager> clazz, final RepaintManager delegate) {
try { try {
RepaintManager newManager = clazz.getConstructor(RepaintManager.class).newInstance(delegate); RepaintManager newManager = clazz.getConstructor(RepaintManager.class).newInstance(delegate);
System.out.println("Created " + newManager.getClass().getName());
return newManager; return newManager;
} catch (Throwable t) { } catch (Throwable t) {
throw new RuntimeException("Cannot instantiate " + clazz.getName(), t); throw new RuntimeException("Cannot instantiate " + clazz.getName(), t);

2
src/main/resources/com/weis/darklaf/properties/ui/tabFrame.properties

@ -59,6 +59,8 @@ TabFrameUI = com.weis.darklaf.ui.tabframe.
TabFrame.line = %borderSecondary TabFrame.line = %borderSecondary
TabFrame.tabHeight = 24 TabFrame.tabHeight = 24
TabFrame.acceleratorKeyCode = alt pressed TabFrame.acceleratorKeyCode = alt pressed
TabFrame.dropBackground = %dropBackground
TabFrame.dragBorderColor = %borderTertiary
#Icons #Icons
TabFramePopup.close.icon = navigation/collapse.svg[aware] TabFramePopup.close.icon = navigation/collapse.svg[aware]

2
src/main/resources/com/weis/darklaf/theme/intellij/intellij_defaults.properties

@ -38,7 +38,7 @@
%backgroundHoverColorful = CCCFD5 %backgroundHoverColorful = CCCFD5
%backgroundSelectedColorful = c5cddc %backgroundSelectedColorful = c5cddc
%dropBackground = F7F6F0 %dropBackground = FCFAED
%dropForeground = C0C0C0 %dropForeground = C0C0C0
####Border#### ####Border####

5
src/test/java/TabFrameDemo.java

@ -1,7 +1,7 @@
import com.weis.darklaf.LafManager; import com.weis.darklaf.LafManager;
import com.weis.darklaf.components.OverlayScrollPane; import com.weis.darklaf.components.OverlayScrollPane;
import com.weis.darklaf.components.alignment.Alignment; import com.weis.darklaf.components.alignment.Alignment;
import com.weis.darklaf.components.tabframe.TabFrame; import com.weis.darklaf.components.tabframe.JTabFrame;
import com.weis.darklaf.components.tabframe.TabbedPopup; import com.weis.darklaf.components.tabframe.TabbedPopup;
import com.weis.darklaf.icons.IconLoader; import com.weis.darklaf.icons.IconLoader;
@ -42,7 +42,7 @@ public class TabFrameDemo {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
var tabFrame = new TabFrame(); var tabFrame = new JTabFrame();
for (var o : Alignment.values()) { for (var o : Alignment.values()) {
if (o != Alignment.CENTER) { if (o != Alignment.CENTER) {
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
@ -61,7 +61,6 @@ public class TabFrameDemo {
panel.add(label); panel.add(label);
tabbedPopup.getTabbedPane().addTab("Tab " + i, panel); tabbedPopup.getTabbedPane().addTab("Tab " + i, panel);
} }
/* Activate for custom tab demo. /* Activate for custom tab demo.
tabFrame.setUserTabComponentAt(new JLabel("NORTH (custom tab)") {{ tabFrame.setUserTabComponentAt(new JLabel("NORTH (custom tab)") {{
setBorder(new EmptyBorder(0, 5, 0, 5)); setBorder(new EmptyBorder(0, 5, 0, 5));

2
src/test/java/ToolBarDemo.java

@ -37,7 +37,6 @@
*/ */
import com.weis.darklaf.LafManager; import com.weis.darklaf.LafManager;
import com.weis.darklaf.theme.Theme;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import javax.swing.*; import javax.swing.*;
@ -109,7 +108,6 @@ public class ToolBarDemo extends JPanel implements ActionListener {
button.setIcon(new ImageIcon(imageURL, altText)); button.setIcon(new ImageIcon(imageURL, altText));
} else { //no image found } else { //no image found
button.setText(altText); button.setText(altText);
System.err.println("Resource not found: " + imgLocation);
} }
return button; return button;

13
src/test/java/UIDemo.java

@ -1,5 +1,6 @@
import com.weis.darklaf.LafManager; import com.weis.darklaf.LafManager;
import com.weis.darklaf.components.TextFieldHistory; import com.weis.darklaf.components.text.SearchTextField;
import com.weis.darklaf.components.text.SearchTextFieldWithHistory;
import com.weis.darklaf.components.tristate.TristateCheckBox; import com.weis.darklaf.components.tristate.TristateCheckBox;
import com.weis.darklaf.icons.IconLoader; import com.weis.darklaf.icons.IconLoader;
import org.jdesktop.swingx.JXStatusBar; import org.jdesktop.swingx.JXStatusBar;
@ -141,14 +142,8 @@ public final class UIDemo {
add(new JTextField("TextField") {{ add(new JTextField("TextField") {{
putClientProperty("JTextField.alternativeArc", Boolean.TRUE); putClientProperty("JTextField.alternativeArc", Boolean.TRUE);
}}); }});
add(new JTextField("SearchField") {{ add(new SearchTextField("SearchField"));
putClientProperty("JTextField.variant", "search"); add(new SearchTextFieldWithHistory("SearchFieldWithHistory"));
}});
add(new JTextField("SearchFieldWithHistory") {{
putClientProperty("JTextField.variant", "search");
putClientProperty("JTextField.Search.FindPopup",
new TextFieldHistory(this, 50, 100));
}});
add(new JPasswordField("Password")); add(new JPasswordField("Password"));
add(new JPasswordField("VeryStrongPassword") {{ add(new JPasswordField("VeryStrongPassword") {{
putClientProperty("JTextField.alternativeArc", Boolean.TRUE); putClientProperty("JTextField.alternativeArc", Boolean.TRUE);

Loading…
Cancel
Save