mirror of
https://github.com/carlrobertoh/ProxyAI.git
synced 2026-05-03 14:10:51 +00:00
Change project's name, heavy refactoring
This commit is contained in:
parent
c0cea7cc43
commit
483abe146b
80 changed files with 969 additions and 968 deletions
|
|
@ -0,0 +1,299 @@
|
|||
package ee.carlrobert.codegpt.ide.toolwindow.components;
|
||||
|
||||
import java.awt.*;
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.*;
|
||||
|
||||
// https://tips4java.wordpress.com/2009/09/27/component-border/
|
||||
/**
|
||||
* The ComponentBorder class allows you to place a real component in
|
||||
* the space reserved for painting the Border of a component.
|
||||
*
|
||||
* This class takes advantage of the knowledge that all Swing components are
|
||||
* also Containers. By default the layout manager is null, so we should be
|
||||
* able to place a child component anywhere in the parent component. In order
|
||||
* to prevent the child component from painting over top of the parent
|
||||
* component a Border is added to the parent componet such that the insets of
|
||||
* the Border will reserve space for the child component to be painted without
|
||||
* affecting the parent component.
|
||||
*/
|
||||
public class ComponentBorder implements Border
|
||||
{
|
||||
public enum Edge
|
||||
{
|
||||
TOP,
|
||||
LEFT,
|
||||
BOTTOM,
|
||||
RIGHT;
|
||||
}
|
||||
|
||||
public static final float LEADING = 0.0f;
|
||||
public static final float CENTER = 0.5f;
|
||||
public static final float TRAILING = 1.0f;
|
||||
|
||||
private JComponent parent;
|
||||
private JComponent component;
|
||||
private Edge edge;
|
||||
private float alignment;
|
||||
private int gap = 5;
|
||||
private boolean adjustInsets = true;
|
||||
private Insets borderInsets = new Insets(0, 0, 0, 0);
|
||||
|
||||
/**
|
||||
* Convenience constructor that uses the default edge (Edge.RIGHT) and
|
||||
* alignment (CENTER).
|
||||
*
|
||||
* @param component the component to be added in the Border area
|
||||
*/
|
||||
public ComponentBorder(JComponent component)
|
||||
{
|
||||
this(component, Edge.RIGHT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience constructor that uses the default alignment (CENTER).
|
||||
*
|
||||
* @param component the component to be added in the Border area
|
||||
* @param edge a valid Edge enum of TOP, LEFT, BOTTOM, RIGHT
|
||||
*/
|
||||
public ComponentBorder(JComponent component, Edge edge)
|
||||
{
|
||||
this(component, edge, CENTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main constructor to create a ComponentBorder.
|
||||
*
|
||||
* @param component the component to be added in the Border area
|
||||
* @param edge a valid Edge enum of TOP, LEFT, BOTTOM, RIGHT
|
||||
* @param alignment the alignment of the component along the
|
||||
* specified Edge. Must be in the range 0 - 1.0.
|
||||
*/
|
||||
public ComponentBorder(JComponent component, Edge edge, float alignment )
|
||||
{
|
||||
this.component = component;
|
||||
component.setSize( component.getPreferredSize() );
|
||||
component.setCursor(Cursor.getDefaultCursor());
|
||||
setEdge( edge );
|
||||
setAlignment( alignment );
|
||||
}
|
||||
|
||||
public boolean isAdjustInsets()
|
||||
{
|
||||
return adjustInsets;
|
||||
}
|
||||
|
||||
public void setAdjustInsets(boolean adjustInsets)
|
||||
{
|
||||
this.adjustInsets = adjustInsets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the component alignment along the Border Edge
|
||||
*
|
||||
* @return the alignment
|
||||
*/
|
||||
public float getAlignment()
|
||||
{
|
||||
return alignment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the component alignment along the Border Edge
|
||||
*
|
||||
* @param alignment a value in the range 0 - 1.0. Standard values would be
|
||||
* CENTER (default), LEFT and RIGHT.
|
||||
*/
|
||||
public void setAlignment(float alignment)
|
||||
{
|
||||
this.alignment = alignment > 1.0f ? 1.0f : alignment < 0.0f ? 0.0f : alignment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Edge the component is positioned along
|
||||
*
|
||||
* @return the Edge
|
||||
*/
|
||||
public Edge getEdge()
|
||||
{
|
||||
return edge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Edge the component is positioned along
|
||||
*
|
||||
* @param edge the Edge the component is position on.
|
||||
*/
|
||||
public void setEdge(Edge edge)
|
||||
{
|
||||
this.edge = edge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the gap between the border component and the parent component
|
||||
*
|
||||
* @return the gap in pixels.
|
||||
*/
|
||||
public int getGap()
|
||||
{
|
||||
return gap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the gap between the border component and the parent component
|
||||
*
|
||||
* @param gap the gap in pixels (default is 5)
|
||||
*/
|
||||
public void setGap(int gap)
|
||||
{
|
||||
this.gap = gap;
|
||||
}
|
||||
|
||||
//
|
||||
// Implement the Border interface
|
||||
//
|
||||
|
||||
public Insets getBorderInsets(Component c)
|
||||
{
|
||||
return borderInsets;
|
||||
}
|
||||
|
||||
public boolean isBorderOpaque()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* In this case a real component is to be painted. Setting the location
|
||||
* of the component will cause it to be painted at that location.
|
||||
*/
|
||||
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height)
|
||||
{
|
||||
float x2 = (width - component.getWidth()) * component.getAlignmentX() + x;
|
||||
float y2 = (height - component.getHeight()) * component.getAlignmentY() + y;
|
||||
component.setLocation((int)x2, (int)y2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Install this Border on the specified component by replacing the
|
||||
* existing Border with a CompoundBorder containing the original Border
|
||||
* and our ComponentBorder
|
||||
*
|
||||
* This method should only be invoked once all the properties of this
|
||||
* class have been set. Installing the Border more than once will cause
|
||||
* unpredictable results.
|
||||
*/
|
||||
public void install(JComponent parent)
|
||||
{
|
||||
this.parent = parent;
|
||||
|
||||
determineInsetsAndAlignment();
|
||||
|
||||
// Add this Border to the parent
|
||||
|
||||
Border current = parent.getBorder();
|
||||
|
||||
if (current == null)
|
||||
{
|
||||
parent.setBorder(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
CompoundBorder compound = new CompoundBorder(current, this);
|
||||
parent.setBorder(compound);
|
||||
}
|
||||
|
||||
// Add component to the parent
|
||||
|
||||
parent.add(component);
|
||||
}
|
||||
|
||||
/**
|
||||
* The insets need to be determined so they are included in the preferred
|
||||
* size of the component the Border is attached to.
|
||||
*
|
||||
* The alignment of the component is determined here so it doesn't need
|
||||
* to be recalculated every time the Border is painted.
|
||||
*/
|
||||
private void determineInsetsAndAlignment()
|
||||
{
|
||||
borderInsets = new Insets(0, 0, 0, 0);
|
||||
|
||||
// The insets will only be updated for the edge the component will be
|
||||
// diplayed on.
|
||||
//
|
||||
// The X, Y alignment of the component is controlled by both the edge
|
||||
// and alignment parameters
|
||||
|
||||
if (edge == Edge.TOP)
|
||||
{
|
||||
borderInsets.top = component.getPreferredSize().height + gap;
|
||||
component.setAlignmentX(alignment);
|
||||
component.setAlignmentY(0.0f);
|
||||
}
|
||||
else if (edge == Edge.BOTTOM)
|
||||
{
|
||||
borderInsets.bottom = component.getPreferredSize().height + gap;
|
||||
component.setAlignmentX(alignment);
|
||||
component.setAlignmentY(1.0f);
|
||||
}
|
||||
else if (edge == Edge.LEFT)
|
||||
{
|
||||
borderInsets.left = component.getPreferredSize().width + gap;
|
||||
component.setAlignmentX(0.0f);
|
||||
component.setAlignmentY(alignment);
|
||||
}
|
||||
else if (edge == Edge.RIGHT)
|
||||
{
|
||||
borderInsets.right = component.getPreferredSize().width + gap;
|
||||
component.setAlignmentX(1.0f);
|
||||
component.setAlignmentY(alignment);
|
||||
}
|
||||
|
||||
if (adjustInsets)
|
||||
adjustBorderInsets();
|
||||
}
|
||||
|
||||
/*
|
||||
* The complimentary edges of the Border may need to be adjusted to allow
|
||||
* the component to fit completely in the bounds of the parent component.
|
||||
*/
|
||||
private void adjustBorderInsets()
|
||||
{
|
||||
Insets parentInsets = parent.getInsets();
|
||||
|
||||
// May need to adust the height of the parent component to fit
|
||||
// the component in the Border
|
||||
|
||||
if (edge == Edge.RIGHT || edge == Edge.LEFT)
|
||||
{
|
||||
int parentHeight = parent.getPreferredSize().height - parentInsets.top - parentInsets.bottom;
|
||||
int diff = component.getHeight() - parentHeight;
|
||||
|
||||
if (diff > 0)
|
||||
{
|
||||
int topDiff = (int)(diff * alignment);
|
||||
int bottomDiff = diff - topDiff;
|
||||
borderInsets.top += topDiff;
|
||||
borderInsets.bottom += bottomDiff;
|
||||
}
|
||||
}
|
||||
|
||||
// May need to adust the width of the parent component to fit
|
||||
// the component in the Border
|
||||
|
||||
if (edge == Edge.TOP || edge == Edge.BOTTOM)
|
||||
{
|
||||
int parentWidth = parent.getPreferredSize().width - parentInsets.left - parentInsets.right;
|
||||
int diff = component.getWidth() - parentWidth;
|
||||
|
||||
if (diff > 0)
|
||||
{
|
||||
int leftDiff = (int)(diff * alignment);
|
||||
int rightDiff = diff - leftDiff;
|
||||
borderInsets.left += leftDiff;
|
||||
borderInsets.right += rightDiff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package ee.carlrobert.codegpt.ide.toolwindow.components;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.SwingConstants;
|
||||
|
||||
public class GenerateButton extends JButton {
|
||||
|
||||
public GenerateButton() {
|
||||
initialize();
|
||||
}
|
||||
|
||||
public void setMode(Mode mode, Runnable onClick) {
|
||||
var isStopMode = mode == Mode.STOP;
|
||||
setIcon(isStopMode ? AllIcons.Actions.Suspend : AllIcons.Actions.Refresh);
|
||||
setText(isStopMode ? "Stop generating" : "Regenerate response");
|
||||
for (var listener : getActionListeners()) {
|
||||
removeActionListener(listener);
|
||||
}
|
||||
addActionListener(e -> onClick.run());
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
setVerticalTextPosition(SwingConstants.CENTER);
|
||||
setHorizontalTextPosition(SwingConstants.RIGHT);
|
||||
setVerticalAlignment(SwingConstants.CENTER);
|
||||
setAlignmentY(0.5f);
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
public enum Mode {
|
||||
STOP,
|
||||
REFRESH
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package ee.carlrobert.codegpt.ide.toolwindow.components;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import icons.Icons;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.util.List;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingConstants;
|
||||
|
||||
public class LandingView {
|
||||
|
||||
private static final List<String> questions = List.of("How do I make an HTTP request in Javascript?",
|
||||
"What is the difference between px, dip, dp, and sp?",
|
||||
"How do I undo the most recent local commits in Git?",
|
||||
"What is the difference between stack and heap?");
|
||||
|
||||
public List<JPanel> getQuestionPanels() {
|
||||
return questions.stream()
|
||||
.map(this::createQuestionPanel)
|
||||
.collect(toList());
|
||||
}
|
||||
|
||||
public JPanel createImageIconPanel() {
|
||||
var imageIconPanel = new JPanel();
|
||||
imageIconPanel.setLayout(new GridBagLayout());
|
||||
var imageIconLabel = new JLabel(Icons.SunImageIcon);
|
||||
imageIconLabel.setHorizontalAlignment(JLabel.CENTER);
|
||||
imageIconPanel.add(imageIconLabel);
|
||||
return imageIconPanel;
|
||||
}
|
||||
|
||||
private JPanel createQuestionPanel(String question) {
|
||||
var panel = new JPanel();
|
||||
panel.setLayout(new GridBagLayout());
|
||||
var label = new JLabel(question, SwingConstants.CENTER);
|
||||
label.setHorizontalAlignment(JLabel.CENTER);
|
||||
panel.add(label);
|
||||
return panel;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package ee.carlrobert.codegpt.ide.toolwindow.components;
|
||||
|
||||
import com.intellij.openapi.roots.ui.componentsList.components.ScrollablePanel;
|
||||
import com.intellij.ui.components.JBScrollPane;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import java.awt.Adjustable;
|
||||
import java.awt.event.AdjustmentEvent;
|
||||
import java.awt.event.AdjustmentListener;
|
||||
import javax.swing.JScrollBar;
|
||||
import javax.swing.ScrollPaneConstants;
|
||||
|
||||
public class ScrollPane extends JBScrollPane {
|
||||
|
||||
public ScrollPane(ScrollablePanel scrollablePanel) {
|
||||
super(scrollablePanel);
|
||||
setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
setBorder(JBUI.Borders.empty(0, 8));
|
||||
setViewportBorder(null);
|
||||
}
|
||||
|
||||
public void scrollToBottom() {
|
||||
JScrollBar verticalBar = getVerticalScrollBar();
|
||||
verticalBar.addAdjustmentListener(new AdjustmentListener() {
|
||||
public void adjustmentValueChanged(AdjustmentEvent e) {
|
||||
Adjustable adjustable = e.getAdjustable();
|
||||
adjustable.setValue(adjustable.getMaximum());
|
||||
verticalBar.removeAdjustmentListener(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
package ee.carlrobert.codegpt.ide.toolwindow.components;
|
||||
|
||||
import com.intellij.ui.JBColor;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.event.ActionEvent;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.KeyStroke;
|
||||
|
||||
public class SwingUtils {
|
||||
|
||||
public static JTextArea createTextArea(String selectedText) {
|
||||
var textArea = new JTextArea();
|
||||
textArea.append(selectedText);
|
||||
textArea.setLineWrap(true);
|
||||
textArea.setEditable(false);
|
||||
textArea.setFont(textArea.getFont().deriveFont(Font.ITALIC));
|
||||
textArea.setWrapStyleWord(true);
|
||||
textArea.setBackground(JBColor.PanelBackground);
|
||||
return textArea;
|
||||
}
|
||||
|
||||
public static JLabel createIconLabel(Icon icon, String text) {
|
||||
var iconLabel = new JLabel(icon);
|
||||
iconLabel.setText(text);
|
||||
iconLabel.setFont(iconLabel.getFont().deriveFont(iconLabel.getFont().getStyle() | Font.BOLD));
|
||||
iconLabel.setIconTextGap(8);
|
||||
return iconLabel;
|
||||
}
|
||||
|
||||
public static JButton createIconButton(Icon icon) {
|
||||
var button = new JButton(icon);
|
||||
button.setBorder(BorderFactory.createEmptyBorder());
|
||||
button.setContentAreaFilled(false);
|
||||
button.setPreferredSize(new Dimension(icon.getIconWidth(), icon.getIconHeight()));
|
||||
return button;
|
||||
}
|
||||
|
||||
public static Box justifyLeft(Component component) {
|
||||
Box box = Box.createHorizontalBox();
|
||||
box.add(component);
|
||||
box.add(Box.createHorizontalGlue());
|
||||
return box;
|
||||
}
|
||||
|
||||
public static void addShiftEnterInputMap(JTextArea textArea, Runnable onEnter) {
|
||||
var input = textArea.getInputMap();
|
||||
var enterStroke = KeyStroke.getKeyStroke("ENTER");
|
||||
var shiftEnterStroke = KeyStroke.getKeyStroke("shift ENTER");
|
||||
input.put(shiftEnterStroke, "insert-break");
|
||||
input.put(enterStroke, "text-submit");
|
||||
|
||||
var actions = textArea.getActionMap();
|
||||
actions.put("text-submit", new AbstractAction() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
onEnter.run();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
package ee.carlrobert.codegpt.ide.toolwindow.components;
|
||||
|
||||
import static ee.carlrobert.codegpt.ide.toolwindow.components.SwingUtils.createIconButton;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.datatransfer.Clipboard;
|
||||
import java.awt.datatransfer.StringSelection;
|
||||
import java.io.IOException;
|
||||
import javax.swing.JButton;
|
||||
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
|
||||
import org.fife.ui.rsyntaxtextarea.Theme;
|
||||
import org.fife.ui.rtextarea.CaretStyle;
|
||||
|
||||
public class SyntaxTextArea extends RSyntaxTextArea {
|
||||
|
||||
public SyntaxTextArea(boolean isReadOnly, boolean withBlockCaret, String syntax) {
|
||||
super("");
|
||||
setStyles(isReadOnly, withBlockCaret, syntax);
|
||||
}
|
||||
|
||||
public void displayCopyButton() {
|
||||
ComponentBorder cb = new ComponentBorder(createCopyButton());
|
||||
cb.setAlignment(TOP_ALIGNMENT);
|
||||
cb.install(this);
|
||||
}
|
||||
|
||||
public void hideCaret() {
|
||||
getCaret().setVisible(false);
|
||||
}
|
||||
|
||||
public void changeStyleViaThemeXml() {
|
||||
var baseThemePath = "/org/fife/ui/rsyntaxtextarea/themes/";
|
||||
try {
|
||||
Theme theme = Theme.load(getClass().getResourceAsStream(
|
||||
UIUtil.isUnderDarcula() ? baseThemePath + "dark.xml" : baseThemePath + "idea.xml"));
|
||||
theme.apply(this);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void setStyles(boolean isReadOnly, boolean withBlockCaret, String syntax) {
|
||||
setMargin(JBUI.insets(5));
|
||||
setAntiAliasingEnabled(true);
|
||||
setEnabled(true);
|
||||
setEditable(!isReadOnly);
|
||||
setPaintTabLines(false);
|
||||
setHighlightCurrentLine(false);
|
||||
setLineWrap(true);
|
||||
if (withBlockCaret) {
|
||||
setCaretStyle(0, CaretStyle.BLOCK_STYLE);
|
||||
getCaret().setVisible(true);
|
||||
}
|
||||
setSyntaxEditingStyle(syntax);
|
||||
changeStyleViaThemeXml();
|
||||
}
|
||||
|
||||
private void copyToClipboard() {
|
||||
StringSelection stringSelection = new StringSelection(getText().trim());
|
||||
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
|
||||
clipboard.setContents(stringSelection, null);
|
||||
}
|
||||
|
||||
private JButton createCopyButton() {
|
||||
var button = createIconButton(AllIcons.General.InlineCopy);
|
||||
button.addActionListener(e -> {
|
||||
copyToClipboard();
|
||||
button.setIcon(AllIcons.General.InspectionsOK);
|
||||
});
|
||||
return button;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
package ee.carlrobert.codegpt.ide.toolwindow.components;
|
||||
|
||||
import static ee.carlrobert.codegpt.ide.toolwindow.components.SwingUtils.addShiftEnterInputMap;
|
||||
import static ee.carlrobert.codegpt.ide.toolwindow.components.SwingUtils.createIconButton;
|
||||
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.ui.components.JBTextArea;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import icons.Icons;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JScrollPane;
|
||||
|
||||
public class TextArea extends JBTextArea {
|
||||
|
||||
public TextArea(Runnable onSubmit, JScrollPane textAreaScrollPane) {
|
||||
super("Ask me anything...");
|
||||
setForeground(JBColor.GRAY);
|
||||
setMargin(JBUI.insets(5));
|
||||
addFocusListener(getFocusListener());
|
||||
addSubmitButton(onSubmit, textAreaScrollPane);
|
||||
addShiftEnterInputMap(this, onSubmit);
|
||||
}
|
||||
|
||||
private void addSubmitButton(Runnable onSubmit, JScrollPane textAreaScrollPane) {
|
||||
var button = createSubmitButton(e -> onSubmit.run());
|
||||
ComponentBorder cb = new ComponentBorder(button);
|
||||
cb.setAdjustInsets(true);
|
||||
cb.install(textAreaScrollPane);
|
||||
}
|
||||
|
||||
private JButton createSubmitButton(ActionListener submitButtonListener) {
|
||||
var button = createIconButton(Icons.SendImageIcon);
|
||||
button.addActionListener(submitButtonListener);
|
||||
return button;
|
||||
}
|
||||
|
||||
private FocusListener getFocusListener() {
|
||||
return new FocusListener() {
|
||||
public void focusGained(FocusEvent e) {
|
||||
if (getText().equals("Ask me anything...")) {
|
||||
setText("");
|
||||
setForeground(JBColor.BLACK);
|
||||
}
|
||||
}
|
||||
|
||||
public void focusLost(FocusEvent e) {
|
||||
if (getText().isEmpty()) {
|
||||
setForeground(JBColor.GRAY);
|
||||
setText("Ask me anything...");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue