1 19 20 package org.netbeans.lib.editor.bookmarks.actions; 21 22 import java.awt.Component ; 23 import java.awt.event.ActionEvent ; 24 import java.beans.PropertyChangeEvent ; 25 import java.beans.PropertyChangeListener ; 26 import javax.swing.AbstractAction ; 27 import javax.swing.AbstractButton ; 28 import javax.swing.Action ; 29 import javax.swing.ButtonModel ; 30 import javax.swing.ImageIcon ; 31 import javax.swing.JButton ; 32 import javax.swing.JEditorPane ; 33 import javax.swing.JToggleButton ; 34 import javax.swing.event.ChangeEvent ; 35 import javax.swing.event.ChangeListener ; 36 import javax.swing.text.BadLocationException ; 37 import javax.swing.text.Caret ; 38 import javax.swing.text.Document ; 39 import javax.swing.text.JTextComponent ; 40 import org.netbeans.editor.BaseDocument; 41 import org.netbeans.lib.editor.bookmarks.BookmarksApiPackageAccessor; 42 import org.netbeans.lib.editor.bookmarks.api.Bookmark; 43 import org.netbeans.lib.editor.bookmarks.api.BookmarkList; 44 import org.openide.cookies.EditorCookie; 45 import org.openide.util.ContextAwareAction; 46 import org.openide.util.Lookup; 47 import org.openide.util.NbBundle; 48 import org.openide.util.Utilities; 49 import org.openide.util.WeakListeners; 50 import org.openide.util.actions.Presenter; 51 52 53 58 public final class ToggleBookmarkAction extends AbstractAction implements ContextAwareAction, Presenter.Toolbar { 59 60 private static final String ACTION_NAME = "bookmark-toggle"; private static final String ACTION_ICON = "org/netbeans/modules/editor/bookmarks/resources/toggle_bookmark.png"; 63 private final JTextComponent component; 64 65 public ToggleBookmarkAction() { 66 this(null); 67 } 68 69 public ToggleBookmarkAction(JTextComponent component) { 70 super( 71 NbBundle.getMessage(ToggleBookmarkAction.class, ACTION_NAME), 72 new ImageIcon (Utilities.loadImage(ACTION_ICON)) 73 ); 74 putValue(SHORT_DESCRIPTION, getValue(NAME)); 75 putValue("noIconInMenu", Boolean.TRUE); 77 this.component = component; 78 } 79 80 public Action createContextAwareInstance(Lookup actionContext) { 81 JTextComponent jtc = findComponent(actionContext); 82 return new ToggleBookmarkAction(jtc); 83 } 84 85 public void actionPerformed(ActionEvent arg0) { 86 if (component != null) { 87 actionPerformed(component); 89 } else { 90 JTextComponent jtc = findComponent(Utilities.actionsGlobalContext()); 92 if (jtc != null) { 93 actionPerformed(jtc); 94 } 95 } 96 } 97 98 public Component getToolbarPresenter() { 99 AbstractButton b; 100 101 if (component != null) { 102 b = new MyGaGaButton(); 103 b.setModel(new BookmarkButtonModel(component)); 104 } else { 105 b = new JButton (); 106 } 107 108 b.putClientProperty("hideActionText", Boolean.TRUE); b.setAction(this); 110 111 return b; 112 } 113 114 private static JTextComponent findComponent(Lookup lookup) { 115 EditorCookie ec = (EditorCookie) lookup.lookup(EditorCookie.class); 116 if (ec != null) { 117 JEditorPane panes[] = ec.getOpenedPanes(); 118 if (panes != null && panes.length > 0) { 119 return panes[0]; 120 } 121 } 122 return null; 123 } 124 125 private static void actionPerformed(JTextComponent target) { 126 if (target != null) { 127 if (org.netbeans.editor.Utilities.getEditorUI(target).isGlyphGutterVisible()) { 128 Caret caret = target.getCaret(); 129 BookmarkList bookmarkList = BookmarkList.get(target.getDocument()); 130 bookmarkList.toggleLineBookmark(caret.getDot()); 131 132 } else { target.getToolkit().beep(); 134 } 135 } 136 } 137 138 private static final class BookmarkButtonModel extends JToggleButton.ToggleButtonModel implements PropertyChangeListener , ChangeListener { 139 140 private final JTextComponent component; 141 private Caret caret; 142 private BookmarkList bookmarks; 143 private int lastCurrentLineStartOffset = -1; 144 145 private PropertyChangeListener bookmarksListener = null; 146 private ChangeListener caretListener = null; 147 148 public BookmarkButtonModel(JTextComponent component) { 149 this.component = component; 150 this.component.addPropertyChangeListener(WeakListeners.propertyChange(this, this.component)); 151 rebuild(); 152 } 153 154 public void propertyChange(PropertyChangeEvent evt) { 155 if (evt.getPropertyName() == null || 156 "document".equals(evt.getPropertyName()) || "caret".equals(evt.getPropertyName()) ) { 159 rebuild(); 160 } else if ("bookmarks".equals(evt.getPropertyName())) { lastCurrentLineStartOffset = -1; 162 updateState(); 163 } 164 } 165 166 public void stateChanged(ChangeEvent evt) { 167 updateState(); 168 } 169 170 private static boolean isBookmarkOnTheLine(BookmarkList bookmarks, int lineStartOffset) { 171 Bookmark bm = bookmarks.getNextBookmark(lineStartOffset - 1, false); 172 return bm == null ? false : lineStartOffset == bm.getOffset(); 174 } 175 176 private void rebuild() { 177 BookmarkList newBookmarks = BookmarkList.get(component.getDocument()); 179 if (newBookmarks != bookmarks) { 180 if (bookmarksListener != null) { 181 BookmarksApiPackageAccessor.get().removeBookmarkListPcl(bookmarks, bookmarksListener); 182 bookmarksListener = null; 183 } 184 185 bookmarks = newBookmarks; 186 187 if (bookmarks != null) { 188 bookmarksListener = WeakListeners.propertyChange(this, bookmarks); 189 BookmarksApiPackageAccessor.get().addBookmarkListPcl(bookmarks, bookmarksListener); 190 } 191 } 192 193 Caret newCaret = component.getCaret(); 195 if (newCaret != caret) { 196 if (caretListener != null) { 197 caret.removeChangeListener(caretListener); 198 caretListener = null; 199 } 200 201 caret = newCaret; 202 203 if (caret != null) { 204 caretListener = WeakListeners.change(this, caret); 205 caret.addChangeListener(caretListener); 206 } 207 } 208 209 lastCurrentLineStartOffset = -1; 210 updateState(); 211 } 212 213 private void updateState() { 214 Document doc = component.getDocument(); 215 if (caret != null && bookmarks != null && doc instanceof BaseDocument) { 216 try { 217 int currentLineStartOffset = org.netbeans.editor.Utilities.getRowStart((BaseDocument) doc, caret.getDot()); 218 if (currentLineStartOffset != lastCurrentLineStartOffset) { 219 lastCurrentLineStartOffset = currentLineStartOffset; 220 boolean selected = isBookmarkOnTheLine(bookmarks, currentLineStartOffset); 221 222 224 setSelected(selected); 225 } 226 } catch (BadLocationException e) { 227 lastCurrentLineStartOffset = -1; 229 } 230 } 231 } 232 } 234 private static final class MyGaGaButton extends JToggleButton implements ChangeListener { 235 236 public MyGaGaButton() { 237 238 } 239 240 public void setModel(ButtonModel model) { 241 ButtonModel oldModel = getModel(); 242 if (oldModel != null) { 243 oldModel.removeChangeListener(this); 244 } 245 246 super.setModel(model); 247 248 ButtonModel newModel = getModel(); 249 if (newModel != null) { 250 newModel.addChangeListener(this); 251 } 252 253 stateChanged(null); 254 } 255 256 public void stateChanged(ChangeEvent evt) { 257 boolean selected = isSelected(); 258 super.setContentAreaFilled(selected); 259 super.setBorderPainted(selected); 260 } 261 262 public void setBorderPainted(boolean arg0) { 263 if (!isSelected()) { 264 super.setBorderPainted(arg0); 265 } 266 } 267 268 public void setContentAreaFilled(boolean arg0) { 269 if (!isSelected()) { 270 super.setContentAreaFilled(arg0); 271 } 272 } 273 } 275 } 276 277 | Popular Tags |