1 /* 2 * Copyright (c) 2016 Martin Davis. 3 * 4 * All rights reserved. This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * and Eclipse Distribution License v. 1.0 which accompanies this distribution. 7 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v20.html 8 * and the Eclipse Distribution License is available at 9 * 10 * http://www.eclipse.org/org/documents/edl-v10.php. 11 */ 12 package org.locationtech.jtstest.testbuilder; 13 14 import java.awt.BorderLayout; 15 import java.awt.Color; 16 import java.awt.Component; 17 import java.awt.Dimension; 18 import java.awt.Font; 19 import java.awt.Graphics2D; 20 import java.awt.event.ActionEvent; 21 import java.awt.event.ActionListener; 22 import java.awt.event.MouseAdapter; 23 import java.awt.event.MouseEvent; 24 import java.util.ArrayList; 25 import java.util.List; 26 27 import javax.swing.BorderFactory; 28 import javax.swing.Box; 29 import javax.swing.BoxLayout; 30 import javax.swing.JButton; 31 import javax.swing.JCheckBox; 32 import javax.swing.JLabel; 33 import javax.swing.JPanel; 34 import javax.swing.JScrollPane; 35 import javax.swing.JTabbedPane; 36 import javax.swing.border.Border; 37 38 import org.locationtech.jts.geom.Geometry; 39 import org.locationtech.jtstest.testbuilder.model.Layer; 40 import org.locationtech.jtstest.testbuilder.model.LayerList; 41 import org.locationtech.jtstest.testbuilder.model.StaticGeometryContainer; 42 import org.locationtech.jtstest.testbuilder.ui.ColorUtil; 43 import org.locationtech.jtstest.testbuilder.ui.SwingUtil; 44 45 /** 46 * @version 1.7 47 */ 48 public class LayerListPanel extends JPanel { 49 50 private static final int TAB_INDEX_LAYER = 0; 51 52 private static final String LBL_LAYER = "Style"; 53 private static final String LBL_VIEW = "View"; 54 55 JPanel listPanel = new JPanel(); 56 Box buttonPanel = Box.createVerticalBox(); 57 JTabbedPane tabPane = new JTabbedPane(); 58 private LayerStylePanel lyrStylePanel; 59 List<LayerItemPanel> layerItems = new ArrayList<LayerItemPanel>(); 60 61 private JButton btnCopy; 62 63 private JButton btnUp; 64 65 private JButton btnDown; 66 67 private JButton btnDelete; 68 69 private JButton btnPaste; 70 71 private Layer focusLayer; 72 LayerListPanel()73 public LayerListPanel() { 74 try { 75 uiInit(); 76 } catch (Exception ex) { 77 ex.printStackTrace(); 78 } 79 } 80 uiInit()81 private void uiInit() throws Exception { 82 //setSize(300, 250); 83 setBackground(AppColors.BACKGROUND); 84 setLayout(new BorderLayout()); 85 86 JPanel panelLeft = new JPanel(); 87 panelLeft.setLayout(new BorderLayout()); 88 89 listPanel.setLayout(new BoxLayout(listPanel, BoxLayout.Y_AXIS)); 90 listPanel.setBackground(AppColors.BACKGROUND); 91 listPanel.setBorder(BorderFactory.createEmptyBorder(2,2,2,0)); 92 93 JScrollPane jScrollPane1 = new JScrollPane(); 94 jScrollPane1.setBackground(AppColors.BACKGROUND); 95 jScrollPane1.setOpaque(true); 96 jScrollPane1.getViewport().add(listPanel, null); 97 jScrollPane1.setPreferredSize(new Dimension(150, 250)); 98 99 panelLeft.add(jScrollPane1, BorderLayout.CENTER); 100 panelLeft.add(buttonPanel, BorderLayout.EAST); 101 102 btnCopy = SwingUtil.createButton(AppIcons.ADD, 103 "Copy layer to a new layer", 104 new ActionListener() { 105 public void actionPerformed(ActionEvent e) { 106 layerCopy(); 107 } 108 }); 109 buttonPanel.add(btnCopy); 110 111 btnPaste = SwingUtil.createButton(AppIcons.PASTE, 112 "Paste geometry into layer", 113 new ActionListener() { 114 public void actionPerformed(ActionEvent e) { 115 layerPaste(focusLayer); 116 } 117 }); 118 buttonPanel.add(btnPaste); 119 btnUp = SwingUtil.createButton(AppIcons.UP, 120 "Move layer up", 121 new ActionListener() { 122 public void actionPerformed(ActionEvent e) { 123 layerUp(focusLayer); 124 } 125 }); 126 buttonPanel.add(btnUp); 127 btnDown = SwingUtil.createButton(AppIcons.DOWN, 128 "Move layer down", 129 new ActionListener() { 130 public void actionPerformed(ActionEvent e) { 131 layerDown(focusLayer); 132 } 133 }); 134 buttonPanel.add(btnDown); 135 136 btnDelete = SwingUtil.createButton(AppIcons.DELETE, 137 AppStrings.TIP_LAYER_CLEAR, 138 new ActionListener() { 139 public void actionPerformed(ActionEvent e) { 140 if (SwingUtil.isCtlKeyPressed(e)) { 141 layerDelete(focusLayer); 142 } 143 else { 144 layerClear(focusLayer); 145 } 146 } 147 }); 148 buttonPanel.add(btnDelete); 149 150 add(panelLeft, BorderLayout.WEST); 151 152 lyrStylePanel = new LayerStylePanel(); 153 GeometryViewStylePanel viewStylePanel = new GeometryViewStylePanel(); 154 //add(lyrStylePanel, BorderLayout.CENTER); 155 156 //tabFunctions.setBackground(jTabbedPane1.getBackground()); 157 JScrollPane scrollPane = new JScrollPane(); 158 scrollPane.getViewport().add(lyrStylePanel, null); 159 tabPane.add(scrollPane, LBL_LAYER); 160 tabPane.add(viewStylePanel, LBL_VIEW); 161 add(tabPane, BorderLayout.CENTER); 162 } 163 findLayerItem(Layer lyr)164 protected LayerItemPanel findLayerItem(Layer lyr) { 165 for (LayerItemPanel lip : layerItems) { 166 if (lip.getLayer() == lyr) return lip; 167 } 168 return null; 169 } 170 showTabLayerStyle(String title)171 public void showTabLayerStyle(String title) { 172 tabPane.setSelectedIndex(TAB_INDEX_LAYER); 173 //tabPane.setTitleAt(0, LBL_LAYER + " - " + title); 174 //SwingUtil.showTab(tabPane, LBL_LAYER_STYLE); 175 } 176 populateList()177 public void populateList() { 178 listPanel.removeAll(); 179 layerItems.clear(); 180 181 addLayers(JTSTestBuilder.model().getLayersTop()); 182 addLayers(JTSTestBuilder.model().getLayers()); 183 addLayers(JTSTestBuilder.model().getLayersBase()); 184 setLayerFocus(layerItems.get(0)); 185 } 186 updateList()187 public void updateList() { 188 for (LayerItemPanel layerItemPanel : layerItems) { 189 layerItemPanel.update(); 190 } 191 } 192 addLayers(LayerList lyrList)193 private void addLayers(LayerList lyrList) { 194 for (int i = 0; i < lyrList.size(); i++) { 195 Layer lyr = lyrList.getLayer(i); 196 LayerItemPanel item = new LayerItemPanel(lyr, this); 197 listPanel.add(item); 198 layerItems.add(item); 199 } 200 } 201 setLayerFocus(LayerItemPanel layerItem)202 public void setLayerFocus(LayerItemPanel layerItem) { 203 for (LayerItemPanel item : layerItems) { 204 item.setFocusLayer(false); 205 } 206 layerItem.setFocusLayer(true); 207 Layer layer = layerItem.getLayer(); 208 boolean isModifiable = ! JTSTestBuilder.model().isLayerFixed(layer); 209 showTabLayerStyle(layer.getName()); 210 lyrStylePanel.setLayer(layer, isModifiable); 211 focusLayer = layer; 212 updateButtons(focusLayer); 213 } 214 updateButtons(Layer lyr)215 private void updateButtons(Layer lyr) { 216 boolean isModifiable = ! JTSTestBuilder.model().isLayerFixed(lyr); 217 218 // every layer is copyable 219 btnCopy.setEnabled(true); 220 btnPaste.setEnabled(isModifiable && ! lyr.hasGeometry()); 221 btnUp.setEnabled(isModifiable); 222 btnDown.setEnabled(isModifiable); 223 btnDelete.setEnabled(isModifiable); 224 } 225 layerCopy()226 private void layerCopy() { 227 Layer copy = JTSTestBuilder.model().layerCopy(focusLayer); 228 populateList(); 229 setLayerFocus(findLayerItem(copy)); 230 JTSTestBuilder.controller().geometryViewChanged(); 231 } 232 layerDelete(Layer lyr)233 private void layerDelete(Layer lyr) { 234 // don't remove if non-empty 235 if (lyr.hasGeometry()) return; 236 237 JTSTestBuilder.model().layerDelete(lyr); 238 populateList(); 239 JTSTestBuilder.controller().geometryViewChanged(); 240 } 241 layerUp(Layer lyr)242 private void layerUp(Layer lyr) { 243 JTSTestBuilder.model().layerUp(lyr); 244 populateList(); 245 setLayerFocus(findLayerItem(lyr)); 246 JTSTestBuilder.controller().geometryViewChanged(); 247 } 248 layerDown(Layer lyr)249 private void layerDown(Layer lyr) { 250 JTSTestBuilder.model().layerDown(lyr); 251 populateList(); 252 setLayerFocus(findLayerItem(lyr)); 253 JTSTestBuilder.controller().geometryViewChanged(); 254 } 255 layerClear(Layer lyr)256 private void layerClear(Layer lyr) { 257 StaticGeometryContainer src = (StaticGeometryContainer) lyr.getSource(); 258 src.setGeometry(null); 259 updateButtons(focusLayer); 260 JTSTestBuilder.controller().geometryViewChanged(); 261 } 262 layerPaste(Layer lyr)263 protected void layerPaste(Layer lyr) { 264 try { 265 // don't paste into non-empty layers to avoid losing data 266 if (lyr.hasGeometry()) return; 267 268 Geometry geom = JTSTestBuilder.model().readGeometryFromClipboard(); 269 // this will error if layer is not modifiable 270 StaticGeometryContainer src = (StaticGeometryContainer) lyr.getSource(); 271 src.setGeometry(geom); 272 updateButtons(focusLayer); 273 JTSTestBuilder.controller().geometryViewChanged(); 274 } catch (Exception e) { 275 SwingUtil.reportException(this, e); 276 } 277 } 278 } 279 280 class LayerItemPanel extends JPanel { 281 private static Font FONT_FOCUS = new java.awt.Font("Dialog", Font.BOLD, 12); 282 private static Font FONT_NORMAL = new java.awt.Font("Dialog", Font.PLAIN, 12); 283 284 private Border BORDER_CONTROL = BorderFactory.createLineBorder(CLR_CONTROL); 285 private Border BORDER_HIGHLIGHT = BorderFactory.createLineBorder(Color.LIGHT_GRAY); 286 287 private static final Color CLR_CONTROL = AppColors.BACKGROUND; 288 private static final Color CLR_HIGHLIGHT = ColorUtil.darker(CLR_CONTROL, .95); 289 290 private Layer layer; 291 private JCheckBox checkbox; 292 private LayerListPanel lyrListPanel; 293 private LayerItemPanel self; 294 private JPanel namePanel; 295 private boolean hasFocus; 296 private JLabel lblName; 297 private JPanel swatch; 298 LayerItemPanel(Layer lyr, LayerListPanel lyrListPanel)299 LayerItemPanel(Layer lyr, LayerListPanel lyrListPanel) { 300 this.layer = lyr; 301 this.lyrListPanel = lyrListPanel; 302 try { 303 uiInit(); 304 } catch (Exception ex) { 305 ex.printStackTrace(); 306 } 307 self = this; 308 } 309 getLayer()310 public Layer getLayer() { 311 return layer; 312 } 313 setFocusLayer(boolean hasFocus)314 public void setFocusLayer(boolean hasFocus) { 315 setBackground(hasFocus ? AppColors.TAB_FOCUS : AppColors.BACKGROUND); 316 setBorder(hasFocus ? BORDER_HIGHLIGHT : BORDER_CONTROL ); 317 lblName.setFont(hasFocus ? FONT_FOCUS : FONT_NORMAL); 318 revalidate(); 319 this.hasFocus = hasFocus; 320 } 321 isFocusLayer()322 public boolean isFocusLayer() { 323 return hasFocus; 324 } 325 update()326 public void update() { 327 LayerStyleSwatchControl.update(swatch, layer); 328 lblName.setText( layer.getName()); 329 } 330 uiInit()331 private void uiInit() throws Exception { 332 setSize(250, 250); 333 setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); 334 setBackground(AppColors.BACKGROUND); 335 //setOpaque(true); 336 setAlignmentX(Component.LEFT_ALIGNMENT); 337 setBorder(BORDER_CONTROL); 338 339 checkbox = new JCheckBox(); 340 add(checkbox); 341 checkbox.setAlignmentX(Component.LEFT_ALIGNMENT); 342 checkbox.addActionListener(new java.awt.event.ActionListener() { 343 public void actionPerformed(ActionEvent e) { 344 layerVisAction(); 345 } 346 }); 347 checkbox.setSelected(layer.isEnabled()); 348 checkbox.setOpaque(false); 349 350 351 lblName = new JLabel(layer.getName()); 352 lblName.setAlignmentX(Component.LEFT_ALIGNMENT); 353 lblName.setMinimumSize(new Dimension(100,12)); 354 lblName.setPreferredSize(new Dimension(100,12)); 355 lblName.setMaximumSize(new Dimension(100,12)); 356 lblName.setFont(FONT_NORMAL); 357 lblName.addMouseListener(new HighlightMouseListener(this)); 358 lblName.addMouseListener(new MouseAdapter() 359 { 360 public void mouseClicked(MouseEvent e) 361 { 362 lyrListPanel.setLayerFocus(self); 363 } 364 }); 365 366 swatch = LayerStyleSwatchControl.create(layer); 367 add(swatch); 368 add(Box.createRigidArea(new Dimension(4,0))); 369 370 namePanel = new JPanel(); 371 add(namePanel); 372 namePanel.setLayout(new BoxLayout(namePanel, BoxLayout.X_AXIS)); 373 //namePanel.setBackground(CLR_CONTROL); 374 namePanel.setOpaque(false); 375 namePanel.setAlignmentX(Component.LEFT_ALIGNMENT); 376 namePanel.setMinimumSize(new Dimension(100,14)); 377 namePanel.setPreferredSize(new Dimension(100,14)); 378 namePanel.setMaximumSize(new Dimension(100,14)); 379 //namePanel.setBorder(BORDER_HIGHLIGHT);; 380 namePanel.addMouseListener(new HighlightMouseListener(this)); 381 382 namePanel.add(lblName); 383 } 384 layerVisAction()385 private void layerVisAction() { 386 boolean isVisible = checkbox.isSelected(); 387 layer.setEnabled(isVisible); 388 repaint(); 389 JTSTestBuilder.controller().geometryViewChanged(); 390 } 391 392 class HighlightMouseListener extends MouseAdapter { 393 private LayerItemPanel comp; 394 HighlightMouseListener(LayerItemPanel comp)395 HighlightMouseListener(LayerItemPanel comp) { 396 this.comp = comp; 397 } 398 mouseEntered(MouseEvent e)399 public void mouseEntered(MouseEvent e) { 400 if (comp.isFocusLayer()) return; 401 comp.setBackground(CLR_HIGHLIGHT); 402 //comp.setBorder(BORDER_HIGHLIGHT); 403 comp.revalidate(); 404 } 405 mouseExited(MouseEvent e)406 public void mouseExited(MouseEvent e) { 407 if (comp.isFocusLayer()) return; 408 comp.setBackground(AppColors.BACKGROUND); 409 //comp.setBorder(BORDER_CONTROL); 410 comp.revalidate(); 411 } 412 } 413 414 } 415 416 417 class LayerStyleSwatchControl { 418 create(Layer layer)419 public static JPanel create(Layer layer) { 420 JPanel ctl = new JPanel(); 421 Dimension dim = new Dimension(16,16); 422 ctl.setMinimumSize(dim); 423 ctl.setPreferredSize(dim); 424 ctl.setMaximumSize(dim); 425 ctl.setOpaque(true); 426 //update(ctl, layer); 427 return ctl; 428 } 429 update(JPanel ctl, Layer layer)430 public static void update(JPanel ctl, Layer layer) { 431 432 Color fillClr = Color.WHITE; 433 if (layer.getGeometryStyle().isFilled()) 434 fillClr = layer.getGeometryStyle().getFillColor(); 435 436 int lineWidth = 1; 437 if (layer.getGeometryStyle().getStrokeWidth() > 1) 438 lineWidth = 2; 439 440 /* 441 Graphics2D gr = (Graphics2D) ctl.getGraphics(); 442 gr.setColor(fillClr); 443 gr.setPaint(fillClr); 444 gr.fillRect(0, 0, 10, 10); 445 */ 446 ctl.setBackground( fillClr ); 447 ctl.setBorder(BorderFactory.createLineBorder(layer.getGeometryStyle().getLineColor(), lineWidth)); 448 } 449 } 450