2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org
.jetbrains
.idea
.maven
.indices
;
18 import com
.intellij
.openapi
.Disposable
;
19 import com
.intellij
.openapi
.project
.Project
;
20 import com
.intellij
.ui
.DocumentAdapter
;
21 import com
.intellij
.ui
.SimpleColoredComponent
;
22 import com
.intellij
.ui
.SimpleTextAttributes
;
23 import com
.intellij
.ui
.treeStructure
.Tree
;
24 import com
.intellij
.util
.Alarm
;
25 import com
.intellij
.util
.ui
.UIUtil
;
26 import com
.intellij
.util
.ui
.tree
.TreeUtil
;
27 import org
.jetbrains
.idea
.maven
.project
.MavenId
;
28 import org
.jetbrains
.idea
.maven
.utils
.MavenLog
;
29 import org
.sonatype
.nexus
.index
.ArtifactInfo
;
32 import javax
.swing
.event
.DocumentEvent
;
33 import javax
.swing
.event
.TreeModelListener
;
34 import javax
.swing
.event
.TreeSelectionEvent
;
35 import javax
.swing
.event
.TreeSelectionListener
;
36 import javax
.swing
.tree
.TreeCellRenderer
;
37 import javax
.swing
.tree
.TreeModel
;
38 import javax
.swing
.tree
.TreePath
;
40 import java
.awt
.event
.KeyAdapter
;
41 import java
.awt
.event
.KeyEvent
;
42 import java
.awt
.event
.MouseAdapter
;
43 import java
.awt
.event
.MouseEvent
;
44 import java
.util
.List
;
46 public class MavenArtifactSearchPanel
extends JPanel
{
47 private final Project myProject
;
48 private final boolean myClassMode
;
49 private final Listener myListener
;
51 private JTextField mySearchField
;
52 private Tree myResultList
;
54 private final Alarm myAlarm
;
56 public MavenArtifactSearchPanel(Project project
, String initialText
, boolean classMode
, Listener listener
, Disposable parent
) {
58 myClassMode
= classMode
;
59 myListener
= listener
;
61 initComponents(initialText
);
62 myAlarm
= new Alarm(Alarm
.ThreadToUse
.OWN_THREAD
, parent
);
65 public JTextField
getSearchField() {
69 private void initComponents(String initialText
) {
70 mySearchField
= new JTextField(initialText
);
71 myResultList
= new Tree();
73 setLayout(new BorderLayout());
74 add(mySearchField
, BorderLayout
.NORTH
);
75 add(new JScrollPane(myResultList
), BorderLayout
.CENTER
);
77 mySearchField
.getDocument().addDocumentListener(new DocumentAdapter() {
78 protected void textChanged(DocumentEvent e
) {
83 myResultList
.addTreeSelectionListener(new TreeSelectionListener() {
84 public void valueChanged(TreeSelectionEvent e
) {
85 if (myAlarm
.getActiveRequestCount() > 0) return;
87 boolean hasSelection
= !myResultList
.isSelectionEmpty();
88 myListener
.canSelectStateChanged(MavenArtifactSearchPanel
.this, hasSelection
);
92 mySearchField
.addKeyListener(new KeyAdapter() {
94 public void keyPressed(KeyEvent e
) {
95 final Object action
= getAction(e
, myResultList
);
96 if ("selectNext".equals(action
)) {
97 TreeUtil
.moveDown(myResultList
);
99 else if ("selectPrevious".equals(action
)) {
100 TreeUtil
.moveUp(myResultList
);
102 else if ("scrollUpChangeSelection".equals(action
)) {
103 TreeUtil
.movePageUp(myResultList
);
105 else if ("scrollDownChangeSelection".equals(action
)) {
106 TreeUtil
.movePageDown(myResultList
);
110 private Object
getAction(final KeyEvent e
, final JComponent comp
) {
111 final KeyStroke stroke
= KeyStroke
.getKeyStroke(e
.getKeyCode(), e
.getModifiers());
112 return comp
.getInputMap().get(stroke
);
116 myResultList
.setRootVisible(false);
117 myResultList
.setShowsRootHandles(true);
118 myResultList
.setModel(null);
119 myResultList
.setFocusable(false);
120 myResultList
.setCellRenderer(myClassMode ?
new MyClassCellRenderer() : new MyArtifactCellRenderer());
122 myResultList
.addMouseListener(new MouseAdapter() {
124 public void mouseClicked(MouseEvent e
) {
125 if (e
.getClickCount() == 2) {
126 Object sel
= myResultList
.getLastSelectedPathComponent();
127 if (sel
!= null && myResultList
.getModel().isLeaf(sel
)) {
128 myListener
.doubleClicked();
132 if (!mySearchField
.hasFocus()) {
133 mySearchField
.requestFocus();
139 public void scheduleSearch() {
140 myListener
.canSelectStateChanged(this, false);
142 // evaluate text value in the swing thread
143 final String text
= mySearchField
.getText();
145 myAlarm
.cancelAllRequests();
146 myAlarm
.addRequest(new Runnable() {
151 catch (Throwable e
) {
152 MavenLog
.LOG
.warn(e
);
158 private void doSearch(String searchText
) {
159 MavenSearcher searcher
= myClassMode ?
new MavenClassSearcher() : new MavenArtifactSearcher();
160 List
<MavenArtifactSearchResult
> result
= searcher
.search(myProject
, searchText
, 200);
161 final TreeModel model
= new MyTreeModel(result
);
163 SwingUtilities
.invokeLater(new Runnable() {
165 if (myProject
.isDisposed()) return;
166 myResultList
.setModel(model
);
167 myResultList
.setSelectionRow(0);
172 public MavenId
getResult() {
173 Object sel
= myResultList
.getLastSelectedPathComponent();
175 if (sel
instanceof ArtifactInfo
) {
176 info
= (ArtifactInfo
)sel
;
179 info
= ((MavenArtifactSearchResult
)sel
).versions
.get(0);
182 return new MavenId(info
.groupId
, info
.artifactId
, info
.version
);
185 private static class MyTreeModel
implements TreeModel
{
186 List
<?
extends MavenArtifactSearchResult
> myItems
;
188 private MyTreeModel(List
<?
extends MavenArtifactSearchResult
> items
) {
192 public Object
getRoot() {
196 public Object
getChild(Object parent
, int index
) {
197 return getList(parent
).get(index
);
200 public int getChildCount(Object parent
) {
201 return getList(parent
).size();
204 public List
getList(Object parent
) {
205 if (parent
== myItems
) return myItems
;
206 if (parent
instanceof MavenArtifactSearchResult
) return ((MavenArtifactSearchResult
)parent
).versions
;
210 public boolean isLeaf(Object node
) {
211 return getList(node
) == null;
214 public int getIndexOfChild(Object parent
, Object child
) {
215 return getList(parent
).indexOf(child
);
218 public void valueForPathChanged(TreePath path
, Object newValue
) {
221 public void addTreeModelListener(TreeModelListener l
) {
224 public void removeTreeModelListener(TreeModelListener l
) {
228 private static class MyArtifactCellRenderer
extends JPanel
implements TreeCellRenderer
{
229 protected SimpleColoredComponent myLeftComponent
= new SimpleColoredComponent();
230 protected SimpleColoredComponent myRightComponent
= new SimpleColoredComponent();
232 private MyArtifactCellRenderer() {
233 setLayout(new BorderLayout());
236 public Component
getTreeCellRendererComponent(JTree tree
, Object value
, boolean selected
, boolean expanded
, boolean leaf
, int row
,
238 myLeftComponent
.clear();
239 myRightComponent
.clear();
241 if (UIUtil
.isUnderQuaquaLookAndFeel()) {
242 setBackground(selected ? UIUtil
.getTreeSelectionBackground() : null);
246 setBackground(UIUtil
.getTreeSelectionBackground());
247 setForeground(UIUtil
.getTreeSelectionForeground());
251 setForeground(tree
.getForeground());
255 if (getFont() == null) setFont(tree
.getFont());
257 if (value
== tree
.getModel().getRoot()) {
258 myLeftComponent
.append("Results", SimpleTextAttributes
.REGULAR_ATTRIBUTES
);
260 else if (value
instanceof MavenArtifactSearchResult
) {
261 formatSearchResult(tree
, (MavenArtifactSearchResult
)value
);
263 else if (value
instanceof ArtifactInfo
) {
264 ArtifactInfo info
= (ArtifactInfo
)value
;
265 myLeftComponent
.append(info
.groupId
+ ":" + info
.artifactId
+ ":" + info
.version
,
266 SimpleTextAttributes
.GRAY_ATTRIBUTES
);
270 add(myLeftComponent
, BorderLayout
.WEST
);
271 JPanel spacer
= new JPanel();
272 spacer
.setBorder(BorderFactory
.createEmptyBorder(0, 2, 0, 2));
273 spacer
.setBackground(selected ? UIUtil
.getTreeSelectionBackground() : tree
.getBackground());
274 add(spacer
, BorderLayout
.CENTER
);
275 add(myRightComponent
, BorderLayout
.EAST
);
279 protected void formatSearchResult(JTree tree
, MavenArtifactSearchResult searchResult
) {
280 ArtifactInfo first
= searchResult
.versions
.get(0);
281 ArtifactInfo last
= searchResult
.versions
.get(searchResult
.versions
.size() - 1);
282 myLeftComponent
.append(first
.groupId
+ ":" + first
.artifactId
, SimpleTextAttributes
.REGULAR_ATTRIBUTES
);
283 myLeftComponent
.append(":" + last
.version
+ "-" + first
.version
, SimpleTextAttributes
.GRAY_ATTRIBUTES
);
287 private static class MyClassCellRenderer
extends MyArtifactCellRenderer
{
289 protected void formatSearchResult(JTree tree
, MavenArtifactSearchResult searchResult
) {
290 MavenClassSearchResult classResult
= (MavenClassSearchResult
)searchResult
;
291 ArtifactInfo info
= searchResult
.versions
.get(0);
293 myLeftComponent
.append(classResult
.className
, SimpleTextAttributes
.REGULAR_ATTRIBUTES
);
294 myLeftComponent
.append(" (" + classResult
.packageName
+ ")", SimpleTextAttributes
.GRAY_ATTRIBUTES
);
296 myRightComponent
.append(" " + info
.groupId
+ ":" + info
.artifactId
,
297 SimpleTextAttributes
.GRAY_ATTRIBUTES
);
301 public interface Listener
{
302 void doubleClicked();
304 void canSelectStateChanged(MavenArtifactSearchPanel from
, boolean canSelect
);