User:DressyPear4/PintarNotas
From OpenStreetMap Wiki
Jump to navigation
Jump to search
Pintar notas selecionadas
Um script para apoio ao plugin NoteSolver. Com esse código você pode destacar quais notas já foram adicionadas na lista, os destaques podem ser desativados temporariamente pelo botão do painel. Caso a camada "Notas" seja excluída ou clicado em X no diálogo, as seleções serão perdidas.
Como funciona?
- Executar o script
- Ligar pintura
- Clique para destacar
- Clique para remover destaque
Demonstração

Código
Python
Última atualização: 2026-03-11
from org.openstreetmap.josm.gui import MainApplication, Notification
from org.openstreetmap.josm.gui.layer import MapViewPaintable, NoteLayer, LayerManager
from javax.swing import (JDialog, JToggleButton, JPanel, JTextArea, JScrollPane,
JSlider, JCheckBox, JLabel, SwingUtilities, JOptionPane)
from java.awt import Color, BasicStroke, AlphaComposite, BorderLayout, GridLayout
from java.awt.geom import Path2D
import java.awt.event
# --- Variáveis Globais ---
current_note_painter = None
notes_to_highlight = set()
class NoteHighlighter(MapViewPaintable):
def __init__(self, ids_set, transparency, fill_enabled):
self.ids_set = ids_set
self.transparency = transparency
self.fill_enabled = fill_enabled
def paint(self, g, mv, bbox):
if not self.ids_set: return
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, self.transparency))
g.setStroke(BasicStroke(1.5))
for layer in MainApplication.getLayerManager().getLayers():
if isinstance(layer, NoteLayer):
all_notes = layer.getData().getNotes()
for nota in all_notes:
if nota.id in self.ids_set:
p = mv.getPoint(nota.getLatLon())
self._draw_drop(g, p.x, p.y)
def _draw_drop(self, g, x, y):
drop = Path2D.Float()
drop.moveTo(x, y)
drop.curveTo(x - 5, y - 5, x - 7, y - 15, x, y - 15)
drop.curveTo(x + 7, y - 15, x + 5, y - 5, x, y)
drop.closePath()
if self.fill_enabled:
g.setColor(Color.ORANGE)
g.fill(drop)
g.setColor(Color.ORANGE)
g.draw(drop)
# --- Funções de Controle ---
def atualizar_lista_debug():
"""Limpa a depuração e lista apenas os IDs ativos"""
debug_area.setText("")
sorted_ids = sorted(list(notes_to_highlight))
for note_id in sorted_ids:
debug_area.append("Nota: " + str(note_id) + "\n")
def limpar_pintura_mapa():
global current_note_painter
if MainApplication.getMap() and MainApplication.getMap().mapView:
mv = MainApplication.getMap().mapView
if current_note_painter:
mv.removeTemporaryLayer(current_note_painter)
current_note_painter = None
mv.removeMouseListener(mouse_listener)
mv.repaint()
def fechar_dialogo_completo():
limpar_pintura_mapa()
MainApplication.getLayerManager().removeLayerChangeListener(layer_listener)
if dialog.isVisible():
dialog.dispose()
def handle_click(e):
if not toggle_btn.isSelected(): return
if not MainApplication.getMap(): return
mv = MainApplication.getMap().mapView
click_p = e.getPoint()
nota_encontrada = None
for layer in MainApplication.getLayerManager().getLayers():
if isinstance(layer, NoteLayer):
for n in layer.getData().getNotes():
note_p = mv.getPoint(n.getLatLon())
if click_p.distance(note_p) < 10:
nota_encontrada = n
break
if nota_encontrada:
if nota_encontrada.id in notes_to_highlight:
notes_to_highlight.remove(nota_encontrada.id)
else:
notes_to_highlight.add(nota_encontrada.id)
atualizar_lista_debug()
mv.repaint()
def atualizar_desenho(e=None):
global current_note_painter
if not MainApplication.getMap(): return
mv = MainApplication.getMap().mapView
if toggle_btn.isSelected():
if current_note_painter:
mv.removeTemporaryLayer(current_note_painter)
transp = slider_transp.getValue() / 100.0
current_note_painter = NoteHighlighter(notes_to_highlight, transp, chk_fill.isSelected())
mv.addTemporaryLayer(current_note_painter)
mv.repaint()
def on_toggle(e):
if not MainApplication.getMap() or not MainApplication.getMap().mapView:
toggle_btn.setSelected(False)
return
if toggle_btn.isSelected():
MainApplication.getMap().mapView.addMouseListener(mouse_listener)
atualizar_desenho()
toggle_btn.setText("PINTURA: ATIVA")
toggle_btn.setBackground(Color(144, 255, 144))
else:
limpar_pintura_mapa()
toggle_btn.setText("LIGAR PINTURA")
toggle_btn.setBackground(None)
# --- Monitor de Camadas ---
class MyLayerChangeListener(LayerManager.LayerChangeListener):
def layerAdded(self, e): pass
def layerOrderChanged(self, e): pass
def layerRemoving(self, e):
if isinstance(e.getRemovedLayer(), NoteLayer):
def acao_remocao():
fechar_dialogo_completo()
Notification(u"Camada de 'Notas' deletada. Fechando diálogo").setIcon(JOptionPane.WARNING_MESSAGE).show()
SwingUtilities.invokeLater(acao_remocao)
# --- Adaptadores ---
class MapClickAdapter(java.awt.event.MouseAdapter):
def mousePressed(self, e): handle_click(e)
class WindowCloseAdapter(java.awt.event.WindowAdapter):
def windowClosing(self, e): fechar_dialogo_completo()
# --- Verificação Inicial ---
def iniciar_script():
tem_nota = any(isinstance(l, NoteLayer) for l in MainApplication.getLayerManager().getLayers())
if not tem_nota:
Notification("Nenhuma camada 'Notas' encontrada.").setIcon(JOptionPane.ERROR_MESSAGE).show()
return
global dialog, toggle_btn, chk_fill, slider_transp, debug_area, mouse_listener, layer_listener
dialog = JDialog(MainApplication.getMainFrame(), "Note Painter", False)
dialog.setLayout(BorderLayout())
panel_ctrl = JPanel(GridLayout(0, 1))
toggle_btn = JToggleButton("LIGAR PINTURA")
toggle_btn.setOpaque(True)
toggle_btn.addActionListener(on_toggle)
chk_fill = JCheckBox("Preenchimento", True)
chk_fill.addActionListener(atualizar_desenho)
slider_transp = JSlider(0, 100, 75)
slider_transp.addChangeListener(atualizar_desenho)
panel_ctrl.add(toggle_btn)
panel_ctrl.add(chk_fill)
panel_ctrl.add(JLabel(u"Transparência:"))
panel_ctrl.add(slider_transp)
debug_area = JTextArea(6, 10)
debug_area.setEditable(False)
dialog.add(panel_ctrl, BorderLayout.NORTH)
dialog.add(JScrollPane(debug_area), BorderLayout.CENTER)
mouse_listener = MapClickAdapter()
layer_listener = MyLayerChangeListener()
dialog.addWindowListener(WindowCloseAdapter())
MainApplication.getLayerManager().addLayerChangeListener(layer_listener)
dialog.pack()
dialog.setLocationRelativeTo(MainApplication.getMainFrame())
dialog.setVisible(True)
iniciar_script()
JavaScript
Última atualização: 2026-03-11
"use strict";
// --- Importações de API ---
const MainApplication = Java.type("org.openstreetmap.josm.gui.MainApplication");
const Notification = Java.type("org.openstreetmap.josm.gui.Notification");
const MapViewPaintable = Java.type("org.openstreetmap.josm.gui.layer.MapViewPaintable");
const NoteLayer = Java.type("org.openstreetmap.josm.gui.layer.NoteLayer");
const LayerChangeListener = Java.extend(Java.type("org.openstreetmap.josm.gui.layer.LayerManager.LayerChangeListener"));
const JDialog = Java.type("javax.swing.JDialog");
const JToggleButton = Java.type("javax.swing.JToggleButton");
const JPanel = Java.type("javax.swing.JPanel");
const JTextArea = Java.type("javax.swing.JTextArea");
const JScrollPane = Java.type("javax.swing.JScrollPane");
const JSlider = Java.type("javax.swing.JSlider");
const JCheckBox = Java.type("javax.swing.JCheckBox");
const JLabel = Java.type("javax.swing.JLabel");
const JOptionPane = Java.type("javax.swing.JOptionPane");
const SwingUtilities = Java.type("javax.swing.SwingUtilities");
const Color = Java.type("java.awt.Color");
const BasicStroke = Java.type("java.awt.BasicStroke");
const AlphaComposite = Java.type("java.awt.AlphaComposite");
const BorderLayout = Java.type("java.awt.BorderLayout");
const GridLayout = Java.type("java.awt.GridLayout");
const Path2D = Java.type("java.awt.geom.Path2D");
const MouseAdapter = Java.extend(Java.type("java.awt.event.MouseAdapter"));
const WindowAdapter = Java.extend(Java.type("java.awt.event.WindowAdapter"));
const ActionListener = Java.extend(Java.type("java.awt.event.ActionListener"));
const ChangeListener = Java.extend(Java.type("javax.swing.event.ChangeListener"));
const JFloat = Java.type("java.lang.Float");
// --- Helper: itera qualquer coleção Java com segurança ---
function javaIter(collection) {
const result = [];
const it = collection.iterator();
while (it.hasNext()) result.push(it.next());
return result;
}
// --- Variáveis Globais ---
globalThis.notePainterTool = {
currentNotePainter: null,
notesToHighlight: new Set(),
dialog: null,
toggleBtn: null,
chkFill: null,
sliderTransp: null,
debugArea: null,
mouseListener: null,
layerListener: null,
// --- Pintura do Mapa ---
createPaintable: function () {
const self = this;
const PaintClass = Java.extend(MapViewPaintable, {
paint: function (g, mv, bbox) {
if (self.notesToHighlight.size === 0) return;
const transp = new JFloat(self.sliderTransp.getValue() / 100.0);
const fillEnabled = self.chkFill.isSelected();
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, transp));
g.setStroke(new BasicStroke(1.5));
for (const layer of javaIter(MainApplication.getLayerManager().getLayers())) {
if (layer instanceof NoteLayer) {
const allNotes = layer.getData().getNotes();
for (const nota of javaIter(allNotes)) {
if (self.notesToHighlight.has(Number(nota.getId()))) {
const p = mv.getPoint(nota.getLatLon());
self.drawDrop(g, p.x, p.y, fillEnabled);
}
}
}
}
}
});
return new PaintClass();
},
drawDrop: function (g, x, y, fillEnabled) {
const drop = new Path2D.Float();
drop.moveTo(x, y);
drop.curveTo(x - 5, y - 5, x - 7, y - 15, x, y - 15);
drop.curveTo(x + 7, y - 15, x + 5, y - 5, x, y);
drop.closePath();
g.setColor(Color.ORANGE);
if (fillEnabled) {
g.fill(drop);
}
g.draw(drop);
},
// --- Funções de Controle ---
atualizarListaDebug: function () {
this.debugArea.setText("");
const sorted = Array.from(this.notesToHighlight).sort((a, b) => a - b);
for (const noteId of sorted) {
this.debugArea.append("Nota: " + noteId + "\n");
}
},
limparPinturaMapa: function () {
if (MainApplication.getMap() && MainApplication.getMap().mapView) {
const mv = MainApplication.getMap().mapView;
if (this.currentNotePainter) {
mv.removeTemporaryLayer(this.currentNotePainter);
this.currentNotePainter = null;
}
if (this.mouseListener) {
mv.removeMouseListener(this.mouseListener);
}
mv.repaint();
}
},
fecharDialogoCompleto: function () {
this.limparPinturaMapa();
MainApplication.getLayerManager().removeLayerChangeListener(this.layerListener);
if (this.dialog && this.dialog.isVisible()) {
this.dialog.dispose();
}
},
handleClick: function (e) {
if (!this.toggleBtn.isSelected()) return;
if (!MainApplication.getMap()) return;
const mv = MainApplication.getMap().mapView;
const clickP = e.getPoint();
let notaEncontrada = null;
for (const layer of javaIter(MainApplication.getLayerManager().getLayers())) {
if (layer instanceof NoteLayer) {
for (const n of javaIter(layer.getData().getNotes())) {
const noteP = mv.getPoint(n.getLatLon());
if (clickP.distance(noteP) < 10) {
notaEncontrada = n;
break;
}
}
}
if (notaEncontrada) break;
}
if (notaEncontrada) {
const id = Number(notaEncontrada.getId());
if (this.notesToHighlight.has(id)) {
this.notesToHighlight.delete(id);
} else {
this.notesToHighlight.add(id);
}
this.atualizarListaDebug();
mv.repaint();
}
},
atualizarDesenho: function () {
if (!MainApplication.getMap()) return;
const mv = MainApplication.getMap().mapView;
if (this.toggleBtn.isSelected()) {
if (this.currentNotePainter) {
mv.removeTemporaryLayer(this.currentNotePainter);
}
this.currentNotePainter = this.createPaintable();
mv.addTemporaryLayer(this.currentNotePainter);
mv.repaint();
}
},
onToggle: function () {
if (!MainApplication.getMap() || !MainApplication.getMap().mapView) {
this.toggleBtn.setSelected(false);
return;
}
if (this.toggleBtn.isSelected()) {
MainApplication.getMap().mapView.addMouseListener(this.mouseListener);
this.atualizarDesenho();
this.toggleBtn.setText("PINTURA: ATIVA");
this.toggleBtn.setBackground(new Color(144, 255, 144));
} else {
this.limparPinturaMapa();
this.toggleBtn.setText("LIGAR PINTURA");
this.toggleBtn.setBackground(null);
}
},
// --- Janela Principal ---
showWindow: function () {
const self = this;
// Verifica se existe camada de Notas
let temNota = false;
for (const layer of javaIter(MainApplication.getLayerManager().getLayers())) {
if (layer instanceof NoteLayer) { temNota = true; break; }
}
if (!temNota) {
new Notification("Nenhuma camada 'Notas' encontrada.")
.setIcon(JOptionPane.ERROR_MESSAGE).show();
return;
}
this.dialog = new JDialog(MainApplication.getMainFrame(), "Note Painter", false);
this.dialog.setLayout(new BorderLayout());
const panelCtrl = new JPanel(new GridLayout(0, 1));
this.toggleBtn = new JToggleButton("LIGAR PINTURA");
this.toggleBtn.setOpaque(true);
this.toggleBtn.addActionListener(new ActionListener({
actionPerformed: () => self.onToggle()
}));
this.chkFill = new JCheckBox("Preenchimento", true);
this.chkFill.addActionListener(new ActionListener({
actionPerformed: () => self.atualizarDesenho()
}));
this.sliderTransp = new JSlider(0, 100, 75);
this.sliderTransp.addChangeListener(new ChangeListener({
stateChanged: () => self.atualizarDesenho()
}));
panelCtrl.add(this.toggleBtn);
panelCtrl.add(this.chkFill);
panelCtrl.add(new JLabel("Transparência:"));
panelCtrl.add(this.sliderTransp);
this.debugArea = new JTextArea(6, 10);
this.debugArea.setEditable(false);
this.dialog.add(panelCtrl, BorderLayout.NORTH);
this.dialog.add(new JScrollPane(this.debugArea), BorderLayout.CENTER);
// Mouse listener para cliques no mapa
this.mouseListener = new MouseAdapter({
mousePressed: (e) => self.handleClick(e)
});
// Layer listener para detectar remoção da camada de Notas
this.layerListener = new LayerChangeListener({
layerAdded: (e) => {},
layerOrderChanged: (e) => {},
layerRemoving: (e) => {
if (e.getRemovedLayer() instanceof NoteLayer) {
SwingUtilities.invokeLater(() => {
self.fecharDialogoCompleto();
new Notification("Camada de 'Notas' deletada. Fechando diálogo.")
.setIcon(JOptionPane.WARNING_MESSAGE).show();
});
}
}
});
this.dialog.addWindowListener(new WindowAdapter({
windowClosing: (e) => self.fecharDialogoCompleto()
}));
MainApplication.getLayerManager().addLayerChangeListener(this.layerListener);
this.dialog.pack();
this.dialog.setLocationRelativeTo(MainApplication.getMainFrame());
this.dialog.setVisible(true);
}
};
// --- Início ---
notePainterTool.showWindow();