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
.svn
.dialogs
;
18 import com
.intellij
.openapi
.actionSystem
.*;
19 import com
.intellij
.openapi
.keymap
.KeymapManager
;
20 import com
.intellij
.openapi
.project
.Project
;
21 import com
.intellij
.openapi
.util
.IconLoader
;
22 import com
.intellij
.openapi
.vcs
.changes
.VcsDirtyScopeManager
;
23 import com
.intellij
.openapi
.vfs
.VirtualFile
;
24 import com
.intellij
.openapi
.vfs
.VirtualFileManager
;
25 import com
.intellij
.openapi
.wm
.ToolWindowManager
;
26 import com
.intellij
.ui
.PopupHandler
;
27 import com
.intellij
.util
.containers
.HashMap
;
28 import org
.jetbrains
.idea
.svn
.SvnVcs
;
29 import org
.tmatesoft
.svn
.core
.SVNException
;
30 import org
.tmatesoft
.svn
.core
.SVNProperty
;
31 import org
.tmatesoft
.svn
.core
.SVNPropertyValue
;
32 import org
.tmatesoft
.svn
.core
.SVNURL
;
33 import org
.tmatesoft
.svn
.core
.wc
.ISVNPropertyHandler
;
34 import org
.tmatesoft
.svn
.core
.wc
.SVNPropertyData
;
35 import org
.tmatesoft
.svn
.core
.wc
.SVNRevision
;
36 import org
.tmatesoft
.svn
.core
.wc
.SVNWCClient
;
39 import javax
.swing
.event
.ListSelectionEvent
;
40 import javax
.swing
.event
.ListSelectionListener
;
41 import javax
.swing
.table
.DefaultTableCellRenderer
;
42 import javax
.swing
.table
.DefaultTableModel
;
46 import java
.util
.TreeMap
;
49 * Created by IntelliJ IDEA.
54 public class PropertiesComponent
extends JPanel
{
55 public static final String ID
= "SVN Properties";
56 private JTable myTable
;
57 private JTextArea myTextArea
;
58 private boolean myIsFollowSelection
;
61 private JSplitPane mySplitPane
;
62 private static final String CONTEXT_ID
= "context";
63 private final CloseAction myCloseAction
= new CloseAction();
64 private final RefreshAction myRefreshAction
= new RefreshAction();
65 private ActionGroup myPopupActionGroup
;
67 public PropertiesComponent() {
68 // register toolwindow and add listener to the selection.
69 myIsFollowSelection
= true;
74 setLayout(new BorderLayout());
75 myTable
= new JTable();
76 myTextArea
= new JTextArea(0, 0);
77 myTextArea
.setEditable(false);
78 JScrollPane scrollPane
= new JScrollPane(myTable
);
79 mySplitPane
= new JSplitPane(JSplitPane
.VERTICAL_SPLIT
, true, scrollPane
, new JScrollPane(myTextArea
));
80 add(mySplitPane
, BorderLayout
.CENTER
);
81 add(createToolbar(), BorderLayout
.WEST
);
82 final DefaultTableModel model
= new DefaultTableModel(createTableModel(new HashMap
<String
, String
>()), new Object
[]{"Name", "Value"}) {
83 public boolean isCellEditable(final int row
, final int column
) {
87 myTable
.setModel(model
);
88 myTable
.setShowVerticalLines(true);
89 myTable
.setSelectionMode(ListSelectionModel
.SINGLE_SELECTION
);
90 myTable
.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
91 public void valueChanged(ListSelectionEvent e
) {
92 int index
= myTable
.getSelectedRow();
94 Object value
= myTable
.getValueAt(index
, 1);
95 if (value
instanceof String
) {
96 myTextArea
.setText(((String
) value
));
98 myTextArea
.setText("");
101 myTextArea
.setText("");
105 myPopupActionGroup
= createPopup();
106 PopupHandler
.installPopupHandler(myTable
, myPopupActionGroup
, ActionPlaces
.UNKNOWN
, ActionManager
.getInstance());
107 PopupHandler
.installPopupHandler(scrollPane
, myPopupActionGroup
, ActionPlaces
.UNKNOWN
, ActionManager
.getInstance());
108 final Shortcut
[] shortcuts
= KeymapManager
.getInstance().getActiveKeymap().getShortcuts(IdeActions
.ACTION_CLOSE_ACTIVE_TAB
);
109 myCloseAction
.registerCustomShortcutSet(new CustomShortcutSet(shortcuts
), this);
110 myRefreshAction
.registerCustomShortcutSet(CommonShortcuts
.getRerun(), this);
113 public void setFile(SvnVcs vcs
, File file
) {
114 final Map
<String
, String
> props
= new TreeMap
<String
, String
>();
115 boolean firstTime
= myFile
== null;
120 vcs
.createWCClient().doGetProperty(file
, null, SVNRevision
.UNDEFINED
, SVNRevision
.WORKING
, false, new ISVNPropertyHandler() {
121 public void handleProperty(File path
, SVNPropertyData property
) throws SVNException
{
122 final SVNPropertyValue value
= property
.getValue();
124 props
.put(property
.getName(), value
.getString());
127 public void handleProperty(SVNURL url
, SVNPropertyData property
) throws SVNException
{
129 public void handleProperty(long revision
, SVNPropertyData property
) throws SVNException
{
132 } catch (SVNException e
) {
136 DefaultTableModel model
= (DefaultTableModel
) myTable
.getModel();
137 model
.setDataVector(createTableModel(props
), new Object
[] {"Name", "Value"});
139 myTable
.getColumnModel().setColumnSelectionAllowed(false);
140 myTable
.getColumnModel().getColumn(1).setCellRenderer(new DefaultTableCellRenderer() {
141 protected void setValue(Object value
) {
143 if (value
.toString().indexOf('\r') >= 0) {
144 value
= value
.toString().substring(0, value
.toString().indexOf('\r')) + " [...]";
146 if (value
.toString().indexOf('\n') >= 0) {
147 value
= value
.toString().substring(0, value
.toString().indexOf('\n')) + " [...]";
150 super.setValue(value
);
154 mySplitPane
.setDividerLocation(.5);
156 if (myTable
.getRowCount() > 0) {
157 myTable
.getSelectionModel().setSelectionInterval(0, 0);
161 private static Object
[][] createTableModel(Map
<String
, String
> model
) {
162 Object
[][] result
= new Object
[model
.size()][2];
164 for (final String name
: model
.keySet()) {
165 String value
= model
.get(name
);
169 result
[index
][0] = name
;
170 result
[index
][1] = value
;
176 private JComponent
createToolbar() {
177 DefaultActionGroup group
= new DefaultActionGroup();
178 group
.add(new AddPropertyAction());
179 group
.add(new EditPropertyAction());
180 group
.add(new DeletePropertyAction());
181 group
.addSeparator();
182 group
.add(new SetKeywordsAction());
183 group
.addSeparator();
184 group
.add(new FollowSelectionAction());
185 group
.add(myRefreshAction
);
186 group
.add(myCloseAction
);
187 return ActionManager
.getInstance().createActionToolbar("", group
, false).getComponent();
190 private DefaultActionGroup
createPopup() {
191 DefaultActionGroup group
= new DefaultActionGroup();
192 group
.add(new AddPropertyAction());
193 group
.add(new EditPropertyAction());
194 group
.add(new DeletePropertyAction());
195 group
.addSeparator();
196 group
.add(new SetKeywordsAction());
197 group
.addSeparator();
198 group
.add(myRefreshAction
);
202 private String
getSelectedPropertyName() {
203 int row
= myTable
.getSelectedRow();
207 return (String
) myTable
.getValueAt(row
, 0);
210 private void updateFileStatus(boolean recursive
) {
211 if (myFile
!= null && myVcs
!= null) {
212 String url
= "file://" + myFile
.getPath().replace(File
.separatorChar
, '/');
213 VirtualFile file
= VirtualFileManager
.getInstance().findFileByUrl(url
);
215 if (recursive
&& file
.isDirectory()) {
216 VcsDirtyScopeManager
.getInstance(myVcs
.getProject()).dirDirtyRecursively(file
, true);
218 VcsDirtyScopeManager
.getInstance(myVcs
.getProject()).fileDirty(file
);
224 private static class CloseAction
extends AnAction
{
226 public void update(AnActionEvent e
) {
227 e
.getPresentation().setText("Close");
228 e
.getPresentation().setDescription("Close this tool window");
229 e
.getPresentation().setIcon(IconLoader
.getIcon("/actions/cancel.png"));
232 public void actionPerformed(AnActionEvent e
) {
233 Project p
= e
.getData(PlatformDataKeys
.PROJECT
);
234 ToolWindowManager
.getInstance(p
).unregisterToolWindow(ID
);
238 private class RefreshAction
extends AnAction
{
239 public void update(AnActionEvent e
) {
240 e
.getPresentation().setText("Refresh");
241 e
.getPresentation().setDescription("Reload properties");
242 e
.getPresentation().setIcon(IconLoader
.getIcon("/actions/sync.png"));
243 e
.getPresentation().setEnabled(myFile
!= null);
246 public void actionPerformed(AnActionEvent e
) {
247 setFile(myVcs
, myFile
);
248 updateFileStatus(false);
252 private class SetKeywordsAction
extends AnAction
{
254 public void update(AnActionEvent e
) {
255 e
.getPresentation().setText("Edit Keywords");
256 e
.getPresentation().setDescription("Manage svn:keywords property");
257 if (!CONTEXT_ID
.equals(e
.getPlace())) {
258 e
.getPresentation().setIcon(IconLoader
.getIcon("/actions/properties.png"));
260 e
.getPresentation().setEnabled(myFile
!= null && myFile
.isFile());
263 public void actionPerformed(AnActionEvent e
) {
264 Project project
= PlatformDataKeys
.PROJECT
.getData(e
.getDataContext());
265 SVNWCClient wcClient
= myVcs
.createWCClient();
266 SVNPropertyData propValue
= null;
268 propValue
= wcClient
.doGetProperty(myFile
, SVNProperty
.KEYWORDS
, SVNRevision
.UNDEFINED
, SVNRevision
.WORKING
);
269 } catch (SVNException e1
) {
270 // show error message
273 SetKeywordsDialog dialog
= new SetKeywordsDialog(project
,
274 propValue
!= null ? SVNPropertyValue
.getPropertyAsString(propValue
.getValue()) : null);
277 String value
= dialog
.getKeywords();
279 wcClient
.doSetProperty(myFile
, SVNProperty
.KEYWORDS
, SVNPropertyValue
.create(value
), false, false, null);
281 catch (SVNException err
) {
282 // show error message
285 setFile(myVcs
, myFile
);
286 updateFileStatus(false);
290 private class DeletePropertyAction
extends AnAction
{
291 public void update(AnActionEvent e
) {
292 e
.getPresentation().setText("Delete Property");
293 e
.getPresentation().setDescription("Delete selected property");
294 if (!CONTEXT_ID
.equals(e
.getPlace())) {
295 e
.getPresentation().setIcon(IconLoader
.getIcon("/general/remove.png"));
297 e
.getPresentation().setEnabled(myFile
!= null && getSelectedPropertyName() != null);
300 public void actionPerformed(AnActionEvent e
) {
302 myVcs
.createWCClient().doSetProperty(myFile
, getSelectedPropertyName(), null, true, false, null);
303 } catch (SVNException error
) {
304 // show error message.
306 setFile(myVcs
, myFile
);
307 updateFileStatus(false);
311 private class AddPropertyAction
extends AnAction
{
313 public void update(AnActionEvent e
) {
314 e
.getPresentation().setText("Add Property");
315 e
.getPresentation().setDescription("Add new property");
316 if (!CONTEXT_ID
.equals(e
.getPlace())) {
317 e
.getPresentation().setIcon(IconLoader
.getIcon("/general/add.png"));
319 e
.getPresentation().setEnabled(myFile
!= null);
322 public void actionPerformed(AnActionEvent e
) {
323 Project project
= PlatformDataKeys
.PROJECT
.getData(e
.getDataContext());
324 SetPropertyDialog dialog
= new SetPropertyDialog(project
, new File
[] {myFile
}, null,
325 myFile
.isDirectory());
327 boolean recursive
= false;
329 String name
= dialog
.getPropertyName();
330 String value
= dialog
.getPropertyValue();
331 recursive
= dialog
.isRecursive();
332 SVNWCClient wcClient
= myVcs
.createWCClient();
334 wcClient
.doSetProperty(myFile
, name
, SVNPropertyValue
.create(value
), false, recursive
, null);
336 catch (SVNException err
) {
337 // show error message
340 setFile(myVcs
, myFile
);
341 updateFileStatus(recursive
);
345 private class EditPropertyAction
extends AnAction
{
346 public void update(AnActionEvent e
) {
347 e
.getPresentation().setText("Edit Property");
348 e
.getPresentation().setDescription("Edit selected property value");
349 if (!CONTEXT_ID
.equals(e
.getPlace())) {
350 e
.getPresentation().setIcon(IconLoader
.getIcon("/actions/editSource.png"));
352 e
.getPresentation().setEnabled(myFile
!= null && getSelectedPropertyName() != null);
355 public void actionPerformed(AnActionEvent e
) {
356 Project project
= PlatformDataKeys
.PROJECT
.getData(e
.getDataContext());
357 SetPropertyDialog dialog
= new SetPropertyDialog(project
, new File
[] {myFile
}, getSelectedPropertyName(), myFile
.isDirectory());
359 boolean recursive
= false;
361 String name
= dialog
.getPropertyName();
362 String value
= dialog
.getPropertyValue();
363 recursive
= dialog
.isRecursive();
364 SVNWCClient wcClient
= myVcs
.createWCClient();
366 wcClient
.doSetProperty(myFile
, name
, SVNPropertyValue
.create(value
), false, recursive
, null);
368 catch (SVNException err
) {
369 // show error message
372 setFile(myVcs
, myFile
);
373 updateFileStatus(recursive
);
377 private class FollowSelectionAction
extends ToggleAction
{
379 public boolean isSelected(AnActionEvent e
) {
380 return myIsFollowSelection
;
382 public void setSelected(AnActionEvent e
, boolean state
) {
383 if (state
&& !myIsFollowSelection
) {
386 myIsFollowSelection
= state
;
389 public void update(final AnActionEvent e
) {
391 e
.getPresentation().setIcon(IconLoader
.getIcon("/general/autoscrollFromSource.png"));
392 e
.getPresentation().setText("Follow Selection");
393 e
.getPresentation().setDescription("Follow Selection");
395 if (myIsFollowSelection
) {
400 private void updateSelection(AnActionEvent e
) {
404 VirtualFile vf
= PlatformDataKeys
.VIRTUAL_FILE
.getData(e
.getDataContext());
406 File f
= new File(vf
.getPath());
407 if (!f
.equals(myFile
)) {
409 Project p
= PlatformDataKeys
.PROJECT
.getData(e
.getDataContext());
410 ToolWindowManager
.getInstance(p
).getToolWindow(ID
).setTitle(f
.getName());