Compare commits

..

3 Commits

Author SHA1 Message Date
xdrm-brackets 50f1246a99 ? 2017-11-28 08:26:58 +01:00
xdrm-brackets e680376c54 saispastrop 2017-11-21 08:03:58 +01:00
xdrm-brackets 606cfe8aeb Clean @1 2017-11-19 16:30:22 +01:00
49 changed files with 695 additions and 1870 deletions

View File

@ -22,152 +22,270 @@ import javafx.util.Pair;
public class ApiCall implements Runnable, EventObserver { public class ApiCall implements Runnable, EventObserver {
//Methode appelée une fois que la requete s'est terminé /* (1) Attributes
private Callback callback; ---------------------------------------------------------*/
//connection HTTP /* (1) Request data */
private HttpURLConnection connection; private String httpMethod; // HTTP method
//méthode HTTP private HttpURLConnection httpConnection; // HTTP connection
private String method;
//est ce que cet appel d'API attend un évenement pour se lancer /* (2) Callback data */
private Boolean isDelayed = false; private Boolean isDelayed = false; // If must wait for an event to start
//Methode appellée une fois l'évenement arrivé, il retourne la nouvelle URL et les nouveaux parametres POST private Callback callback; // Callback ran when the request ends
private DelayedCallback delayedCallback; private DelayedCallback delayedCallback; // Callback ran when event handled, returns new URL and POST parameters
//ID et Type de l'évenement attendu private String eventID; // awaited event ID
private String eventID; private String eventType; // awaited event Type
private String eventType; private Thread thread; // main Thread
//objet contenant le thread de l'appel private Boolean shouldStop = false; // If delayedCallback error -> run() must stop (notify)
private Thread thread;
//si une erreur surviens durant le delayedCallback, la boucle run doit tout arreter, cette variable sert a notifier run() de ça
private Boolean shouldStop = false;
public ApiCall(String URL, String method, Callback call) {
this.callback = call; /* (2) API call constructor
this.method = method; *
* @tUrl<String> Target URL
* @tMethod<String> HTTP method
* @callback<Callback> Callback run after the HTTP response received
*
---------------------------------------------------------*/
public ApiCall(String tUrl, String tMethod, Callback callback) {
/* (1) Store attributes
---------------------------------------------------------*/
this.callback = callback;
this.httpMethod = tMethod;
/* (2) Create the connection
---------------------------------------------------------*/
try { try {
//création de la connection
URL url = new URL(URL); /* (1) Set the target URL */
this.connection = (HttpURLConnection) url.openConnection(); URL url = new URL(tUrl);
this.connection.setRequestMethod(method);
//si on fait une requete GET, il faut interdire l'envoie de donnée POST /* (2) Create the connection from URL */
if(method == "GET") { this.httpConnection = (HttpURLConnection) url.openConnection();
this.connection.setDoOutput(false);
}else { /* (3) Set the HTTP method */
this.connection.setDoOutput(true); this.httpConnection.setRequestMethod(this.httpMethod);
}
} catch (IOException e) { /* (4) If GET request, forbid POST data to be sent */
this.callback.onError(); this.httpConnection.setDoOutput( httpMethod == "POST" );
}catch( IOException e ){
/* (x) If cannot create connection -> trigger the onError() callback */
this.callback.onError("cannot create http connection");
} }
} }
public void addHeaders(HashMap<String,String> map) {
Iterator it = map.entrySet().iterator(); /* (3) Add headers to the HTTP connection
while (it.hasNext()) { *
Map.Entry pair = (Map.Entry)it.next(); * @headerMap<HashMap<String,String>> HashMap containing the header pairs (key, value)
this.connection.setRequestProperty((String)pair.getKey(), (String)pair.getValue()); *
it.remove(); // évite les erreurs en cas de modification concurente ---------------------------------------------------------*/
public void addHeaders(HashMap<String,String> headerMap){
/* (1) Create iterator */
Iterator it = headerMap.entrySet().iterator();
/* (2) Iterate until the end */
while( it.hasNext() ){
/* (2.1) Get the current header pair */
Map.Entry pair = (Map.Entry) it.next();
/* (2.2) Add the header to the @httpConnection */
this.httpConnection.setRequestProperty(
(String) pair.getKey(),
(String) pair.getValue()
);
/* (2.3) Avoid concurrency errors -> remove current header */
it.remove();
} }
} }
@Override @Override
public void run() { public void run() {
//si notre appel est delayed, on endort le thread
if(this.isDelayed) { /* (1) If delayed call -> sleep the thread, wait for an event
try { ---------------------------------------------------------*/
//on doit se synchroniser avec le thread avant de l'endormir if( this.isDelayed ){
synchronized(this.thread) {
this.thread.wait(); /* (1) Try to sleep the thread */
} try{
} catch (InterruptedException e) {
this.callback.onError(); synchronized(this.thread){ this.thread.wait(); }
/* (2) If cannot -> call callback onError() */
}catch(InterruptedException e){
this.callback.onError("cannot sleep thread");
return; return;
} }
} }
//si il y a eu une erreur durant le delayedallback, on stope le thread
if(this.shouldStop) { /* (2) If thread must stop (error during delayedCallback)
---------------------------------------------------------*/
if( this.shouldStop )
return; return;
}
/* (3) Manage response
---------------------------------------------------------*/
try { try {
//On envoie les paramètres POST si besoin
if(this.method != "GET") { /* (1) Get output stream to set Post data */
DataOutputStream wr = new DataOutputStream (connection.getOutputStream ()); if( this.httpMethod == "POST" ){
//TODO: implémenter la gestion des parametres POST
DataOutputStream wr = new DataOutputStream( httpConnection.getOutputStream() );
// TODO: manage post data
wr.flush (); wr.flush ();
wr.close (); wr.close ();
} }
//on récupère la réponse de la requete /* (2) Prepare to get response */
InputStream is = connection.getInputStream(); InputStream is = httpConnection.getInputStream(); // Get input stream
BufferedReader rd = new BufferedReader(new InputStreamReader(is)); BufferedReader rd = new BufferedReader(new InputStreamReader(is)); // Input stream into readable buffer
String line; String line;
StringBuffer response = new StringBuffer(); StringBuffer response = new StringBuffer();
while((line = rd.readLine()) != null) {
/* (3) Get response */
while( ( line = rd.readLine() ) != null ){
response.append(line); response.append(line);
} }
rd.close(); rd.close();
//transformation en objet JSON /* (4) Parse JSON */
try { try{
//raplce null values by empty strings
JSONObject json = new JSONObject(response.toString().replaceAll(":null,", ":\"\",")); // {4.1} Specific: replace 'null' by empty strings //
this.callback.onSuccess(json); JSONObject parsedJson = new JSONObject(response.toString().replaceAll(":null,", ":\"\","));
}catch(JSONException e) {
this.callback.onError(); // {4.2} If no error -> trigger onSuccess() //
this.callback.onSuccess(parsedJson);
/* (5) If cannot parse JSON -> trigger onError() */
}catch(JSONException jsonex){
this.callback.onError("json parse error");
} }
} catch (IOException e) {
this.callback.onError(); /* (4) If cannot get response -> trigger onError()
---------------------------------------------------------*/
}catch (IOException ioex){
this.callback.onError("cannot get response");
} }
} }
/* (5) Launches the run() loop in a Thread
*
---------------------------------------------------------*/
public void send() { public void send() {
//send sert juste a lancer la boucle principale run()
/* (1) Create a new Thread for the current class */
this.thread = new Thread(this); this.thread = new Thread(this);
/* (2) Start the thread */
this.thread.start(); this.thread.start();
} }
public void setAsDelayedCall(String eventID, String eventType, DelayedCallback call) {
//on enregistre tout ce dont on a besoin pour traiter l'évenement /* (6) Bind a delayed callback to the API call (chain another API call)
this.isDelayed = true; *
this.delayedCallback = call; * @eventID<String> Event ID
this.eventID = eventID; * @eventType<String> Event Type
this.eventType = eventType; * @delayedCallback<DelayedCallback> Delayed callback
*
---------------------------------------------------------*/
public void setAsDelayedCall(String eventID, String eventType, DelayedCallback delayedCallback) {
/* (1) Notify the delayed callback */
this.isDelayed = true;
this.delayedCallback = delayedCallback;
this.eventID = eventID;
this.eventType = eventType;
} }
@Override @Override
public void handleEvent(Event e) { public void handleEvent(Event e) {
//si on est un appel delayed et que l'évenement est le bon, on lance le delayedCallback
if(this.isDelayed && e.getObjectId() == this.eventID && e.getEventType() == this.eventType) { /* (1) If delayed callback and right event received
Pair<String,HashMap<String,String>> returned = this.delayedCallback.call(); ---------------------------------------------------------*/
if(this.method == "GET") { if( this.isDelayed && e.getObjectId() == this.eventID && e.getEventType() == this.eventType ){
try {
//on met a jour la connection HTTP avec la nouvelle URL en gardant l'ancienne méthode HTTP try{
HttpURLConnection newConnection = (HttpURLConnection) new URL(returned.getKey()).openConnection();
newConnection.setRequestMethod(this.connection.getRequestMethod()); /* (1) Call the callback and fetch its retusn URL+POST params */
newConnection.setDoOutput(this.connection.getDoOutput()); Pair<String, HashMap<String, String>> newData = this.delayedCallback.call();
this.connection = newConnection; URL newURL = new URL(newData.getKey());
//on a fini de mettre a jour la connection, le thread principal peut reprendre //HashMap<String, String> newPostData = newData.getValue();
synchronized(this.thread) {
this.thread.notify(); /* (2) Create the new connection */
} HttpURLConnection newConnection = (HttpURLConnection) newURL.openConnection();
} catch (IOException e1) {
//une erreur est survenue, on stope tout /* (3) Keep the same HTTP method as previous request */
this.callback.onError(); String lastHttpMethod = this.httpConnection.getRequestMethod();
this.shouldStop = true; newConnection.setRequestMethod( lastHttpMethod );
synchronized(this.thread) {
this.thread.notify(); /* (4) If GET request, forbid POST data to be sent */
} newConnection.setDoOutput( lastHttpMethod == "POST" );
/* (5) Manage POST data */
if( this.httpMethod == "POST" ){
// TODO: implement POST params management
} }
}else {
//TODO: implémenter les param POST /* (6) Update current connection (replace with new) */
this.httpConnection = newConnection;
/* (7) Replay main thread */
synchronized(this.thread){ this.thread.notify(); }
/* (1.8) If error while creating new connection -> onError()
---------------------------------------------------------*/
}catch( IOException ioe ){
/* (1) Launch onError() callback method */
this.callback.onError("cannot create delayed http connection");
/* (2) Stop the main thread */
this.shouldStop = true;
synchronized(this.thread){ this.thread.notify(); }
} }
}else {
this.callback.onError();
/* (2) If not a delayed call, or not same event (id/type)
---------------------------------------------------------*/
}else{
/* (1) Launch onError() callback method */
this.callback.onError("unknown event");
/* (2) Stop the main thread */
this.shouldStop = true; this.shouldStop = true;
synchronized(this.thread) { synchronized(this.thread){ this.thread.notify(); }
this.thread.notify();
}
} }
} }

View File

@ -1,20 +1,19 @@
package Classes; package Classes;
public enum Category { public enum Category {
// business, entertainment, gaming, general, healthAndMedical, music, politics, scienceAndNature, sport, technology, all
all("all", "black"), all ( "all", "black" ),
business("business", "red"), business ( "business", "red" ),
entertainment("entertainment", "skyblue"), entertainment ( "entertainment", "skyblue" ),
gaming("gaming", "green"), gaming ( "gaming", "green" ),
health("health", "yellow"), health ( "health", "yellow" ),
music("music", "purple"), music ( "music", "purple" ),
sport("sport", "brown"), sport ( "sport", "brown" ),
science("science", "#f14405"), science ( "science", "#f14405" ),
nature("nature", "#16c668"), nature ( "nature", "#16c668" ),
economics("economics", "#d1991b"), economics ( "economics", "#d1991b" ),
politics("politics", "#6825f4"), politics ( "politics", "#6825f4" ),
technology("technology", "#1e7ebe"); technology ( "technology", "#1e7ebe" );
protected String color; protected String color;
protected String label; protected String label;
@ -22,5 +21,4 @@ public enum Category {
public String getLabel(){ return this.label; } public String getLabel(){ return this.label; }
public String getColor(){ return this.color; } public String getColor(){ return this.color; }
} }

View File

@ -2,21 +2,43 @@ package Classes;
public class Event implements Interfaces.Event { public class Event implements Interfaces.Event {
/* (1) Attributes: Event identifiers
---------------------------------------------------------*/
private String objectId; private String objectId;
private String eventType; private String eventType;
/* (2) Constructs an event
*
* @objectId<String> Event ID
* @eventType<String> Type of event (arbitrary)
*
---------------------------------------------------------*/
public Event(String objectId, String eventType) { public Event(String objectId, String eventType) {
this.objectId = objectId; this.objectId = objectId;
this.eventType = eventType; this.eventType = eventType;
} }
public String getObjectId() {
return objectId; /* (3) GET: @objectId
*
---------------------------------------------------------*/
public String getObjectId(){
return this.objectId;
} }
public String getEventType() {
return eventType; /* (4) GET: @eventType
*
---------------------------------------------------------*/
public String getEventType(){
return this.eventType;
} }
} }

View File

@ -1,63 +0,0 @@
package Classes;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.util.Duration;
public final class Toast
{
public static void makeText(Stage ownerStage, String toastMsg, int toastDelay, int fadeInDelay, int fadeOutDelay)
{
Stage toastStage=new Stage();
toastStage.setY(ownerStage.getHeight());
toastStage.initOwner(ownerStage);
toastStage.setResizable(false);
toastStage.initStyle(StageStyle.TRANSPARENT);
Text text = new Text(toastMsg);
text.setFont(Font.font("Verdana", 15));
text.setFill(Color.gray(0.1));
StackPane root = new StackPane(text);
root.setStyle("-fx-background-radius: 5; -fx-background-color: rgba(200, 200, 200, 0.5); -fx-padding: 20px;");
root.setOpacity(0);
Scene scene = new Scene(root);
scene.setFill(Color.TRANSPARENT);
toastStage.setScene(scene);
toastStage.show();
Timeline fadeInTimeline = new Timeline();
KeyFrame fadeInKey1 = new KeyFrame(Duration.millis(fadeInDelay), new KeyValue (toastStage.getScene().getRoot().opacityProperty(), 1));
fadeInTimeline.getKeyFrames().add(fadeInKey1);
fadeInTimeline.setOnFinished((ae) ->
{
new Thread(() -> {
try
{
Thread.sleep(toastDelay);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
Timeline fadeOutTimeline = new Timeline();
KeyFrame fadeOutKey1 = new KeyFrame(Duration.millis(fadeOutDelay), new KeyValue (toastStage.getScene().getRoot().opacityProperty(), 0));
fadeOutTimeline.getKeyFrames().add(fadeOutKey1);
fadeOutTimeline.setOnFinished((aeb) -> toastStage.close());
fadeOutTimeline.play();
}).start();
});
fadeInTimeline.play();
}
}

View File

@ -0,0 +1,85 @@
package Classes.api;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import org.json.JSONArray;
import org.json.JSONObject;
import Classes.Event;
import Interfaces.Callback;
import model.NewsListModel;
import model.NewsModel;
public class fetchArticles implements Callback{
private NewsListModel context;
private String nextQuery;
public fetchArticles(NewsListModel context, String nextQuery){
this.context = context;
this.nextQuery = nextQuery;
}
@Override
public void onSuccess(JSONObject response){
/* (1) Création des NewsModel depuis le json
---------------------------------------------------------*/
/* (1) Init. news list */
ArrayList<NewsModel> newsArr = new ArrayList<NewsModel>();
/* (2) Get article list */
JSONArray article_list = response.getJSONArray("articles");
/* (3) For each article -> create corresponding NewsModel */
for( int i = 0, il = article_list.length() ; i < il ; i++ ){
// {3.1} Get local copy of the JSON //
JSONObject news_i = (JSONObject) article_list.get(i);
// {3.2} Create new NewsModel //
NewsModel news = new NewsModel();
// {3.3} Set attributes //
news.setAuthor( news_i.getString("author") )
.setDescription( news_i.getString("description") )
.setTitle( news_i.getString("title") )
.setNewsURL( news_i.getString("url") )
.setImageURL( news_i.getString("urlToImage") )
.setSource( news_i.getJSONObject("source").getString("name") )
.addTag( this.context.getCategory() );
// {3.4} Add the date (can throw Ex) //
try { news.setDate(news_i.getString("publishedAt")); }
catch( ParseException e ){ news.setDate(new Date()); }
// {3.5} Add to the set //
newsArr.add(news);
}
/* (4) Apply to Context */
this.context.setNews( newsArr );
this.context.setQuery( this.nextQuery );
/* (5) Remove observers */
this.context.removeObserver("newsApiCall");
this.context.notifyObservers(new Event("NewsModel","NewsQuerySuccess"));
}
@Override
public void onError(String errDesc) {
System.out.println("Error: "+errDesc);
this.context.removeObserver("newsApiCall");
this.context.notifyObservers(new Event("NewsModel","NewsQueryFailed"));
}
}

View File

@ -0,0 +1,54 @@
package Classes.api;
import org.json.JSONArray;
import org.json.JSONObject;
import Classes.Event;
import Interfaces.Callback;
import model.NewsListModel;
public class fetchSources implements Callback{
private NewsListModel context;
private String nextQuery;
public fetchSources(NewsListModel context){
this.context = context;
this.nextQuery = nextQuery;
}
@Override
public void onSuccess(JSONObject response){
//on récupère toutes les sources (dans la limite de 20 sources)
JSONArray arr = response.getJSONArray("sources");
for(int i = 0;i<arr.length() && i<20;i++){
String source_i = (JSONObject) arr.get(i);
this.context.sources.add( source_i.getString("id") );
}
this.context.isRetreivingSources = false;
this.context.apiError = false;
//tout s'est bien passé, on peut notifier du succès
this.context.notifyObservers(new Event("NewsModel", "SourcesUpdated"));
}
@Override
public void onError(String errDesc) {
//on notifie de l'échec et on garde en mémoire le fait que l'on a échoué (afin d'annuler la recherche de news qui va suivre)
this.context.isRetreivingSources = false;
this.context.apiError = true;
this.context.notifyObservers(new Event("NewsModel", "SourcesUpdateFailed"));
}
}

View File

@ -27,10 +27,10 @@ public class ArticleStylesheet{
.add("max-width", Context.getInt("article-width")) .add("max-width", Context.getInt("article-width"))
.add("min-height", Context.getInt("article-height")) .add("min-height", Context.getInt("article-height"))
// .add("max-height", Context.getInt("article-height")) .add("max-height", Context.getInt("article-height"))
.add("pref-width", Context.getString("article-width")) .add("pref-width", Context.getString("article-width"))
// .add("pref-height", Context.getString("article-height")) .add("pref-height", Context.getString("article-height"))
// border // border
.add("border-insets", "10") .add("border-insets", "10")
@ -38,6 +38,7 @@ public class ArticleStylesheet{
.add("border-color", "#ddd") .add("border-color", "#ddd")
// bg // bg
.add("background-insets", "10")
.add("background-radius", "3") .add("background-radius", "3")
.add("background-color", "#fff") .add("background-color", "#fff")
.apply(); .apply();

View File

@ -1,41 +0,0 @@
package Classes.css.user;
import Classes.css.core.Context;
import Classes.css.core.Ruleset;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Bounds;
import javafx.scene.Node;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.FlowPane;
public class ContainerScrollStyleSheet{
/* Builds all necessary CSS/layout rules */
public ContainerScrollStyleSheet(Node target) throws Exception{
/* (1) Set rules */
Ruleset.load(target)
.add("top", Context.getInt("header-height") )
.add("left", Context.getInt("submenu-width") + Context.getInt("menu-width") - 3)
.add("right", 0)
// .add("pref-height", )
.apply();
/* (2) Manage dynamic 1st children bounds to it */
ScrollPane spane = (ScrollPane) target;
spane.layoutBoundsProperty().addListener(new ChangeListener(){
@Override
public void changed(ObservableValue observable, Object oldValue, Object newValue) {
FlowPane child = (FlowPane) spane.getContent();
child.setPrefWidth( spane.getLayoutBounds().getWidth() );
child.setPrefHeight( spane.getLayoutBounds().getHeight() );
}
});
}
}

View File

@ -20,7 +20,7 @@ public class ContextBuilder{
/* (3) Colors */ /* (3) Colors */
Context.bind("main-color", 63, 81, 181); Context.bind("main-color", 63, 81, 181);
Context.bind("menu-bg", 255, 255, 253); Context.bind("menu-bg", 255, 255, 253);
Context.bind("submenu-bg", 244, 244, 244); Context.bind("submenu-bg", 255, 0, 0);
} }

View File

@ -18,11 +18,11 @@ public class SubMenuStyleSheet{
.add("min-width", Context.getInt("submenu-width")) .add("min-width", Context.getInt("submenu-width"))
.add("max-width", Context.getInt("submenu-width")) .add("max-width", Context.getInt("submenu-width"))
// .add("min-height", Context.getInt("screen-height") - Context.getInt("header-height")) .add("min-height", Context.getInt("screen-height") - Context.getInt("header-height"))
// .add("max-height", Context.getInt("screen-height") - Context.getInt("header-height")) .add("max-height", Context.getInt("screen-height") - Context.getInt("header-height"))
.add("pref-width", Context.getInt("submenu-width")) .add("pref-width", Context.getInt("submenu-width"))
// .add("pref-height", Context.getInt("screen-height") - Context.getInt("header-height")) .add("pref-height", Context.getInt("screen-height") - Context.getInt("header-height"))
.add("background-color", Context.getString("submenu-bg")) .add("background-color", Context.getString("submenu-bg"))
.apply(); .apply();

View File

@ -4,8 +4,17 @@ import org.json.JSONObject;
public interface Callback { public interface Callback {
/* (1) Called when success state reached
*
* @response<JSONObject> The fetched response
*
---------------------------------------------------------*/
public void onSuccess(JSONObject response); public void onSuccess(JSONObject response);
public void onError();
/* (2) Called when success state cannot be reached
*
---------------------------------------------------------*/
public void onError(String errDesc);
} }

View File

@ -4,6 +4,8 @@ import java.util.HashMap;
import javafx.util.Pair; import javafx.util.Pair;
public interface DelayedCallback { public interface DelayedCallback {
public Pair<String,HashMap<String,String>> call(); public Pair<String,HashMap<String,String>> call();

View File

@ -3,15 +3,12 @@
*/ */
package Interfaces; package Interfaces;
import Classes.Event;
/** /**
* @author lucas * @author lucas
* *
*/ */
public interface Observable { public interface Observable {
public void notifyObservers(Event e);
public void addObserver(String key , EventObserver o); public void addObserver(String key , EventObserver o);
public void removeObserver(String key); public void removeObserver(String key);

View File

@ -1,29 +1,19 @@
package controller; package controller;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.io.IOException; import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.Iterator;
import Classes.Category; import Classes.Category;
import Classes.Toast;
import Interfaces.EventObserver; import Interfaces.EventObserver;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.control.TextField;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.FlowPane; import javafx.scene.layout.FlowPane;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
import javafx.scene.text.Text; import javafx.scene.text.Text;
import javafx.stage.Stage;
import model.NewsModel; import model.NewsModel;
public class Article{ public class Article{
@ -32,103 +22,69 @@ public class Article{
private ArrayList<AnchorPane> items; private ArrayList<AnchorPane> items;
private FlowPane parent; private FlowPane parent;
private EventObserver observer; private EventObserver observer;
private AnchorPane root;
public Boolean activated = false;
private Stage stage;
/* Constructor */ /* Constructor */
public Article(FlowPane p_parent, EventObserver observer, AnchorPane root_layout, Stage stage){ public Article(FlowPane p_parent, EventObserver observer){
this.parent = p_parent;
this.items = new ArrayList<AnchorPane>(); /* (1) Attributes
---------------------------------------------------------*/
this.parent = p_parent;
this.items = new ArrayList<AnchorPane>();
this.observer = observer; this.observer = observer;
this.root = root_layout;
this.stage = stage;
} }
public synchronized void addAllItem(ArrayList<NewsModel> models) throws IOException { public synchronized void addItem(NewsModel model) throws IOException {
/* (9) Add to the controller local */
TextField tx = (TextField) this.root.lookup("#mag_searchbar");
int i = 0; /* (1) Get the loaded item*/
for(NewsModel news : models) { FXMLLoader loader = new FXMLLoader( getClass().getResource("/fxml/article_disp.fxml") );
tx.textProperty().set("Chargement... "+i+"/"+models.size());
this.items.add(this.buildItem(news));
i++;
}
/* (11) Add to parent (graphics) */
Platform.runLater(new Runnable(){
public void run(){
if(Article.this.activated) {
Article.this.parent.getChildren().addAll(Article.this.items);
tx.textProperty().set("");
}
}
});
}
public AnchorPane buildItem(NewsModel model) throws IOException {
/* (1) Load the article_disp.fxml */
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/fxml/article_disp.fxml"));
/* (2) Get the loaded item*/
AnchorPane item = (AnchorPane) loader.load(); AnchorPane item = (AnchorPane) loader.load();
/* (3) Set content */ /* (2) Set content */
this.gsetContent( model.getDescription(), item ); this.gsetContent( model.getDescription(), item );
/* (4) Set date */ /* (3) Set date */
this.gsetDate( model.getDate(), item ); this.gsetDate( model.getDate(), item );
/* (5) Set title */ /* (4) Set title */
HBox headerContainer = (HBox) item.getChildren().get(3); HBox headerContainer = (HBox) item.getChildren().get(3);
this.gsetTitle( model.getTitle(), headerContainer ); this.gsetTitle( model.getTitle(), headerContainer );
/* (6) Set tags */ /* (5) Set tags */
this.gsetTags( model.getTags(), headerContainer ); this.gsetTags( model.getTags(), headerContainer );
/* (7) Set image */ /* (6) Set image */
this.gsetImage( model.getImageURL(), item ); this.gsetImage( model.getImageURL(), item );
/* (8) Bind event */ /* (7) Bind event */
item.setOnMouseClicked(new EventHandler<MouseEvent>() { // item.setOnMousePressed(new EventHandler<MouseEvent>() {
@Override // @Override
public void handle(MouseEvent event) { // public void handle(MouseEvent event) {
StringSelection selection = new StringSelection(model.getNewsURL()); // Article.this.observer.handleEvent(new Classes.Event(item.getId(),"changeMainLayout"));
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); // }
clipboard.setContents(selection, selection); // });
Toast.makeText(Article.this.stage, "Adresse de l'article copié", 2000, 200, 200); /* (8) Add to the controller local */
this.items.add(item);
} /* (9) On bind au width du parent */
});
/* (10) On bind au width du parent */
item.prefWidthProperty().bind(this.parent.widthProperty()); item.prefWidthProperty().bind(this.parent.widthProperty());
item.maxWidthProperty().bind(this.parent.widthProperty()); item.maxWidthProperty().bind(this.parent.widthProperty());
return item;
} }
public synchronized void clearContent() { public void display(){
this.items.clear();
Platform.runLater(new Runnable(){ Platform.runLater(new Runnable(){
public void run(){ public void run(){
Iterator<Node> it = Article.this.parent.getChildren().iterator();
while(it.hasNext()) { for( AnchorPane item : items )
Node n = it.next(); Article.this.parent.getChildren().add(item);
if(n.getId() != "mag_searchbar") {
it.remove();
}
}
} }
}); });
} }
@ -147,7 +103,7 @@ public class Article{
Text g_date = (Text) p_parent.getChildren().get(2); Text g_date = (Text) p_parent.getChildren().get(2);
/* (2) Update content */ /* (2) Update content */
g_date.setText(new SimpleDateFormat("dd-MM-yyyy HH:mm").format(p_date)); g_date.setText(p_date.toString());
} }
@ -166,10 +122,10 @@ public class Article{
ImageView g_image = (ImageView) p_parent.getChildren().get(0); ImageView g_image = (ImageView) p_parent.getChildren().get(0);
/* (2) Update title */ /* (2) Update title */
try { try{
g_image.setImage(new Image(p_uri)); g_image.setImage(new Image(p_uri));
}catch(Exception e) { }catch(IllegalArgumentException wrongurlex){
g_image.setImage(new Image("http://lorempicsum.com/futurama/255/200/2")); System.out.println("Cannot find image URL: '"+p_uri+"'");
} }
} }
@ -179,21 +135,18 @@ public class Article{
/* (1) For each tag -> load a new one */ /* (1) For each tag -> load a new one */
for( Category tag : p_tags ){ for( Category tag : p_tags ){
/* (1.1) Create the container */ /* (1.1) Load the tag elements */
FXMLLoader loader = new FXMLLoader(); FXMLLoader loader = new FXMLLoader( getClass().getResource("/fxml/article_tag_disp.fxml") );
loader.setLocation(getClass().getResource("/fxml/article_tag_disp.fxml"));
/* (1.2) Load the tag elements */
FlowPane g_tag = (FlowPane) loader.load(); FlowPane g_tag = (FlowPane) loader.load();
Text g_tagText = (Text) g_tag.getChildren().get(0); Text g_tagText = (Text) g_tag.getChildren().get(0);
/* (1.3) Update the tag name */ /* (1.2) Update the tag name */
g_tagText.setText(tag.getLabel()); g_tagText.setText(tag.getLabel());
/* (1.4) Set the custom color */ /* (1.3) Set the custom color */
g_tag.setStyle("-fx-background-color: "+tag.getColor()); g_tag.setStyle("-fx-background-color: "+tag.getColor());
/* (1.5) Ajout au parent*/ /* (1.4) Ajout au parent*/
p_parent.getChildren().add(g_tag); p_parent.getChildren().add(g_tag);
} }

View File

@ -11,37 +11,64 @@ import javafx.scene.layout.FlowPane;
public class HeaderMenu{ public class HeaderMenu{
/* Data */ /* (1) Attributes
---------------------------------------------------------*/
private ArrayList<ImageView> items; private ArrayList<ImageView> items;
private FlowPane parent; private FlowPane parent;
private EventObserver observer; private EventObserver observer;
/* Constructor */ /* Constructor */
/* (2) Constructor
*
* @p_parent<FlowPane> gParent element
* @observer<EventObserver> Main observer (to send event to)
*
---------------------------------------------------------*/
public HeaderMenu(FlowPane p_parent, EventObserver observer){ public HeaderMenu(FlowPane p_parent, EventObserver observer){
this.parent = p_parent;
this.items = new ArrayList<ImageView>(); this.parent = p_parent;
this.items = new ArrayList<ImageView>();
this.observer = observer; this.observer = observer;
} }
/* (3) Add a new menu item (graphically too)
*
* @p_name<String> The new menu item's name
* @p_image_uri<String> The new menu item's image link
*
---------------------------------------------------------*/
public void addItem(String p_name, String p_image_uri) { public void addItem(String p_name, String p_image_uri) {
/* (1) Create ImageView */
ImageView menuItem = new ImageView(); ImageView menuItem = new ImageView();
menuItem.setImage(new Image(p_image_uri)); /* (2) Set useful attributes */
menuItem.setId("header_menu_item_"+p_name); menuItem.setImage(new Image(p_image_uri)); // image link
menuItem.getStyleClass().add("header_menu_item"); menuItem.setId("header_menu_item_"+p_name); // id
menuItem.getStyleClass().add("header_menu_item"); // css .class
/* (3) Bind event -> 'changeMainLayout' */
menuItem.setOnMousePressed(new EventHandler<MouseEvent>() { menuItem.setOnMousePressed(new EventHandler<MouseEvent>() {
@Override @Override
public void handle(MouseEvent event) { public void handle(MouseEvent event) {
HeaderMenu.this.observer.handleEvent(new Classes.Event(menuItem.getId(), "changeMainLayout")); HeaderMenu.this.observer.handleEvent(new Classes.Event(menuItem.getId(), "changeMainLayout"));
} }
}); });
/* (4) Add item to list */
this.items.add(menuItem); this.items.add(menuItem);
// Add to parent
/* (5) Add gitem to gparent */
parent.getChildren().add(menuItem); parent.getChildren().add(menuItem);
} }
} }

View File

@ -1,47 +0,0 @@
package controller;
import java.util.ArrayList;
import Interfaces.EventObserver;
import javafx.event.EventHandler;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.FlowPane;
public class MainMenu{
/* Data */
private ArrayList<ImageView> items;
private FlowPane parent;
private EventObserver observer;
/* Constructor */
public MainMenu(FlowPane p_parent, EventObserver observer){
this.parent = p_parent;
this.items = new ArrayList<ImageView>();
this.observer = observer;
}
public void addItem(String p_name, String p_image_uri) {
ImageView menuItem = new ImageView();
menuItem.setImage(new Image(p_image_uri));
menuItem.setId("header_menu_item_"+p_name);
menuItem.getStyleClass().add("header_menu_item");
menuItem.setOnMousePressed(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
MainMenu.this.observer.handleEvent(new Classes.Event(menuItem.getId(), "changeMainLayout"));
}
});
this.items.add(menuItem);
// Add to parent
parent.getChildren().add(menuItem);
}
}

View File

@ -1,10 +1,10 @@
package controller; package controller;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import Classes.Category; import Classes.Category;
import Classes.SortTypes; import Classes.SortTypes;
import Classes.css.user.ContainerScrollStyleSheet;
import Classes.css.user.ContextBuilder; import Classes.css.user.ContextBuilder;
import Classes.css.user.HeaderIconStyleSheet; import Classes.css.user.HeaderIconStyleSheet;
import Classes.css.user.HeaderStyleSheet; import Classes.css.user.HeaderStyleSheet;
@ -13,45 +13,46 @@ import Classes.css.user.SubMenuStyleSheet;
import Interfaces.Event; import Interfaces.Event;
import Interfaces.EventObserver; import Interfaces.EventObserver;
import javafx.application.Application; import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Scene; import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.FlowPane; import javafx.scene.layout.FlowPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage; import javafx.stage.Stage;
import javafx.util.Pair;
import model.TraductionModel;
import model.NewsListModel; import model.NewsListModel;
import model.NewsModel; import model.NewsModel;
import model.WordTraductionModel;
public class RootLayout extends Application implements EventObserver { public class RootLayout extends Application implements EventObserver {
public static void main(String[] args){ launch(args); }
/* (1) Attributes
---------------------------------------------------------*/
/* (1) Root elements */
private Stage root_stage; private Stage root_stage;
private Scene root_scene; private Scene root_scene;
private AnchorPane root_layout; private AnchorPane root_layout;
/* (2) Local elements */
private FlowPane main_container; private FlowPane main_container;
private VBox main_menu;
private Article articles; private Article articles;
private Traduction dico;
/* (2) Builds the stage, scene, ...
*
* @primary_stage<Stage> The primary stage to create in
*
---------------------------------------------------------*/
@Override @Override
public void start(Stage primary_stage) throws Exception { public void start(Stage primary_stage) throws Exception {
/* (1) Init. stage, scene and context
---------------------------------------------------------*/
/* (1) store primary stage + title it */ /* (1) store primary stage + title it */
this.root_stage = primary_stage; this.root_stage = primary_stage;
this.root_stage.setTitle("Language learner pro plus 2000"); this.root_stage.setTitle("Inifiny Mail Client");
setUserAgentStylesheet(STYLESHEET_CASPIAN);
/* (2) Load the root layout*/ /* (2) Load the root layout*/
this.loadRootLayout(); this.loadRootLayout();
@ -63,26 +64,8 @@ public class RootLayout extends Application implements EventObserver {
this.main_container = (FlowPane) this.root_scene.lookup("#container"); this.main_container = (FlowPane) this.root_scene.lookup("#container");
/* (2) Manage static stylesheet
/* (1) Create controllers' views ---------------------------------------------------------*/
-------------------------------------*/
/* (1) Create header menu */
HeaderMenu hm = new HeaderMenu((FlowPane) this.root_scene.lookup("#header_menu"),this);
hm.addItem("notification", "/src/header-notif.png");
hm.addItem("mail", "/src/header-mail.png");
hm.addItem("search", "/src/header-search.png");
hm.addItem("menu", "/src/header-menu.png");
/* (2) Create container */
this.articles = new Article(this.main_container, this, this.root_layout,this.root_stage);
this.dico = new Traduction(this.main_container, this, this.root_layout);
/* (2) CSS
-------------------------------------*/
/* (1) #header */ /* (1) #header */
new HeaderStyleSheet( this.root_scene.lookup("#header") ); new HeaderStyleSheet( this.root_scene.lookup("#header") );
@ -95,48 +78,31 @@ public class RootLayout extends Application implements EventObserver {
/* (4) #header_icon*/ /* (4) #header_icon*/
new HeaderIconStyleSheet( this.root_scene.lookup("#header_icon") ); new HeaderIconStyleSheet( this.root_scene.lookup("#header_icon") );
/* (4) #scroll_container*/
new ContainerScrollStyleSheet( this.root_scene.lookup("#scroll_container") );
VBox subMenuContainer = (VBox) this.root_layout.lookup("#submenu");
for(Node n : subMenuContainer.getChildren()) {
FlowPane p = (FlowPane) n;
if(p.getChildren().get(0).getId().toLowerCase().equals("all") ) {
p.getStyleClass().add("active");
}
p.setOnMousePressed(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
// De-active all items before activating current one
for( Node n2 : subMenuContainer.getChildren() )
n2.getStyleClass().clear();
// Change category
NewsListModel.getInstance().setCategory(Category.valueOf(p.getChildren().get(0).getId().toLowerCase()));
// Active gui category
p.getStyleClass().add("active");
// Re-launch request
NewsListModel.getInstance().query(NewsListModel.getInstance().getQuery());
}
});
}
this.handleMainLayoutChange("magazines"); /* (3) Manage controllers
---------------------------------------------------------*/
/* (1) Create HeaderMenu */
HeaderMenu hm = new HeaderMenu((FlowPane) this.root_scene.lookup("#header_menu"),this);
hm.addItem("notification", "/src/header-notif.png");
hm.addItem("mail", "/src/header-mail.png");
hm.addItem("search", "/src/header-search.png");
hm.addItem("menu", "/src/header-menu.png");
/* (2) Init. articles controller */
this.articles = new Article(this.main_container, this);
NewsListModel.getInstance().addObserver("MainClass", this);
NewsListModel.getInstance().setCategory(Category.all);
NewsListModel.getInstance().setSortType(SortTypes.relevancy);
TraductionModel.getInstance().addObserver("MainClass", this);
} }
/* (3) Loads the root layout and init. the scene-stage-pane
*
*
---------------------------------------------------------*/
public void loadRootLayout(){ public void loadRootLayout(){
try{ try{
@ -153,17 +119,6 @@ public class RootLayout extends Application implements EventObserver {
/* (3) Add the scene to the stage */ /* (3) Add the scene to the stage */
this.root_stage.setScene(this.root_scene); this.root_stage.setScene(this.root_scene);
//bind events on click fot the menu
this.main_menu = (VBox) this.root_layout.lookup("#menu");
for (Node c : this.main_menu.getChildren()) {
c.setOnMousePressed(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
RootLayout.this.handleEvent(new Classes.Event(c.getId(), "changeMainLayout"));
}
});
}
/* (4) Show the stage */ /* (4) Show the stage */
this.root_stage.show(); this.root_stage.show();
@ -174,177 +129,73 @@ public class RootLayout extends Application implements EventObserver {
} }
public static void main(String[] args) {
launch(args);
}
/* (4) Event dispatcher
*
* @e<Event> observed event received
*
---------------------------------------------------------*/
@Override @Override
public void handleEvent(Event e) { public void handleEvent(Event e) {
/*
HashMap<String,String> headers = new HashMap<String,String>();
headers.put("Referer", "http://www.wordreference.com");
switch(e.getEventType()){ ApiCall call = new ApiCall("http://api.wordreference.com/1/json/enfr/grin","GET",new Callback() {
@Override
public void onSuccess(JSONObject response) {
System.out.println(response.toString());
}
@Override
public void onError() {
System.out.println("APICall error");
}
});
call.addHeaders(headers);
call.send();*/
switch( e.getEventType() ){
/* (1) On HeaderMenu.item.click -> search sources */
case "changeMainLayout": case "changeMainLayout":
this.handleMainLayoutChange(e.getObjectId()); this.handleMainLayoutChange(e.getObjectId());
break; break;
/* (2) articles.query.success -> display articles */
case "NewsQuerySuccess": case "NewsQuerySuccess":
System.out.println(NewsListModel.getInstance().getNews().size()+" News ont été trouvé");
this.articles.clearContent(); for( NewsModel news : NewsListModel.getInstance().getNews() ){
TextField tx = (TextField) this.root_layout.lookup("#mag_searchbar");
tx.setDisable(true);
if(NewsListModel.getInstance().getNews().size() != 0) {
try{ try{
this.articles.addItem( news );
this.articles.addAllItem( NewsListModel.getInstance().getNews() );
}catch(Exception e1){ }catch(Exception e1){
System.out.println("Cannot fetch article data"); System.out.println("Cannot fetch article data");
e1.printStackTrace(); e1.printStackTrace();
} }
tx.setDisable(false);
} }
this.articles.display();
tx.setDisable(false);
break; break;
/* (3) articles.query.error -> display error ('no result') */
case "NewsQueryFailed": case "NewsQueryFailed":
System.out.println("une erreur est survenue"); System.out.println("une erreur est survenue");
break; break;
case "WordQueryFailed":
System.out.println("une erreur est survenue");
break;
case "WordQuerySuccess":
System.out.println(TraductionModel.getInstance().getTranslations().size()+" Traductions ont été trouvés");
System.out.println(TraductionModel.getInstance().getUsages().size()+" Exemples ont été trouvés");
this.dico.clearContent();
TextField tx1 = (TextField) this.root_layout.lookup("#mag_searchbar");
tx1.setDisable(true);
if(TraductionModel.getInstance().getTranslations().size() != 0) {
try{
this.dico.addAll( TraductionModel.getInstance().getTranslations() );
}catch(Exception e1){
System.out.println("Cannot fetch dico data");
e1.printStackTrace();
}
}
tx1.setDisable(false);
break;
case "changeMagCategory":
NewsListModel.getInstance().setCategory(Category.valueOf(e.getObjectId().toLowerCase()));
break;
} }
} }
public void handleMainLayoutChange(String layout) { public void handleMainLayoutChange(String layout) {
this.main_container.getChildren().clear();
FXMLLoader loader;
/* Un-select all menu items but re-select the chosen one */ NewsListModel.getInstance().addObserver("MainClass", this);
for( Node n : this.main_menu.getChildren() ){ NewsListModel.getInstance().setCategory(Category.science);
n.getStyleClass().clear(); NewsListModel.getInstance().setSortType(SortTypes.publishedAt);
n.getStyleClass().add("menu_item"); NewsListModel.getInstance().query("bitcoin");
if( n.getId() == layout )
n.getStyleClass().add("active");
}
switch(layout) {
case "dictionary" :
/* (1) Load the root_disp.fxml */
loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/fxml/vocabulary_disp.fxml"));
/* (2) Load the layout into the scene */
try {
this.main_container.getChildren().add((AnchorPane) loader.load());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
case "exercises" :
/* (1) Load the root_disp.fxml */
loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/fxml/exercise_disp.fxml"));
/* (2) Load the layout into the scene */
try {
this.main_container.getChildren().add((AnchorPane) loader.load());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
case "translator" :
this.root_layout.lookup("#submenu").setVisible(false);
this.articles.activated = false;
this.dico.activated = true;
TextField tx1 = new TextField();
tx1.setPromptText("search...");
tx1.setId("mag_searchbar");
tx1.setOnKeyPressed(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent arg0) {
if(arg0.getCode() == KeyCode.ENTER) {
TraductionModel.getInstance().query(tx1.textProperty().get());
}
}
});
RootLayout.this.main_container.getChildren().add(tx1);
break;
case "magazines" :
this.root_layout.lookup("#submenu").setVisible(true);
this.articles.activated = true;
this.dico.activated = false;
TextField tx = new TextField();
tx.setPromptText("search...");
tx.setId("mag_searchbar");
tx.setOnKeyPressed(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent arg0) {
if(arg0.getCode() == KeyCode.ENTER) {
NewsListModel.getInstance().query(tx.textProperty().get());
}
}
});
this.main_container.getChildren().add(tx);
break;
}
} }
} }

View File

@ -1,184 +0,0 @@
package controller;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import Classes.Category;
import Interfaces.EventObserver;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.HBox;
import javafx.scene.text.Text;
import javafx.util.Pair;
import model.NewsModel;
import model.WordTraductionModel;
public class Traduction{
/* Data */
private ArrayList<AnchorPane> items;
private FlowPane parent;
private EventObserver observer;
private AnchorPane root;
public Boolean activated = false;
/* Constructor */
public Traduction(FlowPane p_parent, EventObserver observer, AnchorPane root_layout){
this.parent = p_parent;
this.items = new ArrayList<AnchorPane>();
this.observer = observer;
this.root = root_layout;
}
public synchronized void addAll(ArrayList<Pair<WordTraductionModel, WordTraductionModel>> models) throws IOException {
/* (9) Add to the controller local */
TextField tx = (TextField) this.root.lookup("#mag_searchbar");
int i = 0;
for(Pair<WordTraductionModel, WordTraductionModel> news : models) {
tx.textProperty().set("Chargement... "+i+"/"+models.size());
this.items.add(this.buildItem(news.getKey()));
i++;
}
/* (11) Add to parent (graphics) */
Platform.runLater(new Runnable(){
public void run(){
if(Traduction.this.activated) {
Traduction.this.parent.getChildren().addAll(Traduction.this.items);
tx.textProperty().set("");
}
}
});
}
public AnchorPane buildItem(WordTraductionModel model) throws IOException {
/* (1) Load the article_disp.fxml */
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/fxml/article_disp.fxml"));
/* (2) Get the loaded item*/
AnchorPane item = (AnchorPane) loader.load();
/* (3) Set content */
this.gsetContent( model.getSense(), item );
/* (4) Set date */
//this.gsetDate( model.getDate(), item );
/* (5) Set title */
HBox headerContainer = (HBox) item.getChildren().get(3);
this.gsetTitle( model.getUsage(), headerContainer );
/* (6) Set tags */
this.gsetTags( model.getPOS(), headerContainer );
/* (7) Set image */
//this.gsetImage( model.getImageURL(), item );
/* (8) Bind event */
// item.setOnMousePressed(new EventHandler<MouseEvent>() {
// @Override
// public void handle(MouseEvent event) {
// Article.this.observer.handleEvent(new Classes.Event(item.getId(),"changeMainLayout"));
// }
// });
/* (10) On bind au width du parent */
item.prefWidthProperty().bind(this.parent.widthProperty());
item.maxWidthProperty().bind(this.parent.widthProperty());
return item;
}
public void clearContent() {
this.items.clear();
Platform.runLater(new Runnable(){
public void run(){
Iterator<Node> it = Traduction.this.parent.getChildren().iterator();
while(it.hasNext()) {
Node n = it.next();
if(n.getId() != "mag_searchbar") {
it.remove();
}
}
}
});
}
public void gsetContent(String p_content, AnchorPane p_parent){
/* (1) Get node */
Text g_content = (Text) p_parent.getChildren().get(1);
/* (2) Update content */
g_content.setText(p_content);
}
public void gsetDate(Date p_date, AnchorPane p_parent){
/* (1) Get node */
Text g_date = (Text) p_parent.getChildren().get(2);
/* (2) Update content */
g_date.setText(new SimpleDateFormat("dd-MM-yyyy HH:mm").format(p_date));
}
public void gsetTitle(String p_title, HBox p_parent){
/* (1) Get node */
Text g_title = (Text) p_parent.getChildren().get(0);
/* (2) Update title */
g_title.setText(p_title);
}
public void gsetImage(String p_uri, AnchorPane p_parent){
/* (1) Get node */
ImageView g_image = (ImageView) p_parent.getChildren().get(0);
/* (2) Update title */
try {
g_image.setImage(new Image(p_uri));
}catch(Exception e) {
g_image.setImage(new Image("http://lorempicsum.com/futurama/255/200/2"));
}
}
public void gsetTags(String p_tags, HBox p_parent) throws IOException{
/* (1.1) Create the container */
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/fxml/article_tag_disp.fxml"));
/* (1.2) Load the tag elements */
FlowPane g_tag = (FlowPane) loader.load();
Text g_tagText = (Text) g_tag.getChildren().get(0);
/* (1.3) Update the tag name */
g_tagText.setText(p_tags);
/* (1.5) Ajout au parent*/
p_parent.getChildren().add(g_tag);
}
}

View File

@ -1,26 +0,0 @@
@import "./constants.css";
#mag_searchbar{
-fx-border-radius: 0 0 1 0;
-fx-background-color: #ffffff;
-fx-border-color: #eeeeee;
-fx-background-radius: 0;
-fx-border-radius: 0;
-fx-pref-height: 26;
-fx-pref-width: 759;
-fx-margin: 20 0 20 0;
}
#vocab > * > *{
-fx-background-color: #ffffff;
-fx-border-width: 0 0 1 0;
-fx-border-color: #dddddd;
}
#vocab{
-fx-cursor: normal;
}

View File

@ -27,22 +27,6 @@
-fx-min-height: -vn-header-height; -fx-min-height: -vn-header-height;
-fx-max-height: -vn-header-height; -fx-max-height: -vn-header-height;
-fx-background-color: #ffffff; -fx-background-color: #fffffd;
} }
.menu_item{
-fx-border-width: 0 0 1 0;
-fx-border-color: #eeeeee;
}
.menu_item.active{
-fx-background-color: #eeeeee;
}
#menu{
-fx-background-color: #ffffff;
-fx-border-width: 0 1 0 0;
-fx-border-color: #eeeeee;
}

View File

@ -1,11 +0,0 @@
@import "./constants.css";
#submenu{
-fx-background-color: #ff0000;
}
#submenu .active{
-fx-fill: #000000;
-fx-font-weight: bold;
}

View File

@ -10,7 +10,7 @@
<?import javafx.scene.text.Font?> <?import javafx.scene.text.Font?>
<?import javafx.scene.text.Text?> <?import javafx.scene.text.Text?>
<AnchorPane layoutX="65.0" layoutY="146.0" prefHeight="96.0" prefWidth="800.0" style="-fx-border-insets: 30; -fx-background-insets: 30; -fx-background-color: #fff; -fx-background-radius: 3; -fx-border-radius: 3; -fx-border-color: #ddd;"> <AnchorPane layoutX="65.0" layoutY="146.0" prefHeight="120.0" prefWidth="800.0" style="-fx-border-insets: 30; -fx-background-insets: 30; -fx-background-color: #fff; -fx-background-radius: 3; -fx-border-radius: 3; -fx-border-color: #ddd;">
<opaqueInsets> <opaqueInsets>
<Insets /> <Insets />
</opaqueInsets> </opaqueInsets>

View File

@ -1,53 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.Cursor?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.control.ToggleGroup?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Text?>
<AnchorPane id="exerc" fx:id="exerc" prefHeight="228.0" prefWidth="620.0" style="-fx-border-insets: 10; -fx-background-insets: 10; -fx-background-color: #ffffff; -fx-background-radius: 3; -fx-border-radius: 3; -fx-border-color: #ddd;" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1">
<opaqueInsets>
<Insets />
</opaqueInsets>
<children>
<Text layoutX="251.0" layoutY="39.0" strokeType="OUTSIDE" strokeWidth="0.0" style="-fx-font-size: 20;" text="Exercise #1" />
<Button layoutX="536.0" layoutY="194.0" mnemonicParsing="false" style="-fx-background-color: #ffffff; -fx-border-width: 1; -fx-border-color: #aaaaaa; -fx-text-fill: #000000; -fx-border-radius: 3; -fx-background-radius: 3;" text="Check" />
<Text layoutX="47.0" layoutY="96.0" strokeType="OUTSIDE" strokeWidth="0.0" text="&quot;I am doing my homework&quot; is affirmative" />
<Text layoutX="47.0" layoutY="118.0" strokeType="OUTSIDE" strokeWidth="0.0" />
<Text layoutX="105.0" layoutY="129.0" strokeType="OUTSIDE" strokeWidth="0.0" text="&quot;Where do you live ?&quot; is passive" />
<Text layoutX="33.0" layoutY="161.0" strokeType="OUTSIDE" strokeWidth="0.0" text="&quot;She had a nightmare&quot; happens in the past" />
<Text layoutX="59.0" layoutY="191.0" strokeType="OUTSIDE" strokeWidth="0.0" text="&quot;She had a dream ?&quot; is a valid question" />
<Text layoutX="317.0" layoutY="67.0" strokeType="OUTSIDE" strokeWidth="0.0" text="True" />
<Text layoutX="352.0" layoutY="68.0" strokeType="OUTSIDE" strokeWidth="0.0" text="False" />
<RadioButton layoutX="327.0" layoutY="83.0" mnemonicParsing="false" selected="true">
<toggleGroup>
<ToggleGroup fx:id="g1" />
</toggleGroup>
</RadioButton>
<RadioButton layoutX="353.0" layoutY="83.0" mnemonicParsing="false" toggleGroup="$g1" />
<RadioButton layoutX="327.0" layoutY="117.0" mnemonicParsing="false" selected="true">
<toggleGroup>
<ToggleGroup fx:id="g2" />
</toggleGroup>
</RadioButton>
<RadioButton layoutX="353.0" layoutY="117.0" mnemonicParsing="false" toggleGroup="$g2" />
<RadioButton layoutX="327.0" layoutY="148.0" mnemonicParsing="false" selected="true">
<toggleGroup>
<ToggleGroup fx:id="g3" />
</toggleGroup>
</RadioButton>
<RadioButton layoutX="353.0" layoutY="148.0" mnemonicParsing="false" toggleGroup="$g3" />
<RadioButton layoutX="327.0" layoutY="178.0" mnemonicParsing="false" selected="true">
<toggleGroup>
<ToggleGroup fx:id="g4" />
</toggleGroup>
</RadioButton>
<RadioButton layoutX="353.0" layoutY="178.0" mnemonicParsing="false" toggleGroup="$g4" />
</children>
<cursor>
<Cursor fx:constant="HAND" />
</cursor>
</AnchorPane>

View File

@ -1,10 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?> <?import javafx.geometry.Insets?>
<?import javafx.scene.Cursor?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ScrollPane?> <?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.image.Image?> <?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?> <?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?> <?import javafx.scene.layout.AnchorPane?>
@ -14,7 +11,7 @@
<?import javafx.scene.text.Font?> <?import javafx.scene.text.Font?>
<?import javafx.scene.text.Text?> <?import javafx.scene.text.Text?>
<AnchorPane fx:id="root" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="700.0" prefWidth="1450.0" style="-fx-background-color: f4f4f4" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1"> <AnchorPane fx:id="root" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="700.0" prefWidth="1280.0" style="-fx-background-color: #edf0f5;" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1">
<children> <children>
<AnchorPane id="header" fx:id="header" layoutX="200.0" maxHeight="40.0" maxWidth="1280.0" prefHeight="40.0" prefWidth="1080.0" stylesheets="@../css/header.css" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> <AnchorPane id="header" fx:id="header" layoutX="200.0" maxHeight="40.0" maxWidth="1280.0" prefHeight="40.0" prefWidth="1080.0" stylesheets="@../css/header.css" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children> <children>
@ -23,18 +20,10 @@
</AnchorPane> </AnchorPane>
<AnchorPane id="menu_wrapper" fx:id="menu_wrapper" maxHeight="700.0" maxWidth="251.0" minHeight="680.0" minWidth="40.0" prefHeight="700.0" prefWidth="234.0" stylesheets="@../css/menu.css" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0"> <AnchorPane id="menu_wrapper" fx:id="menu_wrapper" maxHeight="700.0" maxWidth="251.0" minHeight="680.0" minWidth="40.0" prefHeight="700.0" prefWidth="234.0" stylesheets="@../css/menu.css" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0">
<children> <children>
<Pane id="header_icon" fx:id="header_icon" maxHeight="40.0" minHeight="40.0" minWidth="40.0" prefHeight="40.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> <Pane id="header_icon" fx:id="header_icon" maxHeight="40.0" minHeight="40.0" minWidth="40.0" prefHeight="40.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
<children>
<ImageView fitHeight="35.0" fitWidth="32.0" layoutX="10.0" layoutY="9.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../src/icon.png" />
</image>
</ImageView>
<Text fill="WHITE" layoutX="57.0" layoutY="34.0" strokeType="OUTSIDE" strokeWidth="0.0" style="-fx-font-size: 25; -fx-font-family: Lato;" text="Lingo Pro" />
</children></Pane>
<VBox id="menu" fx:id="menu" layoutX="50.0" layoutY="40.0" prefHeight="600.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="50.0"> <VBox id="menu" fx:id="menu" layoutX="50.0" layoutY="40.0" prefHeight="600.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="50.0">
<children> <children>
<FlowPane id="profile" alignment="CENTER_LEFT" prefHeight="114.0" prefWidth="234.0" style="-fx-border-width: 0 0 1 0; -fx-border-color: #eeeeee;"> <FlowPane alignment="CENTER_LEFT" prefHeight="114.0" prefWidth="234.0" style="-fx-border-width: 0 0 1 0; -fx-border-color: #fafafa;">
<children> <children>
<ImageView fitHeight="57.0" fitWidth="56.0" pickOnBounds="true" preserveRatio="true"> <ImageView fitHeight="57.0" fitWidth="56.0" pickOnBounds="true" preserveRatio="true">
<image> <image>
@ -46,11 +35,11 @@
</ImageView> </ImageView>
<Pane prefHeight="56.0" prefWidth="125.0"> <Pane prefHeight="56.0" prefWidth="125.0">
<children> <children>
<Text fill="#838383" layoutX="4.0" layoutY="40.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Niveau B2"> <Text fill="#838383" layoutX="4.0" layoutY="40.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Designer of App">
<font> <font>
<Font name="Lato Regular" size="11.0" /> <Font name="Lato Regular" size="11.0" />
</font></Text> </font></Text>
<Text fill="#545454" layoutX="4.0" layoutY="23.0" strokeType="OUTSIDE" strokeWidth="0.0" text="nom utilisateur" wrappingWidth="120.7770004272461"> <Text fill="#545454" layoutX="4.0" layoutY="23.0" strokeType="OUTSIDE" strokeWidth="0.0" text="ADRIEN MARQUES" wrappingWidth="120.7770004272461">
<font> <font>
<Font name="Lato Regular" size="13.0" /> <Font name="Lato Regular" size="13.0" />
</font> </font>
@ -59,312 +48,17 @@
</Pane> </Pane>
</children> </children>
</FlowPane> </FlowPane>
<FlowPane id="dictionary" alignment="CENTER" columnHalignment="CENTER" layoutX="10.0" layoutY="124.0" prefHeight="58.0" prefWidth="234.0" styleClass="menu_item">
<children>
<ImageView fitHeight="20.0" fitWidth="20.0" pickOnBounds="true" preserveRatio="true">
<FlowPane.margin>
<Insets right="20.0" />
</FlowPane.margin>
<image>
<Image url="@../src/menu/dictionary.png" />
</image>
</ImageView>
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Vocabulaire" />
</children>
</FlowPane>
<FlowPane id="exercises" alignment="CENTER" columnHalignment="CENTER" layoutX="10.0" layoutY="182.0" prefHeight="58.0" prefWidth="234.0" styleClass="menu_item">
<children>
<ImageView fitHeight="20.0" fitWidth="20.0" pickOnBounds="true" preserveRatio="true">
<FlowPane.margin>
<Insets right="20.0" />
</FlowPane.margin>
<image>
<Image url="@../src/menu/exercises.png" />
</image>
</ImageView>
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Excercices" />
</children>
</FlowPane>
<FlowPane id="translator" alignment="CENTER" columnHalignment="CENTER" layoutX="10.0" layoutY="240.0" prefHeight="58.0" prefWidth="234.0" styleClass="menu_item">
<children>
<ImageView fitHeight="20.0" fitWidth="20.0" pickOnBounds="true" preserveRatio="true">
<FlowPane.margin>
<Insets right="20.0" />
</FlowPane.margin>
<image>
<Image url="@../src/menu/translator.png" />
</image>
</ImageView>
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Traducteur" />
</children>
</FlowPane>
<FlowPane id="magazines" alignment="CENTER" columnHalignment="CENTER" layoutX="10.0" layoutY="240.0" prefHeight="58.0" prefWidth="234.0" styleClass="menu_item">
<children>
<ImageView fitHeight="20.0" fitWidth="20.0" pickOnBounds="true" preserveRatio="true">
<FlowPane.margin>
<Insets right="20.0" />
</FlowPane.margin>
<image>
<Image url="@../src/menu/magazines.png" />
</image>
</ImageView>
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Magazines" />
</children>
</FlowPane>
</children> </children>
</VBox> </VBox>
</children> </children>
</AnchorPane> </AnchorPane>
<VBox id="submenu" fx:id="submenu" layoutX="234.0" layoutY="50.0" prefWidth="200.0" stylesheets="@../css/submenu.css" AnchorPane.bottomAnchor="0.0" AnchorPane.topAnchor="50.0"> <VBox id="submenu" fx:id="submenu" layoutX="234.0" layoutY="50.0" prefHeight="650.0" prefWidth="194.0" style="-fx-background-color: white;" AnchorPane.bottomAnchor="0.0" AnchorPane.topAnchor="50.0" />
<children> <ScrollPane id="container_scroll" fx:id="container_scroll" hbarPolicy="NEVER" layoutX="428.0" layoutY="50.0" pannable="true" prefHeight="650.0" prefWidth="852.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="428.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="50.0">
<FlowPane alignment="CENTER_RIGHT" columnHalignment="CENTER" prefHeight="35.0" prefWidth="234.0">
<children>
<Text fx:id="all" fill="#656565" strokeType="OUTSIDE" strokeWidth="0.0" text="Show all" />
<ImageView fitHeight="15.0" fitWidth="15.0" pickOnBounds="true" preserveRatio="true">
<FlowPane.margin>
<Insets left="15.0" />
</FlowPane.margin>
<image>
<Image url="@../src/submenu/all.png" />
</image>
</ImageView>
</children>
<VBox.margin>
<Insets left="20.0" right="20.0" top="25.0" />
</VBox.margin>
</FlowPane>
<FlowPane alignment="CENTER_RIGHT" columnHalignment="CENTER" layoutX="30.0" layoutY="60.0" prefHeight="35.0" prefWidth="234.0" styleClass="menu_item">
<children>
<Text fx:id="science" fill="#656565" strokeType="OUTSIDE" strokeWidth="0.0" text="Science" />
<ImageView fitHeight="15.0" fitWidth="15.0" pickOnBounds="true" preserveRatio="true">
<FlowPane.margin>
<Insets left="15.0" />
</FlowPane.margin>
<image>
<Image url="@../src/submenu/science.png" />
</image>
</ImageView>
</children>
<VBox.margin>
<Insets left="20.0" right="20.0" />
</VBox.margin>
</FlowPane>
<FlowPane alignment="CENTER_RIGHT" columnHalignment="CENTER" layoutX="30.0" layoutY="95.0" prefHeight="35.0" prefWidth="234.0" styleClass="menu_item">
<children>
<Text fx:id="business" fill="#656565" strokeType="OUTSIDE" strokeWidth="0.0" text="Business" />
<ImageView fitHeight="15.0" fitWidth="15.0" pickOnBounds="true" preserveRatio="true">
<FlowPane.margin>
<Insets left="15.0" />
</FlowPane.margin>
<image>
<Image url="@../src/submenu/business.png" />
</image>
</ImageView>
</children>
<VBox.margin>
<Insets left="20.0" right="20.0" />
</VBox.margin>
</FlowPane>
<FlowPane alignment="CENTER_RIGHT" columnHalignment="CENTER" layoutX="30.0" layoutY="130.0" prefHeight="35.0" prefWidth="234.0" styleClass="menu_item">
<children>
<Text fx:id="entertainment" fill="#656565" strokeType="OUTSIDE" strokeWidth="0.0" text="Entertainment" />
<ImageView fitHeight="15.0" fitWidth="15.0" pickOnBounds="true" preserveRatio="true">
<FlowPane.margin>
<Insets left="15.0" />
</FlowPane.margin>
<image>
<Image url="@../src/submenu/entertainment.png" />
</image>
</ImageView>
</children>
<VBox.margin>
<Insets left="20.0" right="20.0" />
</VBox.margin>
</FlowPane>
<FlowPane alignment="CENTER_RIGHT" columnHalignment="CENTER" layoutX="10.0" layoutY="165.0" prefHeight="35.0" prefWidth="234.0" styleClass="menu_item">
<children>
<Text fx:id="gaming" fill="#656565" strokeType="OUTSIDE" strokeWidth="0.0" text="Gaming" />
<ImageView fitHeight="15.0" fitWidth="15.0" pickOnBounds="true" preserveRatio="true">
<FlowPane.margin>
<Insets left="15.0" />
</FlowPane.margin>
<image>
<Image url="@../src/submenu/gaming.png" />
</image>
</ImageView>
</children>
<VBox.margin>
<Insets left="20.0" right="20.0" />
</VBox.margin>
</FlowPane>
<FlowPane alignment="CENTER_RIGHT" columnHalignment="CENTER" layoutX="10.0" layoutY="200.0" prefHeight="35.0" prefWidth="234.0" styleClass="menu_item">
<children>
<Text fx:id="health" fill="#656565" strokeType="OUTSIDE" strokeWidth="0.0" text="Health" />
<ImageView fitHeight="15.0" fitWidth="15.0" pickOnBounds="true" preserveRatio="true">
<FlowPane.margin>
<Insets left="15.0" />
</FlowPane.margin>
<image>
<Image url="@../src/submenu/health.png" />
</image>
</ImageView>
</children>
<VBox.margin>
<Insets left="20.0" right="20.0" />
</VBox.margin>
</FlowPane>
<FlowPane alignment="CENTER_RIGHT" columnHalignment="CENTER" layoutX="30.0" layoutY="235.0" prefHeight="35.0" prefWidth="234.0" styleClass="menu_item">
<children>
<Text fx:id="music" fill="#656565" strokeType="OUTSIDE" strokeWidth="0.0" text="Music" />
<ImageView fitHeight="15.0" fitWidth="15.0" pickOnBounds="true" preserveRatio="true">
<FlowPane.margin>
<Insets left="15.0" />
</FlowPane.margin>
<image>
<Image url="@../src/submenu/music.png" />
</image>
</ImageView>
</children>
<VBox.margin>
<Insets left="20.0" right="20.0" />
</VBox.margin>
</FlowPane>
<FlowPane alignment="CENTER_RIGHT" columnHalignment="CENTER" layoutX="10.0" layoutY="270.0" prefHeight="35.0" prefWidth="234.0" styleClass="menu_item">
<children>
<Text fx:id="sport" fill="#656565" strokeType="OUTSIDE" strokeWidth="0.0" text="Sport" />
<ImageView fitHeight="15.0" fitWidth="15.0" pickOnBounds="true" preserveRatio="true">
<FlowPane.margin>
<Insets left="15.0" />
</FlowPane.margin>
<image>
<Image url="@../src/submenu/sport.png" />
</image>
</ImageView>
</children>
<VBox.margin>
<Insets left="20.0" right="20.0" />
</VBox.margin>
</FlowPane>
<FlowPane alignment="CENTER_RIGHT" columnHalignment="CENTER" layoutX="10.0" layoutY="305.0" prefHeight="35.0" prefWidth="234.0" styleClass="menu_item">
<children>
<Text fx:id="nature" fill="#656565" strokeType="OUTSIDE" strokeWidth="0.0" text="Nature" />
<ImageView fitHeight="15.0" fitWidth="15.0" pickOnBounds="true" preserveRatio="true">
<FlowPane.margin>
<Insets left="15.0" />
</FlowPane.margin>
<image>
<Image url="@../src/submenu/nature.png" />
</image>
</ImageView>
</children>
<VBox.margin>
<Insets left="20.0" right="20.0" />
</VBox.margin>
</FlowPane>
<FlowPane alignment="CENTER_RIGHT" columnHalignment="CENTER" layoutX="10.0" layoutY="340.0" prefHeight="35.0" prefWidth="234.0" styleClass="menu_item">
<children>
<Text fx:id="economics" fill="#656565" strokeType="OUTSIDE" strokeWidth="0.0" text="Economics" />
<ImageView fitHeight="15.0" fitWidth="15.0" pickOnBounds="true" preserveRatio="true">
<FlowPane.margin>
<Insets left="15.0" />
</FlowPane.margin>
<image>
<Image url="@../src/submenu/economics.png" />
</image>
</ImageView>
</children>
<VBox.margin>
<Insets left="20.0" right="20.0" />
</VBox.margin>
</FlowPane>
<FlowPane alignment="CENTER_RIGHT" columnHalignment="CENTER" layoutX="10.0" layoutY="375.0" prefHeight="35.0" prefWidth="234.0" styleClass="menu_item">
<children>
<Text fx:id="politics" fill="#656565" strokeType="OUTSIDE" strokeWidth="0.0" text="Politics" />
<ImageView fx:id="politics" fitHeight="15.0" fitWidth="15.0" pickOnBounds="true" preserveRatio="true">
<FlowPane.margin>
<Insets left="15.0" />
</FlowPane.margin>
<image>
<Image url="@../src/submenu/politics.png" />
</image>
</ImageView>
</children>
<VBox.margin>
<Insets left="20.0" right="20.0" />
</VBox.margin>
</FlowPane>
<FlowPane alignment="CENTER_RIGHT" columnHalignment="CENTER" layoutX="10.0" layoutY="410.0" prefHeight="35.0" prefWidth="234.0" styleClass="menu_item">
<children>
<Text fx:id="technology" fill="#656565" strokeType="OUTSIDE" strokeWidth="0.0" text="Technology" />
<ImageView fitHeight="15.0" fitWidth="15.0" pickOnBounds="true" preserveRatio="true">
<FlowPane.margin>
<Insets left="15.0" />
</FlowPane.margin>
<image>
<Image url="@../src/submenu/technology.png" />
</image>
</ImageView>
</children>
<VBox.margin>
<Insets left="20.0" right="20.0" />
</VBox.margin>
</FlowPane>
</children></VBox>
<ScrollPane id="scroll_container" fx:id="scroll_container" hbarPolicy="NEVER" pickOnBounds="false" prefHeight="651.0" prefWidth="1015.0" style="-fx-background-color: transparent;" AnchorPane.bottomAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="49.0">
<content> <content>
<FlowPane id="container" fx:id="container" alignment="TOP_CENTER" columnHalignment="CENTER" prefHeight="650.0" prefWrapLength="1000.0" stylesheets="@../css/container.css"> <FlowPane id="container" fx:id="container" alignment="TOP_CENTER" columnHalignment="CENTER" prefWrapLength="1000.0">
<children>
<AnchorPane id="vocab" fx:id="card1" prefHeight="228.0" prefWidth="620.0" style="-fx-border-insets: 10; -fx-background-insets: 10; -fx-background-color: #ffffff; -fx-background-radius: 3; -fx-border-radius: 3; -fx-border-color: #ddd;">
<opaqueInsets>
<Insets />
</opaqueInsets>
<children>
<FlowPane columnHalignment="CENTER" layoutX="51.0" layoutY="54.0" prefHeight="149.0" prefWidth="160.0" vgap="10.0">
<children>
<TextField promptText="manger" />
<TextField layoutX="10.0" layoutY="10.0" promptText="voyager" />
<TextField layoutX="10.0" layoutY="36.0" promptText="dormir" />
<TextField layoutX="10.0" layoutY="62.0" promptText="apprendre" />
</children>
</FlowPane>
<FlowPane columnHalignment="CENTER" layoutX="251.0" layoutY="56.0" prefHeight="151.0" prefWidth="160.0" vgap="10.0">
<children>
<TextField promptText="pain (du)" />
<TextField promptText="nourriture (la)" />
<TextField promptText="animaux (des)" />
</children>
</FlowPane>
<FlowPane columnHalignment="CENTER" layoutX="438.0" layoutY="53.0" prefHeight="139.0" prefWidth="160.0" vgap="10.0">
<children>
<TextField promptText="journal (un)" />
<TextField promptText="pays (un)" />
<TextField promptText="chambre (une)" />
</children>
</FlowPane>
<Text layoutX="249.0" layoutY="48.0" strokeType="OUTSIDE" strokeWidth="0.0" style="-fx-font-size: 20;" text="Vocabulary #1" />
<Text layoutX="37.0" layoutY="74.0" strokeType="OUTSIDE" strokeWidth="0.0" style="-fx-font-size: 16;" text="1" />
<Text layoutX="35.0" layoutY="109.0" strokeType="OUTSIDE" strokeWidth="0.0" style="-fx-font-size: 16;" text="4" />
<Text layoutX="35.0" layoutY="145.0" strokeType="OUTSIDE" strokeWidth="0.0" style="-fx-font-size: 16;" text="7" />
<Text layoutX="26.0" layoutY="181.0" strokeType="OUTSIDE" strokeWidth="0.0" style="-fx-font-size: 16;" text="10" />
<Text layoutX="238.0" layoutY="74.0" strokeType="OUTSIDE" strokeWidth="0.0" style="-fx-font-size: 16;" text="2" />
<Text layoutX="236.0" layoutY="111.0" strokeType="OUTSIDE" strokeWidth="0.0" style="-fx-font-size: 16;" text="5" />
<Text layoutX="236.0" layoutY="147.0" strokeType="OUTSIDE" strokeWidth="0.0" style="-fx-font-size: 16;" text="8" />
<Text layoutX="427.0" layoutY="72.0" strokeType="OUTSIDE" strokeWidth="0.0" style="-fx-font-size: 16;" text="3" />
<Text layoutX="425.0" layoutY="109.0" strokeType="OUTSIDE" strokeWidth="0.0" style="-fx-font-size: 16;" text="6" />
<Text layoutX="425.0" layoutY="144.0" strokeType="OUTSIDE" strokeWidth="0.0" style="-fx-font-size: 16;" text="9" />
<Button layoutX="536.0" layoutY="194.0" mnemonicParsing="false" style="-fx-background-color: #ffffff; -fx-border-width: 1; -fx-border-color: #aaaaaa; -fx-text-fill: #000000; -fx-border-radius: 3; -fx-background-radius: 3;" text="Check" />
</children>
<cursor>
<Cursor fx:constant="HAND" />
</cursor>
</AnchorPane>
</children>
<opaqueInsets> <opaqueInsets>
<Insets /> <Insets />
</opaqueInsets> </opaqueInsets>
<padding>
<Insets top="20.0" />
</padding>
</FlowPane> </FlowPane>
</content> </content>
</ScrollPane> </ScrollPane>

View File

@ -1,212 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.Cursor?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.FlowPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.text.Text?>
<VBox id="submenu" fx:id="submenu" layoutX="234.0" layoutY="50.0" prefWidth="200.0" stylesheets="@../css/submenu.css" AnchorPane.bottomAnchor="0.0" AnchorPane.topAnchor="50.0">
<children>
<FlowPane alignment="CENTER_RIGHT" columnHalignment="CENTER" prefHeight="35.0" prefWidth="234.0">
<children>
<Text fx:id="all" fill="#656565" strokeType="OUTSIDE" strokeWidth="0.0" text="Tout afficher" />
<ImageView fitHeight="15.0" fitWidth="15.0" pickOnBounds="true" preserveRatio="true">
<FlowPane.margin>
<Insets left="15.0" />
</FlowPane.margin>
<image>
<Image url="@../src/submenu/all.png" />
</image>
</ImageView>
</children>
<VBox.margin>
<Insets left="20.0" right="20.0" top="25.0" />
</VBox.margin>
</FlowPane>
<FlowPane alignment="CENTER_RIGHT" columnHalignment="CENTER" layoutX="30.0" layoutY="60.0" prefHeight="35.0" prefWidth="234.0" styleClass="menu_item">
<children>
<Text fx:id="science" fill="#656565" strokeType="OUTSIDE" strokeWidth="0.0" text="Science" />
<ImageView fitHeight="15.0" fitWidth="15.0" pickOnBounds="true" preserveRatio="true">
<FlowPane.margin>
<Insets left="15.0" />
</FlowPane.margin>
<image>
<Image url="@../src/submenu/science.png" />
</image>
</ImageView>
</children>
<VBox.margin>
<Insets left="20.0" right="20.0" />
</VBox.margin>
</FlowPane>
<FlowPane alignment="CENTER_RIGHT" columnHalignment="CENTER" layoutX="30.0" layoutY="95.0" prefHeight="35.0" prefWidth="234.0" styleClass="menu_item">
<children>
<Text fx:id="business" fill="#656565" strokeType="OUTSIDE" strokeWidth="0.0" text="Business" />
<ImageView fitHeight="15.0" fitWidth="15.0" pickOnBounds="true" preserveRatio="true">
<FlowPane.margin>
<Insets left="15.0" />
</FlowPane.margin>
<image>
<Image url="@../src/submenu/business.png" />
</image>
</ImageView>
</children>
<VBox.margin>
<Insets left="20.0" right="20.0" />
</VBox.margin>
</FlowPane>
<FlowPane alignment="CENTER_RIGHT" columnHalignment="CENTER" layoutX="30.0" layoutY="130.0" prefHeight="35.0" prefWidth="234.0" styleClass="menu_item">
<children>
<Text fx:id="entertainment" fill="#656565" strokeType="OUTSIDE" strokeWidth="0.0" text="Entertainment" />
<ImageView fitHeight="15.0" fitWidth="15.0" pickOnBounds="true" preserveRatio="true">
<FlowPane.margin>
<Insets left="15.0" />
</FlowPane.margin>
<image>
<Image url="@../src/submenu/entertainment.png" />
</image>
</ImageView>
</children>
<VBox.margin>
<Insets left="20.0" right="20.0" />
</VBox.margin>
</FlowPane>
<FlowPane alignment="CENTER_RIGHT" columnHalignment="CENTER" layoutX="10.0" layoutY="165.0" prefHeight="35.0" prefWidth="234.0" styleClass="menu_item">
<children>
<Text fx:id="gaming" fill="#656565" strokeType="OUTSIDE" strokeWidth="0.0" text="Gaming" />
<ImageView fitHeight="15.0" fitWidth="15.0" pickOnBounds="true" preserveRatio="true">
<FlowPane.margin>
<Insets left="15.0" />
</FlowPane.margin>
<image>
<Image url="@../src/submenu/gaming.png" />
</image>
</ImageView>
</children>
<VBox.margin>
<Insets left="20.0" right="20.0" />
</VBox.margin>
</FlowPane>
<FlowPane alignment="CENTER_RIGHT" columnHalignment="CENTER" layoutX="10.0" layoutY="200.0" prefHeight="35.0" prefWidth="234.0" styleClass="menu_item">
<children>
<Text fx:id="health" fill="#656565" strokeType="OUTSIDE" strokeWidth="0.0" text="Health" />
<ImageView fitHeight="15.0" fitWidth="15.0" pickOnBounds="true" preserveRatio="true">
<FlowPane.margin>
<Insets left="15.0" />
</FlowPane.margin>
<image>
<Image url="@../src/submenu/health.png" />
</image>
</ImageView>
</children>
<VBox.margin>
<Insets left="20.0" right="20.0" />
</VBox.margin>
</FlowPane>
<FlowPane alignment="CENTER_RIGHT" columnHalignment="CENTER" layoutX="30.0" layoutY="235.0" prefHeight="35.0" prefWidth="234.0" styleClass="menu_item">
<children>
<Text fx:id="music" fill="#656565" strokeType="OUTSIDE" strokeWidth="0.0" text="Music" />
<ImageView fitHeight="15.0" fitWidth="15.0" pickOnBounds="true" preserveRatio="true">
<FlowPane.margin>
<Insets left="15.0" />
</FlowPane.margin>
<image>
<Image url="@../src/submenu/music.png" />
</image>
</ImageView>
</children>
<VBox.margin>
<Insets left="20.0" right="20.0" />
</VBox.margin>
</FlowPane>
<FlowPane alignment="CENTER_RIGHT" columnHalignment="CENTER" layoutX="10.0" layoutY="270.0" prefHeight="35.0" prefWidth="234.0" styleClass="menu_item">
<children>
<Text fx:id="sport" fill="#656565" strokeType="OUTSIDE" strokeWidth="0.0" text="Sport" />
<ImageView fitHeight="15.0" fitWidth="15.0" pickOnBounds="true" preserveRatio="true">
<FlowPane.margin>
<Insets left="15.0" />
</FlowPane.margin>
<image>
<Image url="@../src/submenu/sport.png" />
</image>
</ImageView>
</children>
<VBox.margin>
<Insets left="20.0" right="20.0" />
</VBox.margin>
</FlowPane>
<FlowPane alignment="CENTER_RIGHT" columnHalignment="CENTER" layoutX="10.0" layoutY="305.0" prefHeight="35.0" prefWidth="234.0" styleClass="menu_item">
<children>
<Text fx:id="nature" fill="#656565" strokeType="OUTSIDE" strokeWidth="0.0" text="Nature" />
<ImageView fitHeight="15.0" fitWidth="15.0" pickOnBounds="true" preserveRatio="true">
<FlowPane.margin>
<Insets left="15.0" />
</FlowPane.margin>
<image>
<Image url="@../src/submenu/nature.png" />
</image>
</ImageView>
</children>
<VBox.margin>
<Insets left="20.0" right="20.0" />
</VBox.margin>
</FlowPane>
<FlowPane alignment="CENTER_RIGHT" columnHalignment="CENTER" layoutX="10.0" layoutY="340.0" prefHeight="35.0" prefWidth="234.0" styleClass="menu_item">
<children>
<Text fx:id="economics" fill="#656565" strokeType="OUTSIDE" strokeWidth="0.0" text="Economics" />
<ImageView fitHeight="15.0" fitWidth="15.0" pickOnBounds="true" preserveRatio="true">
<FlowPane.margin>
<Insets left="15.0" />
</FlowPane.margin>
<image>
<Image url="@../src/submenu/economics.png" />
</image>
</ImageView>
</children>
<VBox.margin>
<Insets left="20.0" right="20.0" />
</VBox.margin>
</FlowPane>
<FlowPane alignment="CENTER_RIGHT" columnHalignment="CENTER" layoutX="10.0" layoutY="375.0" prefHeight="35.0" prefWidth="234.0" styleClass="menu_item">
<children>
<Text fx:id="politics" fill="#656565" strokeType="OUTSIDE" strokeWidth="0.0" text="Politics" />
<ImageView fx:id="politics" fitHeight="15.0" fitWidth="15.0" pickOnBounds="true" preserveRatio="true">
<FlowPane.margin>
<Insets left="15.0" />
</FlowPane.margin>
<image>
<Image url="@../src/submenu/politics.png" />
</image>
</ImageView>
</children>
<VBox.margin>
<Insets left="20.0" right="20.0" />
</VBox.margin>
</FlowPane>
<FlowPane alignment="CENTER_RIGHT" columnHalignment="CENTER" layoutX="10.0" layoutY="410.0" prefHeight="35.0" prefWidth="234.0" styleClass="menu_item">
<children>
<Text fx:id="technology" fill="#656565" strokeType="OUTSIDE" strokeWidth="0.0" text="Technology" />
<ImageView fitHeight="15.0" fitWidth="15.0" pickOnBounds="true" preserveRatio="true">
<FlowPane.margin>
<Insets left="15.0" />
</FlowPane.margin>
<image>
<Image url="@../src/submenu/technology.png" />
</image>
</ImageView>
</children>
<VBox.margin>
<Insets left="20.0" right="20.0" />
</VBox.margin>
</FlowPane>
</children></VBox>

View File

@ -1,54 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.Cursor?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.FlowPane?>
<?import javafx.scene.text.Text?>
<AnchorPane id="vocab" fx:id="vocab" prefHeight="228.0" prefWidth="620.0" style="-fx-border-color: #ddd;" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1">
<opaqueInsets>
<Insets />
</opaqueInsets>
<children>
<FlowPane columnHalignment="CENTER" layoutX="51.0" layoutY="54.0" prefHeight="149.0" prefWidth="160.0" vgap="10.0">
<children>
<TextField promptText="manger" />
<TextField layoutX="10.0" layoutY="10.0" promptText="voyager" />
<TextField layoutX="10.0" layoutY="36.0" promptText="dormir" />
<TextField layoutX="10.0" layoutY="62.0" promptText="apprendre" />
</children>
</FlowPane>
<FlowPane columnHalignment="CENTER" layoutX="251.0" layoutY="56.0" prefHeight="151.0" prefWidth="160.0" vgap="10.0">
<children>
<TextField promptText="pain (du)" />
<TextField promptText="nourriture (la)" />
<TextField promptText="animaux (des)" />
</children>
</FlowPane>
<FlowPane columnHalignment="CENTER" layoutX="438.0" layoutY="53.0" prefHeight="139.0" prefWidth="160.0" vgap="10.0">
<children>
<TextField promptText="journal (un)" />
<TextField promptText="pays (un)" />
<TextField promptText="chambre (une)" />
</children>
</FlowPane>
<Text layoutX="249.0" layoutY="34.0" strokeType="OUTSIDE" strokeWidth="0.0" style="-fx-font-size: 20;" text="Vocabulary #1" />
<Text layoutX="37.0" layoutY="74.0" strokeType="OUTSIDE" strokeWidth="0.0" style="-fx-font-size: 16;" text="1" />
<Text layoutX="35.0" layoutY="109.0" strokeType="OUTSIDE" strokeWidth="0.0" style="-fx-font-size: 16;" text="4" />
<Text layoutX="35.0" layoutY="145.0" strokeType="OUTSIDE" strokeWidth="0.0" style="-fx-font-size: 16;" text="7" />
<Text layoutX="26.0" layoutY="181.0" strokeType="OUTSIDE" strokeWidth="0.0" style="-fx-font-size: 16;" text="10" />
<Text layoutX="238.0" layoutY="74.0" strokeType="OUTSIDE" strokeWidth="0.0" style="-fx-font-size: 16;" text="2" />
<Text layoutX="236.0" layoutY="111.0" strokeType="OUTSIDE" strokeWidth="0.0" style="-fx-font-size: 16;" text="5" />
<Text layoutX="236.0" layoutY="147.0" strokeType="OUTSIDE" strokeWidth="0.0" style="-fx-font-size: 16;" text="8" />
<Text layoutX="427.0" layoutY="72.0" strokeType="OUTSIDE" strokeWidth="0.0" style="-fx-font-size: 16;" text="3" />
<Text layoutX="425.0" layoutY="109.0" strokeType="OUTSIDE" strokeWidth="0.0" style="-fx-font-size: 16;" text="6" />
<Text layoutX="425.0" layoutY="144.0" strokeType="OUTSIDE" strokeWidth="0.0" style="-fx-font-size: 16;" text="9" />
<Button layoutX="536.0" layoutY="194.0" mnemonicParsing="false" style="-fx-background-color: #ffffff; -fx-border-width: 1; -fx-border-color: #aaaaaa; -fx-text-fill: #000000; -fx-border-radius: 3; -fx-background-radius: 3;" text="Check" />
</children>
<cursor>
<Cursor fx:constant="HAND" />
</cursor>
</AnchorPane>

View File

@ -7,33 +7,31 @@ public class LangModel {
private static LangModel instance; private static LangModel instance;
private Languages fromLang = Languages.fr; private Languages fromLang = Languages.fr;
private Languages toLang = Languages.en; private Languages toLang = Languages.en;
private LangModel() { private LangModel(){}
}
public static LangModel getInstance() { public static LangModel getInstance(){
if(LangModel.instance == null) { if( LangModel.instance == null )
LangModel.instance = new LangModel(); LangModel.instance = new LangModel();
}
return LangModel.instance; return LangModel.instance;
} }
public void setFromLang(Languages lang) { public void setFromLang(Languages lang){
this.fromLang = lang; this.fromLang = lang;
} }
public Languages getFromLang() { public Languages getFromLang(){
return this.fromLang; return this.fromLang;
} }
public void setToLang(Languages lang) { public void setToLang(Languages lang){
this.toLang = lang; this.toLang = lang;
} }
public Languages getToLang() { public Languages getToLang(){
return this.toLang; return this.toLang;
} }

View File

@ -1,19 +1,16 @@
package model; package model;
import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import Classes.ApiCall; import Classes.ApiCall;
import Classes.Category; import Classes.Category;
import Classes.Event; import Classes.Event;
import Classes.SortTypes; import Classes.SortTypes;
import Classes.api.fetchArticles;
import Interfaces.Callback; import Interfaces.Callback;
import Interfaces.DelayedCallback; import Interfaces.DelayedCallback;
import Interfaces.EventObserver; import Interfaces.EventObserver;
@ -25,66 +22,62 @@ public class NewsListModel implements Observable{
//instance du singleton //instance du singleton
private static NewsListModel instance; private static NewsListModel instance;
//Clé d'API
private String APIKey; private String APIKey; // Clé d'API
//catégorie choise parl'utilisateur private Category cat = Category.all; // catégorie choise parl'utilisateur
private Category cat = Category.all; private Boolean isRetreivingSources = false; // est ce que le modele est en train de récupérer les sources
//est ce que le modele est en train de récupérer les sources private Boolean apiError = false; // est ce que l'api a rencontré une erreur
private Boolean isRetreivingSources = false; private ArrayList<String> sources; // liste des sources
//est ce que l'api a rencontré une erreur private HashMap<String,EventObserver> observers; // liste des observers
private Boolean apiError = false; private ArrayList<NewsModel> news; // liste des news finale
//liste des sources private SortTypes sortType = SortTypes.relevancy; // critère de tri
private ArrayList<String> sources; private String query = ""; // critère de recherche de l'utilisateur
//liste des observers
private HashMap<String,EventObserver> observers;
//liste des news finale
private ArrayList<NewsModel> news;
//critère de tri
private SortTypes sortType = SortTypes.relevancy;
//critère de recherche de l'utilisateur
private String query = "";
private NewsListModel(String APIKey) { private NewsListModel(String APIKey) {
this.APIKey = APIKey; this.APIKey = APIKey;
//comme la liste des sources retournée par l'API est de 20 éléments max, pas la peine de déclarer une arraylist sans borne //comme la liste des sources retournée par l'API est de 20 éléments max, pas la peine de déclarer une arraylist sans borne
this.sources = new ArrayList<String>(20); this.sources = new ArrayList<String>(20);
this.observers = new HashMap<String,EventObserver>(); this.observers = new HashMap<String, EventObserver>();
this.news = new ArrayList<NewsModel>(); this.news = new ArrayList<NewsModel>();
} }
public static NewsListModel getInstance() { public static NewsListModel getInstance() {
if(NewsListModel.instance == null) {
if( NewsListModel.instance == null )
NewsListModel.instance = new NewsListModel("0e72f765c5c84313ae31a5a7e9e61735"); NewsListModel.instance = new NewsListModel("0e72f765c5c84313ae31a5a7e9e61735");
}
return NewsListModel.instance; return NewsListModel.instance;
} }
public void setCategory(Category cat) { public void setCategory(Category cat) {
if(cat == Category.all) { if( cat == Category.all ){
this.sources = null; this.sources = null;
this.cat = cat; this.cat = cat;
return; return;
} }
//on vide la liste des sources //on vide la liste des sources
this.sources = new ArrayList<String>(20); this.sources.clear();
this.cat = cat; this.cat = cat;
//on créé l'URL d'appel de l'API //on créé l'URL d'appel de l'API
String lang = LangModel.getInstance().getToLang().name(); String lang = LangModel.getInstance().getToLang().name();
String URL = "http://beta.newsapi.org/v2/sources?language="+lang; String URL = "http://beta.newsapi.org/v2/sources?language="+lang;
//on rajoute la catégorie //on rajoute la catégorie
if(cat != Category.all) { if( cat != Category.all )
URL += "&category="+cat.name(); URL += "&category="+cat.name();
}
//on rajoute la clé d'api //on rajoute la clé d'api
URL += "&apiKey="+this.APIKey; URL += "&apiKey="+this.APIKey;
//création de l'appel // Création de l'appel
ApiCall api = new ApiCall(URL,"GET",new Callback() { ApiCall api = new ApiCall(URL, "GET", new Callback(){
@Override @Override
public void onSuccess(JSONObject response) { public void onSuccess(JSONObject response) {
@ -101,7 +94,7 @@ public class NewsListModel implements Observable{
} }
@Override @Override
public void onError() { public void onError(String errDesc) {
//on notifie de l'échec et on garde en mémoire le fait que l'on a échoué (afin d'annuler la recherche de news qui va suivre) //on notifie de l'échec et on garde en mémoire le fait que l'on a échoué (afin d'annuler la recherche de news qui va suivre)
NewsListModel.this.isRetreivingSources = false; NewsListModel.this.isRetreivingSources = false;
NewsListModel.this.apiError = true; NewsListModel.this.apiError = true;
@ -110,6 +103,7 @@ public class NewsListModel implements Observable{
} }
}); });
this.isRetreivingSources = true; this.isRetreivingSources = true;
api.send(); api.send();
} }
@ -119,32 +113,15 @@ public class NewsListModel implements Observable{
} }
public void query(String q) { public void query(String q) {
//si recherche vide
if(q.isEmpty()) {
this.news = new ArrayList<NewsModel>();
NewsListModel.this.notifyObservers(new Event("NewsModel","NewsQuerySuccess"));
return;
}
//si la recherche de source s'est fini avec une erreur, pas la peine de chercher des articles //si la recherche de source s'est fini avec une erreur, pas la peine de chercher des articles
if(this.apiError) { if(this.apiError) {
NewsListModel.this.notifyObservers(new Event("NewsModel","NewsQueryFailed")); NewsListModel.this.notifyObservers(new Event("NewsModel","NewsQueryFailed"));
this.apiError = false; this.apiError = false;
return; return;
} }
this.query = q;
final String encodedQuery;
try {
encodedQuery = java.net.URLEncoder.encode(q,"UTF-8");
} catch (UnsupportedEncodingException e1) {
this.notifyObservers(new Event("NewsModel","NewsQueryFailed"));
return;
}
//on créer l'URL de l'appel //on créer l'URL de l'appel
String lang = LangModel.getInstance().getToLang().name(); String lang = LangModel.getInstance().getToLang().name();
String URL = "http://beta.newsapi.org/v2/everything?apiKey="+this.APIKey+"&language="+lang+"&q="+encodedQuery+"&sortBy="+this.sortType.name(); String URL = "http://beta.newsapi.org/v2/everything?apiKey="+this.APIKey+"&language="+lang+"&q="+q+"&sortBy="+this.sortType.name();
//on ajoute la liste des sources a l'URL de la requete //on ajoute la liste des sources a l'URL de la requete
if(NewsListModel.this.sources != null && NewsListModel.this.sources.size() != 0) { if(NewsListModel.this.sources != null && NewsListModel.this.sources.size() != 0) {
@ -157,57 +134,10 @@ public class NewsListModel implements Observable{
URL += sources; URL += sources;
} }
ApiCall api = new ApiCall(URL,"GET",new Callback() { ApiCall api = new ApiCall(URL,
"GET",
@Override new fetchArticles(this, q)
public void onSuccess(JSONObject response) { );
//on parcours le JSON en créant les objets NewsModel corespondant
NewsListModel.this.news = new ArrayList<NewsModel>();
JSONArray arr = response.getJSONArray("articles");
for(int i = 0;i<arr.length();i++) {
JSONObject jsonNews = (JSONObject)arr.get(i);
NewsModel news = new NewsModel();
news.setAuthor(jsonNews.getString("author"))
.setDescription(jsonNews.getString("description"))
.setTitle(jsonNews.getString("title"))
.setNewsURL(jsonNews.getString("url"))
.setImageURL(jsonNews.getString("urlToImage"))
.setSource(jsonNews.getJSONObject("source").getString("name"))
.addTag(NewsListModel.this.cat);
try {
news.setDate(jsonNews.getString("publishedAt"));
}catch (ParseException e) {
news.setDate(new Date());
}
if(NewsListModel.this.query == q) {
NewsListModel.this.news.add(news);
}else {
return;
}
}
if(NewsListModel.this.query == q) {
//ne pas oublier d'enlever l'api des observer, sinon il y a des risques de récurrence
NewsListModel.this.removeObserver("newsApiCall");
NewsListModel.this.notifyObservers(new Event("NewsModel","NewsQuerySuccess"));
}else {
return;
}
}
@Override
public void onError() {
//L'appel a échoué :(
System.out.println("Error");
NewsListModel.this.removeObserver("newsApiCall");
NewsListModel.this.notifyObservers(new Event("NewsModel","NewsQueryFailed"));
}
});
//on delay uniquement si on est en train de récupérer les sources //on delay uniquement si on est en train de récupérer les sources
if(this.isRetreivingSources) { if(this.isRetreivingSources) {
@ -224,7 +154,7 @@ public class NewsListModel implements Observable{
String lang = LangModel.getInstance().getToLang().name(); String lang = LangModel.getInstance().getToLang().name();
String URL = "http://beta.newsapi.org/v2/everything?apiKey="+NewsListModel.this.APIKey+"&language="+lang String URL = "http://beta.newsapi.org/v2/everything?apiKey="+NewsListModel.this.APIKey+"&language="+lang
+"&q="+encodedQuery+"&sortBy="+NewsListModel.this.sortType.name(); +"&q="+q+"&sortBy="+NewsListModel.this.sortType.name();
//on ajoute la liste des sources a l'URL de la requete //on ajoute la liste des sources a l'URL de la requete
if(NewsListModel.this.sources != null && NewsListModel.this.sources.size() != 0) { if(NewsListModel.this.sources != null && NewsListModel.this.sources.size() != 0) {
@ -259,9 +189,12 @@ public class NewsListModel implements Observable{
} }
} }
public void setQuery(String query){
this.query = query;
}
public String getQuery() { public void setNews(ArrayList<NewsModel> news){
return this.query; this.news = news;
} }
public ArrayList<NewsModel> getNews(){ public ArrayList<NewsModel> getNews(){

View File

@ -69,7 +69,7 @@ public class NewsModel {
return description; return description;
} }
public NewsModel setDescription(String description) { public NewsModel setDescription(String description) {
this.description = description+"\n\n"; this.description = description;
return this; return this;
} }
public Date getDate() { public Date getDate() {

View File

@ -1,170 +0,0 @@
package model;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import org.json.JSONObject;
import Classes.ApiCall;
import Classes.Event;
import Interfaces.Callback;
import Interfaces.EventObserver;
import Interfaces.Observable;
import javafx.util.Pair;
public class TraductionModel implements Observable {
private HashMap<String,EventObserver> observers;
private static TraductionModel instance;
private ArrayList<Pair<WordTraductionModel,WordTraductionModel>> translations;
private ArrayList<Pair<WordTraductionModel,WordTraductionModel>> usages;
private TraductionModel() {
this.observers = new HashMap<String,EventObserver>();
}
public static TraductionModel getInstance() {
if(TraductionModel.instance == null) {
TraductionModel.instance = new TraductionModel();
}
return TraductionModel.instance;
}
public void query(String search) {
//si recherche vide
if(search.isEmpty()) {
this.translations = new ArrayList<Pair<WordTraductionModel,WordTraductionModel>>();
this.usages = new ArrayList<Pair<WordTraductionModel,WordTraductionModel>>();
this.notifyObservers(new Event("DictionaryModel","WordQuerySuccess"));
return;
}
final String encodedQuery;
try {
encodedQuery = java.net.URLEncoder.encode(search,"UTF-8");
} catch (UnsupportedEncodingException e1) {
this.notifyObservers(new Event("DictionaryModel","WordQueryFailed"));
return;
}
HashMap<String,String> headers = new HashMap<String,String>();
//si on ne met pas ce header l'API refuse de répondre
headers.put("Referer", "http://www.wordreference.com");
String dic = LangModel.getInstance().getFromLang().name()+LangModel.getInstance().getToLang().name();
ApiCall call = new ApiCall("http://api.wordreference.com/1/json/"+dic+"/"+encodedQuery,"GET",new Callback() {
@Override
public void onSuccess(JSONObject response) {
try {
//on reset le contenu du modele
TraductionModel.this.translations = new ArrayList<Pair<WordTraductionModel,WordTraductionModel>>();
TraductionModel.this.usages = new ArrayList<Pair<WordTraductionModel,WordTraductionModel>>();
if(response.has("Error")) {
//pas de résultat
TraductionModel.this.notifyObservers(new Event("DictionaryModel","WordQueryFailed"));
}else{
//Traitement des traductions principales
TraductionModel.this.translations.addAll(
TraductionModel.this.computeJSON(
response.getJSONObject("term0").getJSONObject("PrincipalTranslations")
)
);
//Traitement des traductions secondaires
if(response.getJSONObject("term0").has("AdditionalTranslations")) {
TraductionModel.this.translations.addAll(
TraductionModel.this.computeJSON(
response.getJSONObject("term0").getJSONObject("AdditionalTranslations")
)
);
}
//traitement des usages
TraductionModel.this.usages.addAll(
TraductionModel.this.computeJSON(
response.getJSONObject("original").getJSONObject("Compounds")
)
);
TraductionModel.this.notifyObservers(new Event("DictionaryModel","WordQuerySuccess"));
}
}catch(Exception e) {
e.printStackTrace();
}
}
@Override
public void onError() {
TraductionModel.this.notifyObservers(new Event("DictionaryModel","WordQueryFailed"));
}
});
call.addHeaders(headers);
call.send();
}
private ArrayList<Pair<WordTraductionModel,WordTraductionModel>> computeJSON(JSONObject container){
ArrayList<Pair<WordTraductionModel,WordTraductionModel>> returned = new ArrayList<Pair<WordTraductionModel,WordTraductionModel>>();
for (Object key : container.keySet()) {
//get original term
WordTraductionModel term = new WordTraductionModel();
JSONObject jterm = container.getJSONObject((String)key).getJSONObject("OriginalTerm");
term.setWord(jterm.getString("term"))
.setPOS(jterm.getString("POS"))
.setSense(jterm.getString("sense"))
.setUsage(jterm.getString("term"));
//get traduction
WordTraductionModel trad = new WordTraductionModel();
jterm = container.getJSONObject((String)key).getJSONObject("FirstTranslation");
term.setWord(jterm.getString("term"))
.setPOS(jterm.getString("POS"))
.setSense(jterm.getString("sense"))
.setUsage(jterm.getString("term"));
returned.add(new Pair<WordTraductionModel,WordTraductionModel>(term,trad));
}
return returned;
}
public ArrayList<Pair<WordTraductionModel,WordTraductionModel>> getTranslations(){
return this.translations;
}
public ArrayList<Pair<WordTraductionModel,WordTraductionModel>> getUsages(){
return this.usages;
}
@Override
public void addObserver(String key, EventObserver o) {
this.observers.put(key, o);
}
@Override
public void removeObserver(String key) {
this.observers.remove(key);
}
@Override
public void notifyObservers(Event e) {
for(Object key : this.observers.keySet().toArray()) {
this.observers.get(key).handleEvent(e);
}
}
}

View File

@ -1,40 +0,0 @@
package model;
public class WordTraductionModel {
private String word;
private String POS;
private String sense;
private String usage;
public String getWord() {
return word;
}
public WordTraductionModel setWord(String word) {
this.word = word;
return this;
}
public String getPOS() {
return POS;
}
public WordTraductionModel setPOS(String pOS) {
POS = pOS;
return this;
}
public String getSense() {
return sense;
}
public WordTraductionModel setSense(String sense) {
this.sense = sense;
return this;
}
public String getUsage() {
return usage;
}
public WordTraductionModel setUsage(String usage) {
this.usage = usage;
return this;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 597 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 505 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 644 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 461 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 457 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 968 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 846 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 457 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 431 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 404 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 697 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 269 B