1 19 20 package org.netbeans.modules.web.project.ui.customizer; 21 22 import java.awt.*; 23 import java.awt.event.ActionEvent ; 24 import java.awt.event.ActionListener ; 25 import java.io.File ; 26 import java.net.URI ; 27 import java.net.URL ; 28 import java.util.Iterator ; 29 import java.util.HashSet ; 30 import java.util.Set ; 31 import java.util.Vector ; 32 import java.text.MessageFormat ; 33 import javax.swing.*; 34 import javax.swing.event.ListSelectionEvent ; 35 import javax.swing.event.ListSelectionListener ; 36 import javax.swing.event.CellEditorListener ; 37 import javax.swing.event.ChangeEvent ; 38 import javax.swing.table.DefaultTableCellRenderer ; 39 import javax.swing.table.DefaultTableModel ; 40 import org.netbeans.api.project.ProjectUtils; 41 import org.netbeans.modules.web.project.WebProject; 42 import org.netbeans.api.project.FileOwnerQuery; 43 import org.netbeans.api.project.Project; 44 import org.netbeans.api.project.ProjectInformation; 45 import org.netbeans.modules.web.project.SourceRoots; 46 import org.openide.DialogDisplayer; 47 import org.openide.DialogDescriptor; 48 import org.openide.filesystems.FileUtil; 49 import org.openide.util.NbBundle; 50 51 52 56 public final class WebSourceRootsUi { 57 58 public static DefaultTableModel createModel( SourceRoots roots ) { 59 60 String [] rootLabels = roots.getRootNames(); 61 String [] rootProps = roots.getRootProperties(); 62 URL [] rootURLs = roots.getRootURLs(); 63 Object [][] data = new Object [rootURLs.length] [2]; 64 for (int i=0; i< rootURLs.length; i++) { 65 data[i][0] = new File (URI.create (rootURLs[i].toExternalForm())); 66 data[i][1] = roots.getRootDisplayName(rootLabels[i], rootProps[i]); 67 } 68 return new SourceRootsModel(data); 69 70 } 71 72 public static EditMediator registerEditMediator( WebProject master, 73 SourceRoots sourceRoots, 74 JTable rootsList, 75 JButton addFolderButton, 76 JButton removeButton, 77 JButton upButton, 78 JButton downButton) { 79 80 EditMediator em = new EditMediator( master, 81 sourceRoots, 82 rootsList, 83 addFolderButton, 84 removeButton, 85 upButton, 86 downButton); 87 88 addFolderButton.addActionListener( em ); 91 removeButton.addActionListener( em ); 92 upButton.addActionListener( em ); 93 downButton.addActionListener( em ); 94 rootsList.getSelectionModel().addListSelectionListener( em ); 96 DefaultCellEditor editor = new DefaultCellEditor(new JTextField()); 97 editor.addCellEditorListener (em); 98 rootsList.setDefaultRenderer( File .class, new FileRenderer (FileUtil.toFile(master.getProjectDirectory()))); 99 rootsList.setDefaultEditor(String .class, editor); 100 em.valueChanged( null ); 102 103 DefaultTableModel model = (DefaultTableModel )rootsList.getModel(); 104 String [] columnNames = new String [2]; 105 columnNames[0] = NbBundle.getMessage( WebSourceRootsUi.class,"CTL_PackageFolders"); columnNames[1] = NbBundle.getMessage( WebSourceRootsUi.class,"CTL_PackageLabels"); model.setColumnIdentifiers(columnNames); 108 rootsList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); 109 110 return em; 111 } 112 113 117 public static void showIllegalRootsDialog (Set roots) { 118 JButton closeOption = new JButton (NbBundle.getMessage(WebSourceRootsUi.class,"CTL_WebSourceRootsUi_Close")); 119 closeOption.getAccessibleContext ().setAccessibleDescription (NbBundle.getMessage(WebSourceRootsUi.class,"AD_WebSourceRootsUi_Close")); 120 JPanel warning = new WarningDlg (roots); 121 String message = NbBundle.getMessage(WebSourceRootsUi.class,"MSG_InvalidRoot"); 122 JOptionPane optionPane = new JOptionPane (new Object [] {message, warning}, 123 JOptionPane.WARNING_MESSAGE, 124 0, 125 null, 126 new Object [0], 127 null); 128 optionPane.getAccessibleContext().setAccessibleDescription (NbBundle.getMessage(WebSourceRootsUi.class,"AD_InvalidRootDlg")); 129 DialogDescriptor dd = new DialogDescriptor (optionPane, 130 NbBundle.getMessage(WebSourceRootsUi.class,"TITLE_InvalidRoot"), 131 true, 132 new Object [] { 133 closeOption, 134 }, 135 closeOption, 136 DialogDescriptor.DEFAULT_ALIGN, 137 null, 138 null); 139 DialogDisplayer.getDefault().notify(dd); 140 } 141 142 144 public static class EditMediator implements ActionListener , ListSelectionListener , CellEditorListener { 145 146 147 final JTable rootsList; 148 final JButton addFolderButton; 149 final JButton removeButton; 150 final JButton upButton; 151 final JButton downButton; 152 private final Project project; 153 private final SourceRoots sourceRoots; 154 private final Set ownedFolders; 155 private DefaultTableModel rootsModel; 156 private EditMediator relatedEditMediator; 157 private File lastUsedDir; 159 public EditMediator( WebProject master, 160 SourceRoots sourceRoots, 161 JTable rootsList, 162 JButton addFolderButton, 163 JButton removeButton, 164 JButton upButton, 165 JButton downButton) { 166 167 if ( !( rootsList.getModel() instanceof DefaultTableModel ) ) { 168 throw new IllegalArgumentException ( "Jtable's model has to be of class DefaultTableModel" ); } 170 171 this.rootsList = rootsList; 172 this.addFolderButton = addFolderButton; 173 this.removeButton = removeButton; 174 this.upButton = upButton; 175 this.downButton = downButton; 176 this.ownedFolders = new HashSet (); 177 178 this.project = master; 179 this.sourceRoots = sourceRoots; 180 181 this.ownedFolders.clear(); 182 this.rootsModel = (DefaultTableModel )rootsList.getModel(); 183 Vector data = rootsModel.getDataVector(); 184 for (Iterator it = data.iterator(); it.hasNext();) { 185 Vector row = (Vector ) it.next (); 186 File f = (File ) row.elementAt(0); 187 this.ownedFolders.add (f); 188 } 189 } 190 191 public void setRelatedEditMediator(EditMediator rem) { 192 this.relatedEditMediator = rem; 193 } 194 195 197 199 public void actionPerformed( ActionEvent e ) { 200 201 Object source = e.getSource(); 202 203 if ( source == addFolderButton ) { 204 JFileChooser chooser = new JFileChooser(); 206 FileUtil.preventFileChooserSymlinkTraversal(chooser, null); 207 chooser.setFileSelectionMode( JFileChooser.DIRECTORIES_ONLY ); 208 chooser.setMultiSelectionEnabled( true ); 209 210 if (sourceRoots.isTest()) 211 chooser.setDialogTitle( NbBundle.getMessage( WebSourceRootsUi.class, "LBL_TestFolder_DialogTitle" )); else 213 chooser.setDialogTitle( NbBundle.getMessage( WebSourceRootsUi.class, "LBL_SourceFolder_DialogTitle" )); 215 File curDir = this.lastUsedDir; 216 if (curDir == null) { 217 curDir = FileUtil.toFile(this.project.getProjectDirectory()); 218 } 219 if (curDir != null) { 220 chooser.setCurrentDirectory (curDir); 221 } 222 int option = chooser.showOpenDialog( SwingUtilities.getWindowAncestor( addFolderButton ) ); 224 if ( option == JFileChooser.APPROVE_OPTION ) { 225 curDir = chooser.getCurrentDirectory(); 226 if (curDir != null) { 227 this.lastUsedDir = curDir; 228 if (this.relatedEditMediator != null) { 229 this.relatedEditMediator.lastUsedDir = curDir; 230 } 231 } 232 File files[] = chooser.getSelectedFiles(); 233 addFolders( files ); 234 } 235 236 } 237 else if ( source == removeButton ) { 238 removeElements(); 239 } 240 else if ( source == upButton ) { 241 moveUp(); 242 } 243 else if ( source == downButton ) { 244 moveDown(); 245 } 246 } 247 248 250 252 public void valueChanged( ListSelectionEvent e ) { 253 254 int[] si = rootsList.getSelectedRows(); 255 256 258 260 262 boolean remove = si != null && si.length > 0; 264 266 boolean up = si != null && si.length > 0 && si[0] != 0; 269 270 boolean down = si != null && si.length > 0 && si[si.length-1] !=rootsList.getRowCount() - 1; 273 274 removeButton.setEnabled( remove ); 275 upButton.setEnabled( up ); 276 downButton.setEnabled( down ); 277 } 278 279 public void editingCanceled(ChangeEvent e) { 280 281 } 282 283 public void editingStopped(ChangeEvent e) { 284 } 286 287 private void addFolders( File files[] ) { 288 int[] si = rootsList.getSelectedRows(); 289 int lastIndex = si == null || si.length == 0 ? -1 : si[si.length - 1]; 290 ListSelectionModel selectionModel = this.rootsList.getSelectionModel(); 291 selectionModel.clearSelection(); 292 Set rootsFromOtherProjects = new HashSet (); 293 Set rootsFromRelatedSourceRoots = new HashSet (); 294 for( int i = 0; i < files.length; i++ ) { 295 File normalizedFile = FileUtil.normalizeFile(files[i]); 296 Project p; 297 if (ownedFolders.contains(normalizedFile)) { 298 Vector dataVector = rootsModel.getDataVector(); 299 for (int j=0; j<dataVector.size();j++) { 300 File f = (File )((Vector )dataVector.elementAt(j)).elementAt(0); 302 if (f.equals(normalizedFile)) { 303 selectionModel.addSelectionInterval(j,j); 304 } 305 } 306 } 307 else if (this.relatedEditMediator != null && this.relatedEditMediator.ownedFolders.contains(normalizedFile)) { 308 rootsFromRelatedSourceRoots.add (normalizedFile); 309 } 310 else if ((p=FileOwnerQuery.getOwner(normalizedFile.toURI()))!=null && !p.getProjectDirectory().equals(project.getProjectDirectory())) { 311 rootsFromOtherProjects.add (normalizedFile); 312 } 313 else { 314 int current = lastIndex + 1 + i; 315 rootsModel.insertRow( current, new Object [] {normalizedFile, sourceRoots.createInitialDisplayName(normalizedFile)}); selectionModel.addSelectionInterval(current,current); 317 this.ownedFolders.add (normalizedFile); 318 } 319 } 320 if (rootsFromOtherProjects.size() > 0 || rootsFromRelatedSourceRoots.size() > 0) { 321 rootsFromOtherProjects.addAll(rootsFromRelatedSourceRoots); 322 showIllegalRootsDialog (rootsFromOtherProjects); 323 } 324 } 326 327 private void removeElements() { 328 329 int[] si = rootsList.getSelectedRows(); 330 331 if( si == null || si.length == 0 ) { 332 assert false : "Remove button should be disabled"; } 334 335 for( int i = si.length - 1 ; i >= 0 ; i-- ) { 337 this.ownedFolders.remove(((Vector )rootsModel.getDataVector().elementAt(0)).elementAt(0)); 338 rootsModel.removeRow( si[i] ); 339 } 340 341 342 if ( rootsModel.getRowCount() != 0) { 343 int selectedIndex = si[si.length - 1] - si.length + 1; 345 if ( selectedIndex > rootsModel.getRowCount() - 1) { 346 selectedIndex = rootsModel.getRowCount() - 1; 347 } 348 rootsList.setRowSelectionInterval( selectedIndex, selectedIndex ); 349 } 350 351 353 } 354 355 private void moveUp() { 356 357 int[] si = rootsList.getSelectedRows(); 358 359 if( si == null || si.length == 0 ) { 360 assert false : "MoveUp button should be disabled"; } 362 363 ListSelectionModel selectionModel = this.rootsList.getSelectionModel(); 365 selectionModel.clearSelection(); 366 for( int i = 0; i < si.length; i++ ) { 367 Vector item = (Vector ) rootsModel.getDataVector().elementAt(si[i]); 368 int newIndex = si[i]-1; 369 rootsModel.removeRow( si[i] ); 370 rootsModel.insertRow( newIndex, item ); 371 selectionModel.addSelectionInterval(newIndex,newIndex); 372 } 373 } 375 376 private void moveDown() { 377 378 int[] si = rootsList.getSelectedRows(); 379 380 if( si == null || si.length == 0 ) { 381 assert false : "MoveDown button should be disabled"; } 383 384 ListSelectionModel selectionModel = this.rootsList.getSelectionModel(); 386 selectionModel.clearSelection(); 387 for( int i = si.length -1 ; i >= 0 ; i-- ) { 388 Vector item = (Vector ) rootsModel.getDataVector().elementAt(si[i]); 389 int newIndex = si[i] + 1; 390 rootsModel.removeRow( si[i] ); 391 rootsModel.insertRow( newIndex, item ); 392 selectionModel.addSelectionInterval(newIndex,newIndex); 393 } 394 } 396 397 398 } 399 400 private static class SourceRootsModel extends DefaultTableModel { 401 402 public SourceRootsModel (Object [][] data) { 403 super (data,new Object []{"location","label"}); } 405 406 public boolean isCellEditable(int row, int column) { 407 return column == 1; 408 } 409 410 public Class getColumnClass(int columnIndex) { 411 switch (columnIndex) { 412 case 0: 413 return File .class; 414 case 1: 415 return String .class; 416 default: 417 return super.getColumnClass (columnIndex); 418 } 419 } 420 } 421 422 private static class FileRenderer extends DefaultTableCellRenderer { 423 424 private File projectFolder; 425 426 public FileRenderer (File projectFolder) { 427 this.projectFolder = projectFolder; 428 } 429 430 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,int row, int column) { 431 String displayName; 432 if (value instanceof File ) { 433 File root = (File ) value; 434 String pfPath = projectFolder.getAbsolutePath() + File.separatorChar; 435 String srPath = root.getAbsolutePath(); 436 if (srPath.startsWith(pfPath)) { 437 displayName = srPath.substring(pfPath.length()); 438 } 439 else { 440 displayName = srPath; 441 } 442 } 443 else { 444 displayName = null; 445 } 446 Component c = super.getTableCellRendererComponent(table, displayName, isSelected, hasFocus, row, column); 447 if (c instanceof JComponent) { 448 ((JComponent) c).setToolTipText (displayName); 449 } 450 return c; 451 } 452 } 453 454 private static class WarningDlg extends JPanel { 455 456 public WarningDlg (Set invalidRoots) { 457 this.initGui (invalidRoots); 458 } 459 460 private void initGui (Set invalidRoots) { 461 setLayout( new GridBagLayout ()); 462 JLabel label = new JLabel (); 463 label.setText (NbBundle.getMessage(WebSourceRootsUi.class,"LBL_InvalidRoot")); label.setDisplayedMnemonic(NbBundle.getMessage(WebSourceRootsUi.class,"MNE_InvalidRoot").charAt(0)); GridBagConstraints c = new GridBagConstraints(); 466 c.gridx = GridBagConstraints.RELATIVE; 467 c.gridy = GridBagConstraints.RELATIVE; 468 c.gridwidth = GridBagConstraints.REMAINDER; 469 c.fill = GridBagConstraints.HORIZONTAL; 470 c.anchor = GridBagConstraints.NORTHWEST; 471 c.weightx = 1.0; 472 c.insets = new Insets (12,0,6,0); 473 ((GridBagLayout)this.getLayout()).setConstraints(label,c); 474 this.add (label); 475 JList roots = new JList (invalidRoots.toArray()); 476 roots.setCellRenderer (new InvalidRootRenderer(true)); 477 JScrollPane p = new JScrollPane (roots); 478 c = new GridBagConstraints(); 479 c.gridx = GridBagConstraints.RELATIVE; 480 c.gridy = GridBagConstraints.RELATIVE; 481 c.gridwidth = GridBagConstraints.REMAINDER; 482 c.fill = GridBagConstraints.BOTH; 483 c.anchor = GridBagConstraints.NORTHWEST; 484 c.weightx = c.weighty = 1.0; 485 c.insets = new Insets (0,0,12,0); 486 ((GridBagLayout)this.getLayout()).setConstraints(p,c); 487 this.add (p); 488 label.setLabelFor(roots); 489 roots.getAccessibleContext().setAccessibleDescription (NbBundle.getMessage(WebSourceRootsUi.class,"AD_InvalidRoot")); JLabel label2 = new JLabel (); 491 label2.setText (NbBundle.getMessage(WebSourceRootsUi.class,"MSG_InvalidRoot2")); c = new GridBagConstraints(); 493 c.gridx = GridBagConstraints.RELATIVE; 494 c.gridy = GridBagConstraints.RELATIVE; 495 c.gridwidth = GridBagConstraints.REMAINDER; 496 c.fill = GridBagConstraints.HORIZONTAL; 497 c.anchor = GridBagConstraints.NORTHWEST; 498 c.weightx = 1.0; 499 c.insets = new Insets (0,0,0,0); 500 ((GridBagLayout)this.getLayout()).setConstraints(label2,c); 501 this.add (label2); 502 } 503 504 private static class InvalidRootRenderer extends DefaultListCellRenderer { 505 506 private boolean projectConflict; 507 508 public InvalidRootRenderer (boolean projectConflict) { 509 this.projectConflict = projectConflict; 510 } 511 512 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { 513 File f = (File ) value; 514 String message = f.getAbsolutePath(); 515 if (projectConflict) { 516 Project p = FileOwnerQuery.getOwner(f.toURI()); 517 if (p!=null) { 518 ProjectInformation pi = ProjectUtils.getInformation(p); 519 String projectName = pi.getDisplayName(); 520 message = MessageFormat.format (NbBundle.getMessage(WebSourceRootsUi.class,"TXT_RootOwnedByProject"), new Object [] { message, 522 projectName}); 523 } 524 } 525 return super.getListCellRendererComponent(list, message, index, isSelected, cellHasFocus); 526 } 527 } 528 } 529 } 530 | Popular Tags |