How to handle datepicker control in Katalon studio?
I am very new to Katalon studio.
Here is custom keyword to handle bootstrap date-picker.
package framework
class component{
#Keyword
public static void handleDatepicker(TestObject calender, String exp_Date, String exp_Month,
String exp_Year) throws Exception {
String expDate = null, calYear = null,datepickerText=null,minYear=null,maxYear=null;
int expMonth = 0, expYear = 0;
WebElement datePicker;
List<WebElement> noOfDays=null,noOfMonths=null,noOfYears=null;
boolean dateNotFound = true;
List<String> monthList = Arrays.asList("None","Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
"Aug", "Sep", "Oct", "Nov", "Dec");
def driver = DriverFactory.getWebDriver()
WebElement SelectCalender = WebUiCommonHelper.findWebElement(calender, 20);
SelectCalender.click()
expDate = (exp_Date);
expMonth = Integer.parseInt(exp_Month);
expYear = Integer.parseInt(exp_Year);
WebElement datePicker_Heading1 =(driver).findElement(By.xpath("//div[#class='datepicker-days']/table/thead/tr[1]/th[2]"));
WebDriverWait wait = new WebDriverWait(driver,10);
wait.until(ExpectedConditions.elementToBeClickable(datePicker_Heading1));
datePicker_Heading1.click();
WebElement datePicker_Heading2 =(driver).findElement(By.xpath("//div[#class='datepicker-months']/table/thead/tr[1]/th[2]"));
wait.until(ExpectedConditions.elementToBeClickable(datePicker_Heading2));
datePicker_Heading2.click();
while (dateNotFound) {
WebElement datePicker_Heading3 =(driver).findElement(By.xpath("//div[#class='datepicker-years']/table/thead/tr[1]/th[2]"));
wait.until(ExpectedConditions.visibilityOf(datePicker_Heading3));
datepickerText =datePicker_Heading3.getText();
String[] datepickerYear = datepickerText.split("-");
minYear =datepickerYear[0];
maxYear = datepickerYear[1];
if((expYear >= Integer.parseInt(minYear)) && (expYear<=Integer.parseInt(maxYear)))
{
datePicker = (driver).findElement(By.xpath("//div[#class='datepicker-years']/table"));
noOfYears = datePicker.findElements(By.xpath("//span[contains(#class,'year')]"));
firstloop:
for (WebElement year : noOfYears) {
if (year.getText().equalsIgnoreCase((String)exp_Year)) {
year.click();
Thread.sleep(1500);
datePicker = (driver).findElement(By.xpath("//div[#class='datepicker-months']/table"));
//noOfMonths = datePicker.findElements(By.xpath("//span[#class='month']"));
noOfMonths = datePicker.findElements(By.cssSelector("span.month"));
Thread.sleep(1000);
for (WebElement month : noOfMonths) {
System.out.println(" the expected month in int is : "+expMonth);
System.out.println(" the expected month is : "+monthList.get(expMonth));
System.out.println(" the Actual month is : "+month.getText());
if ((monthList.get(expMonth)).equalsIgnoreCase(month.getText())) {
System.out.println("days ");
month.click();
datePicker = (driver).findElement(By.xpath("//div[#class='datepicker-days']/table"));
noOfDays = datePicker.findElements(By.xpath("//td[#class='day']"));
Thread.sleep(1500);
for (WebElement cell : noOfDays) {
if (cell.getText().equalsIgnoreCase(expDate)) {
System.out.println("days ");
cell.click();
break firstloop;
}
}
}
}
}
}
dateNotFound = false;
}else if (expYear > Integer.parseInt(maxYear)) {
WebElement Next =(driver).findElement(By.xpath("//div[#class='datepicker-years']/table/thead/tr[1]/th[#class='next']"));
if(Next.getAttribute("style").equalsIgnoreCase("visibility: visible;"))
{// Click on next button of date picker.
Next.click();
}else {
throw new Exception("This is exception")
}
}
// If current selected month and year are greater than expected
// month and year then go Inside this condition.
else if (expYear < Integer.parseInt(minYear)) {
WebElement Previous =(driver).findElement(By.xpath("//div[#class='datepicker-years']/table/thead/tr[1]/th[#class='prev']"));
if(Previous.getAttribute("style").equalsIgnoreCase("visibility: visible;"))
{
// Click on previous button of date picker.
Previous.click();
}else{
throw new Exception("This is exception")
}
}
}
}
}
You can use above keyword as below
CustomKeywords.'framework.component.handleDatepicker'(findTestObject('testobject'),'10', '12', '1990')
Note : "Framework" folder had been created by us as inside the Keyword folder and then We had created the "component" keyword
This way you can able to create custom keyword as per your component.
I hope this might help you and other developers.
Maybe this can help, it seems to be a similar situation:
https://forum.katalon.com/discussion/1999/how-to-handle-date-pickers-in-katalon.
There are some generic project templates in Katalon Studio 6.2.0. One of them is "Tips and Tricks with Katalon Studio" that contains a "Datepicker.groovy" file with this generic datepicker code that you can adapt as you wish:
import static com.kms.katalon.core.testobject.ObjectRepository.findTestObject
import com.kms.katalon.core.annotation.Keyword
import com.kms.katalon.core.model.FailureHandling
import com.kms.katalon.core.testobject.TestObject
import com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords as WebUI
import static java.util.Calendar.*
import org.apache.xerces.jaxp.datatype.XMLGregorianCalendarImpl.DaysInMonth
class Datepicker {
Date date;
TestObject obj;
Datepicker() {}
Datepicker(TestObject object, String input_date) {
this.obj = object;
date = new Date().parse("MM/dd/yyyy", input_date)
}
def open_calendar_form() {
WebUI.waitForElementClickable(this.obj, 0)
WebUI.click(this.obj)
}
def displaying_month() {
WebUI.waitForElementVisible(findTestObject('Object Repository/jqueryui/widgets/datepicker/date_month'), 0)
return WebUI.getText(
findTestObject('Object Repository/jqueryui/widgets/datepicker/date_month'),
FailureHandling.STOP_ON_FAILURE)
}
def displaying_year() {
WebUI.waitForElementVisible(findTestObject('Object Repository/jqueryui/widgets/datepicker/date_year'), 0)
return WebUI.getText(
findTestObject('Object Repository/jqueryui/widgets/datepicker/date_year'),
FailureHandling.STOP_ON_FAILURE)
}
def displaying_date() {
return new Date().parse("MMM/yyyy", displaying_month() + "/" + displaying_year())
}
def pick_year() {
if (displaying_date()[YEAR] == date[YEAR]) return
while (displaying_date()[YEAR] < date[YEAR]) {
WebUI.click(findTestObject('Object Repository/jqueryui/widgets/datepicker/Next'))
}
while (displaying_date()[YEAR] > date[YEAR]) {
WebUI.click(findTestObject('Object Repository/jqueryui/widgets/datepicker/Prev'))
}
}
def pick_month() {
if (displaying_date()[MONTH] == date[MONTH]) return
while (displaying_date()[MONTH] < date[MONTH]) {
WebUI.click(findTestObject('Object Repository/jqueryui/widgets/datepicker/Next'))
}
while (displaying_date()[MONTH] > date[MONTH]) {
WebUI.click(findTestObject('Object Repository/jqueryui/widgets/datepicker/Prev'))
}
}
def pick_day() {
println date[DAY_OF_MONTH]
WebUI.click(findTestObject('Object Repository/jqueryui/widgets/datepicker/date_day', [('day') : date[DAY_OF_MONTH]]))
}
def pick_date() {
pick_year()
pick_month()
pick_day()
}
#Keyword
def pickDate(TestObject ob, String date) {
def picker = new Datepicker(ob, date)
picker.open_calendar_form()
picker.pick_date()
}
}
If your datepicker widget is anything like the ones in Zoho (it auto-populates with today's date, and setting the text to different date either has no effect or appends to today's date string), try this out:
public final class GeneralWebUIUtils {
public static final String VALUE = "value";
public static String GetTextValue(TestObject to) {
return WebUI.getAttribute(to, this.VALUE)
}
public static Keys GetCommandKey() {
final String os = System.getProperty("os.name")
if (os.toUpperCase().contains("WINDOWS"))
return Keys.CONTROL;
return Keys.COMMAND;
}
public static void ClearAndEnterText(TestObject to, String text) {
WebUI.sendKeys(to,
Keys.chord("${this.GetCommandKey().toString()}A"),
FailureHandling.STOP_ON_FAILURE);
WebUI.sendKeys(to, text, FailureHandling.STOP_ON_FAILURE);
}
public static void UpdateDateField(TestObject to, Date newDate) {
this.WaitForTextFieldNonEmpty(to, 1, FailureHandling.CONTINUE_ON_FAILURE)
if (newDate == null) {
WebUI.clearText(to, FailureHandling.STOP_ON_FAILURE);
return;
}
final String fieldTextValue = this.GetTextValue(to),
newDateTextValue = SMDDateUtils.ToDateString(newDate);
if ((!newDateTextValue.isEmpty()) && (!fieldTextValue.equals(newDateTextValue))) {
this.ClearAndEnterText(to, newDateTextValue);
KeywordUtil.logInfo("'${newDateTextValue}' written to the date field")
}
WebUI.sendKeys(to, Keys.TAB.toString());
KeywordUtil.logInfo("After trying to write to the field, it has value '${this.GetTextValue(to)}'")
}
public static boolean WaitForElementCondition(Closure<Boolean> onCheckCondition, Closure onContinue, TestObject to, int timeOut, FailureHandling failureHandling = FailureHandling.STOP_ON_FAILURE) {
final long startTime = System.currentTimeMillis()
boolean isConditionSatisfied = false;
while ((System.currentTimeMillis() < startTime + timeOut * 1000) && (!isConditionSatisfied)) {
isConditionSatisfied = WebUI.waitForElementPresent(to, 1, failureHandling) && onCheckCondition(to);
if (onContinue != null)
onContinue(isConditionSatisfied, to);
}
if ((!isConditionSatisfied) && (failureHandling.equals(FailureHandling.STOP_ON_FAILURE))) {
KeywordUtil.markFailedAndStop("Condition for TestObject '${to.getObjectId()}' not met after ${(System.currentTimeMillis() - startTime) / 1000} seconds");
}
return isConditionSatisfied;
}
public static boolean WaitForTextFieldNonEmpty(TestObject to, int timeOut, FailureHandling failureHandling = FailureHandling.STOP_ON_FAILURE) {
return this.WaitForElementCondition({ TestObject testObj ->
return (!this.GetTextValue(testObj).isEmpty());
},
null,
to,
timeOut,
failureHandling);
}
}
public final class SMDDateUtils {
// TODO: replace with the date format that you use in your project
private static DateFormat DateFormat = new SimpleDateFormat("MM-dd-yyyy");
public static String ToDateString(Date date) {
return this.DateFormat.format(date);
}
}
Save that to two keywords: GeneralWebUIUtils and SMDDateUtils (feel free to replace the name prefix on that one :) )
Then you can just be like:
GeneralWebUIUtils.UpdateDateField(findTestObject('Order/dataSigned'), todaysDate)
to update to todaysDate
and even
GeneralWebUIUtils.UpdateDateField(findTestObject('Order/dataSigned'), null)
to clear it! :)
DISCLAIMER: those utils are pulled straight from my testing codebase.
Related
In extending code from OptaPlanner nurse rostering sample code. What causes the "constraintMatchTotal could not add constraintMatch" (Illegal state?) error to be thrown, that would be related to the parsing of a .drl rule with an 'or' clause, please? It is occurring immediately at import of data into .drl-based ruleset... but does NOT error if either of the two 'or' clauses is commented out. I believe that as they individually are acceptable, the system should handle them in the 'or' setup.
The rule is below, followed by the error, and the domain object used in the 'or' clause. I confirmed that:
If I comment out the 'or' and the BoundaryDate clause above it, the
program loads and runs.
If I comment out the 'or' and the BoundaryDate clause below it, the program loads and runs.
If I leave both in place, the error (below the rule) is thrown immediately.
Additionally, if I insert this clause into the 2nd BoundaryDate condition (after the 'or'), then the program loads and runs:
preferredSequenceStart == true,
.drl rule:
rule "Highlight irregular shifts"
when
EmployeeWorkSameShiftTypeSequence(
employee != null,
$firstDayIndex : firstDayIndex,
$lastDayIndex : lastDayIndex,
$employee : employee,
$dayLength : dayLength)
(
BoundaryDate(
dayIndex == $firstDayIndex,
preferredSequenceStart == false // does not start on a boundary start date
)
or // or
BoundaryDate(
dayIndex == $firstDayIndex,
$dayLength != preferredCoveringLength // is incorrect length for exactly one block
)
)
StaffRosterParametrization($lastDayIndex >= planningWindowStartDayIndex) // ignore if assignment is in (fixed) prior data
// non-functional identification drives desired indictment display on ShiftAssignment planning objects
ShiftAssignment(employee == $employee, shiftDateDayIndex >= $firstDayIndex, shiftDateDayIndex <= $lastDayIndex)
then
scoreHolder.addSoftConstraintMatch(kcontext, -1);
end
Exception executing consequence for rule "Highlight irregular shifts" in westgranite.staffrostering.solver: java.lang.IllegalStateException: The constraintMatchTotal (westgranite.staffrostering.solver/Highlight irregular shifts=0hard/-274soft) could not add constraintMatch (westgranite.staffrostering.solver/Highlight irregular shifts/[2020-01-02/D/6, 2018-12-25 - 2020-01-06, 2020-01-02, ...
[continues on with a list of constraint matches]
The BoundaryData.java is below, so the methods being called from the rule are visible:
package westgranite.staffrostering.domain;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import westgranite.common.domain.AbstractPersistable;
#XStreamAlias("BoundaryDate")
public class BoundaryDate extends AbstractPersistable {
/**
*
*/
private static final long serialVersionUID = -7393276689810490427L;
private static final DateTimeFormatter LABEL_FORMATTER = DateTimeFormatter.ofPattern("E d MMM");
private int dayIndex;
private LocalDate date;
private boolean preferredSequenceStart; // true means "this date is a preferred start to assignment sequences"
private boolean preferredSequenceEnd; // true means "this date is a preferred end for assignment sequences"
private int nextPreferredStartDayIndex; // MAX_VALUE means "none"; if preferredSequenceStart is true, then this ref is still to the FUTURE next pref start date
private int prevPreferredStartDayIndex; // MIN_VALUE means "none"; if preferredSequenceStart is true, then this ref is still to the PREVIOUS next pref start date
// magic value that is beyond reasonable dayIndex range and still allows delta of indices to be an Integer
public static final int noNextPreferredDayIndex = Integer.MAX_VALUE/3;
public static final int noPrevPreferredDayIndex = Integer.MIN_VALUE/3;
public int getDayIndex() {
return dayIndex;
}
public void setDayIndex(int dayIndex) {
this.dayIndex = dayIndex;
}
public LocalDate getDate() {
return date;
}
public void setDate(LocalDate date) {
this.date = date;
}
public boolean isPreferredSequenceStart() {
return preferredSequenceStart;
}
public void setPreferredSequenceStart(boolean preferredSequenceStart) {
this.preferredSequenceStart = preferredSequenceStart;
}
public boolean isPreferredSequenceEnd() {
return preferredSequenceEnd;
}
public void setPreferredSequenceEnd(boolean preferredSequenceEnd) {
this.preferredSequenceEnd = preferredSequenceEnd;
}
public int getNextPreferredStartDayIndex() {
return nextPreferredStartDayIndex;
}
public void setNextPreferredStartDayIndex(int nextPreferredStartDayIndex) {
this.nextPreferredStartDayIndex = nextPreferredStartDayIndex;
}
public int getPrevPreferredStartDayIndex() {
return prevPreferredStartDayIndex;
}
public void setPrevPreferredStartDayIndex(int prevPreferredStartDayIndex) {
this.prevPreferredStartDayIndex = prevPreferredStartDayIndex;
}
// ===================== COMPLEX METHODS ===============================
public int getCurrOrPrevPreferredStartDayIndex() {
return (isPreferredSequenceStart() ? dayIndex : prevPreferredStartDayIndex);
}
public int getCurrOrNextPreferredStartDayIndex() {
return (isPreferredSequenceStart() ? dayIndex : nextPreferredStartDayIndex);
}
public int getCurrOrPrevPreferredEndDayIndex() {
return (isPreferredSequenceEnd() ? dayIndex : (isPreferredSequenceStart() ? dayIndex-1 : prevPreferredStartDayIndex-1));
}
public int getCurrOrNextPreferredEndDayIndex() {
return (isPreferredSequenceEnd() ? dayIndex : nextPreferredStartDayIndex-1);
}
public boolean isNoNextPreferred() {
return getNextPreferredStartDayIndex() == noNextPreferredDayIndex;
}
public boolean isNoPrevPreferred() {
return getPrevPreferredStartDayIndex() == noPrevPreferredDayIndex;
}
/**
* #return if this is a preferred start date, then the sequence length that will fill from this date through the next end date; otherwise the days filling the past preferred start date through next end date
*/
public int getPreferredCoveringLength() {
if (isPreferredSequenceStart()) {
return nextPreferredStartDayIndex - dayIndex;
}
return nextPreferredStartDayIndex - prevPreferredStartDayIndex;
}
/**
* #return if this is a preferred start boundary, then "today", else day of most recent start boundary
*/
public DayOfWeek getPreferredStartDayOfWeek() {
if (isPreferredSequenceStart()) {
return getDayOfWeek();
}
if (isNoPrevPreferred()) {
throw new IllegalStateException("No prev preferred day of week available for " + toString());
}
return date.minusDays(dayIndex - getPrevPreferredStartDayIndex()).getDayOfWeek();
}
public DayOfWeek getPreferredEndDayOfWeek() {
if (isPreferredSequenceEnd()) {
return getDayOfWeek();
}
if (isNoNextPreferred()) {
throw new IllegalStateException("No next preferred day of week available for " + toString());
}
return date.plusDays((getNextPreferredStartDayIndex()-1) - dayIndex).getDayOfWeek();
}
public DayOfWeek getDayOfWeek() {
return date.getDayOfWeek();
}
public int getMostRecentDayIndexOf(DayOfWeek targetDayOfWeek) {
return dayIndex - getBackwardDaysToReach(targetDayOfWeek);
}
public int getUpcomingDayIndexOf(DayOfWeek targetDayOfWeek) {
return dayIndex + getForwardDaysToReach(targetDayOfWeek);
}
public LocalDate getMostRecentDateOf(DayOfWeek targetDayOfWeek) {
return date.minusDays(getBackwardDaysToReach(targetDayOfWeek));
}
public LocalDate getUpcomingDateOf(DayOfWeek targetDayOfWeek) {
return date.plusDays(getForwardDaysToReach(targetDayOfWeek));
}
public int getForwardDaysToReach(DayOfWeek targetDayOfWeek) {
return getForwardDaysToReach(this.getDayOfWeek(), targetDayOfWeek);
}
public static int getForwardDaysToReach(DayOfWeek startDayOfWeek, DayOfWeek targetDayOfWeek) {
if (startDayOfWeek == targetDayOfWeek) {
return 0;
}
int forwardDayCount = 1;
while (startDayOfWeek.plus(forwardDayCount) != targetDayOfWeek) {
forwardDayCount++;
if (forwardDayCount > 10) {
throw new IllegalStateException("counting forward in days from " + startDayOfWeek + " never found target day of week: " + targetDayOfWeek);
}
}
return forwardDayCount;
}
public int getBackwardDaysToReach(DayOfWeek targetDayOfWeek) {
return getBackwardDaysToReach(this.getDayOfWeek(), targetDayOfWeek);
}
public static int getBackwardDaysToReach(DayOfWeek startDayOfWeek, DayOfWeek targetDayOfWeek) {
if (startDayOfWeek == targetDayOfWeek) {
return 0;
}
int backwardDayCount = 1;
while (startDayOfWeek.minus(backwardDayCount) != targetDayOfWeek) {
backwardDayCount++;
if (backwardDayCount > 10) {
throw new IllegalStateException("counting backward in days from " + startDayOfWeek + " never found target day of week: " + targetDayOfWeek);
}
}
return backwardDayCount;
}
public String getLabel() {
return date.format(LABEL_FORMATTER);
}
#Override
public String toString() {
return date.format(DateTimeFormatter.ISO_DATE);
}
}
If the same object being tested in the rule can match in multiple parts of an 'or' condition, then Optaplanner throws this IllegalStateException, at least through 7.15.0. See details explored in optaplanner jira 1433.
Workaround is to always add terms to later terms of 'or' expressions that ensure the matching object can not be the same one that matched earlier parts of the 'or'. For the original posting above, the 'preferredSequenceStart == true' achieved this exclusion.
Note that the use of the 'exists' keyword in the terms of the 'or' can cause trouble with this workaround; try to avoid using 'exists' in this situation.
The AutoCompleteTextField seems to work exactly as intended until I start backspacing in the TextField. I am not sure what the difference is, but if I type in something like "123 M" then I get values that start with "123 M". If I backspace and delete the M leaving "123 " in the field, the list changes, but it does not scroll to the top of the list.
I should note that everything works fine on the simulator and that I am experiencing this behavior when running a debug build on my iPhone.
EDIT: So this does not only seem to happen when backspacing. This image shows the results I have when typing in an address key by key. In any of the pictures where the list isn't viewable or is clipped, I am able to drag down on the list to get it to then display properly. I have not tried this on an Android device.
EDIT2:
public class CodenameOneTest {
private Form current;
private Resources theme;
private WaitingClass w;
private String[] properties = {"1 MAIN STREET", "123 E MAIN STREET", "12 EASTER ROAD", "24 MAIN STREET"};
public void init(Object context) {
theme = UIManager.initFirstTheme("/theme");
// Enable Toolbar on all Forms by default
Toolbar.setGlobalToolbar(true);
}
public void start() {
if(current != null) {
current.show();
return;
}
Form form = new Form("AutoCompleteTextField");
form.setLayout(new BorderLayout());
final DefaultListModel<String> options = new DefaultListModel<>();
AutoCompleteTextField ac = new AutoCompleteTextField(options) {
protected boolean filter(String text) {
if(text.length() == 0) {
options.removeAll();
return false;
}
String[] l = searchLocations(text);
if(l == null || l.length == 0) {
return false;
}
options.removeAll();
for(String s : l) {
options.addItem(s);
}
return true;
};
};
Container container = new Container(BoxLayout.y());
container.setScrollableY(true); // If you comment this out then the field works fine
container.add(ac);
form.addComponent(BorderLayout.CENTER, container);
form.show();
}
String[] searchLocations(String text) {
try {
if(text.length() > 0) {
if(w != null) {
w.actionPerformed(null);
}
w = new WaitingClass();
String[] properties = getProperties(text);
if(Display.getInstance().isEdt()) {
Display.getInstance().invokeAndBlock(w);
}
else {
w.run();
}
return properties;
}
}
catch(Exception e) {
Log.e(e);
}
return null;
}
private String[] getProperties(String text) {
List<String> returnList = new ArrayList<>();
List<String> propertyList = Arrays.asList(properties);
for(String property : propertyList) {
if(property.startsWith(text)) {
returnList.add(property);
}
}
w.actionPerformed(null);
return returnList.toArray(new String[returnList.size()]);
}
class WaitingClass implements Runnable, ActionListener<ActionEvent> {
private boolean finishedWaiting;
public void run() {
while(!finishedWaiting) {
try {
Thread.sleep(30);
}
catch(InterruptedException ex) {
ex.printStackTrace();
}
}
}
public void actionPerformed(ActionEvent e) {
finishedWaiting = true;
return;
}
}
public void stop() {
current = Display.getInstance().getCurrent();
if(current instanceof Dialog) {
((Dialog)current).dispose();
current = Display.getInstance().getCurrent();
}
}
public void destroy() {
}
}
I used this code on an iPhone 4s:
public void start() {
if(current != null){
current.show();
return;
}
Form hi = new Form("AutoComplete", new BorderLayout());
if(apiKey == null) {
hi.add(new SpanLabel("This demo requires a valid google API key to be set in the constant apiKey, "
+ "you can get this key for the webservice (not the native key) by following the instructions here: "
+ "https://developers.google.com/places/web-service/get-api-key"));
hi.getToolbar().addCommandToRightBar("Get Key", null, e -> Display.getInstance().execute("https://developers.google.com/places/web-service/get-api-key"));
hi.show();
return;
}
Container box = new Container(new BoxLayout(BoxLayout.Y_AXIS));
box.setScrollableY(true);
for(int iter = 0 ; iter < 30 ; iter++) {
box.add(createAutoComplete());
}
hi.add(BorderLayout.CENTER, box);
hi.show();
}
private AutoCompleteTextField createAutoComplete() {
final DefaultListModel<String> options = new DefaultListModel<>();
AutoCompleteTextField ac = new AutoCompleteTextField(options) {
#Override
protected boolean filter(String text) {
if(text.length() == 0) {
return false;
}
String[] l = searchLocations(text);
if(l == null || l.length == 0) {
return false;
}
options.removeAll();
for(String s : l) {
options.addItem(s);
}
return true;
}
};
ac.setMinimumElementsShownInPopup(5);
return ac;
}
String[] searchLocations(String text) {
try {
if(text.length() > 0) {
ConnectionRequest r = new ConnectionRequest();
r.setPost(false);
r.setUrl("https://maps.googleapis.com/maps/api/place/autocomplete/json");
r.addArgument("key", apiKey);
r.addArgument("input", text);
NetworkManager.getInstance().addToQueueAndWait(r);
Map<String,Object> result = new JSONParser().parseJSON(new InputStreamReader(new ByteArrayInputStream(r.getResponseData()), "UTF-8"));
String[] res = Result.fromContent(result).getAsStringArray("//description");
return res;
}
} catch(Exception err) {
Log.e(err);
}
return null;
}
I was able to create this issue but not the issue you describe.
What i am trying to do is display the response from a POST message on to the HTML loaded in my webview. However, the my webview appears blank. I can see the response message by in LogCat by printing it out. However, again my webview appears blank. Example.html is the page loading in my webview. My implementation is below:
private void startSchedule()
{
for(int i=0;i<temPojoData.size();i++)
{
tempPojo tem =temPojoData.get(i);
/////////////////////// Daily and AllDays functionality start here //////////////////
if(tem.getDaysweekmonth().equals("Daily") )
{
if(tem.getDaysbases().equals("AllDays")) {
if (findDateBTwoDates(tem.getStartDate(), tem.getEndDate())) {
Log.i("Daily Date", "Today Available");
layoutID += tem.getLayout();
}
}else if(tem.getDaysbases().equals("Whole Day")){
}else if(tem.getDaysbases().equals("Morning"))
{ scheduleStartTimes.add(tem.getStartTime());
}else if(tem.getDaysbases().equals("After Noon"))
{ scheduleStartTimes.add(tem.getStartTime());
}else if(tem.getDaysbases().equals("Evening"))
{ scheduleStartTimes.add(tem.getStartTime());
}else if(tem.getDaysbases().equals("Night"))
{ scheduleStartTimes.add(tem.getStartTime());
}else if(tem.getDaysbases().equals("Choose Time"))
{ scheduleStartTimes.add(tem.getStartTime());
}
}
/////////////////////// Weekly and AllDays functionality start here //////////////////
else if(tem.getDaysweekmonth().equals("weekly") && tem.getDaysbases().equals("AllDays"))
{
if(tem.getDaysbases().equals("AllDays")) {
}
}
/////////////////////// Monthly and AllDays functionality start here //////////////////
else if(tem.getDaysweekmonth().equals("montly") && tem.getDaysbases().equals("AllDays"))
{
if(tem.getDaysbases().equals("AllDays")) {
}
}
}
}
private void findTimeBTwoTimes(String sTime,String eTime)
{
try {
String string1 = "20:11:13";
Date time1 = new SimpleDateFormat("HH:mm:ss").parse(string1);
Calendar calendar1 = Calendar.getInstance();
calendar1.setTime(time1);
String string2 = "14:49:00";
Date time2 = new SimpleDateFormat("HH:mm:ss").parse(string2);
Calendar calendar2 = Calendar.getInstance();
calendar2.setTime(time2);
calendar2.add(Calendar.DATE, 1);
String someRandomTime = "01:00:00";
Date d = new SimpleDateFormat("HH:mm:ss").parse(someRandomTime);
Calendar calendar3 = Calendar.getInstance();
calendar3.setTime(d);
calendar3.add(Calendar.DATE, 1);
Date x = calendar3.getTime();
if (x.after(calendar1.getTime()) && x.before(calendar2.getTime())) {
//checkes whether the current time is between 14:49:00 and 20:11:13.
System.out.println(true);
}
} catch (ParseException e) {
e.printStackTrace();
}
}
private boolean findDateBTwoDates(String sDate,String eDate)
{
try {
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
String s = sDate.replace(" AM","");
String e = eDate.replace(" AM","");
String oeStartDateStr =sDate.replace("PM","");
String oeEndDateStr =eDate.replace("PM","");
Log.i("Start End Date ",sDate+"------------"+eDate);
Calendar cal = Calendar.getInstance();
Integer year = cal.get(Calendar.YEAR);
Date startDate = sdf.parse(oeStartDateStr);
Date endDate = sdf.parse(oeEndDateStr);
Date d = new Date();
String currDt = sdf.format(d);
if ((d.after(startDate) && (d.before(endDate))) || (currDt.equals(sdf.format(startDate)) || currDt.equals(sdf.format(endDate)))) {
System.out.println("Date is between 1st april to 14th nov...");
return true;
}
/*else {
System.out.println("Date is not between 1st april to 14th nov...");
}*/
}catch (Exception e){}
return false;
}
I will explain this in a sudo code so that you can come up with a solution.
The first point to your answer is that -> No, you cannot do it in a straightforward manner. The reason behind this is that MongoDB does not have/support joins. Like in SQL where you can join two tables and query them for conditional results; the same is not doable in MongoDB.
But do not lose hope. You cannot do a join on the DB side but you can certainly come up with a solution on the driver/application side. What I would suggest you to do is as follows. (I am using the JAVA driver and Morphia so my solutions' arrangement may look specific to them)
Have a DAO interface for both collections seperately
public interface MyDAO1 extends DAO<MyClass1, ObjectId>
{
public MyClass1 getByName(String name);
}
public interface MyDAO2 extends DAO<MyClass2, ObjectId>
{
public MyClass2 getByResult(int result);
}
First make implementation classes for both the above interfaces. That's pretty simple so I am skipping it to move on to the real part. Have an implementation of the interface
public class MyDAOImpl extends BasicDAO<MyClass, ObjectId> implements MyDAO1, MyDAO2
{
public MyClass1 getByName (String name)
{
MyClass1 output= query collection1 with with the Name;
return output;
}
public MyClass2 getByResult (int result)
{
MyClass2 output= query collection2 with with the result;
return output;
}
public void getByNameResult (String name, int result)
{
MyClass1 output1 = getByName (name);
MyClass2 output2 = getByResult (result);
print them in however format you want OR create a string;
}
}
please note:
MyClass1 is the #Entity class for the employee collection
MyClass2 is the #Entity class for the result collection
On the application I am currently working, it is necessary to select a single date or a period from the same JavaFX 8 DatePicker.
The preferred way of doing this would be as follows:
Selecting a single date - same as default behaviour of the DatePicker.
Selecting a period - select start/end date by holding down the mouse button and drag to the desired end/start date. When the mouse button is released you have defined your period. The fact that you cannot select dates other than those displayed is acceptable.
Editing should work for both single date (ex 24.12.2014) and period ( ex: 24.12.2014 - 27.12.2014)
A possible rendering of the selected period (minus the content of the text editor) above would look like this:
Where orange indicates current date, blue indicates selected period. The picture is from a prototype I made, but where the period is selected by using 2 DatePickers rather than one.
I had a look at the sourcecode for
com.sun.javafx.scene.control.skin.DatePickerContent
which has a
protected List<DateCell> dayCells = new ArrayList<DateCell>();
in order to find a way of detecting when the mouse selected a date end when the mouse was released (or maybe detecting a drag).
However I am not quite sure how to go about it. Any suggestions?
I am attaching the simple prototype code I have made so far (that makes use of 2 rather than the desired 1 datepicker).
import java.time.LocalDate;
import javafx.beans.property.SimpleObjectProperty;
public interface PeriodController {
/**
* #return Today.
*/
LocalDate currentDate();
/**
* #return Selected from date.
*/
SimpleObjectProperty<LocalDate> fromDateProperty();
/**
* #return Selected to date.
*/
SimpleObjectProperty<LocalDate> toDateProperty();
}
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import javafx.util.StringConverter;
public class DateConverter extends StringConverter<LocalDate> {
private DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy"); // TODO i18n
#Override
public String toString(LocalDate date) {
if (date != null) {
return dateFormatter.format(date);
} else {
return "";
}
}
#Override
public LocalDate fromString(String string) {
if (string != null && !string.isEmpty()) {
return LocalDate.parse(string, dateFormatter);
} else {
return null;
}
}
}
import static java.lang.System.out;
import java.time.LocalDate;
import java.util.Locale;
import javafx.application.Application;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.geometry.HPos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class PeriodMain extends Application {
private Stage stage;
public static void main(String[] args) {
Locale.setDefault(new Locale("no", "NO"));
launch(args);
}
#Override
public void start(Stage stage) {
this.stage = stage;
stage.setTitle("Period prototype ");
initUI();
stage.getScene().getStylesheets().add(getClass().getResource("/period-picker.css").toExternalForm());
stage.show();
}
private void initUI() {
VBox vbox = new VBox(20);
vbox.setStyle("-fx-padding: 10;");
Scene scene = new Scene(vbox, 400, 200);
stage.setScene(scene);
final PeriodPickerPrototype periodPickerPrototype = new PeriodPickerPrototype(new PeriodController() {
SimpleObjectProperty<LocalDate> fromDate = new SimpleObjectProperty<>();
SimpleObjectProperty<LocalDate> toDate = new SimpleObjectProperty<>();
{
final ChangeListener<LocalDate> dateListener = (observable, oldValue, newValue) -> {
if (fromDate.getValue() != null && toDate.getValue() != null) {
out.println("Selected period " + fromDate.getValue() + " - " + toDate.getValue());
}
};
fromDate.addListener(dateListener);
toDate.addListener(dateListener);
}
#Override public LocalDate currentDate() {
return LocalDate.now();
}
#Override public SimpleObjectProperty<LocalDate> fromDateProperty() {
return fromDate;
}
#Override public SimpleObjectProperty<LocalDate> toDateProperty() {
return toDate;
}
});
GridPane gridPane = new GridPane();
gridPane.setHgap(10);
gridPane.setVgap(10);
Label checkInlabel = new Label("Check-In Date:");
GridPane.setHalignment(checkInlabel, HPos.LEFT);
gridPane.add(periodPickerPrototype, 0, 1);
vbox.getChildren().add(gridPane);
}
}
import java.time.LocalDate;
import javafx.beans.value.ChangeListener;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.DateCell;
import javafx.scene.control.DatePicker;
import javafx.scene.control.Label;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.GridPane;
import javafx.util.Callback;
import javafx.util.StringConverter;
/**
* Selecting a single date or a period - only a prototype.
* As long as you have made an active choice on the {#code toDate}, the {#code fromDate} and {#code toDate} will have the same date.
*/
public class PeriodPickerPrototype extends GridPane {
private static final String CSS_CALENDAR_BEFORE = "calendar-before";
private static final String CSS_CALENDAR_BETWEEN = "calendar-between";
private static final String CSS_CALENDAR_TODAY = "calendar-today";
private static final boolean DISPLAY_WEEK_NUMBER = true;
private Label fromLabel;
private Label toLabel;
private DatePicker fromDate;
private DatePicker toDate;
private StringConverter<LocalDate> converter;
private PeriodController controller;
private ChangeListener<LocalDate> fromDateListener;
private ChangeListener<LocalDate> toDateListener;
private Callback<DatePicker, DateCell> toDateCellFactory;
private Callback<DatePicker, DateCell> fromDateCellFactory;
private Tooltip todayTooltip;
private boolean toDateIsActivlyChosenbyUser;
public PeriodPickerPrototype(final PeriodController periodController)
{
this.controller = periodController;
createComponents();
makeLayout();
createHandlers();
bindAndRegisterHandlers();
i18n();
initComponent();
}
public void createComponents() {
fromLabel = new Label();
toLabel = new Label();
fromDate = new DatePicker();
toDate = new DatePicker();
todayTooltip = new Tooltip();
}
public void createHandlers() {
fromDate.setOnAction(event -> {
if ((!toDateIsActivlyChosenbyUser) || fromDate.getValue().isAfter(toDate.getValue())) {
setDateWithoutFiringEvent(fromDate.getValue(), toDate);
toDateIsActivlyChosenbyUser = false;
}
});
toDate.setOnAction(event -> toDateIsActivlyChosenbyUser = true);
fromDateCellFactory = new Callback<DatePicker, DateCell>() {
#Override public DateCell call(final DatePicker datePicker) {
return new DateCell() {
#Override
public void updateItem(LocalDate item, boolean empty) {
super.updateItem(item, empty);
getStyleClass().removeAll(CSS_CALENDAR_TODAY, CSS_CALENDAR_BEFORE, CSS_CALENDAR_BETWEEN);
if ((item.isBefore(toDate.getValue()) || item.isEqual(toDate.getValue())) && item.isAfter(fromDate.getValue())) {
getStyleClass().add(CSS_CALENDAR_BETWEEN);
}
if (item.isEqual(controller.currentDate())) {
getStyleClass().add(CSS_CALENDAR_TODAY);
setTooltip(todayTooltip);
} else {
setTooltip(null);
}
}
};
}
};
toDateCellFactory =
new Callback<DatePicker, DateCell>() {
#Override
public DateCell call(final DatePicker datePicker) {
return new DateCell() {
#Override
public void updateItem(LocalDate item, boolean empty) {
super.updateItem(item, empty);
setDisable(item.isBefore(fromDate.getValue()));
getStyleClass().removeAll(CSS_CALENDAR_TODAY, CSS_CALENDAR_BEFORE, CSS_CALENDAR_BETWEEN);
if (item.isBefore(fromDate.getValue())) {
getStyleClass().add(CSS_CALENDAR_BEFORE);
} else if (item.isBefore(toDate.getValue()) || item.isEqual(toDate.getValue())) {
getStyleClass().add(CSS_CALENDAR_BETWEEN);
}
if (item.isEqual(controller.currentDate())) {
getStyleClass().add(CSS_CALENDAR_TODAY);
setTooltip(todayTooltip);
} else {
setTooltip(null);
}
}
};
}
};
converter = new DateConverter();
fromDateListener = (observableValue, oldValue, newValue) -> {
if (newValue == null) {
// Restting old value and cancel..
setDateWithoutFiringEvent(oldValue, fromDate);
return;
}
controller.fromDateProperty().set(newValue);
};
toDateListener = (observableValue, oldValue, newValue) -> {
if (newValue == null) {
// Restting old value and cancel..
setDateWithoutFiringEvent(oldValue, toDate);
return;
}
controller.toDateProperty().set(newValue);
};
}
/**
* Changes the date on {#code datePicker} without fire {#code onAction} event.
*/
private void setDateWithoutFiringEvent(LocalDate newDate, DatePicker datePicker) {
final EventHandler<ActionEvent> onAction = datePicker.getOnAction();
datePicker.setOnAction(null);
datePicker.setValue(newDate);
datePicker.setOnAction(onAction);
}
public void bindAndRegisterHandlers() {
toDate.setDayCellFactory(toDateCellFactory);
fromDate.setDayCellFactory(fromDateCellFactory);
fromDate.valueProperty().addListener(fromDateListener);
fromDate.setConverter(converter);
toDate.valueProperty().addListener(toDateListener);
toDate.setConverter(converter);
}
public void makeLayout() {
setHgap(6);
add(fromLabel, 0, 0);
add(fromDate, 1, 0);
add(toLabel, 2, 0);
add(toDate, 3, 0);
fromDate.setPrefWidth(120);
toDate.setPrefWidth(120);
fromLabel.setId("calendar-label");
toLabel.setId("calendar-label");
}
public void i18n() {
// i18n code replaced with
fromDate.setPromptText("dd.mm.yyyy");
toDate.setPromptText("dd.mm.yyyy");
fromLabel.setText("From");
toLabel.setText("To");
todayTooltip.setText("Today");
}
public void initComponent() {
fromDate.setTooltip(null); // Ønsker ikke tooltip
setDateWithoutFiringEvent(controller.currentDate(), fromDate);
fromDate.setShowWeekNumbers(DISPLAY_WEEK_NUMBER);
toDate.setTooltip(null); // Ønsker ikke tooltip
setDateWithoutFiringEvent(controller.currentDate(), toDate);
toDate.setShowWeekNumbers(DISPLAY_WEEK_NUMBER);
}
}
/** period-picker.css goes udner resources (using maven) **/
.date-picker {
/* -fx-font-size: 11pt;*/
}
.calendar-before {
}
.calendar-between {
-fx-background-color: #bce9ff;
}
.calendar-between:hover {
-fx-background-color: rgb(0, 150, 201);
}
.calendar-between:focused {
-fx-background-color: rgb(0, 150, 201);
}
.calendar-today {
-fx-background-color: rgb(255, 218, 111);
}
.calendar-today:hover {
-fx-background-color: rgb(0, 150, 201);
}
.calendar-today:focused {
-fx-background-color: rgb(0, 150, 201);
}
#calendar-label {
-fx-font-style: italic;
-fx-fill: rgb(75, 75, 75);
-fx-font-size: 11;
}
I think you are already in the right track... DateCell and drag could work, since the popup is not closed if a dragging event is detected or when it ends. That gives you the opportunity to track the cells selected by the user.
This is a quick hack, but it may help you with the range selection.
First it will get the content and a list of all the cells within the displayed month, adding a listener to drag events, marking as the first cell that where the drag starts, and selecting all the cells within this first cell and the cell under the actual mouse position, deselecting the rest.
After the drag event finished, the selected range is shown on the console. And you can start all over again, until the popup is closed.
private DateCell iniCell=null;
private DateCell endCell=null;
#Override
public void start(Stage primaryStage) {
DatePicker datePicker=new DatePicker();
datePicker.setValue(LocalDate.now());
Scene scene = new Scene(new AnchorPane(datePicker), 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
datePicker.showingProperty().addListener((obs,b,b1)->{
if(b1){
DatePickerContent content = (DatePickerContent)((DatePickerSkin)datePicker.getSkin()).getPopupContent();
List<DateCell> cells = content.lookupAll(".day-cell").stream()
.filter(ce->!ce.getStyleClass().contains("next-month"))
.map(n->(DateCell)n)
.collect(Collectors.toList());
content.setOnMouseDragged(e->{
Node n=e.getPickResult().getIntersectedNode();
DateCell c=null;
if(n instanceof DateCell){
c=(DateCell)n;
} else if(n instanceof Text){
c=(DateCell)(n.getParent());
}
if(c!=null && c.getStyleClass().contains("day-cell") &&
!c.getStyleClass().contains("next-month")){
if(iniCell==null){
iniCell=c;
}
endCell=c;
}
if(iniCell!=null && endCell!=null){
int ini=(int)Math.min(Integer.parseInt(iniCell.getText()),
Integer.parseInt(endCell.getText()));
int end=(int)Math.max(Integer.parseInt(iniCell.getText()),
Integer.parseInt(endCell.getText()));
cells.stream()
.forEach(ce->ce.getStyleClass().remove("selected"));
cells.stream()
.filter(ce->Integer.parseInt(ce.getText())>=ini)
.filter(ce->Integer.parseInt(ce.getText())<=end)
.forEach(ce->ce.getStyleClass().add("selected"));
}
});
content.setOnMouseReleased(e->{
if(iniCell!=null && endCell!=null){
System.out.println("Selection from "+iniCell.getText()+" to "+endCell.getText());
}
endCell=null;
iniCell=null;
});
}
});
}
And this is how it looks like:
For now this doesn't update the textfield, as this involves using a custom formatter.
EDIT
I've added a custom string converter to show the range on the textfield, after a selection is done, and also to select a range if a valid one is entered.
This is not bullet proof, but it works as a proof of concept.
private DateCell iniCell=null;
private DateCell endCell=null;
private LocalDate iniDate;
private LocalDate endDate;
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d.MM.uuuu", Locale.ENGLISH);
#Override
public void start(Stage primaryStage) {
DatePicker datePicker=new DatePicker();
datePicker.setValue(LocalDate.now());
datePicker.setConverter(new StringConverter<LocalDate>() {
#Override
public String toString(LocalDate object) {
if(iniDate!=null && endDate!=null){
return iniDate.format(formatter)+" - "+endDate.format(formatter);
}
return object.format(formatter);
}
#Override
public LocalDate fromString(String string) {
if(string.contains("-")){
try{
iniDate=LocalDate.parse(string.split("-")[0].trim(), formatter);
endDate=LocalDate.parse(string.split("-")[1].trim(), formatter);
} catch(DateTimeParseException dte){
return LocalDate.parse(string, formatter);
}
return iniDate;
}
return LocalDate.parse(string, formatter);
}
});
Scene scene = new Scene(new AnchorPane(datePicker), 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
datePicker.showingProperty().addListener((obs,b,b1)->{
if(b1){
DatePickerContent content = (DatePickerContent)((DatePickerSkin)datePicker.getSkin()).getPopupContent();
List<DateCell> cells = content.lookupAll(".day-cell").stream()
.filter(ce->!ce.getStyleClass().contains("next-month"))
.map(n->(DateCell)n)
.collect(Collectors.toList());
// select initial range
if(iniDate!=null && endDate!=null){
int ini=iniDate.getDayOfMonth();
int end=endDate.getDayOfMonth();
cells.stream()
.forEach(ce->ce.getStyleClass().remove("selected"));
cells.stream()
.filter(ce->Integer.parseInt(ce.getText())>=ini)
.filter(ce->Integer.parseInt(ce.getText())<=end)
.forEach(ce->ce.getStyleClass().add("selected"));
}
iniCell=null;
endCell=null;
content.setOnMouseDragged(e->{
Node n=e.getPickResult().getIntersectedNode();
DateCell c=null;
if(n instanceof DateCell){
c=(DateCell)n;
} else if(n instanceof Text){
c=(DateCell)(n.getParent());
}
if(c!=null && c.getStyleClass().contains("day-cell") &&
!c.getStyleClass().contains("next-month")){
if(iniCell==null){
iniCell=c;
}
endCell=c;
}
if(iniCell!=null && endCell!=null){
int ini=(int)Math.min(Integer.parseInt(iniCell.getText()),
Integer.parseInt(endCell.getText()));
int end=(int)Math.max(Integer.parseInt(iniCell.getText()),
Integer.parseInt(endCell.getText()));
cells.stream()
.forEach(ce->ce.getStyleClass().remove("selected"));
cells.stream()
.filter(ce->Integer.parseInt(ce.getText())>=ini)
.filter(ce->Integer.parseInt(ce.getText())<=end)
.forEach(ce->ce.getStyleClass().add("selected"));
}
});
content.setOnMouseReleased(e->{
if(iniCell!=null && endCell!=null){
iniDate=LocalDate.of(datePicker.getValue().getYear(),
datePicker.getValue().getMonth(),
Integer.parseInt(iniCell.getText()));
endDate=LocalDate.of(datePicker.getValue().getYear(),
datePicker.getValue().getMonth(),
Integer.parseInt(endCell.getText()));
System.out.println("Selection from "+iniDate+" to "+endDate);
datePicker.setValue(iniDate);
int ini=iniDate.getDayOfMonth();
int end=endDate.getDayOfMonth();
cells.stream()
.forEach(ce->ce.getStyleClass().remove("selected"));
cells.stream()
.filter(ce->Integer.parseInt(ce.getText())>=ini)
.filter(ce->Integer.parseInt(ce.getText())<=end)
.forEach(ce->ce.getStyleClass().add("selected"));
}
endCell=null;
iniCell=null;
});
}
});
}
By using this answer here: https://stackoverflow.com/a/60618476/9278333
I was able to create this date range selector without the use of a private api:
Usage:
MultiDatePicker multiDatePicker = new MultiDatePicker().withRangeSelectionMode();
DatePicker rangePicker = multiDatePicker.getDatePicker();
import javafx.collections.FXCollections;
import javafx.scene.control.*;
import javafx.util.StringConverter;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import static java.time.temporal.ChronoUnit.DAYS;
import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
import javafx.collections.ObservableSet;
import javafx.event.EventHandler;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
public class MultiDatePicker
{
private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
private final ObservableSet<LocalDate> selectedDates;
private final DatePicker datePicker;
public MultiDatePicker()
{
this.selectedDates = FXCollections.observableSet(new TreeSet<>());
this.datePicker = new DatePicker();
setUpDatePicker();
}
public MultiDatePicker withRangeSelectionMode()
{
EventHandler<MouseEvent> mouseClickedEventHandler = (MouseEvent clickEvent) ->
{
if (clickEvent.getButton() == MouseButton.PRIMARY)
{
if (!this.selectedDates.contains(this.datePicker.getValue()))
{
this.selectedDates.add(datePicker.getValue());
this.selectedDates.addAll(getRangeGaps((LocalDate) this.selectedDates.toArray()[0], (LocalDate) this.selectedDates.toArray()[this.selectedDates.size() - 1]));
} else
{
this.selectedDates.remove(this.datePicker.getValue());
this.selectedDates.removeAll(getTailEndDatesToRemove(this.selectedDates, this.datePicker.getValue()));
this.datePicker.setValue(getClosestDateInTree(new TreeSet<>(this.selectedDates), this.datePicker.getValue()));
}
}
this.datePicker.show();
clickEvent.consume();
};
this.datePicker.setDayCellFactory((DatePicker param) -> new DateCell()
{
#Override
public void updateItem(LocalDate item, boolean empty)
{
super.updateItem(item, empty);
//...
if (item != null && !empty)
{
//...
addEventHandler(MouseEvent.MOUSE_CLICKED, mouseClickedEventHandler);
} else
{
//...
removeEventHandler(MouseEvent.MOUSE_CLICKED, mouseClickedEventHandler);
}
if (!selectedDates.isEmpty() && selectedDates.contains(item))
{
if (Objects.equals(item, selectedDates.toArray()[0]) || Objects.equals(item, selectedDates.toArray()[selectedDates.size() - 1]))
{
setStyle("-fx-background-color: rgba(3, 169, 1, 0.7);");
} else
{
setStyle("-fx-background-color: rgba(3, 169, 244, 0.7);");
}
} else
{
setStyle(null);
}
}
});
return this;
}
public ObservableSet<LocalDate> getSelectedDates()
{
return this.selectedDates;
}
public DatePicker getDatePicker()
{
return this.datePicker;
}
private void setUpDatePicker()
{
this.datePicker.setConverter(new StringConverter<LocalDate>()
{
#Override
public String toString(LocalDate date)
{
return (date == null) ? "" : DATE_FORMAT.format(date);
}
#Override
public LocalDate fromString(String string)
{
return ((string == null) || string.isEmpty()) ? null : LocalDate.parse(string, DATE_FORMAT);
}
});
EventHandler<MouseEvent> mouseClickedEventHandler = (MouseEvent clickEvent) ->
{
if (clickEvent.getButton() == MouseButton.PRIMARY)
{
if (!this.selectedDates.contains(this.datePicker.getValue()))
{
this.selectedDates.add(datePicker.getValue());
} else
{
this.selectedDates.remove(this.datePicker.getValue());
this.datePicker.setValue(getClosestDateInTree(new TreeSet<>(this.selectedDates), this.datePicker.getValue()));
}
}
this.datePicker.show();
clickEvent.consume();
};
this.datePicker.setDayCellFactory((DatePicker param) -> new DateCell()
{
#Override
public void updateItem(LocalDate item, boolean empty)
{
super.updateItem(item, empty);
//...
if (item != null && !empty)
{
//...
addEventHandler(MouseEvent.MOUSE_CLICKED, mouseClickedEventHandler);
} else
{
//...
removeEventHandler(MouseEvent.MOUSE_CLICKED, mouseClickedEventHandler);
}
if (selectedDates.contains(item))
{
setStyle("-fx-background-color: rgba(3, 169, 244, 0.7);");
} else
{
setStyle(null);
}
}
});
}
private static Set<LocalDate> getTailEndDatesToRemove(Set<LocalDate> dates, LocalDate date)
{
TreeSet<LocalDate> tempTree = new TreeSet<>(dates);
tempTree.add(date);
int higher = tempTree.tailSet(date).size();
int lower = tempTree.headSet(date).size();
if (lower <= higher)
{
return tempTree.headSet(date);
} else if (lower > higher)
{
return tempTree.tailSet(date);
} else
{
return new TreeSet<>();
}
}
private static LocalDate getClosestDateInTree(TreeSet<LocalDate> dates, LocalDate date)
{
Long lower = null;
Long higher = null;
if (dates.isEmpty())
{
return null;
}
if (dates.size() == 1)
{
return dates.first();
}
if (dates.lower(date) != null)
{
lower = Math.abs(DAYS.between(date, dates.lower(date)));
}
if (dates.higher(date) != null)
{
higher = Math.abs(DAYS.between(date, dates.higher(date)));
}
if (lower == null)
{
return dates.higher(date);
} else if (higher == null)
{
return dates.lower(date);
} else if (lower <= higher)
{
return dates.lower(date);
} else if (lower > higher)
{
return dates.higher(date);
} else
{
return null;
}
}
private static Set<LocalDate> getRangeGaps(LocalDate min, LocalDate max)
{
Set<LocalDate> rangeGaps = new LinkedHashSet<>();
if (min == null || max == null)
{
return rangeGaps;
}
LocalDate lastDate = min.plusDays(1);
while (lastDate.isAfter(min) && lastDate.isBefore(max))
{
rangeGaps.add(lastDate);
lastDate = lastDate.plusDays(1);
}
return rangeGaps;
}
}
I have a LWUIT app that should display the number of records in a LWUIT list.
To get all the records I use a method called getRecordData() that returns all records as a String array, it works fine.
But how do I count the number of these records?
import java.util.*;
import com.sun.lwuit.events.*;
import javax.microedition.midlet.*;
import com.sun.lwuit.*;
import com.sun.lwuit.plaf.*;
import javax.microedition.rms.RecordStore;
import javax.microedition.rms .*;
public class number_of_records extends MIDlet {
private RecordStore recordStore;
// Refresh2( ) method for getting the time now
public String Refresh2()
{
java.util.Calendar calendar = java.util.Calendar.getInstance();
Date myDate = new Date();
calendar.setTime(myDate);
StringBuffer time = new StringBuffer();
time.append(calendar.get(java.util.Calendar.HOUR_OF_DAY)).append(':');
time.append(calendar.get(java.util.Calendar.MINUTE)) ;
// time.append(calendar.get(java.util.Calendar.SECOND));
String tt = time.toString();
return tt;
}
// return all records of recordStore RecordStore
public String [] getRecordData( )
{
String[] str = null;
int counter = 0;
try
{
RecordEnumeration enumeration = recordStore.enumerateRecords(null, null, false);
str = new String[recordStore.getNumRecords()];
while(enumeration.hasNextElement())
{
try
{
str[counter] = (new String(enumeration.nextRecord()));
counter ++;
}
catch(javax.microedition.rms.RecordStoreException e)
{
}
}
}
catch(javax.microedition.rms.RecordStoreNotOpenException e)
{
}
catch(java.lang.NullPointerException n)
{
}
return str;
}
public void startApp()
{
com.sun.lwuit.Display.init(this);
final Button addition = new Button("add a goal");
final com.sun.lwuit.TextField tf = new com.sun.lwuit.TextField();
final com.sun.lwuit.List mylist = new com.sun.lwuit.List();
final Button All = new Button("All Goals");
final com.sun.lwuit.Form ff = new com.sun.lwuit.Form();
final com.sun.lwuit.Form g = new com.sun.lwuit.Form();
ff.getStyle().setBgColor(0X99CCFF);
All.getStyle().setBgColor(0X0066CC);
Style g_style5 = g.getSelectedStyle() ;
g.addComponent(tf);
g.addComponent(addition);
addition.getStyle().setBgColor(0X0066CC);
g.addComponent(All);
g.getStyle().setBgColor(0X99CCFF);
addition.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
//
String s =tf.getText();
if( s!=null && s.length() > 0)
{
try
{
// Store the time in the String k
String k = Refresh2();
// The record and the time stored in KK String
String kk =tf.getText()+"-"+k;
// Add an item (the kk String) to mylist List.
mylist.addItem(kk);
byte bytestream[] = kk.getBytes() ;
// Add a record to recordStore.
int i = recordStore.addRecord(bytestream, 0, bytestream.length);
}
catch(Exception ex) { }
// Inform the User that he added the a record.
Dialog validDialog = new Dialog(" ");
Style Dialogstyle = validDialog.getSelectedStyle() ;
validDialog.setScrollable(false);
validDialog.getDialogStyle().setBgColor(0x0066CC);
validDialog.setTimeout(1000); // set timeout milliseconds
TextArea textArea = new TextArea("...."); //pass the alert text here
textArea.setFocusable(false);
textArea.setText("A goal has been added"+"" );
validDialog.addComponent(textArea);
validDialog.show(0, 10, 10, 10, true);
}
// Information to user that he/she didn’t add a record
else if((s==null || s.length()<= 0))
{
Dialog validDialo = new Dialog(" ");
validDialo.setScrollable(false);
validDialo.getDialogStyle().setBgColor(0x0066CC);
validDialo.setTimeout(5000); // set timeout milliseconds
TextArea textArea = new TextArea("...."); //pass the alert text here
textArea.setFocusable(false);
textArea.setText("please enter scorer name or number");
validDialo.addComponent(textArea);
validDialo.show(50, 50, 50, 50, true);
}
}
});
/*Action here for displaying all records of recordStore RecordStore in a new form */
All.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
try
{
recordStore = RecordStore.openRecordStore("My Record Store", true);
}
catch(Exception ex) {}
try
{
com.sun.lwuit.Label l = new com.sun.lwuit.Label(" Team Goals") ;
ff.addComponent(l);
// Store the records of recordStore in string array
String [] record= getRecordData();
int j1;
String valueToBeInserted2="";
int k=getRecordData().length;
for( j1=0;j1< getRecordData().length;j1++)
{
valueToBeInserted2=valueToBeInserted2 + " " + record[j1];
if(j1==getRecordData().length)
{
mylist.addItem(record[j1]);
int m = getRecordData().length;
// Counting the number of records
String goals =""+getRecordData().length;
/* I tried to use for…loop to count them by length of the recordStore and render it.
This list also should display the number of records on the form.
But it didn’t !!!
*/
mylist.addItem(goals);
}
}
ff.addComponent(mylist);
}
catch(java.lang.IllegalArgumentException e)
{
}
finally
{
ff.show();
}
}
}
);
g.show();
}
public void pauseApp()
{
}
public void destroyApp(boolean unconditional) {
}
}
I Wrote this code but it gives NullPointerException at recordStore.enumerateRecords (null, null,true);
So I think the problem here.
please help.
myButton.addActionListener( new ActionListener()
{
public void actionPerformed(ActionEvet av)
{
try
{
RecordEnumeration enumeration = recordStore.enumerateRecords (null, null,true);
int o =recordStore.getNumRecords () ;
}
catch(Exception e)
{
}
}
});
what you need is enumeration.numRecords(); i reckon recordStore.getNumRecords() should work also, since this is what you are using the populate the array, you could even use the length of the array itself. These options are all in the code, it would be better to explore a bit more and also check the documentation to resolve trivial problems.
you could use the length of the array or set a RecordListener to your recordstore and increase a counter when added a record to recordstore.
here is the solution of my problem , I do a for loop to get the number of
elements of the array.
the counter should be the length of array
count.addActionListener( new ActionListener()
{
public void actionPerformed(ActionEvent av)
{
try
{
recordStore = RecordStore.openRecordStore("recordStore", true);
}
catch(Exception e)
{ }
try
{
RecordEnumeration enumeration = recordStore.enumerateRecords (null, null,true);
}
catch(Exception e)
{
}
String record[] = getRecordData();
int j;
j = record.length-1;
Dialog validDialog = new Dialog(" ");
Style Dialogstyle = validDialog.getSelectedStyle() ;
validDialog.setScrollable(false);
validDialog.getDialogStyle().setBgColor(0x0066CC);
validDialog.setTimeout(1000); // set timeout milliseconds
TextArea textArea = new TextArea("....");
textArea.setFocusable(false);
textArea.setText("Number Counted"+j );
validDialog.addComponent(textArea);
validDialog.show(0, 10, 10, 10, true);
}});