package ru.testing.client.controllers; import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; import javafx.collections.transformation.FilteredList; import javafx.concurrent.Task; import javafx.fxml.FXML; import javafx.scene.control.Button; import javafx.scene.control.*; import javafx.scene.control.Label; import javafx.scene.control.MenuBar; import javafx.scene.control.MenuItem; import javafx.scene.control.TextField; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; import javafx.scene.input.KeyCombination; import javafx.scene.layout.StackPane; import javafx.scene.layout.TilePane; import org.controlsfx.control.textfield.CustomTextField; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ru.testing.client.common.FilesOperations; import ru.testing.client.common.HttpTypes; import ru.testing.client.common.objects.*; import ru.testing.client.common.properties.AppProperties; import ru.testing.client.elements.http.settings.HttpSettingsPopOver; import ru.testing.client.elements.tabs.*; import ru.testing.client.websocket.ReceivedMessageFormat; import ru.testing.client.websocket.WsClient; import java.awt.*; import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.List; import static org.controlsfx.tools.Platform.OSX; import static ru.testing.client.MainApp.getPrimaryStage; /** * FXML controller for main page */ public class MainController { private static final Logger LOGGER = LoggerFactory.getLogger(MainController.class); private final ObservableList<HttpTypes> httpTypes = FXCollections.observableArrayList(); private final org.controlsfx.tools.Platform platform = org.controlsfx.tools.Platform.getCurrent(); private final KeyCombination.Modifier keyModifier = (platform == OSX) ? KeyCombination.META_DOWN : KeyCombination.CONTROL_DOWN; private List<WsClient> wsClients = new ArrayList<>(); private AppProperties properties = AppProperties.getAppProperties(); private NewClientTab newClientTab = new NewClientTab(); private HttpSettingsPopOver httpSettingsPopOver; private SettingsTab settingsTab; @FXML private MenuBar menuBar; @FXML private TilePane connectTilePane; @FXML private ComboBox<HttpTypes> httpTypesComboBox; @FXML private CustomTextField serverUrl; @FXML private Label urlCleaner; @FXML private ToggleButton httpSettings; @FXML private Button connectionButton; @FXML private TabPane tabPane; @FXML private MenuItem saveOutputMenu; @FXML private MenuItem settingsMenu; @FXML private MenuItem exitAppMenu; @FXML private MenuItem nextTab; @FXML private MenuItem prevTab; @FXML private MenuItem closeTab; @FXML private MenuItem closeAllTabs; @FXML private ProgressBar progress; /** * Method run then this controller initialize */ @FXML protected void initialize() { // Close application getPrimaryStage().setOnCloseRequest((event -> exitApplication())); // Tabs change listener tabPane.getTabs().add(newClientTab); tabPane.getTabs().addListener((ListChangeListener<? super Tab>) c -> { if (c.next()) { final StackPane header = (StackPane) tabPane.lookup(".tab-header-area"); if (header != null) { if (tabPane.getTabs().size() == 1) { header.setStyle("-fx-pref-height: 0"); } else { header.setStyle("-fx-pref-height: 30"); } } } }); tabPane.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> { HttpSettingsController httpController = getHttpSettingsPopOver().getHttpSettingsController(); // Save inserted last values in 'new' tab if (oldValue instanceof NewClientTab) { newClientTab.setPrevType(httpTypesComboBox.getSelectionModel().getSelectedItem()); newClientTab.setPrevHeaders(httpController.getHeadersList()); newClientTab.setPrevHttpParams(httpController.getHttpParametersList()); newClientTab.setPrevUrl(serverUrl.getText()); } // Set data for new tab if (newValue instanceof NewClientTab) { connectTilePane.setDisable(false); httpTypesComboBox.setDisable(false); httpSettings.setDisable(false); serverUrl.setEditable(true); urlCleaner.setDisable(false); updateConnectionButtonName(); // Set previous data httpTypesComboBox.getSelectionModel().select(newClientTab.getPrevType()); httpController.getHeadersList().clear(); httpController.getHeadersList().addAll(newClientTab.getPrevHeaders()); httpController.getHttpParametersList().clear(); httpController.getHttpParametersList().addAll(newClientTab.getPrevHttpParams()); serverUrl.setText(newClientTab.getPrevUrl()); } else if (newValue instanceof SettingsTab || newValue instanceof WsMessageTab) { connectTilePane.setDisable(true); } else if (newValue instanceof WsMessagesTab) { connectTilePane.setDisable(false); httpTypesComboBox.setDisable(true); httpTypesComboBox.getSelectionModel().select(HttpTypes.WEBSOCKET); httpSettings.setDisable(true); urlCleaner.setDisable(true); // Set ws client data ((WsMessagesTab) newValue).getController().checkConnectionStatus(); serverUrl.setText(((WsMessagesTab) newValue).getServerUrl()); serverUrl.setEditable(false); } else if (newValue instanceof RestTab) { connectTilePane.setDisable(false); httpTypesComboBox.setDisable(true); httpSettings.setDisable(false); serverUrl.setEditable(false); urlCleaner.setDisable(true); connectionButton.setDisable(false); // Set request data TabRestController restController = ((RestTab) newValue).getController(); serverUrl.setText(restController.getServerUrl()); httpTypesComboBox.getSelectionModel().select(restController.getHttpType()); httpController.getHeadersList().clear(); httpController.getHeadersList().addAll(restController.getHeaders()); httpController.getHttpParametersList().clear(); httpController.getHttpParametersList().addAll(restController.getParameters()); connectionButton.setText("Send"); } }); // Http clients types httpTypes.addAll(HttpTypes.values()); httpTypesComboBox.setItems(httpTypes); httpTypesComboBox.getSelectionModel().select(0); httpTypesComboBox.valueProperty().addListener((observable, oldValue, newValue) -> { HttpSettingsController controller = getHttpSettingsPopOver().getHttpSettingsController(); TitledPane paramsPane = controller.getParametersPane(); TitledPane headersPane = controller.getHeadersPane(); if (newValue != HttpTypes.WEBSOCKET) { paramsPane.setVisible(true); paramsPane.setManaged(true); headersPane.setCollapsible(true); } else { controller.getAccordion().setExpandedPane(headersPane); headersPane.setCollapsible(false); paramsPane.setVisible(false); paramsPane.setManaged(false); } updateConnectionButtonName(); validateServerUrl(); }); // Set hot keys setHotKey(closeTab, KeyCode.W); setHotKey(closeAllTabs, KeyCode.W, KeyCombination.SHIFT_DOWN); setHotKey(nextTab, KeyCode.RIGHT); setHotKey(prevTab, KeyCode.LEFT); setHotKey(exitAppMenu, KeyCode.X); setHotKey(saveOutputMenu, KeyCode.S); setHotKey(settingsMenu, KeyCode.COMMA); // Connect or disconnect with server serverUrl.setOnKeyPressed(keyEvent -> { if (!connectionButton.isDisable() && keyEvent.getCode() == KeyCode.ENTER) { createRequest(); } }); serverUrl.textProperty().addListener((observable) -> { if (serverUrl.getText().length() > 0) { validateServerUrl(); urlCleaner.setVisible(true); } else { connectionButton.setDisable(true); urlCleaner.setVisible(false); } }); } /** * Close application with connection */ @FXML private void exitApplication() { wsClients.forEach(wsClient -> { if (wsClient != null && wsClient.isOpenConnection()) { wsClient.closeConnection(); } }); Platform.exit(); System.exit(0); } @FXML private void createRequest() { HttpTypes currentType = httpTypesComboBox.getSelectionModel().getSelectedItem(); Task task = new Task() { @Override protected Object call() throws Exception { connectionButton.setDisable(true); setProgressVisible(true); Tab currentTab = tabPane.getSelectionModel().getSelectedItem(); if (currentTab instanceof NewClientTab) { if (currentType == HttpTypes.WEBSOCKET) { WsMessagesTab wsClientTab = new WsMessagesTab(); WsClient wsClient = wsClientTab.getController().getWsClient(); if (wsClient.isOpenConnection()) { wsClients.add(wsClient); addNewTab(wsClientTab); } } else { RestTab restTab = new RestTab(httpTypesComboBox.getSelectionModel().getSelectedItem()); addNewTab(restTab); } } else if (currentTab instanceof WsMessagesTab) { TabWsMessagesController controller = ((WsMessagesTab) currentTab).getController(); WsClient wsClient = controller.getWsClient(); if (!wsClient.isOpenConnection()) { controller.startWsClient(); controller.checkConnectionStatus(); } else { wsClient.closeConnection(); } } else if (currentTab instanceof RestTab) { TabRestController controller = ((RestTab) currentTab).getController(); controller.execute(); } setProgressVisible(false); connectionButton.setDisable(false); return null; } }; new Thread(task).start(); } /** * Save output message to text file */ @FXML private void saveOutputToFile() { if (tabPane.isVisible()) { Tab tab = tabPane.getSelectionModel().getSelectedItem(); StringBuilder builder = new StringBuilder(); if (tab instanceof WsMessagesTab) { TabWsMessagesController controller = ((WsMessagesTab) tab).getController(); for (ReceivedMessage message : controller.getReceivedMessageList()) { builder.append(String.format(ReceivedMessageFormat.DEFAULT.getFormat().concat("\n"), message.getFormattedTime(), message.getMessage())); } } else if (tab instanceof RestTab) { TabRestController controller = ((RestTab) tab).getController(); builder.append(controller.getDetailNode().getText()); builder.append(controller.getMasterNode().getText()); } new FilesOperations().saveTextToFile(builder.toString()); } } /** * Show settings tab */ @FXML private void showSettings() { if (settingsTab == null) { settingsTab = new SettingsTab(); settingsTab.setOnClosed(event -> settingsTab = null); } ObservableList<Tab> tabsList = tabPane.getTabs(); SingleSelectionModel<Tab> selectTabModel = tabPane.getSelectionModel(); if (!tabsList.contains(settingsTab)) { tabsList.add(settingsTab); } selectTabModel.select(settingsTab); } /** * Get headers pop over */ @FXML private void showHttpSettingsPopOver() { if (httpSettings.isSelected()) { getHttpSettingsPopOver().show(httpSettings, -4); } else { getHttpSettingsPopOver().hide(); } } /** * Go to web page for get last tag version */ @FXML private void getLastTagVersionFromWeb() { goToWebPage(properties.getLastReleaseUrl()); } /** * Go to web page for get about info */ @FXML private void getAboutFromWeb() { goToWebPage(properties.getAboutUrl()); } /** * Clear server url input */ @FXML private void clearServerUrl() { if (serverUrl.getText().length() > 0) { serverUrl.clear(); } } @FXML private void nextTab() { if (!serverUrl.isFocused()) { int currentIndex = tabPane.getSelectionModel().getSelectedIndex(); if (currentIndex < tabPane.getTabs().size()) { tabPane.getSelectionModel().select(currentIndex + 1); } } } @FXML private void previousTab() { if (!serverUrl.isFocused()) { int currentIndex = tabPane.getSelectionModel().getSelectedIndex(); if (currentIndex != 0) { tabPane.getSelectionModel().select(currentIndex - 1); } } } @FXML private void closeTab() { Tab currentTab = tabPane.getSelectionModel().getSelectedItem(); if (!(currentTab instanceof NewClientTab)) { if (currentTab instanceof WsMessagesTab) { WsClient wsClient = ((WsMessagesTab) currentTab).getController().getWsClient(); wsClient.closeConnection(); } tabPane.getTabs().remove(currentTab); } } @FXML private void closeTabs() { FilteredList<Tab> tabs = tabPane.getTabs().filtered(tab -> !(tab instanceof NewClientTab)); for (Tab tab: tabs) { if (tab instanceof WsMessagesTab) { WsClient wsClient = ((WsMessagesTab) tab).getController().getWsClient(); wsClient.closeConnection(); } } tabPane.getTabs().removeAll(tabs); } /** * Add new client as tab with result * * @param tab Tab */ private void addNewTab(Tab tab) { Platform.runLater(() -> { TabPane tabPane = getTabPane(); SingleSelectionModel<Tab> selectTabModel = tabPane.getSelectionModel(); tabPane.getTabs().add(tab); selectTabModel.select(tab); }); } /** * Validate server url start with correct uri schema */ private void validateServerUrl() { if (getHttpType() == HttpTypes.WEBSOCKET) { if (serverUrl.getText().startsWith("ws://") || serverUrl.getText().startsWith("wss://")) { connectionButton.setDisable(false); } else { connectionButton.setDisable(true); } } else { if (serverUrl.getText().startsWith("http://") || serverUrl.getText().startsWith("https://")) { connectionButton.setDisable(false); } else { connectionButton.setDisable(true); } } } /** * Get ws clients list * * @return List<WsClient> */ public List<WsClient> getWsClients() { return wsClients; } /** * Get current selected http type * @return HttpTypes */ HttpTypes getHttpType() { return httpTypesComboBox.getSelectionModel().getSelectedItem(); } /** * Get http headers pop over * * @return HttpSettingsPopOver */ private HttpSettingsPopOver getHttpSettingsPopOver() { if (httpSettingsPopOver == null) { httpSettingsPopOver = new HttpSettingsPopOver(); } return httpSettingsPopOver; } /** * Get tab pane element * * @return TabPane */ public TabPane getTabPane() { return tabPane; } /** * Application exit menu item * * @return MenuItem */ public MenuItem getExitAppMenu() { return exitAppMenu; } /** * Application menu toolbar * * @return MenuBar */ public MenuBar getMenuBar() { return menuBar; } /** * Get websocket server url from field * * @return String */ public TextField getServerUrl() { return serverUrl; } /** * Get connection button * * @return Button */ Button getConnectionButton() { return connectionButton; } /** * Get headers list * * @return ObservableList<Header> */ ObservableList<Header> getHeadersList() { return getHttpSettingsPopOver().getHttpSettingsController().getHeadersList(); } /** * Get http parameters list * * @return ObservableList<HttpParameter> */ ObservableList<HttpParameter> getHttpParametersList() { return getHttpSettingsPopOver().getHttpSettingsController().getHttpParametersList(); } /** * Get http settings button * * @return ToggleButton */ public ToggleButton getHttpSettings() { return httpSettings; } /** * Set connection button name */ private void updateConnectionButtonName() { if (httpTypesComboBox.getSelectionModel().getSelectedItem() != HttpTypes.WEBSOCKET) { connectionButton.setText("New Request"); } else { connectionButton.setText("New Connect"); } } /** * Set hot key for menu element * * @param item MenuItem * @param keyCode KeyCode */ private void setHotKey(MenuItem item, KeyCode keyCode) { item.setAccelerator(new KeyCodeCombination(keyCode, keyModifier)); } /** * Set hot key for menu element with shift * * @param item MenuItem * @param keyCode KeyCode */ private void setHotKey(MenuItem item, KeyCode keyCode, KeyCombination.Modifier keyMod) { item.setAccelerator(new KeyCodeCombination(keyCode, keyMod, keyModifier)); } /** * Go to desktop browser page action * * @param url String */ private void goToWebPage(String url) { Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null; if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) { try { desktop.browse(new URL(url).toURI()); } catch (IOException | URISyntaxException e) { LOGGER.error("Error go to web page: {}", e.getMessage()); } } } /** * Set visible progress bar * * @param isVisible boolean */ public void setProgressVisible(boolean isVisible) { Platform.runLater(() -> progress.setVisible(isVisible)); } }