Skip to content

Commit 6ac2a72

Browse files
jGauravGuptastefanofornari
authored andcommitted
feat: Implement #9: Show Jeddict icon in NetBeans menus
This commit implements the user story from issue #9, allowing Jeddict icons to be displayed before menu items in NetBeans, enhancing visibility and usability. As part of this feature, significant refactoring was undertaken to improve code quality and maintainability: - Introduced `BaseGitAction` to centralize Git project-related action logic. - Introduced `BaseContextAction` for common context-aware action functionalities. - Introduced `BaseProjectContextAction` for project-specific context actions. - Refactored `GenerateCommitMessageAction` and `ReviewAction` to leverage these new base classes. - Added comprehensive Javadoc to all classes within the `io.github.jeddict.ai.actions` package for improved code documentation.
2 parents 0b68e14 + 2364799 commit 6ac2a72

18 files changed

Lines changed: 1424 additions & 568 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,4 @@ hs_err_pid*
2424
replay_pid*
2525
/target/
2626
test
27+
/src/var/

src/main/java/io/github/jeddict/ai/actions/AIAssistantPopupAction.java

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@
1818
import io.github.jeddict.ai.hints.AssistantChatManager;
1919
import java.awt.event.ActionEvent;
2020
import java.awt.event.ActionListener;
21-
import javax.swing.AbstractAction;
22-
import static javax.swing.Action.NAME;
2321
import javax.swing.JOptionPane;
2422
import javax.swing.text.BadLocationException;
2523
import javax.swing.text.JTextComponent;
@@ -37,26 +35,42 @@
3735
import org.openide.util.Exceptions;
3836
import org.openide.util.NbBundle;
3937

38+
/**
39+
* A popup action that provides AI assistance in the editor. This action is
40+
* available in the editor's context menu and can be invoked with a shortcut.
41+
* It opens a chat window with the selected text and allows the user to interact
42+
* with the AI assistant to modify the code.
43+
*/
4044
@ActionID(
41-
category = "Edit/Chat",
42-
id = "io.github.jeddict.ai.actions.AIAssistantPopupAction"
45+
category = "Edit/Chat",
46+
id = "io.github.jeddict.ai.actions.AIAssistantPopupAction"
4347
)
4448
@ActionRegistration(
45-
displayName = "#CTL_AIAssistantPopupAction", lazy = false
49+
displayName = "#CTL_AIAssistantPopupAction",
50+
lazy = false,
51+
iconInMenu = true,
52+
iconBase = "icons/logo16.png"
4653
)
4754
@ActionReferences({
4855
@ActionReference(path = "Editors/Popup", position = 101),
4956
@ActionReference(path = "Shortcuts", name = "C-QUOTE")
5057
})
5158
@NbBundle.Messages("CTL_AIAssistantPopupAction=AI Assistant")
52-
public final class AIAssistantPopupAction extends AbstractAction implements ActionListener {
59+
public final class AIAssistantPopupAction extends BaseContextAction implements ActionListener {
5360

61+
/**
62+
* Constructs a new AIAssistantPopupAction.
63+
*/
5464
public AIAssistantPopupAction() {
55-
putValue(NAME, Bundle.CTL_AIAssistantPopupAction());
56-
setEnabled(true);
65+
super(Bundle.CTL_AIAssistantPopupAction(), true);
5766
}
5867

59-
68+
/**
69+
* Opens the AI assistant chat window with the selected text from the
70+
* editor.
71+
*
72+
* @param e the action event.
73+
*/
6074
@Override
6175
public void actionPerformed(ActionEvent e) {
6276

@@ -101,6 +115,15 @@ public void actionPerformed(ActionEvent e) {
101115
});
102116
}
103117

118+
/**
119+
* Inserts the given content into the document and reformats the inserted
120+
* text.
121+
*
122+
* @param document the document to modify.
123+
* @param content the content to insert.
124+
* @param startPosition the position at which to insert the content.
125+
* @param lengthToRemove the length of the text to remove.
126+
*/
104127
private void insertAndReformat(StyledDocument document, String content, int startPosition, int lengthToRemove) {
105128
try {
106129
if (lengthToRemove > 0) {

src/main/java/io/github/jeddict/ai/actions/AddToChatContextAction.java

Lines changed: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,21 @@
3232
import org.openide.windows.TopComponent;
3333
import org.openide.windows.WindowManager;
3434

35+
/**
36+
* An action that adds the selected file(s) or folder(s) to the current AI
37+
* chat session context. This action is available in the context menu of files
38+
* and folders in the Projects view.
39+
*/
3540
@ActionID(
36-
category = "Project",
37-
id = "io.github.jeddict.ai.actions.AddToChatContextAction"
41+
category = "Project",
42+
id = "io.github.jeddict.ai.actions.AddToChatContextAction"
3843
)
3944
@ActionRegistration(
40-
displayName = "#CTL_AddToChatContextAction",
41-
lazy = false,
42-
asynchronous = false
45+
displayName = "#CTL_AddToChatContextAction",
46+
lazy = false,
47+
iconInMenu = true,
48+
iconBase = "icons/logo16.png",
49+
asynchronous = false
4350
)
4451
@ActionReferences({
4552
@ActionReference(path = "Projects/package/Actions", position = 101),
@@ -49,23 +56,45 @@
4956
@Messages({"CTL_AddToChatContextAction=Add to Chat Session Context"})
5057
public final class AddToChatContextAction extends AbstractAction implements ContextAwareAction {
5158

59+
/**
60+
* This method is never called directly. The action is handled by the
61+
* context-aware instance.
62+
*
63+
* @param e the action event.
64+
*/
5265
@Override
5366
public void actionPerformed(ActionEvent e) {
54-
// nikdy nebude volaná priamo - len cez ContextAction
67+
// It will never be called directly—only through ContextAction
5568
}
5669

70+
/**
71+
* Creates a context-aware instance of this action.
72+
*
73+
* @param context the lookup context.
74+
* @return a new instance of the context-aware action.
75+
*/
5776
@Override
5877
public Action createContextAwareInstance(Lookup context) {
5978
List<FileObject> files = new ArrayList<>(context.lookupAll(FileObject.class));
6079
boolean en = !files.isEmpty() && isAssistantChatOpened();
6180
return new ContextAction(en, files);
6281
}
6382

83+
/**
84+
* Returns true if the AI assistant chat is opened, false otherwise.
85+
*
86+
* @return true if the AI assistant chat is opened, false otherwise.
87+
*/
6488
@Override
6589
public boolean isEnabled() {
6690
return isAssistantChatOpened();
6791
}
6892

93+
/**
94+
* Checks if the AI assistant chat window is opened and showing.
95+
*
96+
* @return true if the chat window is opened and showing, false otherwise.
97+
*/
6998
private static boolean isAssistantChatOpened() {
7099
Set<? extends Mode> modes = WindowManager.getDefault().getModes();
71100
for (Mode mode : modes) {
@@ -81,6 +110,11 @@ private static boolean isAssistantChatOpened() {
81110
return false;
82111
}
83112

113+
/**
114+
* Returns the opened AI assistant chat window.
115+
*
116+
* @return the opened chat window, or null if it is not opened.
117+
*/
84118
private static TopComponent getOpenedAssistantChat() {
85119
Set<? extends Mode> modes = WindowManager.getDefault().getModes();
86120
for (Mode mode : modes) {
@@ -96,17 +130,30 @@ private static TopComponent getOpenedAssistantChat() {
96130
return null;
97131
}
98132

99-
private static final class ContextAction extends AbstractAction {
133+
/**
134+
* The context-aware action that adds the selected files to the chat
135+
* session.
136+
*/
137+
private static final class ContextAction extends BaseContextAction {
100138

101139
private final List<FileObject> files;
102140

141+
/**
142+
* Constructs a new ContextAction.
143+
*
144+
* @param enabled true to enable the action, false to disable it.
145+
* @param files the list of files to add to the chat session.
146+
*/
103147
private ContextAction(boolean enabled, List<FileObject> files) {
104-
super(Bundle.CTL_AddToChatContextAction());
148+
super(Bundle.CTL_AddToChatContextAction(), enabled);
105149
this.files = files;
106-
this.putValue(DynamicMenuContent.HIDE_WHEN_DISABLED, true);
107-
setEnabled(enabled);
108150
}
109151

152+
/**
153+
* Adds the selected files to the chat session context.
154+
*
155+
* @param e the action event.
156+
*/
110157
@Override
111158
public void actionPerformed(ActionEvent e) {
112159
TopComponent openedAssistantChat = getOpenedAssistantChat();
@@ -121,6 +168,11 @@ public void actionPerformed(ActionEvent e) {
121168
}
122169
}
123170

171+
/**
172+
* Returns true if the AI assistant chat is opened, false otherwise.
173+
*
174+
* @return true if the AI assistant chat is opened, false otherwise.
175+
*/
124176
@Override
125177
public boolean isEnabled() {
126178
return isAssistantChatOpened();

src/main/java/io/github/jeddict/ai/actions/AskAIDBAction.java

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,26 @@
2727
import org.openide.awt.ActionReference;
2828
import org.openide.awt.ActionReferences;
2929
import org.openide.awt.ActionRegistration;
30-
import org.openide.awt.DynamicMenuContent;
3130
import org.openide.util.ContextAwareAction;
3231
import org.openide.util.Lookup;
3332
import org.openide.util.NbBundle.Messages;
3433

34+
/**
35+
* An action that allows the user to ask AI questions about a database
36+
* connection. This action is available in the context menu of a database
37+
* connection in the Services window.
38+
*/
3539
@ActionID(
36-
category = "File",
37-
id = "io.github.jeddict.ai.actions.AskAIDBAction")
40+
category = "File",
41+
id = "io.github.jeddict.ai.actions.AskAIDBAction"
42+
)
3843
@ActionRegistration(
39-
displayName = "#CTL_AskAIDBAction", lazy = false, asynchronous = true)
44+
displayName = "#CTL_AskAIDBAction",
45+
lazy = false,
46+
asynchronous = true,
47+
iconInMenu = true,
48+
iconBase = "icons/logo16.png"
49+
)
4050
@ActionReferences({
4151
@ActionReference(path = "Databases/Explorer/Connection/Actions", position = 350),
4252
// @ActionReference(path = "Databases/Explorer/Catalog/Actions", position = 350),
@@ -50,10 +60,22 @@
5060
@Messages({"CTL_AskAIDBAction=AI Assistant"})
5161
public final class AskAIDBAction extends AbstractAction implements ContextAwareAction {
5262

63+
/**
64+
* This method is never called directly. The action is handled by the
65+
* context-aware instance.
66+
*
67+
* @param ev the action event.
68+
*/
5369
@Override
5470
public void actionPerformed(ActionEvent ev) {
5571
}
5672

73+
/**
74+
* Creates a context-aware instance of this action.
75+
*
76+
* @param actionContext the lookup context.
77+
* @return a new instance of the context-aware action.
78+
*/
5779
@Override
5880
public Action createContextAwareInstance(Lookup actionContext) {
5981
if (actionContext != null) {
@@ -65,17 +87,30 @@ public Action createContextAwareInstance(Lookup actionContext) {
6587
return new AskAIDBAction.ContextAction(false, null);
6688
}
6789

68-
private static final class ContextAction extends AbstractAction {
90+
/**
91+
* The context-aware action that opens the AI chat window for the selected
92+
* database connection.
93+
*/
94+
private static final class ContextAction extends BaseContextAction {
6995

7096
private final DatabaseConnection connection;
7197

98+
/**
99+
* Constructs a new ContextAction.
100+
*
101+
* @param enable true to enable the action, false to disable it.
102+
* @param connection the database connection.
103+
*/
72104
private ContextAction(boolean enable, DatabaseConnection connection) {
73-
super(Bundle.CTL_AskAIDBAction());
74-
this.putValue(DynamicMenuContent.HIDE_WHEN_DISABLED, true);
75-
this.setEnabled(enable);
105+
super(Bundle.CTL_AskAIDBAction(), enable);
76106
this.connection = connection;
77107
}
78108

109+
/**
110+
* Opens the AI chat window for the selected database connection.
111+
*
112+
* @param evt the action event.
113+
*/
79114
@Override
80115
public void actionPerformed(ActionEvent evt) {
81116
if (connection == null) {

src/main/java/io/github/jeddict/ai/actions/AskAIPackageAction.java

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,31 +30,51 @@
3030
import org.openide.awt.ActionReference;
3131
import org.openide.awt.ActionReferences;
3232
import org.openide.awt.ActionRegistration;
33-
import org.openide.awt.DynamicMenuContent;
3433
import org.openide.filesystems.FileObject;
3534
import org.openide.util.ContextAwareAction;
3635
import org.openide.util.Lookup;
3736
import org.openide.util.NbBundle.Messages;
3837

38+
/**
39+
* An action that allows the user to ask AI questions about a package or a file.
40+
* This action is available in the context menu of a package or a file in the
41+
* Projects view.
42+
*/
3943
@ActionID(
40-
category = "Project",
41-
id = "io.github.jeddict.ai.actions.AskAIPackageAction")
44+
category = "Project",
45+
id = "io.github.jeddict.ai.actions.AskAIPackageAction"
46+
)
4247
@ActionRegistration(
43-
displayName = "#CTL_AskAIPackageAction", lazy = true, asynchronous = true, iconBase = "icons/logo28.png")
48+
displayName = "#CTL_AskAIPackageAction",
49+
lazy = false,
50+
asynchronous = true,
51+
iconBase = "icons/logo16.png"
52+
)
4453
@ActionReferences({
4554
@ActionReference(path = "Projects/package/Actions", position = 100),
46-
@ActionReference(path="Loaders/text/x-java/Actions", position=100),
55+
@ActionReference(path = "Loaders/text/x-java/Actions", position=100),
4756
@ActionReference(path = "Loaders/folder/any/Actions", position = 300),
4857
@ActionReference(path = "Toolbars/Build", position = 100)})
4958
@Messages({"CTL_AskAIPackageAction=AI Assistant"})
5059
public final class AskAIPackageAction extends AbstractAction implements ContextAwareAction {
5160

61+
/**
62+
* Opens the AI assistant chat window.
63+
*
64+
* @param ev the action event.
65+
*/
5266
@Override
5367
public void actionPerformed(ActionEvent ev) {
5468
AssistantChatManager learnFix = new AssistantChatManager(io.github.jeddict.ai.completion.Action.QUERY);
5569
learnFix.openChat(null, "", null, "AI Assistant", null);
5670
}
5771

72+
/**
73+
* Creates a context-aware instance of this action.
74+
*
75+
* @param actionContext the lookup context.
76+
* @return a new instance of the context-aware action.
77+
*/
5878
@Override
5979
public Action createContextAwareInstance(Lookup actionContext) {
6080
if (actionContext != null) {
@@ -70,17 +90,30 @@ public Action createContextAwareInstance(Lookup actionContext) {
7090
return new AskAIPackageAction.ContextAction(false, null);
7191
}
7292

73-
private static final class ContextAction extends AbstractAction {
93+
/**
94+
* The context-aware action that opens the AI chat window for the selected
95+
* package or file.
96+
*/
97+
private static final class ContextAction extends BaseContextAction {
7498

7599
private final List<FileObject> selectedFileObjects;
76100

101+
/**
102+
* Constructs a new ContextAction.
103+
*
104+
* @param enable true to enable the action, false to disable it.
105+
* @param selectedPackages the list of selected packages or files.
106+
*/
77107
private ContextAction(boolean enable, List<FileObject> selectedPackages) {
78-
super(Bundle.CTL_AskAIPackageAction());
79-
this.putValue(DynamicMenuContent.HIDE_WHEN_DISABLED, true);
80-
this.setEnabled(enable);
108+
super(Bundle.CTL_AskAIPackageAction(), enable);
81109
this.selectedFileObjects = selectedPackages;
82110
}
83111

112+
/**
113+
* Opens the AI chat window for the selected package or file.
114+
*
115+
* @param evt the action event.
116+
*/
84117
@Override
85118
public void actionPerformed(ActionEvent evt) {
86119
AssistantChatManager learnFix = new AssistantChatManager(io.github.jeddict.ai.completion.Action.QUERY, selectedFileObjects);

0 commit comments

Comments
 (0)