/*******************************************************************************
* Copyright 2011 Antti Havanko
*
* This file is part of Motiver.fi.
* Motiver.fi is licensed under one open source license and one commercial license.
*
* Commercial license: This is the appropriate option if you want to use Motiver.fi in
* commercial purposes. Contact license@motiver.fi for licensing options.
*
* Open source license: This is the appropriate option if you are creating an open source
* application with a license compatible with the GNU GPL license v3. Although the GPLv3 has
* many terms, the most important is that you must provide the source code of your application
* to your users so they can be free to modify your application for their own needs.
******************************************************************************/
package com.delect.motiver.client.view.nutrition;
import java.util.Date;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.delect.motiver.client.AppController;
import com.delect.motiver.client.Motiver;
import com.delect.motiver.client.presenter.nutrition.NutritionDayPresenter;
import com.delect.motiver.client.presenter.nutrition.NutritionDayPresenter.NutritionDayHandler;
import com.delect.motiver.client.view.widget.MyButton;
import com.delect.motiver.shared.Constants;
import com.delect.motiver.shared.util.CommonUtils;
import com.delect.motiver.shared.util.CommonUtils.MessageBoxHandler;
import com.extjs.gxt.ui.client.Style.ButtonScale;
import com.extjs.gxt.ui.client.event.BaseEvent;
import com.extjs.gxt.ui.client.event.ComponentEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.util.Margins;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.Document;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.MessageBox;
import com.extjs.gxt.ui.client.widget.Text;
import com.extjs.gxt.ui.client.widget.form.DateField;
import com.extjs.gxt.ui.client.widget.layout.RowData;
import com.extjs.gxt.ui.client.widget.layout.RowLayout;
/**
* Foods for single day
* <br> Totals always visible
* <br> When clicked totals -> shows foods & comments
* @author Antti
*
*/
public class NutritionDayView extends NutritionDayPresenter.NutritionDayDisplay {
private MessageBox box = null;
private MyButton btnShowFoods = new MyButton();
private int floatingPosition;
private boolean foodsPermission = true;
private NutritionDayHandler handler;
private boolean isFloating = false;
private Listener<ComponentEvent> listenerShortcuts = new Listener<ComponentEvent>() {
@Override
public void handleEvent(ComponentEvent ce) {
//if valid key comco
if(CommonUtils.isValidKeyCombo(ce)) {
//if enough time elapsed
if(System.currentTimeMillis() - timeLastKeyEvent < Constants.DELAY_KEY_EVENTS) {
return;
}
switch(ce.getKeyCode()) {
//shift + T
case 84:
timeLastKeyEvent = System.currentTimeMillis();
handler.newTime();
ce.cancelBubble();
break;
}
}
}
};
private ContentPanel panelData = new ContentPanel();
private ContentPanel panelDetailed = new ContentPanel();
private HorizontalPanel panelButtonsBottom = new HorizontalPanel();
private LayoutContainer panelComments = new LayoutContainer();
private LayoutContainer panelContent = new LayoutContainer();
private LayoutContainer panelFoods = new LayoutContainer();
private LayoutContainer panelGuide = new LayoutContainer();
private LayoutContainer panelTotals = new LayoutContainer();
private LayoutContainer panelTotalsDuplicate = new LayoutContainer();
private Text textTitle = new Text();
private long timeLastKeyEvent = 0;
private Date date;
MyButton btnCopyTimes = new MyButton();
final DateField tfDate = CommonUtils.getDateField(new Date());
public NutritionDayView() {
panelContent.setStyleName("panel-today-nutrition");
panelContent.setLayout(new RowLayout());
panelData.setLayout(new RowLayout());
panelDetailed.setHeaderVisible(false);
panelDetailed.setTitleCollapse(true);
panelDetailed.setCollapsible(true);
panelData.setHeaderVisible(false);
panelData.setTitleCollapse(true);
panelData.setCollapsible(true);
//listeners for shift+key
Document.get().addListener(Constants.EVENT_TYPE_GLOBAL_HOTKEYS, listenerShortcuts);
}
@Override
public Widget asWidget() {
panelContent.removeAll();
this.removeAll();
//title
textTitle.setStyleName("label-title-medium");
panelContent.add(textTitle, new RowData(-1, -1, new Margins(10)));
//totals
panelContent.add(panelTotals);
//"duplicate". Used when floating totals panel
panelTotalsDuplicate.setVisible(false);
panelContent.add(panelTotalsDuplicate);
//buttons (if permission to show foods)
if(foodsPermission) {
HorizontalPanel panelButtons = new HorizontalPanel();
panelButtons.setSpacing(8);
//show/hide foods
btnShowFoods.setText(AppController.Lang.ShowTarget(AppController.Lang.Foods().toLowerCase()));
btnShowFoods.setScale(ButtonScale.MEDIUM);
btnShowFoods.addListener(Events.OnClick, new Listener<BaseEvent>() {
@Override
public void handleEvent(BaseEvent be) {
if(panelData.isExpanded()) {
btnShowFoods.setText(AppController.Lang.ShowTarget(AppController.Lang.Foods().toLowerCase()));
panelData.collapse();
}
else {
btnShowFoods.setText(AppController.Lang.HideTarget(AppController.Lang.Foods().toLowerCase()));
panelData.expand();
}
}
});
panelButtons.add(btnShowFoods);
//show extra info
final MyButton btnShowExtraInfo = new MyButton();
btnShowExtraInfo.setStyleAttribute("margin-right", "10px");
btnShowExtraInfo.setText(AppController.Lang.ShowTarget(AppController.Lang.Details().toLowerCase()));
btnShowExtraInfo.setScale(ButtonScale.MEDIUM);
btnShowExtraInfo.addListener(Events.OnClick, new Listener<BaseEvent>() {
@Override
public void handleEvent(BaseEvent be) {
if(panelDetailed.isExpanded()) {
btnShowExtraInfo.setText(AppController.Lang.ShowTarget(AppController.Lang.Details().toLowerCase()));
panelDetailed.collapse();
}
else {
btnShowExtraInfo.setText(AppController.Lang.HideTarget(AppController.Lang.Details().toLowerCase()));
panelDetailed.expand();
}
}
});
panelButtons.add(btnShowExtraInfo);
panelContent.add(panelButtons);
}
//detailed info
panelDetailed.addListener(Events.Expand, new Listener<BaseEvent>() {
@Override
public void handleEvent(BaseEvent be) {
handler.detailsVisible();
}
});
panelDetailed.addListener(Events.Collapse, new Listener<BaseEvent>() {
@Override
public void handleEvent(BaseEvent be) {
handler.detailsHidden();
}
});
panelContent.add(panelDetailed);
panelDetailed.collapse();
//foods
panelData.setBorders(false);
panelData.add(panelFoods, new RowData(-1, -1, new Margins(10, 0, 0, 0)));
//buttons
//add time link
MyButton btnAdd = new MyButton();
btnAdd.setText(AppController.Lang.AddTarget(AppController.Lang.Time().toLowerCase()));
btnAdd.setScale(ButtonScale.MEDIUM);
btnAdd.setColor(MyButton.Style.GREEN);
btnAdd.addListener(Events.OnClick, new Listener<BaseEvent>() {
@Override
public void handleEvent(BaseEvent be) {
handler.newTime();
}
});
panelButtonsBottom.add(btnAdd);
//remove all times link
MyButton btnRemoveAll = new MyButton();
btnRemoveAll.setStyleAttribute("margin-left", "5px");
btnRemoveAll.setText(AppController.Lang.RemoveAllTarget(AppController.Lang.Times().toLowerCase()));
btnRemoveAll.setScale(ButtonScale.MEDIUM);
btnRemoveAll.setColor(MyButton.Style.RED);
btnRemoveAll.addListener(Events.OnClick, new Listener<BaseEvent>() {
@Override
public void handleEvent(BaseEvent be) {
//ask for confirm
box = CommonUtils.getMessageBoxConfirm(AppController.Lang.RemoveConfirm(AppController.Lang.AllTimes().toLowerCase()), new MessageBoxHandler() {
@Override
public void okPressed(String text) {
handler.removeTimes();
}
});
box.show();
}
});
panelButtonsBottom.add(btnRemoveAll);
//copy times to another day
tfDate.setStyleAttribute("margin-left", "75px");
tfDate.setStyleAttribute("margin-top", "2px");
tfDate.addListener(Events.Valid, new Listener<BaseEvent>() {
@Override
public void handleEvent(BaseEvent be) {
btnCopyTimes.setText(AppController.Lang.CopyTargetTo(AppController.Lang.Foods().toLowerCase(), CommonUtils.getDateString(tfDate.getValue(), false, false, true)));
//disable button if current day
btnCopyTimes.setEnabled(!CommonUtils.isSameDate(date, tfDate.getValue()));
}
});
panelButtonsBottom.add(tfDate);
btnCopyTimes.setStyleAttribute("margin-left", "15px");
btnCopyTimes.setText(AppController.Lang.CopyTargetTo(AppController.Lang.Foods().toLowerCase(), CommonUtils.getDateString(tfDate.getValue(), false, false, true)));
btnCopyTimes.setScale(ButtonScale.MEDIUM);
btnCopyTimes.addListener(Events.OnClick, new Listener<BaseEvent>() {
@Override
public void handleEvent(BaseEvent be) {
handler.copyTimes(tfDate.getValue());
}
});
panelButtonsBottom.add(btnCopyTimes);
panelData.add(panelButtonsBottom, new RowData(-1, -1, new Margins(10, 0, 10, 10)));
//call handler when panel expands/collapses
panelData.addListener(Events.Expand, new Listener<BaseEvent>() {
@Override
public void handleEvent(BaseEvent be) {
handler.timesVisible();
}
});
panelData.addListener(Events.Collapse, new Listener<BaseEvent>() {
@Override
public void handleEvent(BaseEvent be) {
handler.timesHidden();
}
});
panelContent.add(panelData, new RowData(-1, -1, new Margins(0, 0, 5, 0)));
//comments
panelContent.add(panelComments, new RowData(-1, -1, new Margins(10)));
this.add(panelContent);
//guides
this.add(panelGuide);
panelFoods.setStyleAttribute("min-height", "250px");
panelFoods.setLayout(new RowLayout());
panelData.collapse();
//transparent when mouse not over
setTransparencyOnMouseOver(true);
return this;
}
@Override
public LayoutContainer getBodyContainer() {
return panelFoods;
}
@Override
public LayoutContainer getCommentsContainer() {
return panelComments;
}
@Override
public LayoutContainer getDetailsContainer() {
return panelDetailed;
}
@Override
public LayoutContainer getGuideContainer() {
return panelGuide;
}
@Override
public LayoutContainer getTotalsContainer() {
return panelTotals;
}
@Override
public void onScroll(int y) {
try {
//save position
if(!isFloating) {
floatingPosition = panelTotals.getAbsoluteTop();
}
//if not floating or scrolled over this panel
int foodsY = panelFoods.getAbsoluteTop();
int foodsH = panelFoods.getHeight();
//if panel not visible
if(floatingPosition < y + 40) {
//if scrolled over whole panel -> stop float
if(y + panelTotals.getHeight() + 100 > foodsY + foodsH) {
if(isFloating) {
//hide "duplicate"
panelTotalsDuplicate.setVisible(false);
panelTotals.removeStyleName("panel-floating");
isFloating = false;
}
}
else if(!isFloating) {
//show "duplicate"
panelTotalsDuplicate.setHeight(panelTotals.getHeight());
panelTotalsDuplicate.setVisible(true);
panelTotals.setWidth(panelTotalsDuplicate.getWidth());
panelTotals.addStyleName("panel-floating");
panelTotals.setStyleAttribute("left", (panelTotalsDuplicate.getAbsoluteLeft() - 2) + "px");
isFloating = true;
}
}
//panel visible
else {
if(isFloating) {
//hide "duplicate"
panelTotalsDuplicate.setVisible(false);
panelTotals.removeStyleName("panel-floating");
isFloating = false;
}
}
} catch (Exception e) {
Motiver.showException(e);
}
}
@Override
public void onStop() {
//remove key listeners
Document.get().removeListener(Constants.EVENT_TYPE_GLOBAL_HOTKEYS, listenerShortcuts);
if(box != null && box.isVisible()) {
box.close();
}
}
@Override
public void removeAllFromTotals() {
panelTotals.removeAll();
}
@Override
public void setAddButtonVisible(boolean visible) {
if(panelButtonsBottom != null) {
panelButtonsBottom.setVisible(visible);
}
}
@Override
public void setDate(Date date) {
this.date = date;
textTitle.setText(AppController.Lang.Foods());
//disable copy button if current day
btnCopyTimes.setEnabled(!CommonUtils.isSameDate(date, tfDate.getValue()));
}
@Override
public void setFoodsEnabled(boolean foodsPermission) {
this.foodsPermission = foodsPermission;
}
@Override
public void setHandler(final NutritionDayHandler handler) {
this.handler = handler;
}
@Override
public void showContent() {
//if already expanded -> just call handler
if(panelData.isExpanded()) {
handler.timesVisible();
}
else {
panelData.expand();
}
btnShowFoods.setText(AppController.Lang.HideTarget(AppController.Lang.Foods().toLowerCase()));
}
}