├── doc ├── date.png ├── time.png ├── year.png ├── disable.png └── year_month.png ├── lib └── com.patrikdufresne.fontawesome-5.0.0.jar ├── src ├── main │ └── java │ │ └── cn │ │ └── nextop │ │ └── thorin │ │ └── rcp │ │ └── support │ │ ├── swt │ │ ├── widget │ │ │ └── xcalendar │ │ │ │ ├── event │ │ │ │ ├── reactor │ │ │ │ │ ├── XCalendarReactor.java │ │ │ │ │ ├── XCalendarAction.java │ │ │ │ │ └── impl │ │ │ │ │ │ ├── action │ │ │ │ │ │ ├── XCalendarSetupAction.java │ │ │ │ │ │ ├── XCalendarFeedAction.java │ │ │ │ │ │ ├── XCalendarResizeAction.java │ │ │ │ │ │ ├── XCalendarSelectAction.java │ │ │ │ │ │ └── AbstractXCalendarAction.java │ │ │ │ │ │ └── XCalendarDefaultRector.java │ │ │ │ ├── XCalendarEvent.java │ │ │ │ ├── listener │ │ │ │ │ └── XCalendarEventListener.java │ │ │ │ ├── bus │ │ │ │ │ ├── internal │ │ │ │ │ │ ├── XCalendarMouseUpEvent.java │ │ │ │ │ │ ├── XCalendarMouseDownEvent.java │ │ │ │ │ │ ├── XCalendarMouseEnterEvent.java │ │ │ │ │ │ ├── XCalendarMouseLeaveEvent.java │ │ │ │ │ │ ├── XCalendarMouseMoveEvent.java │ │ │ │ │ │ └── XCalendarMouseEvent.java │ │ │ │ │ ├── external │ │ │ │ │ │ ├── XCalendarFeedEvent.java │ │ │ │ │ │ └── XCalendarSelectEvent.java │ │ │ │ │ ├── AbstractXCalendarEvent.java │ │ │ │ │ ├── XCalendarDefaultEventBus.java │ │ │ │ │ └── AbstractXCalendarEventBus.java │ │ │ │ ├── handler │ │ │ │ │ ├── XCalendarEventHandler.java │ │ │ │ │ └── impl │ │ │ │ │ │ ├── AbstractXCalendarEventHandler.java │ │ │ │ │ │ └── XCalendarDefaultEventHandler.java │ │ │ │ └── XCalendarEventBus.java │ │ │ │ ├── model │ │ │ │ ├── config │ │ │ │ │ ├── render │ │ │ │ │ │ ├── XCalendarRender.java │ │ │ │ │ │ ├── XCalendarFrame.java │ │ │ │ │ │ └── impl │ │ │ │ │ │ │ └── XCalendarDefaultRender.java │ │ │ │ │ ├── layout │ │ │ │ │ │ ├── XCalendarLayout.java │ │ │ │ │ │ └── impl │ │ │ │ │ │ │ └── XCalendarDefaultLayout.java │ │ │ │ │ ├── widget │ │ │ │ │ │ ├── XCalendarWidget.java │ │ │ │ │ │ ├── impl │ │ │ │ │ │ │ ├── XCalendarTextWidget.java │ │ │ │ │ │ │ ├── XCalendarNextWidget.java │ │ │ │ │ │ │ ├── XCalendarPrevWidget.java │ │ │ │ │ │ │ ├── XCalendarClearWidget.java │ │ │ │ │ │ │ ├── XCalendarSelectWidget.java │ │ │ │ │ │ │ ├── XCalendarSelectTodayWidget.java │ │ │ │ │ │ │ ├── XCalendarSelectTimeWidget.java │ │ │ │ │ │ │ ├── XCalendarHourWidget.java │ │ │ │ │ │ │ ├── XCalendarDecrWidget.java │ │ │ │ │ │ │ ├── XCalendarIncrWidget.java │ │ │ │ │ │ │ ├── XCalendarMinuteWidget.java │ │ │ │ │ │ │ ├── XCalendarSecondWidget.java │ │ │ │ │ │ │ ├── XCalendarTimeWidget.java │ │ │ │ │ │ │ ├── XCalendarYearWidget.java │ │ │ │ │ │ │ ├── XCalendarMonthWidget.java │ │ │ │ │ │ │ ├── XCalendarDecadeWidget.java │ │ │ │ │ │ │ └── XCalendarDayWidget.java │ │ │ │ │ │ ├── AbstractXCalendarWidget.java │ │ │ │ │ │ └── XCalendarWidgetFactory.java │ │ │ │ │ └── XCalendarConfig.java │ │ │ │ ├── theme │ │ │ │ │ ├── XCalendarThemeFactory.java │ │ │ │ │ ├── impl │ │ │ │ │ │ ├── XCalendarThemeJp.java │ │ │ │ │ │ └── XCalendarThemeEn.java │ │ │ │ │ └── XCalendarTheme.java │ │ │ │ └── XCalendarModel.java │ │ │ │ ├── support │ │ │ │ ├── glossary │ │ │ │ │ ├── XCalendarTime.java │ │ │ │ │ └── XCalendarState.java │ │ │ │ ├── tracker │ │ │ │ │ └── XCalendarMouseTracker.java │ │ │ │ ├── fsm │ │ │ │ │ └── XCalendarStateMachine.java │ │ │ │ ├── XVirtualCalendar.java │ │ │ │ └── XCalendarUtils.java │ │ │ │ └── XCalendar.java │ │ └── utility │ │ │ ├── graphics │ │ │ ├── Cursors.java │ │ │ ├── Extents.java │ │ │ ├── Colors.java │ │ │ └── Fonts.java │ │ │ └── SwtUtils.java │ │ └── util │ │ ├── collection │ │ └── map │ │ │ ├── LruMap.java │ │ │ └── ConcurrentMultiKeyMap.java │ │ ├── type │ │ ├── Pair.java │ │ └── Range.java │ │ ├── Objects.java │ │ └── Strings.java └── test │ └── java │ └── cn │ └── nextop │ └── thorin │ └── rcp │ └── support │ └── swt │ └── widget │ └── xcalendar │ └── XDateTimeSnippet.java ├── .gitignore ├── README.md ├── pom.xml └── LICENSE /doc/date.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nextopcn/xcalendar/HEAD/doc/date.png -------------------------------------------------------------------------------- /doc/time.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nextopcn/xcalendar/HEAD/doc/time.png -------------------------------------------------------------------------------- /doc/year.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nextopcn/xcalendar/HEAD/doc/year.png -------------------------------------------------------------------------------- /doc/disable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nextopcn/xcalendar/HEAD/doc/disable.png -------------------------------------------------------------------------------- /doc/year_month.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nextopcn/xcalendar/HEAD/doc/year_month.png -------------------------------------------------------------------------------- /lib/com.patrikdufresne.fontawesome-5.0.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nextopcn/xcalendar/HEAD/lib/com.patrikdufresne.fontawesome-5.0.0.jar -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/event/reactor/XCalendarReactor.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.reactor; 2 | 3 | /** 4 | * 5 | * @author Jingqi Xu 6 | */ 7 | public interface XCalendarReactor { 8 | 9 | void submit(XCalendarAction action); 10 | } 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | /target 3 | 4 | # Mobile Tools for Java (J2ME) 5 | .mtj.tmp/ 6 | 7 | # Package Files # 8 | *.war 9 | *.ear 10 | 11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 12 | hs_err_pid* 13 | /.idea/ 14 | /.idea/* 15 | 16 | # eclipse 17 | /.classpath 18 | /.project 19 | 20 | # idea 21 | /xcalendar.iml -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/event/XCalendarEvent.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event; 2 | 3 | import org.eclipse.swt.widgets.Event; 4 | 5 | /** 6 | * 7 | * @author Jingqi Xu 8 | */ 9 | public interface XCalendarEvent { 10 | 11 | Event getSource(); 12 | 13 | boolean isDoit(); void setDoit(boolean doit); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/event/listener/XCalendarEventListener.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.listener; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.XCalendarEvent; 4 | 5 | /** 6 | * 7 | * @author Jingqi Xu 8 | */ 9 | public interface XCalendarEventListener { 10 | 11 | void onEvent(XCalendarEvent event); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/model/config/render/XCalendarRender.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.render; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 4 | import org.eclipse.swt.graphics.GC; 5 | 6 | /** 7 | * @author chenby 8 | * 9 | */ 10 | public interface XCalendarRender { 11 | void render(XCalendar popup, GC gc); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/event/bus/internal/XCalendarMouseUpEvent.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.internal; 2 | 3 | import org.eclipse.swt.widgets.Event; 4 | 5 | /** 6 | * 7 | * @author Jingqi Xu 8 | */ 9 | public class XCalendarMouseUpEvent extends XCalendarMouseEvent { 10 | 11 | /** 12 | * 13 | */ 14 | public XCalendarMouseUpEvent(Event event) { 15 | super(event); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/event/bus/internal/XCalendarMouseDownEvent.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.internal; 2 | 3 | import org.eclipse.swt.widgets.Event; 4 | 5 | /** 6 | * 7 | * @author Jingqi Xu 8 | */ 9 | public class XCalendarMouseDownEvent extends XCalendarMouseEvent { 10 | 11 | /** 12 | * 13 | */ 14 | public XCalendarMouseDownEvent(Event event) { 15 | super(event); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/event/bus/internal/XCalendarMouseEnterEvent.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.internal; 2 | 3 | import org.eclipse.swt.widgets.Event; 4 | 5 | /** 6 | * 7 | * @author Jingqi Xu 8 | */ 9 | public class XCalendarMouseEnterEvent extends XCalendarMouseEvent { 10 | 11 | /** 12 | * 13 | */ 14 | public XCalendarMouseEnterEvent(Event event) { 15 | super(event); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/event/bus/internal/XCalendarMouseLeaveEvent.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.internal; 2 | 3 | import org.eclipse.swt.widgets.Event; 4 | 5 | /** 6 | * 7 | * @author Jingqi Xu 8 | */ 9 | public class XCalendarMouseLeaveEvent extends XCalendarMouseEvent { 10 | 11 | /** 12 | * 13 | */ 14 | public XCalendarMouseLeaveEvent(Event event) { 15 | super(event); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/event/bus/internal/XCalendarMouseMoveEvent.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.internal; 2 | 3 | import org.eclipse.swt.widgets.Event; 4 | 5 | /** 6 | * 7 | * @author Jingqi Xu 8 | */ 9 | public class XCalendarMouseMoveEvent extends XCalendarMouseEvent { 10 | 11 | /** 12 | * 13 | */ 14 | public XCalendarMouseMoveEvent(Event event) { 15 | super(event); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/event/reactor/XCalendarAction.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.reactor; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 4 | 5 | /** 6 | * 7 | * @author Jingqi Xu 8 | */ 9 | public interface XCalendarAction { 10 | 11 | /** 12 | * 13 | */ 14 | Type getType(); 15 | 16 | void apply(XCalendar calendar); 17 | 18 | /** 19 | * 20 | */ 21 | enum Type { FEED, SETUP, SELECT, RESIZE; } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/event/bus/internal/XCalendarMouseEvent.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.internal; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.AbstractXCalendarEvent; 4 | import org.eclipse.swt.widgets.Event; 5 | 6 | /** 7 | * 8 | * @author Jingqi Xu 9 | */ 10 | public class XCalendarMouseEvent extends AbstractXCalendarEvent { 11 | 12 | /** 13 | * 14 | */ 15 | public XCalendarMouseEvent(Event event) { 16 | super(event); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/model/config/layout/XCalendarLayout.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.layout; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 4 | import org.eclipse.swt.graphics.Rectangle; 5 | import org.eclipse.swt.widgets.Composite; 6 | 7 | /** 8 | * 9 | * @author Jingqi Xu 10 | */ 11 | public interface XCalendarLayout { 12 | 13 | /** 14 | * 15 | */ 16 | void layout(XCalendar calendar); 17 | 18 | void layout(XCalendar calendar, Composite parent, Rectangle bounds); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/event/handler/XCalendarEventHandler.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.handler; 2 | 3 | import org.eclipse.swt.widgets.Event; 4 | 5 | /** 6 | * 7 | * @author Jingqi Xu 8 | */ 9 | public interface XCalendarEventHandler { 10 | 11 | /** 12 | * 13 | */ 14 | int getPriority(); 15 | 16 | boolean handle(Context context, Event event); 17 | 18 | /** 19 | * 20 | */ 21 | interface Context { 22 | 23 | XCalendarEventHandler getFocus(); 24 | 25 | void setFocus(XCalendarEventHandler handler); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/event/XCalendarEventBus.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.handler.XCalendarEventHandler; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.listener.XCalendarEventListener; 5 | import org.eclipse.swt.widgets.Event; 6 | 7 | /** 8 | * 9 | * @author Jingqi Xu 10 | */ 11 | public interface XCalendarEventBus { 12 | 13 | /** 14 | * 15 | */ 16 | void handle(Event event); 17 | 18 | boolean addHandler(XCalendarEventHandler reactor); 19 | 20 | boolean delHandler(XCalendarEventHandler reactor); 21 | 22 | /** 23 | * 24 | */ 25 | void publish(XCalendarEvent event); 26 | 27 | boolean addListener(XCalendarEventListener listener); 28 | 29 | boolean delListener(XCalendarEventListener listener); 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/event/bus/external/XCalendarFeedEvent.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.external; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.AbstractXCalendarEvent; 4 | import org.eclipse.swt.widgets.Event; 5 | 6 | import javax.annotation.Nullable; 7 | import java.util.Date; 8 | 9 | /** 10 | * 11 | * @author Baoyi Chen 12 | */ 13 | public class XCalendarFeedEvent extends AbstractXCalendarEvent { 14 | // 15 | private final Date value; 16 | 17 | /** 18 | * 19 | */ 20 | public Date getValue() { 21 | return value; 22 | } 23 | 24 | /** 25 | * 26 | */ 27 | public XCalendarFeedEvent(@Nullable Date value) { 28 | this(null, value); 29 | } 30 | 31 | public XCalendarFeedEvent(Event source, @Nullable Date value) { 32 | super(source); this.value = value; 33 | } 34 | } -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/utility/graphics/Cursors.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.utility.graphics; 2 | 3 | import org.eclipse.swt.SWT; 4 | import org.eclipse.swt.graphics.Cursor; 5 | 6 | import static org.eclipse.swt.widgets.Display.getDefault; 7 | 8 | /** 9 | * 10 | * @author Jingqi Xu 11 | */ 12 | public final class Cursors { 13 | // 14 | public static final Cursor CURSOR_WAIT = getDefault().getSystemCursor(SWT.CURSOR_WAIT); 15 | public static final Cursor CURSOR_HAND = getDefault().getSystemCursor(SWT.CURSOR_HAND); 16 | public static final Cursor CURSOR_IBEAM = getDefault().getSystemCursor(SWT.CURSOR_IBEAM); 17 | public static final Cursor CURSOR_ARROW = getDefault().getSystemCursor(SWT.CURSOR_ARROW); 18 | public static final Cursor CURSOR_SIZENS = getDefault().getSystemCursor(SWT.CURSOR_SIZENS); 19 | public static final Cursor CURSOR_SIZEWE = getDefault().getSystemCursor(SWT.CURSOR_SIZEWE); 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/event/reactor/impl/action/XCalendarSetupAction.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.reactor.impl.action; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 4 | 5 | import java.util.Date; 6 | import java.util.function.Predicate; 7 | 8 | /** 9 | * 10 | * @author Baoyi Chen 11 | */ 12 | public class XCalendarSetupAction extends AbstractXCalendarAction { 13 | // 14 | private final boolean nullable; 15 | private final Predicate predicate; 16 | 17 | /** 18 | * 19 | */ 20 | public XCalendarSetupAction(Predicate v1, boolean v2) { 21 | super(Type.SETUP); this.predicate = v1; this.nullable = v2; 22 | } 23 | 24 | /** 25 | * 26 | */ 27 | @Override 28 | public void apply(XCalendar calendar) { 29 | calendar.getModel().setNullable(this.nullable); 30 | calendar.getModel().getCalendar().setFilter(this.predicate); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/event/reactor/impl/XCalendarDefaultRector.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.reactor.impl; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.reactor.XCalendarAction; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.reactor.XCalendarReactor; 6 | 7 | /** 8 | * 9 | * @author Jingqi Xu 10 | */ 11 | public class XCalendarDefaultRector implements XCalendarReactor { 12 | // 13 | protected XCalendar calendar; 14 | 15 | /** 16 | * 17 | */ 18 | public XCalendarDefaultRector(XCalendar calendar) { 19 | this.calendar = calendar; 20 | } 21 | 22 | /** 23 | * 24 | */ 25 | @Override 26 | public void submit(XCalendarAction action) { 27 | if(this.calendar.isDisposed()) return; 28 | this.calendar.getDisplay().syncExec(() -> { action.apply(this.calendar); }); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/util/collection/map/LruMap.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.util.collection.map; 2 | 3 | import java.util.LinkedHashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * 8 | * @author Jingqi Xu 9 | */ 10 | public final class LruMap extends LinkedHashMap { 11 | // 12 | private static final long serialVersionUID = -366538766679345583L; 13 | 14 | // 15 | private final int capacity; 16 | 17 | /** 18 | * 19 | */ 20 | public LruMap(int capacity) { 21 | this(capacity, true); 22 | } 23 | 24 | public LruMap(int capacity, boolean accessOrder) { 25 | super(capacity + 1, 1, accessOrder); 26 | if(capacity < 1) throw new IllegalArgumentException("invalid parameter capacity: " + capacity); 27 | this.capacity = capacity; 28 | } 29 | 30 | /** 31 | * 32 | */ 33 | public int getCapacity() { 34 | return capacity; 35 | } 36 | 37 | /** 38 | * 39 | */ 40 | protected boolean removeEldestEntry(Map.Entry eldest) { 41 | return size() > this.capacity; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/model/config/render/XCalendarFrame.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.render; 2 | 3 | import org.eclipse.swt.graphics.GC; 4 | import org.eclipse.swt.graphics.Rectangle; 5 | import org.eclipse.swt.graphics.Transform; 6 | 7 | /** 8 | * 9 | * @author Jingqi Xu 10 | */ 11 | public class XCalendarFrame implements AutoCloseable { 12 | // 13 | private GC gc; 14 | private Transform transform; 15 | 16 | /** 17 | * 18 | */ 19 | public XCalendarFrame(GC gc, Transform transform) { 20 | this.gc = gc; this.transform = transform; 21 | } 22 | 23 | /** 24 | * 25 | */ 26 | public final GC getGc() { 27 | return gc; 28 | } 29 | 30 | public Transform getTransform() { 31 | return transform; 32 | } 33 | 34 | /** 35 | * 36 | */ 37 | @Override 38 | public void close() { 39 | if(this.gc.isDisposed()) return; 40 | gc.setClipping((Rectangle)null); 41 | if(transform != null && !transform.isDisposed()) transform.dispose(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/model/theme/XCalendarThemeFactory.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.theme; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.theme.impl.XCalendarThemeEn; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.theme.impl.XCalendarThemeJp; 5 | 6 | import java.util.HashMap; 7 | import java.util.Locale; 8 | import java.util.Map; 9 | 10 | /** 11 | * 12 | * @author Baoyi Chen 13 | */ 14 | public class XCalendarThemeFactory { 15 | // 16 | private Map map = new HashMap<>(); 17 | 18 | /** 19 | * 20 | */ 21 | public XCalendarThemeFactory() { 22 | register(Locale.ENGLISH, new XCalendarThemeEn()); 23 | register(Locale.JAPANESE, new XCalendarThemeJp()); 24 | } 25 | 26 | /** 27 | * 28 | */ 29 | public XCalendarTheme create(Locale locale) { 30 | return map.getOrDefault(locale, new XCalendarThemeEn()); 31 | } 32 | 33 | /** 34 | * 35 | */ 36 | protected void register(Locale locale, XCalendarTheme theme) { 37 | map.put(locale, theme); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/event/reactor/impl/action/XCalendarFeedAction.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.reactor.impl.action; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.external.XCalendarSelectEvent; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.XCalendarModel; 6 | 7 | import javax.annotation.Nullable; 8 | import java.util.Date; 9 | 10 | /** 11 | * 12 | * @author Baoyi Chen 13 | */ 14 | public class XCalendarFeedAction extends AbstractXCalendarAction { 15 | // 16 | private Date date; 17 | 18 | /** 19 | * 20 | */ 21 | public XCalendarFeedAction(@Nullable Date date) { 22 | super(Type.FEED); this.date = date; 23 | } 24 | 25 | /** 26 | * 27 | */ 28 | @Override 29 | public void apply(final XCalendar calendar) { 30 | final XCalendarModel model = calendar.getModel(); 31 | if(date != null) date = model.getCalendar().adjust(date); 32 | model.setDate(date); publish(calendar, new XCalendarSelectEvent(date, model.getZoneId()), true); 33 | } 34 | } -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/model/config/widget/XCalendarWidget.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.XCalendarEvent; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.render.XCalendarFrame; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.tracker.XCalendarMouseTracker; 6 | import cn.nextop.thorin.rcp.support.util.type.Pair; 7 | import org.eclipse.swt.graphics.Point; 8 | import org.eclipse.swt.graphics.Rectangle; 9 | 10 | /** 11 | * 12 | * @author Baoyi Chen 13 | */ 14 | public interface XCalendarWidget { 15 | 16 | /** 17 | * 18 | */ 19 | void dispose(); 20 | 21 | boolean isDisposed(); 22 | 23 | XCalendarMouseTracker getMouse(); 24 | 25 | void render(XCalendarFrame frame); 26 | 27 | boolean handle(XCalendarEvent event); 28 | 29 | /** 30 | * 31 | */ 32 | Point getMargin(); 33 | 34 | Rectangle getBounds(); 35 | 36 | void setMargin(Point margin); 37 | 38 | void setBounds(int x, int y, int w, int h); 39 | 40 | Pair locate(int x, int y, int maxWidth, int margin); 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/event/bus/AbstractXCalendarEvent.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.XCalendarEvent; 4 | import org.eclipse.swt.widgets.Event; 5 | 6 | /** 7 | * 8 | * @author Jingqi Xu 9 | */ 10 | public abstract class AbstractXCalendarEvent implements XCalendarEvent { 11 | // 12 | protected Event source; 13 | protected boolean doit = true; 14 | 15 | /** 16 | * 17 | */ 18 | public AbstractXCalendarEvent() { 19 | } 20 | 21 | public AbstractXCalendarEvent(Event source) { 22 | this.source = source; 23 | } 24 | 25 | /** 26 | * 27 | */ 28 | @Override 29 | public String toString() { 30 | return "source : " + source + ", doit : " + doit; 31 | } 32 | 33 | /** 34 | * 35 | */ 36 | @Override 37 | public boolean isDoit() { 38 | return doit; 39 | } 40 | 41 | @Override 42 | public void setDoit(boolean doit) { 43 | this.doit = doit; 44 | } 45 | 46 | @Override 47 | public Event getSource() { 48 | return source; 49 | } 50 | 51 | public final void setSource(Event source) { 52 | this.source = source; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/event/reactor/impl/action/XCalendarResizeAction.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.reactor.impl.action; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.XCalendarModel; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.XCalendarConfig; 6 | import org.eclipse.swt.graphics.Rectangle; 7 | import org.eclipse.swt.widgets.Composite; 8 | 9 | /** 10 | * 11 | * @author Jingqi Xu 12 | */ 13 | public class XCalendarResizeAction extends AbstractXCalendarAction { 14 | // 15 | private final Composite parent; 16 | private final Rectangle bounds; 17 | 18 | /** 19 | * 20 | */ 21 | public XCalendarResizeAction(Composite parent, Rectangle bounds) { 22 | super(Type.RESIZE); 23 | this.parent = parent; this.bounds = bounds; 24 | } 25 | 26 | /** 27 | * 28 | */ 29 | @Override 30 | public void apply(final XCalendar calendar) { 31 | final XCalendarModel model = calendar.getModel(); 32 | final XCalendarConfig config = model.getConfig(); 33 | config.getLayout().layout(calendar, parent, bounds); calendar.redraw(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/utility/graphics/Extents.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.utility.graphics; 2 | 3 | import cn.nextop.thorin.rcp.support.util.collection.map.IntHashMap; 4 | import cn.nextop.thorin.rcp.support.util.collection.map.LruMap; 5 | import org.eclipse.swt.graphics.GC; 6 | import org.eclipse.swt.graphics.Point; 7 | 8 | import java.util.Map; 9 | 10 | /** 11 | * 12 | * @author Jingqi Xu 13 | */ 14 | public final class Extents { 15 | // 16 | private static final IntHashMap> EXTENTS = new IntHashMap<>(256); 17 | 18 | /** 19 | * Any better idea about EXTENTS' key? 20 | */ 21 | public static Point extent(GC gc, String text) { 22 | return extent(gc, text, getExtents(gc, 20480)); 23 | } 24 | 25 | public static Point extent(GC gc, String text, Map cache) { 26 | Point r = cache.get(text); if (r != null) return r; 27 | cache.put(text, r = gc.textExtent(text)); return r; 28 | } 29 | 30 | protected static Map getExtents(final GC gc, int capacity) { 31 | final int hash = System.identityHashCode(gc.getFont()); 32 | LruMap r = EXTENTS.get(hash); if (r != null) return r; 33 | EXTENTS.put(hash, r = new LruMap(capacity)); return r; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/event/reactor/impl/action/XCalendarSelectAction.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.reactor.impl.action; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.external.XCalendarSelectEvent; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.XCalendarModel; 6 | 7 | import javax.annotation.Nullable; 8 | import java.util.Date; 9 | 10 | /** 11 | * 12 | * @author Baoyi Chen 13 | */ 14 | public class XCalendarSelectAction extends AbstractXCalendarAction { 15 | // 16 | private Date date; 17 | private boolean clear; 18 | 19 | public XCalendarSelectAction(@Nullable Date date) { 20 | this(date, false); 21 | } 22 | 23 | /** 24 | * 25 | */ 26 | public XCalendarSelectAction(@Nullable Date date, boolean clear) { 27 | super(Type.SELECT); this.date = date; this.clear = clear; 28 | } 29 | 30 | /** 31 | * 32 | */ 33 | @Override 34 | public void apply(final XCalendar calendar) { 35 | final XCalendarModel model = calendar.getModel(); 36 | if (date != null) date = model.getCalendar().adjust(date, clear); 37 | model.setDate(date); publish(calendar, new XCalendarSelectEvent(date, model.getZoneId()), true); 38 | } 39 | } -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/model/config/XCalendarConfig.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.layout.XCalendarLayout; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.layout.impl.XCalendarDefaultLayout; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.render.XCalendarRender; 6 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.render.impl.XCalendarDefaultRender; 7 | 8 | /** 9 | * 10 | * @author Jingqi Xu 11 | */ 12 | public class XCalendarConfig { 13 | // 14 | protected XCalendarLayout layout; 15 | protected XCalendarRender render; 16 | 17 | /** 18 | * 19 | */ 20 | public XCalendarConfig() { 21 | this.layout = new XCalendarDefaultLayout(); 22 | this.render = new XCalendarDefaultRender(); 23 | } 24 | 25 | /** 26 | * 27 | */ 28 | public final XCalendarLayout getLayout() { 29 | return layout; 30 | } 31 | 32 | public final void setLayout(XCalendarLayout layout) { 33 | this.layout = layout; 34 | } 35 | 36 | public final XCalendarRender getRender() { 37 | return render; 38 | } 39 | 40 | public final void setRender(XCalendarRender render) { 41 | this.render = render; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/model/theme/impl/XCalendarThemeJp.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.theme.impl; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.theme.XCalendarTheme; 4 | 5 | /** 6 | * 7 | * @author Baoyi Chen 8 | */ 9 | public class XCalendarThemeJp extends XCalendarTheme { 10 | // 11 | private static final String[][] MONTH = { { "1月", "2月", "3月", "4月" }, 12 | { "5月", "6月", "7月", "8月" }, 13 | { "9月", "10月", "11月", "12月" } }; 14 | 15 | private static final String[] MONTH_OF_YEAR_NAME = { "", "1月", "2月", "3月", 16 | "4月", "5月", "6月", "7月", 17 | "8月", "9月", "10月", "11月", "12月" }; 18 | 19 | private static final String[] DAY_OF_WEEK_NAME = { "日", "月", "火", "水", "木", "金", "土" }; 20 | 21 | /** 22 | * 23 | */ 24 | @Override public String[][] getMonthTheme(){ return MONTH; } 25 | @Override public String[] getDayOfWeekTheme() { return DAY_OF_WEEK_NAME; }; 26 | @Override public String[] getMonthOfYearTheme() { return MONTH_OF_YEAR_NAME; } 27 | @Override public String header(int month, int year) { return year + "年" + getMonthOfYearTheme()[month] + "月"; } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/model/theme/impl/XCalendarThemeEn.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.theme.impl; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.theme.XCalendarTheme; 4 | 5 | /** 6 | * 7 | * @author Baoyi Chen 8 | */ 9 | public class XCalendarThemeEn extends XCalendarTheme { 10 | // 11 | private static final String[][] MONTH = { { "Jan", "Feb", "Mar", "Apr" }, 12 | { "May", "Jun", "Jul", "Aug" }, 13 | { "Sep", "Oct", "Nov", "Dec" } }; 14 | 15 | private static final String[] MONTH_OF_YEAR_NAME = { "", "January", "February", "March", 16 | "April", "May", "June", "July", "August", 17 | "September", "October", "November", "December" }; 18 | 19 | private static final String[] DAY_OF_WEEK_NAME = { "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa" }; 20 | 21 | /** 22 | * 23 | */ 24 | @Override public String[][] getMonthTheme(){ return MONTH; } 25 | @Override public String[] getDayOfWeekTheme() { return DAY_OF_WEEK_NAME; }; 26 | @Override public String[] getMonthOfYearTheme() { return MONTH_OF_YEAR_NAME; } 27 | @Override public String header(int month, int year) { return getMonthOfYearTheme()[month] + " "+ year; } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/event/bus/external/XCalendarSelectEvent.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.external; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.AbstractXCalendarEvent; 4 | import org.eclipse.swt.widgets.Event; 5 | 6 | import javax.annotation.Nullable; 7 | import java.sql.Time; 8 | import java.time.YearMonth; 9 | import java.time.ZoneId; 10 | import java.util.Date; 11 | 12 | /** 13 | * 14 | * @author Baoyi Chen 15 | */ 16 | public class XCalendarSelectEvent extends AbstractXCalendarEvent { 17 | // 18 | private final Date value; 19 | private final ZoneId zoneId; 20 | 21 | /** 22 | * 23 | */ 24 | public XCalendarSelectEvent(@Nullable Date value, ZoneId zoneId) { 25 | this(null, value, zoneId); 26 | } 27 | 28 | public XCalendarSelectEvent(Event source, @Nullable Date value, ZoneId zoneId) { 29 | super(source); this.value = value; this.zoneId = zoneId; 30 | } 31 | 32 | /** 33 | * 34 | */ 35 | public Date getValue() { 36 | return value; 37 | } 38 | 39 | public Time getTime() { 40 | return value == null ? null : new Time(value.getTime()); 41 | } 42 | 43 | public Integer getYear() { 44 | return value == null ? null : YearMonth.from(value.toInstant().atZone(zoneId)).getYear(); 45 | } 46 | 47 | public YearMonth getYearMonth() { 48 | return value == null ? null : YearMonth.from(value.toInstant().atZone(zoneId)); 49 | } 50 | } -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/support/glossary/XCalendarTime.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.glossary; 2 | 3 | 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.theme.XCalendarTheme; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.XVirtualCalendar; 6 | import org.eclipse.swt.SWTException; 7 | 8 | import static cn.nextop.thorin.rcp.support.util.Strings.lappend; 9 | 10 | /** 11 | * 12 | * @author Baoyi Chen 13 | */ 14 | public enum XCalendarTime { 15 | // 16 | HOUR, MINUTE, SECOND; 17 | 18 | /** 19 | * 20 | */ 21 | public void decr(XVirtualCalendar calendar) { 22 | switch(this) { 23 | case HOUR: calendar.prevHour(); break; 24 | case MINUTE: calendar.prevMinute(); break; 25 | case SECOND: calendar.prevSecond(); break; 26 | default: throw new SWTException("invalid calendar time: " + this); 27 | } 28 | } 29 | 30 | public void incr(XVirtualCalendar calendar) { 31 | switch(this) { 32 | case HOUR: calendar.nextHour(); break; 33 | case MINUTE: calendar.nextMinute(); break; 34 | case SECOND: calendar.nextSecond(); break; 35 | default: throw new SWTException("invalid calendar time: " + this); 36 | } 37 | } 38 | 39 | /** 40 | * 41 | */ 42 | public String text(XCalendarTheme theme, XVirtualCalendar calendar) { 43 | switch(this) { 44 | case HOUR: return lappend(calendar.getHour(), 2, '0'); 45 | case MINUTE: return lappend(calendar.getMinute(), 2, '0'); 46 | case SECOND: return lappend(calendar.getSecond(), 2, '0'); 47 | default: throw new SWTException("invalid calendar time: " + this); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/event/reactor/impl/action/AbstractXCalendarAction.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.reactor.impl.action; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.XCalendarEvent; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.reactor.XCalendarAction; 6 | import org.eclipse.swt.widgets.Event; 7 | 8 | /** 9 | * 10 | * @author Jingqi Xu 11 | */ 12 | public abstract class AbstractXCalendarAction implements XCalendarAction { 13 | // 14 | protected final Type type; 15 | protected final Event event; 16 | 17 | /** 18 | * 19 | */ 20 | public AbstractXCalendarAction(Type type) { 21 | this.type = type; this.event = null; 22 | } 23 | 24 | public AbstractXCalendarAction(Type type, Event event) { 25 | this.type = type; this.event = event; 26 | } 27 | 28 | /** 29 | * 30 | */ 31 | @Override 32 | public final Type getType() { 33 | return this.type; 34 | } 35 | 36 | /** 37 | * 38 | */ 39 | public final Event getEvent() { 40 | return this.event; 41 | } 42 | 43 | /** 44 | * 45 | */ 46 | @Override 47 | public String toString() { 48 | return new StringBuilder() 49 | .append("type:" + type) 50 | .append("event:" + event).toString(); 51 | } 52 | 53 | /** 54 | * 55 | */ 56 | protected boolean confirm(XCalendar calendar, XCalendarEvent event) { 57 | calendar.getBus().publish(event); return event.isDoit(); 58 | } 59 | 60 | protected boolean publish(XCalendar calendar, XCalendarEvent event, boolean redraw) { 61 | calendar.getBus().publish(event); 62 | if(redraw && !calendar.isDisposed()) { calendar.redraw(); } return event.isDoit(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/util/type/Pair.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.util.type; 2 | 3 | /** 4 | * 5 | * @author Jingqi Xu 6 | * @param 7 | */ 8 | public final class Pair { 9 | // 10 | private T v1; 11 | private T v2; 12 | 13 | /** 14 | * 15 | */ 16 | public Pair() { 17 | } 18 | 19 | public Pair(T v1, T v2) { 20 | this.v1 = v1; 21 | this.v2 = v2; 22 | } 23 | 24 | @Override 25 | public String toString() { 26 | return "Pair{" + 27 | "v1=" + v1 + 28 | ", v2=" + v2 + 29 | '}'; 30 | } 31 | 32 | @Override 33 | public boolean equals(Object o) { 34 | if (this == o) return true; 35 | if (o == null || getClass() != o.getClass()) return false; 36 | 37 | Pair pair = (Pair) o; 38 | 39 | if (v1 != null ? !v1.equals(pair.v1) : pair.v1 != null) return false; 40 | return v2 != null ? v2.equals(pair.v2) : pair.v2 == null; 41 | } 42 | 43 | @Override 44 | public int hashCode() { 45 | int result = v1 != null ? v1.hashCode() : 0; 46 | result = 31 * result + (v2 != null ? v2.hashCode() : 0); 47 | return result; 48 | } 49 | 50 | /** 51 | * 52 | */ 53 | public T getV1() { 54 | return v1; 55 | } 56 | 57 | public void setV1(T v1) { 58 | this.v1 = v1; 59 | } 60 | 61 | public T getV2() { 62 | return v2; 63 | } 64 | 65 | public void setV2(T v2) { 66 | this.v2 = v2; 67 | } 68 | 69 | /** 70 | * 71 | */ 72 | public synchronized void swap() { 73 | T backup = this.v1; 74 | this.v1 = this.v2; 75 | this.v2 = backup; 76 | } 77 | 78 | /** 79 | * 80 | */ 81 | public static void swap(Pair p) { 82 | doSwap(p); // Nothing but capture the 83 | } 84 | 85 | private static void doSwap(Pair p) { 86 | synchronized(p) { 87 | T backup = p.v1; 88 | p.v1 = p.v2; 89 | p.v2 = backup; 90 | } 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/utility/graphics/Colors.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.utility.graphics; 2 | 3 | import org.eclipse.swt.SWT; 4 | import org.eclipse.swt.graphics.Color; 5 | import org.eclipse.swt.widgets.Display; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | import static org.eclipse.swt.widgets.Display.getDefault; 11 | 12 | /** 13 | * 14 | * @author Jingqi Xu 15 | */ 16 | public final class Colors { 17 | // 18 | protected static final Map COLORS = new HashMap<>(256); 19 | 20 | // 21 | public static final Color COLOR_RED = Display.getDefault().getSystemColor(SWT.COLOR_RED); 22 | public static final Color COLOR_BLUE = Display.getDefault().getSystemColor(SWT.COLOR_BLUE); 23 | public static final Color COLOR_BLACK = Display.getDefault().getSystemColor(SWT.COLOR_BLACK); 24 | public static final Color COLOR_GREEN = Display.getDefault().getSystemColor(SWT.COLOR_GREEN); 25 | public static final Color COLOR_WHITE = Display.getDefault().getSystemColor(SWT.COLOR_WHITE); 26 | public static final Color COLOR_LIST_BACKGROUND = getDefault().getSystemColor(SWT.COLOR_LIST_BACKGROUND); 27 | public static final Color COLOR_WIDGET_FOREGROUND = getDefault().getSystemColor(SWT.COLOR_WIDGET_FOREGROUND); 28 | public static final Color COLOR_WIDGET_BACKGROUND = getDefault().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND); 29 | public static final Color COLOR_WIDGET_NORMAL_SHADOW = getDefault().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW); 30 | 31 | /** 32 | * Color 33 | */ 34 | public static final Color getColor(int r, int g, int b) { 35 | final String key = new StringBuilder(12).append(r).append(":").append(g).append(":").append(b).toString(); 36 | Color c = COLORS.get(key); if (c == null) COLORS.put(key, c = new Color(getDefault(), r, g, b)); return c; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/event/handler/impl/AbstractXCalendarEventHandler.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.handler.impl; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.handler.XCalendarEventHandler; 5 | import org.eclipse.swt.widgets.Event; 6 | 7 | import static org.eclipse.swt.SWT.*; 8 | 9 | /** 10 | * 11 | * @author Jingqi Xu 12 | */ 13 | public abstract class AbstractXCalendarEventHandler implements XCalendarEventHandler { 14 | // 15 | protected final int priority; 16 | protected final XCalendar calendar; 17 | 18 | // 19 | protected abstract boolean accepts(Context c, Event e); 20 | protected abstract boolean process(Context c, Event e); 21 | 22 | /** 23 | * 24 | */ 25 | public AbstractXCalendarEventHandler(XCalendar x, int p) { 26 | this.calendar = x; this.priority = p; 27 | } 28 | 29 | /** 30 | * 31 | */ 32 | @Override 33 | public int getPriority() { 34 | return this.priority; 35 | } 36 | 37 | /** 38 | * 39 | */ 40 | @Override 41 | public String toString() { 42 | return new StringBuilder().append("priority:" + priority) 43 | .append("calendar:" + calendar).toString(); 44 | } 45 | 46 | /** 47 | * 48 | */ 49 | protected boolean isMouseEvent(Event event) { 50 | final int t = event.type; 51 | if(t == MouseEnter || t == MouseExit) return true; 52 | return t == MouseUp || t == MouseMove || t == MouseDown; 53 | } 54 | 55 | /** 56 | * 57 | */ 58 | @Override 59 | public final boolean handle(Context ctx, Event event) { 60 | final XCalendarEventHandler focus = ctx.getFocus(); 61 | if (focus != null && focus != this) return false; 62 | return !accepts(ctx, event) ? false : process(ctx, event); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/model/config/render/impl/XCalendarDefaultRender.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.render.impl; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.XCalendarModel; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.render.XCalendarFrame; 6 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.render.XCalendarRender; 7 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.XCalendarWidget; 8 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.theme.XCalendarTheme; 9 | import org.eclipse.swt.SWT; 10 | import org.eclipse.swt.graphics.GC; 11 | import org.eclipse.swt.graphics.Rectangle; 12 | import org.eclipse.swt.graphics.Transform; 13 | 14 | import java.util.List; 15 | 16 | /** 17 | * @author chenby 18 | * 19 | */ 20 | public class XCalendarDefaultRender implements XCalendarRender { 21 | 22 | public void render(XCalendar popup, GC gc) { 23 | final XCalendarModel model = popup.getModel(); 24 | final XCalendarTheme theme = model.getTheme(); 25 | final Transform t = new Transform(gc.getDevice()); 26 | 27 | // 28 | try (final XCalendarFrame frame = new XCalendarFrame(gc, t)) { 29 | // 30 | Rectangle area = new Rectangle((area = popup.getClientArea()).x, area.y, area.width - 1, area.height - 1); 31 | gc.setAdvanced(true); 32 | gc.setAntialias(SWT.ON); 33 | gc.setBackground(theme.getBackground(true, false, false, false)); 34 | gc.fillRectangle(area); gc.setForeground(theme.getGrid(true)); gc.drawRectangle(area); 35 | 36 | List widgets = popup.getWidgets(); 37 | for(XCalendarWidget widget:widgets) widget.render(frame); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/utility/graphics/Fonts.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.utility.graphics; 2 | 3 | import cn.nextop.thorin.rcp.support.util.collection.map.ConcurrentMultiKeyMap; 4 | import com.patrikdufresne.fontawesome.FontAwesome; 5 | import org.eclipse.jface.resource.FontDescriptor; 6 | import org.eclipse.swt.SWT; 7 | import org.eclipse.swt.graphics.Font; 8 | import org.eclipse.swt.widgets.Display; 9 | 10 | import java.util.function.Supplier; 11 | 12 | /** 13 | * 14 | * @author Jingqi Xu 15 | */ 16 | public final class Fonts { 17 | // 18 | public static final Font SYSTEM = Display.getDefault().getSystemFont(); 19 | public static final Font AWESOME = FontAwesome.getFont(Math.max(10, getHeight(SYSTEM))); 20 | 21 | // 22 | protected static final ConcurrentMultiKeyMap, String, Font> FONTS = new ConcurrentMultiKeyMap<>(); 23 | 24 | /** 25 | * Font 26 | */ 27 | public static Font getSystemFont() { 28 | return SYSTEM; 29 | } 30 | 31 | public static Font getAwesomeFont() { 32 | return AWESOME; 33 | } 34 | 35 | /** 36 | * 37 | */ 38 | public static final int getHeight(Font font) { 39 | return font.getFontData()[0].getHeight(); 40 | } 41 | 42 | public static final Font bold(final Font font) { 43 | FontDescriptor fd = FontDescriptor.createFrom(font); 44 | return fd.setStyle(SWT.BOLD).createFont(Display.getDefault()); 45 | } 46 | 47 | public static final Font size(Font font, int delta) { 48 | FontDescriptor fd = FontDescriptor.createFrom(font); 49 | int height = fd.getFontData()[0].getHeight() + delta; 50 | return fd.setHeight(height).createFont(Display.getDefault()); 51 | } 52 | 53 | /** 54 | * 55 | */ 56 | public static Font getFont(Class clazz, String key, Supplier font) { 57 | Font r = FONTS.get(clazz, key); if(r != null) return r; 58 | Font existing = FONTS.putIfAbsent(clazz, key, r = font.get()); 59 | if (existing != null) { r.dispose(); r = existing; } return r; // Dispose 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/event/bus/XCalendarDefaultEventBus.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.XCalendarEvent; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.handler.XCalendarEventHandler; 6 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.listener.XCalendarEventListener; 7 | import org.eclipse.swt.widgets.Event; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | /** 12 | * 13 | * @author Jingqi Xu 14 | */ 15 | public class XCalendarDefaultEventBus extends AbstractXCalendarEventBus implements XCalendarEventHandler.Context { 16 | // 17 | private static Logger LOGGER = LoggerFactory.getLogger(XCalendarDefaultEventBus.class); 18 | 19 | // 20 | protected XCalendarEventHandler focus; 21 | 22 | /** 23 | * 24 | */ 25 | public XCalendarDefaultEventBus(XCalendar datetime) { 26 | super(datetime); 27 | } 28 | 29 | /** 30 | * 31 | */ 32 | @Override 33 | public XCalendarEventHandler getFocus() { 34 | return focus; 35 | } 36 | 37 | @Override 38 | public void setFocus(XCalendarEventHandler focus) { 39 | this.focus = focus; 40 | } 41 | 42 | /** 43 | * 44 | */ 45 | @Override 46 | public void handle(final Event event) { 47 | for(final XCalendarEventHandler handler : this.handlers) { 48 | try { 49 | if(handler.handle(this, event)) break; 50 | } catch(Throwable tx) { 51 | LOGGER.error("[XCalendar.event.bus]failed to handle event: " + event, tx); 52 | } 53 | } 54 | } 55 | 56 | /** 57 | * 58 | */ 59 | @Override 60 | public void publish(final XCalendarEvent event) { 61 | for(final XCalendarEventListener listener : this.listeners) { 62 | try { 63 | listener.onEvent(event); 64 | } catch(Throwable tx) { 65 | LOGGER.error("[XCalendar.event.bus]failed to publish event: " + event, tx); 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/support/glossary/XCalendarState.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.glossary; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.theme.XCalendarTheme; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.XVirtualCalendar; 5 | import cn.nextop.thorin.rcp.support.util.Strings; 6 | import cn.nextop.thorin.rcp.support.util.type.Range; 7 | import org.eclipse.swt.SWTException; 8 | 9 | /** 10 | * 11 | * @author Baoyi Chen 12 | */ 13 | public enum XCalendarState { 14 | // 15 | DATE, MONTH, YEAR, DECADE, TIME, HOUR, MINUTE, SECOND; 16 | 17 | /** 18 | * 19 | */ 20 | public void prev(XVirtualCalendar calendar) { 21 | switch(this){ 22 | case DATE: calendar.prevMonth(); break; 23 | case MONTH: calendar.prevYear(); break; 24 | case YEAR: calendar.prevDecade(); break; 25 | case DECADE: calendar.prevCentury(); break; 26 | default: throw new SWTException("invalid calendar state: " + this); 27 | } 28 | } 29 | 30 | public void next(XVirtualCalendar calendar) { 31 | switch(this) { 32 | case DATE: calendar.nextMonth(); break; 33 | case MONTH: calendar.nextYear(); break; 34 | case YEAR: calendar.nextDecade(); break; 35 | case DECADE: calendar.nextCentury(); break; 36 | default: throw new SWTException("invalid calendar state: " + this); 37 | } 38 | } 39 | 40 | /** 41 | * 42 | */ 43 | public String text(XCalendarTheme theme, XVirtualCalendar calendar) { 44 | switch (this) { 45 | case MONTH: 46 | return Strings.toString(calendar.getYear()); 47 | case YEAR: 48 | Range decade = calendar.getDecade(); 49 | return decade.getValue1() + "-" + decade.getValue2(); 50 | case DECADE: 51 | Range century = calendar.getCentury(); 52 | return century.getValue1() + "-" + century.getValue2(); 53 | case DATE: 54 | return theme.header(calendar.getMonth(), calendar.getYear()); 55 | default: throw new SWTException("invalid calendar state: " + this); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/event/bus/AbstractXCalendarEventBus.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.XCalendarEventBus; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.handler.XCalendarEventHandler; 6 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.listener.XCalendarEventListener; 7 | 8 | import java.util.Collections; 9 | import java.util.Comparator; 10 | import java.util.List; 11 | import java.util.concurrent.CopyOnWriteArrayList; 12 | 13 | /** 14 | * 15 | * @author Jingqi Xu 16 | */ 17 | public abstract class AbstractXCalendarEventBus implements XCalendarEventBus { 18 | // 19 | protected final XCalendar calendar; 20 | protected final List handlers; 21 | protected final List listeners; 22 | 23 | /** 24 | * 25 | */ 26 | public AbstractXCalendarEventBus(XCalendar calendar) { 27 | this.calendar = calendar; 28 | this.handlers = new CopyOnWriteArrayList<>(); 29 | this.listeners = new CopyOnWriteArrayList<>(); 30 | } 31 | 32 | /** 33 | * 34 | */ 35 | @Override 36 | public boolean addListener(XCalendarEventListener listener) { 37 | return this.listeners.add(listener); 38 | } 39 | 40 | @Override 41 | public boolean delListener(XCalendarEventListener listener) { 42 | return this.listeners.remove(listener); 43 | } 44 | 45 | @Override 46 | public boolean delHandler(final XCalendarEventHandler handler) { 47 | return this.handlers.remove(handler); 48 | } 49 | 50 | @Override 51 | public boolean addHandler(final XCalendarEventHandler handler) { 52 | int i = Collections.binarySearch(this.handlers, handler, ASC); 53 | this.handlers.add(i < 0 ? -(i + 1) : i + 1, handler); return true; 54 | } 55 | 56 | /** 57 | * 58 | */ 59 | protected static final Comparator ASC = new Comparator() { 60 | @Override public int compare(XCalendarEventHandler o1, XCalendarEventHandler o2) { return o1.getPriority() - o2.getPriority(); } 61 | }; 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/support/tracker/XCalendarMouseTracker.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.tracker; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.XCalendarEvent; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.internal.*; 5 | 6 | /** 7 | * 8 | * @author Jingqi Xu 9 | */ 10 | public class XCalendarMouseTracker { 11 | // 12 | protected static final int MASK_ENTERED = (1 << 0); 13 | protected static final int MASK_PRESSED = (1 << 1); 14 | 15 | // 16 | private int x, y; 17 | private byte state; 18 | 19 | /** 20 | * 21 | */ 22 | public final int getX() { 23 | return x; 24 | } 25 | 26 | public final void setX(int x) { 27 | this.x = x; 28 | } 29 | 30 | public final int getY() { 31 | return y; 32 | } 33 | 34 | public final void setY(int y) { 35 | this.y = y; 36 | } 37 | 38 | /** 39 | * 40 | */ 41 | public void reset() { 42 | this.state = 0; 43 | this.x = this.y = -1; 44 | } 45 | 46 | public void reset(XCalendarMouseTracker rhs) { 47 | this.state = rhs.state; 48 | this.x = rhs.x; this.y = rhs.y; 49 | } 50 | 51 | /** 52 | * 53 | */ 54 | @Override 55 | public String toString() { 56 | return new StringBuilder() 57 | .append("x:" + x).append("y:" + y) 58 | .append("entered:" + isEntered()) 59 | .append("pressed:" + isPressed()).toString(); 60 | } 61 | 62 | /** 63 | * 64 | */ 65 | public boolean track(final XCalendarEvent event) { 66 | if(!(event instanceof XCalendarMouseEvent)) return false; 67 | this.x = event.getSource().x; this.y = event.getSource().y; 68 | if (event instanceof XCalendarMouseUpEvent) setPressed(false); 69 | else if(event instanceof XCalendarMouseDownEvent) setPressed(true); 70 | else if(event instanceof XCalendarMouseEnterEvent) setEntered(true); 71 | else if(event instanceof XCalendarMouseLeaveEvent) setEntered(false); 72 | return true; 73 | } 74 | 75 | /** 76 | * 77 | */ 78 | public boolean isEntered() { 79 | return (this.state & MASK_ENTERED) != 0; 80 | } 81 | 82 | public void setEntered(boolean entered) { 83 | if(entered) this.state |= MASK_ENTERED; else this.state &= ~MASK_ENTERED; 84 | } 85 | 86 | public boolean isPressed() { 87 | return (this.state & MASK_PRESSED) != 0; 88 | } 89 | 90 | public void setPressed(boolean pressed) { 91 | if(pressed) this.state |= MASK_PRESSED; else this.state &= ~MASK_PRESSED; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/support/fsm/XCalendarStateMachine.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.fsm; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.impl.*; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.glossary.XCalendarState; 5 | 6 | import javax.annotation.Nullable; 7 | 8 | import static cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.glossary.XCalendarState.*; 9 | 10 | /** 11 | * 12 | * @author Baoyi Chen 13 | */ 14 | public class XCalendarStateMachine { 15 | // 16 | private XCalendarState curr, prev; 17 | 18 | /** 19 | * 20 | */ 21 | public XCalendarStateMachine(XCalendarState curr) { 22 | this(curr, null); 23 | } 24 | 25 | public XCalendarStateMachine(XCalendarState curr, @Nullable XCalendarState prev) { 26 | this.curr = curr; this.prev = prev; 27 | } 28 | 29 | /** 30 | * 31 | */ 32 | public XCalendarState current() { 33 | return curr; 34 | } 35 | 36 | public void reset() { 37 | if(isTime()) this.curr = prev; this.prev = TIME; 38 | } 39 | 40 | public boolean isTime() { 41 | if(this.curr == TIME) return true; 42 | return curr == HOUR || curr == MINUTE || curr == SECOND; 43 | } 44 | 45 | /** 46 | * 47 | */ 48 | public void mutate(XCalendarSelectTimeWidget widget) { 49 | XCalendarState temp = this.curr; 50 | this.curr = this.prev; this.prev = temp; 51 | } 52 | 53 | public void mutate(final XCalendarTimeWidget widget) { 54 | switch (widget.getType()) { 55 | case HOUR: this.curr = XCalendarState.HOUR; break; 56 | case MINUTE: this.curr = XCalendarState.MINUTE; break; 57 | case SECOND: this.curr = XCalendarState.SECOND; break; 58 | default: throw new AssertionError("invalid widget: " + widget); 59 | } 60 | } 61 | 62 | public void mutate(final XCalendarSelectWidget widget) { 63 | switch (this.curr) { 64 | case DATE: this.curr = XCalendarState.MONTH; break; 65 | case MONTH: this.curr = XCalendarState.YEAR; break; 66 | case YEAR: this.curr = XCalendarState.DECADE; break; 67 | case DECADE: break; 68 | default: throw new AssertionError("invalid widget: " + widget); 69 | } 70 | } 71 | 72 | /** 73 | * 74 | */ 75 | public void mutate(XCalendarDecadeWidget widget) { this.curr = XCalendarState.YEAR; } 76 | public void mutate(XCalendarYearWidget widget) { this.curr = XCalendarState.MONTH; } 77 | public void mutate(XCalendarMonthWidget widget) { this.curr = XCalendarState.DATE; } 78 | public void mutate(XCalendarHourWidget widget) { this.curr = XCalendarState.TIME; } 79 | public void mutate(XCalendarMinuteWidget widget) { this.curr = XCalendarState.TIME; } 80 | public void mutate(XCalendarSecondWidget widget) { this.curr = XCalendarState.TIME; } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/model/config/layout/impl/XCalendarDefaultLayout.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.layout.impl; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.XCalendarModel; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.layout.XCalendarLayout; 6 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.XCalendarWidget; 7 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.theme.XCalendarTheme; 8 | import cn.nextop.thorin.rcp.support.util.type.Pair; 9 | import org.eclipse.swt.graphics.Point; 10 | import org.eclipse.swt.graphics.Rectangle; 11 | import org.eclipse.swt.widgets.Composite; 12 | import org.eclipse.swt.widgets.Display; 13 | import org.eclipse.swt.widgets.Shell; 14 | 15 | import java.util.List; 16 | 17 | /** 18 | * 19 | * @author Baoyi Chen 20 | */ 21 | public class XCalendarDefaultLayout implements XCalendarLayout { 22 | // 23 | private Composite prevParent; 24 | private Rectangle prevBounds; 25 | 26 | /** 27 | * 28 | */ 29 | @Override 30 | public void layout(XCalendar popup) { 31 | layout(popup, this.prevParent, this.prevBounds); 32 | } 33 | 34 | /** 35 | * 36 | */ 37 | @Override 38 | public void layout(XCalendar popup, Composite parent, Rectangle bounds) { 39 | // 40 | this.prevParent = parent; 41 | this.prevBounds = bounds; 42 | final XCalendarModel model = popup.getModel(); 43 | final XCalendarTheme theme = model.getTheme(); 44 | int x = theme.getMargin(), y = theme.getMargin(); 45 | int m = theme.getMargin(), w = theme.getWidth() - 2 * m; 46 | 47 | // 48 | List widgets = popup.getWidgets(); 49 | for(int i = 0; i < widgets.size(); i++) { 50 | final XCalendarWidget v = widgets.get(i); 51 | final Pair points = v.locate(x, y, w, m); 52 | v.setBounds(x, y, points.getV1().x, points.getV1().y); 53 | x = points.getV2().x; y = points.getV2().y; 54 | } 55 | 56 | // 57 | final Shell shell = popup.getShell(); 58 | shell.setSize(new Point(theme.getWidth(), y + m)); setLocation(popup); 59 | } 60 | 61 | /** 62 | * 63 | */ 64 | protected void setLocation(final XCalendar popup) { 65 | // 66 | final Shell shell = popup.getShell(); 67 | final Display display = popup.getDisplay(); 68 | final Rectangle r1 = display.map(prevParent, null, prevBounds); 69 | final Rectangle r2 = popup.getMonitor().getClientArea(); // Client area 70 | 71 | // 72 | final int margin = 2; 73 | final Point size = shell.getSize(); 74 | int x = r1.x, y = r1.y + r1.height + margin; 75 | if(y + size.y > r2.y + r2.height) y = r1.y - size.y - margin; 76 | if(x < r2.x) x = r2.x; else if(x + size.x > r2.x + r2.width) x = r2.x + r2.width - size.x; 77 | shell.setLocation(x, y); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/model/config/widget/impl/XCalendarTextWidget.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.impl; 2 | 3 | 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.internal.*; 6 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.XCalendarModel; 7 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.render.XCalendarFrame; 8 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.AbstractXCalendarWidget; 9 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.theme.XCalendarTheme; 10 | import cn.nextop.thorin.rcp.support.util.type.Pair; 11 | import org.eclipse.swt.graphics.GC; 12 | import org.eclipse.swt.graphics.Point; 13 | 14 | import static cn.nextop.thorin.rcp.support.swt.utility.graphics.Extents.extent; 15 | 16 | /** 17 | * @author chenby 18 | * 19 | */ 20 | public class XCalendarTextWidget extends AbstractXCalendarWidget { 21 | // 22 | private final int col; 23 | 24 | /** 25 | * 26 | */ 27 | public XCalendarTextWidget(XCalendar popup, int col) { 28 | super(popup); this.col = col; 29 | } 30 | 31 | /** 32 | * 33 | */ 34 | @Override 35 | public Pair locate(int x, int y, int w, int m) { 36 | int unit = w / 7; 37 | if(col == 6) { x = m; y += unit; } else { x += unit; } 38 | return new Pair<>(new Point(unit, unit), new Point(x, y)); 39 | } 40 | 41 | /** 42 | * Event 43 | */ 44 | @Override 45 | protected boolean onMouseMove(XCalendarMouseMoveEvent event) { 46 | return true; 47 | } 48 | 49 | @Override 50 | protected boolean onMouseDown(XCalendarMouseDownEvent event) { 51 | return true; 52 | } 53 | 54 | @Override 55 | protected boolean onMouseEnter(XCalendarMouseEnterEvent event) { 56 | popup.redraw(); return true; 57 | } 58 | 59 | @Override 60 | protected boolean onMouseLeave(XCalendarMouseLeaveEvent event) { 61 | popup.redraw(); return true; 62 | } 63 | 64 | @Override 65 | protected boolean onMouseUp(final XCalendarMouseUpEvent event) { 66 | popup.redraw(); return true; 67 | } 68 | 69 | /** 70 | * 71 | */ 72 | @Override 73 | public void render(XCalendarFrame frame) { 74 | // Background 75 | final GC gc = frame.getGc(); 76 | final XCalendarModel model = popup.getModel(); 77 | final XCalendarTheme theme = model.getTheme(); 78 | int x = bounds.x, y = bounds.y, w = bounds.width, h = bounds.height; 79 | gc.setBackground(theme.getBackground(true, false, false, false)); 80 | gc.fillRoundRectangle(x, y, w, h, theme.getArc(), theme.getArc()); 81 | 82 | // Foreground 83 | String text = theme.getDayOfWeekTheme()[col]; 84 | gc.setForeground(theme.getForeground(true, false, true)); 85 | gc.setFont(theme.getBold()); final Point size = extent(gc, text); 86 | gc.drawText(text, x + 1 + ((w - size.x) >> 1), y + 1 + ((h - size.y) >> 1)); 87 | } 88 | } -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/util/collection/map/ConcurrentMultiKeyMap.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.util.collection.map; 2 | 3 | import java.util.Map; 4 | import java.util.Set; 5 | import java.util.concurrent.ConcurrentHashMap; 6 | import java.util.concurrent.ConcurrentMap; 7 | import java.util.concurrent.atomic.AtomicBoolean; 8 | import java.util.concurrent.atomic.AtomicReference; 9 | 10 | /** 11 | * 12 | * @author Jingqi Xu 13 | * @param 14 | * @param 15 | */ 16 | public class ConcurrentMultiKeyMap { 17 | // 18 | private final ConcurrentMap> map; 19 | 20 | /** 21 | * 22 | */ 23 | public ConcurrentMultiKeyMap() { 24 | this.map = new ConcurrentHashMap<>(); 25 | } 26 | 27 | public ConcurrentMultiKeyMap(int capacity) { 28 | this.map = new ConcurrentHashMap<>(capacity); 29 | } 30 | 31 | /** 32 | * 33 | */ 34 | public int size() { 35 | return map.size(); 36 | } 37 | 38 | public void clear() { 39 | this.map.clear(); 40 | } 41 | 42 | public Set keySet() { 43 | return this.map.keySet(); 44 | } 45 | 46 | public boolean isEmpty() { 47 | return this.map.isEmpty(); 48 | } 49 | 50 | public V get(final K1 k1, final K2 k2) { 51 | ConcurrentMap m = this.map.get(k1); 52 | return m == null ? null : m.get(k2); 53 | } 54 | 55 | public boolean containsKey(K1 k1, K2 k2) { 56 | ConcurrentMap m = this.map.get(k1); 57 | return m == null ? false : m.containsKey(k2); 58 | } 59 | 60 | public ConcurrentMap get(final K1 k1) { 61 | return this.map.get(k1); 62 | } 63 | 64 | public ConcurrentMap remove(final K1 k1) { 65 | return this.map.remove(k1); 66 | } 67 | 68 | public void puts(final K1 k1, Map values) { 69 | this.map.put(k1, new ConcurrentHashMap<>(values)); 70 | } 71 | 72 | /** 73 | * 74 | */ 75 | public V remove(final K1 k1, final K2 k2) { 76 | AtomicReference r = new AtomicReference<>(null); 77 | this.map.computeIfPresent(k1, (k, v) -> { 78 | r.set(v.remove(k2)); return v.size() == 0 ? null : v; 79 | }); 80 | return r.get(); 81 | } 82 | 83 | public V put(final K1 k1, final K2 k2, final V value) { 84 | AtomicReference r = new AtomicReference<>(null); 85 | this.map.compute(k1, (k, v) -> { 86 | if(v == null) v = new ConcurrentHashMap<>(); 87 | r.set(v.put(k2, value)); return v; 88 | }); 89 | return r.get(); 90 | } 91 | 92 | public V putIfAbsent(final K1 k1, final K2 k2, final V value) { 93 | AtomicReference r = new AtomicReference<>(null); 94 | this.map.compute(k1, (k, v) -> { 95 | if(v == null) v = new ConcurrentHashMap<>(); 96 | r.set(v.putIfAbsent(k2, value)); return v; 97 | }); 98 | return r.get(); 99 | } 100 | 101 | public boolean remove(final K1 k1, final K2 k2, final V value) { 102 | AtomicBoolean r = new AtomicBoolean(false); 103 | this.map.computeIfPresent(k1, (k, v) -> { 104 | r.set(v.remove(k2, value)); return v.size() == 0 ? null : v; 105 | }); 106 | return r.get(); 107 | } 108 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Table of Contents 2 | ================= 3 | 4 | * [1. Install](#1-install) 5 | * [1.1. Brief introduction](#11-brief-introduction) 6 | * [1.2. Requirements](#12-requirements) 7 | * [1.3. Install from source code](#13-install-from-source-code) 8 | * [2. Simple usage](#2-simple-usage) 9 | * [2.1. Select date](#21-select-date) 10 | * [2.2. Select date time](#22-select-date-time) 11 | * [2.3. Select year](#23-select-year) 12 | * [2.4. Select year month](#24-select-year-month) 13 | * [2.5. Select time](#25-select-time) 14 | * [2.6. Filters](#26-filters) 15 | * [2.7. XCalendarSelectEvent](#27-xcalendarselectevent) 16 | 17 | 18 | # 1. Install 19 | ## 1.1. Brief introduction 20 | swt calendar widget 21 | 22 | ## 1.2. Requirements 23 | jdk 1.8+ 24 | maven-3.2.3+ 25 | swt 4.2.1+ 26 | 27 | ## 1.3. Install from source code 28 | 29 | ``` 30 | #windows 31 | $mvn clean install -Pwin_x86_64 -Dmaven.test.skip=true 32 | 33 | #mac 34 | $mvn clean install -Pmac_x86_64 -Dmaven.test.skip=true 35 | 36 | #linux 37 | $mvn clean install -Plinux_x86_64 -Dmaven.test.skip=true 38 | ``` 39 | 40 | # 2. Simple usage 41 | ## 2.1. Select date 42 | 43 | ```java 44 | XCalendar x = new XCalendar(text.getParent(), SWT.DATE); 45 | x.setup(v -> true, true); 46 | x.show(text.getParent(), text.getBounds()); 47 | ``` 48 | 49 | ![date](./doc/date.png) 50 | 51 | ## 2.2. Select date time 52 | 53 | ```java 54 | XCalendar x = new XCalendar(text.getParent(), SWT.LONG); 55 | x.setup(v -> true, true); 56 | x.show(text.getParent(), text.getBounds()); 57 | ``` 58 | 59 | ![date](./doc/date.png)![time](./doc/time.png) 60 | 61 | ## 2.3. Select year 62 | 63 | ```java 64 | XCalendar x = new XCalendar(text.getParent(), SWT.SHORT); 65 | x.setup(v -> true, true); 66 | x.show(text.getParent(), text.getBounds()); 67 | ``` 68 | 69 | ![year](./doc/year.png) 70 | 71 | ## 2.4. Select year month 72 | 73 | ```java 74 | XCalendar x = new XCalendar(text.getParent(), SWT.MEDIUM); 75 | x.setup(v -> true, true); 76 | x.show(text.getParent(), text.getBounds()); 77 | ``` 78 | 79 | ![year_month](./doc/year_month.png) 80 | 81 | ## 2.5. Select time 82 | 83 | ```java 84 | XCalendar x = new XCalendar(text.getParent(), SWT.TIME); 85 | x.setup(v -> true, true); 86 | x.show(text.getParent(), text.getBounds()); 87 | ``` 88 | 89 | ![time](./doc/time.png) 90 | 91 | ## 2.6. Filters 92 | 93 | ```java 94 | x.setup(v -> v.after(new Date()), true); 95 | ``` 96 | 97 | ![disable](./doc/disable.png) 98 | 99 | ## 2.7. XCalendarSelectEvent 100 | 101 | ```java 102 | XCalendar x = new XCalendar(text.getParent(), SWT.MEDIUM); 103 | x.setup(v -> true, true); 104 | x.addXCalendarEventListener(new XCalendarEventListener() { 105 | @Override 106 | public void onEvent(XCalendarEvent event) { 107 | if (!(event instanceof XCalendarSelectEvent)) return; 108 | XCalendarSelectEvent s = (XCalendarSelectEvent) event; 109 | // your code goes here. 110 | } 111 | }); 112 | x.show(text.getParent(), text.getBounds()); 113 | ``` -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/model/config/widget/impl/XCalendarNextWidget.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.impl; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.utility.graphics.Fonts; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.internal.*; 6 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.XCalendarModel; 7 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.render.XCalendarFrame; 8 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.AbstractXCalendarWidget; 9 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.theme.XCalendarTheme; 10 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.XVirtualCalendar; 11 | import cn.nextop.thorin.rcp.support.util.type.Pair; 12 | import org.eclipse.swt.graphics.GC; 13 | import org.eclipse.swt.graphics.Point; 14 | 15 | import static cn.nextop.thorin.rcp.support.swt.utility.graphics.Extents.extent; 16 | import static com.patrikdufresne.fontawesome.FontAwesome.chevron_right; 17 | 18 | /** 19 | * @author chenby 20 | * 21 | */ 22 | public class XCalendarNextWidget extends AbstractXCalendarWidget { 23 | 24 | /** 25 | * 26 | */ 27 | public XCalendarNextWidget(XCalendar popup) { 28 | super(popup); 29 | } 30 | 31 | /** 32 | * 33 | */ 34 | @Override 35 | public Pair locate(int x, int y, int w, int m) { 36 | int u = w / 7; 37 | return new Pair<>(new Point(u, u), new Point(m, y + u)); 38 | } 39 | 40 | /** 41 | * Event 42 | */ 43 | @Override 44 | protected boolean onMouseMove(XCalendarMouseMoveEvent event) { 45 | return true; 46 | } 47 | 48 | @Override 49 | protected boolean onMouseDown(XCalendarMouseDownEvent event) { 50 | return true; 51 | } 52 | 53 | @Override 54 | protected boolean onMouseEnter(XCalendarMouseEnterEvent event) { 55 | showCursor(); popup.redraw(); return true; 56 | } 57 | 58 | @Override 59 | protected boolean onMouseLeave(XCalendarMouseLeaveEvent event) { 60 | hideCursor(); popup.redraw(); return true; 61 | } 62 | 63 | @Override 64 | protected boolean onMouseUp(final XCalendarMouseUpEvent event) { 65 | if (!mouse.isEntered()) { popup.redraw(); return true; } 66 | final XCalendarModel model = popup.getModel(); 67 | final XVirtualCalendar calendar = model.getCalendar(); 68 | model.getState().next(calendar); popup.redraw(); return true; 69 | } 70 | 71 | /** 72 | * 73 | */ 74 | @Override 75 | public void render(XCalendarFrame frame) { 76 | // Background 77 | final GC gc = frame.getGc(); 78 | final XCalendarModel model = popup.getModel(); 79 | final XCalendarTheme theme = model.getTheme(); 80 | final boolean hovered = this.mouse.isEntered(); 81 | int x = bounds.x, y = bounds.y, w = bounds.width, h = bounds.height; 82 | gc.setBackground(theme.getBackground(true, false, false, hovered)); 83 | gc.fillRoundRectangle(x, y, w, h, theme.getArc(), theme.getArc()); 84 | 85 | // Foreground 86 | String text = chevron_right; 87 | gc.setForeground(theme.getForeground(true, false, true)); 88 | gc.setFont(Fonts.getAwesomeFont()); final Point size = extent(gc, text); 89 | gc.drawText(text, x + 1 + ((w - size.x) >> 1), y + 1 + ((h - size.y) >> 1)); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/model/config/widget/impl/XCalendarPrevWidget.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.impl; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.utility.graphics.Fonts; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.internal.*; 6 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.XCalendarModel; 7 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.render.XCalendarFrame; 8 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.AbstractXCalendarWidget; 9 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.theme.XCalendarTheme; 10 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.XVirtualCalendar; 11 | import cn.nextop.thorin.rcp.support.util.type.Pair; 12 | import org.eclipse.swt.graphics.GC; 13 | import org.eclipse.swt.graphics.Point; 14 | 15 | import static cn.nextop.thorin.rcp.support.swt.utility.graphics.Extents.extent; 16 | import static com.patrikdufresne.fontawesome.FontAwesome.chevron_left; 17 | 18 | /** 19 | * @author chenby 20 | * 21 | */ 22 | public class XCalendarPrevWidget extends AbstractXCalendarWidget { 23 | 24 | /** 25 | * 26 | */ 27 | public XCalendarPrevWidget(XCalendar popup) { 28 | super(popup); 29 | } 30 | 31 | /** 32 | * 33 | */ 34 | @Override 35 | public Pair locate(int x, int y, int w, int m) { 36 | int u = w / 7; 37 | return new Pair<>(new Point(u, u), new Point(x + u, y)); 38 | } 39 | 40 | /** 41 | * Event 42 | */ 43 | @Override 44 | protected boolean onMouseMove(XCalendarMouseMoveEvent event) { 45 | return true; 46 | } 47 | 48 | @Override 49 | protected boolean onMouseDown(XCalendarMouseDownEvent event) { 50 | return true; 51 | } 52 | 53 | @Override 54 | protected boolean onMouseEnter(XCalendarMouseEnterEvent event) { 55 | showCursor(); popup.redraw(); return true; 56 | } 57 | 58 | @Override 59 | protected boolean onMouseLeave(XCalendarMouseLeaveEvent event) { 60 | hideCursor(); popup.redraw(); return true; 61 | } 62 | 63 | @Override 64 | protected boolean onMouseUp(final XCalendarMouseUpEvent event) { 65 | if (!mouse.isEntered()) { popup.redraw(); return true; } 66 | final XCalendarModel model = popup.getModel(); 67 | final XVirtualCalendar calendar = model.getCalendar(); 68 | model.getState().prev(calendar); popup.redraw(); return true; 69 | } 70 | 71 | /** 72 | * 73 | */ 74 | @Override 75 | public void render(XCalendarFrame frame) { 76 | // Background 77 | final GC gc = frame.getGc(); 78 | final XCalendarModel model = popup.getModel(); 79 | final XCalendarTheme theme = model.getTheme(); 80 | final boolean hovered = this.mouse.isEntered(); 81 | int x = bounds.x, y = bounds.y, w = bounds.width, h = bounds.height; 82 | gc.setBackground(theme.getBackground(true, false, false, hovered)); 83 | gc.fillRoundRectangle(x, y, w, h, theme.getArc(), theme.getArc()); 84 | 85 | // Foreground 86 | String text = chevron_left; 87 | gc.setForeground(theme.getForeground(true, false, true)); 88 | gc.setFont(Fonts.getAwesomeFont()); final Point size = extent(gc, text); 89 | gc.drawText(text, x + 1 + ((w - size.x) >> 1), y + 1 + ((h - size.y) >> 1)); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/util/Objects.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.util; 2 | 3 | import java.io.Serializable; 4 | import java.util.HashSet; 5 | import java.util.Set; 6 | 7 | /** 8 | * 9 | * @author Jingqi Xu 10 | */ 11 | @SuppressWarnings({"unchecked"}) 12 | public final class Objects { 13 | // 14 | public static final Object NULL = new Object(); 15 | public static final Object[] EMPTY = new Object[0]; 16 | 17 | // 18 | private static final Set> PRIMITIVES_AND_WRAPPERS = new HashSet>(); 19 | static { 20 | PRIMITIVES_AND_WRAPPERS.add(boolean.class); 21 | PRIMITIVES_AND_WRAPPERS.add(Boolean.class); 22 | PRIMITIVES_AND_WRAPPERS.add(byte.class); 23 | PRIMITIVES_AND_WRAPPERS.add(Byte.class); 24 | PRIMITIVES_AND_WRAPPERS.add(char.class); 25 | PRIMITIVES_AND_WRAPPERS.add(Character.class); 26 | PRIMITIVES_AND_WRAPPERS.add(double.class); 27 | PRIMITIVES_AND_WRAPPERS.add(Double.class); 28 | PRIMITIVES_AND_WRAPPERS.add(float.class); 29 | PRIMITIVES_AND_WRAPPERS.add(Float.class); 30 | PRIMITIVES_AND_WRAPPERS.add(int.class); 31 | PRIMITIVES_AND_WRAPPERS.add(Integer.class); 32 | PRIMITIVES_AND_WRAPPERS.add(long.class); 33 | PRIMITIVES_AND_WRAPPERS.add(Long.class); 34 | PRIMITIVES_AND_WRAPPERS.add(short.class); 35 | PRIMITIVES_AND_WRAPPERS.add(Short.class); 36 | } 37 | 38 | /** 39 | * 40 | */ 41 | public static T cast(Object obj) { 42 | return (T)obj; 43 | } 44 | 45 | public static boolean isEquals(Object lhs, Object rhs) { 46 | if(lhs == rhs) return true; 47 | else if(lhs == null && rhs == null) return true; 48 | else if(lhs == null || rhs == null) return false; 49 | else return lhs.equals(rhs); 50 | } 51 | 52 | /** 53 | * 54 | */ 55 | public static boolean isArray(Object array) { 56 | if(array == null) return false; 57 | return array.getClass().isArray(); 58 | } 59 | 60 | public static boolean isSerializable(Object obj) { 61 | return obj instanceof Serializable; 62 | } 63 | 64 | public static boolean isPrimitiveOrWrapper(Object obj) { 65 | if(obj == null) return false; 66 | return PRIMITIVES_AND_WRAPPERS.contains(obj.getClass()); 67 | } 68 | 69 | public static boolean isArrayOfPrimitives(Object array) { 70 | if (array == null) return false; 71 | final Class clazz = array.getClass(); 72 | return clazz.isArray() && clazz.getComponentType().isPrimitive(); 73 | } 74 | 75 | public static boolean isArrayOfPrimitivesOrWrappers(Object array) { 76 | if (array == null) return false; 77 | final Class clazz = array.getClass(); 78 | return clazz.isArray() && PRIMITIVES_AND_WRAPPERS.contains(clazz); 79 | } 80 | 81 | /** 82 | * 83 | */ 84 | public static Object getDefaultValue(final Class clazz) { 85 | if(clazz == null || !clazz.isPrimitive()) return null; 86 | if(void.class == clazz) return null; 87 | if(boolean.class == clazz) return Boolean.FALSE; 88 | if(byte.class == clazz) return Byte.valueOf((byte) 0); 89 | if(short.class == clazz) return Short.valueOf((short) 0); 90 | if(int.class == clazz) return Integer.valueOf(0); 91 | if(long.class == clazz) return Long.valueOf(0L); 92 | if(char.class == clazz) return Character.valueOf((char) 0); 93 | if(double.class == clazz) return Double.valueOf(0d); 94 | if(float.class == clazz) return Float.valueOf(0); 95 | throw new RuntimeException("assertion failed, should not reach here, clazz: " + clazz); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/model/config/widget/impl/XCalendarClearWidget.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.impl; 2 | 3 | 4 | import cn.nextop.thorin.rcp.support.swt.utility.graphics.Fonts; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 6 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.internal.*; 7 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.reactor.impl.action.XCalendarSelectAction; 8 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.XCalendarModel; 9 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.render.XCalendarFrame; 10 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.AbstractXCalendarWidget; 11 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.theme.XCalendarTheme; 12 | import cn.nextop.thorin.rcp.support.util.type.Pair; 13 | import org.eclipse.swt.graphics.GC; 14 | import org.eclipse.swt.graphics.Point; 15 | 16 | import static cn.nextop.thorin.rcp.support.swt.utility.graphics.Extents.extent; 17 | import static com.patrikdufresne.fontawesome.FontAwesome.trash_o; 18 | 19 | /** 20 | * 21 | * @author Baoyi Chen 22 | */ 23 | public class XCalendarClearWidget extends AbstractXCalendarWidget { 24 | 25 | /** 26 | * 27 | */ 28 | public XCalendarClearWidget(XCalendar popup) { 29 | super(popup); 30 | } 31 | 32 | /** 33 | * 34 | */ 35 | @Override 36 | public Pair locate(int x, int y, int w, int m) { 37 | XCalendarModel model = popup.getModel(); 38 | boolean time = model.isDateTime(), nullable = model.isNullable(); 39 | int unit = w / 7, c = 1 + (time ? 1 : 0) + (nullable ? 1 : 0); 40 | return new Pair<>(new Point(w / c, unit), new Point(m, y + unit)); 41 | } 42 | 43 | /** 44 | * Event 45 | */ 46 | @Override 47 | protected boolean onMouseMove(XCalendarMouseMoveEvent event) { 48 | return true; 49 | } 50 | 51 | @Override 52 | protected boolean onMouseDown(XCalendarMouseDownEvent event) { 53 | return true; 54 | } 55 | 56 | @Override 57 | protected boolean onMouseEnter(XCalendarMouseEnterEvent event) { 58 | showCursor(); popup.redraw(); return true; 59 | } 60 | 61 | @Override 62 | protected boolean onMouseLeave(XCalendarMouseLeaveEvent event) { 63 | hideCursor(); popup.redraw(); return true; 64 | } 65 | 66 | @Override 67 | protected boolean onMouseUp(final XCalendarMouseUpEvent event) { 68 | if (!mouse.isEntered()) { popup.redraw(); return true; } 69 | super.submit(new XCalendarSelectAction(null)); return true; 70 | } 71 | 72 | /** 73 | * Render 74 | */ 75 | @Override 76 | public void render(XCalendarFrame frame) { 77 | // Background 78 | final GC gc = frame.getGc(); 79 | final XCalendarModel model = popup.getModel(); 80 | final XCalendarTheme theme = model.getTheme(); 81 | final boolean hovered = this.mouse.isEntered(); 82 | int x = bounds.x, y = bounds.y, w = bounds.width, h = bounds.height; 83 | gc.setBackground(theme.getBackground(true, false, false, hovered)); 84 | gc.fillRoundRectangle(x, y, w, h, theme.getArc(), theme.getArc()); 85 | 86 | // Foreground 87 | String text = trash_o; 88 | gc.setForeground(theme.getToolBarBackground(false)); 89 | gc.setFont(Fonts.getAwesomeFont()); final Point size = extent(gc, text); 90 | gc.drawText(text, x + 1 + ((w - size.x) >> 1), y + 1 + ((h - size.y) >> 1)); 91 | } 92 | } -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/model/config/widget/impl/XCalendarSelectWidget.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.impl; 2 | 3 | 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.internal.*; 6 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.XCalendarModel; 7 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.XCalendarConfig; 8 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.render.XCalendarFrame; 9 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.AbstractXCalendarWidget; 10 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.theme.XCalendarTheme; 11 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.XVirtualCalendar; 12 | import cn.nextop.thorin.rcp.support.util.type.Pair; 13 | import org.eclipse.swt.graphics.GC; 14 | import org.eclipse.swt.graphics.Point; 15 | 16 | import static cn.nextop.thorin.rcp.support.swt.utility.graphics.Extents.extent; 17 | 18 | /** 19 | * @author chenby 20 | * 21 | */ 22 | public class XCalendarSelectWidget extends AbstractXCalendarWidget { 23 | 24 | /** 25 | * 26 | */ 27 | public XCalendarSelectWidget(XCalendar popup) { 28 | super(popup); 29 | } 30 | 31 | /** 32 | * 33 | */ 34 | @Override 35 | public Pair locate(int x, int y, int w, int m) { 36 | int u = w / 7; 37 | return new Pair<>(new Point(5 * u, u), new Point(x + 5 * u, y)); 38 | } 39 | 40 | /** 41 | * Event 42 | */ 43 | @Override 44 | protected boolean onMouseMove(XCalendarMouseMoveEvent event) { 45 | return true; 46 | } 47 | 48 | @Override 49 | protected boolean onMouseDown(XCalendarMouseDownEvent event) { 50 | return true; 51 | } 52 | 53 | @Override 54 | protected boolean onMouseEnter(XCalendarMouseEnterEvent event) { 55 | showCursor(); popup.redraw(); return true; 56 | } 57 | 58 | @Override 59 | protected boolean onMouseLeave(XCalendarMouseLeaveEvent event) { 60 | hideCursor(); popup.redraw(); return true; 61 | } 62 | 63 | @Override 64 | protected boolean onMouseUp(final XCalendarMouseUpEvent event) { 65 | if (!mouse.isEntered()) { popup.redraw(); return true; } 66 | final XCalendarModel model = popup.getModel(); 67 | final XCalendarConfig config = model.getConfig(); 68 | model.getStateMachine().mutate(this); // Mutate 69 | config.getLayout().layout(popup); popup.redraw(); return true; 70 | } 71 | 72 | /** 73 | * 74 | */ 75 | @Override 76 | public void render(XCalendarFrame frame) { 77 | // Background 78 | final GC gc = frame.getGc(); 79 | final boolean hovered = mouse.isEntered(); 80 | final XCalendarModel model = popup.getModel(); 81 | final XCalendarTheme theme = model.getTheme(); 82 | final XVirtualCalendar calendar = model.getCalendar(); 83 | int x = bounds.x, y = bounds.y, w = bounds.width, h = bounds.height; 84 | gc.setBackground(theme.getBackground(true, false, false, hovered)); 85 | gc.fillRoundRectangle(x, y, w, h, theme.getArc(), theme.getArc()); 86 | 87 | // Foreground 88 | String text = model.getState().text(theme, calendar); 89 | gc.setForeground(theme.getForeground(true, false, true)); 90 | gc.setFont(theme.getBold()); final Point size = extent(gc, text); 91 | gc.drawText(text, x + 1 + ((w - size.x) >> 1), y + 1 + ((h - size.y) >> 1)); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/model/config/widget/impl/XCalendarSelectTodayWidget.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.impl; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.utility.graphics.Fonts; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.internal.*; 6 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.reactor.impl.action.XCalendarSelectAction; 7 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.XCalendarModel; 8 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.render.XCalendarFrame; 9 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.AbstractXCalendarWidget; 10 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.theme.XCalendarTheme; 11 | import cn.nextop.thorin.rcp.support.util.type.Pair; 12 | import org.eclipse.swt.graphics.GC; 13 | import org.eclipse.swt.graphics.Point; 14 | 15 | import java.util.Date; 16 | 17 | import static cn.nextop.thorin.rcp.support.swt.utility.graphics.Extents.extent; 18 | import static com.patrikdufresne.fontawesome.FontAwesome.crosshairs; 19 | 20 | /** 21 | * @author chenby 22 | * 23 | */ 24 | public class XCalendarSelectTodayWidget extends AbstractXCalendarWidget { 25 | 26 | /** 27 | * 28 | */ 29 | public XCalendarSelectTodayWidget(XCalendar popup) { 30 | super(popup); 31 | } 32 | 33 | /** 34 | * 35 | */ 36 | @Override 37 | public Pair locate(int x, int y, int w, int m) { 38 | XCalendarModel model = popup.getModel(); 39 | boolean time = model.isDateTime(), nullable = model.isNullable(); 40 | int u = w / 7; int c = 1 + (time ? 1 : 0) + (nullable ? 1 : 0); 41 | if(!time && !nullable) { 42 | return new Pair<>(new Point(w / c, u),new Point(m, y + u)); 43 | } else { 44 | return new Pair<>(new Point(w / c, u), new Point(x + w / c, y)); 45 | } 46 | } 47 | 48 | /** 49 | * Event 50 | */ 51 | @Override 52 | protected boolean onMouseMove(XCalendarMouseMoveEvent event) { 53 | return true; 54 | } 55 | 56 | @Override 57 | protected boolean onMouseDown(XCalendarMouseDownEvent event) { 58 | return true; 59 | } 60 | 61 | @Override 62 | protected boolean onMouseEnter(XCalendarMouseEnterEvent event) { 63 | showCursor(); popup.redraw(); return true; 64 | } 65 | 66 | @Override 67 | protected boolean onMouseLeave(XCalendarMouseLeaveEvent event) { 68 | hideCursor(); popup.redraw(); return true; 69 | } 70 | 71 | @Override 72 | protected boolean onMouseUp(final XCalendarMouseUpEvent event) { 73 | if (!mouse.isEntered()) { popup.redraw(); return true; } 74 | XCalendarModel model = popup.getModel(); Date now = model.now(); 75 | super.submit(new XCalendarSelectAction(now, true)); return true; 76 | } 77 | 78 | /** 79 | * 80 | */ 81 | @Override 82 | public void render(XCalendarFrame frame) { 83 | // Background 84 | final GC gc = frame.getGc(); 85 | final XCalendarModel model = popup.getModel(); 86 | final XCalendarTheme theme = model.getTheme(); 87 | final boolean hovered = this.mouse.isEntered(); 88 | int x = bounds.x, y = bounds.y, w = bounds.width, h = bounds.height; 89 | gc.setBackground(theme.getBackground(true, false, false, hovered)); 90 | gc.fillRoundRectangle(x, y, w, h, theme.getArc(), theme.getArc()); 91 | 92 | // Foreground 93 | String text = crosshairs; 94 | gc.setForeground(theme.getToolBarBackground(false)); 95 | gc.setFont(Fonts.getAwesomeFont()); final Point size = extent(gc, text); 96 | gc.drawText(text, x + 1 + ((w - size.x) >> 1), y + 1 + ((h - size.y) >> 1)); 97 | } 98 | } -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/model/config/widget/impl/XCalendarSelectTimeWidget.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.impl; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.utility.graphics.Fonts; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.internal.*; 6 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.XCalendarModel; 7 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.render.XCalendarFrame; 8 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.AbstractXCalendarWidget; 9 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.theme.XCalendarTheme; 10 | import cn.nextop.thorin.rcp.support.util.type.Pair; 11 | import org.eclipse.swt.graphics.GC; 12 | import org.eclipse.swt.graphics.Point; 13 | 14 | import static cn.nextop.thorin.rcp.support.swt.utility.graphics.Extents.extent; 15 | import static com.patrikdufresne.fontawesome.FontAwesome.calendar; 16 | import static com.patrikdufresne.fontawesome.FontAwesome.clock_o; 17 | 18 | /** 19 | * @author chenby 20 | * 21 | */ 22 | public class XCalendarSelectTimeWidget extends AbstractXCalendarWidget { 23 | 24 | /** 25 | * 26 | */ 27 | public XCalendarSelectTimeWidget(XCalendar popup) { 28 | super(popup); 29 | } 30 | 31 | /** 32 | * 33 | */ 34 | @Override 35 | public Pair locate(int x, int y, int w, int m) { 36 | XCalendarModel model = popup.getModel(); 37 | boolean time = model.isDateTime(), nullable = model.isNullable(); 38 | int u = w / 7; int c = 1 + (time ? 1 : 0) + (nullable ? 1 : 0); 39 | if (!nullable) { 40 | return new Pair<>(new Point(w / c, u), new Point(m, y + u)); 41 | } else { 42 | return new Pair<>(new Point(w / c, u), new Point(x + w / c, y)); 43 | } 44 | } 45 | 46 | /** 47 | * Event 48 | */ 49 | @Override 50 | protected boolean onMouseMove(XCalendarMouseMoveEvent event) { 51 | return true; 52 | } 53 | 54 | @Override 55 | protected boolean onMouseDown(XCalendarMouseDownEvent event) { 56 | return true; 57 | } 58 | 59 | @Override 60 | protected boolean onMouseEnter(XCalendarMouseEnterEvent event) { 61 | showCursor(); popup.redraw(); return true; 62 | } 63 | 64 | @Override 65 | protected boolean onMouseLeave(XCalendarMouseLeaveEvent event) { 66 | hideCursor(); popup.redraw(); return true; 67 | } 68 | 69 | @Override 70 | protected boolean onMouseUp(final XCalendarMouseUpEvent event) { 71 | if (!mouse.isEntered()) { popup.redraw(); return true; } 72 | XCalendarModel m = popup.getModel(); m.getStateMachine().mutate(this); 73 | m.getConfig().getLayout().layout(popup); this.popup.redraw(); return true; 74 | } 75 | 76 | /** 77 | * 78 | */ 79 | @Override 80 | public void render(XCalendarFrame frame) { 81 | // Background 82 | final GC gc = frame.getGc(); 83 | final XCalendarModel model = popup.getModel(); 84 | final XCalendarTheme theme = model.getTheme(); 85 | final boolean hovered = this.mouse.isEntered(); 86 | final boolean time = model.getStateMachine().isTime(); 87 | int x = bounds.x, y = bounds.y, w = bounds.width, h = bounds.height; 88 | gc.setBackground(theme.getBackground(true, false, false, hovered)); 89 | gc.fillRoundRectangle(x, y, w, h, theme.getArc(), theme.getArc()); 90 | 91 | // Foreground 92 | String text = time ? calendar : clock_o; 93 | gc.setForeground(theme.getToolBarBackground(false)); 94 | gc.setFont(Fonts.getAwesomeFont()); final Point size = extent(gc, text); 95 | gc.drawText(text, x + 1 + ((w - size.x) >> 1), y + 1 + ((h - size.y) >> 1)); 96 | } 97 | } -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/utility/SwtUtils.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.utility; 2 | 3 | import org.eclipse.swt.graphics.GC; 4 | import org.eclipse.swt.graphics.Point; 5 | import org.eclipse.swt.graphics.Rectangle; 6 | import org.eclipse.swt.widgets.Display; 7 | import org.eclipse.swt.widgets.Shell; 8 | import org.eclipse.swt.widgets.Slider; 9 | 10 | import javax.annotation.Nullable; 11 | import java.util.concurrent.atomic.AtomicReference; 12 | import java.util.function.Supplier; 13 | 14 | /** 15 | * 16 | * @author Jingqi Xu 17 | */ 18 | public final class SwtUtils { 19 | 20 | /** 21 | * 22 | */ 23 | public static void dispose(GC v) { 24 | if(v != null && !v.isDisposed()) v.dispose(); 25 | } 26 | 27 | /** 28 | * Display 29 | */ 30 | public static boolean isUIThread() { 31 | return isUIThread(getDisplay()); 32 | } 33 | 34 | public static boolean isUIThread(Display display) { 35 | return display.getThread() == Thread.currentThread(); 36 | } 37 | 38 | public static final Display getDisplay() { 39 | final Display display = Display.getCurrent(); 40 | return display != null ? display : Display.getDefault(); 41 | } 42 | 43 | public static void sync(@Nullable Display display, Runnable task) { 44 | if(display == null) display = getDisplay(); display.syncExec(task); 45 | } 46 | 47 | public static void async(@Nullable Display display, Runnable task) { 48 | if(display == null) display = getDisplay(); display.asyncExec(task); 49 | } 50 | 51 | public static T sync(@Nullable Display display, Supplier task) { 52 | final AtomicReference result = new AtomicReference<>(); 53 | sync(display, () -> { result.set(task.get()); }); return result.get(); 54 | } 55 | 56 | /** 57 | * Dispatch 58 | */ 59 | public static void dispatch(final Supplier condition) { 60 | final Display display = Display.getCurrent(); 61 | while (!condition.get()) if(!display.readAndDispatch()) display.sleep(); 62 | } 63 | 64 | /** 65 | * Slider 66 | */ 67 | public static void setValues(Slider s) { 68 | setValues(s, 0, 0, 1, 0); 69 | } 70 | 71 | public static void setValues(Slider s, int min, int max, int thumb) { 72 | setValues(s, min, max, thumb, s.getSelection()); 73 | } 74 | 75 | public static void setValues(Slider s, int min, int max, int thumb, int selection) { 76 | setValues(s, min, thumb + max, thumb, selection, s.getIncrement(), s.getPageIncrement()); 77 | } 78 | 79 | public static void setValues(Slider s, int min, int max, int thumb, int selection, int increment, int page) { 80 | s.setValues(selection, min, max, thumb, increment, page); 81 | } 82 | 83 | /** 84 | * Shell 85 | */ 86 | public static void center(final Shell shell) { 87 | final Rectangle r1 = shell.getMonitor().getBounds(), r2 = shell.getBounds(); 88 | shell.setLocation(r1.x + (r1.width - r2.width) / 2, r1.y + (r1.height - r2.height) / 2); 89 | } 90 | 91 | public static void resize(Shell shell, @Nullable Integer width, @Nullable Integer height) { 92 | final Point s = shell.getSize(); 93 | int w = width == null ? s.x : width, h = height == null ? s.y : height; shell.setSize(new Point(w, h)); 94 | } 95 | 96 | public static void resize(Shell shell, @Nullable Integer width, @Nullable Integer height, @Nullable Integer wMargin, @Nullable Integer hMargin) { 97 | final Rectangle r = shell.getMonitor().getBounds(); 98 | final int wm = wMargin == null ? 0 : wMargin, hm = hMargin == null ? 0 : hMargin; 99 | final int w = width == null ? r.width : width, h = height == null ? r.height : height; shell.setSize(new Point(w - (wm << 1), h - (hm << 1))); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/model/config/widget/impl/XCalendarHourWidget.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.impl; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.internal.*; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.reactor.impl.action.XCalendarSelectAction; 6 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.XCalendarModel; 7 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.render.XCalendarFrame; 8 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.AbstractXCalendarWidget; 9 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.theme.XCalendarTheme; 10 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.XVirtualCalendar; 11 | import cn.nextop.thorin.rcp.support.util.type.Pair; 12 | import org.eclipse.swt.graphics.GC; 13 | import org.eclipse.swt.graphics.Point; 14 | 15 | import static cn.nextop.thorin.rcp.support.swt.utility.graphics.Extents.extent; 16 | import static java.lang.Integer.parseInt; 17 | 18 | /** 19 | * @author chenby 20 | * 21 | */ 22 | public class XCalendarHourWidget extends AbstractXCalendarWidget { 23 | // 24 | private final int col, row; 25 | 26 | /** 27 | * 28 | */ 29 | public XCalendarHourWidget(XCalendar popup, int col, int row) { 30 | super(popup); this.col = col; this.row = row; 31 | } 32 | 33 | /** 34 | * 35 | */ 36 | @Override 37 | public Pair locate(int x, int y, int w, int m) { 38 | int unit = w / 4; int height = unit / 2 + unit / 5; 39 | if(col == 3) { x = m; y += height; } else { x += unit; } 40 | return new Pair<>(new Point(unit, height), new Point(x, y)); 41 | } 42 | 43 | /** 44 | * Event 45 | */ 46 | @Override 47 | protected boolean onMouseMove(XCalendarMouseMoveEvent event) { 48 | return true; 49 | } 50 | 51 | @Override 52 | protected boolean onMouseDown(XCalendarMouseDownEvent event) { 53 | return true; 54 | } 55 | 56 | @Override 57 | protected boolean onMouseEnter(XCalendarMouseEnterEvent event) { 58 | showCursor(); popup.redraw(); return true; 59 | } 60 | 61 | @Override 62 | protected boolean onMouseLeave(XCalendarMouseLeaveEvent event) { 63 | hideCursor(); popup.redraw(); return true; 64 | } 65 | 66 | @Override 67 | protected boolean onMouseUp(final XCalendarMouseUpEvent event) { 68 | if (!mouse.isEntered()) { popup.redraw(); return true; } 69 | final XCalendarModel model = popup.getModel(); 70 | final XCalendarTheme theme = model.getTheme(); 71 | final XVirtualCalendar v = model.getCalendar(); 72 | model.getStateMachine().mutate(this); // Mutate 73 | v.setHour(parseInt(theme.getHourTheme()[row][col])); 74 | model.getConfig().getLayout().layout(this.popup); // Layout 75 | super.submit(new XCalendarSelectAction(v.getDate())); return true; 76 | } 77 | 78 | /** 79 | * 80 | */ 81 | @Override 82 | public void render(XCalendarFrame frame) { 83 | // Background 84 | final GC gc = frame.getGc(); 85 | final XCalendarModel model = popup.getModel(); 86 | final XCalendarTheme theme = model.getTheme(); 87 | final boolean hovered = this.mouse.isEntered(); 88 | int x = bounds.x, y = bounds.y, w = bounds.width, h = bounds.height; 89 | gc.setBackground(theme.getBackground(true, false, false, hovered)); 90 | gc.fillRoundRectangle(x, y, w, h, theme.getArc(), theme.getArc()); 91 | 92 | // Foreground 93 | String text = theme.getHourTheme()[row][col]; 94 | gc.setForeground(theme.getForeground(true, false, true)); 95 | gc.setFont(theme.getFont()); final Point size = extent(gc, text); 96 | gc.drawText(text, x + 1 + ((w - size.x) >> 1), y + 1 + ((h - size.y) >> 1)); 97 | } 98 | } -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/model/config/widget/impl/XCalendarDecrWidget.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.impl; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.utility.graphics.Fonts; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.internal.*; 6 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.reactor.impl.action.XCalendarSelectAction; 7 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.XCalendarModel; 8 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.render.XCalendarFrame; 9 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.AbstractXCalendarWidget; 10 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.theme.XCalendarTheme; 11 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.XVirtualCalendar; 12 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.glossary.XCalendarTime; 13 | import cn.nextop.thorin.rcp.support.util.type.Pair; 14 | import org.eclipse.swt.graphics.GC; 15 | import org.eclipse.swt.graphics.Point; 16 | 17 | import static cn.nextop.thorin.rcp.support.swt.utility.graphics.Extents.extent; 18 | import static cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.glossary.XCalendarTime.SECOND; 19 | import static com.patrikdufresne.fontawesome.FontAwesome.chevron_down; 20 | 21 | /** 22 | * 23 | * @author chenby 24 | */ 25 | public class XCalendarDecrWidget extends AbstractXCalendarWidget { 26 | // 27 | private final XCalendarTime type; 28 | 29 | /** 30 | * 31 | */ 32 | public XCalendarDecrWidget(XCalendar popup, XCalendarTime type) { 33 | super(popup); this.type = type; setMargin(new Point(10, 10)); 34 | } 35 | 36 | /** 37 | * 38 | */ 39 | @Override 40 | public Pair locate(int x, int y, int w, int m) { 41 | int unit = w / 3; 42 | if(type == SECOND) { x = m; y += unit; } else x += unit; 43 | return new Pair<>(new Point(unit, unit), new Point(x, y)); 44 | } 45 | 46 | /** 47 | * Event 48 | */ 49 | @Override 50 | protected boolean onMouseMove(XCalendarMouseMoveEvent event) { 51 | return true; 52 | } 53 | 54 | @Override 55 | protected boolean onMouseDown(XCalendarMouseDownEvent event) { 56 | return true; 57 | } 58 | 59 | @Override 60 | protected boolean onMouseEnter(XCalendarMouseEnterEvent event) { 61 | showCursor(); popup.redraw(); return true; 62 | } 63 | 64 | @Override 65 | protected boolean onMouseLeave(XCalendarMouseLeaveEvent event) { 66 | hideCursor(); popup.redraw(); return true; 67 | } 68 | 69 | @Override 70 | protected boolean onMouseUp(final XCalendarMouseUpEvent event) { 71 | if (!mouse.isEntered()) { popup.redraw(); return true; } 72 | final XVirtualCalendar v = popup.getModel().getCalendar(); 73 | type.decr(v); return submit(new XCalendarSelectAction(v.getDate())); 74 | } 75 | 76 | /** 77 | * 78 | */ 79 | @Override 80 | public void render(XCalendarFrame frame) { 81 | // Background 82 | final GC gc = frame.getGc(); 83 | final XCalendarModel model = popup.getModel(); 84 | final XCalendarTheme theme = model.getTheme(); 85 | final boolean hovered = this.mouse.isEntered(); 86 | int x = bounds.x, y = bounds.y, w = bounds.width, h = bounds.height; 87 | gc.setBackground(theme.getBackground(true, false, false, hovered)); 88 | gc.fillRoundRectangle(x, y, w, h, theme.getArc(), theme.getArc()); 89 | 90 | // Foreground 91 | String text = chevron_down; 92 | gc.setForeground(theme.getToolBarBackground(hovered)); 93 | gc.setFont(Fonts.getAwesomeFont()); final Point size = extent(gc, text); 94 | gc.drawText(text, x + 1 + ((w - size.x) >> 1), y + 1 + ((h - size.y) >> 1)); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/model/config/widget/impl/XCalendarIncrWidget.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.impl; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.utility.graphics.Fonts; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.internal.*; 6 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.reactor.impl.action.XCalendarSelectAction; 7 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.XCalendarModel; 8 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.render.XCalendarFrame; 9 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.AbstractXCalendarWidget; 10 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.theme.XCalendarTheme; 11 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.XVirtualCalendar; 12 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.glossary.XCalendarTime; 13 | import cn.nextop.thorin.rcp.support.util.type.Pair; 14 | import org.eclipse.swt.graphics.GC; 15 | import org.eclipse.swt.graphics.Point; 16 | 17 | import static cn.nextop.thorin.rcp.support.swt.utility.graphics.Extents.extent; 18 | import static cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.glossary.XCalendarTime.SECOND; 19 | import static com.patrikdufresne.fontawesome.FontAwesome.chevron_up; 20 | 21 | /** 22 | * @author chenby 23 | * 24 | */ 25 | public class XCalendarIncrWidget extends AbstractXCalendarWidget { 26 | // 27 | private final XCalendarTime type; 28 | 29 | /** 30 | * 31 | */ 32 | public XCalendarIncrWidget(XCalendar popup, XCalendarTime type) { 33 | super(popup); this.type = type; setMargin(new Point(10, 10)); 34 | } 35 | 36 | /** 37 | * 38 | */ 39 | @Override 40 | public Pair locate(int x, int y, int w, int m) { 41 | int unit = w / 3; 42 | if(type == SECOND) { x = m; y += unit; } else x += unit; 43 | return new Pair<>(new Point(unit, unit), new Point(x, y)); 44 | } 45 | 46 | /** 47 | * Event 48 | */ 49 | @Override 50 | protected boolean onMouseMove(XCalendarMouseMoveEvent event) { 51 | return true; 52 | } 53 | 54 | @Override 55 | protected boolean onMouseDown(XCalendarMouseDownEvent event) { 56 | return true; 57 | } 58 | 59 | @Override 60 | protected boolean onMouseEnter(XCalendarMouseEnterEvent event) { 61 | showCursor(); popup.redraw(); return true; 62 | } 63 | 64 | @Override 65 | protected boolean onMouseLeave(XCalendarMouseLeaveEvent event) { 66 | hideCursor(); popup.redraw(); return true; 67 | } 68 | 69 | @Override 70 | protected boolean onMouseUp(final XCalendarMouseUpEvent event) { 71 | if (!mouse.isEntered()) { popup.redraw(); return true; } 72 | final XVirtualCalendar v = popup.getModel().getCalendar(); 73 | type.incr(v); return submit(new XCalendarSelectAction(v.getDate())); 74 | } 75 | 76 | /** 77 | * 78 | */ 79 | @Override 80 | public void render(XCalendarFrame frame) { 81 | // Background 82 | final GC gc = frame.getGc(); 83 | final XCalendarModel model = popup.getModel(); 84 | final XCalendarTheme theme = model.getTheme(); 85 | final boolean hovered = this.mouse.isEntered(); 86 | int x = bounds.x, y = bounds.y, w = bounds.width, h = bounds.height; 87 | gc.setBackground(theme.getBackground(true, false, false, hovered)); 88 | gc.fillRoundRectangle(x, y, w, h, theme.getArc(), theme.getArc()); 89 | 90 | // Foreground 91 | String text = chevron_up; 92 | gc.setForeground(theme.getToolBarBackground(hovered)); 93 | gc.setFont(Fonts.getAwesomeFont()); final Point size = extent(gc, text); 94 | gc.drawText(text, x + 1 + ((w - size.x) >> 1), y + 1 + ((h - size.y) >> 1)); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/model/config/widget/impl/XCalendarMinuteWidget.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.impl; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.internal.*; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.reactor.impl.action.XCalendarSelectAction; 6 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.XCalendarModel; 7 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.render.XCalendarFrame; 8 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.AbstractXCalendarWidget; 9 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.theme.XCalendarTheme; 10 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.XVirtualCalendar; 11 | import cn.nextop.thorin.rcp.support.util.type.Pair; 12 | import org.eclipse.swt.graphics.GC; 13 | import org.eclipse.swt.graphics.Point; 14 | 15 | import static cn.nextop.thorin.rcp.support.swt.utility.graphics.Extents.extent; 16 | import static java.lang.Integer.parseInt; 17 | 18 | /** 19 | * @author chenby 20 | * 21 | */ 22 | public class XCalendarMinuteWidget extends AbstractXCalendarWidget { 23 | // 24 | private final int col, row; 25 | 26 | /** 27 | * 28 | */ 29 | public XCalendarMinuteWidget(XCalendar popup, int col, int row) { 30 | super(popup); this.col = col; this.row = row; 31 | } 32 | 33 | /** 34 | * 35 | */ 36 | @Override 37 | public Pair locate(int x, int y, int w, int m) { 38 | int unit = w / 4; int height = unit + unit / 10; 39 | if(col == 3) { x = m; y += height; } else { x += unit; } 40 | return new Pair<>(new Point(unit, height), new Point(x, y)); 41 | } 42 | 43 | /** 44 | * Event 45 | */ 46 | @Override 47 | protected boolean onMouseMove(XCalendarMouseMoveEvent event) { 48 | return true; 49 | } 50 | 51 | @Override 52 | protected boolean onMouseDown(XCalendarMouseDownEvent event) { 53 | return true; 54 | } 55 | 56 | @Override 57 | protected boolean onMouseEnter(XCalendarMouseEnterEvent event) { 58 | showCursor(); popup.redraw(); return true; 59 | } 60 | 61 | @Override 62 | protected boolean onMouseLeave(XCalendarMouseLeaveEvent event) { 63 | hideCursor(); popup.redraw(); return true; 64 | } 65 | 66 | @Override 67 | protected boolean onMouseUp(final XCalendarMouseUpEvent event) { 68 | if (!mouse.isEntered()) { popup.redraw(); return true; } 69 | final XCalendarModel model = popup.getModel(); 70 | final XCalendarTheme theme = model.getTheme(); 71 | final XVirtualCalendar v = model.getCalendar(); 72 | model.getStateMachine().mutate(this); // Mutate 73 | v.setMinute(parseInt(theme.getMinuteTheme()[row][col])); 74 | model.getConfig().getLayout().layout(this.popup); // Layout 75 | return super.submit(new XCalendarSelectAction(v.getDate())); 76 | } 77 | 78 | /** 79 | * 80 | */ 81 | @Override 82 | public void render(XCalendarFrame frame) { 83 | // Background 84 | final GC gc = frame.getGc(); 85 | final XCalendarModel model = popup.getModel(); 86 | final XCalendarTheme theme = model.getTheme(); 87 | final boolean hovered = this.mouse.isEntered(); 88 | int x = bounds.x, y = bounds.y, w = bounds.width, h = bounds.height; 89 | gc.setBackground(theme.getBackground(true, false, false, hovered)); 90 | gc.fillRoundRectangle(x, y, w, h, theme.getArc(), theme.getArc()); 91 | 92 | // Foreground 93 | String text = theme.getMinuteTheme()[row][col]; 94 | gc.setForeground(theme.getForeground(true, false, true)); 95 | gc.setFont(theme.getFont()); final Point size = extent(gc, text); 96 | gc.drawText(text, x + 1 + ((w - size.x) >> 1), y + 1 + ((h - size.y) >> 1)); 97 | } 98 | } -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/model/config/widget/impl/XCalendarSecondWidget.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.impl; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.internal.*; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.reactor.impl.action.XCalendarSelectAction; 6 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.XCalendarModel; 7 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.render.XCalendarFrame; 8 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.AbstractXCalendarWidget; 9 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.theme.XCalendarTheme; 10 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.XVirtualCalendar; 11 | import cn.nextop.thorin.rcp.support.util.type.Pair; 12 | import org.eclipse.swt.graphics.GC; 13 | import org.eclipse.swt.graphics.Point; 14 | 15 | import static cn.nextop.thorin.rcp.support.swt.utility.graphics.Extents.extent; 16 | import static java.lang.Integer.parseInt; 17 | 18 | /** 19 | * @author chenby 20 | * 21 | */ 22 | public class XCalendarSecondWidget extends AbstractXCalendarWidget { 23 | // 24 | private final int col, row; 25 | 26 | /** 27 | * 28 | */ 29 | public XCalendarSecondWidget(XCalendar popup, int col, int row) { 30 | super(popup); this.col = col; this.row = row; 31 | } 32 | 33 | /** 34 | * 35 | */ 36 | @Override 37 | public Pair locate(int x, int y, int w, int m) { 38 | int unit = w / 4, height = unit + unit / 10; 39 | if(col == 3) { x = m; y += height; } else { x += unit; } 40 | return new Pair<>(new Point(unit, height), new Point(x, y)); 41 | } 42 | 43 | /** 44 | * Event 45 | */ 46 | @Override 47 | protected boolean onMouseMove(XCalendarMouseMoveEvent event) { 48 | return true; 49 | } 50 | 51 | @Override 52 | protected boolean onMouseDown(XCalendarMouseDownEvent event) { 53 | return true; 54 | } 55 | 56 | @Override 57 | protected boolean onMouseEnter(XCalendarMouseEnterEvent event) { 58 | showCursor(); popup.redraw(); return true; 59 | } 60 | 61 | @Override 62 | protected boolean onMouseLeave(XCalendarMouseLeaveEvent event) { 63 | hideCursor(); popup.redraw(); return true; 64 | } 65 | 66 | @Override 67 | protected boolean onMouseUp(final XCalendarMouseUpEvent event) { 68 | if (!mouse.isEntered()) { popup.redraw(); return true; } 69 | final XCalendarModel model = popup.getModel(); 70 | final XCalendarTheme theme = model.getTheme(); 71 | final XVirtualCalendar v = model.getCalendar(); 72 | model.getStateMachine().mutate(this); // Mutate 73 | v.setSecond(parseInt(theme.getSecondTheme()[row][col])); 74 | model.getConfig().getLayout().layout(this.popup); // Layout 75 | super.submit(new XCalendarSelectAction(v.getDate())); return true; 76 | } 77 | 78 | /** 79 | * 80 | */ 81 | @Override 82 | public void render(XCalendarFrame frame) { 83 | // Background 84 | final GC gc = frame.getGc(); 85 | final XCalendarModel model = popup.getModel(); 86 | final XCalendarTheme theme = model.getTheme(); 87 | final boolean hovered = this.mouse.isEntered(); 88 | int x = bounds.x, y = bounds.y, w = bounds.width, h = bounds.height; 89 | gc.setBackground(theme.getBackground(true, false, false, hovered)); 90 | gc.fillRoundRectangle(x, y, w, h, theme.getArc(), theme.getArc()); 91 | 92 | // Foreground 93 | String text = theme.getSecondTheme()[row][col]; 94 | gc.setForeground(theme.getForeground(true, false, true)); 95 | gc.setFont(theme.getFont()); final Point size = extent(gc, text); 96 | gc.drawText(text, x + 1 + ((w - size.x) >> 1), y + 1 + ((h - size.y) >> 1)); 97 | } 98 | } -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/model/config/widget/AbstractXCalendarWidget.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget; 2 | 3 | 4 | import cn.nextop.thorin.rcp.support.swt.utility.graphics.Cursors; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 6 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.XCalendarEvent; 7 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.internal.*; 8 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.reactor.XCalendarAction; 9 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.XVirtualCalendar; 10 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.tracker.XCalendarMouseTracker; 11 | import org.eclipse.swt.graphics.Point; 12 | import org.eclipse.swt.graphics.Rectangle; 13 | 14 | import java.time.ZoneId; 15 | 16 | import static cn.nextop.thorin.rcp.support.util.Objects.cast; 17 | 18 | /** 19 | * 20 | * @author Baoyi Chen 21 | */ 22 | public abstract class AbstractXCalendarWidget implements XCalendarWidget { 23 | // 24 | protected Point margin; 25 | protected Rectangle bounds; 26 | protected boolean disposed; 27 | protected final XCalendar popup; 28 | protected boolean enabled = true; 29 | protected XCalendarMouseTracker mouse; 30 | 31 | /** 32 | * 33 | */ 34 | public AbstractXCalendarWidget(XCalendar popup) { 35 | this.popup = popup; 36 | this.disposed = false; 37 | this.margin = new Point(1, 1); 38 | this.bounds = new Rectangle(0, 0, 0, 0); 39 | this.mouse = new XCalendarMouseTracker(); 40 | } 41 | 42 | /** 43 | * 44 | */ 45 | @Override 46 | public void dispose() { 47 | this.disposed = true; 48 | } 49 | 50 | @Override 51 | public boolean isDisposed() { 52 | return this.disposed; 53 | } 54 | 55 | @Override 56 | public final Point getMargin() { 57 | return this.margin; 58 | } 59 | 60 | @Override 61 | public final Rectangle getBounds() { 62 | return this.bounds; 63 | } 64 | 65 | @Override 66 | public void setMargin(Point margin) { 67 | this.margin = margin; 68 | } 69 | 70 | @Override 71 | public XCalendarMouseTracker getMouse() { 72 | return this.mouse; 73 | } 74 | @Override 75 | public void setBounds(int x, int y, int w, int h) { 76 | int mx = margin.x, my = margin.y; 77 | bounds = new Rectangle(x + mx, y + my, w - (mx << 1), h - (my << 1)); 78 | } 79 | 80 | /** 81 | * 82 | */ 83 | protected void showCursor() { 84 | this.popup.setCursor(Cursors.CURSOR_HAND); 85 | } 86 | 87 | protected void hideCursor() { 88 | this.popup.setCursor(Cursors.CURSOR_ARROW); 89 | } 90 | 91 | protected boolean submit(final XCalendarAction action) { 92 | this.popup.getReactor().submit(action); return true; 93 | } 94 | 95 | protected T query(XVirtualCalendar v, ZoneId z, int col, int row) { 96 | throw new UnsupportedOperationException(); 97 | } 98 | 99 | /** 100 | * Event 101 | */ 102 | protected boolean onMouseUp(XCalendarMouseUpEvent event) { 103 | return false; 104 | } 105 | 106 | protected boolean onMouseDown(XCalendarMouseDownEvent event) { 107 | return false; 108 | } 109 | 110 | protected boolean onMouseMove(XCalendarMouseMoveEvent event) { 111 | return false; 112 | } 113 | 114 | protected boolean onMouseEnter(XCalendarMouseEnterEvent event) { 115 | return false; 116 | } 117 | 118 | protected boolean onMouseLeave(XCalendarMouseLeaveEvent event) { 119 | return false; 120 | } 121 | 122 | @Override 123 | public boolean handle(final XCalendarEvent event) { 124 | // 125 | if(!popup.getEnabled() || !popup.getEditable()) return false; 126 | 127 | // 128 | this.mouse.track(event); 129 | if(event instanceof XCalendarMouseUpEvent) return onMouseUp(cast(event)); 130 | else if(event instanceof XCalendarMouseDownEvent) return onMouseDown(cast(event)); 131 | else if(event instanceof XCalendarMouseMoveEvent) return onMouseMove(cast(event)); 132 | else if(event instanceof XCalendarMouseEnterEvent) return onMouseEnter(cast(event)); 133 | else if(event instanceof XCalendarMouseLeaveEvent) return onMouseLeave(cast(event)); 134 | return false; 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/model/config/widget/impl/XCalendarTimeWidget.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.impl; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.internal.*; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.XCalendarModel; 6 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.XCalendarConfig; 7 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.render.XCalendarFrame; 8 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.AbstractXCalendarWidget; 9 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.theme.XCalendarTheme; 10 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.XVirtualCalendar; 11 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.glossary.XCalendarTime; 12 | import cn.nextop.thorin.rcp.support.util.type.Pair; 13 | import org.eclipse.swt.graphics.GC; 14 | import org.eclipse.swt.graphics.Point; 15 | 16 | import static cn.nextop.thorin.rcp.support.swt.utility.graphics.Extents.extent; 17 | import static cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.glossary.XCalendarTime.SECOND; 18 | 19 | /** 20 | * @author chenby 21 | * 22 | */ 23 | public class XCalendarTimeWidget extends AbstractXCalendarWidget { 24 | // 25 | private final XCalendarTime type; 26 | 27 | /** 28 | * 29 | */ 30 | public XCalendarTimeWidget(XCalendar popup, XCalendarTime type) { 31 | super(popup); this.type = type; setMargin(new Point(10, 10)); 32 | } 33 | 34 | /** 35 | * 36 | */ 37 | public XCalendarTime getType() { 38 | return type; 39 | } 40 | 41 | /** 42 | * 43 | */ 44 | @Override 45 | public Pair locate(int x, int y, int w, int m) { 46 | int unit = w / 3; 47 | if(type == SECOND) { x = m; y += unit; } else x += unit; 48 | return new Pair<>(new Point(unit, unit), new Point(x, y)); 49 | } 50 | 51 | /** 52 | * Event 53 | */ 54 | @Override 55 | protected boolean onMouseMove(XCalendarMouseMoveEvent event) { 56 | return true; 57 | } 58 | 59 | @Override 60 | protected boolean onMouseDown(XCalendarMouseDownEvent event) { 61 | return true; 62 | } 63 | 64 | @Override 65 | protected boolean onMouseEnter(XCalendarMouseEnterEvent event) { 66 | showCursor(); popup.redraw(); return true; 67 | } 68 | 69 | @Override 70 | protected boolean onMouseLeave(XCalendarMouseLeaveEvent event) { 71 | hideCursor(); popup.redraw(); return true; 72 | } 73 | 74 | @Override 75 | protected boolean onMouseUp(final XCalendarMouseUpEvent event) { 76 | if (!mouse.isEntered()) { popup.redraw(); return true; } 77 | final XCalendarModel model = popup.getModel(); 78 | final XCalendarConfig config = model.getConfig(); 79 | model.getStateMachine().mutate(this); // Mutate 80 | config.getLayout().layout(popup); popup.redraw(); return true; 81 | } 82 | 83 | /** 84 | * 85 | */ 86 | @Override 87 | public void render(XCalendarFrame frame) { 88 | // Background 89 | final GC gc = frame.getGc(); 90 | final boolean hovered = mouse.isEntered(); 91 | final XCalendarModel model = popup.getModel(); 92 | final XCalendarTheme theme = model.getTheme(); 93 | final XVirtualCalendar calendar = model.getCalendar(); 94 | int x = bounds.x, y = bounds.y, w = bounds.width, h = bounds.height; 95 | gc.setBackground(theme.getBackground(true, false, false, hovered)); 96 | gc.fillRoundRectangle(x, y, w, h, theme.getArc(), theme.getArc()); 97 | 98 | // Foreground 99 | String t1 = this.type.text(theme, calendar); 100 | gc.setForeground(theme.getForeground(true, false, true)); 101 | gc.setFont(theme.getBold()); final Point s1 = extent(gc, t1); 102 | gc.drawText(t1, x + 1 + ((w - s1.x) >> 1), y + 1 + ((h - s1.y) >> 1)); 103 | 104 | if(this.type == XCalendarTime.HOUR || this.type == XCalendarTime.MINUTE) { 105 | String t2 = ":"; Point s2 = extent(gc, t2); 106 | gc.setBackground(theme.getBackground(true, false, false, false)); 107 | gc.drawText(t2, x + 1 + w + (getMargin().x >> 2), y + 1 + ((h - s2.y) >> 1)); 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/model/XCalendarModel.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.XCalendarConfig; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.theme.XCalendarTheme; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.theme.XCalendarThemeFactory; 6 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.XCalendarUtils; 7 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.XVirtualCalendar; 8 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.fsm.XCalendarStateMachine; 9 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.glossary.XCalendarState; 10 | import org.eclipse.swt.SWT; 11 | 12 | import java.time.ZoneId; 13 | import java.time.temporal.ChronoUnit; 14 | import java.util.Date; 15 | import java.util.Locale; 16 | 17 | import static cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.XCalendarUtils.toDate; 18 | import static cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.XCalendarUtils.truncatedTo; 19 | import static cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.glossary.XCalendarState.*; 20 | 21 | /** 22 | * 23 | * @author Baoyi Chen 24 | */ 25 | public class XCalendarModel { 26 | // 27 | protected int style; 28 | protected Date date; 29 | protected ZoneId zoneId; 30 | protected boolean nullable; 31 | protected XCalendarTheme theme; 32 | protected XCalendarConfig config; 33 | protected XVirtualCalendar calendar; 34 | protected XCalendarStateMachine stateMachine; 35 | 36 | /** 37 | * 38 | */ 39 | public XCalendarModel(int style) { 40 | // 41 | this.style = style; 42 | this.config = new XCalendarConfig(); 43 | this.zoneId = ZoneId.systemDefault(); 44 | this.calendar = new XVirtualCalendar(this.zoneId, isDateTime()); 45 | this.theme = new XCalendarThemeFactory().create(Locale.getDefault()); 46 | 47 | // 48 | if (isDateTime()) { 49 | this.stateMachine = new XCalendarStateMachine(DATE, TIME); 50 | } else if (isDate()) { 51 | this.stateMachine = new XCalendarStateMachine(DATE, null); 52 | } else if (isYear()) { 53 | this.stateMachine = new XCalendarStateMachine(YEAR, null); 54 | } else if (isTime()) { 55 | this.stateMachine = new XCalendarStateMachine(TIME, null); 56 | } else if (isYearMonth()) { 57 | this.stateMachine = new XCalendarStateMachine(MONTH, null); 58 | } 59 | } 60 | 61 | /** 62 | * 63 | */ 64 | public boolean isTime() { 65 | return (style & SWT.TIME) != 0; 66 | } 67 | 68 | public boolean isDate() { 69 | return (style & SWT.DATE) != 0; 70 | } 71 | 72 | public boolean isYear() { 73 | return (style & SWT.SHORT) != 0; 74 | } 75 | 76 | public boolean isDateTime() { 77 | return (style & SWT.LONG) != 0; 78 | } 79 | 80 | public boolean isYearMonth() { 81 | return (style & SWT.MEDIUM) != 0; 82 | } 83 | 84 | /** 85 | * 86 | */ 87 | public Date getDate() { 88 | return date; 89 | } 90 | 91 | public void setDate(Date date) { 92 | this.date = date; 93 | } 94 | 95 | public ZoneId getZoneId() { 96 | return zoneId; 97 | } 98 | 99 | public void setZoneId(ZoneId zoneId) { 100 | this.zoneId = zoneId; 101 | } 102 | 103 | public boolean isNullable() { 104 | return nullable; 105 | } 106 | 107 | public void setNullable(boolean nullable) { 108 | this.nullable = nullable; 109 | } 110 | 111 | public XCalendarState getState() { 112 | return this.stateMachine.current(); 113 | } 114 | 115 | public XCalendarStateMachine getStateMachine() { 116 | return this.stateMachine; 117 | } 118 | 119 | public final XCalendarTheme getTheme() { 120 | return theme; 121 | } 122 | 123 | public final void setTheme(XCalendarTheme theme) { 124 | this.theme = theme; 125 | } 126 | 127 | public XVirtualCalendar getCalendar() { 128 | return calendar; 129 | } 130 | 131 | public void setCalendar(XVirtualCalendar calendar) { 132 | this.calendar = calendar; 133 | } 134 | 135 | public final XCalendarConfig getConfig() { 136 | return config; 137 | } 138 | 139 | public final void setConfig(XCalendarConfig config) { 140 | this.config = config; 141 | } 142 | 143 | /** 144 | * 145 | */ 146 | public Date now() { 147 | if(!isDateTime() && !isTime()) { 148 | return toDate(truncatedTo(XCalendarUtils.now(getZoneId()), ChronoUnit.DAYS)); 149 | } else { 150 | return toDate(truncatedTo(XCalendarUtils.now(getZoneId()), ChronoUnit.SECONDS)); 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/util/type/Range.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.util.type; 2 | 3 | /** 4 | * @author Jingqi Xu 5 | * @param 6 | */ 7 | public class Range> { 8 | // 9 | private T value1; 10 | private T value2; 11 | private Bound bound1; 12 | private Bound bound2; 13 | 14 | // 15 | public static enum Bound { 16 | // 17 | OPEN, CLOSED; 18 | 19 | // 20 | public boolean isOpen() { 21 | return this == OPEN; 22 | } 23 | 24 | public static Bound parse(boolean open) { 25 | return open ? OPEN : CLOSED; 26 | } 27 | 28 | private > boolean contains(T v1, T v2) { 29 | if(v1 == null) return true; 30 | if(v2 == null) return false; 31 | final int r = v1.compareTo(v2); 32 | if(r != 0) return r < 0; else return this == CLOSED; 33 | } 34 | 35 | private > boolean contains(T v1, T v2, Bound b2) { 36 | if(v1 == null) return true; 37 | if(v2 == null) return false; 38 | final int r = v1.compareTo(v2); 39 | if(r != 0) return r < 0; else return this == CLOSED && b2 == CLOSED; 40 | } 41 | } 42 | 43 | /** 44 | * 45 | */ 46 | public Range() { 47 | } 48 | 49 | public Range(T v1, T v2, Bound b1, Bound b2) { 50 | this.value1 = v1; 51 | this.value2 = v2; 52 | this.bound1 = b1; 53 | this.bound2 = b2; 54 | } 55 | 56 | /** 57 | * 58 | */ 59 | public T getValue1() { 60 | return value1; 61 | } 62 | 63 | public void setValue1(T value) { 64 | this.value1 = value; 65 | } 66 | 67 | public T getValue2() { 68 | return value2; 69 | } 70 | 71 | public void setValue2(T value) { 72 | this.value2 = value; 73 | } 74 | 75 | public Bound getBound1() { 76 | return bound1; 77 | } 78 | 79 | public void setBound1(Bound bound) { 80 | this.bound1 = bound; 81 | } 82 | 83 | public Bound getBound2() { 84 | return bound2; 85 | } 86 | 87 | public void setBound2(Bound bound) { 88 | this.bound2 = bound; 89 | } 90 | 91 | @Override 92 | public String toString() { 93 | return "Range{" + 94 | "value1=" + value1 + 95 | ", value2=" + value2 + 96 | ", bound1=" + bound1 + 97 | ", bound2=" + bound2 + 98 | '}'; 99 | } 100 | 101 | @Override 102 | public boolean equals(Object o) { 103 | if (this == o) return true; 104 | if (o == null || getClass() != o.getClass()) return false; 105 | 106 | Range range = (Range) o; 107 | 108 | if (!value1.equals(range.value1)) return false; 109 | if (!value2.equals(range.value2)) return false; 110 | if (bound1 != range.bound1) return false; 111 | return bound2 == range.bound2; 112 | } 113 | 114 | @Override 115 | public int hashCode() { 116 | int result = value1.hashCode(); 117 | result = 31 * result + value2.hashCode(); 118 | result = 31 * result + bound1.hashCode(); 119 | result = 31 * result + bound2.hashCode(); 120 | return result; 121 | } 122 | 123 | /** 124 | * 125 | */ 126 | public boolean isValid() { 127 | if(value1 == null && value2 == null) return false; 128 | if(value1 == null || value2 == null) return true; 129 | final int r = this.value2.compareTo(this.value1); 130 | if(r < 0) return false; else if(r > 0) return true; 131 | return bound1 == Bound.CLOSED && bound2 == Bound.CLOSED; 132 | } 133 | 134 | public final boolean contains(final T value) { 135 | if(!this.bound1.contains(this.value1, value)) return false; 136 | if(!this.bound2.contains(value, this.value2)) return false; 137 | return true; 138 | } 139 | 140 | public final boolean contains(final Range range) { 141 | return contains(range.getValue1()) && contains(range.getValue2()); 142 | } 143 | 144 | public final boolean isOverlap(final Range rhs) { 145 | if(!this.bound1.contains(this.value1, rhs.value2, rhs.bound2)) return false; 146 | if(!this.bound2.contains(rhs.value1, this.value2, rhs.bound1)) return false; 147 | return true; 148 | } 149 | 150 | /** 151 | * 152 | */ 153 | public static > Range open(T lower, T upper) { 154 | return new Range(lower, upper, Bound.OPEN, Bound.OPEN); 155 | } 156 | 157 | public static > Range closed(T lower, T upper) { 158 | return new Range(lower, upper, Bound.CLOSED, Bound.CLOSED); 159 | } 160 | 161 | public static > Range openClosed(T lower, T upper) { 162 | return new Range(lower, upper, Bound.OPEN, Bound.CLOSED); 163 | } 164 | 165 | public static > Range closedOpen(T lower, T upper) { 166 | return new Range(lower, upper, Bound.CLOSED, Bound.OPEN); 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/model/config/widget/impl/XCalendarYearWidget.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.impl; 2 | 3 | 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.internal.*; 6 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.reactor.impl.action.XCalendarSelectAction; 7 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.XCalendarModel; 8 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.XCalendarConfig; 9 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.render.XCalendarFrame; 10 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.AbstractXCalendarWidget; 11 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.theme.XCalendarTheme; 12 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.XVirtualCalendar; 13 | import cn.nextop.thorin.rcp.support.util.Strings; 14 | import cn.nextop.thorin.rcp.support.util.type.Pair; 15 | import org.eclipse.swt.graphics.GC; 16 | import org.eclipse.swt.graphics.Point; 17 | 18 | import java.time.ZoneId; 19 | 20 | import static cn.nextop.thorin.rcp.support.swt.utility.graphics.Extents.extent; 21 | import static cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.XCalendarUtils.*; 22 | import static cn.nextop.thorin.rcp.support.util.Objects.cast; 23 | 24 | /** 25 | * @author chenby 26 | * 27 | */ 28 | public class XCalendarYearWidget extends AbstractXCalendarWidget { 29 | // 30 | public final int col, row; 31 | 32 | /** 33 | * 34 | */ 35 | public XCalendarYearWidget(XCalendar popup, int col, int row) { 36 | super(popup); this.col = col; this.row = row; 37 | } 38 | 39 | /** 40 | * 41 | */ 42 | @Override 43 | public Pair locate(int x, int y, int w, int m) { 44 | int unit = w / 4; 45 | if(col == 3) { x = m; y += unit; } else { x += unit; } 46 | return new Pair<>(new Point(unit, unit), new Point(x, y)); 47 | } 48 | 49 | /** 50 | * Event 51 | */ 52 | @Override 53 | protected boolean onMouseMove(XCalendarMouseMoveEvent event) { 54 | return true; 55 | } 56 | 57 | @Override 58 | protected boolean onMouseDown(XCalendarMouseDownEvent event) { 59 | return true; 60 | } 61 | 62 | @Override 63 | protected boolean onMouseEnter(XCalendarMouseEnterEvent event) { 64 | if(this.enabled) showCursor(); popup.redraw(); return true; 65 | } 66 | 67 | @Override 68 | protected boolean onMouseLeave(XCalendarMouseLeaveEvent event) { 69 | if(this.enabled) hideCursor(); popup.redraw(); return true; 70 | } 71 | 72 | @Override 73 | protected boolean onMouseUp(final XCalendarMouseUpEvent event) { 74 | if (!mouse.isEntered() || !enabled) { popup.redraw(); return true; } 75 | final XCalendarModel model = popup.getModel(); 76 | final XCalendarConfig config = model.getConfig(); 77 | final XVirtualCalendar calendar = model.getCalendar(); 78 | final int y = query(calendar, model.getZoneId(), col, row); 79 | if (!model.isYear()) { 80 | calendar.setYear(y); model.getStateMachine().mutate(this); 81 | config.getLayout().layout(popup); popup.redraw(); return true; 82 | } else { 83 | return submit(new XCalendarSelectAction(soy(y, model.getZoneId()))); 84 | } 85 | } 86 | 87 | /** 88 | * 89 | */ 90 | @Override 91 | protected T query(XVirtualCalendar c, ZoneId z, int col, int row) { 92 | int idx = row * 4 + col; return cast(c.getDecade().getValue1() + idx); 93 | } 94 | 95 | /** 96 | * 97 | */ 98 | @Override 99 | public void render(XCalendarFrame frame) { 100 | // Background 101 | final GC gc = frame.getGc(); 102 | final boolean hovered = mouse.isEntered(); 103 | final XCalendarModel model = popup.getModel(); 104 | final XCalendarTheme theme = model.getTheme(); 105 | final XVirtualCalendar calendar = model.getCalendar(); 106 | final int year = query(calendar, model.getZoneId(), col, row); 107 | this.enabled = isValidYear(year, model.getZoneId(), calendar::isValid); 108 | boolean same = isSameYear(year, calendar.getCalendarDateTime().getYear()); 109 | final int x = bounds.x, y = bounds.y, w = bounds.width, h = bounds.height; 110 | gc.setBackground(theme.getBackground(enabled, same, false, hovered)); 111 | gc.fillRoundRectangle(x, y, w, h, theme.getArc(), theme.getArc()); 112 | 113 | // Foreground 114 | String text = Strings.toString(year); 115 | gc.setForeground(theme.getForeground(enabled, same, true)); 116 | gc.setFont(theme.getFont()); final Point size = extent(gc, text); 117 | gc.drawText(text, x + 1 + ((w - size.x) >> 1), y + 1 + ((h - size.y) >> 1)); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/model/theme/XCalendarTheme.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.theme; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.utility.graphics.Fonts; 4 | import org.eclipse.swt.graphics.Color; 5 | import org.eclipse.swt.graphics.Font; 6 | 7 | import static cn.nextop.thorin.rcp.support.swt.utility.graphics.Colors.getColor; 8 | 9 | /** 10 | * 11 | * @author Jingqi Xu 12 | */ 13 | public abstract class XCalendarTheme { 14 | 15 | private static final String[][] HOUR = { { "00", "01", "02", "03" }, 16 | { "04", "05", "06", "07" }, 17 | { "08", "09", "10", "11" }, 18 | { "12", "13", "14", "15" }, 19 | { "16", "17", "18", "19" }, 20 | { "20", "21", "22", "23" } }; 21 | 22 | private static final String[][] MINUTE = { { "00", "05", "10", "15" }, 23 | { "20", "25", "30", "35" }, 24 | { "40", "45", "50", "55" } }; 25 | 26 | private static final String[][] SECOND = { { "00", "05", "10", "15" }, 27 | { "20", "25", "30", "35" }, 28 | { "40", "45", "50", "55" } }; 29 | 30 | // 31 | protected int arc = 8; 32 | protected int margin = 5; 33 | protected int width = 220; 34 | protected Font font = Fonts.getSystemFont(); 35 | protected Font bold = Fonts.getFont(XCalendarTheme.class, "bold", () -> Fonts.bold(this.font)); 36 | 37 | protected Color[] grid = new Color[] { getColor(0xc8, 0xc8, 0xc8), getColor(0x8f, 0xbc, 0xee) }; 38 | protected Color[] toolbar = new Color[] { getColor(0x00, 0x00, 0x00), getColor(0x40, 0x87, 0xcc) }; 39 | protected Color[] foreground = new Color[] { getColor(0x00, 0x00, 0x00), getColor(0x9f, 0x9f, 0x9f), getColor(0xff, 0xff, 0xff) }; 40 | protected Color[] background = new Color[] { getColor(0xff, 0xff, 0xff), getColor(0xe0, 0xe0, 0xe0), getColor(0x00, 0x69, 0xcf), getColor(0xfe, 0xde, 0x00) }; 41 | 42 | /** 43 | * 44 | */ 45 | public abstract String[][] getMonthTheme(); 46 | public abstract String[] getDayOfWeekTheme(); 47 | public abstract String[] getMonthOfYearTheme(); 48 | public abstract String header(int month, int year); 49 | 50 | public String[][] getHourTheme(){ return HOUR; } 51 | public String[][] getMinuteTheme(){ return MINUTE; } 52 | public String[][] getSecondTheme(){ return SECOND; } 53 | 54 | /** 55 | * 56 | */ 57 | public int getArc() { 58 | return arc; 59 | } 60 | 61 | public Font getBold() { 62 | return bold; 63 | } 64 | 65 | public Font getFont() { 66 | return font; 67 | } 68 | 69 | public int getWidth() { 70 | return width; 71 | } 72 | 73 | public int getMargin() { 74 | return margin; 75 | } 76 | 77 | public Color[] getToolbar() { 78 | return toolbar; 79 | } 80 | 81 | public Color[] getForeground() { 82 | return foreground; 83 | } 84 | 85 | public Color[] getBackground() { 86 | return background; 87 | } 88 | 89 | /** 90 | * 91 | */ 92 | public void setArc(int arc) { 93 | this.arc = arc; 94 | } 95 | 96 | public void setBold(Font bold) { 97 | this.bold = bold; 98 | } 99 | 100 | public void setFont(Font font) { 101 | this.font = font; 102 | } 103 | 104 | public void setWidth(int width) { 105 | this.width = width; 106 | } 107 | 108 | public void setMargin(int margin) { 109 | this.margin = margin; 110 | } 111 | 112 | public void setToolbar(Color[] toolbar) { 113 | this.toolbar = toolbar; 114 | } 115 | 116 | public final void setGrid(Color[] colors) { 117 | this.grid = colors; 118 | } 119 | 120 | public void setForeground(Color[] foreground) { 121 | this.foreground = foreground; 122 | } 123 | 124 | public void setBackground(Color[] background) { 125 | this.background = background; 126 | } 127 | 128 | /** 129 | * 130 | */ 131 | public Color getGrid(boolean focused) { 132 | return focused ? grid[1] : grid[0]; 133 | } 134 | 135 | public Color getToolBarBackground(boolean hovered){ 136 | return hovered ? toolbar[0] : toolbar[1]; 137 | } 138 | 139 | public Color getForeground(boolean enabled, boolean selected, boolean same) { 140 | return !enabled? foreground[1] : selected ? foreground[2] : same ? foreground[0] : foreground[1]; 141 | } 142 | 143 | public Color getBackground(boolean enabled, boolean selected, boolean same, boolean hovered) { 144 | return !enabled ? background[0] : selected ? background[2] : same ? background[3] : hovered? background[1] : background[0]; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/model/config/widget/impl/XCalendarMonthWidget.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.impl; 2 | 3 | 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.internal.*; 6 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.reactor.impl.action.XCalendarSelectAction; 7 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.XCalendarModel; 8 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.XCalendarConfig; 9 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.render.XCalendarFrame; 10 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.AbstractXCalendarWidget; 11 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.theme.XCalendarTheme; 12 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.XVirtualCalendar; 13 | import cn.nextop.thorin.rcp.support.util.type.Pair; 14 | import org.eclipse.swt.graphics.GC; 15 | import org.eclipse.swt.graphics.Point; 16 | 17 | import java.time.ZoneId; 18 | import java.time.ZonedDateTime; 19 | 20 | import static cn.nextop.thorin.rcp.support.swt.utility.graphics.Extents.extent; 21 | import static cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.XCalendarUtils.*; 22 | import static cn.nextop.thorin.rcp.support.util.Objects.cast; 23 | 24 | /** 25 | * @author chenby 26 | * 27 | */ 28 | public class XCalendarMonthWidget extends AbstractXCalendarWidget { 29 | // 30 | private final int col, row; 31 | 32 | /** 33 | * 34 | */ 35 | public XCalendarMonthWidget(XCalendar popup, int col, int row) { 36 | super(popup); this.col = col;this.row = row; 37 | } 38 | 39 | /** 40 | * 41 | */ 42 | @Override 43 | public Pair locate(int x, int y, int w, int m) { 44 | int unit = w / 4; 45 | if(col == 3) { x = m; y += unit; } else { x += unit; } 46 | return new Pair<>(new Point(unit, unit), new Point(x, y)); 47 | } 48 | 49 | /** 50 | * Event 51 | */ 52 | @Override 53 | protected boolean onMouseMove(XCalendarMouseMoveEvent event) { 54 | return true; 55 | } 56 | 57 | @Override 58 | protected boolean onMouseDown(XCalendarMouseDownEvent event) { 59 | return true; 60 | } 61 | 62 | @Override 63 | protected boolean onMouseEnter(XCalendarMouseEnterEvent event) { 64 | if(this.enabled) showCursor(); popup.redraw(); return true; 65 | } 66 | 67 | @Override 68 | protected boolean onMouseLeave(XCalendarMouseLeaveEvent event) { 69 | if(this.enabled) hideCursor(); popup.redraw(); return true; 70 | } 71 | 72 | @Override 73 | protected boolean onMouseUp(final XCalendarMouseUpEvent event) { 74 | if(!mouse.isEntered() || !enabled) { popup.redraw(); return true; } 75 | final XCalendarModel model = popup.getModel(); 76 | final XCalendarConfig config = model.getConfig(); 77 | final XVirtualCalendar calendar = model.getCalendar(); 78 | final int m = query(calendar, model.getZoneId(), col, row); 79 | if (!model.isYearMonth()) { 80 | calendar.setMonth(m); model.getStateMachine().mutate(this); 81 | config.getLayout().layout(popup); popup.redraw(); return true; 82 | } else { 83 | final int y = calendar.getYear(); 84 | return submit(new XCalendarSelectAction(som(y, m, model.getZoneId()))); 85 | } 86 | } 87 | 88 | /** 89 | * 90 | */ 91 | @Override 92 | protected T query(XVirtualCalendar calendar, ZoneId z, int col, int row) { 93 | int idx = row * 4 + col; return cast(idx + 1); 94 | } 95 | 96 | /** 97 | * 98 | */ 99 | @Override 100 | public void render(XCalendarFrame frame) { 101 | // Background 102 | final GC gc = frame.getGc(); 103 | final boolean hovered = mouse.isEntered(); 104 | final XCalendarModel model = popup.getModel(); 105 | final XCalendarTheme theme = model.getTheme(); 106 | final XVirtualCalendar calendar = model.getCalendar(); 107 | 108 | ZoneId zoneId = model.getZoneId(); 109 | final int year = calendar.getYear(); 110 | final int month = query(calendar, zoneId, col, row); 111 | final ZonedDateTime d2 = calendar.getTravelDateTime(); 112 | final ZonedDateTime d1 = calendar.getCalendarDateTime(); 113 | boolean selected = isSameYear(d1, d2) && month == d1.getMonthValue(); 114 | this.enabled = isValidYearMonth(year, month, zoneId, calendar::isValid); 115 | int x = bounds.x, y = bounds.y, w = bounds.width, h = bounds.height; 116 | gc.setBackground(theme.getBackground(enabled, selected, false, hovered)); 117 | gc.fillRoundRectangle(x, y, w, h, theme.getArc(), theme.getArc()); 118 | 119 | // Foreground 120 | String text = theme.getMonthTheme()[row][col]; 121 | gc.setForeground(theme.getForeground(enabled, selected, true)); 122 | gc.setFont(theme.getFont()); final Point size = extent(gc, text); 123 | gc.drawText(text, x + 1 + ((w - size.x) >> 1), y + 1 + ((h - size.y) >> 1)); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/event/handler/impl/XCalendarDefaultEventHandler.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.handler.impl; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.utility.SwtUtils; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.internal.*; 6 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.XCalendarWidget; 7 | import org.eclipse.swt.SWT; 8 | import org.eclipse.swt.widgets.Display; 9 | import org.eclipse.swt.widgets.Event; 10 | import org.eclipse.swt.widgets.Shell; 11 | import org.eclipse.swt.widgets.Widget; 12 | 13 | /** 14 | * 15 | * @author Baoyi Chen 16 | */ 17 | public class XCalendarDefaultEventHandler extends AbstractXCalendarEventHandler { 18 | // 19 | protected enum Status { NORMAL, TRACKING; } 20 | 21 | // 22 | protected XCalendarWidget prev; 23 | protected Status status = Status.NORMAL; 24 | 25 | /** 26 | * 27 | */ 28 | public XCalendarDefaultEventHandler(XCalendar calendar) { 29 | super(calendar, 1); 30 | } 31 | 32 | /** 33 | * 34 | */ 35 | protected boolean reset(Context context, Event event) { 36 | // 37 | boolean r = false; this.status = Status.NORMAL; 38 | if(context.getFocus() == this) context.setFocus(null); 39 | 40 | // 41 | final XCalendarWidget prev = this.prev; this.prev = null; 42 | if(prev != null && !prev.isDisposed()) { 43 | r |= prev.handle(new XCalendarMouseLeaveEvent(event)); 44 | } 45 | return r; 46 | } 47 | 48 | /** 49 | * 50 | */ 51 | @Override 52 | protected boolean accepts(Context context, Event event) { 53 | // 54 | final Widget widget = event.widget; 55 | if(calendar == null || calendar.isDisposed()) return false; 56 | 57 | // 58 | final Shell shell = calendar.getShell(); 59 | if(widget != calendar && widget != shell) return false; 60 | return isMouseEvent(event) || event.type == SWT.Deactivate; 61 | } 62 | 63 | /** 64 | * 65 | */ 66 | @Override 67 | protected boolean process(Context context, Event event) { 68 | // Deactivated 69 | if (event.type == SWT.Deactivate) { 70 | reset(context, event); 71 | final Display display = calendar.getDisplay(); 72 | SwtUtils.sync(display, () -> calendar.hide()); 73 | return true; 74 | } 75 | 76 | // 77 | final int x = event.x, y = event.y; 78 | if (this.status == Status.NORMAL) { 79 | // 80 | if (this.prev != null && this.prev.isDisposed()) { 81 | this.prev = null; 82 | } 83 | 84 | // Exit 85 | final XCalendarWidget prev = this.prev; 86 | final XCalendarWidget next = calendar.getWidget(x, y); 87 | if (next == null || event.type == SWT.MouseExit) { 88 | return reset(context, event); 89 | } 90 | 91 | // Leave & Enter 92 | this.prev = next; 93 | if (prev != null && prev != next) { 94 | prev.handle(new XCalendarMouseLeaveEvent(event)); 95 | } 96 | if (prev == null || prev != next) { 97 | next.handle(new XCalendarMouseEnterEvent(event)); 98 | } 99 | 100 | // Up & Down & Move 101 | if (event.type == SWT.MouseMove) { 102 | return next.handle(new XCalendarMouseMoveEvent(event)); 103 | } else if (event.type == SWT.MouseUp && event.button == 1) { 104 | return next.handle(new XCalendarMouseUpEvent(event)); 105 | } else if (event.type == SWT.MouseDown && event.button == 1) { 106 | if(!next.handle(new XCalendarMouseDownEvent(event))) return false; 107 | context.setFocus(this); this.status = Status.TRACKING; return true; 108 | } 109 | return false; 110 | } else if(this.status == Status.TRACKING) { 111 | // 112 | final XCalendarWidget prev = this.prev; 113 | final XCalendarWidget next = calendar.getWidget(x, y); 114 | 115 | // Up 116 | if (event.type == SWT.MouseUp && event.button == 1) { 117 | // 118 | prev.handle(new XCalendarMouseUpEvent(event)); 119 | this.status = Status.NORMAL; context.setFocus(null); 120 | 121 | // 122 | if (next == null || prev != next) { 123 | this.prev = null; prev.handle(new XCalendarMouseLeaveEvent(event)); 124 | } 125 | if (next != null && prev != next) { 126 | this.prev = next; next.handle(new XCalendarMouseEnterEvent(event)); 127 | } 128 | } else if (event.type == SWT.MouseMove || event.type == SWT.MouseExit) { 129 | // 130 | if (next == prev && !prev.getMouse().isEntered()) { 131 | prev.handle(new XCalendarMouseEnterEvent(event)); return true; // Enter 132 | } else if (next != prev && prev.getMouse().isEntered()) { 133 | prev.handle(new XCalendarMouseLeaveEvent(event)); return true; // Leave 134 | } 135 | 136 | // 137 | prev.handle(new XCalendarMouseMoveEvent(event)); // All events are routed to previous 138 | } 139 | return true; // Handle all events if current handler owns the focus & always returns true 140 | } else { 141 | throw new AssertionError("[XCalendarPopup]failed to handle event, invalid status: " + this.status); 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/model/config/widget/impl/XCalendarDecadeWidget.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.impl; 2 | 3 | 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.internal.*; 6 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.XCalendarModel; 7 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.render.XCalendarFrame; 8 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.AbstractXCalendarWidget; 9 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.theme.XCalendarTheme; 10 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.XVirtualCalendar; 11 | import cn.nextop.thorin.rcp.support.util.Strings; 12 | import cn.nextop.thorin.rcp.support.util.type.Pair; 13 | import cn.nextop.thorin.rcp.support.util.type.Range; 14 | import org.eclipse.swt.graphics.GC; 15 | import org.eclipse.swt.graphics.Point; 16 | 17 | import java.time.ZoneId; 18 | 19 | import static cn.nextop.thorin.rcp.support.swt.utility.graphics.Extents.extent; 20 | import static cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.XCalendarUtils.DECADE_OFFSET; 21 | import static cn.nextop.thorin.rcp.support.util.Objects.cast; 22 | import static cn.nextop.thorin.rcp.support.util.type.Range.closed; 23 | 24 | /** 25 | * @author chenby 26 | * 27 | */ 28 | public class XCalendarDecadeWidget extends AbstractXCalendarWidget { 29 | // 30 | private final int col,row; 31 | 32 | /** 33 | * 34 | */ 35 | public XCalendarDecadeWidget(XCalendar popup, int col, int row) { 36 | super(popup); this.col = col; this.row = row; 37 | } 38 | 39 | /** 40 | * 41 | */ 42 | @Override 43 | public Pair locate(int x, int y, int w, int m) { 44 | int unit = w / 4; 45 | if(col == 3) { x = m; y += unit; } else { x += unit; } 46 | return new Pair<>(new Point(unit, unit), new Point(x, y)); 47 | } 48 | 49 | /** 50 | * Event 51 | */ 52 | @Override 53 | protected boolean onMouseMove(XCalendarMouseMoveEvent event) { 54 | return true; 55 | } 56 | 57 | @Override 58 | protected boolean onMouseDown(XCalendarMouseDownEvent event) { 59 | return true; 60 | } 61 | 62 | @Override 63 | protected boolean onMouseEnter(XCalendarMouseEnterEvent event) { 64 | showCursor(); popup.redraw(); return true; 65 | } 66 | 67 | @Override 68 | protected boolean onMouseLeave(XCalendarMouseLeaveEvent event) { 69 | hideCursor(); popup.redraw(); return true; 70 | } 71 | 72 | @Override 73 | protected boolean onMouseUp(final XCalendarMouseUpEvent event) { 74 | if (!mouse.isEntered()) { popup.redraw(); return true; } 75 | final XCalendarModel model = popup.getModel(); 76 | final XVirtualCalendar calendar = model.getCalendar(); 77 | Range decade = query(calendar, model.getZoneId(), col, row); 78 | if(decade != null) { // Last 3 decades are always null 79 | model.getStateMachine().mutate(this); 80 | model.getCalendar().setDecade(decade.getValue1()); 81 | } 82 | model.getConfig().getLayout().layout(popup); popup.redraw(); return true; 83 | } 84 | 85 | /** 86 | * 87 | */ 88 | @Override 89 | protected T query(XVirtualCalendar c, ZoneId z, int col, int row) { 90 | int idx = row * 4 + col; int from; 91 | final Integer v = DECADE_OFFSET[idx]; if(v == null) return null; 92 | return cast(closed((from = c.getCentury().getValue1() + v), from + 11)); 93 | } 94 | 95 | /** 96 | * 97 | */ 98 | @Override 99 | public void render(XCalendarFrame frame) { 100 | // Background 101 | final GC gc = frame.getGc(); 102 | final boolean hovered = mouse.isEntered(); 103 | final XCalendarModel model = popup.getModel(); 104 | final XCalendarTheme theme = model.getTheme(); 105 | final XVirtualCalendar calendar = model.getCalendar(); 106 | Range decade = query(calendar, model.getZoneId(), col, row); 107 | int year = model.getCalendar().getCalendarDateTime().getYear(); 108 | final boolean selected = decade != null && decade.contains(year); 109 | int x = bounds.x, y = bounds.y, w = bounds.width, h = bounds.height; 110 | gc.setBackground(theme.getBackground(true, selected, false, hovered)); 111 | gc.fillRoundRectangle(x, y, w, h, theme.getArc(), theme.getArc()); 112 | 113 | // Foreground 114 | String text = ""; 115 | if (decade != null) { 116 | Integer v1 = decade.getValue1(), v2 = decade.getValue2(); 117 | text = Strings.toString(v1) + "-" + Strings.toString(v2); 118 | } 119 | 120 | gc.setForeground(theme.getForeground(true, false, true)); 121 | gc.setFont(theme.getFont()); Point size = extent(gc, text); 122 | if(size.x > w) { 123 | String text1 = text.substring(0, text.length() / 2); 124 | final String text2 = text.substring(text.length() / 2); 125 | Point size1 = extent(gc, text1); Point size2 = extent(gc, text2); 126 | gc.drawText(text1, x + 1 + ((w - size1.x) >> 1), y + 5); 127 | gc.drawText(text2, x + 1 + ((w - size2.x) >> 1), y + 10 + size1.y); 128 | } else { 129 | gc.drawText(text, x + 1 + ((w - size.x) >> 1), y + 1 + ((h - size.y) >> 1)); 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/model/config/widget/impl/XCalendarDayWidget.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.impl; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.internal.*; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.reactor.impl.action.XCalendarSelectAction; 6 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.XCalendarModel; 7 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.render.XCalendarFrame; 8 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.AbstractXCalendarWidget; 9 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.theme.XCalendarTheme; 10 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.XVirtualCalendar; 11 | import cn.nextop.thorin.rcp.support.util.Strings; 12 | import cn.nextop.thorin.rcp.support.util.type.Pair; 13 | import org.eclipse.swt.graphics.GC; 14 | import org.eclipse.swt.graphics.Point; 15 | import org.eclipse.swt.graphics.Rectangle; 16 | 17 | import java.time.ZoneId; 18 | import java.time.ZonedDateTime; 19 | 20 | import static cn.nextop.thorin.rcp.support.swt.utility.graphics.Extents.extent; 21 | import static cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.XCalendarUtils.*; 22 | import static cn.nextop.thorin.rcp.support.util.Objects.cast; 23 | 24 | /** 25 | * @author chenby 26 | * 27 | */ 28 | public class XCalendarDayWidget extends AbstractXCalendarWidget { 29 | // 30 | private final int col, row; 31 | 32 | /** 33 | * 34 | */ 35 | public XCalendarDayWidget(XCalendar popup, int col, int row) { 36 | super(popup); this.col = col; this.row = row; 37 | } 38 | 39 | /** 40 | * 41 | */ 42 | @Override 43 | public Pair locate(int x, int y, int w, int m) { 44 | int unit = w / 7; 45 | if(col == 6) { x = m; y += unit; } else { x += unit; } 46 | return new Pair<>(new Point(unit, unit), new Point(x, y)); 47 | } 48 | 49 | /** 50 | * Event 51 | */ 52 | @Override 53 | protected boolean onMouseMove(XCalendarMouseMoveEvent event) { 54 | return true; 55 | } 56 | 57 | @Override 58 | protected boolean onMouseDown(XCalendarMouseDownEvent event) { 59 | return true; 60 | } 61 | 62 | @Override 63 | protected boolean onMouseEnter(XCalendarMouseEnterEvent event) { 64 | if(this.enabled) showCursor(); popup.redraw(); return true; 65 | } 66 | 67 | @Override 68 | protected boolean onMouseLeave(XCalendarMouseLeaveEvent event) { 69 | if(this.enabled) hideCursor(); popup.redraw(); return true; 70 | } 71 | 72 | @Override 73 | protected boolean onMouseUp(final XCalendarMouseUpEvent event) { 74 | if(!mouse.isEntered() || !enabled) { popup.redraw(); return true; } 75 | final ZoneId zoneId = popup.getModel().getZoneId(); 76 | final XVirtualCalendar calendar = popup.getModel().getCalendar(); 77 | final ZonedDateTime date = this.query(calendar, zoneId, col, row); 78 | super.submit(new XCalendarSelectAction(toDate(date))); return true; 79 | } 80 | 81 | /** 82 | * 83 | */ 84 | @Override 85 | protected T query(XVirtualCalendar c, ZoneId zoneId, int col, int row) { 86 | final int year = c.getYear(), month = c.getMonth(); 87 | final int h = c.getHour(), m = c.getMinute(), s = c.getSecond(); 88 | final ZonedDateTime som = toDateTime(year, month, 1, h, m, s, 0, zoneId); 89 | return cast(som.plusDays((row * 7 + col) - (som.getDayOfWeek().getValue() % 7))); 90 | } 91 | 92 | /** 93 | * 94 | */ 95 | @Override 96 | public void render(XCalendarFrame frame) { 97 | // Background 98 | final GC gc = frame.getGc(); 99 | final XCalendarModel model = popup.getModel(); 100 | final XCalendarTheme theme = model.getTheme(); 101 | final XVirtualCalendar calendar = model.getCalendar(); 102 | final ZonedDateTime d1 = calendar.getCalendarDateTime(); 103 | final ZonedDateTime d2 = query(calendar, model.getZoneId(), col, row); 104 | 105 | boolean hovered = this.mouse.isEntered(); 106 | boolean same1 = isSameDate(d2, now(model.getZoneId())); 107 | this.enabled = isValidDate(toDate(d2), calendar::isValid); 108 | boolean selected = model.getDate() != null && isSameDate(d1, d2); 109 | int x = bounds.x, y = bounds.y, w = bounds.width, h = bounds.height; 110 | gc.setBackground(theme.getBackground(enabled, selected, same1, hovered)); 111 | gc.fillRoundRectangle(x, y, w, h, theme.getArc(), theme.getArc()); 112 | 113 | // Foreground 114 | String text = Strings.toString(d2.getDayOfMonth()); 115 | boolean same2 = isSameYearMonth(d2, calendar.getTravelDateTime()); 116 | gc.setForeground(theme.getForeground(this.enabled, selected, same2)); 117 | gc.setFont(model.getTheme().getFont()); final Point size = extent(gc, text); 118 | gc.drawText(text, x + 1 + ((w - size.x) >> 1), y + 1 + ((h - size.y) >> 1)); 119 | 120 | if(!same1) return; int c = w / 7; 121 | gc.setClipping(x + c, y + c, w - 2 * c, h - 2 * c); 122 | gc.setBackground(theme.getForeground(true, selected, false)); 123 | gc.fillPolygon(new int[] { x + w * 3 / 5, y + h, x + w, y + h, x + w, y + h * 3 / 5 }); 124 | gc.setClipping((Rectangle) null); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/support/XVirtualCalendar.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support; 2 | 3 | import cn.nextop.thorin.rcp.support.util.type.Range; 4 | 5 | import java.time.ZoneId; 6 | import java.time.ZonedDateTime; 7 | import java.time.temporal.ChronoUnit; 8 | import java.util.Date; 9 | import java.util.function.Predicate; 10 | 11 | import static cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.XCalendarUtils.*; 12 | import static cn.nextop.thorin.rcp.support.util.type.Range.closed; 13 | import static java.time.temporal.ChronoUnit.DAYS; 14 | 15 | /** 16 | * 17 | * @author Baoyi Chen 18 | */ 19 | public class XVirtualCalendar { 20 | // 21 | private int decade; 22 | private int century; 23 | private Date prevDate; 24 | private int depth = 400; 25 | private final boolean time; 26 | private final ZoneId zoneId; 27 | private ZonedDateTime travel; 28 | private ZonedDateTime calendar; 29 | private Predicate predicate; 30 | 31 | /** 32 | * 33 | */ 34 | public XVirtualCalendar(ZoneId zoneId, boolean time) { 35 | this.zoneId = zoneId; this.time = time; this.predicate = (v) -> true; 36 | adjust(toDate(truncatedTo(now(zoneId), DAYS))); this.prevDate = null; 37 | } 38 | 39 | /** 40 | * 41 | */ 42 | private void update() { updateDecade(); updateCentury(); } 43 | private void updateDecade() { decade = travel.getYear() / 10 * 10; } 44 | private void updateCentury() { this.century = this.decade / 100 * 100; } 45 | 46 | /** 47 | * 48 | */ 49 | public void prevCentury() { century -= 100; } 50 | public void prevDecade() { decade -= 10; updateCentury(); } 51 | public void prevYear() { travel = travel.minusYears(1); update(); } 52 | public void prevMonth() { travel = travel.minusMonths(1); update(); } 53 | public void prevHour() { this.calendar = this.calendar.minusHours(1); } 54 | public void prevMinute() { this.calendar = this.calendar.minusMinutes(1); } 55 | public void prevSecond() { this.calendar = this.calendar.minusSeconds(1); } 56 | 57 | /** 58 | * 59 | */ 60 | public void nextCentury() { century += 100; } 61 | public void nextDecade() { decade += 10; updateCentury(); } 62 | public void nextYear() { travel = travel.plusYears(1); update(); } 63 | public void nextMonth() { travel = travel.plusMonths(1); update(); } 64 | public void nextHour() { this.calendar = this.calendar.plusHours(1); } 65 | public void nextMinute() { this.calendar = this.calendar.plusMinutes(1); } 66 | public void nextSecond() { this.calendar = this.calendar.plusSeconds(1); } 67 | 68 | /** 69 | * 70 | */ 71 | public Date getDate() { return toDate(calendar); } 72 | public Date getTravel() { return toDate(travel); } 73 | public ZonedDateTime getTravelDateTime() { return travel; } 74 | public ZonedDateTime getCalendarDateTime() { return calendar; } 75 | public boolean isValid(Date date) { return predicate.test(date); } 76 | public void setFilter(Predicate filter) { this.predicate = filter; } 77 | 78 | /** 79 | * 80 | */ 81 | public int getYear() { return travel.getYear(); } 82 | public int getMonth() { return travel.getMonthValue(); } 83 | public int getHour() { return this.calendar.getHour(); } 84 | public int getMinute() { return this.calendar.getMinute(); } 85 | public int getSecond() { return this.calendar.getSecond(); } 86 | public Range getDecade() { return closed(decade, decade + 11); } 87 | public Range getCentury() { return closed(century, century + 107); } 88 | 89 | /** 90 | * 91 | */ 92 | public void setCentury(int century) { this.century = century; } 93 | public void setDecade(int decade) { this.decade = decade; updateCentury(); } 94 | public void setYear(int year) { travel = travel.withYear(year); update(); } 95 | public void setMonth(int month) { travel = travel.withMonth(month); update(); } 96 | public void setHour(int hour ) { this.calendar = this.calendar.withHour(hour); } 97 | public void setMinute(int minute) { this.calendar = this.calendar.withMinute(minute); } 98 | public void setSecond(int second) { this.calendar = this.calendar.withSecond(second); } 99 | 100 | /** 101 | * 102 | */ 103 | public Date adjust(Date date) { 104 | return adjust(date, false); 105 | } 106 | 107 | public Date adjust(Date date, boolean clear) { 108 | // 109 | Date currDate = null; 110 | if (!this.time || clear) this.prevDate = null; 111 | this.travel = toDateTime(truncatedTo(date, ChronoUnit.SECONDS), zoneId); 112 | this.calendar = toDateTime(truncatedTo(date, ChronoUnit.SECONDS), zoneId); 113 | 114 | // +1 direction 115 | ZonedDateTime next = this.travel; 116 | for (int i = 0; i < depth && !isValid(currDate = toDate(next)); i++) 117 | next = next.plusDays(prevDate == null ? 1 : !prevDate.after(currDate) ? 1 : -1); 118 | if (isValid(toDate(next))) { 119 | this.travel = next; this.calendar = next; prevDate = currDate; update(); return toDate(calendar); 120 | } 121 | 122 | // -1 direction 123 | ZonedDateTime prev = this.travel; 124 | for (int i = 0; i < depth && !isValid(currDate = toDate(prev)); i++) 125 | prev = prev.plusDays(prevDate == null ? -1 : !prevDate.after(currDate) ? 1 : -1); 126 | if (isValid(toDate(prev))) { 127 | this.travel = prev; this.calendar = prev; prevDate = currDate; update(); return toDate(calendar); 128 | } 129 | return adjust(prevDate); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/support/XCalendarUtils.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support; 2 | 3 | import java.time.*; 4 | import java.time.temporal.ChronoUnit; 5 | import java.time.temporal.TemporalUnit; 6 | import java.util.Date; 7 | import java.util.function.Predicate; 8 | 9 | import static java.time.LocalDateTime.from; 10 | 11 | /** 12 | * 13 | * @author Baoyi Chen 14 | */ 15 | public final class XCalendarUtils { 16 | // 17 | public static final Integer[] DECADE_OFFSET = new Integer[] { 18 | 0, 12, 24, 36, 48, 60, 72, 84, 96, null, null, null }; 19 | 20 | /** 21 | * 22 | */ 23 | public static ZonedDateTime now(ZoneId z) { 24 | return ZonedDateTime.now(z); 25 | } 26 | 27 | /** 28 | * 29 | */ 30 | public static Date som(YearMonth ym, ZoneId zid) { 31 | return toDate(ym.atDay(1).atStartOfDay(zid)); 32 | } 33 | 34 | public static Date eom(YearMonth ym, ZoneId zid) { 35 | return toDate(ym.atEndOfMonth().atStartOfDay(zid)); 36 | } 37 | 38 | public static Date som(int y, int m, ZoneId zid) { 39 | return toDate(YearMonth.of(y, m).atDay(1).atStartOfDay(zid)); 40 | } 41 | 42 | public static Date eom(int y, int m, ZoneId zid) { 43 | return toDate(YearMonth.of(y, m).atEndOfMonth().atStartOfDay(zid)); 44 | } 45 | 46 | public static Date soy(final int y, final ZoneId zid) { 47 | return toDate(YearMonth.of(y, 1).atDay(1).atStartOfDay(zid)); 48 | } 49 | 50 | public static Date eoy(final int y, final ZoneId zid) { 51 | return toDate(YearMonth.of(y, 12).atEndOfMonth().atStartOfDay(zid)); 52 | } 53 | 54 | /** 55 | * 56 | */ 57 | public static Instant truncatedTo(Date d, TemporalUnit unit) { 58 | return d.toInstant().truncatedTo(unit); 59 | } 60 | 61 | public static Instant truncatedTo(Instant d, TemporalUnit unit) { 62 | return d.truncatedTo(unit); 63 | } 64 | 65 | public static Instant truncatedTo(ZonedDateTime d, TemporalUnit unit) { 66 | return d.truncatedTo(unit).toInstant(); 67 | } 68 | 69 | /** 70 | * 71 | */ 72 | public static boolean isSameYear(int y1, int y2) { 73 | return y1 == y2; 74 | } 75 | 76 | public static boolean isSameYear(Date d1, Date d2) { 77 | return isSameYear(from(d1.toInstant()), from(d2.toInstant())); 78 | } 79 | 80 | public static boolean isSameYear(ZonedDateTime zdt1, ZonedDateTime zdt2) { 81 | return zdt1.getYear() == zdt2.getYear(); 82 | } 83 | 84 | public static boolean isSameYear(LocalDateTime ldt1, LocalDateTime ldt2) { 85 | return ldt1.getYear() == ldt2.getYear(); 86 | } 87 | 88 | /** 89 | * 90 | */ 91 | public static boolean isSameYearMonth(Date d1, Date d2) { 92 | return isSameYearMonth(from(d1.toInstant()), from(d2.toInstant())); 93 | } 94 | 95 | public static boolean isSameYearMonth(ZonedDateTime d1, ZonedDateTime d2) { 96 | return d1.getYear() == d2.getYear() && d1.getMonthValue() == d2.getMonthValue(); 97 | } 98 | 99 | public static boolean isSameYearMonth(LocalDateTime d1, LocalDateTime d2) { 100 | return d1.getYear() == d2.getYear() && d1.getMonthValue() == d2.getMonthValue(); 101 | } 102 | 103 | /** 104 | * 105 | */ 106 | public static boolean isSameDate(Date d1, Date d2) { 107 | return isSameDate(from(d1.toInstant()), from(d2.toInstant())); 108 | } 109 | 110 | public static boolean isSameDate(ZonedDateTime d1, ZonedDateTime d2) { 111 | return d1.truncatedTo(ChronoUnit.DAYS).compareTo(d2.truncatedTo(ChronoUnit.DAYS)) == 0; 112 | } 113 | 114 | public static boolean isSameDate(LocalDateTime d1, LocalDateTime d2) { 115 | return d1.truncatedTo(ChronoUnit.DAYS).compareTo(d2.truncatedTo(ChronoUnit.DAYS)) == 0; 116 | } 117 | 118 | /** 119 | * 120 | */ 121 | public static boolean isValidDate(Date d, Predicate test) { 122 | return test.test(d); 123 | } 124 | 125 | public static boolean isValidYear(final int y, final ZoneId zid, Predicate test) { 126 | LocalDate soy = toDateTime(soy(y, zid), zid).toLocalDate(); 127 | LocalDate eoy = toDateTime(eoy(y, zid), zid).toLocalDate(); 128 | return isValid(soy, eoy, zid, test); 129 | } 130 | 131 | public static boolean isValidYearMonth(int y, int m, ZoneId zid, Predicate test) { 132 | LocalDate som = toDateTime(som(y, m, zid), zid).toLocalDate(); 133 | LocalDate eom = toDateTime(eom(y, m, zid), zid).toLocalDate(); 134 | return isValid(som, eom, zid, test); 135 | } 136 | 137 | public static boolean isValid(LocalDate ld1, LocalDate ld2, ZoneId zid, Predicate test) { 138 | while (ld1.compareTo(ld2) != 0) { 139 | if (test.test(toDate(ld1.atStartOfDay(zid)))) return true; else ld1 = ld1.plusDays(1); 140 | } 141 | return false; 142 | } 143 | 144 | /** 145 | * 146 | */ 147 | public static Date toDate(Instant v) { 148 | return Date.from(v); 149 | } 150 | 151 | public static Date toDate(ZonedDateTime v) { 152 | return Date.from(v.toInstant()); 153 | } 154 | 155 | public static ZonedDateTime toDateTime(Date v, ZoneId z) { 156 | return toDateTime(v.toInstant(), z); 157 | } 158 | 159 | public static ZonedDateTime toDateTime(Instant v, ZoneId z) { 160 | return ZonedDateTime.ofInstant(v, z); 161 | } 162 | 163 | public static Date toDate(int y, int m, int d, int hh, int mm, int ss, int nano, ZoneId z) { 164 | return toDate(ZonedDateTime.of(y, m, d, hh, mm, ss, nano, z)); 165 | } 166 | 167 | public static ZonedDateTime toDateTime(int y, int m, int d, int hh, int mm, int ss, int nano, ZoneId z) { 168 | return ZonedDateTime.of(y, m, d, hh, mm, ss, nano, z); 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/util/Strings.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.util; 2 | 3 | 4 | /** 5 | * 6 | * @author Jingqi Xu 7 | */ 8 | public final class Strings { 9 | // 10 | /** 11 | * 12 | */ 13 | public static int length(String s) { 14 | return s == null ? 0 : s.length(); 15 | } 16 | 17 | public static String lower(final String s) { 18 | return s == null ? null : s.toLowerCase(); 19 | } 20 | 21 | public static String upper(final String s) { 22 | return s == null ? null : s.toUpperCase(); 23 | } 24 | 25 | public static String add(final String... s) { 26 | if(s == null) return ""; 27 | final StringBuilder r = new StringBuilder(); 28 | for(int i = 0; i < s.length; i++) r.append(s[i]); 29 | return r.toString(); 30 | } 31 | 32 | /** 33 | * 34 | */ 35 | public static String trim(final String s) { 36 | return s == null ? null : s.trim(); 37 | } 38 | 39 | public static String trimToNull(String s) { 40 | s = trim(s); return isEmpty(s) ? null : s; 41 | } 42 | 43 | public static String trimToEmpty(String s) { 44 | return s == null ? "" : s.trim(); 45 | } 46 | 47 | public static String trim(String s, char c) { 48 | return rtrim(ltrim(s, c), c); 49 | } 50 | 51 | public static String trim(String s, int max) { 52 | if(s == null) return null; s = s.trim(); 53 | if(s.length() > max) s = s.substring(0, max); 54 | return s; 55 | } 56 | 57 | public static String ltrim(String s, char trim) { 58 | if(s == null) return null; int i = 0; 59 | for(int length = s.length(); i < length; i++) { 60 | if(s.charAt(i) != trim) break; 61 | } 62 | return i >= s.length() ? "" : s.substring(i); 63 | } 64 | 65 | public static String rtrim(String s, char trim) { 66 | if(s == null) return null; int i = s.length() - 1; 67 | for(; i >= 0; i--) if (s.charAt(i) != trim) break; 68 | return i < 0 ? "" : s.substring(0, i + 1); // Empty 69 | } 70 | 71 | /** 72 | * 73 | */ 74 | public static boolean isEmpty(String s) { 75 | return s == null || s.length() == 0; 76 | } 77 | 78 | public static boolean isEmpty(String s, boolean trim) { 79 | if(s == null) return true; 80 | return trim ? s.trim().length() == 0 : s.length() == 0; 81 | } 82 | 83 | public static boolean isEquals(final String s1, final String s2) { 84 | return isEquals(s1, s2, false); 85 | } 86 | 87 | public static boolean isEquals(String s1, String s2, boolean ic) { 88 | if(s1 == s2) return true; 89 | else if(s1 == null && s2 == null) return true; 90 | else if(s1 == null || s2 == null) return false; 91 | else return ic ? s1.equalsIgnoreCase(s2) : s1.equals(s2); 92 | } 93 | 94 | public static boolean isEquals(String s1, String s2, String... strs) { 95 | if(isEquals(s1, s2)) return true; else if(strs == null) return false; 96 | for(int i = 0; i < strs.length; i++) if(isEquals(s1, strs[i])) return true; 97 | return false; 98 | } 99 | 100 | /** 101 | * 102 | */ 103 | public static String toString(Object o) { 104 | return o == null ? "" : o.toString(); 105 | } 106 | 107 | public static String[] toArray(String s) { 108 | return s == null ? null : new String[]{s}; 109 | } 110 | 111 | public static String[] toArray(String... s) { 112 | return s; 113 | } 114 | 115 | public static String toString(Object[] array) { 116 | return toString(array, array.length); 117 | } 118 | 119 | public static String toString(byte[] array, int length) { 120 | final StringBuilder r = new StringBuilder("["); 121 | for(int i = 0, count = Math.min(length, array.length); i < count; i++) { 122 | r.append(array[i]); if(i < count - 1) r.append(","); 123 | } 124 | r.append("]"); return r.toString(); 125 | } 126 | 127 | public static String toString(int[] array, int length) { 128 | final StringBuilder r = new StringBuilder("["); 129 | for(int i = 0, count = Math.min(length, array.length); i < count; i++) { 130 | r.append(array[i]); if(i < count - 1) r.append(","); 131 | } 132 | r.append("]"); return r.toString(); 133 | } 134 | 135 | public static String toString(long[] array, int length) { 136 | final StringBuilder r = new StringBuilder("["); 137 | for(int i = 0, count = Math.min(length, array.length); i < count; i++) { 138 | r.append(array[i]); if(i < count - 1) r.append(","); 139 | } 140 | r.append("]"); return r.toString(); 141 | } 142 | 143 | public static String toString(Object[] array, int length) { 144 | final StringBuilder r = new StringBuilder("["); 145 | for(int i = 0, count = Math.min(length, array.length); i < count; i++) { 146 | r.append(array[i]); if(i < count - 1) r.append(","); 147 | } 148 | r.append("]"); return r.toString(); 149 | } 150 | 151 | /** 152 | * 153 | */ 154 | public static final String lappend(int src, int length, char padding) { 155 | return lappend(String.valueOf(src), length, padding); 156 | } 157 | 158 | public static final String rappend(int src, int length, char padding) { 159 | return rappend(String.valueOf(src), length, padding); 160 | } 161 | 162 | public static final String lappend(String src, int length, char padding) { 163 | // 164 | if(src != null && src.length() >= length) { return src; } 165 | 166 | // 167 | src = src == null ? "" : src; 168 | final StringBuilder r = new StringBuilder(length); 169 | for(int i = src.length(); i < length; i++) { r.append(padding); } 170 | r.append(src); return r.toString(); 171 | } 172 | 173 | public static final String rappend(String src, int length, char padding) { 174 | // 175 | if(src != null && src.length() >= length) { return src; } 176 | 177 | // 178 | src = src == null ? "" : src; 179 | final StringBuilder r = new StringBuilder(length); r.append(src); 180 | for(int i = src.length() ; i < length; i++) { r.append(padding); } return r.toString(); 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | cn.nextop 5 | xcalendar 6 | 1.0.0-SNAPSHOT 7 | 8 | xcalendar 9 | 10 | https://github.com/nextopcn/xcalendar 11 | 12 | 13 | 14 | The Apache Software License, Version 2.0 15 | http://www.apache.org/licenses/LICENSE-2.0.txt 16 | 17 | 18 | 19 | 20 | 21 | Jingqi Xu 22 | xujq@nextop.cn 23 | nextopcn 24 | 25 | 26 | 27 | leon.chen 28 | chenby@nextop.cn 29 | nextopcn 30 | 31 | 32 | 33 | 34 | scm:git:git@github.com:nextopcn/xcalendar.git 35 | scm:git:git@github.com:nextopcn/xcalendar.git 36 | scm:git:git@github.com:nextopcn/xcalendar.git 37 | 1.0.0 38 | 39 | 40 | 41 | github 42 | https://github.com/nextopcn/xcalendar/issues 43 | 44 | 45 | 46 | UTF-8 47 | 1.8 48 | 1.8 49 | 50 | 51 | 52 | 53 | org.slf4j 54 | slf4j-api 55 | 1.7.21 56 | 57 | 58 | com.google.code.findbugs 59 | jsr305 60 | 3.0.1 61 | 62 | 63 | org.eclipse.jface 64 | text 65 | 3.3.0-v20070606-0010 66 | provided 67 | 68 | 69 | com.patrikdufresne.fontawesome 70 | com.patrikdufresne 71 | 5.0.0 72 | system 73 | ${project.basedir}/lib/com.patrikdufresne.fontawesome-5.0.0.jar 74 | 75 | 76 | junit 77 | junit 78 | 4.11 79 | test 80 | 81 | 82 | 83 | 84 | 85 | linux_x86_64 86 | 87 | 88 | linux 89 | amd64 90 | 91 | 92 | 93 | 94 | org.eclipse.swt 95 | org.eclipse.swt.gtk.linux.x86_64 96 | [4.2.1,) 97 | provided 98 | 99 | 100 | 101 | 102 | win_x86_64 103 | 104 | 105 | windows 106 | amd64 107 | 108 | 109 | 110 | 111 | org.eclipse.swt 112 | org.eclipse.swt.win32.win32.x86_64 113 | [4.2.1,) 114 | provided 115 | 116 | 117 | 118 | 119 | mac_x86_64 120 | 121 | 122 | mac 123 | amd64 124 | 125 | 126 | 127 | 128 | org.eclipse.swt 129 | org.eclipse.swt.cocoa.macosx.x86_64 130 | [4.2.1,) 131 | provided 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | org.apache.maven.plugins 141 | maven-compiler-plugin 142 | 3.1 143 | 144 | ${maven.compiler.source} 145 | ${maven.compiler.target} 146 | 147 | 148 | 149 | org.apache.maven.plugins 150 | maven-source-plugin 151 | 3.0.1 152 | 153 | 154 | attach-sources 155 | 156 | jar 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/XCalendar.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar; 2 | 3 | 4 | import cn.nextop.thorin.rcp.support.swt.utility.SwtUtils; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.XCalendarEventBus; 6 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.XCalendarDefaultEventBus; 7 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.handler.impl.XCalendarDefaultEventHandler; 8 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.listener.XCalendarEventListener; 9 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.reactor.XCalendarReactor; 10 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.reactor.impl.XCalendarDefaultRector; 11 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.reactor.impl.action.XCalendarFeedAction; 12 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.reactor.impl.action.XCalendarResizeAction; 13 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.reactor.impl.action.XCalendarSetupAction; 14 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.XCalendarModel; 15 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.layout.XCalendarLayout; 16 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.XCalendarWidget; 17 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.XCalendarWidgetFactory; 18 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.glossary.XCalendarState; 19 | import org.eclipse.swt.SWT; 20 | import org.eclipse.swt.SWTException; 21 | import org.eclipse.swt.events.PaintEvent; 22 | import org.eclipse.swt.events.PaintListener; 23 | import org.eclipse.swt.graphics.GC; 24 | import org.eclipse.swt.graphics.Rectangle; 25 | import org.eclipse.swt.layout.FillLayout; 26 | import org.eclipse.swt.widgets.*; 27 | 28 | import java.util.Date; 29 | import java.util.HashMap; 30 | import java.util.List; 31 | import java.util.Map; 32 | import java.util.function.Predicate; 33 | 34 | import static cn.nextop.thorin.rcp.support.util.Objects.cast; 35 | 36 | /** 37 | * 38 | * @author Jingqi Xu 39 | */ 40 | public class XCalendar extends Canvas { 41 | // 42 | protected final XCalendarModel model; 43 | protected final XCalendarEventBus bus; 44 | protected final XCalendarReactor reactor; 45 | protected volatile boolean editable = true; 46 | protected final Map cookies; 47 | protected Map> widgets; 48 | 49 | // 50 | public final XCalendarEventBus getBus() { return this.bus; } 51 | public final XCalendarModel getModel() { return this.model; } 52 | public final XCalendarReactor getReactor() {return this.reactor; } 53 | 54 | /** 55 | * 56 | */ 57 | public XCalendar(Composite parent, int style) { 58 | // 59 | super(shell(parent), checkStyle(style | SWT.DOUBLE_BUFFERED)); 60 | this.cookies = new HashMap<>(); 61 | this.model = new XCalendarModel(style); 62 | this.bus = new XCalendarDefaultEventBus(this); 63 | this.reactor = new XCalendarDefaultRector(this); 64 | this.bus.addHandler(new XCalendarDefaultEventHandler(this)); 65 | 66 | // 67 | getShell().setLayout(new FillLayout()); 68 | addPaintListener(new XPaintListener()); 69 | this.addListener(SWT.MouseUp, new XListener()); 70 | this.addListener(SWT.MouseDown, new XListener()); 71 | this.addListener(SWT.MouseMove, new XListener()); 72 | this.addListener(SWT.MouseExit, new XListener()); 73 | this.addListener(SWT.MouseEnter, new XListener()); 74 | getShell().addListener(SWT.Deactivate, new XDeactivateListener()); 75 | } 76 | 77 | /** 78 | * 79 | */ 80 | @Override 81 | public boolean setFocus() { 82 | super.forceFocus(); 83 | return true; 84 | } 85 | 86 | public boolean isFocused() { 87 | return isFocusControl(); 88 | } 89 | 90 | public boolean getEditable() { 91 | return editable; 92 | } 93 | 94 | public void setEditable(boolean editable) { 95 | this.editable = editable; redraw(); 96 | } 97 | 98 | /** 99 | * Cookie 100 | */ 101 | public final T getCookie() { 102 | return getCookie("$DEFAULT"); 103 | } 104 | 105 | public final void setCookie(Object value) { 106 | setCookie("$DEFAULT", value); 107 | } 108 | 109 | public final T getCookie(final Object key) { 110 | return cast(this.cookies.get(key)); 111 | } 112 | 113 | public void setCookie(Object key, Object value) { 114 | this.cookies.put(key, value); 115 | } 116 | 117 | /** 118 | * 119 | */ 120 | public void hide() { 121 | if(!isDisposed()) getShell().dispose(); 122 | } 123 | 124 | public void show(Composite parent, Rectangle bounds) { 125 | this.widgets = XCalendarWidgetFactory.create(this); 126 | XCalendarLayout layout = model.getConfig().getLayout(); 127 | layout.layout(this, parent, bounds); getShell().open(); 128 | } 129 | 130 | /** 131 | * 132 | */ 133 | public void feed(Date date) { 134 | this.reactor.submit(new XCalendarFeedAction(date)); 135 | } 136 | 137 | public void setup(Predicate predicate) { 138 | this.reactor.submit(new XCalendarSetupAction(predicate, false)); 139 | } 140 | 141 | public void resize(Composite parent, Rectangle bounds) { 142 | this.reactor.submit(new XCalendarResizeAction(parent, bounds)); 143 | } 144 | 145 | public void setup(Predicate predicate, boolean nullable) { 146 | this.reactor.submit(new XCalendarSetupAction(predicate, nullable)); 147 | } 148 | 149 | /** 150 | * 151 | */ 152 | public List getWidgets() { 153 | return this.widgets.get(getModel().getState()); 154 | } 155 | 156 | public XCalendarWidget getWidget(int x, int y) { 157 | return filter((v) -> v.getBounds().contains(x, y)); 158 | } 159 | 160 | public void addXCalendarEventListener(XCalendarEventListener listener) { 161 | this.getBus().addListener(listener); 162 | } 163 | 164 | public void delXCalendarEventListener(XCalendarEventListener listener) { 165 | this.getBus().delListener(listener); 166 | } 167 | 168 | public XCalendarWidget filter(Predicate test) { 169 | for(XCalendarWidget v : getWidgets()) if(test.test(v)) return v; return null; 170 | } 171 | 172 | /** 173 | * 174 | */ 175 | protected void handle(Event event) { 176 | this.bus.handle(event); 177 | } 178 | 179 | protected void paint(final GC gc) { 180 | this.model.getConfig().getRender().render(this, gc); 181 | } 182 | 183 | protected static Composite shell(Composite parent) { 184 | return new Shell(parent.getShell(), SWT.NO_TRIM | SWT.ON_TOP); 185 | } 186 | 187 | protected final class XListener implements Listener { 188 | @Override public void handleEvent(Event event) { handle(event); } 189 | } 190 | 191 | protected final class XPaintListener implements PaintListener { 192 | @Override public final void paintControl(final PaintEvent event) { paint(event.gc); } 193 | } 194 | 195 | protected final class XDeactivateListener implements Listener { 196 | @Override public void handleEvent(Event event) { SwtUtils.async(null, () -> { handle(event); }); } 197 | } 198 | 199 | protected static int checkStyle(int style) { 200 | if((style & SWT.TIME) != 0 || (style & SWT.DATE) != 0 || (style & SWT.LONG) != 0 || 201 | (style & SWT.SHORT) != 0 || (style & SWT.MEDIUM) != 0) return style; else throw new SWTException(SWT.ERROR_INVALID_ARGUMENT); 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /src/test/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/XDateTimeSnippet.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.utility.SwtUtils; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.XCalendarEvent; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.bus.external.XCalendarSelectEvent; 6 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.event.listener.XCalendarEventListener; 7 | import org.eclipse.swt.SWT; 8 | import org.eclipse.swt.events.ControlEvent; 9 | import org.eclipse.swt.events.ControlListener; 10 | import org.eclipse.swt.events.SelectionAdapter; 11 | import org.eclipse.swt.events.SelectionEvent; 12 | import org.eclipse.swt.graphics.Rectangle; 13 | import org.eclipse.swt.widgets.Button; 14 | import org.eclipse.swt.widgets.Display; 15 | import org.eclipse.swt.widgets.Shell; 16 | import org.eclipse.swt.widgets.Text; 17 | 18 | import java.text.SimpleDateFormat; 19 | import java.util.Date; 20 | import java.util.function.Predicate; 21 | 22 | public class XDateTimeSnippet { 23 | 24 | public static void main(String[] args) { 25 | // 26 | Display display = new Display(); 27 | Shell shell = new Shell(display); 28 | shell.setLayout(null); 29 | 30 | // 31 | Object[] o1 = calendar(shell, SWT.LONG, v -> v.before(new Date()), true); 32 | Text text1 = (Text) o1[0]; 33 | Button button1 = (Button) o1[1]; 34 | 35 | Object[] o2 = calendar(shell, SWT.SHORT, v -> v.before(new Date()), true); 36 | Text text2 = (Text) o2[0]; 37 | Button button2 = (Button) o2[1]; 38 | 39 | Object[] o3 = calendar(shell, SWT.MEDIUM, v -> v.before(new Date()), true); 40 | Text text3 = (Text) o3[0]; 41 | Button button3 = (Button) o3[1]; 42 | 43 | Object[] o4 = calendar(shell, SWT.DATE, v -> v.before(new Date()), true); 44 | Text text4 = (Text) o4[0]; 45 | Button button4 = (Button) o4[1]; 46 | 47 | Object[] o5 = calendar(shell, SWT.LONG, v -> true, false); 48 | Text text5 = (Text) o5[0]; 49 | Button button5 = (Button) o5[1]; 50 | 51 | Object[] o6 = calendar(shell, SWT.MEDIUM, v -> true, true); 52 | Text text6 = (Text) o6[0]; 53 | Button button6 = (Button) o6[1]; 54 | 55 | Object[] o7 = calendar(shell, SWT.SHORT, v -> true, true); 56 | Text text7 = (Text) o7[0]; 57 | Button button7 = (Button) o7[1]; 58 | 59 | Object[] o8 = calendar(shell, SWT.TIME, v -> true, true); 60 | Text text8 = (Text) o8[0]; 61 | Button button8 = (Button) o8[1]; 62 | 63 | shell.addControlListener(new ControlListener() { 64 | @Override 65 | public void controlMoved(ControlEvent e) { 66 | } 67 | 68 | @Override 69 | public void controlResized(ControlEvent e) { 70 | final Rectangle r = shell.getClientArea(); 71 | final int h = (r.height - 5) / 10; 72 | text1.setBounds(5, 5, r.width - 60, h - 5); 73 | button1.setBounds(5 + r.width - 60, 5, 40, h - 5); 74 | 75 | text2.setBounds(5, 1 * h + 5, r.width - 60, h - 5); 76 | button2.setBounds(5 + r.width - 60, 1 * h + 5, 40, h - 5); 77 | 78 | text3.setBounds(5, 2 * h + 5, r.width - 60, h - 5); 79 | button3.setBounds(5 + r.width - 60, 2 * h + 5, 40, h - 5); 80 | 81 | text4.setBounds(5, 3 * h + 5, r.width - 60, h - 5); 82 | button4.setBounds(5 + r.width - 60, 3 * h + 5, 40, h - 5); 83 | 84 | text5.setBounds(5, 4 * h + 5, r.width - 60, h - 5); 85 | button5.setBounds(5 + r.width - 60, 4 * h + 5, 40, h - 5); 86 | 87 | text6.setBounds(5, 5 * h + 5, r.width - 60, h - 5); 88 | button6.setBounds(5 + r.width - 60, 5 * h + 5, 40, h - 5); 89 | 90 | text7.setBounds(5, 6 * h + 5, r.width - 60, h - 5); 91 | button7.setBounds(5 + r.width - 60, 6 * h + 5, 40, h - 5); 92 | 93 | text8.setBounds(5, 7 * h + 5, r.width - 60, h - 5); 94 | button8.setBounds(5 + r.width - 60, 7 * h + 5, 40, h - 5); 95 | } 96 | }); 97 | // 98 | shell.setSize(300, 330); 99 | shell.layout(); 100 | shell.open(); 101 | SwtUtils.center(shell); 102 | while (!shell.isDisposed()) if (!display.readAndDispatch()) display.sleep(); 103 | display.dispose(); 104 | } 105 | 106 | private static Object[] calendar(Shell shell, int style, Predicate test, boolean nullable) { 107 | Text text1 = new Text(shell, SWT.BORDER); 108 | Button button1 = new Button(shell, SWT.PUSH); 109 | button1.setText("click"); 110 | button1.addSelectionListener(new XSelectionAdapter(text1, style, test, nullable)); 111 | return new Object[]{text1, button1}; 112 | } 113 | 114 | private static class XSelectionAdapter extends SelectionAdapter { 115 | private final Text text; 116 | private final int style; 117 | private final boolean nullable; 118 | private final Predicate test; 119 | 120 | public XSelectionAdapter(Text text, int style, Predicate test, boolean nullable) { 121 | this.text = text; 122 | this.style = style; 123 | this.test = test; 124 | this.nullable = nullable; 125 | } 126 | 127 | @Override 128 | public void widgetSelected(SelectionEvent selectionEvent) { 129 | XCalendar x = new XCalendar(text.getParent(), style); 130 | x.setup(test, nullable); 131 | x.addXCalendarEventListener(new XCalendarEventListener() { 132 | @Override 133 | public void onEvent(XCalendarEvent event) { 134 | if (!(event instanceof XCalendarSelectEvent)) return; 135 | XCalendarSelectEvent s = (XCalendarSelectEvent) event; 136 | text.setData(s.getValue()); 137 | String v = ""; 138 | if (s.getValue() != null || s.getYear() != null || s.getYearMonth() != null || s.getTime() != null) { 139 | if (x.getModel().isDateTime()) { 140 | SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 141 | v = format.format(s.getValue()); 142 | } else if (x.getModel().isDate()) { 143 | SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); 144 | v = format.format(s.getValue()); 145 | } else if (x.getModel().isYear()) { 146 | v = String.valueOf(s.getYear()); 147 | } else if (x.getModel().isYearMonth()) { 148 | SimpleDateFormat format = new SimpleDateFormat("yyyy-MM"); 149 | v = format.format(s.getValue()); 150 | } else if (x.getModel().isTime()) { 151 | SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss"); 152 | v = format.format(s.getTime()); 153 | } 154 | } 155 | text.setText(v); 156 | } 157 | }); 158 | x.show(text.getParent(), text.getBounds()); 159 | } 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/main/java/cn/nextop/thorin/rcp/support/swt/widget/xcalendar/model/config/widget/XCalendarWidgetFactory.java: -------------------------------------------------------------------------------- 1 | package cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget; 2 | 3 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.XCalendar; 4 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.XCalendarModel; 5 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.model.config.widget.impl.*; 6 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.glossary.XCalendarState; 7 | import cn.nextop.thorin.rcp.support.swt.widget.xcalendar.support.glossary.XCalendarTime; 8 | 9 | import java.util.HashMap; 10 | import java.util.LinkedList; 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | /** 15 | * 16 | * @author Baoyi Chen 17 | */ 18 | public class XCalendarWidgetFactory { 19 | 20 | /** 21 | * 22 | */ 23 | public static Map> create(XCalendar popup) { 24 | XCalendarModel model = popup.getModel(); 25 | List headers = new LinkedList<>(); 26 | headers.add(new XCalendarPrevWidget(popup)); 27 | headers.add(new XCalendarSelectWidget(popup)); 28 | headers.add(new XCalendarNextWidget(popup)); 29 | 30 | Map> r = new HashMap<>(); 31 | decade(r, headers, popup); 32 | year(r, headers, popup); if(model.isYear()) return r; 33 | month(r, headers, popup); if(model.isYearMonth()) return r; 34 | day(r, headers, popup); if (model.isDate()) return r; 35 | time(r, popup); hour(r, popup); minute(r, popup); second(r, popup); return r; 36 | } 37 | 38 | /** 39 | * 40 | */ 41 | private static void time(Map> out, XCalendar popup) { 42 | XCalendarModel model = popup.getModel(); 43 | List widgets = new LinkedList<>(); 44 | widgets.add(new XCalendarSelectTodayWidget(popup)); 45 | if (!model.isTime()) widgets.add(new XCalendarSelectTimeWidget(popup)); 46 | if (model.isNullable()) widgets.add(new XCalendarClearWidget(popup)); 47 | 48 | widgets.add(new XCalendarIncrWidget(popup, XCalendarTime.HOUR)); 49 | widgets.add(new XCalendarIncrWidget(popup, XCalendarTime.MINUTE)); 50 | widgets.add(new XCalendarIncrWidget(popup, XCalendarTime.SECOND)); 51 | 52 | widgets.add(new XCalendarTimeWidget(popup, XCalendarTime.HOUR)); 53 | widgets.add(new XCalendarTimeWidget(popup, XCalendarTime.MINUTE)); 54 | widgets.add(new XCalendarTimeWidget(popup, XCalendarTime.SECOND)); 55 | 56 | widgets.add(new XCalendarDecrWidget(popup, XCalendarTime.HOUR)); 57 | widgets.add(new XCalendarDecrWidget(popup, XCalendarTime.MINUTE)); 58 | widgets.add(new XCalendarDecrWidget(popup, XCalendarTime.SECOND)); 59 | out.put(XCalendarState.TIME, widgets); 60 | } 61 | 62 | private static void hour(Map> out, XCalendar popup) { 63 | XCalendarModel model = popup.getModel(); 64 | List widgets = new LinkedList<>(); 65 | 66 | int hourColumn = 4, hourRow = 6; 67 | widgets.add(new XCalendarSelectTodayWidget(popup)); 68 | if (!model.isTime()) widgets.add(new XCalendarSelectTimeWidget(popup)); 69 | if (model.isNullable()) widgets.add(new XCalendarClearWidget(popup)); 70 | 71 | for (int row = 0; row < hourRow; row++) 72 | for (int col = 0; col < hourColumn; col++) 73 | widgets.add(new XCalendarHourWidget(popup, col, row)); 74 | 75 | out.put(XCalendarState.HOUR, widgets); 76 | } 77 | 78 | private static void minute(Map> out, XCalendar popup) { 79 | XCalendarModel model = popup.getModel(); 80 | List widgets = new LinkedList<>(); 81 | 82 | int minuteColumn = 4, minuteRow = 3; 83 | widgets.add(new XCalendarSelectTodayWidget(popup)); 84 | if (!model.isTime()) widgets.add(new XCalendarSelectTimeWidget(popup)); 85 | if (model.isNullable()) widgets.add(new XCalendarClearWidget(popup)); 86 | 87 | for (int row = 0; row < minuteRow; row++) 88 | for (int col = 0; col < minuteColumn; col++) 89 | widgets.add(new XCalendarMinuteWidget(popup, col, row)); 90 | 91 | out.put(XCalendarState.MINUTE, widgets); 92 | } 93 | 94 | private static void second(Map> out, XCalendar popup) { 95 | XCalendarModel model = popup.getModel(); 96 | List widgets = new LinkedList<>(); 97 | 98 | int secondColumn = 4, secondRow = 3; 99 | widgets.add(new XCalendarSelectTodayWidget(popup)); 100 | if (!model.isTime()) widgets.add(new XCalendarSelectTimeWidget(popup)); 101 | if (model.isNullable()) widgets.add(new XCalendarClearWidget(popup)); 102 | 103 | for (int row = 0; row < secondRow; row++) 104 | for (int col = 0; col < secondColumn; col++) 105 | widgets.add(new XCalendarSecondWidget(popup, col, row)); 106 | 107 | out.put(XCalendarState.SECOND, widgets); 108 | } 109 | 110 | /** 111 | * 112 | */ 113 | private static void day(Map> out, List headers, XCalendar popup) { 114 | XCalendarModel model = popup.getModel(); 115 | List widgets = new LinkedList<>(); 116 | widgets.addAll(headers); 117 | 118 | int dayColumn = 7,dayRow = 6; 119 | for (int col = 0; col < dayColumn; col++) 120 | widgets.add(new XCalendarTextWidget(popup, col)); 121 | 122 | for (int row = 0; row < dayRow; row++) 123 | for (int col = 0; col < dayColumn; col++) 124 | widgets.add(new XCalendarDayWidget(popup, col, row)); 125 | 126 | widgets.add(new XCalendarSelectTodayWidget(popup)); 127 | if (model.isDateTime()) widgets.add(new XCalendarSelectTimeWidget(popup)); 128 | if (model.isNullable()) widgets.add(new XCalendarClearWidget(popup)); 129 | out.put(XCalendarState.DATE, widgets); 130 | } 131 | 132 | private static void month(Map> out, List headers, XCalendar popup) { 133 | XCalendarModel model = popup.getModel(); 134 | List widgets = new LinkedList<>(); 135 | widgets.addAll(headers); 136 | 137 | int monthColumn = 4, monthRow = 3; 138 | for (int row = 0; row < monthRow; row++) 139 | for (int col = 0; col < monthColumn; col++) 140 | widgets.add(new XCalendarMonthWidget(popup, col, row)); 141 | 142 | widgets.add(new XCalendarSelectTodayWidget(popup)); 143 | if (model.isDateTime()) widgets.add(new XCalendarSelectTimeWidget(popup)); 144 | if (model.isNullable()) widgets.add(new XCalendarClearWidget(popup)); 145 | out.put(XCalendarState.MONTH, widgets); 146 | } 147 | 148 | private static void year(Map> out, List headers, XCalendar popup) { 149 | XCalendarModel model = popup.getModel(); 150 | List widgets = new LinkedList<>(); 151 | widgets.addAll(headers); 152 | 153 | int yearColumn = 4, yearRow = 3; 154 | for (int row = 0; row < yearRow; row++) 155 | for (int col = 0; col < yearColumn; col++) 156 | widgets.add(new XCalendarYearWidget(popup, col, row)); 157 | 158 | widgets.add(new XCalendarSelectTodayWidget(popup)); 159 | if (model.isDateTime()) widgets.add(new XCalendarSelectTimeWidget(popup)); 160 | if (model.isNullable()) widgets.add(new XCalendarClearWidget(popup)); 161 | out.put(XCalendarState.YEAR, widgets); 162 | } 163 | 164 | private static void decade(Map> out, List headers, XCalendar popup) { 165 | XCalendarModel model = popup.getModel(); 166 | List widgets = new LinkedList<>(); 167 | widgets.addAll(headers); 168 | 169 | int decadeColumn = 4, decadeRow = 3; 170 | for (int row = 0; row < decadeRow; row++) 171 | for (int col = 0; col < decadeColumn; col++) 172 | widgets.add(new XCalendarDecadeWidget(popup, col, row)); 173 | 174 | widgets.add(new XCalendarSelectTodayWidget(popup)); 175 | if (model.isDateTime()) widgets.add(new XCalendarSelectTimeWidget(popup)); 176 | if (model.isNullable()) widgets.add(new XCalendarClearWidget(popup)); 177 | out.put(XCalendarState.DECADE, widgets); 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------