1 19 20 package org.netbeans.modules.search; 21 22 import java.awt.BorderLayout ; 23 import java.awt.CardLayout ; 24 import java.awt.Dimension ; 25 import java.awt.EventQueue ; 26 import java.awt.Rectangle ; 27 import javax.swing.BorderFactory ; 28 import javax.swing.Box ; 29 import javax.swing.JEditorPane ; 30 import javax.swing.JLabel ; 31 import javax.swing.JPanel ; 32 import javax.swing.JScrollBar ; 33 import javax.swing.JScrollPane ; 34 import javax.swing.JTree ; 35 import javax.swing.SwingConstants ; 36 import javax.swing.UIManager ; 37 import javax.swing.border.Border ; 38 import javax.swing.event.TreeSelectionEvent ; 39 import javax.swing.event.TreeSelectionListener ; 40 import javax.swing.text.BadLocationException ; 41 import javax.swing.text.Document ; 42 import javax.swing.text.Element ; 43 import javax.swing.text.StyledDocument ; 44 import javax.swing.tree.TreePath ; 45 import org.netbeans.modules.search.types.TextDetail; 46 import org.openide.ErrorManager; 47 import org.openide.text.NbDocument; 48 import org.openide.util.NbBundle; 49 import org.openide.util.RequestProcessor; 50 import static java.lang.Thread.NORM_PRIORITY ; 51 52 63 final class ContextView extends JPanel implements TreeSelectionListener { 64 65 66 private static final String FILE_VIEW = "file view"; 68 private static final String MESSAGE_VIEW = "message view"; 70 71 private final CardLayout cardLayout; 72 73 private final JEditorPane editorPane = new JEditorPane (); 74 75 private final JScrollPane editorScroll; 76 77 private final JLabel lblPath = new JLabel (); 78 79 private final JLabel lblMessage = new JLabel (); 80 84 private final Displayer displayer = new Displayer(); 85 86 private final RequestProcessor requestProcessor 87 = new RequestProcessor("TextView", NORM_PRIORITY, true); 89 90 private ResultModel resultModel; 91 92 private RequestProcessor.Task task = null; 93 94 private TextFetcher textFetcher = null; 95 96 private String displayedCard = null; 97 98 private String msgNoFileSelected = null; 99 100 private String msgMultipleFilesSelected = null; 101 102 private String editorMimeType = null; 103 104 109 public ContextView(ResultModel resultModel) { 110 Border b = BorderFactory.createCompoundBorder( 111 BorderFactory.createMatteBorder( 0, 0, 1, 0, 113 UIManager.getColor("controlShadow")), BorderFactory.createEmptyBorder( 5, 5, 1, 5)); 116 lblPath.setBorder(b); 117 118 editorPane.setEditable(false); 119 editorPane.getCaret().setBlinkRate(0); 120 121 editorScroll = new JScrollPane (editorPane); 122 editorScroll.setViewportBorder(BorderFactory.createEmptyBorder()); 123 editorScroll.setBorder(BorderFactory.createEmptyBorder()); 124 125 JPanel fileViewPanel = new JPanel (); 126 fileViewPanel.setLayout(new BorderLayout ()); 127 fileViewPanel.add(lblPath, BorderLayout.NORTH); 128 fileViewPanel.add(editorScroll, BorderLayout.CENTER); 129 130 Box messagePanel = Box.createVerticalBox(); 131 messagePanel.add(Box.createVerticalGlue()); 132 messagePanel.add(lblMessage); 133 messagePanel.add(Box.createVerticalGlue()); 134 lblMessage.setAlignmentX(0.5f); 135 lblMessage.setHorizontalAlignment(SwingConstants.CENTER); 136 lblMessage.setEnabled(false); 137 138 setLayout(cardLayout = new CardLayout ()); 139 add(fileViewPanel, FILE_VIEW); 140 add(messagePanel, MESSAGE_VIEW); 141 142 setResultModel(resultModel); 143 } 144 145 @Override 146 public Dimension getMinimumSize() { 147 151 Dimension minSize = super.getMinimumSize(); 152 minSize.width = 0; 153 return minSize; 154 } 155 156 158 void setResultModel(ResultModel resultModel) { 159 if (resultModel == this.resultModel) { 160 return; 161 } 162 163 synchronized (this) { if (textFetcher != null) { 165 textFetcher.cancel(); 166 textFetcher = null; 167 } 168 } 169 this.resultModel = resultModel; 170 } 171 172 174 void bindToTreeSelection(final JTree tree) { 175 assert EventQueue.isDispatchThread(); 176 177 displaySelectedFiles(tree); 178 tree.addTreeSelectionListener(this); 179 } 180 181 183 void unbindFromTreeSelection(final JTree tree) { 184 assert EventQueue.isDispatchThread(); 185 186 tree.removeTreeSelectionListener(this); 187 188 synchronized (this) { if (textFetcher != null) { 190 textFetcher.cancel(); 191 textFetcher = null; 192 } 193 } 194 } 195 196 199 public void valueChanged(TreeSelectionEvent e) { 200 displaySelectedFiles((JTree ) e.getSource()); 201 } 202 203 208 private void displaySelectedFiles(final JTree tree) { 209 final TreePath [] selectedPaths = tree.getSelectionPaths(); 210 if ((selectedPaths == null) || (selectedPaths.length == 0)) { 211 displayNoFileSelected(); 212 } else if (selectedPaths.length > 1) { 213 displayMultipleItemsSelected(); 214 } else { 215 assert selectedPaths.length == 1; 216 217 final TreePath path = selectedPaths[0]; 218 int pathCount = path.getPathCount(); 219 if (pathCount == 1) { displayNoFileSelected(); 221 } else { 222 assert pathCount == 2 || pathCount == 3; 223 MatchingObject matchingObj; 224 int matchIndex; 225 if (pathCount == 2) { matchingObj = (MatchingObject) path.getLastPathComponent(); 227 matchIndex = -1; 228 } else { TreePath matchingObjPath = path.getParentPath(); 230 matchingObj = (MatchingObject) 231 matchingObjPath.getLastPathComponent(); 232 int matchingObjRow = tree.getRowForPath(matchingObjPath); 233 int matchRow = tree.getRowForPath(path); 234 matchIndex = matchRow - matchingObjRow - 1; 235 } 236 displayFile(matchingObj, matchIndex); 237 } 238 } 239 } 240 241 243 private void displayNoFileSelected() { 244 if (msgNoFileSelected == null) { 245 msgNoFileSelected = NbBundle.getMessage( 246 getClass(), 247 "MsgNoFileSelected"); } 249 displayMessage(msgNoFileSelected); 250 } 251 252 254 private void displayMultipleItemsSelected() { 255 if (msgMultipleFilesSelected == null) { 256 msgMultipleFilesSelected = NbBundle.getMessage( 257 getClass(), 258 "MsgMultipleFilesSelected"); } 260 displayMessage(msgMultipleFilesSelected); 261 } 262 263 265 private void displayMessage(String message) { 266 lblMessage.setText(message); 267 if (displayedCard != MESSAGE_VIEW) { 268 cardLayout.show(this, displayedCard = MESSAGE_VIEW); 269 } 270 } 271 272 276 private void displayFile(final MatchingObject matchingObj, 277 final int partIndex) { 278 assert EventQueue.isDispatchThread(); 279 280 synchronized (displayer) { if (task != null) { 282 task.cancel(); 283 task = null; 284 } 285 286 final Item item = new Item(resultModel, matchingObj, partIndex); 287 288 MatchingObject.InvalidityStatus invalidityStatus 289 = matchingObj.checkValidity(); 290 if (invalidityStatus != null) { 291 displayMessage(invalidityStatus.getDescription( 292 matchingObj.getFile().getPath())); 293 return; 294 } 295 296 requestText(item, displayer); 297 String description = matchingObj.getDescription(); 298 lblPath.setText(description); 299 lblPath.setToolTipText(description); } 301 } 302 303 314 private void requestText(Item item, TextDisplayer textDisplayer) { 315 assert EventQueue.isDispatchThread(); 316 317 synchronized (this) { if (textFetcher != null) { 319 if (textFetcher.replaceLocation(item, textDisplayer)) { 320 return; 321 } else { 322 textFetcher.cancel(); 323 textFetcher = null; 324 } 325 } 326 if (textFetcher == null) { 327 textFetcher = new TextFetcher(item, 328 textDisplayer, 329 requestProcessor); 330 } 331 } 332 } 333 334 344 private class Displayer implements TextDisplayer, Runnable { 345 346 private TextDetail location; 347 348 351 public void setText(final String text, 352 String mimeType, 353 final TextDetail location) { 354 assert EventQueue.isDispatchThread(); 355 356 if ("content/unknown".equals(mimeType)) { mimeType = "text/plain"; } 359 360 365 if ((editorMimeType == null) || !editorMimeType.equals(mimeType)) { 366 editorPane.setContentType(mimeType); 367 editorMimeType = mimeType; 368 } 369 editorPane.setText(text); 370 371 if (displayedCard != FILE_VIEW) { 372 cardLayout.show(ContextView.this, displayedCard = FILE_VIEW); 373 } 374 375 if (location != null) { 376 this.location = location; 380 EventQueue.invokeLater(this); 381 } else { 382 scrollToTop(); 383 } 384 } 385 386 391 public void run() { 392 assert EventQueue.isDispatchThread(); 393 394 boolean scrolled = false; 395 try { 396 if (!editorPane.isShowing()) { 397 return; 398 } 399 400 if (location != null) { 401 final Document document = editorPane.getDocument(); 402 if (document instanceof StyledDocument ) { 403 StyledDocument styledDocument 404 = (StyledDocument ) document; 405 int cursorOffset = getCursorOffset( 406 (StyledDocument ) document, 407 location.getLine() - 1); 408 int startOff = cursorOffset + location.getColumn() - 1; 409 int endOff = startOff + location.getMarkLength(); 410 editorPane.setSelectionStart(startOff); 411 editorPane.setSelectionEnd(endOff); 412 Rectangle r = editorPane.modelToView(startOff); 413 if (r != null) { 414 editorPane.scrollRectToVisible(r); 416 scrolled = true; 417 } 418 } 419 editorPane.getCaret().setBlinkRate(0); 420 editorPane.repaint(); 421 } 422 } catch (BadLocationException e) { 423 ErrorManager.getDefault().notify( ErrorManager.INFORMATIONAL, e); 428 } 429 if (!scrolled) { 430 scrollToTop(); 431 } 432 } 433 434 446 private int getCursorOffset(StyledDocument doc, int line) { 447 assert EventQueue.isDispatchThread(); 448 assert line >= 0; 449 450 try { 451 return NbDocument.findLineOffset(doc, line); 452 } catch (IndexOutOfBoundsException ex) { 453 454 455 Element lineRootElement = NbDocument.findLineRootElement(doc); 456 int lineCount = lineRootElement.getElementCount(); 457 if (line >= lineCount) { 458 return NbDocument.findLineOffset(doc, lineCount - 1); 459 } else { 460 throw ex; 461 } 462 } 463 } 464 465 467 private void scrollToTop() { 468 JScrollBar scrollBar; 469 470 scrollBar = editorScroll.getHorizontalScrollBar(); 471 scrollBar.setValue(scrollBar.getMinimum()); 472 473 scrollBar = editorScroll.getVerticalScrollBar(); 474 scrollBar.setValue(scrollBar.getMinimum()); 475 } 476 477 } 478 479 } 480 | Popular Tags |