9d58d81c4d0ee29380b77acac651674694f9834e
[pithos-web-client] / src / gr / grnet / pithos / web / client / InvitationsDialog.java
1 /*
2  * Copyright 2011 GRNET S.A. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or
5  * without modification, are permitted provided that the following
6  * conditions are met:
7  *
8  *   1. Redistributions of source code must retain the above
9  *      copyright notice, this list of conditions and the following
10  *      disclaimer.
11  *
12  *   2. Redistributions in binary form must reproduce the above
13  *      copyright notice, this list of conditions and the following
14  *      disclaimer in the documentation and/or other materials
15  *      provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
18  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
21  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
24  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  *
30  * The views and conclusions contained in the software and
31  * documentation are those of the authors and should not be
32  * interpreted as representing official policies, either expressed
33  * or implied, of GRNET S.A.
34  */
35 package gr.grnet.pithos.web.client;
36
37 import gr.grnet.pithos.web.client.foldertree.Resource;
38 import gr.grnet.pithos.web.client.rest.PostRequest;
39
40 import com.google.gwt.core.client.GWT;
41 import com.google.gwt.core.client.Scheduler;
42 import com.google.gwt.dom.client.NativeEvent;
43 import com.google.gwt.event.dom.client.ClickEvent;
44 import com.google.gwt.event.dom.client.ClickHandler;
45 import com.google.gwt.event.dom.client.KeyCodes;
46 import com.google.gwt.http.client.Response;
47 import com.google.gwt.user.client.Event.NativePreviewEvent;
48 import com.google.gwt.user.client.ui.Anchor;
49 import com.google.gwt.user.client.ui.Button;
50 import com.google.gwt.user.client.ui.DialogBox;
51 import com.google.gwt.user.client.ui.FlexTable;
52 import com.google.gwt.user.client.ui.HTML;
53 import com.google.gwt.user.client.ui.HasHorizontalAlignment;
54 import com.google.gwt.user.client.ui.HorizontalPanel;
55 import com.google.gwt.user.client.ui.Image;
56 import com.google.gwt.user.client.ui.TextBox;
57 import com.google.gwt.user.client.ui.VerticalPanel;
58 import com.google.gwt.user.client.ui.Widget;
59
60
61 /**
62  * A dialog box that displays info about invitations
63  */
64 public class InvitationsDialog extends DialogBox {
65         private static final int INV_PER_PAGE = 5;
66         
67         Pithos app;
68         VerticalPanel messagesPanel;
69         int rows = 0;
70         FlexTable sentInvitationsTable; 
71         /**
72          * The current displayed page of sent invitations 
73          */
74         int currentPage = 0;
75         HorizontalPanel pagerPanel;     
76         /**
77          * The widget constructor.
78          */
79         public InvitationsDialog(Pithos _app, final Invitations inv) {
80                 this.app = _app;
81                 Anchor close = new Anchor();
82                 close.addStyleName("close");
83                 close.addClickHandler(new ClickHandler() {
84                         
85                         @Override
86                         public void onClick(ClickEvent event) {
87                                 hide();
88                         }
89                 });
90                 // Set the dialog's caption.
91                 setText("Invite friends");
92                 setAnimationEnabled(true);
93                 setGlassEnabled(true);
94                 setStyleName("pithos-DialogBox");
95                 VerticalPanel outer = new VerticalPanel();
96                 outer.addStyleName("outer");
97                 outer.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT);
98
99                 VerticalPanel inner = new VerticalPanel();
100                 inner.addStyleName("inner");
101                 // Create the text and set a style name so we can style it with CSS.
102                 HTML text = new HTML("You have <span class='pithos-leftInvitationsNumber'>" + inv.getInvitationsLeft() + "</span> invitations left");
103                 text.addStyleName("pithos-invitationsLeft");
104                 inner.add(text);
105                 
106                 HorizontalPanel split = new HorizontalPanel();
107                 split.addStyleName("pithos-invitationsSplitPanel");
108
109                 VerticalPanel left = new VerticalPanel();
110                 left.addStyleName("pithos-sendInvitationsPanel");
111                 left.setVisible(inv.getInvitationsLeft() > 0);
112
113                 HorizontalPanel sendLabelPanel = new HorizontalPanel();
114                 HTML sendLabel = new HTML("Send new invitations");
115                 sendLabel.addStyleName("pithos-sendInvitationsTitle");
116                 sendLabelPanel.add(sendLabel);
117                 Image plus = new Image("images/plus.png");
118                 plus.addStyleName("pithos-addInvitationImg");
119                 sendLabelPanel.add(plus);
120                 left.add(sendLabelPanel);
121
122                 messagesPanel = new VerticalPanel();
123                 messagesPanel.setSpacing(5);
124                 left.add(messagesPanel);
125                 
126                 final FlexTable table = new FlexTable();
127                 table.setCellSpacing(0);
128                 if (inv.getInvitationsLeft() > 0) {
129                         table.setHTML(0, 0, "Name <span class='eg'>e.g. John Smith</span>");
130                         table.getFlexCellFormatter().setStyleName(0, 0, "props-labels");
131                         table.setText(0, 1, "Email");
132                         table.getFlexCellFormatter().setStyleName(0, 1, "props-labels");
133                         rows = 1;
134                         addFormLine(table);
135                 }
136                 left.add(table);
137                 plus.addClickHandler(new ClickHandler() {
138                         
139                         @Override
140                         public void onClick(ClickEvent event) {
141                                 if (rows == 0) {
142                                         table.setHTML(0, 0, "Name <span class='eg'>e.g. John Smith</span>");
143                                         table.getFlexCellFormatter().setStyleName(0, 0, "props-labels");
144                                         table.setText(0, 1, "Email");
145                                         table.getFlexCellFormatter().setStyleName(0, 1, "props-labels");
146                                         rows++;
147                                 }
148                                 addFormLine(table);
149                         }
150                 });
151
152                 Button send = new Button("send invitations", new ClickHandler() {
153                         @Override
154                         public void onClick(ClickEvent event) {
155                                 int rowCount = table.getRowCount();
156                                 
157                                 for (int i = 1; i<rowCount; i++) {
158                                         String name = ((TextBox) table.getWidget(i, 0)).getText().trim();
159                                         String email = ((TextBox) table.getWidget(i, 1)).getText().trim();
160                                         sendInvitation(email, name);
161                                 }
162                         }
163                 });
164                 send.addStyleName("pithos-sendInvitationButton");
165                 send.setVisible(inv.getInvitationsLeft() > 0);
166                 left.add(send);
167                 
168                 split.add(left);
169                 split.setCellWidth(left, "50%");
170
171                 VerticalPanel right = new VerticalPanel();
172                 right.addStyleName("pithos-sentInvitationsPanel");
173                 
174                 HTML sentLabel = new HTML("Invitations sent");
175                 sentLabel.addStyleName("pithos-sentInvitationsTitle");
176                 right.add(sentLabel);
177                 
178                 sentInvitationsTable = new FlexTable();
179                 sentInvitationsTable.setCellSpacing(0);
180                 sentInvitationsTable.addStyleName("pithos-sentInvitationsTable");
181                 fillSentInvitationsTable(inv);
182                 right.add(sentInvitationsTable);
183                 
184                 pagerPanel = new HorizontalPanel();
185                 pagerPanel.setSpacing(5);
186                 Button prev = new Button("Prev");
187                 prev.addStyleName("pithos-pagerButton");
188                 prev.addClickHandler(new ClickHandler() {
189                         
190                         @Override
191                         public void onClick(ClickEvent event) {
192                                 if (currentPage > 0) {
193                                         pagerPanel.getWidget(currentPage + 1).removeStyleName("pithos-pagerButtonCurrent");
194                                         currentPage--;
195                                         fillSentInvitationsTable(inv);
196                                         pagerPanel.getWidget(currentPage + 1).addStyleName("pithos-pagerButtonCurrent");
197                                 }
198                         }
199                 });
200                 pagerPanel.add(prev);
201                 Button next = new Button("Next");
202                 next.addStyleName("pithos-pagerButton");
203                 next.addClickHandler(new ClickHandler() {
204                         
205                         @Override
206                         public void onClick(ClickEvent event) {
207                                 int numOfInvs = inv.getSentInvitations().size();
208                                 int numOfPages = numOfInvs / INV_PER_PAGE + (numOfInvs % INV_PER_PAGE == 0 ? 0 : 1);
209                                 if (currentPage < numOfPages - 1) {
210                                         pagerPanel.getWidget(currentPage + 1).removeStyleName("pithos-pagerButtonCurrent");
211                                         currentPage++;
212                                         pagerPanel.getWidget(currentPage + 1).addStyleName("pithos-pagerButtonCurrent");
213                                         fillSentInvitationsTable(inv);
214                                 }
215                         }
216                 });
217                 pagerPanel.add(next);
218                 right.add(pagerPanel);
219                 updatePagerPanel(inv);
220                 
221                 split.add(right);
222                 
223                 inner.add(split);
224                 
225                 outer.add(inner);
226                 outer.add(close);
227                 outer.setCellHorizontalAlignment(inner, HasHorizontalAlignment.ALIGN_CENTER);
228                 setWidget(outer);
229         }
230
231         private void addFormLine(final FlexTable table) {
232                 table.setWidget(rows, 0, new TextBox());
233                 table.getFlexCellFormatter().setStyleName(1, 0, "props-values");
234
235                 table.setWidget(rows, 1, new TextBox());
236                 table.getFlexCellFormatter().setStyleName(1, 1, "props-values");
237                 
238                 Image delete = new Image("images/delete.png");
239                 delete.addStyleName("pithos-invitationDeleteImg");
240                 delete.addClickHandler(new ClickHandler() {
241                         
242                         @Override
243                         public void onClick(ClickEvent event) {
244                                 int rowIndex = table.getCellForEvent(event).getRowIndex();
245                                 table.removeRow(rowIndex);
246                                 if (rowIndex == 1 && table.getRowCount() > 1) {
247                                         table.getCellFormatter().removeStyleName(rowIndex, 0, "pithos-invitationFormRow");
248                                         table.getCellFormatter().removeStyleName(rowIndex, 1, "pithos-invitationFormRow");
249                                         table.getCellFormatter().removeStyleName(rowIndex, 2, "pithos-invitationFormRow");
250                                 }
251                                 rows--;
252                         }
253                 });
254                 table.setWidget(rows, 2, delete);
255
256                 if (rows > 1) {
257                         table.getCellFormatter().addStyleName(rows, 0, "pithos-invitationFormRow");
258                         table.getCellFormatter().addStyleName(rows, 1, "pithos-invitationFormRow");
259                         table.getCellFormatter().addStyleName(rows, 2, "pithos-invitationFormRow");
260                 }
261                 rows++;
262         }
263
264         void sendInvitation(String email, final String realname) {
265                 if (realname == null || realname.length() == 0) {
266                         HTML msg = new HTML("Name cannot be empty");
267                         msg.addStyleName("pithos-invitationResponseError");
268                         messagesPanel.add(msg);
269                 }
270                 else if (email == null || email.length() == 0 || !email.contains("@") || 
271                                 email.substring(email.indexOf("@")).length() < 4 || !email.substring(email.indexOf("@") + 2).contains(".")) {
272                         HTML msg = new HTML("Invalid email");
273                         msg.addStyleName("pithos-invitationResponseError");
274                         messagesPanel.add(msg);
275                 }
276                 else {
277                         PostRequest sendInvitation = new PostRequest("/im/", "", "invite", "uniq=" + email + "&realname=" + realname) {
278                                 
279                                 @Override
280                                 protected void onUnauthorized(Response response) {
281                                         app.sessionExpired();
282                                 }
283                                 
284                                 @Override
285                                 public void onSuccess(Resource result) {
286                                         HTML msg = new HTML("Invitation to <span class='user'>" + realname + "</span> was sent.");
287                                         msg.addStyleName("pithos-invitationResponse");
288                                         messagesPanel.add(msg);
289                                 }
290                                 
291                                 @Override
292                                 public void onError(Throwable t) {
293                                         GWT.log("", t);
294                                 }
295                         };
296                         sendInvitation.setHeader("X-Auth-Token", app.getToken());
297                         Scheduler.get().scheduleDeferred(sendInvitation);
298                 }
299         }
300         
301         void fillSentInvitationsTable(Invitations inv) {
302                 sentInvitationsTable.removeAllRows();
303                 int row = 0;
304                 for (int j=currentPage * INV_PER_PAGE + 0; j<inv.getSentInvitations().size() && j<(currentPage + 1)* INV_PER_PAGE; j++) {
305                         final Invitation i = inv.getSentInvitations().get(j);
306                         sentInvitationsTable.setText(row, 0, i.getRealname());
307                         if (i.isAccepted())
308                                 sentInvitationsTable.setWidget(row, 1, new Image("images/invitation_accepted.png"));
309                         else {
310                                 Image img = new Image("images/resend.png");
311                                 img.addStyleName("pithos-resendInvitation");
312                                 img.addClickHandler(new ClickHandler() {
313                                         
314                                         @Override
315                                         public void onClick(ClickEvent event) {
316                                                 sendInvitation(i.getEmail(), i.getRealname());
317                                         }
318                                 });
319                                 sentInvitationsTable.setWidget(row, 1, img);
320                         }
321                         sentInvitationsTable.getFlexCellFormatter().setRowSpan(row, 1, 2);
322                         sentInvitationsTable.getFlexCellFormatter().setHorizontalAlignment(row, 1, HasHorizontalAlignment.ALIGN_RIGHT);
323                         if (j < inv.getSentInvitations().size() - 1 && j < (currentPage + 1)* INV_PER_PAGE - 1)
324                                 sentInvitationsTable.getFlexCellFormatter().addStyleName(row, 1, "pithos-invitedEmailBorder");
325                         row++;
326                         sentInvitationsTable.setText(row, 0, i.getEmail());
327                         sentInvitationsTable.getFlexCellFormatter().addStyleName(row, 0, "pithos-invitedEmail");
328                         if (j < inv.getSentInvitations().size() - 1 && j < (currentPage + 1)* INV_PER_PAGE - 1)
329                                 sentInvitationsTable.getFlexCellFormatter().addStyleName(row, 0, "pithos-invitedEmailBorder");
330                         row++;
331                 }
332         }
333         
334         void updatePagerPanel(final Invitations inv) {
335                 int numOfInvitations = inv.getSentInvitations().size();
336                 int numOfPages = numOfInvitations / INV_PER_PAGE + (numOfInvitations % INV_PER_PAGE == 0 ? 0 : 1);
337                 for (int i=0; i<numOfPages; i++) {
338                         final Button page = new Button(String.valueOf(i + 1));
339                         page.addStyleName("pithos-pagerButton");
340                         if (i == currentPage)
341                                 page.addStyleName("pithos-pagerButtonCurrent");
342                                 
343                         final int j = i;
344                         page.addClickHandler(new ClickHandler() {
345                                 
346                                 @Override
347                                 public void onClick(ClickEvent event) {
348                                         pagerPanel.getWidget(currentPage + 1).removeStyleName("pithos-pagerButtonCurrent");
349                                         currentPage = j;
350                                         fillSentInvitationsTable(inv);
351                                         page.addStyleName("pithos-pagerButtonCurrent");
352                                 }
353                         });
354                         pagerPanel.insert(page, i + 1);
355                 }
356         }
357 }