28
28
29
29
import java .awt .BorderLayout ;
30
30
import java .awt .Font ;
31
+ import java .awt .Toolkit ;
31
32
import java .awt .event .ActionEvent ;
32
33
import java .awt .event .ActionListener ;
34
+ import java .awt .event .InputEvent ;
35
+ import java .awt .event .KeyEvent ;
33
36
import java .awt .event .MouseWheelListener ;
34
37
import java .awt .event .MouseWheelEvent ;
35
38
36
39
import java .io .IOException ;
37
40
38
41
import javax .swing .Action ;
39
42
import javax .swing .BorderFactory ;
43
+ import javax .swing .Icon ;
44
+ import javax .swing .InputMap ;
45
+ import javax .swing .JComponent ;
40
46
import javax .swing .JMenuItem ;
41
47
import javax .swing .JPanel ;
42
48
import javax .swing .JPopupMenu ;
49
+ import javax .swing .KeyStroke ;
50
+ import javax .swing .SwingUtilities ;
43
51
import javax .swing .ToolTipManager ;
52
+ import javax .swing .UIManager ;
44
53
import javax .swing .border .MatteBorder ;
45
54
import javax .swing .event .PopupMenuEvent ;
46
55
import javax .swing .event .PopupMenuListener ;
52
61
53
62
import static java .nio .file .StandardWatchEventKinds .*;
54
63
import java .nio .file .WatchService ;
64
+ import java .util .ArrayList ;
65
+ import java .util .List ;
55
66
import java .nio .file .WatchKey ;
56
67
import java .nio .file .WatchEvent ;
57
68
import java .nio .file .FileSystems ;
58
69
import java .nio .file .Path ;
59
70
import java .io .File ;
60
71
61
72
import org .fife .ui .rsyntaxtextarea .RSyntaxDocument ;
73
+ import org .fife .ui .rsyntaxtextarea .RSyntaxTextArea ;
62
74
import org .fife .ui .rsyntaxtextarea .RSyntaxTextAreaEditorKit ;
63
75
import org .fife .ui .rsyntaxtextarea .RSyntaxUtilities ;
64
76
import org .fife .ui .rtextarea .Gutter ;
77
+ import org .fife .ui .rtextarea .GutterIconInfo ;
78
+ import org .fife .ui .rtextarea .RTADefaultInputMap ;
79
+ import org .fife .ui .rtextarea .RTextArea ;
80
+ import org .fife .ui .rtextarea .RTextAreaEditorKit ;
65
81
import org .fife .ui .rtextarea .RTextScrollPane ;
82
+ import org .fife .ui .rtextarea .RecordableTextAction ;
66
83
67
84
import cc .arduino .UpdatableBoardsLibsFakeURLsHandler ;
68
85
import processing .app .helpers .DocumentTextChangeListener ;
86
+ import processing .app .helpers .PreferencesMap ;
69
87
import processing .app .syntax .ArduinoTokenMakerFactory ;
70
88
import processing .app .syntax .PdeKeywords ;
71
89
import processing .app .syntax .SketchTextArea ;
@@ -136,6 +154,8 @@ private RSyntaxDocument createDocument(String contents) {
136
154
return document ;
137
155
}
138
156
157
+ public static final String rtaNextBookmarkAction = "RTA.NextBookmarkAction" ;
158
+
139
159
private RTextScrollPane createScrollPane (SketchTextArea textArea ) throws IOException {
140
160
RTextScrollPane scrollPane = new RTextScrollPane (textArea , true );
141
161
scrollPane .setBorder (new MatteBorder (0 , 6 , 0 , 0 , Theme .getColor ("editor.bgcolor" )));
@@ -144,13 +164,118 @@ private RTextScrollPane createScrollPane(SketchTextArea textArea) throws IOExcep
144
164
scrollPane .setIconRowHeaderEnabled (false );
145
165
146
166
Gutter gutter = scrollPane .getGutter ();
147
- gutter .setBookmarkingEnabled (false );
148
- //gutter.setBookmarkIcon(CompletionsRenderer.getIcon(CompletionType.TEMPLATE));
167
+
168
+ if (PreferencesData .getBoolean ("editor.bookmarks" )) {
169
+ gutter .setBookmarkingEnabled (true );
170
+ gutter .setBookmarkIcon (CompletionsRenderer .getIcon (CompletionType .FUNCTION ));
171
+ InputMap map = SwingUtilities .getUIInputMap (textArea , JComponent .WHEN_FOCUSED );
172
+ NextBookmarkAction action = new NextBookmarkAction (rtaNextBookmarkAction );
173
+ map .put (KeyStroke .getKeyStroke (KeyEvent .VK_F3 , 0 ), action );
174
+ SwingUtilities .replaceUIInputMap (textArea ,JComponent .WHEN_FOCUSED ,map );
175
+ }
176
+
149
177
gutter .setIconRowHeaderInheritsGutterBackground (true );
150
178
151
179
return scrollPane ;
152
180
}
153
181
182
+ public class GutterIconInfoTabs {
183
+ GutterIconInfo bookmark ;
184
+ SketchFile file ;
185
+ RTextArea textArea ;
186
+
187
+ public String toString ( ) {
188
+ return "File:" + file .getFileName () + " -- Line:" + bookmark .getMarkedOffset ();
189
+ }
190
+ }
191
+
192
+ /**
193
+ * Action that moves the caret to the next bookmark.
194
+ */
195
+ public class NextBookmarkAction extends RecordableTextAction {
196
+
197
+ public NextBookmarkAction (String name ) {
198
+ super (name );
199
+ }
200
+
201
+ @ Override
202
+ public void actionPerformedImpl (ActionEvent e , RTextArea textArea ) {
203
+
204
+ Gutter gutter = RSyntaxUtilities .getGutter (textArea );
205
+
206
+ List <GutterIconInfoTabs > bookmarks = new ArrayList <GutterIconInfoTabs >();
207
+
208
+ try {
209
+
210
+ for (EditorTab tab : editor .getTabs ()) {
211
+ gutter = RSyntaxUtilities .getGutter (tab .getTextArea ());
212
+
213
+ if (gutter !=null ) {
214
+ GutterIconInfo [] tabBookmarks = gutter .getBookmarks ();
215
+ for (GutterIconInfo element : tabBookmarks ) {
216
+ GutterIconInfoTabs bookmark = new GutterIconInfoTabs ();
217
+ bookmark .file = tab .getSketchFile ();
218
+ bookmark .bookmark = element ;
219
+ bookmark .textArea = tab .getTextArea ();
220
+ bookmarks .add (bookmark );
221
+ }
222
+ }
223
+ }
224
+
225
+ if (bookmarks .size ()==0 ) {
226
+ UIManager .getLookAndFeel ().
227
+ provideErrorFeedback (textArea );
228
+ return ;
229
+ }
230
+
231
+ GutterIconInfoTabs moveTo = null ;
232
+ int curLine = textArea .getCaretLineNumber ();
233
+
234
+ for (int i =0 ; i <bookmarks .size (); i ++) {
235
+ GutterIconInfo bookmark = bookmarks .get (i ).bookmark ;
236
+ int offs = bookmark .getMarkedOffset ();
237
+ int line = 0 ;
238
+ int curTabIndex = editor .getCurrentTabIndex ();
239
+ int bookmarkTabIndex = editor .findTabIndex (bookmarks .get (i ).file );
240
+ if (curTabIndex == bookmarkTabIndex ) {
241
+ line = textArea .getLineOfOffset (offs );
242
+ }
243
+ if ((curTabIndex == bookmarkTabIndex && line >curLine ) || (curTabIndex < bookmarkTabIndex )) {
244
+ moveTo = bookmarks .get (i );
245
+ break ;
246
+ }
247
+ }
248
+ if (moveTo ==null ) { // Loop back to beginning
249
+ moveTo = bookmarks .get (0 );
250
+ }
251
+
252
+ editor .selectTab (editor .findTabIndex (moveTo .file ));
253
+
254
+ int offs = moveTo .bookmark .getMarkedOffset ();
255
+ if (moveTo .textArea instanceof RSyntaxTextArea ) {
256
+ RSyntaxTextArea rsta = (RSyntaxTextArea )moveTo .textArea ;
257
+ if (rsta .isCodeFoldingEnabled ()) {
258
+ rsta .getFoldManager ().
259
+ ensureOffsetNotInClosedFold (offs );
260
+ }
261
+ }
262
+ int line = moveTo .textArea .getLineOfOffset (offs );
263
+ offs = moveTo .textArea .getLineStartOffset (line );
264
+ moveTo .textArea .setCaretPosition (offs );
265
+
266
+ } catch (BadLocationException ble ) { // Never happens
267
+ UIManager .getLookAndFeel ().
268
+ provideErrorFeedback (textArea );
269
+ ble .printStackTrace ();
270
+ }
271
+ }
272
+
273
+ @ Override
274
+ public String getMacroID () {
275
+ return getName ();
276
+ }
277
+ }
278
+
154
279
private SketchTextArea createTextArea (RSyntaxDocument document )
155
280
throws IOException {
156
281
final SketchTextArea textArea = new SketchTextArea (document , editor .base .getPdeKeywords ());
0 commit comments