This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 268177
Collapse All | Expand All

(-)editor.bookmarks/src/org/netbeans/lib/editor/bookmarks/actions/Bundle.properties (-1 lines)
Lines 42-46 Link Here
42
42
43
bookmark-next=Next B&ookmark
43
bookmark-next=Next B&ookmark
44
bookmark-previous=Previo&us Bookmark
44
bookmark-previous=Previo&us Bookmark
45
bookmark-toggle=Toggle Bookmar&k
46
clear-document-bookmarks=Clear Document Bookmarks
45
clear-document-bookmarks=Clear Document Bookmarks
(-)editor.bookmarks/src/org/netbeans/lib/editor/bookmarks/actions/ToggleBookmarkAction.java (-251 / +30 lines)
Lines 41-125 Link Here
41
 * Version 2 license, then the option applies only if the new code is
41
 * Version 2 license, then the option applies only if the new code is
42
 * made subject to such option by the copyright holder.
42
 * made subject to such option by the copyright holder.
43
 */
43
 */
44
45
package org.netbeans.lib.editor.bookmarks.actions;
44
package org.netbeans.lib.editor.bookmarks.actions;
46
45
47
import java.awt.Component;
48
import java.awt.event.ActionEvent;
46
import java.awt.event.ActionEvent;
49
import java.beans.PropertyChangeEvent;
50
import java.beans.PropertyChangeListener;
51
import java.lang.ref.Reference;
52
import java.lang.ref.WeakReference;
53
import javax.swing.AbstractAction;
54
import javax.swing.AbstractButton;
55
import javax.swing.Action;
47
import javax.swing.Action;
56
import javax.swing.ButtonModel;
57
import javax.swing.JButton;
58
import javax.swing.JToggleButton;
59
import javax.swing.event.ChangeEvent;
60
import javax.swing.event.ChangeListener;
61
import javax.swing.text.BadLocationException;
62
import javax.swing.text.Caret;
48
import javax.swing.text.Caret;
63
import javax.swing.text.Document;
64
import javax.swing.text.JTextComponent;
49
import javax.swing.text.JTextComponent;
65
import org.netbeans.api.editor.EditorRegistry;
50
import org.netbeans.api.editor.EditorActionRegistration;
66
import org.netbeans.editor.BaseDocument;
67
import org.netbeans.lib.editor.bookmarks.api.Bookmark;
68
import org.netbeans.lib.editor.bookmarks.api.BookmarkList;
51
import org.netbeans.lib.editor.bookmarks.api.BookmarkList;
69
import org.openide.awt.Actions;
52
import org.netbeans.spi.editor.AbstractEditorAction;
53
import org.openide.awt.ActionID;
54
import org.openide.awt.ActionReference;
55
import org.openide.awt.ActionReferences;
56
import org.openide.awt.ActionRegistration;
70
import org.openide.cookies.EditorCookie;
57
import org.openide.cookies.EditorCookie;
71
import org.openide.text.NbDocument;
58
import org.openide.text.NbDocument;
72
import org.openide.util.ContextAwareAction;
73
import org.openide.util.ImageUtilities;
59
import org.openide.util.ImageUtilities;
74
import org.openide.util.Lookup;
60
import org.openide.util.Lookup;
75
import org.openide.util.NbBundle;
61
import org.openide.util.NbBundle;
76
import org.openide.util.Utilities;
62
import org.openide.util.Utilities;
77
import org.openide.util.WeakListeners;
78
import org.openide.util.actions.Presenter;
79
63
80
81
/**
64
/**
82
 * Toggles a bookmark in a line in an opened document.
65
 * Toggles a bookmark in a line in an opened document.
83
 *
66
 *
84
 * @author Vita Stejskal
67
 * @author Vita Stejskal
85
 */
68
 */
86
public final class ToggleBookmarkAction extends AbstractAction implements ContextAwareAction, Presenter.Toolbar {
69
@NbBundle.Messages({"bookmark-toggle=Toggle Bookmark", "CTL_ToggleBookmarkAction=Toggle Bookmar&k"})
70
@ActionID(id = "org.netbeans.lib.editor.bookmarks.actions.ToggleBookmarkAction", category = "Edit")
71
@EditorActionRegistration(
72
        name = "bookmark-toggle", noIconInMenu = true,
73
        iconResource = "org/netbeans/modules/editor/bookmarks/resources/toggle_bookmark.png",
74
        menuText = "#CTL_ToggleBookmarkAction")
75
@ActionRegistration(
76
        lazy = false,
77
        displayName = "#CTL_ToggleBookmarkAction",
78
        menuText = "#CTL_ToggleBookmarkAction",
79
        iconInMenu = false
80
//,iconBase = "org/netbeans/modules/editor/bookmarks/resources/toggle_bookmark.png"
81
)
82
@ActionReferences({
83
    @ActionReference(path = "Menu/GoTo", position = 1900),}
84
)
85
public final class ToggleBookmarkAction extends AbstractEditorAction {
87
86
88
    private static final String ACTION_NAME = "bookmark-toggle"; // NOI18N
89
    private static final String ACTION_ICON = "org/netbeans/modules/editor/bookmarks/resources/toggle_bookmark.png"; // NOI18N
90
        
91
    private final JTextComponent component;
92
    
93
    public ToggleBookmarkAction() {
87
    public ToggleBookmarkAction() {
94
        this(null);
88
        super();
89
        putValue(Action.SMALL_ICON, ImageUtilities.loadImageIcon("org/netbeans/modules/editor/bookmarks/resources/toggle_bookmark.png", false));
90
        putValue(Action.NAME, Bundle.CTL_ToggleBookmarkAction());
91
        putValue(Action.LONG_DESCRIPTION, Bundle.CTL_ToggleBookmarkAction());
92
        putValue(Action.SHORT_DESCRIPTION, Bundle.CTL_ToggleBookmarkAction());
95
    }
93
    }
96
94
97
    public ToggleBookmarkAction(JTextComponent component) {
98
        super(
99
            NbBundle.getMessage(ToggleBookmarkAction.class, ACTION_NAME),ImageUtilities.loadImageIcon(ACTION_ICON, false));
100
        putValue(SHORT_DESCRIPTION, Actions.cutAmpersand((String) getValue(NAME)));
101
        putValue("noIconInMenu", Boolean.TRUE); // NOI18N
102
        
103
        this.component = component;
104
        updateEnabled();
105
        PropertyChangeListener editorRegistryListener = new EditorRegistryListener(this);
106
        EditorRegistry.addPropertyChangeListener(editorRegistryListener);
107
    }
108
109
    private void updateEnabled() {
110
        setEnabled(isEnabled());
111
    }
112
113
    @Override
95
    @Override
114
    public Action createContextAwareInstance(Lookup actionContext) {
96
    protected void actionPerformed(ActionEvent arg0, JTextComponent component) {
115
        JTextComponent jtc = findComponent(actionContext);
116
        ToggleBookmarkAction toggleBookmarkAction = new ToggleBookmarkAction(jtc);
117
        toggleBookmarkAction.putValue(ACCELERATOR_KEY, this.getValue(ACCELERATOR_KEY));
118
        return toggleBookmarkAction;
119
    }
120
121
    @Override
122
    public void actionPerformed(ActionEvent arg0) {
123
        if (component != null) {
97
        if (component != null) {
124
            // cloned action with context
98
            // cloned action with context
125
            actionPerformed(component);
99
            actionPerformed(component);
Lines 132-172 Link Here
132
        }
106
        }
133
    }
107
    }
134
108
135
    @Override
136
    public boolean isEnabled() {
137
        if (component != null) {
138
            return true;
139
        } else {
140
            if (EditorRegistry.lastFocusedComponent() == null) {
141
                return false;
142
            } else {
143
                return true;
144
            }
145
        }
146
    }
147
148
    @Override
149
    public Component getToolbarPresenter() {
150
        AbstractButton b;
151
        
152
        if (component != null) {
153
            b = new MyGaGaButton();
154
            b.setModel(new BookmarkButtonModel(component));
155
        } else {
156
            b = new JButton();
157
        }
158
        
159
        b.putClientProperty("hideActionText", Boolean.TRUE); //NOI18N
160
        b.setAction(this);
161
        
162
        return b;
163
    }
164
165
    public static JTextComponent findComponent(Lookup lookup) {
109
    public static JTextComponent findComponent(Lookup lookup) {
166
        EditorCookie ec = lookup.lookup(EditorCookie.class);
110
        EditorCookie ec = lookup.lookup(EditorCookie.class);
167
        return ec == null ? null : NbDocument.findRecentEditorPane(ec);
111
        return ec == null ? null : NbDocument.findRecentEditorPane(ec);
168
    }
112
    }
169
    
113
170
    private static void actionPerformed(JTextComponent target) {
114
    private static void actionPerformed(JTextComponent target) {
171
        if (target != null) {
115
        if (target != null) {
172
            if (org.netbeans.editor.Utilities.getEditorUI(target).isGlyphGutterVisible()) {
116
            if (org.netbeans.editor.Utilities.getEditorUI(target).isGlyphGutterVisible()) {
Lines 179-348 Link Here
179
            }
123
            }
180
        }
124
        }
181
    }
125
    }
182
    
183
    private static final class BookmarkButtonModel extends JToggleButton.ToggleButtonModel implements PropertyChangeListener, ChangeListener {
184
        
185
        private final JTextComponent component;
186
        private Caret caret;
187
        private BookmarkList bookmarks;
188
        private int lastCurrentLineStartOffset = -1;
189
        
190
        private PropertyChangeListener bookmarksListener = null;
191
        private ChangeListener caretListener = null;
192
        
193
        @SuppressWarnings("LeakingThisInConstructor")
194
        public BookmarkButtonModel(JTextComponent component) {
195
            this.component = component;
196
            this.component.addPropertyChangeListener(WeakListeners.propertyChange(this, this.component));
197
            rebuild();
198
        }
199
126
200
        @Override
201
        public void propertyChange(PropertyChangeEvent evt) {
202
            if (evt.getPropertyName() == null || 
203
                "document".equals(evt.getPropertyName()) || //NOI18N
204
                "caret".equals(evt.getPropertyName()) //NOI18N
205
            ) {
206
                rebuild();
207
            } else if ("bookmarks".equals(evt.getPropertyName())) { //NOI18N
208
                lastCurrentLineStartOffset = -1;
209
                updateState();
210
            }
211
        }
212
213
        @Override
214
        public void stateChanged(ChangeEvent evt) {
215
            updateState();
216
        }
217
218
        private static boolean isBookmarkOnTheLine(BookmarkList bookmarks, int lineStartOffset) {
219
            Bookmark bm = bookmarks.getNextBookmark(lineStartOffset - 1, false);
220
//            System.out.println("offset: " + lineStartOffset + " -> " + bm + (bm == null ? "" : "; bm.getOffset() = " + bm.getOffset()));
221
            return bm == null ? false : lineStartOffset == bm.getOffset();
222
        }
223
        
224
        private void rebuild() {
225
            // Hookup the bookmark list
226
            BookmarkList newBookmarks = BookmarkList.get(component.getDocument());
227
            if (newBookmarks != bookmarks) {
228
                if (bookmarksListener != null) {
229
                    bookmarks.removePropertyChangeListener (bookmarksListener);
230
                    bookmarksListener = null;
231
                }
232
233
                bookmarks = newBookmarks;
234
235
                if (bookmarks != null) {
236
                    bookmarksListener = WeakListeners.propertyChange(this, bookmarks);
237
                    bookmarks.addPropertyChangeListener (bookmarksListener);
238
                }
239
            }
240
            
241
            // Hookup the caret
242
            Caret newCaret = component.getCaret();
243
            if (newCaret != caret) {
244
                if (caretListener != null) {
245
                    caret.removeChangeListener(caretListener);
246
                    caretListener = null;
247
                }
248
249
                caret = newCaret;
250
251
                if (caret != null) {
252
                    caretListener = WeakListeners.change(this, caret);
253
                    caret.addChangeListener(caretListener);
254
                }
255
            }
256
            
257
            lastCurrentLineStartOffset = -1;
258
            updateState();
259
        }
260
        
261
        private void updateState() {
262
            Document doc = component.getDocument();
263
            if (caret != null && bookmarks != null && doc instanceof BaseDocument) {
264
                try {
265
                    int currentLineStartOffset = org.netbeans.editor.Utilities.getRowStart((BaseDocument) doc, caret.getDot());
266
                    if (currentLineStartOffset != lastCurrentLineStartOffset) {
267
                        lastCurrentLineStartOffset = currentLineStartOffset;
268
                        boolean selected = isBookmarkOnTheLine(bookmarks, currentLineStartOffset);
269
                        
270
//                        System.out.println("updateState: offset=" + currentLineStartOffset + ", hasBookmark=" + selected);
271
                        
272
                        setSelected(selected);
273
                    }
274
                } catch (BadLocationException e) {
275
                    // ignore
276
                    lastCurrentLineStartOffset = -1;
277
                }
278
            }
279
        }
280
    } // End of BookmarkButtonModel class
281
    
282
    private static final class MyGaGaButton extends JToggleButton implements ChangeListener {
283
284
        public MyGaGaButton() {
285
286
        }
287
288
        @Override
289
        public void setModel(ButtonModel model) {
290
            ButtonModel oldModel = getModel();
291
            if (oldModel != null) {
292
                oldModel.removeChangeListener(this);
293
            }
294
295
            super.setModel(model);
296
297
            ButtonModel newModel = getModel();
298
            if (newModel != null) {
299
                newModel.addChangeListener(this);
300
            }
301
302
            stateChanged(null);
303
        }
304
305
        @Override
306
        public void stateChanged(ChangeEvent evt) {
307
            boolean selected = isSelected();
308
            super.setContentAreaFilled(selected);
309
            super.setBorderPainted(selected);
310
        }
311
312
        @Override
313
        public void setBorderPainted(boolean arg0) {
314
            if (!isSelected()) {
315
                super.setBorderPainted(arg0);
316
            }
317
        }
318
319
        @Override
320
        public void setContentAreaFilled(boolean arg0) {
321
            if (!isSelected()) {
322
                super.setContentAreaFilled(arg0);
323
            }
324
        }
325
    } // End of MyGaGaButton class
326
327
    private static final class EditorRegistryListener implements PropertyChangeListener {
328
        
329
        private final Reference<ToggleBookmarkAction> actionRef;
330
        
331
        EditorRegistryListener(ToggleBookmarkAction action) {
332
            actionRef = new WeakReference<ToggleBookmarkAction>(action);
333
        }
334
        
335
        @Override
336
        public void propertyChange(PropertyChangeEvent evt) {
337
            ToggleBookmarkAction action = actionRef.get();
338
            if (action != null) {
339
                action.updateEnabled();
340
            } else {
341
                EditorRegistry.removePropertyChangeListener(this); // EditorRegistry fires frequently so remove this way
342
            }
343
        }
344
345
    }
346
347
}
127
}
348
(-)editor.bookmarks/src/org/netbeans/modules/editor/bookmarks/resources/layer.xml (-8 / +1 lines)
Lines 60-68 Link Here
60
            <file name="bookmark-history-popup-previous.instance">
60
            <file name="bookmark-history-popup-previous.instance">
61
                <attr name="instanceCreate" newvalue="org.netbeans.modules.editor.bookmarks.WrapperBookmarkAction$PopupPrevious"/>
61
                <attr name="instanceCreate" newvalue="org.netbeans.modules.editor.bookmarks.WrapperBookmarkAction$PopupPrevious"/>
62
            </file>
62
            </file>
63
            <file name="bookmark-toggle.instance">
64
                <attr name="instanceCreate" newvalue="org.netbeans.lib.editor.bookmarks.actions.ToggleBookmarkAction"/>
65
            </file>
66
            <file name="clear-document-bookmarks.instance">
63
            <file name="clear-document-bookmarks.instance">
67
                <attr name="instanceCreate" newvalue="org.netbeans.modules.editor.bookmarks.WrapperBookmarkAction$ClearDocumentBookmarks"/>
64
                <attr name="instanceCreate" newvalue="org.netbeans.modules.editor.bookmarks.WrapperBookmarkAction$ClearDocumentBookmarks"/>
68
            </file>
65
            </file>
Lines 77-87 Link Here
77
74
78
    <folder name="Menu">
75
    <folder name="Menu">
79
        <folder name="GoTo">
76
        <folder name="GoTo">
80
            <file name="org-netbeans-editor-bookmarks-ToggleBookmark.shadow">
81
                <attr name="originalFile" stringvalue="Actions/Edit/bookmark-toggle.instance"/>
82
                <attr name="position" intvalue="1900"/>
83
            </file>
84
            
85
            <file name="bookmark-history-popup-next.shadow">
77
            <file name="bookmark-history-popup-next.shadow">
86
                <attr name="originalFile" stringvalue="Actions/Edit/bookmark-history-popup-next.instance"/>
78
                <attr name="originalFile" stringvalue="Actions/Edit/bookmark-history-popup-next.instance"/>
87
                <attr name="position" intvalue="2000"/>
79
                <attr name="position" intvalue="2000"/>
Lines 118-123 Link Here
118
                    <attr name="originalFile" stringvalue="Actions/Edit/bookmark-next.instance"/>
110
                    <attr name="originalFile" stringvalue="Actions/Edit/bookmark-next.instance"/>
119
                    <attr name="position" intvalue="12000"/>
111
                    <attr name="position" intvalue="12000"/>
120
                </file>
112
                </file>
113
                <!-- explicite registration because of https://netbeans.org/bugzilla/show_bug.cgi?id=268185 -->
121
                <file name="bookmark-toggle.shadow">
114
                <file name="bookmark-toggle.shadow">
122
                    <attr name="originalFile" stringvalue="Actions/Edit/bookmark-toggle.instance"/>
115
                    <attr name="originalFile" stringvalue="Actions/Edit/bookmark-toggle.instance"/>
123
                    <attr name="position" intvalue="13000"/>
116
                    <attr name="position" intvalue="13000"/>

Return to bug 268177