mirror of https://github.com/weisJ/darklaf.git
weisj
5 years ago
43 changed files with 2091 additions and 350 deletions
@ -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(); |
||||
} |
||||
} |
@ -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; |
||||
} |
||||
} |
@ -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); |
||||
} |
@ -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 >= 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> < 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); |
||||
} |
||||
} |
@ -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 >= 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> < 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); |
||||
} |
||||
} |
||||
} |
@ -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(); |
||||
} |
||||
} |
@ -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); |
||||
} |
||||
} |
||||
} |
@ -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; |
||||
} |
||||
} |
||||
} |
@ -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()); |
||||
} |
||||
} |
Loading…
Reference in new issue