All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.scudata.ide.common.swing.MonthlyCalendar Maven / Gradle / Ivy

Go to download

SPL(Structured Process Language) A programming language specially for structured data computing.

There is a newer version: 20240823
Show newest version
package com.scudata.ide.common.swing;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.Calendar;

import javax.swing.JComponent;
import javax.swing.border.Border;

import com.scudata.app.common.Section;
import com.scudata.ide.common.resources.IdeCommonMessage;

/**
 * Monthly Calendar organized in weeks.
 */

public class MonthlyCalendar extends JComponent implements MouseListener,
		MouseMotionListener {
	private static final long serialVersionUID = 1L;

	/** Default symbols to be displayed for the header */
	public static String[] DEFAULT_HEADER_SYMBOLS;

	/** Default font to be used */
	public static Font DEFAULT_FONT;

	/** Default background color of the header */
	public static final Color DEFAULT_HEADER_BG = new Color(0x7A, 0x96, 0xDF);

	/** Default foreground color of the header */
	public static final Color DEFAULT_HEADER_FG = new Color(0xD8, 0xE4, 0xF8);

	/** Default background color of the date */
	public static final Color DEFAULT_DATE_BG = Color.white;

	/** Default foreground color of the date */
	public static final Color DEFAULT_DATE_FG = Color.black;

	/** Default background color of highlighted date */
	public static final Color DEFAULT_HIGHLIGHT_BG = new Color(0x00, 0x54, 0xE3);

	/** Default foreground color of highlighted date */
	public static final Color DEFAULT_HIGHLIGHT_FG = Color.white;

	/** Default cell width */
	public static final int DEFAULT_CELL_WIDTH = 24;

	/** Default cell height */
	public static final int DEFAULT_CELL_HEIGHT = 18;

	/** Array to hold date distribution information */
	private int[] dateData = new int[42];

	/** Year value for this calendar */
	private int year = -1;

	/** Month value for this calendar */
	private int month = -1;

	/** Index in the date data array for the highlighted date */
	private int hindex = -1;

	/** Selected date */
	private int selectedDate = 0;

	/** if true, week starts with Sunday; else week starts with Monday */
	private boolean startOnSunday = true;

	/** Cell width */
	private int cellWidth = DEFAULT_CELL_WIDTH;

	/** Cell height */
	private int cellHeight = DEFAULT_CELL_HEIGHT;

	/** Header font */
	private Font headerFont = DEFAULT_FONT;

	/** Date font */
	private Font dateFont = DEFAULT_FONT;

	/** Header background */
	private Color headerBg = DEFAULT_HEADER_BG;

	/** Header foreground */
	private Color headerFg = DEFAULT_HEADER_FG;

	/** Date background */
	private Color dateBg = DEFAULT_DATE_BG;

	/** Date foreground */
	private Color dateFg = DEFAULT_DATE_FG;

	/** Highlighted date background */
	private Color highBg = DEFAULT_HIGHLIGHT_BG;

	/** Highlighted date foreground */
	private Color highFg = DEFAULT_HIGHLIGHT_FG;

	/** User installed header component */
	private JComponent headerComponent;

	/** Keep ref to preferredsize to avoid multiple instantiation of objects */
	private Dimension pSize;

	/**
	 * When border are added, origin of graphics will shift; else, origin at(0,
	 * 0)
	 */
	private int basex = 0;

	/**
	 * When border are added, origin of graphics will shift; else, origin at(0,
	 * 0)
	 */
	private int basey = 0;

	/**
	 * Variable keep track of whether "this" MouseListener+MouseMotionListenre
	 * is installed
	 */
	private boolean isListening;

	/** Default constructor */
	public MonthlyCalendar() {
		loadLanguageString();
		pSize = new Dimension(cellWidth * 7, cellHeight * 7);
		super.setPreferredSize(pSize);
		setMouseListeningEnabled(true);
	}

	/**
	 * ??????????Դ
	 */
	private void loadLanguageString() {
		DEFAULT_HEADER_SYMBOLS = new Section(IdeCommonMessage.get().getMessage(
				"monthlycalendar.weekdays")).toStringArray(); // ??, һ, ??, ??, ??,
		// ??, ??
		DEFAULT_FONT = new java.awt.Font("Dialog", 0, 12);
	}

	/**
	 * Bean method. Once disabled, there will be no highlighting effect and no
	 * "date selection event".
	 */
	public void setMouseListeningEnabled(boolean b) {
		if (b && !isListening) {
			addMouseListener(this);
			addMouseMotionListener(this);
		} else if (!b && isListening) {
			removeMouseListener(this);
			removeMouseMotionListener(this);
		}
		isListening = b;
	}

	/** Bean method. */
	public boolean getMouseListeningEnabled() {
		return isListening;
	}

	/** Bean method */
	public void setYear(int year) {
		if (year < 1970) {
			throw new IllegalArgumentException("Year must be later than 1970!");
		}
		if (month != -1) {
			setYearMonth(year, month);
		} else {
			this.year = year;
		}
	}

	/** Bean method */
	public int getYear() {
		return year;
	}

	/** Bean method */
	public void setMonth(int month) {
		if (month < 1 || month > 12) {
			throw new IllegalArgumentException("Invalid month specified!");
		}
		if (year != -1) {
			setYearMonth(year, month);
		} else {
			this.month = month;
		}
	}

	/** Bean method */
	public int getMonth() {
		return month;
	}

	/** Convinent method to set year and month */
	public void setYearMonth(int year, int month) {
		// NOTE: JANUARY = 0 in Calendar object.
		if (this.year == year && this.month == month) {
			return;
		}
		Calendar calendar = Calendar.getInstance();
		calendar.set(year, month - 1, 1);
		setYearMonth(calendar);
	}

	/** Convinent method to set year and month */
	public void setYearMonth(Calendar calendar) {
		// NOTE: Calendar.SUNDAY = 1;
		// Calendar.MONDAY = 2;
		// Calendar.TUESDAY = 3; ... Calendar.SATURDAY = 6;
		int y = calendar.get(Calendar.YEAR);
		int m = calendar.get(Calendar.MONTH) + 1;
		int d = calendar.get(Calendar.DAY_OF_MONTH);

		calendar.set(Calendar.DAY_OF_MONTH, 1);
		int max = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
		int start = calendar.get(Calendar.DAY_OF_WEEK);
		if (startOnSunday) {
			start = start - 1;
		} else {
			start = (start + 5) % 7;
		}
		hindex = d + start - 1;
		if (year == y && month == m) {
			return;
		}
		year = y;
		month = m;

		int backupDate = calendar.get(Calendar.DAY_OF_MONTH);

		for (int i = 0; i < start; i++) {
			dateData[i] = -1;
		}
		for (int i = 0; i < max; i++) {
			dateData[i + start] = i + 1;
		}
		for (int i = start + max; i < 42; i++) {
			dateData[i] = -1;
		}
		// restore old day of month value
		calendar.set(Calendar.DAY_OF_MONTH, backupDate);
	}

	/** Bean method */
	public void setWeekStartOnSunday(boolean b) {
		startOnSunday = b;
	}

	/** Bean method */
	public boolean getWeekStartOnSunday() {
		return startOnSunday;
	}

	/** Bean method */
	public void setHeaderFont(Font font) {
		headerFont = font;
	}

	/** Bean method */
	public Font getHeaderFont() {
		return headerFont;
	}

	/** Bean method */
	public void setDateFont(Font font) {
		dateFont = font;
	}

	/** Bean method */
	public Font getDateFont() {
		return dateFont;
	}

	/** Bean method */
	public void setHeaderBackground(Color c) {
		headerBg = c;
	}

	/** Bean method */
	public Color getHeaderBackground() {
		return headerBg;
	}

	/** Bean method */
	public void setHeaderForeground(Color c) {
		headerFg = c;
	}

	/** Bean method */
	public Color getHeaderForeground() {
		return headerFg;
	}

	/** Bean method */
	public void setDateBackground(Color c) {
		dateBg = c;
	}

	/** Bean method */
	public Color getDateBackground() {
		return dateBg;
	}

	/** Bean method */
	public void setDateForeground(Color c) {
		dateFg = c;
	}

	/** Bean method */
	public Color getDateForeground() {
		return dateFg;
	}

	/** Bean method */
	public void setHighlightBackground(Color c) {
		highBg = c;
	}

	/** Bean method */
	public Color getHighlightBackground() {
		return highBg;
	}

	/** Bean method */
	public void setHighlightForeground(Color c) {
		highFg = c;
	}

	/** Bean method */
	public Color getHighlightForeground() {
		return highFg;
	}

	/**
	 * Bean method. Note: if headerComponent is set, calling this method will
	 * have no effect.
	 */
	public void setCellDimension(Dimension d) {
		if (headerComponent != null) {
			return;
		}
		cellWidth = d.width;
		cellHeight = d.height;
		resize();
	}

	/** Bean method */
	public Dimension getCellDimension() {
		return new Dimension(cellWidth, cellHeight);
	}

	/**
	 * This method will be called in three occasions: (1) when cell dimension is
	 * set; (2) when header component is set; (3) when border is set. It makes
	 * sure the preferredSize of the component is set properly: if header
	 * component is not set, simply use the cell dimension to determine the
	 * preferredSize; if header component is set, use the header component size
	 * to determine cell dimension, and then determine the preferred size. if
	 * border of the component is set, the preferredSize will be incremented to
	 * include the border insets.
	 */
	private void resize() {
		Border border = getBorder();
		int aw, ah;
		if (border != null) {
			Insets insets = border.getBorderInsets(this);
			aw = insets.left + insets.right;
			ah = insets.top + insets.bottom;
			basex = insets.left;
			basey = insets.top;
		} else {
			aw = ah = basex = basey = 0;
		}
		if (headerComponent == null) {
			pSize.width = cellWidth * 7 + aw;
			pSize.height = cellHeight * 7 + ah;
		} else {
			Dimension d = headerComponent.getPreferredSize();
			cellWidth = d.width / 7;
			cellHeight = d.height;
			pSize.width = cellWidth * 7 + d.width % 7 + aw;
			pSize.height = cellHeight * 7 + ah;
			headerComponent.setBounds(basex, basey, d.width, d.height);
		}
		super.setPreferredSize(pSize);
	}

	/**
	 * Override parent class setBorder method to make sure border insets is
	 * included.
	 */
	public void setBorder(Border border) {
		super.setBorder(border);
		resize();
	}

	/**
	 * Bean method. If header component is set, the default header will not
	 * display anymore.
	 */
	public void setHeaderComponent(JComponent comp) {
		removeAll();
		headerComponent = comp;
		if (comp != null) {
			add(comp);
		}
		resize();
	}

	/** Bean method */
	public JComponent getHeaderComponent() {
		return headerComponent;
	}

	/**
	 * This method is blank implemented to disable it. The size of the component
	 * is controlled by the cell dimension. Method is finalized to prevent
	 * subclass overriding.
	 */
	public final void setPreferredSize(Dimension d) {
	}

	/**
	 * Draw the graphics. Method is finalized to prevent subclass overriding.
	 */
	protected final void paintComponent(Graphics g) {
		super.paintComponent(g);

		// default header will be displayed if no header component is installed
		if (headerComponent == null) {
			for (int i = 0; i < 7; i++) {
				int shift;
				if (startOnSunday) {
					shift = i;
				} else {
					shift = (i + 6) % 7;
				}
				int x = shift * cellWidth;
				int y = 0;
				paintSymbol(g, headerFont, headerBg, headerFg,
						DEFAULT_HEADER_SYMBOLS[i], basex + x, basey + y,
						cellWidth, cellHeight);
			}
		}

		if (year != -1 && month != -1) {
			for (int i = 0; i < 42; i++) {
				int x = cellWidth * (i % 7);
				int y = cellHeight * (i / 7 + 1);
				if (dateData[i] == -1) {
					paintSymbol(g, dateFont, dateBg, dateFg, null, basex + x,
							basey + y, cellWidth, cellHeight);
				} else {
					if (hindex == i) {
						paintSymbol(g, dateFont, highBg, highFg,
								String.valueOf(dateData[i]), basex + x, basey
										+ y, cellWidth, cellHeight);
					} else {
						paintSymbol(g, dateFont, dateBg, dateFg,
								String.valueOf(dateData[i]), basex + x, basey
										+ y, cellWidth, cellHeight);
					}
				}
			}
		} // end if
	}

	/**
	 * This will fill a rectangle area specified by x, y, w, h using bg color.
	 * If String s is not null, it will also paint the specified String s at the
	 * center of the rectangle using the specified font and fg color.
	 */
	public static void paintSymbol(Graphics g, Font f, Color bg, Color fg,
			String s, int x, int y, int w, int h) {
		if (s == null) {
			g.setColor(bg);
			g.fillRect(x, y, w, h);
		} else {
			g.setFont(f);
			FontMetrics fm = g.getFontMetrics();
			int sx = (w - fm.stringWidth(s)) / 2;
			int sy = (h - fm.getHeight()) / 2 + fm.getAscent();
			g.setColor(bg);
			g.fillRect(x, y, w, h);
			g.setColor(fg);
			g.drawString(s, x + sx, y + sy);
		}
	}

	/**
	 * Reset highlighted date. Use in combination with repaint().
	 */
	public void resetHighlight() {
		hindex = -1;
	}

	public int getSelectedIndex() {
		return hindex;
	}

	/** Returns only the DAY_OF_MONTH date value */
	public int getSelectedDay() {
		return selectedDate;
	}

	/** Return YEAR+MONTH+DAY_OF_MONTH as a Calendar object */
	public Calendar getSelectedDate() {
		Calendar cal = Calendar.getInstance();
		cal.set(year, month - 1, selectedDate);
		return cal;
	}

	/**
	 * Implementation of MouseListener interface method. User program should
	 * ignore this method. Method is finalized to prevent subclass overriding.
	 */
	public final void mouseEntered(MouseEvent e) {
		if (e.getSource() != this) {
			throw new RuntimeException(
					"You are not supposed to install 'this' "
							+ "mouse handler to any component other than itself.");
		}
	}

	/**
	 * Implementation of MouseListener interface method. User program should
	 * ignore this method. Method is finalized to prevent subclass overriding.
	 */
	public final void mouseExited(MouseEvent e) {
		if (e.getSource() != this) {
			throw new RuntimeException(
					"You are not supposed to install 'this' "
							+ "mouse handler to any component other than itself.");
		}
		// hindex = -1;
		repaint();
	}

	/**
	 * Implementation of MouseListener interface method. User program should
	 * ignore this method. Method is finalized to prevent subclass overriding.
	 */
	public final void mouseClicked(MouseEvent e) {
		if (e.getSource() != this) {
			throw new RuntimeException(
					"You are not supposed to install 'this' "
							+ "mouse handler to any component other than itself.");
		}
		// get selected date
		// int x = e.getX();
		// int y = e.getY();
		// int i = x / cellWidth;
		// int j = y / cellHeight;
		// j--;

		int x = e.getX() - basex;
		int y = e.getY() - basey - cellHeight;
		int width = cellWidth * 7;
		int height = cellHeight * 6;
		if (x < 0 || x >= width || y < 0 || y >= height) {
			if (hindex != -1) {
				// hindex = -1;
				repaint();
			}
			return;
		}
		int i = x / cellWidth;
		int j = y / cellHeight;
		if (dateData[j * 7 + i] != -1) {
			hindex = j * 7 + i;
		} else {
			hindex = -1;
		}

		if (j >= 0 && dateData[j * 7 + i] != -1) {
			selectedDate = dateData[j * 7 + i];
			dateSelected();
		} else {
			selectedDate = 0;
		}
		repaint();
	}

	/**
	 * Implementation of MouseListener interface method. User program should
	 * ignore this method. Method is finalized to prevent subclass overriding.
	 */
	public final void mousePressed(MouseEvent e) {
		if (e.getSource() != this) {
			throw new RuntimeException(
					"You are not supposed to install 'this' "
							+ "mouse handler to any component other than itself.");
		}
	}

	/**
	 * Implementation of MouseListener interface method. User program should
	 * ignore this method. Method is finalized to prevent subclass overriding.
	 */
	public final void mouseReleased(MouseEvent e) {
		if (e.getSource() != this) {
			throw new RuntimeException(
					"You are not supposed to install 'this' "
							+ "mouse handler to any component other than itself.");
		}
	}

	/**
	 * Implementation of MouseMotionListener interface method. User program
	 * should ignore this method. Method is finalized to prevent subclass
	 * overriding.
	 */
	public final void mouseMoved(MouseEvent e) {
		if (e.getSource() != this) {
			throw new RuntimeException(
					"You are not supposed to install 'this' "
							+ "mouse motion handler to any component other than itself.");
		}
		mousePositionChanged(e);
	}

	/**
	 * Implementation of MouseMotionListener interface method. User program
	 * should ignore this method. Method is finalized to prevent subclass
	 * overriding.
	 */
	public final void mouseDragged(MouseEvent e) {
		if (e.getSource() != this) {
			throw new RuntimeException(
					"You are not supposed to install 'this' "
							+ "mouse motion handler to any component other than itself.");
		}
		mousePositionChanged(e);
	}

	/** Called by mouseDragged and mouseMoved method */
	private void mousePositionChanged(MouseEvent e) {
		// int x = e.getX() - basex;
		// int y = e.getY() - basey - cellHeight;
		// int width = cellWidth * 7;
		// int height = cellHeight * 6;
		// if (x < 0 || x >= width || y < 0 || y >= height) {
		// if (hindex != -1) {
		// hindex = -1;
		// repaint();
		// }
		// return;
		// }
		// int i = x / cellWidth;
		// int j = y / cellHeight;
		// if (dateData[j * 7 + i] != -1) {
		// hindex = j * 7 + i;
		// }
		// else {
		// hindex = -1;
		// }
		// repaint();
	}

	/**
	 * This method will be called when the "date selection event" occurs. The
	 * implementation of the method is left empty. Subclasses should override
	 * this method to specify "event handling code".
	 */
	protected void dateSelected() {
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy