Commit c97acc55 authored by Arne Styve's avatar Arne Styve
Browse files

Some major last minute cleanups. Changed from using TreeMap to ArrayList in...

Some major last minute cleanups. Changed from using TreeMap to ArrayList in the AddressBookPlain-class for simplicity. Added support for editing/updating a contact detail, and more...Ready for release of 0.6.
parent c32c3bdf
......@@ -12,6 +12,7 @@ The project was developed for use in teaching in the course "IDATx2001 Programme
**Version** | **Description**
--------|------------
v0.6 | Added an alternative JavaFX-GUI based on FXML to give an example of how the project could be solved using FXML and CSS. To run the FXML-version, run the class **ContactsAppFXML**. This class uses the **ContactsMain.fxml**-file to build the GUI, together with the **ContactsAppFXML.css**-file. The controller used with the FXML-version of the GUI, is the **ContactsAppFXMLController**. <br>NOTE: Using "FXML" as part of the class-names is not a recommended practice, and is only done so in this project to make it clear which of the classes/files are linked to the use of the JavaFx FXML-solution. <br>Also, the existing non FXML-controller class **MainController** has been refactored to take the responsibility for the AddressBook instance (previously managed by the view class **ContactsApp**. <br>And there are also some other minor changes/modifications.
v0.5.1 | Some minor adjustments: removed *synchronized* from the iterator()-method of ContactDetails (not needed). Updated the ContactDetails-constructor to make use of the set-methods of the class.
v0.5 | Added support for MySQL-DB at IDI (https://mysql-ait.stud.idi.ntnu.no/phpmyadmin/) through a separate *persistence unit (PU)* in the persistence.xml-file. NOTE: You must set your own **username**, **password** and **database name**. Also support has been added for a locally installed Apache Derby Server.
v0.4.3 | Added support for MySQL-DB at IDI (https://mysql-ait.stud.idi.ntnu.no/phpmyadmin/) through a separate *persistence unit (PU)* in the persistence.xml-file. NOTE: You must set your own **username**, **password** and **database name**. Also support has been added for a locally installed Apache Derby Server.
......
......@@ -2,7 +2,16 @@ package no.ntnu.idata2001.contacts;
/**
* A simple class to hold the version of the application.
*
* <p>Using the "final" keyword on a class prevents the class to
* be subclassed (inherited from), which makes sence in this case.
* The field is also being set to final to indicate that there are to be
* no changes to the field (i.e. a constant). Setting the field to
* static creates a "class field", i.e. a field that exsists without having to
* create an instance of the class.
* To access the VERSION-constant, use:
* <code>AppVersion.VERSION</code>
*/
public class AppVersion {
public static String VERSION = "0.6";
public final class AppVersion {
public static final String VERSION = "0.6";
}
......@@ -27,6 +27,7 @@ import no.ntnu.idata2001.contacts.AppVersion;
import no.ntnu.idata2001.contacts.model.AddressBook;
import no.ntnu.idata2001.contacts.model.AddressBookDBHandler;
import no.ntnu.idata2001.contacts.model.AddressBookFileHandler;
import no.ntnu.idata2001.contacts.model.AddressBookPlain;
import no.ntnu.idata2001.contacts.model.ContactDetails;
import no.ntnu.idata2001.contacts.views.ContactDetailsDialog;
......@@ -63,13 +64,9 @@ public class ContactsAppFXMLController {
@FXML
private void initialize() {
this.observableContactsList = FXCollections.observableArrayList();
//observableContactsList.add(new ContactDetails("Arne Styve", "Phone", "Address"));
//observableContactsList.add(new ContactDetails("Eskil Styve", "Phone", "Address"));
//observableContactsList.add(new ContactDetails("Siw Styve", "Phone", "Address"));
this.addressBook = new AddressBookDBHandler();
//this.addressBook = new AddressBookPlain();
this.observableContactsList.setAll(this.addressBook.getAllContacts());
this.contactDetailsTableView.setItems(observableContactsList);
}
......@@ -200,12 +197,31 @@ public class ContactsAppFXMLController {
}
/**
* Edit the contact details selected in the table view.
* Edit the selected item.
*
* @param actionEvent the actionevent triggering this call
*/
public void editContact(ActionEvent actionEvent) {
System.out.println("editContact() was called...");
ContactDetails selectedContact = this.contactDetailsTableView
.getSelectionModel()
.getSelectedItem();
if (selectedContact == null) {
showPleaseSelectItemDialog();
} else {
ContactDetailsDialog contactDialog = new ContactDetailsDialog(selectedContact, true);
contactDialog.showAndWait();
// The selectedContact now contains the updates. If the address book is
// stored in memory (implemented using one of the collection classes in the JDK
// or similar), we do not need to tell the address book that this instance
// has been changed. But if a DB is being used, the updated details
// must be stored/updeted in the DB too. Hence lets treat this change
// independent upon the address book being "in memory" or in a DB by
// calling the update()-method of the address book
this.addressBook.updateContact(selectedContact);
this.updateObservableList(this.addressBook);
}
}
......
......@@ -23,6 +23,7 @@ import no.ntnu.idata2001.contacts.AppVersion;
import no.ntnu.idata2001.contacts.model.AddressBook;
import no.ntnu.idata2001.contacts.model.AddressBookDBHandler;
import no.ntnu.idata2001.contacts.model.AddressBookFileHandler;
import no.ntnu.idata2001.contacts.model.AddressBookPlain;
import no.ntnu.idata2001.contacts.model.ContactDetails;
import no.ntnu.idata2001.contacts.views.ContactDetailsDialog;
import no.ntnu.idata2001.contacts.views.ContactsApp;
......@@ -66,6 +67,7 @@ public class MainController {
public void initialize() {
// Use the AddressBookDBHandler as AddressBook implementation
this.addressBook = new AddressBookDBHandler();
//this.addressBook = new AddressBookPlain();
}
/**
......@@ -110,6 +112,15 @@ public class MainController {
ContactDetailsDialog contactDialog = new ContactDetailsDialog(selectedContact, true);
contactDialog.showAndWait();
// The selectedContact now contains the updates. If the address book is
// stored in memory (implemented using one of the collection classes in the JDK
// or similar), we do not need to tell the address book that this instance
// has been changed. But if a DB is being used, the updated details
// must be stored/updeted in the DB too. Hence lets treat this change
// independent upon the address book being "in memory" or in a DB by
// calling the update()-method of the address book
this.addressBook.updateContact(selectedContact);
parent.updateObservableList(this.addressBook);
}
}
......
......@@ -25,6 +25,13 @@ public interface AddressBook extends Serializable, Iterable<ContactDetails> {
*/
void removeContact(String phoneNumber);
/**
* Update the contact info for the given contact.
*
* @param contactDetails the contact details to update.
*/
void updateContact(ContactDetails contactDetails);
/**
* Returns all the contacts as a collection.
*
......
......@@ -65,8 +65,6 @@ public class AddressBookDBHandler implements AddressBook {
+ contact.getPhone());
}
//TODO: Should add an "update contact details" method that updates an exsisting object in the DB.
@Override
public void removeContact(String phoneNumber) {
EntityManager eman = this.efact.createEntityManager();
......@@ -95,6 +93,25 @@ public class AddressBookDBHandler implements AddressBook {
}
@Override
public void updateContact(ContactDetails contactDetails) {
EntityManager eman = this.efact.createEntityManager();
eman.getTransaction().begin();
// First find the contact details matching the unique id of the
// given contact (cannot use the phone number, since that
// might have changed....)
ContactDetails contactToUpdate = eman.find(ContactDetails.class, contactDetails.getId());
if (contactToUpdate != null) {
// Use the updateFrom() method of the ContactDetails-class to
// update the entity in the DB with the data from the parameter contactDetails
contactToUpdate.updateFrom(contactDetails);
eman.getTransaction().commit();
}
eman.close();
}
@Override
public Collection<ContactDetails> getAllContacts() {
EntityManager eman = this.efact.createEntityManager();
......
package no.ntnu.idata2001.contacts.model;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.TreeMap;
......@@ -9,7 +10,10 @@ import java.util.TreeMap;
* Based on the example in the book "Objects first with Java" by David J. Barnes
* and Michael K&ouml;lling.
*
* <p>Each contact is stored in a TreeMap using the phone number as the key.
* <p>Each contact is stored in an ArrayList. We could have used
* a HasMap or a TreeMap using the phone number as the key, but since the phone
* number might change for a given contact, it is not advisable to use the
* phone number as a key, and hence no need to use a Map to store the contact details.
*
* @author David J. Barnes and Michael K&ouml;lling and Arne Styve
* @version 2020.03.16
......@@ -23,13 +27,13 @@ public class AddressBookPlain implements AddressBook {
// TreeMap is a bit less efficient than a HashMap in terms of searching, du to the
// sorted order. For more details on the difference:
// https://javatutorial.net/difference-between-hashmap-and-treemap-in-java
private final TreeMap<String, ContactDetails> book;
private final ArrayList<ContactDetails> book;
/**
* Creates an instance of the AddressBook, initialising the instance.
*/
public AddressBookPlain() {
this.book = new TreeMap<>();
this.book = new ArrayList<>();
}
/**
......@@ -39,18 +43,53 @@ public class AddressBookPlain implements AddressBook {
*/
public void addContact(ContactDetails contact) {
if (contact != null) {
book.put(contact.getPhone(), contact);
book.add(contact);
}
}
/**
* Remove the contact with the given phonenumber from the address book.
* Remove the contact with the given phone number from the address book.
* The phone number should be one that is currently in use.
*
* @param phoneNumber The phone number to the contact to remove
*/
public void removeContact(String phoneNumber) {
this.book.remove(phoneNumber);
// First find the contact details with the given phone number
ContactDetails contactDetails = findContactByPhone(phoneNumber);
if (contactDetails != null) {
this.book.remove(contactDetails);
}
}
/**
* Finds the contact details matching the given phone number.
* If no match is found, <code>null</code> is returned.
* @param phoneNumber the phone number to search for
* @return the contact details matching the phone number provided.
* If no match, <code>null</code> is returned.
*/
private ContactDetails findContactByPhone(String phoneNumber) {
ContactDetails foundContact = null;
for (ContactDetails contactDetails : this.book) {
if (contactDetails.getPhone().equals(phoneNumber)) {
foundContact = contactDetails;
}
}
return foundContact;
}
@Override
public void updateContact(ContactDetails contactDetails) {
// There is really no need to do anything with regards
// to the ArrayList storing the contact details, as
// long as the contactDetaisl-object provided in the
// parameter is still within the ArrayList.
// But to be sure, we will verify that the object IS in the
// ArrayList, and if not, we will add it, just in case.
if (!this.book.contains(contactDetails)) {
this.book.add(contactDetails);
}
}
/**
......@@ -59,7 +98,7 @@ public class AddressBookPlain implements AddressBook {
* @return all the contacts as a collection.
*/
public Collection<ContactDetails> getAllContacts() {
return this.book.values();
return this.book;
}
@Override
......@@ -69,6 +108,6 @@ public class AddressBookPlain implements AddressBook {
@Override
public Iterator<ContactDetails> iterator() {
return this.book.values().iterator();
return this.book.iterator();
}
}
......@@ -50,6 +50,24 @@ public class ContactDetails implements Comparable<ContactDetails>, Serializable
// Intentionally left empty.
}
/**
* Updates the contact details from another instance of contact details.
* @param contactDetails the contact details to use for updating this instance.
*/
public void updateFrom(ContactDetails contactDetails) {
this.setAddress(contactDetails.getAddress());
this.setName(contactDetails.getName());
this.setPhone(contactDetails.getPhone());
}
/**
* Returns the unique ID of the contact details instance.
* @return the unique ID of the contact details instance.
*/
public Integer getId() {
return this.id;
}
/**
* Returns the name.
*
......
......@@ -117,7 +117,7 @@ public class ContactDetailsDialog extends Dialog<ContactDetails> {
TextField phoneNumber = new TextField();
phoneNumber.setPromptText("Phone number");
// Fill inn data from the provided Newspaper, if not null.
// Fill inn data from the provided contact details, if not null.
if ((mode == Mode.EDIT) || (mode == Mode.INFO)) {
name.setText(existingContact.getName());
address.setText(existingContact.getAddress());
......
......@@ -5,7 +5,6 @@ import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import no.ntnu.idata2001.contacts.controllers.ContactsAppFXMLController;
public class ContactsAppFXML extends Application {
......@@ -20,9 +19,7 @@ public class ContactsAppFXML extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
ContactsAppFXMLController contactsAppFXMLController = new ContactsAppFXMLController();
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("ContactsMain.fxml"));
//fxmlLoader.setController(contactsAppFXMLController);
Parent root = fxmlLoader.load();
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment