Skip to content

Commit

Permalink
Fixes #495
Browse files Browse the repository at this point in the history
Fixes #133
needs further improvment
  • Loading branch information
1-alex98 committed Jun 12, 2017
1 parent 8d91b85 commit 33e01d1
Show file tree
Hide file tree
Showing 7 changed files with 211 additions and 7 deletions.
138 changes: 134 additions & 4 deletions src/main/java/com/faforever/client/chat/ChatController.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,50 @@
import com.faforever.client.chat.event.ChatMessageEvent;
import com.faforever.client.fx.AbstractViewController;
import com.faforever.client.fx.JavaFxUtil;
import com.faforever.client.fx.WindowController;
import com.faforever.client.fx.WindowController.WindowButtonType;
import com.faforever.client.i18n.I18n;
import com.faforever.client.net.ConnectionState;
import com.faforever.client.theme.UiService;
import com.faforever.client.user.UserService;
import com.faforever.client.user.event.LoggedOutEvent;
import com.faforever.client.util.ProgrammingError;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import com.sun.glass.ui.Robot;
import javafx.application.Platform;
import javafx.beans.InvalidationListener;
import javafx.collections.ListChangeListener;
import javafx.geometry.Insets;
import javafx.scene.Cursor;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TextField;
import javafx.scene.image.WritableImage;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.DataFormat;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.scene.transform.Transform;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.inject.Inject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
Expand All @@ -38,19 +61,26 @@ public class ChatController extends AbstractViewController<Node> {
private final UiService uiService;
private final UserService userService;
private final EventBus eventBus;
private final I18n i18n;
private final Robot robot;
public Node chatRoot;
public TabPane tabPane;
public Pane connectingProgressPane;
public VBox noOpenTabsContainer;
public TextField channelNameTextField;
public ArrayList<String> outSourcedChannels;

@Inject
public ChatController(ChatService chatService, UiService uiService, UserService userService, EventBus eventBus) {
public ChatController(ChatService chatService, UiService uiService, UserService userService, EventBus eventBus, I18n i18n) {
this.chatService = chatService;
this.uiService = uiService;
this.i18n = i18n;
this.userService = userService;
this.eventBus = eventBus;

robot =
com.sun.glass.ui.Application.GetApplication().createRobot();

nameToChatTabController = new HashMap<>();
}

Expand Down Expand Up @@ -105,14 +135,83 @@ private AbstractChatTabController getOrCreateChannelTab(String channelName) {
private void addTab(String playerOrChannelName, AbstractChatTabController tabController) {
JavaFxUtil.assertApplicationThread();
nameToChatTabController.put(playerOrChannelName, tabController);
tabPane.getTabs().add(tabController.getRoot());
Tab newTab = tabController.getRoot();
MenuItem menuItem = new MenuItem(i18n.get("chat.popOutTab"));
ContextMenu menu = new ContextMenu(menuItem);
menu.setOnAction(event -> showSeperateWindow(newTab));
newTab.setContextMenu(menu);
tabPane.getTabs().add(newTab);
}

private void showSeperateWindow(Tab newTab) {
Stage stage = new Stage(StageStyle.UNDECORATED);
outSourcedChannels.add(newTab.getId());
Pane content = (Pane) newTab.getContent();
tabPane.getTabs().remove(newTab);
newTab.setContent(null);
final Scene scene = new Scene(new Pane(content), content.getWidth(), content.getHeight());
stage.setScene(scene);
stage.setTitle(newTab.getText());

Screen screen = Screen.getScreensForRectangle(robot.getMouseX(), robot.getMouseY(), 1, 1).get(0);
stage.setX(screen.getVisualBounds().getMinX());
stage.setY(screen.getVisualBounds().getMinY());

assureCorrectLayout(content, scene);

WindowController windowController = uiService.loadFxml("theme/window.fxml");
windowController.configure(scene, stage, true, WindowButtonType.CLOSE, WindowButtonType.MAXIMIZE_RESTORE, WindowButtonType.MINIMIZE);
windowController.setOnClose(this.new closureHandler(newTab, content, stage));

stage.show();
}

public void detectDrages() {
tabPane.setOnDragDetected(
event -> {
Tab selectedTab = ((TabPane) event.getSource()).getSelectionModel().getSelectedItem();
if (((Text) event.getTarget()).getText().equals(selectedTab.getText())) {
tabPane.setCursor(Cursor.MOVE);
Pane root = (Pane) tabPane.getScene().getRoot();
root.setOnDragOver((DragEvent event1) -> {
event1.acceptTransferModes(TransferMode.ANY);
event1.consume();
});
SnapshotParameters snapshotParams = new SnapshotParameters();
snapshotParams.setTransform(Transform.scale(0.4, 0.4));
WritableImage snapshot = selectedTab.getContent().snapshot(snapshotParams, null);
Dragboard db = tabPane.startDragAndDrop(TransferMode.MOVE);
ClipboardContent clipboardContent = new ClipboardContent();
clipboardContent.put(DataFormat.PLAIN_TEXT, "");
db.setDragView(snapshot, 40, 40);
db.setContent(clipboardContent);
}
event.consume();
}
);

tabPane.setOnDragDone(
(DragEvent event) -> {
showSeperateWindow(((TabPane) event.getSource()).getSelectionModel().getSelectedItem());
tabPane.setCursor(Cursor.DEFAULT);
event.consume();
}
);
}

private void assureCorrectLayout(Region content, Scene scene) {
content.setPadding(new Insets(20));
content.setPrefWidth(scene.getWidth());
content.setPrefHeight(scene.getHeight());
scene.widthProperty().addListener((observable, oldValue, newValue) -> content.setPrefWidth((Double) newValue));
scene.heightProperty().addListener((observable, oldValue, newValue) -> content.setPrefHeight((Double) newValue));
}

@Override
public void initialize() {
super.initialize();
eventBus.register(this);

outSourcedChannels = new ArrayList<String>();
tabPane.getTabs().addListener((InvalidationListener) observable ->
noOpenTabsContainer.setVisible(tabPane.getTabs().isEmpty()));

Expand All @@ -130,16 +229,25 @@ public void initialize() {

tabPane.getTabs().addListener((ListChangeListener<Tab>) change -> {
while (change.next()) {
change.getRemoved().forEach(tab -> nameToChatTabController.remove(tab.getId()));
change.getRemoved().forEach(tab -> {
if (!outSourcedChannels.contains(tab.getId())) {
nameToChatTabController.remove(tab.getId());
}
});
}
});
detectDrages();
}

@Subscribe
public void onLoggedOutEvent(LoggedOutEvent event) {
onLoggedOut();
}

private void sortTabs() {
//TODO: sort so that the + tab is at the end again, can only be done after merging of the other branch
}

private void onConnectionStateChange(ConnectionState newValue) {
switch (newValue) {
case DISCONNECTED:
Expand Down Expand Up @@ -254,4 +362,26 @@ protected void onHide() {
Optional.ofNullable(nameToChatTabController.get(tab.getId())).ifPresent(AbstractChatTabController::onHide);
}
}

protected class closureHandler implements Runnable {
private Stage stage;
private Pane content;
private Tab newTab;

protected closureHandler(Tab newTab, Pane content, Stage stage) {
this.newTab = newTab;
this.content = content;
this.stage = stage;
}

@Override
public void run() {
content.setPadding(Insets.EMPTY);
newTab.setContent(content);
tabPane.getTabs().add(newTab);
sortTabs();
outSourcedChannels.remove(newTab.getId());
stage.close();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import org.pircbotx.User;
import org.pircbotx.UserHostmask;
import org.pircbotx.UtilSSLSocketFactory;
import org.pircbotx.exception.DaoException;
import org.pircbotx.exception.IrcException;
import org.pircbotx.hooks.Event;
import org.pircbotx.hooks.events.ActionEvent;
Expand Down Expand Up @@ -498,7 +499,11 @@ public void removeUsersListener(String channelName, MapChangeListener<String, Ch

@Override
public void leaveChannel(String channelName) {
pircBotX.getUserChannelDao().getChannel(channelName).send().part();
try {
pircBotX.getUserChannelDao().getChannel(channelName).send().part();
} catch (DaoException e) {
logger.warn("Channel did not exist: ", e);
}
}

@Override
Expand Down
64 changes: 64 additions & 0 deletions src/main/java/com/faforever/client/fx/WindowController.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.faforever.client.fx;

import com.faforever.client.theme.UiService;
import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.css.PseudoClass;
import javafx.event.EventHandler;
Expand Down Expand Up @@ -53,6 +54,10 @@ public class WindowController implements Controller<Node> {
private Point2D dragOffset;
private EnumSet<ResizeDirection> resizeDirections;
private boolean isResizing;
private double initialX;
private double initialY;
private Runnable closureRunnable;
private boolean movable = false;

@Inject
public WindowController(UiService uiService) {
Expand Down Expand Up @@ -82,9 +87,16 @@ public void onMinimizeButtonClicked() {
}

public void onCloseButtonClicked() {
if (closureRunnable != null) {
Platform.runLater(closureRunnable);
}
stage.close();
}

public void setOnClose(Runnable runnable) {
closureRunnable = runnable;
}

public void onRestoreButtonClicked() {
restore();
}
Expand Down Expand Up @@ -359,6 +371,58 @@ public void onMouseExited() {
windowRoot.setCursor(Cursor.DEFAULT);
}

public void configure(Scene scene, Stage stage, boolean resizable, WindowButtonType... buttons) {
if (this.stage != null) {
throw new IllegalStateException("Already configured");
}

this.stage = stage;
this.resizable = resizable;
Region content = (Region) scene.getRoot();
scene.setRoot(windowRoot);

stage.setScene(scene);
uiService.registerScene(scene);

// Configure these only once per stage
if (!stage.getProperties().containsKey(PROPERTY_WINDOW_DECORATOR)) {
stage.getProperties().put(PROPERTY_WINDOW_DECORATOR, this);
stage.iconifiedProperty().addListener((observable, oldValue, newValue) -> {
if (!newValue && stage.isMaximized()) {
maximize();
}
});
}

maximizeButton.managedProperty().bind(maximizeButton.visibleProperty());
restoreButton.managedProperty().bind(restoreButton.visibleProperty());

List<WindowButtonType> buttonList = Arrays.asList(buttons);

if (!resizable) {
maximizeButton.setVisible(false);
restoreButton.setVisible(false);
} else if (buttonList.contains(MAXIMIZE_RESTORE)) {
maximizeButton.visibleProperty().bind(stage.maximizedProperty().not());
restoreButton.visibleProperty().bind(stage.maximizedProperty());
} else {
maximizeButton.setVisible(false);
restoreButton.setVisible(false);
}

minimizeButton.setVisible(buttonList.contains(MINIMIZE));
closeButton.setVisible(buttonList.contains(CLOSE));
resizeDirections = EnumSet.noneOf(ResizeDirection.class);

if (stage.isMaximized()) {
maximize();
} else {
restore();
}

setContent(content);
}

public enum WindowButtonType {
MINIMIZE,
MAXIMIZE_RESTORE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ public void onSettingsSelected() {
SettingsController settingsController = uiService.loadFxml("theme/settings/settings.fxml");
WindowController windowController = uiService.loadFxml("theme/window.fxml");
windowController.configure(stage, settingsController.getRoot(), true, CLOSE);
windowController.setOnHiding(event -> preferencesService.storeInBackground());
windowController.setOnClose(preferencesService::storeInBackground);

stage.setTitle(i18n.get("settings.windowTitle"));
stage.show();
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/i18n/messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -572,3 +572,4 @@ reviewScore.four=4
reviewScore.three=3
reviewScore.two=2
reviewScore.one=1
chat.popOutTab=show in seperate window
1 change: 1 addition & 0 deletions src/main/resources/i18n/messages_de_DE.properties
Original file line number Diff line number Diff line change
Expand Up @@ -597,3 +597,4 @@ mapVault.mostPlayed=Meist gespielt
minuteAgo=Vor {0,number,#} Minuten
hourAgo=Vor {0,number,#} Stunden
monthAgo=Vor {0,number,#} Monaten
chat.popOutTab=seperat anzeigen
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.faforever.client.chat;

import com.faforever.client.chat.event.ChatMessageEvent;
import com.faforever.client.i18n.I18n;
import com.faforever.client.net.ConnectionState;
import com.faforever.client.test.AbstractPlainJavaFxTest;
import com.faforever.client.theme.UiService;
Expand Down Expand Up @@ -56,6 +57,8 @@ public class ChatControllerTest extends AbstractPlainJavaFxTest {
private ChatService chatService;
@Mock
private EventBus eventBus;
@Mock
private I18n i18n;
@Captor
private ArgumentCaptor<MapChangeListener<String, Channel>> channelsListener;
@Captor
Expand All @@ -66,7 +69,7 @@ public class ChatControllerTest extends AbstractPlainJavaFxTest {

@Before
public void setUp() throws Exception {
instance = new ChatController(chatService, uiService, userService, eventBus);
instance = new ChatController(chatService, uiService, userService, eventBus, i18n);

connectionState = new SimpleObjectProperty<>(ConnectionState.DISCONNECTED);

Expand Down

0 comments on commit 33e01d1

Please sign in to comment.