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

Imagem.gif, clique para visualizar.

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();