Source Code Cross Referenced for AnnotationBar.java in  » IDE-Netbeans » versioning » org » netbeans » modules » versioning » system » cvss » ui » actions » annotate » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE Netbeans » versioning » org.netbeans.modules.versioning.system.cvss.ui.actions.annotate 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003:         *
0004:         * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005:         *
0006:         * The contents of this file are subject to the terms of either the GNU
0007:         * General Public License Version 2 only ("GPL") or the Common
0008:         * Development and Distribution License("CDDL") (collectively, the
0009:         * "License"). You may not use this file except in compliance with the
0010:         * License. You can obtain a copy of the License at
0011:         * http://www.netbeans.org/cddl-gplv2.html
0012:         * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013:         * specific language governing permissions and limitations under the
0014:         * License.  When distributing the software, include this License Header
0015:         * Notice in each file and include the License file at
0016:         * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
0017:         * particular file as subject to the "Classpath" exception as provided
0018:         * by Sun in the GPL Version 2 section of the License file that
0019:         * accompanied this code. If applicable, add the following below the
0020:         * License Header, with the fields enclosed by brackets [] replaced by
0021:         * your own identifying information:
0022:         * "Portions Copyrighted [year] [name of copyright owner]"
0023:         *
0024:         * Contributor(s):
0025:         *
0026:         * The Original Software is NetBeans. The Initial Developer of the Original
0027:         * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
0028:         * Microsystems, Inc. All Rights Reserved.
0029:         *
0030:         * If you wish your version of this file to be governed by only the CDDL
0031:         * or only the GPL Version 2, indicate your decision by adding
0032:         * "[Contributor] elects to include this software in this distribution
0033:         * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034:         * single choice of license, a recipient has the option to distribute
0035:         * your version of this file under either the CDDL, the GPL Version 2 or
0036:         * to extend the choice of license to its licensees as provided above.
0037:         * However, if you add GPL Version 2 code and therefore, elected the GPL
0038:         * Version 2 license, then the option applies only if the new code is
0039:         * made subject to such option by the copyright holder.
0040:         */
0041:
0042:        package org.netbeans.modules.versioning.system.cvss.ui.actions.annotate;
0043:
0044:        import org.netbeans.editor.*;
0045:        import org.netbeans.editor.Utilities;
0046:        import org.netbeans.api.editor.fold.*;
0047:        import org.netbeans.api.diff.*;
0048:        import org.netbeans.api.project.*;
0049:        import org.netbeans.api.project.ui.OpenProjects;
0050:        import org.netbeans.modules.versioning.system.cvss.ui.actions.log.*;
0051:        import org.netbeans.modules.versioning.system.cvss.ui.actions.diff.*;
0052:        import org.netbeans.modules.versioning.system.cvss.ui.actions.update.GetCleanAction;
0053:        import org.netbeans.modules.versioning.system.cvss.util.*;
0054:        import org.netbeans.modules.versioning.system.cvss.util.Utils;
0055:        import org.netbeans.lib.cvsclient.command.annotate.*;
0056:        import org.netbeans.spi.diff.*;
0057:        import org.openide.*;
0058:        import org.openide.loaders.*;
0059:        import org.openide.filesystems.*;
0060:        import org.openide.text.*;
0061:        import org.openide.util.*;
0062:        import org.openide.xml.*;
0063:
0064:        import javax.swing.*;
0065:        import javax.swing.Timer;
0066:        import javax.swing.event.*;
0067:        import javax.swing.text.*;
0068:        import javax.accessibility.Accessible;
0069:        import java.awt.*;
0070:        import java.awt.event.*;
0071:        import java.beans.*;
0072:        import java.util.*;
0073:        import java.util.List;
0074:        import java.io.*;
0075:        import java.text.MessageFormat;
0076:
0077:        /**
0078:         * Represents annotation sidebar componnet in editor. It's
0079:         * created by {@link AnnotationBarManager}.
0080:         *
0081:         * <p>It reponds to following external signals:
0082:         * <ul>
0083:         *   <li> {@link #annotate} message
0084:         *   <li> {@link LogOutputListener} events
0085:         * </ul>
0086:         *
0087:         * @author Petr Kuzel
0088:         */
0089:        final class AnnotationBar extends JComponent implements  Accessible,
0090:                PropertyChangeListener, LogOutputListener, DocumentListener,
0091:                ChangeListener, ActionListener, Runnable, ComponentListener {
0092:
0093:            /**
0094:             * Target text component for which the annotation bar is aiming.
0095:             */
0096:            private final JTextComponent textComponent;
0097:
0098:            /**
0099:             * User interface related to the target text component.
0100:             */
0101:            private final EditorUI editorUI;
0102:
0103:            /**
0104:             * Fold hierarchy of the text component user interface.
0105:             */
0106:            private final FoldHierarchy foldHierarchy;
0107:
0108:            /** 
0109:             * Document related to the target text component.
0110:             */
0111:            private final BaseDocument doc;
0112:
0113:            /**
0114:             * Caret of the target text component.
0115:             */
0116:            private final Caret caret;
0117:
0118:            /**
0119:             * Caret batch timer launched on receiving
0120:             * annotation data structures (AnnotateLine).
0121:             */
0122:            private Timer caretTimer;
0123:
0124:            /**
0125:             * Controls annotation bar visibility.
0126:             */
0127:            private boolean annotated;
0128:
0129:            /**
0130:             * Maps document {@link Element}s (representing lines) to
0131:             * {@link AnnotateLine}. <code>null</code> means that
0132:             * no data are available, yet. So alternative
0133:             * {@link #elementAnnotationsSubstitute} text shoudl be used.
0134:             *
0135:             * @thread it is accesed from multiple threads all mutations
0136:             * and iterations must be under elementAnnotations lock,
0137:             */
0138:            private Map elementAnnotations;
0139:
0140:            /**
0141:             * Maps revision number (strings) to raw commit
0142:             * messages (strings).
0143:             */
0144:            private Map commitMessages;
0145:
0146:            /**
0147:             * Represents text that should be displayed in
0148:             * visible bar with yet <code>null</code> elementAnnotations.
0149:             */
0150:            private String elementAnnotationsSubstitute;
0151:
0152:            private Color backgroundColor = Color.WHITE;
0153:            private Color foregroundColor = Color.BLACK;
0154:            private Color selectedColor = Color.BLUE;
0155:
0156:            /**
0157:             * Most recent status message.
0158:             */
0159:            private String recentStatusMessage;
0160:
0161:            /**
0162:             * Revision associated with caret line.
0163:             */
0164:            private String recentRevision;
0165:
0166:            /**
0167:             * Request processor to create threads that may be cancelled.
0168:             */
0169:            RequestProcessor requestProcessor = null;
0170:
0171:            /**
0172:             * Latest annotation comment fetching task launched.
0173:             */
0174:            private RequestProcessor.Task latestAnnotationTask = null;
0175:
0176:            /**
0177:             * Rendering hints for annotations sidebar inherited from editor settings.
0178:             */
0179:            private final Map renderingHints;
0180:
0181:            /**
0182:             * Creates new instance initializing final fields.
0183:             */
0184:            public AnnotationBar(JTextComponent target) {
0185:                this .textComponent = target;
0186:                this .editorUI = Utilities.getEditorUI(target);
0187:                this .foldHierarchy = FoldHierarchy.get(editorUI.getComponent());
0188:                this .doc = editorUI.getDocument();
0189:                this .caret = textComponent.getCaret();
0190:                if (textComponent instanceof  JEditorPane) {
0191:                    JEditorPane jep = (JEditorPane) textComponent;
0192:                    Class kitClass = jep.getEditorKit().getClass();
0193:                    Object userSetHints = Settings.getValue(kitClass,
0194:                            SettingsNames.RENDERING_HINTS);
0195:                    renderingHints = (userSetHints instanceof  Map && ((Map) userSetHints)
0196:                            .size() > 0) ? (Map) userSetHints : null;
0197:                } else {
0198:                    renderingHints = null;
0199:                }
0200:            }
0201:
0202:            // public contract ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0203:
0204:            /**
0205:             * Makes the bar visible and sensitive to
0206:             * LogOutoutListener events that should deliver
0207:             * actual content to be displayed.
0208:             */
0209:            public void annotate() {
0210:                annotated = true;
0211:                elementAnnotations = null;
0212:                commitMessages = null;
0213:                ResourceBundle loc = NbBundle.getBundle(AnnotationBar.class);
0214:                elementAnnotationsSubstitute = loc
0215:                        .getString("CTL_AnnotationSubstitute");
0216:
0217:                doc.addDocumentListener(this );
0218:                textComponent.addComponentListener(this );
0219:                editorUI.addPropertyChangeListener(this );
0220:
0221:                revalidate(); // resize the component
0222:            }
0223:
0224:            /**
0225:             * Result computed show it...
0226:             * Takes AnnotateLines and shows them.
0227:             */
0228:            public void annotationLines(File file, List annotateLines) {
0229:                List lines = new LinkedList(annotateLines);
0230:                int lineCount = lines.size();
0231:                /** 0 based line numbers => 1 based line numbers*/
0232:                int ann2editorPermutation[] = new int[lineCount];
0233:                for (int i = 0; i < lineCount; i++) {
0234:                    ann2editorPermutation[i] = i + 1;
0235:                }
0236:
0237:                DiffProvider diff = (DiffProvider) Lookup.getDefault().lookup(
0238:                        DiffProvider.class);
0239:                if (diff != null) {
0240:                    Reader r = new LinesReader(lines);
0241:                    Reader docReader = org.netbeans.modules.versioning.util.Utils
0242:                            .getDocumentReader(doc);
0243:                    try {
0244:
0245:                        Difference[] differences = diff.computeDiff(r,
0246:                                docReader);
0247:
0248:                        // customize annotation line numbers to match different reality
0249:                        // compule line permutation
0250:
0251:                        for (int i = 0; i < differences.length; i++) {
0252:                            Difference d = differences[i];
0253:                            if (d.getType() == Difference.ADD)
0254:                                continue;
0255:
0256:                            int editorStart;
0257:                            int firstShift = d.getFirstEnd()
0258:                                    - d.getFirstStart() + 1;
0259:                            if (d.getType() == Difference.CHANGE) {
0260:                                int firstLen = d.getFirstEnd()
0261:                                        - d.getFirstStart();
0262:                                int secondLen = d.getSecondEnd()
0263:                                        - d.getSecondStart();
0264:                                if (secondLen >= firstLen)
0265:                                    continue; // ADD or pure CHANGE
0266:                                editorStart = d.getSecondStart();
0267:                                firstShift = firstLen - secondLen;
0268:                            } else { // DELETE
0269:                                editorStart = d.getSecondStart() + 1;
0270:                            }
0271:
0272:                            for (int c = editorStart + firstShift - 1; c < lineCount; c++) {
0273:                                ann2editorPermutation[c] -= firstShift;
0274:                            }
0275:                        }
0276:
0277:                        for (int i = differences.length - 1; i >= 0; i--) {
0278:                            Difference d = differences[i];
0279:                            if (d.getType() == Difference.DELETE)
0280:                                continue;
0281:
0282:                            int firstStart;
0283:                            int firstShift = d.getSecondEnd()
0284:                                    - d.getSecondStart() + 1;
0285:                            if (d.getType() == Difference.CHANGE) {
0286:                                int firstLen = d.getFirstEnd()
0287:                                        - d.getFirstStart();
0288:                                int secondLen = d.getSecondEnd()
0289:                                        - d.getSecondStart();
0290:                                if (secondLen <= firstLen)
0291:                                    continue; // REMOVE or pure CHANGE
0292:                                firstShift = secondLen - firstLen;
0293:                                firstStart = d.getFirstStart();
0294:                            } else {
0295:                                firstStart = d.getFirstStart() + 1;
0296:                            }
0297:
0298:                            for (int k = firstStart - 1; k < lineCount; k++) {
0299:                                ann2editorPermutation[k] += firstShift;
0300:                            }
0301:                        }
0302:
0303:                    } catch (IOException e) {
0304:                        ErrorManager err = ErrorManager.getDefault();
0305:                        err
0306:                                .annotate(e,
0307:                                        "Cannot compute local diff required for annotations, ignoring..."); // NOI18N
0308:                        err.notify(ErrorManager.INFORMATIONAL, e);
0309:                    }
0310:                }
0311:
0312:                try {
0313:                    doc.atomicLock();
0314:                    StyledDocument sd = (StyledDocument) doc;
0315:                    Iterator it = lines.iterator();
0316:                    elementAnnotations = Collections
0317:                            .synchronizedMap(new HashMap(lines.size()));
0318:                    while (it.hasNext()) {
0319:                        AnnotateLine line = (AnnotateLine) it.next();
0320:                        int lineNum = ann2editorPermutation[line.getLineNum() - 1];
0321:                        try {
0322:                            int lineOffset = NbDocument.findLineOffset(sd,
0323:                                    lineNum - 1);
0324:                            Element element = sd
0325:                                    .getParagraphElement(lineOffset);
0326:                            elementAnnotations.put(element, line);
0327:                        } catch (IndexOutOfBoundsException ex) {
0328:                            // TODO how could I get line behind document end?
0329:                            // furtunately user does not spot it
0330:                            ErrorManager.getDefault().notify(
0331:                                    ErrorManager.INFORMATIONAL, ex);
0332:                        }
0333:                    }
0334:                } finally {
0335:                    doc.atomicUnlock();
0336:                }
0337:
0338:                // lazy listener registration
0339:                caret.addChangeListener(this );
0340:                this .caretTimer = new Timer(500, this );
0341:                caretTimer.setRepeats(false);
0342:
0343:                onCurrentLine();
0344:                revalidate();
0345:                repaint();
0346:            }
0347:
0348:            /**
0349:             * Takes commit messages and shows them as tooltips.
0350:             *
0351:             * @param a hashmap containing commit messages
0352:             */
0353:            public void commitMessages(Map messages) {
0354:                this .commitMessages = messages;
0355:            }
0356:
0357:            // implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0358:
0359:            /**
0360:             * Gets a the file related to the document
0361:             *
0362:             * @return the file related to the document, <code>null</code> if none
0363:             * exists.
0364:             */
0365:            private File getCurrentFile() {
0366:                File result = null;
0367:
0368:                DataObject dobj = (DataObject) doc
0369:                        .getProperty(Document.StreamDescriptionProperty);
0370:                if (dobj != null) {
0371:                    FileObject fo = dobj.getPrimaryFile();
0372:                    result = FileUtil.toFile(fo);
0373:                }
0374:
0375:                return result;
0376:            }
0377:
0378:            /**
0379:             * Registers "close" popup menu, tooltip manager
0380:             * and repaint on documet change manager.
0381:             */
0382:            public void addNotify() {
0383:                super .addNotify();
0384:
0385:                this .addMouseListener(new MouseAdapter() {
0386:                    public void mousePressed(MouseEvent e) {
0387:                        maybeShowPopup(e);
0388:                    }
0389:
0390:                    public void mouseReleased(MouseEvent e) {
0391:                        maybeShowPopup(e);
0392:                    }
0393:
0394:                    private void maybeShowPopup(MouseEvent e) {
0395:                        if (e.isPopupTrigger()) {
0396:                            e.consume();
0397:                            createPopup().show(e.getComponent(), e.getX(),
0398:                                    e.getY());
0399:                        }
0400:                    }
0401:                });
0402:
0403:                // register with tooltip manager
0404:                setToolTipText(""); // NOI18N
0405:
0406:            }
0407:
0408:            private JPopupMenu createPopup() {
0409:                final ResourceBundle loc = NbBundle
0410:                        .getBundle(AnnotationBar.class);
0411:                final JPopupMenu popupMenu = new JPopupMenu();
0412:                final JMenuItem diffMenu = new JMenuItem(loc
0413:                        .getString("CTL_MenuItem_DiffToRevision"));
0414:                diffMenu.addActionListener(new ActionListener() {
0415:                    public void actionPerformed(ActionEvent e) {
0416:                        if (recentRevision != null) {
0417:                            String prevRevision = Utils
0418:                                    .previousRevision(recentRevision);
0419:                            if (prevRevision != null) {
0420:                                File file = getCurrentFile();
0421:                                if (file != null) {
0422:                                    DiffExecutor diffExecutor = new DiffExecutor(
0423:                                            file.getName());
0424:                                    diffExecutor.showDiff(file, prevRevision,
0425:                                            recentRevision);
0426:                                }
0427:                            }
0428:                        }
0429:                    }
0430:                });
0431:                popupMenu.add(diffMenu);
0432:
0433:                final JMenuItem rollbackMenu = new JMenuItem(loc
0434:                        .getString("CTL_MenuItem_RollbackToRevision"));
0435:                rollbackMenu.addActionListener(new ActionListener() {
0436:                    public void actionPerformed(ActionEvent e) {
0437:                        File file = getCurrentFile();
0438:                        GetCleanAction.rollback(file, recentRevision);
0439:                    }
0440:                });
0441:                popupMenu.add(rollbackMenu);
0442:
0443:                Project prj = Utils.getProject(getCurrentFile());
0444:                if (prj != null) {
0445:                    String prjName = ProjectUtils.getInformation(prj)
0446:                            .getDisplayName();
0447:                    JMenuItem menu = new JMenuItem(NbBundle.getMessage(
0448:                            AnnotationBar.class,
0449:                            "CTL_MenuItem_FindCommitInProject", prjName));
0450:                    menu.addActionListener(new ActionListener() {
0451:                        public void actionPerformed(ActionEvent e) {
0452:                            int line = getCurrentLine();
0453:                            if (line == -1)
0454:                                return;
0455:                            AnnotateLine al = getAnnotateLine(line);
0456:                            if (al == null || commitMessages == null)
0457:                                return;
0458:                            String message = (String) commitMessages.get(al
0459:                                    .getRevision());
0460:                            File file = getCurrentFile();
0461:                            Project project = Utils.getProject(file);
0462:                            Context context = Utils.getProjectContext(project,
0463:                                    file);
0464:                            SearchHistoryAction.openSearch(context,
0465:                                    ProjectUtils.getInformation(project)
0466:                                            .getDisplayName(), message, al
0467:                                            .getAuthor(), al.getDate());
0468:                        }
0469:                    });
0470:                    popupMenu.add(menu);
0471:                }
0472:
0473:                JMenuItem menu = new JMenuItem(loc
0474:                        .getString("CTL_MenuItem_FindCommitInProjects"));
0475:                menu.addActionListener(new ActionListener() {
0476:                    public void actionPerformed(ActionEvent e) {
0477:                        int line = getCurrentLine();
0478:                        if (line == -1)
0479:                            return;
0480:                        AnnotateLine al = getAnnotateLine(line);
0481:                        if (al == null || commitMessages == null)
0482:                            return;
0483:                        String message = (String) commitMessages.get(al
0484:                                .getRevision());
0485:                        Project[] projects = OpenProjects.getDefault()
0486:                                .getOpenProjects();
0487:                        int n = projects.length;
0488:                        SearchHistoryAction
0489:                                .openSearch(
0490:                                        (n == 1) ? ProjectUtils.getInformation(
0491:                                                projects[0]).getDisplayName()
0492:                                                : NbBundle
0493:                                                        .getMessage(
0494:                                                                AnnotationBar.class,
0495:                                                                "CTL_FindAssociateChanges_OpenProjects_Title",
0496:                                                                Integer
0497:                                                                        .toString(n)),
0498:                                        message, al.getAuthor(), al.getDate());
0499:                    }
0500:                });
0501:                popupMenu.add(menu);
0502:
0503:                menu = new JMenuItem(loc
0504:                        .getString("CTL_MenuItem_CloseAnnotations"));
0505:                menu.addActionListener(new ActionListener() {
0506:                    public void actionPerformed(ActionEvent e) {
0507:                        hideBar();
0508:                    }
0509:                });
0510:                popupMenu.addSeparator();
0511:                popupMenu.add(menu);
0512:
0513:                // dynamic labels an dvisibility
0514:
0515:                diffMenu.setVisible(false);
0516:                rollbackMenu.setVisible(false);
0517:                if (recentRevision != null) {
0518:                    String prevRevision = Utils
0519:                            .previousRevision(recentRevision);
0520:                    if (prevRevision != null) {
0521:                        String format = loc
0522:                                .getString("CTL_MenuItem_DiffToRevision");
0523:                        diffMenu.setText(MessageFormat.format(format,
0524:                                new Object[] { recentRevision, prevRevision }));
0525:                        diffMenu.setVisible(true);
0526:                    }
0527:                    String format = loc
0528:                            .getString("CTL_MenuItem_RollbackToRevision");
0529:                    rollbackMenu.setText(MessageFormat.format(format,
0530:                            new Object[] { recentRevision }));
0531:                    rollbackMenu.setVisible(true);
0532:                }
0533:
0534:                return popupMenu;
0535:            }
0536:
0537:            /**
0538:             * Hides the annotation bar from user. 
0539:             */
0540:            void hideBar() {
0541:                annotated = false;
0542:                revalidate();
0543:                release();
0544:            }
0545:
0546:            /**
0547:             * Gets the line number of the caret's current position. The first line
0548:             * will return a line number of 0 (zero). If it's impossible to determine
0549:             * the caret's current line number -1 will be returned.
0550:             *
0551:             * @return the line number of the caret's current position
0552:             */
0553:            private int getCurrentLine() {
0554:                int result = 0;
0555:
0556:                int offset = caret.getDot();
0557:                try {
0558:                    result = Utilities.getLineOffset(doc, offset);
0559:                } catch (BadLocationException ex) {
0560:                    result = -1;
0561:                }
0562:
0563:                return result;
0564:            }
0565:
0566:            /**
0567:             * Gets a request processor which is able to cancel tasks.
0568:             */
0569:            private RequestProcessor getRequestProcessor() {
0570:                if (requestProcessor == null) {
0571:                    requestProcessor = new RequestProcessor("AnnotationBarRP",
0572:                            1, true); // NOI18N
0573:                }
0574:
0575:                return requestProcessor;
0576:            }
0577:
0578:            /**
0579:             * Shows commit message in status bar and or revision change repaints side
0580:             * bar (to highlight same revision). This process is started in a
0581:             * seperate thread.
0582:             */
0583:            private void onCurrentLine() {
0584:                if (latestAnnotationTask != null) {
0585:                    latestAnnotationTask.cancel();
0586:                }
0587:
0588:                latestAnnotationTask = getRequestProcessor().post(this );
0589:            }
0590:
0591:            // latestAnnotationTask business logic
0592:            public void run() {
0593:                // get resource bundle
0594:                ResourceBundle loc = NbBundle.getBundle(AnnotationBar.class);
0595:                // give status bar "wait" indication
0596:                StatusBar statusBar = editorUI.getStatusBar();
0597:                recentStatusMessage = loc
0598:                        .getString("CTL_StatusBar_WaitFetchAnnotation");
0599:                statusBar.setText(StatusBar.CELL_MAIN, recentStatusMessage);
0600:
0601:                // determine current line
0602:                int line = -1;
0603:                int offset = caret.getDot();
0604:                try {
0605:                    line = Utilities.getLineOffset(doc, offset);
0606:                } catch (BadLocationException ex) {
0607:                    ErrorManager err = ErrorManager.getDefault();
0608:                    err.annotate(ex, "Can not get line for caret at offset "
0609:                            + offset); // NOI18N
0610:                    err.notify(ex);
0611:                    clearRecentFeedback();
0612:                    return;
0613:                }
0614:
0615:                // handle locally modified lines
0616:                AnnotateLine al = getAnnotateLine(line);
0617:                if (al == null) {
0618:                    AnnotationMarkProvider amp = AnnotationMarkInstaller
0619:                            .getMarkProvider(textComponent);
0620:                    if (amp != null) {
0621:                        amp.setMarks(Collections.EMPTY_LIST);
0622:                    }
0623:                    clearRecentFeedback();
0624:                    if (recentRevision != null) {
0625:                        recentRevision = null;
0626:                        repaint();
0627:                    }
0628:                    return;
0629:                }
0630:
0631:                // handle unchanged lines
0632:                String revision = al.getRevision();
0633:                if (revision.equals(recentRevision) == false) {
0634:                    recentRevision = revision;
0635:                    repaint();
0636:
0637:                    AnnotationMarkProvider amp = AnnotationMarkInstaller
0638:                            .getMarkProvider(textComponent);
0639:                    if (amp != null) {
0640:
0641:                        List marks = new ArrayList(elementAnnotations.size());
0642:                        // I cannot affort to lock elementAnnotations for long time
0643:                        // it's accessed from editor thread too
0644:                        Iterator it2;
0645:                        synchronized (elementAnnotations) {
0646:                            it2 = new HashSet(elementAnnotations.entrySet())
0647:                                    .iterator();
0648:                        }
0649:                        while (it2.hasNext()) {
0650:                            Map.Entry next = (Map.Entry) it2.next();
0651:                            AnnotateLine annotateLine = (AnnotateLine) next
0652:                                    .getValue();
0653:                            if (revision.equals(annotateLine.getRevision())) {
0654:                                Element element = (Element) next.getKey();
0655:                                if (elementAnnotations.containsKey(element) == false) {
0656:                                    continue;
0657:                                }
0658:                                int elementOffset = element.getStartOffset();
0659:                                int lineNumber = NbDocument.findLineNumber(
0660:                                        (StyledDocument) doc, elementOffset);
0661:                                AnnotationMark mark = new AnnotationMark(
0662:                                        lineNumber, revision);
0663:                                marks.add(mark);
0664:                            }
0665:
0666:                            if (Thread.interrupted()) {
0667:                                clearRecentFeedback();
0668:                                return;
0669:                            }
0670:                        }
0671:                        amp.setMarks(marks);
0672:                    }
0673:                }
0674:
0675:                if (commitMessages != null) {
0676:                    String message = (String) commitMessages.get(revision);
0677:                    if (message != null) {
0678:                        recentStatusMessage = message;
0679:                        statusBar.setText(StatusBar.CELL_MAIN, al.getAuthor()
0680:                                + ": " + recentStatusMessage); // NOI18N
0681:                    } else {
0682:                        clearRecentFeedback();
0683:                    }
0684:                } else {
0685:                    clearRecentFeedback();
0686:                }
0687:                ;
0688:            }
0689:
0690:            /**
0691:             * Clears the status bar if it contains the latest status message
0692:             * displayed by this annotation bar.
0693:             */
0694:            private void clearRecentFeedback() {
0695:                StatusBar statusBar = editorUI.getStatusBar();
0696:                if (statusBar.getText(StatusBar.CELL_MAIN) == recentStatusMessage) {
0697:                    statusBar.setText(StatusBar.CELL_MAIN, ""); // NOI18N
0698:                }
0699:            }
0700:
0701:            /**
0702:             * Components created by SibeBarFactory are positioned
0703:             * using a Layout manager that determines componnet size
0704:             * by retireving preferred size.
0705:             *
0706:             * <p>Once componnet needs resizing it simply calls
0707:             * {@link #revalidate} that triggers new layouting
0708:             * that consults prefered size.
0709:             */
0710:            public Dimension getPreferredSize() {
0711:                Dimension dim = textComponent.getSize();
0712:                int width = annotated ? getBarWidth() : 0;
0713:                dim.width = width;
0714:                dim.height *= 2; // XXX
0715:                return dim;
0716:            }
0717:
0718:            /**
0719:             * Gets the maximum size of this component.
0720:             *
0721:             * @return the maximum size of this component
0722:             */
0723:            public Dimension getMaximumSize() {
0724:                return getPreferredSize();
0725:            }
0726:
0727:            /**
0728:             * Gets the preferred width of this component.
0729:             *
0730:             * @return the preferred width of this component
0731:             */
0732:            private int getBarWidth() {
0733:                String longestString = ""; // NOI18N
0734:                if (elementAnnotations == null) {
0735:                    longestString = elementAnnotationsSubstitute;
0736:                } else {
0737:                    synchronized (elementAnnotations) {
0738:                        Iterator it = elementAnnotations.values().iterator();
0739:                        while (it.hasNext()) {
0740:                            AnnotateLine line = (AnnotateLine) it.next();
0741:                            String displayName = line.getRevision() + " "
0742:                                    + line.getAuthor(); // NOI18N
0743:                            if (displayName.length() > longestString.length()) {
0744:                                longestString = displayName;
0745:                            }
0746:                        }
0747:                    }
0748:                }
0749:                char[] data = longestString.toCharArray();
0750:                int w = getGraphics().getFontMetrics().charsWidth(data, 0,
0751:                        data.length);
0752:                return w;
0753:            }
0754:
0755:            /**
0756:             * Pair method to {@link #annotate}. It releases
0757:             * all resources.
0758:             */
0759:            private void release() {
0760:                editorUI.removePropertyChangeListener(this );
0761:                textComponent.removeComponentListener(this );
0762:                doc.removeDocumentListener(this );
0763:                caret.removeChangeListener(this );
0764:                if (caretTimer != null) {
0765:                    caretTimer.removeActionListener(this );
0766:                }
0767:                commitMessages = null;
0768:                elementAnnotations = null;
0769:                // cancel running annotation task if active
0770:                if (latestAnnotationTask != null) {
0771:                    latestAnnotationTask.cancel();
0772:                }
0773:                AnnotationMarkProvider amp = AnnotationMarkInstaller
0774:                        .getMarkProvider(textComponent);
0775:                if (amp != null) {
0776:                    amp.setMarks(Collections.EMPTY_LIST);
0777:                }
0778:
0779:                clearRecentFeedback();
0780:            }
0781:
0782:            /**
0783:             * Paints one view that corresponds to a line (or
0784:             * multiple lines if folding takes effect).
0785:             */
0786:            private void paintView(View view, Graphics g, int yBase) {
0787:                JTextComponent component = editorUI.getComponent();
0788:                if (component == null)
0789:                    return;
0790:                BaseTextUI textUI = (BaseTextUI) component.getUI();
0791:
0792:                Element rootElem = textUI.getRootView(component).getElement();
0793:                int line = rootElem.getElementIndex(view.getStartOffset());
0794:
0795:                String annotation = ""; // NOI18N
0796:                AnnotateLine al = null;
0797:                if (elementAnnotations != null) {
0798:                    al = getAnnotateLine(line);
0799:                    if (al != null) {
0800:                        annotation = al.getRevision() + " " + al.getAuthor(); // NOI18N
0801:                    }
0802:                } else {
0803:                    annotation = elementAnnotationsSubstitute;
0804:                }
0805:
0806:                if (al != null && al.getRevision().equals(recentRevision)) {
0807:                    g.setColor(selectedColor());
0808:                } else {
0809:                    g.setColor(foregroundColor());
0810:                }
0811:                g.drawString(annotation, 0, yBase + editorUI.getLineAscent());
0812:            }
0813:
0814:            /**
0815:             * Presents commit message as tooltips.
0816:             */
0817:            public String getToolTipText(MouseEvent e) {
0818:                if (editorUI == null)
0819:                    return null;
0820:                int line = getLineFromMouseEvent(e);
0821:
0822:                StringBuffer annotation = new StringBuffer();
0823:                if (elementAnnotations != null) {
0824:                    AnnotateLine al = getAnnotateLine(line);
0825:
0826:                    if (al != null) {
0827:                        String escapedAuthor = NbBundle.getMessage(
0828:                                AnnotationBar.class, "BK0001");
0829:                        try {
0830:                            escapedAuthor = XMLUtil.toElementContent(al
0831:                                    .getAuthor());
0832:                        } catch (CharConversionException e1) {
0833:                            ErrorManager err = ErrorManager.getDefault();
0834:                            err.annotate(e1, "CVS.AB: can not HTML escape: "
0835:                                    + al.getAuthor()); // NOI18N
0836:                            err.notify(ErrorManager.INFORMATIONAL, e1);
0837:                        }
0838:
0839:                        // always return unique string to avoid tooltip sharing on mouse move over same revisions -->
0840:                        annotation.append("<html><!-- line=" + line++ + " -->"
0841:                                + al.getRevision() + " <b>" + escapedAuthor
0842:                                + "</b> " + al.getDateString()); // NOI18N
0843:                        if (commitMessages != null) {
0844:                            String message = (String) commitMessages.get(al
0845:                                    .getRevision());
0846:                            if (message != null) {
0847:                                String escaped = null;
0848:                                try {
0849:                                    escaped = XMLUtil.toElementContent(message);
0850:                                } catch (CharConversionException e1) {
0851:                                    ErrorManager err = ErrorManager
0852:                                            .getDefault();
0853:                                    err.annotate(e1,
0854:                                            "CVS.AB: can not HTML escape: "
0855:                                                    + message); // NOI18N
0856:                                    err.notify(ErrorManager.INFORMATIONAL, e1);
0857:                                }
0858:                                if (escaped != null) {
0859:                                    String lined = escaped.replaceAll(System
0860:                                            .getProperty("line.separator"),
0861:                                            "<br>"); // NOI18N
0862:                                    annotation.append("<p>" + lined); // NOI18N
0863:                                }
0864:                            }
0865:                        }
0866:                    }
0867:                } else {
0868:                    annotation.append(elementAnnotationsSubstitute);
0869:                }
0870:
0871:                return annotation.toString();
0872:            }
0873:
0874:            /**
0875:             * Locates AnnotateLine associated with given line. The
0876:             * line is translated to Element that is used as map lookup key.
0877:             * The map is initially filled up with Elements sampled on
0878:             * annotate() method.
0879:             *
0880:             * <p>Key trick is that Element's identity is maintained
0881:             * until line removal (and is restored on undo).
0882:             *
0883:             * @param line
0884:             * @return found AnnotateLine or <code>null</code>
0885:             */
0886:            private AnnotateLine getAnnotateLine(int line) {
0887:                StyledDocument sd = (StyledDocument) doc;
0888:                int lineOffset = NbDocument.findLineOffset(sd, line);
0889:                Element element = sd.getParagraphElement(lineOffset);
0890:                AnnotateLine al = (AnnotateLine) elementAnnotations
0891:                        .get(element);
0892:
0893:                if (al != null) {
0894:                    int startOffset = element.getStartOffset();
0895:                    int endOffset = element.getEndOffset();
0896:                    try {
0897:                        int len = endOffset - startOffset;
0898:                        String text = doc.getText(startOffset, len - 1);
0899:                        String content = al.getContent();
0900:                        if (text.equals(content)) {
0901:                            return al;
0902:                        }
0903:                    } catch (BadLocationException e) {
0904:                        ErrorManager err = ErrorManager.getDefault();
0905:                        err.annotate(e,
0906:                                "CVS.AB: can not locate line annotation."); // NOI18N
0907:                        err.notify(ErrorManager.INFORMATIONAL, e);
0908:                    }
0909:                }
0910:
0911:                return null;
0912:            }
0913:
0914:            /**
0915:             * GlyphGutter copy pasted bolerplate method.
0916:             * It invokes {@link #paintView} that contains
0917:             * actual business logic.
0918:             */
0919:            public void paintComponent(Graphics g) {
0920:                super .paintComponent(g);
0921:
0922:                Rectangle clip = g.getClipBounds();
0923:
0924:                JTextComponent component = editorUI.getComponent();
0925:                if (component == null)
0926:                    return;
0927:
0928:                BaseTextUI textUI = (BaseTextUI) component.getUI();
0929:                View rootView = Utilities.getDocumentView(component);
0930:                if (rootView == null)
0931:                    return;
0932:
0933:                g.setColor(backgroundColor());
0934:                g.fillRect(clip.x, clip.y, clip.width, clip.height);
0935:
0936:                if (renderingHints != null) {
0937:                    ((Graphics2D) g).addRenderingHints(renderingHints);
0938:                }
0939:
0940:                AbstractDocument doc = (AbstractDocument) component
0941:                        .getDocument();
0942:                doc.readLock();
0943:                try {
0944:                    foldHierarchy.lock();
0945:                    try {
0946:                        int startPos = textUI.getPosFromY(clip.y);
0947:                        int startViewIndex = rootView.getViewIndex(startPos,
0948:                                Position.Bias.Forward);
0949:                        int rootViewCount = rootView.getViewCount();
0950:
0951:                        if (startViewIndex >= 0
0952:                                && startViewIndex < rootViewCount) {
0953:                            // find the nearest visible line with an annotation
0954:                            Rectangle rec = textUI.modelToView(component,
0955:                                    rootView.getView(startViewIndex)
0956:                                            .getStartOffset());
0957:                            int y = (rec == null) ? 0 : rec.y;
0958:
0959:                            int clipEndY = clip.y + clip.height;
0960:                            for (int i = startViewIndex; i < rootViewCount; i++) {
0961:                                View view = rootView.getView(i);
0962:                                paintView(view, g, y);
0963:                                y += editorUI.getLineHeight();
0964:                                if (y >= clipEndY) {
0965:                                    break;
0966:                                }
0967:                            }
0968:                        }
0969:
0970:                    } finally {
0971:                        foldHierarchy.unlock();
0972:                    }
0973:                } catch (BadLocationException ble) {
0974:                    ErrorManager.getDefault().notify(ble);
0975:                } finally {
0976:                    doc.readUnlock();
0977:                }
0978:            }
0979:
0980:            private Color backgroundColor() {
0981:                if (textComponent != null) {
0982:                    return textComponent.getBackground();
0983:                }
0984:                return backgroundColor;
0985:            }
0986:
0987:            private Color foregroundColor() {
0988:                if (textComponent != null) {
0989:                    return textComponent.getForeground();
0990:                }
0991:                return foregroundColor;
0992:            }
0993:
0994:            private Color selectedColor() {
0995:                if (backgroundColor == backgroundColor()) {
0996:                    return selectedColor;
0997:                }
0998:                if (textComponent != null) {
0999:                    return textComponent.getForeground();
1000:                }
1001:                return selectedColor;
1002:
1003:            }
1004:
1005:            /** GlyphGutter copy pasted utility method. */
1006:            private int getLineFromMouseEvent(MouseEvent e) {
1007:                int line = -1;
1008:                if (editorUI != null) {
1009:                    try {
1010:                        JTextComponent component = editorUI.getComponent();
1011:                        BaseTextUI textUI = (BaseTextUI) component.getUI();
1012:                        int clickOffset = textUI.viewToModel(component,
1013:                                new Point(0, e.getY()));
1014:                        line = Utilities.getLineOffset(doc, clickOffset);
1015:                    } catch (BadLocationException ble) {
1016:                    }
1017:                }
1018:                return line;
1019:            }
1020:
1021:            /** Implementation */
1022:            public void propertyChange(PropertyChangeEvent evt) {
1023:                if (evt == null)
1024:                    return;
1025:                String id = evt.getPropertyName();
1026:                if (EditorUI.COMPONENT_PROPERTY.equals(id)) { // NOI18N
1027:                    if (evt.getNewValue() == null) {
1028:                        // component deinstalled, lets uninstall all isteners
1029:                        release();
1030:                    }
1031:                }
1032:
1033:            }
1034:
1035:            /** Implementation */
1036:            public void changedUpdate(DocumentEvent e) {
1037:            }
1038:
1039:            /** Implementation */
1040:            public void insertUpdate(DocumentEvent e) {
1041:                // handle new lines,  Enter hit at end of line changes
1042:                // the line element instance
1043:                // XXX Actually NB document implementation triggers this method two times
1044:                //  - first time with one removed and two added lines
1045:                //  - second time with two removed and two added lines
1046:                if (elementAnnotations != null) {
1047:                    Element[] elements = e.getDocument().getRootElements();
1048:                    synchronized (elementAnnotations) { // atomic change
1049:                        for (int i = 0; i < elements.length; i++) {
1050:                            Element element = elements[i];
1051:                            DocumentEvent.ElementChange change = e
1052:                                    .getChange(element);
1053:                            if (change == null)
1054:                                continue;
1055:                            Element[] removed = change.getChildrenRemoved();
1056:                            Element[] added = change.getChildrenAdded();
1057:
1058:                            if (removed.length == added.length) {
1059:                                for (int c = 0; c < removed.length; c++) {
1060:                                    Object recent = elementAnnotations
1061:                                            .get(removed[c]);
1062:                                    if (recent != null) {
1063:                                        elementAnnotations.remove(removed[c]);
1064:                                        elementAnnotations
1065:                                                .put(added[c], recent);
1066:                                    }
1067:                                }
1068:                            } else if (removed.length == 1 && added.length > 0) {
1069:                                Element key = removed[0];
1070:                                Object recent = elementAnnotations.get(key);
1071:                                if (recent != null) {
1072:                                    elementAnnotations.remove(key);
1073:                                    elementAnnotations.put(added[0], recent);
1074:                                }
1075:                            }
1076:                        }
1077:                    }
1078:                }
1079:                repaint();
1080:            }
1081:
1082:            /** Implementation */
1083:            public void removeUpdate(DocumentEvent e) {
1084:                if (e.getDocument().getLength() == 0) { // external reload
1085:                    hideBar();
1086:                }
1087:                repaint();
1088:            }
1089:
1090:            /** Caret */
1091:            public void stateChanged(ChangeEvent e) {
1092:                assert e.getSource() == caret;
1093:                caretTimer.restart();
1094:            }
1095:
1096:            /** Timer */
1097:            public void actionPerformed(ActionEvent e) {
1098:                assert e.getSource() == caretTimer;
1099:                onCurrentLine();
1100:            }
1101:
1102:            /** on JTextPane */
1103:            public void componentHidden(ComponentEvent e) {
1104:            }
1105:
1106:            /** on JTextPane */
1107:            public void componentMoved(ComponentEvent e) {
1108:            }
1109:
1110:            /** on JTextPane */
1111:            public void componentResized(ComponentEvent e) {
1112:                revalidate();
1113:            }
1114:
1115:            /** on JTextPane */
1116:            public void componentShown(ComponentEvent e) {
1117:            }
1118:
1119:            private static class CvsAnnotation extends Annotation {
1120:
1121:                private final String text;
1122:
1123:                private Line line;
1124:
1125:                public CvsAnnotation(String tooltip, Line line) {
1126:                    text = tooltip;
1127:                    this .line = line;
1128:                }
1129:
1130:                public void attach() {
1131:                    attach(line);
1132:                    line = null;
1133:                }
1134:
1135:                public String getShortDescription() {
1136:                    return text;
1137:                }
1138:
1139:                public String getAnnotationType() {
1140:                    return "org-netbeans-modules-versioning-system-cvss-Annotation"; // NOI18N
1141:                }
1142:            }
1143:        }
w_ww__.j___a__v__a___2s_.__c_o___m | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.