Modify connection between MainWindow and the NotesInputPanel.
This commit is contained in:
		
							parent
							
								
									cfa374c12d
								
							
						
					
					
						commit
						1a664b8a3c
					
				
					 8 changed files with 158 additions and 19 deletions
				
			
		
							
								
								
									
										24
									
								
								src/main/org/insa/graphics/DrawingChangeListener.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/main/org/insa/graphics/DrawingChangeListener.java
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,24 @@ | ||||||
|  | package org.insa.graphics; | ||||||
|  | 
 | ||||||
|  | import org.insa.graphics.drawing.Drawing; | ||||||
|  | 
 | ||||||
|  | public interface DrawingChangeListener { | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Event fired when a new drawing is loaded. | ||||||
|  |      *  | ||||||
|  |      * @param oldDrawing Old drawing, may be null if no drawing exits prior to this | ||||||
|  |      *        one. | ||||||
|  |      * @param newDrawing New drawing. | ||||||
|  |      */ | ||||||
|  |     public void onDrawingLoaded(Drawing oldDrawing, Drawing newDrawing); | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Event fired when a redraw request is emitted - This is typically emitted | ||||||
|  |      * after a onDrawingLoaded event, but not always, and request that elements are | ||||||
|  |      * drawn again on the new drawing. | ||||||
|  |      *  | ||||||
|  |      */ | ||||||
|  |     public void onRedrawRequest(); | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										14
									
								
								src/main/org/insa/graphics/GraphChangeListener.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/main/org/insa/graphics/GraphChangeListener.java
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | ||||||
|  | package org.insa.graphics; | ||||||
|  | 
 | ||||||
|  | import org.insa.graph.Graph; | ||||||
|  | 
 | ||||||
|  | public interface GraphChangeListener { | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Event fire when a new graph has been loaded. | ||||||
|  |      *  | ||||||
|  |      * @param graph The new graph. | ||||||
|  |      */ | ||||||
|  |     public void newGraphLoaded(Graph graph); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -21,6 +21,7 @@ import java.io.FileOutputStream; | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| import java.io.PrintStream; | import java.io.PrintStream; | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
|  | import java.util.List; | ||||||
| 
 | 
 | ||||||
| import javax.swing.BorderFactory; | import javax.swing.BorderFactory; | ||||||
| import javax.swing.Box; | import javax.swing.Box; | ||||||
|  | @ -131,6 +132,10 @@ public class MainWindow extends JFrame { | ||||||
|     // Factory |     // Factory | ||||||
|     private BlockingActionFactory baf; |     private BlockingActionFactory baf; | ||||||
| 
 | 
 | ||||||
|  |     // Observers | ||||||
|  |     private List<DrawingChangeListener> drawingChangeListeners = new ArrayList<>(); | ||||||
|  |     private List<GraphChangeListener> graphChangeListeneres = new ArrayList<>(); | ||||||
|  | 
 | ||||||
|     public MainWindow() { |     public MainWindow() { | ||||||
|         super(WINDOW_TITLE); |         super(WINDOW_TITLE); | ||||||
| 
 | 
 | ||||||
|  | @ -143,7 +148,7 @@ public class MainWindow extends JFrame { | ||||||
| 
 | 
 | ||||||
|         this.drawing = this.basicDrawing; |         this.drawing = this.basicDrawing; | ||||||
| 
 | 
 | ||||||
|         spPanel = new ShortestPathPanel(MainWindow.this); |         spPanel = new ShortestPathPanel(); | ||||||
|         spPanel.addStartActionListener(new ActionListener() { |         spPanel.addStartActionListener(new ActionListener() { | ||||||
|             @Override |             @Override | ||||||
|             public void actionPerformed(ActionEvent e) { |             public void actionPerformed(ActionEvent e) { | ||||||
|  | @ -166,15 +171,19 @@ public class MainWindow extends JFrame { | ||||||
|         }); |         }); | ||||||
|         spPanel.setVisible(false); |         spPanel.setVisible(false); | ||||||
| 
 | 
 | ||||||
|  |         // Add click listeners to both drawing. | ||||||
|         basicDrawing.addDrawingClickListener(spPanel.nodesInputPanel); |         basicDrawing.addDrawingClickListener(spPanel.nodesInputPanel); | ||||||
|         mapViewDrawing.addDrawingClickListener(spPanel.nodesInputPanel); |         mapViewDrawing.addDrawingClickListener(spPanel.nodesInputPanel); | ||||||
| 
 | 
 | ||||||
|  |         this.graphChangeListeneres.add(spPanel.nodesInputPanel); | ||||||
|  |         this.drawingChangeListeners.add(spPanel.nodesInputPanel); | ||||||
|  | 
 | ||||||
|  |         // Create action factory. | ||||||
|         this.currentThread = new ThreadWrapper(this); |         this.currentThread = new ThreadWrapper(this); | ||||||
|         this.baf = new BlockingActionFactory(this); |         this.baf = new BlockingActionFactory(this); | ||||||
|         this.baf.addAction(currentThread); |         this.baf.addAction(currentThread); | ||||||
| 
 | 
 | ||||||
|         // Click adapter |         // Click adapter | ||||||
|         addDrawingClickListeners(); |  | ||||||
|         setJMenuBar(createMenuBar()); |         setJMenuBar(createMenuBar()); | ||||||
| 
 | 
 | ||||||
|         addWindowListener(new WindowAdapter() { |         addWindowListener(new WindowAdapter() { | ||||||
|  | @ -229,6 +238,8 @@ public class MainWindow extends JFrame { | ||||||
|         // Top Panel |         // Top Panel | ||||||
|         this.add(createStatusBar(), BorderLayout.SOUTH); |         this.add(createStatusBar(), BorderLayout.SOUTH); | ||||||
| 
 | 
 | ||||||
|  |         // Notify everythin | ||||||
|  |         notifyDrawingLoaded(null, drawing); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | @ -369,7 +380,34 @@ public class MainWindow extends JFrame { | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void addDrawingClickListeners() { |     /** | ||||||
|  |      * Notify all listeners that a new graph has been loaded. | ||||||
|  |      */ | ||||||
|  |     private void notifyNewGraphLoaded() { | ||||||
|  |         for (GraphChangeListener listener: graphChangeListeneres) { | ||||||
|  |             listener.newGraphLoaded(graph); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Notify all listeners that a new drawing has been set up. | ||||||
|  |      *  | ||||||
|  |      * @param oldDrawing | ||||||
|  |      * @param newDrawing | ||||||
|  |      */ | ||||||
|  |     private void notifyDrawingLoaded(Drawing oldDrawing, Drawing newDrawing) { | ||||||
|  |         for (DrawingChangeListener listener: drawingChangeListeners) { | ||||||
|  |             listener.onDrawingLoaded(oldDrawing, newDrawing); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Notify all listeners that a redraw request is emitted. | ||||||
|  |      */ | ||||||
|  |     private void notifyRedrawRequest() { | ||||||
|  |         for (DrawingChangeListener listener: drawingChangeListeners) { | ||||||
|  |             listener.onRedrawRequest(); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | @ -414,22 +452,26 @@ public class MainWindow extends JFrame { | ||||||
|                 drawing = mapViewDrawing; |                 drawing = mapViewDrawing; | ||||||
|                 mainPanel.setLeftComponent(mapViewDrawing); |                 mainPanel.setLeftComponent(mapViewDrawing); | ||||||
|                 mainPanel.setDividerLocation(oldLocation); |                 mainPanel.setDividerLocation(oldLocation); | ||||||
|  |                 notifyDrawingLoaded(basicDrawing, mapViewDrawing); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             // 2. We draw the graph. |             // 2. We draw the graph. | ||||||
|             drawing.clear(); |             drawing.clear(); | ||||||
|             ((MapViewDrawing) drawing).drawGraph(mfile); |             ((MapViewDrawing) drawing).drawGraph(mfile); | ||||||
|  |             notifyRedrawRequest(); | ||||||
|  | 
 | ||||||
|         } |         } | ||||||
|         else if (!isMapView || (isMapView && mfile == null && isNewGraph)) { |         else if (!isMapView || (isMapView && mfile == null && isNewGraph)) { | ||||||
|             if (drawing == mapViewDrawing) { |             if (drawing == mapViewDrawing) { | ||||||
|                 mapViewDrawing.clear(); |                 mapViewDrawing.clear(); | ||||||
|                 drawing = basicDrawing; |                 drawing = basicDrawing; | ||||||
|                 addDrawingClickListeners(); |  | ||||||
|                 mainPanel.setLeftComponent(basicDrawing); |                 mainPanel.setLeftComponent(basicDrawing); | ||||||
|                 mainPanel.setDividerLocation(oldLocation); |                 mainPanel.setDividerLocation(oldLocation); | ||||||
|  |                 notifyDrawingLoaded(mapViewDrawing, basicDrawing); | ||||||
|             } |             } | ||||||
|             drawing.clear(); |             drawing.clear(); | ||||||
|             drawing.drawGraph(graph, palette); |             drawing.drawGraph(graph, palette); | ||||||
|  |             notifyRedrawRequest(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
|  | @ -485,6 +527,7 @@ public class MainWindow extends JFrame { | ||||||
|                                 exception.printStackTrace(System.out); |                                 exception.printStackTrace(System.out); | ||||||
|                                 return; |                                 return; | ||||||
|                             } |                             } | ||||||
|  |                             notifyNewGraphLoaded(); | ||||||
| 
 | 
 | ||||||
|                             // Save file path. |                             // Save file path. | ||||||
|                             graphFilePath = path; |                             graphFilePath = path; | ||||||
|  |  | ||||||
|  | @ -21,12 +21,15 @@ import javax.swing.JTextField; | ||||||
| import javax.swing.event.DocumentEvent; | import javax.swing.event.DocumentEvent; | ||||||
| import javax.swing.event.DocumentListener; | import javax.swing.event.DocumentListener; | ||||||
| 
 | 
 | ||||||
|  | import org.insa.graph.Graph; | ||||||
| import org.insa.graph.Node; | import org.insa.graph.Node; | ||||||
| import org.insa.graph.Point; | import org.insa.graph.Point; | ||||||
|  | import org.insa.graphics.drawing.Drawing; | ||||||
| import org.insa.graphics.drawing.DrawingClickListener; | import org.insa.graphics.drawing.DrawingClickListener; | ||||||
| import org.insa.graphics.drawing.overlays.MarkerOverlay; | import org.insa.graphics.drawing.overlays.MarkerOverlay; | ||||||
| 
 | 
 | ||||||
| public class NodesInputPanel extends JPanel implements DrawingClickListener { | public class NodesInputPanel extends JPanel | ||||||
|  |         implements DrawingClickListener, DrawingChangeListener, GraphChangeListener { | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      *  |      *  | ||||||
|  | @ -61,8 +64,8 @@ public class NodesInputPanel extends JPanel implements DrawingClickListener { | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     // Node inputs and markers. |     // Node inputs and markers. | ||||||
|     private ArrayList<JTextField> nodeInputs = new ArrayList<>(); |     private final ArrayList<JTextField> nodeInputs = new ArrayList<>(); | ||||||
|     private Map<JTextField, MarkerOverlay> markerTrackers = new IdentityHashMap<JTextField, MarkerOverlay>(); |     private final Map<JTextField, MarkerOverlay> markerTrackers = new IdentityHashMap<JTextField, MarkerOverlay>(); | ||||||
| 
 | 
 | ||||||
|     // Component that can be enabled/disabled. |     // Component that can be enabled/disabled. | ||||||
|     private ArrayList<JComponent> components = new ArrayList<>(); |     private ArrayList<JComponent> components = new ArrayList<>(); | ||||||
|  | @ -71,12 +74,16 @@ public class NodesInputPanel extends JPanel implements DrawingClickListener { | ||||||
|     // ActionListener called when all inputs are filled. |     // ActionListener called when all inputs are filled. | ||||||
|     private ArrayList<ActionListener> inputChangeListeners = new ArrayList<>(); |     private ArrayList<ActionListener> inputChangeListeners = new ArrayList<>(); | ||||||
| 
 | 
 | ||||||
|     // Instance of mainwindow. |     // Drawing and graph | ||||||
|     MainWindow mainWindow; |     private Drawing drawing; | ||||||
|  |     private Graph graph; | ||||||
| 
 | 
 | ||||||
|     public NodesInputPanel(MainWindow mainWindow) { |     /** | ||||||
|  |      * @param drawing Original drawing used (see {@link:newDrawingLoaded}). | ||||||
|  |      * @param graph Original graph used (see {@link:newGraphLoaded}); | ||||||
|  |      */ | ||||||
|  |     public NodesInputPanel() { | ||||||
|         super(new GridBagLayout()); |         super(new GridBagLayout()); | ||||||
|         this.mainWindow = mainWindow; |  | ||||||
|         initInputToFill(); |         initInputToFill(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -105,6 +112,7 @@ public class NodesInputPanel extends JPanel implements DrawingClickListener { | ||||||
|     public void clear() { |     public void clear() { | ||||||
|         for (JTextField field: nodeInputs) { |         for (JTextField field: nodeInputs) { | ||||||
|             field.setText(""); |             field.setText(""); | ||||||
|  |             markerTrackers.put(field, null); | ||||||
|         } |         } | ||||||
|         initInputToFill(); |         initInputToFill(); | ||||||
|     } |     } | ||||||
|  | @ -174,7 +182,7 @@ public class NodesInputPanel extends JPanel implements DrawingClickListener { | ||||||
|                 MarkerOverlay tracker = markerTrackers.getOrDefault(textField, null); |                 MarkerOverlay tracker = markerTrackers.getOrDefault(textField, null); | ||||||
|                 if (curnode != null) { |                 if (curnode != null) { | ||||||
|                     if (tracker == null) { |                     if (tracker == null) { | ||||||
|                         tracker = mainWindow.drawing.drawMarker(curnode.getPoint(), markerColor); |                         tracker = drawing.drawMarker(curnode.getPoint(), markerColor); | ||||||
|                         markerTrackers.put(textField, tracker); |                         markerTrackers.put(textField, tracker); | ||||||
|                     } |                     } | ||||||
|                     else { |                     else { | ||||||
|  | @ -223,7 +231,7 @@ public class NodesInputPanel extends JPanel implements DrawingClickListener { | ||||||
|      */ |      */ | ||||||
|     protected Node getNodeForInput(JTextField textfield) { |     protected Node getNodeForInput(JTextField textfield) { | ||||||
|         try { |         try { | ||||||
|             Node node = this.mainWindow.graph.getNodes().get(Integer.valueOf(textfield.getText().trim())); |             Node node = graph.getNodes().get(Integer.valueOf(textfield.getText().trim())); | ||||||
|             return node; |             return node; | ||||||
|         } |         } | ||||||
|         catch (IllegalArgumentException | IndexOutOfBoundsException ex) { |         catch (IllegalArgumentException | IndexOutOfBoundsException ex) { | ||||||
|  | @ -292,11 +300,38 @@ public class NodesInputPanel extends JPanel implements DrawingClickListener { | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public void mouseClicked(Point point) { |     public void mouseClicked(Point point) { | ||||||
|         Node node = this.mainWindow.graph.findClosestNode(point); |         Node node = graph.findClosestNode(point); | ||||||
|         JTextField input = getInputToFill(); |         JTextField input = getInputToFill(); | ||||||
|         if (input != null) { |         if (input != null) { | ||||||
|             input.setText(String.valueOf(node.getId())); |             input.setText(String.valueOf(node.getId())); | ||||||
|             nextInputToFill(); |             nextInputToFill(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void newGraphLoaded(Graph graph) { | ||||||
|  |         if (graph != this.graph) { | ||||||
|  |             this.clear(); | ||||||
|  |             this.graph = graph; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void onDrawingLoaded(Drawing oldDrawing, Drawing newDrawing) { | ||||||
|  |         if (newDrawing != drawing) { | ||||||
|  |             this.drawing = newDrawing; | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void onRedrawRequest() { | ||||||
|  |         for (JTextField input: nodeInputs) { | ||||||
|  |             MarkerOverlay tracker = markerTrackers.getOrDefault(input, null); | ||||||
|  |             if (tracker != null) { | ||||||
|  |                 markerTrackers.put(input, this.drawing.drawMarker(tracker.getPoint(), tracker.getColor())); | ||||||
|  |                 tracker.delete(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -95,7 +95,9 @@ public class ShortestPathPanel extends JPanel { | ||||||
|     // Start listeners |     // Start listeners | ||||||
|     List<ActionListener> startActionListeners = new ArrayList<>(); |     List<ActionListener> startActionListeners = new ArrayList<>(); | ||||||
| 
 | 
 | ||||||
|     public ShortestPathPanel(MainWindow mainWindow) { |     /** | ||||||
|  |      */ | ||||||
|  |     public ShortestPathPanel() { | ||||||
|         super(); |         super(); | ||||||
|         setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); |         setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); | ||||||
| 
 | 
 | ||||||
|  | @ -122,7 +124,7 @@ public class ShortestPathPanel extends JPanel { | ||||||
|         components.add(algoSelect); |         components.add(algoSelect); | ||||||
| 
 | 
 | ||||||
|         // Add inputs for node. |         // Add inputs for node. | ||||||
|         this.nodesInputPanel = new NodesInputPanel(mainWindow); |         this.nodesInputPanel = new NodesInputPanel(); | ||||||
|         this.nodesInputPanel.setAlignmentX(Component.LEFT_ALIGNMENT); |         this.nodesInputPanel.setAlignmentX(Component.LEFT_ALIGNMENT); | ||||||
|         nodesInputPanel.addTextField("Origin: ", new Color(57, 172, 115)); |         nodesInputPanel.addTextField("Origin: ", new Color(57, 172, 115)); | ||||||
|         nodesInputPanel.addTextField("Destination: ", new Color(255, 77, 77)); |         nodesInputPanel.addTextField("Destination: ", new Color(255, 77, 77)); | ||||||
|  |  | ||||||
|  | @ -99,6 +99,11 @@ public class BasicDrawing extends JPanel implements Drawing { | ||||||
|             return point; |             return point; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         @Override | ||||||
|  |         public Color getColor() { | ||||||
|  |             return color; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         @Override |         @Override | ||||||
|         public void moveTo(Point point) { |         public void moveTo(Point point) { | ||||||
|             this.point = point; |             this.point = point; | ||||||
|  | @ -440,7 +445,7 @@ public class BasicDrawing extends JPanel implements Drawing { | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public void drawGraph(Graph graph, GraphPalette palette) { |     public void drawGraph(Graph graph, GraphPalette palette) { | ||||||
|         clear(); |         this.clear(); | ||||||
|         initialize(graph); |         initialize(graph); | ||||||
|         for (Node node: graph.getNodes()) { |         for (Node node: graph.getNodes()) { | ||||||
|             for (Arc arc: node.getSuccessors()) { |             for (Arc arc: node.getSuccessors()) { | ||||||
|  |  | ||||||
|  | @ -80,8 +80,12 @@ public class MapViewDrawing extends MapView implements Drawing { | ||||||
| 
 | 
 | ||||||
|     private class MapViewMarkerOverlay extends MapViewOverlay implements MarkerOverlay { |     private class MapViewMarkerOverlay extends MapViewOverlay implements MarkerOverlay { | ||||||
| 
 | 
 | ||||||
|         public MapViewMarkerOverlay(Marker marker) { |         // Color of this marker | ||||||
|  |         Color color; | ||||||
|  | 
 | ||||||
|  |         public MapViewMarkerOverlay(Marker marker, Color color) { | ||||||
|             super(new Layer[] { marker }); |             super(new Layer[] { marker }); | ||||||
|  |             this.color = color; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         @Override |         @Override | ||||||
|  | @ -90,6 +94,11 @@ public class MapViewDrawing extends MapView implements Drawing { | ||||||
|             return new Point(marker.getLatLong().getLongitude(), marker.getLatLong().getLatitude()); |             return new Point(marker.getLatLong().getLongitude(), marker.getLatLong().getLatitude()); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         @Override | ||||||
|  |         public Color getColor() { | ||||||
|  |             return color; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         @Override |         @Override | ||||||
|         public void moveTo(Point point) { |         public void moveTo(Point point) { | ||||||
|             Marker marker = (Marker) this.layers[0]; |             Marker marker = (Marker) this.layers[0]; | ||||||
|  | @ -187,7 +196,7 @@ public class MapViewDrawing extends MapView implements Drawing { | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public MarkerOverlay drawMarker(Point point, Color color) { |     public MarkerOverlay drawMarker(Point point, Color color) { | ||||||
|         return new MapViewMarkerOverlay(createMarker(point, color)); |         return new MapViewMarkerOverlay(createMarker(point, color), color); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|  |  | ||||||
|  | @ -1,9 +1,16 @@ | ||||||
| package org.insa.graphics.drawing.overlays; | package org.insa.graphics.drawing.overlays; | ||||||
| 
 | 
 | ||||||
|  | import java.awt.Color; | ||||||
|  | 
 | ||||||
| import org.insa.graph.Point; | import org.insa.graph.Point; | ||||||
| 
 | 
 | ||||||
| public interface MarkerOverlay extends Overlay { | public interface MarkerOverlay extends Overlay { | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * @return Color associated with this marker. | ||||||
|  |      */ | ||||||
|  |     public Color getColor(); | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * @return The point associated with this marker. |      * @return The point associated with this marker. | ||||||
|      */ |      */ | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue