1 /* 2 * Copyright 2010 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 package com.google.gwt.sample.showcase.client.content.cell; 17 18 import com.google.gwt.core.client.GWT; 19 import com.google.gwt.i18n.client.Constants; 20 import com.google.gwt.user.client.Random; 21 import com.google.gwt.view.client.HasData; 22 import com.google.gwt.view.client.ListDataProvider; 23 import com.google.gwt.view.client.ProvidesKey; 24 25 import java.util.ArrayList; 26 import java.util.Date; 27 import java.util.HashMap; 28 import java.util.HashSet; 29 import java.util.List; 30 import java.util.Map; 31 import java.util.Set; 32 33 /** 34 * The data source for contact information used in the sample. 35 */ 36 public class ContactDatabase { 37 38 /** 39 * A contact category. 40 */ 41 public static class Category { 42 43 private final String displayName; 44 Category(String displayName)45 private Category(String displayName) { 46 this.displayName = displayName; 47 } 48 getDisplayName()49 public String getDisplayName() { 50 return displayName; 51 } 52 } 53 54 /** 55 * Information about a contact. 56 */ 57 public static class ContactInfo implements Comparable<ContactInfo> { 58 59 /** 60 * The key provider that provides the unique ID of a contact. 61 */ 62 public static final ProvidesKey<ContactInfo> KEY_PROVIDER = new ProvidesKey<ContactInfo>() { 63 @Override 64 public Object getKey(ContactInfo item) { 65 return item == null ? null : item.getId(); 66 } 67 }; 68 69 private static int nextId = 0; 70 71 private String address; 72 private int age; 73 private Date birthday; 74 private Category category; 75 private String firstName; 76 private final int id; 77 private String lastName; 78 ContactInfo(Category category)79 public ContactInfo(Category category) { 80 this.id = nextId; 81 nextId++; 82 setCategory(category); 83 } 84 85 @Override compareTo(ContactInfo o)86 public int compareTo(ContactInfo o) { 87 return (o == null || o.firstName == null) ? -1 : -o.firstName.compareTo(firstName); 88 } 89 90 @Override equals(Object o)91 public boolean equals(Object o) { 92 if (o instanceof ContactInfo) { 93 return id == ((ContactInfo) o).id; 94 } 95 return false; 96 } 97 98 /** 99 * @return the contact's address 100 */ getAddress()101 public String getAddress() { 102 return address; 103 } 104 105 /** 106 * @return the contact's age 107 */ getAge()108 public int getAge() { 109 return age; 110 } 111 112 /** 113 * @return the contact's birthday 114 */ getBirthday()115 public Date getBirthday() { 116 return birthday; 117 } 118 119 /** 120 * @return the category of the conteact 121 */ getCategory()122 public Category getCategory() { 123 return category; 124 } 125 126 /** 127 * @return the contact's firstName 128 */ getFirstName()129 public String getFirstName() { 130 return firstName; 131 } 132 133 /** 134 * @return the contact's full name 135 */ getFullName()136 public final String getFullName() { 137 return firstName + " " + lastName; 138 } 139 140 /** 141 * @return the unique ID of the contact 142 */ getId()143 public int getId() { 144 return this.id; 145 } 146 147 /** 148 * @return the contact's lastName 149 */ getLastName()150 public String getLastName() { 151 return lastName; 152 } 153 154 @Override hashCode()155 public int hashCode() { 156 return id; 157 } 158 159 /** 160 * Set the contact's address. 161 * 162 * @param address the address 163 */ setAddress(String address)164 public void setAddress(String address) { 165 this.address = address; 166 } 167 168 /** 169 * Set the contact's birthday. 170 * 171 * @param birthday the birthday 172 */ 173 @SuppressWarnings("deprecation") setBirthday(Date birthday)174 public void setBirthday(Date birthday) { 175 this.birthday = birthday; 176 177 // Recalculate the age. 178 Date today = new Date(); 179 this.age = today.getYear() - birthday.getYear(); 180 if (today.getMonth() > birthday.getMonth() 181 || (today.getMonth() == birthday.getMonth() && today.getDate() > birthday.getDate())) { 182 this.age--; 183 } 184 } 185 186 /** 187 * Set the contact's category. 188 * 189 * @param category the category to set 190 */ setCategory(Category category)191 public void setCategory(Category category) { 192 assert category != null : "category cannot be null"; 193 this.category = category; 194 } 195 196 /** 197 * Set the contact's first name. 198 * 199 * @param firstName the firstName to set 200 */ setFirstName(String firstName)201 public void setFirstName(String firstName) { 202 this.firstName = firstName; 203 } 204 205 /** 206 * Set the contact's last name. 207 * 208 * @param lastName the lastName to set 209 */ setLastName(String lastName)210 public void setLastName(String lastName) { 211 this.lastName = lastName; 212 } 213 } 214 215 /** 216 * The constants used in this Content Widget. 217 */ 218 static interface DatabaseConstants extends Constants { contactDatabaseCategories()219 String[] contactDatabaseCategories(); 220 } 221 222 private static final String[] FEMALE_FIRST_NAMES = { 223 "Mary", "Patricia", "Linda", "Barbara", "Elizabeth", "Jennifer", "Maria", "Susan", 224 "Margaret", "Dorothy", "Lisa", "Nancy", "Karen", "Betty", "Helen", "Sandra", "Donna", 225 "Carol", "Ruth", "Sharon", "Michelle", "Laura", "Sarah", "Kimberly", "Deborah", "Jessica", 226 "Shirley", "Cynthia", "Angela", "Melissa", "Brenda", "Amy", "Anna", "Rebecca", "Virginia", 227 "Kathleen", "Pamela", "Martha", "Debra", "Amanda", "Stephanie", "Carolyn", "Christine", 228 "Marie", "Janet", "Catherine", "Frances", "Ann", "Joyce", "Diane", "Alice", "Julie", 229 "Heather", "Teresa", "Doris", "Gloria", "Evelyn", "Jean", "Cheryl", "Mildred", "Katherine", 230 "Joan", "Ashley", "Judith", "Rose", "Janice", "Kelly", "Nicole", "Judy", "Christina", 231 "Kathy", "Theresa", "Beverly", "Denise", "Tammy", "Irene", "Jane", "Lori", "Rachel", 232 "Marilyn", "Andrea", "Kathryn", "Louise", "Sara", "Anne", "Jacqueline", "Wanda", "Bonnie", 233 "Julia", "Ruby", "Lois", "Tina", "Phyllis", "Norma", "Paula", "Diana", "Annie", "Lillian", 234 "Emily", "Robin", "Peggy", "Crystal", "Gladys", "Rita", "Dawn", "Connie", "Florence", 235 "Tracy", "Edna", "Tiffany", "Carmen", "Rosa", "Cindy", "Grace", "Wendy", "Victoria", "Edith", 236 "Kim", "Sherry", "Sylvia", "Josephine", "Thelma", "Shannon", "Sheila", "Ethel", "Ellen", 237 "Elaine", "Marjorie", "Carrie", "Charlotte", "Monica", "Esther", "Pauline", "Emma", 238 "Juanita", "Anita", "Rhonda", "Hazel", "Amber", "Eva", "Debbie", "April", "Leslie", "Clara", 239 "Lucille", "Jamie", "Joanne", "Eleanor", "Valerie", "Danielle", "Megan", "Alicia", "Suzanne", 240 "Michele", "Gail", "Bertha", "Darlene", "Veronica", "Jill", "Erin", "Geraldine", "Lauren", 241 "Cathy", "Joann", "Lorraine", "Lynn", "Sally", "Regina", "Erica", "Beatrice", "Dolores", 242 "Bernice", "Audrey", "Yvonne", "Annette", "June", "Samantha", "Marion", "Dana", "Stacy", 243 "Ana", "Renee", "Ida", "Vivian", "Roberta", "Holly", "Brittany", "Melanie", "Loretta", 244 "Yolanda", "Jeanette", "Laurie", "Katie", "Kristen", "Vanessa", "Alma", "Sue", "Elsie", 245 "Beth", "Jeanne"}; 246 private static final String[] MALE_FIRST_NAMES = { 247 "James", "John", "Robert", "Michael", "William", "David", "Richard", "Charles", "Joseph", 248 "Thomas", "Christopher", "Daniel", "Paul", "Mark", "Donald", "George", "Kenneth", "Steven", 249 "Edward", "Brian", "Ronald", "Anthony", "Kevin", "Jason", "Matthew", "Gary", "Timothy", 250 "Jose", "Larry", "Jeffrey", "Frank", "Scott", "Eric", "Stephen", "Andrew", "Raymond", 251 "Gregory", "Joshua", "Jerry", "Dennis", "Walter", "Patrick", "Peter", "Harold", "Douglas", 252 "Henry", "Carl", "Arthur", "Ryan", "Roger", "Joe", "Juan", "Jack", "Albert", "Jonathan", 253 "Justin", "Terry", "Gerald", "Keith", "Samuel", "Willie", "Ralph", "Lawrence", "Nicholas", 254 "Roy", "Benjamin", "Bruce", "Brandon", "Adam", "Harry", "Fred", "Wayne", "Billy", "Steve", 255 "Louis", "Jeremy", "Aaron", "Randy", "Howard", "Eugene", "Carlos", "Russell", "Bobby", 256 "Victor", "Martin", "Ernest", "Phillip", "Todd", "Jesse", "Craig", "Alan", "Shawn", 257 "Clarence", "Sean", "Philip", "Chris", "Johnny", "Earl", "Jimmy", "Antonio", "Danny", 258 "Bryan", "Tony", "Luis", "Mike", "Stanley", "Leonard", "Nathan", "Dale", "Manuel", "Rodney", 259 "Curtis", "Norman", "Allen", "Marvin", "Vincent", "Glenn", "Jeffery", "Travis", "Jeff", 260 "Chad", "Jacob", "Lee", "Melvin", "Alfred", "Kyle", "Francis", "Bradley", "Jesus", "Herbert", 261 "Frederick", "Ray", "Joel", "Edwin", "Don", "Eddie", "Ricky", "Troy", "Randall", "Barry", 262 "Alexander", "Bernard", "Mario", "Leroy", "Francisco", "Marcus", "Micheal", "Theodore", 263 "Clifford", "Miguel", "Oscar", "Jay", "Jim", "Tom", "Calvin", "Alex", "Jon", "Ronnie", 264 "Bill", "Lloyd", "Tommy", "Leon", "Derek", "Warren", "Darrell", "Jerome", "Floyd", "Leo", 265 "Alvin", "Tim", "Wesley", "Gordon", "Dean", "Greg", "Jorge", "Dustin", "Pedro", "Derrick", 266 "Dan", "Lewis", "Zachary", "Corey", "Herman", "Maurice", "Vernon", "Roberto", "Clyde", 267 "Glen", "Hector", "Shane", "Ricardo", "Sam", "Rick", "Lester", "Brent", "Ramon", "Charlie", 268 "Tyler", "Gilbert", "Gene"}; 269 private static final String[] LAST_NAMES = { 270 "Smith", "Johnson", "Williams", "Jones", "Brown", "Davis", "Miller", "Wilson", "Moore", 271 "Taylor", "Anderson", "Thomas", "Jackson", "White", "Harris", "Martin", "Thompson", "Garcia", 272 "Martinez", "Robinson", "Clark", "Rodriguez", "Lewis", "Lee", "Walker", "Hall", "Allen", 273 "Young", "Hernandez", "King", "Wright", "Lopez", "Hill", "Scott", "Green", "Adams", "Baker", 274 "Gonzalez", "Nelson", "Carter", "Mitchell", "Perez", "Roberts", "Turner", "Phillips", 275 "Campbell", "Parker", "Evans", "Edwards", "Collins", "Stewart", "Sanchez", "Morris", 276 "Rogers", "Reed", "Cook", "Morgan", "Bell", "Murphy", "Bailey", "Rivera", "Cooper", 277 "Richardson", "Cox", "Howard", "Ward", "Torres", "Peterson", "Gray", "Ramirez", "James", 278 "Watson", "Brooks", "Kelly", "Sanders", "Price", "Bennett", "Wood", "Barnes", "Ross", 279 "Henderson", "Coleman", "Jenkins", "Perry", "Powell", "Long", "Patterson", "Hughes", 280 "Flores", "Washington", "Butler", "Simmons", "Foster", "Gonzales", "Bryant", "Alexander", 281 "Russell", "Griffin", "Diaz", "Hayes", "Myers", "Ford", "Hamilton", "Graham", "Sullivan", 282 "Wallace", "Woods", "Cole", "West", "Jordan", "Owens", "Reynolds", "Fisher", "Ellis", 283 "Harrison", "Gibson", "Mcdonald", "Cruz", "Marshall", "Ortiz", "Gomez", "Murray", "Freeman", 284 "Wells", "Webb", "Simpson", "Stevens", "Tucker", "Porter", "Hunter", "Hicks", "Crawford", 285 "Henry", "Boyd", "Mason", "Morales", "Kennedy", "Warren", "Dixon", "Ramos", "Reyes", "Burns", 286 "Gordon", "Shaw", "Holmes", "Rice", "Robertson", "Hunt", "Black", "Daniels", "Palmer", 287 "Mills", "Nichols", "Grant", "Knight", "Ferguson", "Rose", "Stone", "Hawkins", "Dunn", 288 "Perkins", "Hudson", "Spencer", "Gardner", "Stephens", "Payne", "Pierce", "Berry", 289 "Matthews", "Arnold", "Wagner", "Willis", "Ray", "Watkins", "Olson", "Carroll", "Duncan", 290 "Snyder", "Hart", "Cunningham", "Bradley", "Lane", "Andrews", "Ruiz", "Harper", "Fox", 291 "Riley", "Armstrong", "Carpenter", "Weaver", "Greene", "Lawrence", "Elliott", "Chavez", 292 "Sims", "Austin", "Peters", "Kelley", "Franklin", "Lawson"}; 293 private static final String[] STREET_NAMES = 294 { 295 "Peachtree", "First", "Second", "Third", "Fourth", "Fifth", "Sixth", "Tenth", 296 "Fourteenth", "Spring", "Techwood", "West Peachtree", "Juniper", "Cypress", "Fowler", 297 "Piedmont", "Juniper", "Main", "Central", "Currier", "Courtland", "Williams", 298 "Centennial", "Olympic", "Baker", "Highland", "Pryor", "Decatur", "Bell", "Edgewood", 299 "Mitchell", "Forsyth", "Capital"}; 300 private static final String[] STREET_SUFFIX = { 301 "St", "Rd", "Ln", "Blvd", "Way", "Pkwy", "Cir", "Ave"}; 302 303 /** 304 * The singleton instance of the database. 305 */ 306 private static ContactDatabase instance; 307 308 /** 309 * Get the singleton instance of the contact database. 310 * 311 * @return the singleton instance 312 */ get()313 public static ContactDatabase get() { 314 if (instance == null) { 315 instance = new ContactDatabase(); 316 } 317 return instance; 318 } 319 320 /** 321 * The provider that holds the list of contacts in the database. 322 */ 323 private ListDataProvider<ContactInfo> dataProvider = new ListDataProvider<ContactInfo>(); 324 325 private final Category[] categories; 326 327 /** 328 * The map of contacts to her friends. 329 */ 330 private final Map<Integer, Set<ContactInfo>> friendsMap = 331 new HashMap<Integer, Set<ContactInfo>>(); 332 333 /** 334 * Construct a new contact database. 335 */ ContactDatabase()336 private ContactDatabase() { 337 // Initialize the categories. 338 DatabaseConstants constants = GWT.create(DatabaseConstants.class); 339 String[] catNames = constants.contactDatabaseCategories(); 340 categories = new Category[catNames.length]; 341 for (int i = 0; i < catNames.length; i++) { 342 categories[i] = new Category(catNames[i]); 343 } 344 345 // Generate initial data. 346 generateContacts(250); 347 } 348 349 /** 350 * Add a new contact. 351 * 352 * @param contact the contact to add. 353 */ addContact(ContactInfo contact)354 public void addContact(ContactInfo contact) { 355 List<ContactInfo> contacts = dataProvider.getList(); 356 // Remove the contact first so we don't add a duplicate. 357 contacts.remove(contact); 358 contacts.add(contact); 359 } 360 361 /** 362 * Add a display to the database. The current range of interest of the display 363 * will be populated with data. 364 * 365 * @param display a {@Link HasData}. 366 */ addDataDisplay(HasData<ContactInfo> display)367 public void addDataDisplay(HasData<ContactInfo> display) { 368 dataProvider.addDataDisplay(display); 369 } 370 371 /** 372 * Generate the specified number of contacts and add them to the data 373 * provider. 374 * 375 * @param count the number of contacts to generate. 376 */ generateContacts(int count)377 public void generateContacts(int count) { 378 List<ContactInfo> contacts = dataProvider.getList(); 379 for (int i = 0; i < count; i++) { 380 contacts.add(createContactInfo()); 381 } 382 } 383 getDataProvider()384 public ListDataProvider<ContactInfo> getDataProvider() { 385 return dataProvider; 386 } 387 388 /** 389 * Get the categories in the database. 390 * 391 * @return the categories in the database 392 */ queryCategories()393 public Category[] queryCategories() { 394 return categories; 395 } 396 397 /** 398 * Query all contacts for the specified category. 399 * 400 * @param category the category 401 * @return the list of contacts in the category 402 */ queryContactsByCategory(Category category)403 public List<ContactInfo> queryContactsByCategory(Category category) { 404 List<ContactInfo> matches = new ArrayList<ContactInfo>(); 405 for (ContactInfo contact : dataProvider.getList()) { 406 if (contact.getCategory() == category) { 407 matches.add(contact); 408 } 409 } 410 return matches; 411 } 412 413 /** 414 * Query all contacts for the specified category that begin with the specified 415 * first name prefix. 416 * 417 * @param category the category 418 * @param firstNamePrefix the prefix of the first name 419 * @return the list of contacts in the category 420 */ queryContactsByCategoryAndFirstName(Category category, String firstNamePrefix)421 public List<ContactInfo> queryContactsByCategoryAndFirstName(Category category, 422 String firstNamePrefix) { 423 List<ContactInfo> matches = new ArrayList<ContactInfo>(); 424 for (ContactInfo contact : dataProvider.getList()) { 425 if (contact.getCategory() == category && contact.getFirstName().startsWith(firstNamePrefix)) { 426 matches.add(contact); 427 } 428 } 429 return matches; 430 } 431 432 /** 433 * Query the list of friends for the specified contact. 434 * 435 * @param contact the contact 436 * @return the friends of the contact 437 */ queryFriends(ContactInfo contact)438 public Set<ContactInfo> queryFriends(ContactInfo contact) { 439 Set<ContactInfo> friends = friendsMap.get(contact.getId()); 440 if (friends == null) { 441 // Assign some random friends. 442 friends = new HashSet<ContactInfo>(); 443 int numContacts = dataProvider.getList().size(); 444 int friendCount = 2 + Random.nextInt(8); 445 for (int i = 0; i < friendCount; i++) { 446 friends.add(dataProvider.getList().get(Random.nextInt(numContacts))); 447 } 448 friendsMap.put(contact.getId(), friends); 449 } 450 return friends; 451 } 452 453 /** 454 * Refresh all displays. 455 */ refreshDisplays()456 public void refreshDisplays() { 457 dataProvider.refresh(); 458 } 459 460 /** 461 * Create a new random {@link ContactInfo}. 462 * 463 * @return the new {@link ContactInfo}. 464 */ 465 @SuppressWarnings("deprecation") createContactInfo()466 private ContactInfo createContactInfo() { 467 ContactInfo contact = new ContactInfo(nextValue(categories)); 468 contact.setLastName(nextValue(LAST_NAMES)); 469 if (Random.nextBoolean()) { 470 // Male. 471 contact.setFirstName(nextValue(MALE_FIRST_NAMES)); 472 } else { 473 // Female. 474 contact.setFirstName(nextValue(FEMALE_FIRST_NAMES)); 475 } 476 477 // Create a birthday between 20-80 years ago. 478 int year = (new Date()).getYear() - 21 - Random.nextInt(61); 479 contact.setBirthday(new Date(year, Random.nextInt(12), 1 + Random.nextInt(31))); 480 481 // Create an address. 482 int addrNum = 1 + Random.nextInt(999); 483 String addrStreet = nextValue(STREET_NAMES); 484 String addrSuffix = nextValue(STREET_SUFFIX); 485 contact.setAddress(addrNum + " " + addrStreet + " " + addrSuffix); 486 return contact; 487 } 488 489 /** 490 * Get the next random value from an array. 491 * 492 * @param array the array 493 * @return a random value in the array 494 */ nextValue(T[] array)495 private <T> T nextValue(T[] array) { 496 return array[Random.nextInt(array.length)]; 497 } 498 499 } 500