<commit_before>/*
 *
 * Copyright (c) 2000-2007 by <NAME>, <NAME>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License (LGPL) as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, copies are available
 * at http://www.opensource.org.
 */
package VASSAL.build.module.map;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;

import javax.swing.JComponent;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import VASSAL.build.Buildable;
import VASSAL.build.GameModule;
import VASSAL.build.module.Map;
import VASSAL.counters.ColoredBorder;
import VASSAL.counters.Deck;
import VASSAL.counters.DeckVisitor;
import VASSAL.counters.Decorator;
import VASSAL.counters.EventFilter;
import VASSAL.counters.GamePiece;
import VASSAL.counters.Immobilized;
import VASSAL.counters.KeyBuffer;
import VASSAL.counters.NonRectangular;
import VASSAL.counters.PieceFinder;
import VASSAL.counters.PieceVisitorDispatcher;
import VASSAL.counters.Properties;
import VASSAL.counters.Stack;
import VASSAL.tools.swing.SwingUtils;

/**
 * This component listens for mouse clicks on a map and draws the selection
 * rectangle.
 *
 * If the user clicks on a {@link GamePiece}, that piece is added to the
 * {@link KeyBuffer}. {@link #draw(Graphics, Map)} is responsible for
 * drawing the mouse selection rectangle, and
 * {@link #mouseDragged(MouseEvent)} is responsible for triggering repaint
 * events as the selection rectangle is moved.
 *
 * @see Map#addLocalMouseListener
 */
public class KeyBufferer extends MouseAdapter implements Buildable, MouseMotionListener, Drawable {
  protected Map map;
  protected Rectangle selection;
  protected Point anchor;
  protected Color color = Color.black;
  protected int thickness = 3;
  protected GamePiece bandSelectPiece = null;

  private enum BandSelectType {
    NONE,
    NORMAL,
    SPECIAL;
  }

  @Override
  public void addTo(Buildable b) {
    map = (Map) b;
    map.addLocalMouseListenerFirst(this);
    map.getView().addMouseMotionListener(this);
    map.addDrawComponent(this);
  }

  @Override
  public void add(Buildable b) {
  }

  @Override
  public Element getBuildElement(Document doc) {
    return doc.createElement(getClass().getName());
  }

  @Override
  public void build(Element e) {
  }

  @Override
  public void mousePressed(MouseEvent e) {
    if (e.isConsumed()) {
      return;
    }

    final KeyBuffer kbuf = KeyBuffer.getBuffer();

    GamePiece p = map.findPiece(e.getPoint(), PieceFinder.PIECE_IN_STACK);
    // Don't clear the buffer until we find the clicked-on piece
    // Because selecting a piece affects its visibility
    EventFilter filter = null;
    BandSelectType bandSelect = BandSelectType.NONE;
    if (p != null) {
      filter = (EventFilter) p.getProperty(Properties.SELECT_EVENT_FILTER);      
      if (!e.isPopupTrigger() && Boolean.TRUE.equals(p.getProperty(Properties.NON_MOVABLE))) {
        // Don't "eat" band-selects if unit found is non-movable
        bandSelect = BandSelectType.SPECIAL;
      }
    }

    boolean ignoreEvent = filter != null && filter.rejectEvent(e);
    if (p != null && !ignoreEvent) {
      boolean movingStacksPickupUnits = (Boolean) GameModule.getGameModule().getPrefs().getValue(Map.MOVING_STACKS_PICKUP_UNITS);
      if (!kbuf.contains(p)) {
        if (!e.isShiftDown() && !SwingUtils.isControlDown(e)) {
          kbuf.clear();
        }
        // RFE 1629255 - If the top piece of an unexpanded stack is left-clicked
        // while not selected, then select all of the pieces in the stack
        if (movingStacksPickupUnits ||
            p.getParent() == null ||
            p.getParent().isExpanded() ||
            SwingUtils.isRightMouseButton(e) ||
            Boolean.TRUE.equals(p.getProperty(Properties.SELECTED)))
        {
          kbuf.add(p);
        }
        else {
          Stack s = p.getParent();
          s.asList().forEach(gamePiece -> KeyBuffer.getBuffer().add(gamePiece));
        }
        // End RFE 1629255
      }
      else {
        // RFE 1659481 Ctrl-click deselects clicked units
        if (SwingUtils.isControlDown(e) && Boolean.TRUE.equals(p.getProperty(Properties.SELECTED))) {
          Stack s = p.getParent();
          if (s == null) {
            kbuf.remove(p);
          }
          else if (!s.isExpanded()) {
            s.asList().forEach(gamePiece -> KeyBuffer.getBuffer().remove(gamePiece));
          }
        }
        // End RFE 1659481
      }

      final GamePiece to_front = p.getParent() != null ? p.getParent() : p;
      map.getPieceCollection().moveToFront(to_front);
    }
    else {
      bandSelect = BandSelectType.NORMAL; //BR// Allowed to band-select  
    }
    
    if (bandSelect != BandSelectType.NONE) {
      bandSelectPiece = null;
      if (!e.isShiftDown() && !SwingUtils.isControlDown(e)) { // No deselect if shift key down
        kbuf.clear();
        <commit_msg>13196 toggle inside an expanded stack - was missing else case<commit_after>/*
 *
 * Copyright (c) 2000-2007 by <NAME>, <NAME>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License (LGPL) as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, copies are available
 * at http://www.opensource.org.
 */
package VASSAL.build.module.map;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;

import javax.swing.JComponent;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import VASSAL.build.Buildable;
import VASSAL.build.GameModule;
import VASSAL.build.module.Map;
import VASSAL.counters.ColoredBorder;
import VASSAL.counters.Deck;
import VASSAL.counters.DeckVisitor;
import VASSAL.counters.Decorator;
import VASSAL.counters.EventFilter;
import VASSAL.counters.GamePiece;
import VASSAL.counters.Immobilized;
import VASSAL.counters.KeyBuffer;
import VASSAL.counters.NonRectangular;
import VASSAL.counters.PieceFinder;
import VASSAL.counters.PieceVisitorDispatcher;
import VASSAL.counters.Properties;
import VASSAL.counters.Stack;
import VASSAL.tools.swing.SwingUtils;

/**
 * This component listens for mouse clicks on a map and draws the selection
 * rectangle.
 *
 * If the user clicks on a {@link GamePiece}, that piece is added to the
 * {@link KeyBuffer}. {@link #draw(Graphics, Map)} is responsible for
 * drawing the mouse selection rectangle, and
 * {@link #mouseDragged(MouseEvent)} is responsible for triggering repaint
 * events as the selection rectangle is moved.
 *
 * @see Map#addLocalMouseListener
 */
public class KeyBufferer extends MouseAdapter implements Buildable, MouseMotionListener, Drawable {
  protected Map map;
  protected Rectangle selection;
  protected Point anchor;
  protected Color color = Color.black;
  protected int thickness = 3;
  protected GamePiece bandSelectPiece = null;

  private enum BandSelectType {
    NONE,
    NORMAL,
    SPECIAL;
  }

  @Override
  public void addTo(Buildable b) {
    map = (Map) b;
    map.addLocalMouseListenerFirst(this);
    map.getView().addMouseMotionListener(this);
    map.addDrawComponent(this);
  }

  @Override
  public void add(Buildable b) {
  }

  @Override
  public Element getBuildElement(Document doc) {
    return doc.createElement(getClass().getName());
  }

  @Override
  public void build(Element e) {
  }

  @Override
  public void mousePressed(MouseEvent e) {
    if (e.isConsumed()) {
      return;
    }

    final KeyBuffer kbuf = KeyBuffer.getBuffer();

    GamePiece p = map.findPiece(e.getPoint(), PieceFinder.PIECE_IN_STACK);
    // Don't clear the buffer until we find the clicked-on piece
    // Because selecting a piece affects its visibility
    EventFilter filter = null;
    BandSelectType bandSelect = BandSelectType.NONE;
    if (p != null) {
      filter = (EventFilter) p.getProperty(Properties.SELECT_EVENT_FILTER);      
      if (!e.isPopupTrigger() && Boolean.TRUE.equals(p.getProperty(Properties.NON_MOVABLE))) {
        // Don't "eat" band-selects if unit found is non-movable
        bandSelect = BandSelectType.SPECIAL;
      }
    }

    boolean ignoreEvent = filter != null && filter.rejectEvent(e);
    if (p != null && !ignoreEvent) {
      boolean movingStacksPickupUnits = (Boolean) GameModule.getGameModule().getPrefs().getValue(Map.MOVING_STACKS_PICKUP_UNITS);
      if (!kbuf.contains(p)) {
        if (!e.isShiftDown() && !SwingUtils.isControlDown(e)) {
          kbuf.clear();
        }
        // RFE 1629255 - If the top piece of an unexpanded stack is left-clicked
        // while not selected, then select all of the pieces in the stack
        if (movingStacksPickupUnits ||
            p.getParent() == null ||
            p.getParent().isExpanded() ||
            SwingUtils.isRightMouseButton(e) ||
            Boolean.TRUE.equals(p.getProperty(Properties.SELECTED)))
        {
          kbuf.add(p);
        }
        else {
          Stack s = p.getParent();
          s.asList().forEach(gamePiece -> KeyBuffer.getBuffer().add(gamePiece));
        }
        // End RFE 1629255
      }
      else {
        // RFE 1659481 Ctrl-click deselects clicked units
        if (SwingUtils.isControlDown(e) && Boolean.TRUE.equals(p.getProperty(Properties.SELECTED))) {
          Stack s = p.getParent();
          if (s == null) {
            kbuf.remove(p);
          }
          else if (!s.isExpanded()) {
            s.asList().forEach(gamePiece -> KeyBuffer.getBuffer().remove(gamePiece));
          } 
          else {
            kbuf.remove(p);  
          }
        }
        // End RFE 1659481
      }

      final GamePiece to_front = p.getParent() != null ? p.getParent() : p;
      map.getPieceCollection().moveToFront(to_front);
    }
    else {
      bandSelect = BandSelectType.NORMAL; //BR// Allowed to band-select  
    }
    
    if (bandSelect != BandSelectType.NONE) {
      bandSelectPiece = null;
      if (!e.isShiftDown() && !SwingUtils.isControlDown(e)) { // No deselect if shift key down
        kbuf.clear();
        
{'fraction_non_alphanumeric': 0.10382562277580071, 'fraction_numerical': 0.007562277580071174, 'mean_word_length': 3.1085526315789473, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5155588', 'n_tokens_mistral': 3457, 'n_tokens_neox': 3364, 'n_words': 925}