edu.nps.moves.mmowgli.components.CardSummaryListHeader.java Source code

Java tutorial

Introduction

Here is the source code for edu.nps.moves.mmowgli.components.CardSummaryListHeader.java

Source

/*
  Copyright (C) 2010-2014 Modeling Virtual Environments and Simulation
  (MOVES) Institute at the Naval Postgraduate School (NPS)
  http://www.MovesInstitute.org and http://www.nps.edu
     
  This file is part of Mmowgli.
      
  Mmowgli is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  any later version.
    
  Mmowgli is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
    
  You should have received a copy of the GNU General Public License
  along with Mmowgli in the form of a file named COPYING.  If not,
  see <http://www.gnu.org/licenses/>
*/

package edu.nps.moves.mmowgli.components;

import java.util.*;

import com.vaadin.event.FieldEvents.TextChangeEvent;
import com.vaadin.event.FieldEvents.TextChangeListener;
import com.vaadin.event.LayoutEvents.LayoutClickEvent;
import com.vaadin.event.LayoutEvents.LayoutClickListener;
import com.vaadin.server.Resource;
import com.vaadin.ui.*;
import com.vaadin.ui.AbstractTextField.TextChangeEventMode;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.Window.CloseEvent;
import com.vaadin.ui.Window.CloseListener;

import edu.nps.moves.mmowgli.*;
import edu.nps.moves.mmowgli.MmowgliSessionGlobals.CardPermission;
import edu.nps.moves.mmowgli.cache.MCacheUserHelper.QuickUser;
import edu.nps.moves.mmowgli.db.*;
import edu.nps.moves.mmowgli.hibernate.HSess;
import edu.nps.moves.mmowgli.markers.*;
import edu.nps.moves.mmowgli.modules.actionplans.AddAuthorDialog;
import edu.nps.moves.mmowgli.modules.cards.*;
import edu.nps.moves.mmowgli.utility.BaseCoroutine;

/**
 * CardSummaryListHeader.java Created on Feb 3, 2011
 * 
 * MOVES Institute Naval Postgraduate School, Monterey, CA, USA www.nps.edu
 * 
 * @author Mike Bailey, jmbailey@nps.edu
 * @version $Id$
 */
public class CardSummaryListHeader extends AbsoluteLayout implements MmowgliComponent {
    private static final long serialVersionUID = 7131657887407479242L;

    public static final String CARDLISTHEADER_H = "165px";
    public static final String CARDLISTHEADER_W = "235px";
    public static final String CARDLISTHEADER_TOTAL_H = "262px";
    public static final String CARDLISTHEADER_TITLE_H = "26px";
    public static final String CARDLISTHEADER_TITLE_W = "214px";
    public static final String CARDLISTHEADER_TITLE_POS = "top:17px;left:20px";
    public static final String CARDLISTHEADER_CONTENT_H = "80px";
    public static final String CARDLISTHEADER_CONTENT_W = "190px";
    public static final String CARDLISTHEADER_CONTENT_POS = "top:58px;left:20px";
    public static final String CARDLISTHEADER_DRAWER_H = "138px";
    public static final String CARDLISTHEADER_DRAWER_W = "236px";
    public static final String CARDLISTHEADER_DRAWER_POS = "top:127px;left:-1px";

    public static final String CARDLISTHEADER_DRAWER_TEXT_W = "208px";
    public static final String CARDLISTHEADER_DRAWER_TEXT_H = "70px";
    public static final String CARDLISTHEADER_DRAWER_TEXT_POS = "top:32px;left:14px";

    public static final String CARDLISTHEADER_DRAWER_COUNT_W = "64px";
    public static final String CARDLISTHEADER_DRAWER_COUNT_H = "15px";
    public static final String CARDLISTHEADER_DRAWER_COUNT_POS = "top:109px;left:15px";
    public static final String CARDLISTHEADER_DRAWER_CANCEL_W = "64px";
    public static final String CARDLISTHEADER_DRAWER_CANCEL_H = "15px";
    public static final String CARDLISTHEADER_DRAWER_CANCEL_POS = "top:106px;left:87px";
    public static final String CARDLISTHEADER_DRAWER_OKBUTT_W = "64px";
    public static final String CARDLISTHEADER_DRAWER_OKBUTT_H = "15px";
    public static final String CARDLISTHEADER_DRAWER_OKBUTT_POS = "top:106px;left:155px";

    public static CardSummaryListHeader newCardSummaryListHeader(CardType ct, Card parent) {
        return newCardSummaryListHeader(ct, false, parent);
    }

    public static CardSummaryListHeader newCardSummaryListHeader(CardType ct, boolean mockupOnly, Card parent) {
        CardSummaryListHeader lstHdr = new CardSummaryListHeader(ct.getId(), mockupOnly, parent);
        MmowgliSessionGlobals globs = Mmowgli2UI.getGlobals();
        lstHdr.bckgrndResource = globs.mediaLocator().getCardSummaryListHeaderBackground(ct);
        lstHdr.drawerResource = globs.mediaLocator().getCardSummaryDrawerBackground(ct);
        return lstHdr;
    }

    private Resource bckgrndResource;
    private Resource drawerResource;
    private Label title;
    private Embedded titleImage;
    private Label content;
    private Object ctId;
    private CardType ct;
    BuilderDrawer drawerComponent;

    private boolean mockupOnly = false;
    private Card parent = null; // may remain null
    private String HEIGHT_NODRAWER = CARDLISTHEADER_H;
    private String HEIGHT_YESDRAWER = CARDLISTHEADER_TOTAL_H;

    @HibernateSessionThreadLocalConstructor
    private CardSummaryListHeader(Object cardTypeId, boolean mockupOnly, Card parent) {
        title = new Label();
        content = new Label();
        this.ctId = cardTypeId;
        this.mockupOnly = mockupOnly;
        this.parent = parent;
    }

    @SuppressWarnings("serial")
    @Override
    public void initGui() {
        addStyleName("m-cursor-pointer");
        if (bckgrndResource != null) {
            Embedded bkgnd = new Embedded(null, bckgrndResource);
            addComponent(bkgnd, "top:0px;left:0px");
        }
        final MmowgliSessionGlobals globs = Mmowgli2UI.getGlobals();
        ct = CardType.getTL(ctId);
        String textColorStyle = CardStyler.getCardTextColorOverBaseStyle(ct);

        // nested abslay for the click handler
        AbsoluteLayout topHalfLay = new AbsoluteLayout();
        topHalfLay.setWidth(CARDLISTHEADER_W);
        topHalfLay.setHeight(HEIGHT_NODRAWER);
        addComponent(topHalfLay, "top:0px;left:0px");

        title.setValue(ct.getTitle()); // .toUpperCase());
        title.setHeight(CARDLISTHEADER_TITLE_H);
        title.setWidth(CARDLISTHEADER_TITLE_W);
        title.addStyleName("m-cardsummarylist-header-title");
        title.addStyleName("m-cursor-pointer");
        title.addStyleName("m-vagabond-font");
        if (textColorStyle != null)
            title.addStyleName(textColorStyle);

        topHalfLay.addComponent(title, CARDLISTHEADER_TITLE_POS);

        content.setValue(ct.getPrompt());
        content.setHeight(CARDLISTHEADER_CONTENT_H);
        content.setWidth(CARDLISTHEADER_CONTENT_W);
        content.addStyleName("m-cardsummarylist-header-content");
        content.addStyleName("m-cursor-pointer");
        if (textColorStyle != null)
            content.addStyleName(textColorStyle);
        // cause exception w/ 2 windows?

        content.setId(CardDebug.getCardCreateClickDebugId(ct));
        topHalfLay.addComponent(content, CARDLISTHEADER_CONTENT_POS);

        boolean cantCreateBecauseHiddenParent = checkNoCreateBecauseHiddenTL(parent);
        boolean cantCreateBecauseParentMarkedNoChild = false; //todo enable with gameswitch checkNoCreateBecauseParentMarkedNoChild(parent);

        if (globs.canCreateCard(ct.isIdeaCard())) {
            markedAsNoCreate = false;
            if (!cantCreateBecauseHiddenParent && !cantCreateBecauseParentMarkedNoChild) {
                //Add the text at the bottom
                Label lab;
                topHalfLay.addComponent(lab = new Label("click to add new"), "top:130px;left:75px");
                lab.addStyleName("m-click-to-add-new");
                if (textColorStyle != null)
                    lab.addStyleName(textColorStyle);
            }
        } else
            markedAsNoCreate = true;

        drawerComponent = new BuilderDrawer();
        addComponent(drawerComponent, CARDLISTHEADER_DRAWER_POS);
        drawerComponent.setVisible(false);

        setWidth(CARDLISTHEADER_W);
        setHeight(HEIGHT_NODRAWER);

        if (!mockupOnly)
            topHalfLay.addLayoutClickListener(new LayoutClickListener() {
                @Override
                @MmowgliCodeEntry
                @HibernateOpened
                @HibernateClosed
                public void layoutClick(LayoutClickEvent event) {
                    HSess.init();
                    if (checkNoCreateBecauseHiddenTL(parent)) { //todo enable with game switch || checkNoCreateBecauseParentMarkedNoChild(parent)) {
                        if (drawerComponent.isVisible())
                            closeDrawer();
                        HSess.close();
                        return;
                    }

                    if (drawerComponent.isVisible())
                        closeDrawer();
                    else {
                        CardPermission cp = globs.cardPermissionsCommon(ct.isIdeaCard());
                        if (!cp.canCreate) {
                            if (!markedAsNoCreate)
                                handleNoCreate();
                            Notification.show(cp.whyNot);
                        } else {
                            showDrawer();
                            handleCanCreate(); // reset tt, etc.
                            if (newCardListener != null)
                                newCardListener.drawerOpenedTL(ctId);
                        }
                    }
                    HSess.close();
                }
            });
        if (cantCreateBecauseHiddenParent)
            handleNoCreate("Can't add card to hidden parent");
        else if (cantCreateBecauseParentMarkedNoChild)
            handleNoCreate("New child cards cannot be added to this card");
        else if (!globs.canCreateCard(ct.isIdeaCard()))
            handleNoCreate();
        else
            setTooltip("Click to add card");
    }

    private boolean checkNoCreateBecauseHiddenTL(Card c) {
        if (c == null)
            return false; // ok to create
        User me = Mmowgli2UI.getGlobals().getUserTL();
        return c.isHidden() && !me.isGameMaster();
    }

    //todo the "no child" marking needs to be enabled with game switch
    private boolean checkNoCreateBecauseParentMarkedNoChild(Card c) {
        if (c == null)
            return false; // ok to create
        return CardMarkingManager.isNoChildren(c);
    }

    private void handleCanCreate() {
        if (markedAsNoCreate) {
            markedAsNoCreate = false;
            setTooltip("Click to add card");
            CardSummaryListHeader.this.addStyleName("m-cursor-pointer");
            title.addStyleName("m-cursor-pointer");
            content.addStyleName("m-cursor-pointer");
        }
    }

    private boolean markedAsNoCreate = false;

    private void handleNoCreate() {
        handleNoCreate(null);
    }

    private void handleNoCreate(String msg) {
        if (!markedAsNoCreate) {
            markedAsNoCreate = true;
            if (msg == null) {
                MmowgliSessionGlobals globs = Mmowgli2UI.getGlobals();
                setTooltip(globs.whyCantCreateCard(ct.isIdeaCard()));
            } else
                setTooltip(msg);

            CardSummaryListHeader.this.removeStyleName("m-cursor-pointer");
            title.removeStyleName("m-cursor-pointer");
            content.removeStyleName("m-cursor-pointer");
        }
    }

    private void setTooltip(String tt) {
        setDescription(tt); // abslay
        if (titleImage != null)
            titleImage.setDescription(tt);
        if (title != null)
            title.setDescription(tt);
        content.setDescription(tt);
    }

    public void closeDrawer() {
        drawerComponent.setVisible(false);
        CardSummaryListHeader.this.setHeight(HEIGHT_NODRAWER);
    }

    private void showDrawer() {
        drawerComponent.setVisible(true);
        CardSummaryListHeader.this.setHeight(HEIGHT_YESDRAWER);
        drawerComponent.getTextEntryComponent().focus();
    }

    class BuilderDrawer extends AbsoluteLayout {
        private static final long serialVersionUID = -9012026151912117528L;
        TextArea content;
        Label count;
        NativeButton submitButt;
        NativeButton cancelButt;

        BuilderDrawer() {
            if (drawerResource != null) {
                Embedded drawerBkg = new Embedded(null, drawerResource);
                addComponent(drawerBkg, "top:0px;left:0px");
            }
            content = new TextArea();
            // only shows if no focus, and if we don't have focus, it's not normally showing
            // content.setInputPrompt("Type here to add to this card chain.");
            content.setWordwrap(true);
            content.setImmediate(true);
            content.setTextChangeEventMode(TextChangeEventMode.LAZY);
            content.setTextChangeTimeout(500);
            // cause exception w/ 2 windows?
            // content.setDebugId(CardTypeManager.getCardContentDebugId(ct));
            content.setId(CardDebug.getCardContentDebugId(ct));//CardTypeManager.getCardContentDebugId(ct));

            content.addTextChangeListener(new characterTypedHandler());

            content.setWidth(CARDLISTHEADER_DRAWER_TEXT_W);
            content.setHeight(CARDLISTHEADER_DRAWER_TEXT_H);
            content.addStyleName("m-white-background");
            addComponent(content, CARDLISTHEADER_DRAWER_TEXT_POS);

            count = new Label("0/140");
            count.setWidth(CARDLISTHEADER_DRAWER_COUNT_W);
            count.setHeight(CARDLISTHEADER_DRAWER_COUNT_H);
            count.addStyleName("m-cardbuilder-count-text");
            addComponent(count, CARDLISTHEADER_DRAWER_COUNT_POS);

            cancelButt = new NativeButton("cancel");
            cancelButt.setWidth(CARDLISTHEADER_DRAWER_CANCEL_W);
            cancelButt.setHeight(CARDLISTHEADER_DRAWER_CANCEL_H);
            cancelButt.addStyleName("borderless");
            cancelButt.addStyleName("m-cardbuilder-button-text");
            cancelButt.addClickListener(new CancelHandler());
            addComponent(cancelButt, CARDLISTHEADER_DRAWER_CANCEL_POS);

            submitButt = new NativeButton("submit");
            // cause exception w/ 2 windows?
            // submitButt.setDebugId(CardTypeManager.getCardSubmitDebugId(ct));
            submitButt.setId(CardDebug.getCardSubmitDebugId(ct));//CardTypeManager.getCardSubmitDebugId(ct));

            submitButt.setWidth(CARDLISTHEADER_DRAWER_OKBUTT_W);
            submitButt.setHeight(CARDLISTHEADER_DRAWER_OKBUTT_H);
            submitButt.addStyleName("borderless");
            submitButt.addStyleName("m-cardbuilder-button-text");
            submitButt.addClickListener(new CardPlayHandler());
            addComponent(submitButt, CARDLISTHEADER_DRAWER_OKBUTT_POS);

            setWidth(CARDLISTHEADER_DRAWER_W);
            setHeight(CARDLISTHEADER_DRAWER_H);
        }

        public AbstractField<?> getTextEntryComponent() {
            return content;
        }

        @Override
        public void setVisible(boolean visible) {
            super.setVisible(visible);
            if (visible && content.getValue().toString().length() > 0)
                content.selectAll();
        }

        @SuppressWarnings("serial")
        class CancelHandler implements ClickListener {
            @Override
            public void buttonClick(ClickEvent event) {
                closeDrawer();
            }
        }

        @SuppressWarnings("serial")
        class characterTypedHandler implements TextChangeListener {
            @Override
            public void textChange(TextChangeEvent event) {
                String s = event.getText();
                if (s == null)
                    ;
                else {
                    int num = s.trim().length();
                    count.setValue("" + num + "/140");
                }
            }
        }

        @SuppressWarnings("serial")
        class CardPlayHandler extends BaseCoroutine implements Button.ClickListener {
            private User author;
            private String txt;
            private ClickEvent event;

            @Override
            @MmowgliCodeEntry
            @HibernateOpened
            @HibernateClosed
            public void buttonClick(ClickEvent event) {
                HSess.init();
                this.event = event;
                run(); // executes step1() of the coroutine
                HSess.close();
            }

            @Override
            public void step1() {
                txt = content.getValue().toString();
                txt = txt.trim();
                if (txt.length() < 5) {
                    Notification.show("Card not played.", "Your message is too short to be useful.",
                            Notification.Type.ERROR_MESSAGE);
                    doNotAdvanceSteps(); // come into step1 again next time
                    return;
                }
                if (txt.length() > 140) {
                    Notification.show("Card not played.", "Only 140 characters please.",
                            Notification.Type.ERROR_MESSAGE);
                    doNotAdvanceSteps(); // come into step1 again next time
                    return;
                }

                // Admins get to add cards under other names
                author = Mmowgli2UI.getGlobals().getUserTL();
                if (author.isAdministrator())
                    adminSwitchAuthorsTL(event.getButton(), this);
                else
                    run(); // does not need to suspend, so "continues" and executes step2
                           // in the same clicklistener thread
            }

            @Override
            @HibernateUserRead
            public void step2() {
                CardType ct = CardType.getTL(ctId);
                Date dt = new Date();
                Card c = new Card(txt, ct, dt);
                c.setCreatedInMove(Move.getCurrentMoveTL());
                c.setAuthor(User.getTL(author.getId())); // fresh
                if (newCardListener != null)
                    newCardListener.cardCreatedTL(c);

                content.setValue("");
                content.setInputPrompt("Enter text for another card.");
                closeDrawer();

                resetCoroutine(); // for another click
            }
        }

        @SuppressWarnings("serial")
        @HibernateRead
        private void adminSwitchAuthorsTL(Button butt, final CardPlayHandler coroutine) {
            ArrayList<User> meLis = new ArrayList<User>(1);
            meLis.add(coroutine.author);
            User me = User.getTL(Mmowgli2UI.getGlobals().getUserID());

            final AddAuthorDialog dial = new AddAuthorDialog(meLis, true);
            StringBuilder sb = new StringBuilder("As adminstrator, <b>");
            sb.append(me.getUserName());
            sb.append("</b>, you may choose another player to be card author.");
            dial.infoLabel.setValue(sb.toString());
            dial.setCaption("Select Proxy Author");
            dial.setMultiSelect(false);
            dial.cancelButt.setCaption("Use myself");
            dial.addButt.setCaption("Use selected");

            // Rearrange buttons, add real cancel butt.
            // -------------------
            HorizontalLayout buttonHL = dial.getButtonHorizontalLayout();
            Iterator<Component> itr = buttonHL.iterator();
            Vector<Component> v = new Vector<Component>();
            while (itr.hasNext()) {
                Component component = itr.next();
                if (component instanceof Button)
                    v.add(component);
            }
            buttonHL.removeAllComponents();
            itr = v.iterator();
            while (itr.hasNext()) {
                buttonHL.addComponent(itr.next());
            }
            Label sp = null;
            buttonHL.addComponent(sp = new Label());
            sp.setWidth("1px");
            buttonHL.setExpandRatio(sp, 1.0f);

            Button cancelButt = null;
            buttonHL.addComponent(cancelButt = new Button("Cancel"));
            cancelButt.addClickListener(new ClickListener() {
                @Override
                public void buttonClick(ClickEvent event) {
                    UI.getCurrent().removeWindow(dial);// dial.getParent().removeWindow(dial);
                    coroutine.resetCoroutine();
                }
            });
            // -------------------

            dial.selectItemAt(0);
            dial.addListener(new CloseListener() {
                @Override
                @MmowgliCodeEntry
                @HibernateOpened
                @HibernateClosed
                @HibernateUserRead
                public void windowClose(CloseEvent e) {
                    HSess.init();
                    if (dial.addClicked) {
                        Object o = dial.getSelected();

                        if (o instanceof User) {
                            coroutine.author = (User) o;
                        } else if (o instanceof QuickUser) {
                            QuickUser qu = (QuickUser) o;
                            coroutine.author = User.getTL(qu.id);
                        }
                    }
                    coroutine.run(); // finish up
                    HSess.close();
                }
            });

            UI.getCurrent().addWindow(dial);
            dial.center();
        }
    }

    NewCardListener newCardListener;

    public void addNewCardListener(NewCardListener lis) {
        newCardListener = lis;
    }

    public static interface NewCardListener {
        public void cardCreatedTL(Card c);

        public void drawerOpenedTL(Object cardTypeId);
    }

    public void cardUpdated_oobTL() {
        parent = Card.getTL(parent.getId()); // refresh in case markings have changed
        parent.getMarking(); // make sure it's retrieved

        // This would close the drawer (edit drop-down) of ANYBODY who is playing off this card at the moment, losing their work
        //if (drawerComponent.isVisible())
        //  closeDrawer();
    }
}