Skip to content

Commit

Permalink
Added GUI
Browse files Browse the repository at this point in the history
  • Loading branch information
octaviospain committed May 22, 2017
1 parent 0ac9236 commit a6300ea
Show file tree
Hide file tree
Showing 8 changed files with 210 additions and 8 deletions.
File renamed without changes.
1 change: 1 addition & 0 deletions run-gui.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mvn package && mvn exec:java -D exec.mainClass="cuni.software.ViewRunner"
120 changes: 120 additions & 0 deletions src/main/java/cuni/software/Controller.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package cuni.software;

import javafx.application.*;
import javafx.beans.property.*;
import javafx.collections.*;
import javafx.fxml.*;
import javafx.scene.control.*;
import javafx.scene.control.SpinnerValueFactory.*;
import javafx.stage.*;
import javafx.stage.FileChooser.*;
import javafx.util.converter.*;

import java.io.*;
import java.util.*;
import java.util.stream.*;

/**
* @author Octavio Calleya
*/
public class Controller {

@FXML
private TextField searchField;
@FXML
private ListView<Hyperlink> listView;
@FXML
private Button searchButton;
@FXML
private Button loadButton;
@FXML
private TextArea textArea;
@FXML
private Spinner<Double> similaritySpinner;

private HostServices hostServices;
private BooleanProperty searchingProperty = new SimpleBooleanProperty(false);
private SearchEngine searchEngine = new SearchEngine();
private List<RssFeed> loadedRssFeeds;

@FXML
public void initialize() {
searchButton.disableProperty().bind(searchingProperty.not().and(searchField.textProperty().isEmpty()));
loadButton.disableProperty().bind(searchingProperty);
loadButton.setOnAction(e -> loadRssFromFile());
searchButton.setOnAction(e -> performSearch());
DoubleSpinnerValueFactory doubleSpinnerValueFactory = new DoubleSpinnerValueFactory(1.550, 1.575);
doubleSpinnerValueFactory.setAmountToStepBy(0.00025);
doubleSpinnerValueFactory.setConverter(new DoubleStringConverter());
similaritySpinner.setValueFactory(doubleSpinnerValueFactory);
}

private void performSearch() {
new Thread(() -> {
Double similarityValue = similaritySpinner.getValue();
List<Article> relatedArticles = searchEngine.findRelatedArticles(searchField.getText(), similarityValue);
Platform.runLater(() -> log("Found " + relatedArticles.size() + " articles"));
addArticlesToList(relatedArticles);
}).start();
}

private void addArticlesToList(List<Article> articles) {
Platform.runLater(() -> {
ObservableList<Hyperlink> links = FXCollections.observableArrayList();
articles.forEach(article -> {
Hyperlink link = new Hyperlink(article.getUri());
link.setOnAction(e -> hostServices.showDocument(article.getUri()));
links.add(link);
});
listView.setItems(links);
});
}

private void loadRssFromFile() {
FileChooser chooser = new FileChooser();
chooser.setTitle("Select file...");
chooser.getExtensionFilters().add(new ExtensionFilter("Text Files", "*.txt"));
File feedsFile = chooser.showOpenDialog(searchField.getScene().getWindow());
if (feedsFile != null) {
new Thread(() -> loadTask(feedsFile)).start();
log("Importing feeds...");
searchingProperty.setValue(true);
}
}

private void loadTask(File feedsFile) {
try {
loadedRssFeeds = RssFeedParse.fromFile(feedsFile);
printParsedFeeds();
addToSearchEngine();
}
catch (IOException e) {
log("Error loading rss feeds from file: " + e.getMessage());
}
finally {
Platform.runLater(() -> searchingProperty.setValue(false));
}
}

private void addToSearchEngine() {
List<Article> allArticles = loadedRssFeeds.stream()
.flatMap(feed -> feed.getArticles().stream())
.collect(Collectors.toList());
searchEngine.addArticles(allArticles);
}

private void printParsedFeeds() {
loadedRssFeeds.forEach(feed -> {
log("\t\t" + feed.getUrl().toString() + "\n\tLoaded articles:");
feed.getArticles().forEach(article -> log(article.toString()));
});
}

public void setHostServices(HostServices hostServices) {
this.hostServices = hostServices;
}

public void log(String message) {
Platform.runLater(() -> textArea.appendText(message + "\n"));
}
}
2 changes: 1 addition & 1 deletion src/main/java/cuni/software/CustomArticleFinderRunner.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public static void main(String[] args) {
menu();
} else if (query.startsWith("search query ")) {
try {
List<Article> relatedArticles = searchEngine.findRelatedArticles(query.substring(13));
List<Article> relatedArticles = searchEngine.findRelatedArticles(query.substring(13), 1.6);
System.out.println("Found " + relatedArticles.size() + " articles");
relatedArticles.forEach(article -> System.out.println(article.getUri()));
}
Expand Down
10 changes: 6 additions & 4 deletions src/main/java/cuni/software/RecursiveSearch.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,18 @@ public class RecursiveSearch extends RecursiveTask<List<Article>> {

private static final int MAX_COMPARING_ARTICLES = 10;
private static final int NUMBER_OF_PARTITIONS = 6;
private static final double SIMILARITY_THRESHOLD = 1.514;

private Article queryArticle;
private Set<String> terms;
private List<Article> articles;
private double similarityThreshold;
private List<Article> foundArticles = new ArrayList<>();

public RecursiveSearch(Article queryArticle, List<Article> articles, Set<String> terms) {
public RecursiveSearch(Article queryArticle, List<Article> articles, Set<String> terms, double threshold) {
this.queryArticle = queryArticle;
this.terms = terms;
this.articles = articles;
this.similarityThreshold = threshold;
}

@Override
Expand All @@ -32,7 +33,7 @@ protected List<Article> compute() {
else {
articles.forEach(article -> {
double cosineSimilarity = cosineSimilarity(queryArticle, article);
if (cosineSimilarity < SIMILARITY_THRESHOLD)
if (cosineSimilarity < similarityThreshold)
foundArticles.add(article);
});
}
Expand All @@ -43,7 +44,8 @@ private void forkIntoSubActions() {
int subListsSize = articles.size() / NUMBER_OF_PARTITIONS;
List<RecursiveSearch> subSearches = Lists.partition(articles, subListsSize)
.stream()
.map(articlesSubList -> new RecursiveSearch(queryArticle, articlesSubList, terms))
.map(articlesSubList -> new RecursiveSearch(queryArticle, articlesSubList,
terms, similarityThreshold))
.collect(ImmutableList.toImmutableList());
subSearches.forEach(RecursiveTask::fork);
subSearches.forEach(action -> foundArticles.addAll(action.join()));
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/cuni/software/SearchEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,16 @@ public void addArticles(Collection<Article> newArticles) {
computeStatistics(newArticles);
}

public List<Article> findRelatedArticles(String query) {
public List<Article> findRelatedArticles(String query, double similarityThreshold) {
Article queryArticle = new Article("");
Set<String> queryTerms = new HashSet<>();
StringTokenizer stk = new StringTokenizer(query, " ");
StringTokenizer stk = new StringTokenizer(query.toLowerCase(), " ");
while (stk.hasMoreElements())
queryTerms.add(stk.nextToken().toLowerCase());
queryArticle.addTerms(queryTerms);

ForkJoinPool forkJoinPool = new ForkJoinPool(6);
RecursiveSearch recursiveSearch = new RecursiveSearch(queryArticle, articles, termStatistics.keySet());
RecursiveSearch recursiveSearch = new RecursiveSearch(queryArticle, articles, termStatistics.keySet(), similarityThreshold);
return forkJoinPool.invoke(recursiveSearch);
}

Expand Down
32 changes: 32 additions & 0 deletions src/main/java/cuni/software/ViewRunner.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package cuni.software;

import javafx.application.*;
import javafx.fxml.*;
import javafx.scene.*;
import javafx.scene.layout.*;
import javafx.stage.*;

/**
* @author Octavio Calleya
*/
public class ViewRunner extends Application {

private Controller controller;

public static void main(String[] args){
launch();
}

@Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/view.fxml"));
BorderPane root = loader.load();
controller = loader.getController();
controller.setHostServices(getHostServices());
primaryStage.setScene(new Scene(root));
primaryStage.setMinWidth(750);
primaryStage.setMinHeight(520);
primaryStage.setTitle("Custom article finder");
primaryStage.show();
}
}
47 changes: 47 additions & 0 deletions src/main/resources/view.fxml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>


<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="500.0" prefWidth="750.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="cuni.software.Controller">
<top>
<HBox BorderPane.alignment="CENTER">
<BorderPane.margin>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
</BorderPane.margin>
<children>
<TextField fx:id="searchField" HBox.hgrow="SOMETIMES" />
<Button fx:id="searchButton" mnemonicParsing="false" text="Search">
<HBox.margin>
<Insets left="10.0" />
</HBox.margin>
</Button>
<Button fx:id="loadButton" mnemonicParsing="false" text="Load feeds from file">
<HBox.margin>
<Insets left="10.0" />
</HBox.margin>
</Button>
<Spinner fx:id="similaritySpinner" prefWidth="120.0">
<HBox.margin>
<Insets left="10.0" />
</HBox.margin>
</Spinner>
</children>
</HBox>
</top>
<center>
<ListView fx:id="listView" minHeight="-Infinity" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<BorderPane.margin>
<Insets bottom="20.0" left="20.0" right="20.0" />
</BorderPane.margin>
</ListView>
</center>
<bottom>
<TextArea fx:id="textArea" editable="false" minHeight="-Infinity" prefHeight="150.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<BorderPane.margin>
<Insets bottom="20.0" left="20.0" right="20.0" />
</BorderPane.margin>
</TextArea>
</bottom>
</BorderPane>

0 comments on commit a6300ea

Please sign in to comment.