Code formatting

This commit is contained in:
xfarrow
2023-08-07 12:39:29 +02:00
parent 52e4de968f
commit 0ba5721315
24 changed files with 1691 additions and 1468 deletions

View File

@ -6,14 +6,14 @@ public class Constants {
public static final String APP_NAME = "Guify"; public static final String APP_NAME = "Guify";
public static final String VERSION = "1.0.4"; public static final String VERSION = "1.0.4";
public static final int VERSION_PROGRESSIVE = 4; public static final int VERSION_PROGRESSIVE = 4;
public static class Constants_FSOperations{ public static class Constants_FSOperations {
public static final int NONE = 0; public static final int NONE = 0;
public static final int CUT = 1; public static final int CUT = 1;
public static final int COPY = 2; public static final int COPY = 2;
} }
public static class GuifyColors{ public static class GuifyColors {
public static final Color BLUE = new Color(3, 169, 244); public static final Color BLUE = new Color(3, 169, 244);
public static final Color GRAY = new Color(240, 240, 240); public static final Color GRAY = new Color(240, 240, 240);
public static final Color GRAY_HOVER = new Color(220, 220, 220); public static final Color GRAY_HOVER = new Color(220, 220, 220);

View File

@ -7,29 +7,30 @@ import views.*;
* Frame factory. Factory for JFrame (Java Swing). * Frame factory. Factory for JFrame (Java Swing).
*/ */
public class JFrameFactory implements IFrameFactory { public class JFrameFactory implements IFrameFactory {
public static Object createJFrame(int frameType, Object controller) throws Exception{ public static Object createJFrame(int frameType, Object controller)
throws Exception {
switch(frameType) {
switch (frameType) {
case LOGIN:
return new Login(controller); case LOGIN :
return new Login(controller);
case DESKTOP:
return new Desktop(controller); case DESKTOP :
return new Desktop(controller);
case NOTEPAD:
return new Notepad(controller); case NOTEPAD :
return new Notepad(controller);
case FIND_AND_REPLACE:
return new FindAndReplace(controller); case FIND_AND_REPLACE :
return new FindAndReplace(controller);
case QUEUE:
return new Queue(controller); case QUEUE :
return new Queue(controller);
default:
throw new Exception("Invalid frame name"); default :
throw new Exception("Invalid frame name");
} }
} }
} }

View File

@ -5,71 +5,71 @@ import code.GuiAbstractions.Interfaces.IGenericTextArea;
/** /**
* *
* A class implementing an interface for a generic text * A class implementing an interface for a generic text area. It is currently
* area. It is currently using JTextArea (Java Swing) * using JTextArea (Java Swing)
* *
*/ */
public class JGenericTextArea implements IGenericTextArea { public class JGenericTextArea implements IGenericTextArea {
private JTextArea textArea; private JTextArea textArea;
public JGenericTextArea(JTextArea textArea) { public JGenericTextArea(JTextArea textArea) {
this.textArea = textArea; this.textArea = textArea;
} }
@Override @Override
public void selectText(int start, int end) { public void selectText(int start, int end) {
if(textArea == null) if (textArea == null)
return; return;
textArea.requestFocus(); // enforce focus or it will not be selected textArea.requestFocus(); // enforce focus or it will not be selected
textArea.select(start, end); textArea.select(start, end);
} }
public String getText() { public String getText() {
if(textArea == null) { if (textArea == null) {
throw new NullPointerException("TextArea is null"); throw new NullPointerException("TextArea is null");
} }
return textArea.getText(); return textArea.getText();
} }
public void setText(String text) { public void setText(String text) {
if(textArea == null) { if (textArea == null) {
throw new NullPointerException("TextArea is null"); throw new NullPointerException("TextArea is null");
} }
textArea.setText(text); textArea.setText(text);
} }
public void replaceRange(String s, int start, int end) { public void replaceRange(String s, int start, int end) {
if(textArea == null) { if (textArea == null) {
throw new NullPointerException("TextArea is null"); throw new NullPointerException("TextArea is null");
} }
textArea.replaceRange(s, start, end); textArea.replaceRange(s, start, end);
} }
@Override @Override
public void setCaretPosition(int position) { public void setCaretPosition(int position) {
if(textArea == null) { if (textArea == null) {
throw new NullPointerException("TextArea is null"); throw new NullPointerException("TextArea is null");
} }
textArea.setCaretPosition(position); textArea.setCaretPosition(position);
} }
@Override @Override
public int getCaretPosition() { public int getCaretPosition() {
if(textArea == null) { if (textArea == null) {
throw new NullPointerException("TextArea is null"); throw new NullPointerException("TextArea is null");
} }
return textArea.getCaretPosition(); return textArea.getCaretPosition();
} }
public int getSelectionStart(){ public int getSelectionStart() {
if(textArea == null) { if (textArea == null) {
throw new NullPointerException("TextArea is null"); throw new NullPointerException("TextArea is null");
} }
return textArea.getSelectionStart(); return textArea.getSelectionStart();
@ -77,10 +77,10 @@ public class JGenericTextArea implements IGenericTextArea {
@Override @Override
public boolean hasHighlightedText() { public boolean hasHighlightedText() {
if(textArea == null) { if (textArea == null) {
throw new NullPointerException("TextArea is null"); throw new NullPointerException("TextArea is null");
} }
return textArea.getSelectionStart() != textArea.getCaretPosition(); return textArea.getSelectionStart() != textArea.getCaretPosition();
} }
} }

View File

@ -3,17 +3,13 @@ package code.GuiAbstractions.Interfaces;
/** /**
* *
* *
* Interface for a generic TextArea. * Interface for a generic TextArea. It is used to create an abstraction of a
* It is used to create an abstraction of a * TextArea, without using view-specific objects (such as JTextArea).
* TextArea, without using view-specific objects
* (such as JTextArea).
* *
* This increases modularity, flexibility and * This increases modularity, flexibility and creates a separation of concerns.
* creates a separation of concerns.
* *
* In case of change of the GUI library you * In case of change of the GUI library you do not need to change neither the
* do not need to change neither the Controllers nor * Controllers nor these interfaces, but only the implementations.
* these interfaces, but only the implementations.
* *
*/ */
public interface IGenericTextArea { public interface IGenericTextArea {

View File

@ -6,16 +6,17 @@ import com.jcraft.jsch.SftpProgressMonitor;
public class GuifySftpProgressMonitor implements SftpProgressMonitor { public class GuifySftpProgressMonitor implements SftpProgressMonitor {
TransferProgress transferProgress = null; TransferProgress transferProgress = null;
@Override @Override
public boolean count(long bytes) { public boolean count(long bytes) {
if(transferProgress != null) { if (transferProgress != null) {
transferProgress.setTransferredBytes(transferProgress.getTransferredBytes() + bytes); transferProgress.setTransferredBytes(
transferProgress.getTransferredBytes() + bytes);
transferProgress.setTransferStatus(TransferProgress.UPDATING); transferProgress.setTransferStatus(TransferProgress.UPDATING);
QueueEventManager.getInstance().notify(transferProgress); QueueEventManager.getInstance().notify(transferProgress);
} }
// true if the transfer should go on // true if the transfer should go on
// false if the transfer should be cancelled // false if the transfer should be cancelled
return true; return true;
@ -23,7 +24,7 @@ public class GuifySftpProgressMonitor implements SftpProgressMonitor {
@Override @Override
public void end() { public void end() {
if(transferProgress != null) { if (transferProgress != null) {
transferProgress.setTransferStatus(TransferProgress.END); transferProgress.setTransferStatus(TransferProgress.END);
QueueEventManager.getInstance().notify(transferProgress); QueueEventManager.getInstance().notify(transferProgress);
} }

View File

@ -9,21 +9,20 @@ public class Helper {
*/ */
public static String combinePath(String s1, String s2) { public static String combinePath(String s1, String s2) {
StringBuilder result = new StringBuilder(s1); StringBuilder result = new StringBuilder(s1);
if(!s1.endsWith("/")) { if (!s1.endsWith("/")) {
result.append('/'); result.append('/');
} }
result.append(s2); result.append(s2);
return result.toString(); return result.toString();
} }
public static String getParentPath(String path) { public static String getParentPath(String path) {
if(path.equals("/")) { if (path.equals("/")) {
return "/"; return "/";
} } else if (path.equals("~")) {
else if(path.equals("~")) { return Path.of(SshEngine.executeCommand("pwd")).getParent()
return Path.of(SshEngine.executeCommand("pwd")).getParent().toString().replace('\\', '/'); .toString().replace('\\', '/');
} } else {
else {
return Path.of(path).getParent().toString().replace('\\', '/'); return Path.of(path).getParent().toString().replace('\\', '/');
} }
} }

View File

@ -4,9 +4,8 @@ import com.jcraft.jsch.ChannelSftp.LsEntry;
/** /**
* *
* Interface describing a DirectoryNodeButton, * Interface describing a DirectoryNodeButton, independently of how a concrete
* independently of how a concrete DirectoryNodeButton * DirectoryNodeButton will be (currently it is concretely a JButton)
* will be (currently it is concretely a JButton)
* *
*/ */
public interface IDirectoryNodeButton { public interface IDirectoryNodeButton {

View File

@ -7,34 +7,35 @@ import com.jcraft.jsch.ChannelSftp.LsEntry;
/** /**
* *
* A JButton representing a Directory Node. * A JButton representing a Directory Node. Useful when a Directory Node is
* Useful when a Directory Node is needed * needed to be drew on screen.
* to be drew on screen.
* *
*/ */
public class JDirectoryNodeButton extends JButton implements IDirectoryNodeButton { public class JDirectoryNodeButton extends JButton
implements
IDirectoryNodeButton {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public ChannelSftp.LsEntry node = null; public ChannelSftp.LsEntry node = null;
private boolean isSelected = false; private boolean isSelected = false;
public JDirectoryNodeButton() { public JDirectoryNodeButton() {
super(); super();
} }
public JDirectoryNodeButton(ChannelSftp.LsEntry node) { public JDirectoryNodeButton(ChannelSftp.LsEntry node) {
super(); super();
setNode(node); setNode(node);
} }
public void setNode(ChannelSftp.LsEntry node) { public void setNode(ChannelSftp.LsEntry node) {
this.node = node; this.node = node;
} }
public void setSelected(boolean selected) { public void setSelected(boolean selected) {
this.isSelected = selected; this.isSelected = selected;
} }
public boolean getSelected() { public boolean getSelected() {
return this.isSelected; return this.isSelected;
} }

View File

@ -4,7 +4,7 @@ import java.awt.EventQueue;
import controllers.LoginController; import controllers.LoginController;
public class Main { public class Main {
/** /**
* Guify's entry point * Guify's entry point
*/ */
@ -19,5 +19,7 @@ public class Main {
} }
}); });
} }
} }
// In loving memory of L.B. and E.B.

View File

@ -1,41 +1,43 @@
package code; package code;
import java.util.Observable; import java.util.Observable;
import java.util.concurrent.*; import java.util.concurrent.*;
@SuppressWarnings("deprecation") // Observer is okay here @SuppressWarnings("deprecation") // Observer is okay here
public class QueueEventManager extends Observable { public class QueueEventManager extends Observable {
private static QueueEventManager instance; private static QueueEventManager instance;
// Cannot instantiate from outside // Cannot instantiate from outside
private QueueEventManager() {} private QueueEventManager() {
}
// We need this object in order to retrieve old transfers which are not being transferred
ConcurrentLinkedQueue<TransferProgress> queue = new ConcurrentLinkedQueue<TransferProgress>(); // We need this object in order to retrieve old transfers which are not
// being transferred
public static synchronized QueueEventManager getInstance() { ConcurrentLinkedQueue<TransferProgress> queue = new ConcurrentLinkedQueue<TransferProgress>();
if (instance == null) {
instance = new QueueEventManager(); public static synchronized QueueEventManager getInstance() {
} if (instance == null) {
return instance; instance = new QueueEventManager();
} }
return instance;
public void notify(TransferProgress arg) { }
updateQueue(arg);
setChanged(); public void notify(TransferProgress arg) {
notifyObservers(arg); updateQueue(arg);
} setChanged();
notifyObservers(arg);
private void updateQueue(TransferProgress transferProgressObj) { }
if(transferProgressObj.getTransferStatus() == TransferProgress.INIT) {
queue.add(transferProgressObj); private void updateQueue(TransferProgress transferProgressObj) {
} if (transferProgressObj.getTransferStatus() == TransferProgress.INIT) {
else if(transferProgressObj.getTransferStatus() == TransferProgress.END) { queue.add(transferProgressObj);
queue.remove(); } else if (transferProgressObj
} .getTransferStatus() == TransferProgress.END) {
} queue.remove();
}
public TransferProgress[] getQueue() { }
return queue.toArray(new TransferProgress[queue.size()]);
} public TransferProgress[] getQueue() {
return queue.toArray(new TransferProgress[queue.size()]);
}
} }

View File

@ -16,29 +16,29 @@ import java.nio.file.*;
/** /**
* *
* Underlying SSH engine for * Underlying SSH engine for the application
* the application
* *
*/ */
public class SshEngine { public class SshEngine {
private static Session session = null; private static Session session = null;
/* /*
* ========== BEGIN SSH Utilities ========== * ========== BEGIN SSH Utilities ==========
*/ */
public static boolean connetion() { public static boolean connetion() {
return createSession(); return createSession();
} }
private static boolean createSession() { private static boolean createSession() {
Properties config = new Properties(); Properties config = new Properties();
config.put("StrictHostKeyChecking", "no"); config.put("StrictHostKeyChecking", "no");
JSch jsch = new JSch(); JSch jsch = new JSch();
try { try {
session = jsch.getSession(LoginController.LoginCredentials.username, LoginController.LoginCredentials.host, session = jsch.getSession(LoginController.LoginCredentials.username,
LoginController.LoginCredentials.host,
LoginController.LoginCredentials.port); LoginController.LoginCredentials.port);
session.setPassword(LoginController.LoginCredentials.password); session.setPassword(LoginController.LoginCredentials.password);
session.setConfig(config); session.setConfig(config);
@ -52,32 +52,31 @@ public class SshEngine {
return true; return true;
} }
private static void checkValidityOrCreateSession() throws JSchException { private static void checkValidityOrCreateSession() throws JSchException {
if(session == null || !session.isConnected()) { if (session == null || !session.isConnected()) {
if(!createSession()) { if (!createSession()) {
throw new JSchException("Failed to create a session in Jsch"); throw new JSchException("Failed to create a session in Jsch");
} }
} }
} }
public static void disconnectSession() { public static void disconnectSession() {
if(session != null) { if (session != null) {
session.disconnect(); session.disconnect();
} }
} }
/* /*
* ========== END SSH Utilities ========== * ========== END SSH Utilities ==========
*/ */
/* /*
* ========== BEGIN SFTP get() and put() methods ========== * ========== BEGIN SFTP get() and put() methods ==========
*/ */
/** /**
* Downloads a file from remote host to local machine. * Downloads a file from remote host to local machine. Executed
* Executed asynchronously. * asynchronously.
*/ */
public static void downloadFile(String source, String dest) { public static void downloadFile(String source, String dest) {
// We execute the lengthy and time-consuming operation on a different // We execute the lengthy and time-consuming operation on a different
@ -85,36 +84,38 @@ public class SshEngine {
// We use SwingWorker so any GUI changes requested by this thread will // We use SwingWorker so any GUI changes requested by this thread will
// be correctly addressed to the Event Dispatch Thread // be correctly addressed to the Event Dispatch Thread
new Thread(new Runnable() { new Thread(new Runnable() {
public void run() { public void run() {
ChannelSftp channelSftp = null; ChannelSftp channelSftp = null;
try { try {
checkValidityOrCreateSession(); checkValidityOrCreateSession();
channelSftp = (ChannelSftp) session.openChannel("sftp"); channelSftp = (ChannelSftp) session.openChannel("sftp");
channelSftp.connect(); channelSftp.connect();
channelSftp.get(source, dest, new GuifySftpProgressMonitor()); channelSftp.get(source, dest,
System.out.println("File " + source + " downloaded in " + dest); new GuifySftpProgressMonitor());
System.out.println(
"File " + source + " downloaded in " + dest);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} finally { } finally {
if (channelSftp != null) if (channelSftp != null)
channelSftp.disconnect(); channelSftp.disconnect();
} }
} }
}).start(); }).start();
} }
/** /**
* Downloads a directory recursively. * Downloads a directory recursively. Executed asynchronously.
* Executed asynchronously.
*/ */
public static void downloadDirectoryRecursively(String source, String dest) { public static void downloadDirectoryRecursively(String source,
String dest) {
// We execute the lengthy and time-consuming operation on a different // We execute the lengthy and time-consuming operation on a different
// thread instead of the Event Dispatch Thread. // thread instead of the Event Dispatch Thread.
// We use SwingWorker so any GUI changes requested by this thread will // We use SwingWorker so any GUI changes requested by this thread will
// be correctly addressed to the Event Dispatch Thread // be correctly addressed to the Event Dispatch Thread
new Thread(new Runnable() { new Thread(new Runnable() {
public void run() { public void run() {
ChannelSftp channelSftp = null; ChannelSftp channelSftp = null;
try { try {
channelSftp = (ChannelSftp) session.openChannel("sftp"); channelSftp = (ChannelSftp) session.openChannel("sftp");
channelSftp.connect(); channelSftp.connect();
@ -125,143 +126,170 @@ public class SshEngine {
if (channelSftp != null) if (channelSftp != null)
channelSftp.disconnect(); channelSftp.disconnect();
} }
} }
}).start(); }).start();
} }
/** /**
* Private utility * Private utility
* @param channel_aux An auxiliary SFTP channel *
* @param channel_aux
* An auxiliary SFTP channel
* @param remoteDirectory * @param remoteDirectory
* @param localDirectory * @param localDirectory
* @throws SftpException * @throws SftpException
*/ */
private static void downloadDirectoryRecursively_aux(ChannelSftp channel_aux, String remoteDirectory, String localDirectory) throws SftpException { private static void downloadDirectoryRecursively_aux(
channel_aux.cd(remoteDirectory); ChannelSftp channel_aux, String remoteDirectory,
String newLocalDir = Helper.combinePath(localDirectory, Paths.get(remoteDirectory).getFileName().toString()); String localDirectory) throws SftpException {
new java.io.File(newLocalDir).mkdirs(); channel_aux.cd(remoteDirectory);
@SuppressWarnings("unchecked") String newLocalDir = Helper.combinePath(localDirectory,
Paths.get(remoteDirectory).getFileName().toString());
new java.io.File(newLocalDir).mkdirs();
@SuppressWarnings("unchecked")
Vector<LsEntry> entries = channel_aux.ls("*"); Vector<LsEntry> entries = channel_aux.ls("*");
for (ChannelSftp.LsEntry entry : entries) { for (ChannelSftp.LsEntry entry : entries) {
if (!entry.getAttrs().isDir()) { if (!entry.getAttrs().isDir()) {
// File - download it // File - download it
// Creates a thread for each file. If there are a lot of files // Creates a thread for each file. If there are a lot of files
// it may be resource-draining. Consider using a ThreadPool // it may be resource-draining. Consider using a ThreadPool
downloadFile(Helper.combinePath(remoteDirectory, entry.getFilename()), Helper.combinePath(newLocalDir, entry.getFilename())); downloadFile(
} else if (!".".equals(entry.getFilename()) && !"..".equals(entry.getFilename())) { Helper.combinePath(remoteDirectory,
// Directory - download recursively entry.getFilename()),
String newRemoteDir = Helper.combinePath(remoteDirectory, entry.getFilename()); Helper.combinePath(newLocalDir, entry.getFilename()));
downloadDirectoryRecursively_aux(channel_aux, newRemoteDir, newLocalDir); } else if (!".".equals(entry.getFilename())
} && !"..".equals(entry.getFilename())) {
} // Directory - download recursively
} String newRemoteDir = Helper.combinePath(remoteDirectory,
entry.getFilename());
downloadDirectoryRecursively_aux(channel_aux, newRemoteDir,
newLocalDir);
}
}
}
/** /**
* Uploads a file from the local machine to the remote host. * Uploads a file from the local machine to the remote host. Executed
* Executed asynchronously. * asynchronously.
*/ */
public static void uploadFile(File fileToUpload, String remoteDirectory) throws SftpException { public static void uploadFile(File fileToUpload, String remoteDirectory)
throws SftpException {
// We execute the lengthy and time-consuming operation on a different // We execute the lengthy and time-consuming operation on a different
// thread instead of the Event Dispatch Thread. // thread instead of the Event Dispatch Thread.
// We use SwingWorker so any GUI changes requested by this thread will // We use SwingWorker so any GUI changes requested by this thread will
// be correctly addressed to the Event Dispatch Thread // be correctly addressed to the Event Dispatch Thread
new Thread(new Runnable() { new Thread(new Runnable() {
public void run() { public void run() {
ChannelSftp channelSftp = null; ChannelSftp channelSftp = null;
String remotePath = null; String remotePath = null;
try { try {
checkValidityOrCreateSession(); checkValidityOrCreateSession();
channelSftp = (ChannelSftp) session.openChannel("sftp"); channelSftp = (ChannelSftp) session.openChannel("sftp");
channelSftp.connect(); channelSftp.connect();
remotePath = Helper.combinePath(remoteDirectory, fileToUpload.getName()); remotePath = Helper.combinePath(remoteDirectory,
channelSftp.put(fileToUpload.getAbsolutePath(), remotePath, new GuifySftpProgressMonitor()); fileToUpload.getName());
System.out.println("File: " + fileToUpload.getAbsolutePath() + " uploaded to remote path: " + remotePath); channelSftp.put(fileToUpload.getAbsolutePath(), remotePath,
} new GuifySftpProgressMonitor());
catch(SftpException sftpex) { System.out.println("File: " + fileToUpload.getAbsolutePath()
+ " uploaded to remote path: " + remotePath);
} catch (SftpException sftpex) {
// TODO maybe no permissions // TODO maybe no permissions
} } catch (Exception e) {
catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} finally { } finally {
if (channelSftp != null) if (channelSftp != null)
channelSftp.disconnect(); channelSftp.disconnect();
} }
} }
}).start(); }).start();
} }
/** /**
* Uploads directory recursively. * Uploads directory recursively. Executed asynchronously.
* Executed asynchronously. *
* @param directory Full path of the local directory to upload * @param directory
* @param remoteDirectory Full path of the remote directory which the local * Full path of the local directory to upload
* directory will be uploaded in * @param remoteDirectory
* Full path of the remote directory which the local directory
* will be uploaded in
*/ */
public static void uploadDirectoriesRecursively(File directory, String remoteDirectory) throws SftpException { public static void uploadDirectoriesRecursively(File directory,
String remoteDirectory) throws SftpException {
// We execute the lengthy and time-consuming operation on a different // We execute the lengthy and time-consuming operation on a different
// thread instead of the Event Dispatch Thread. // thread instead of the Event Dispatch Thread.
// We use SwingWorker so any GUI changes requested by this thread will // We use SwingWorker so any GUI changes requested by this thread will
// be correctly addressed to the Event Dispatch Thread // be correctly addressed to the Event Dispatch Thread
new Thread(new Runnable() { new Thread(new Runnable() {
public void run() { public void run() {
ChannelSftp channelSftp = null; ChannelSftp channelSftp = null;
try { try {
checkValidityOrCreateSession(); checkValidityOrCreateSession();
channelSftp = (ChannelSftp) session.openChannel("sftp"); channelSftp = (ChannelSftp) session.openChannel("sftp");
channelSftp.connect(); channelSftp.connect();
uploadDirectoriesRecursively_aux(channelSftp, directory, remoteDirectory); uploadDirectoriesRecursively_aux(channelSftp, directory,
} remoteDirectory);
catch(SftpException sftpex) { } catch (SftpException sftpex) {
//TODO maybe no permissions // TODO maybe no permissions
} } catch (Exception e) {
catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} finally { } finally {
if (channelSftp != null) if (channelSftp != null)
channelSftp.disconnect(); channelSftp.disconnect();
} }
} }
}).start(); }).start();
} }
/** /**
* Private utility * Private utility
*
* @param channel_aux * @param channel_aux
* @param localPath * @param localPath
* @param remoteDirectory * @param remoteDirectory
* @throws SftpException * @throws SftpException
*/ */
private static void uploadDirectoriesRecursively_aux(ChannelSftp channel_aux, File localPath, String remoteDirectory) throws SftpException { private static void uploadDirectoriesRecursively_aux(
if(localPath != null) { ChannelSftp channel_aux, File localPath, String remoteDirectory)
String subDirectoryPath = Helper.combinePath(remoteDirectory, localPath.getName()); throws SftpException {
channel_aux.mkdir(subDirectoryPath); if (localPath != null) {
String subDirectoryPath = Helper.combinePath(remoteDirectory,
File[] files = localPath.listFiles(); localPath.getName());
if (files != null) { channel_aux.mkdir(subDirectoryPath);
for (File file : files) {
if (file.isFile()) { File[] files = localPath.listFiles();
// Creates a thread for each file. If there are a lot of files if (files != null) {
// it may be resource-draining. Consider using a ThreadPool for (File file : files) {
channel_aux.put(file.getAbsolutePath(), Helper.combinePath(subDirectoryPath, file.getName()), new GuifySftpProgressMonitor()); if (file.isFile()) {
System.out.println("File: " + file.getAbsolutePath() + " uploaded to remote path: " + Helper.combinePath(subDirectoryPath, file.getName())); // Creates a thread for each file. If there are a lot of
} else if (file.isDirectory()) { // files
uploadDirectoriesRecursively_aux(channel_aux, file, subDirectoryPath); // it may be resource-draining. Consider using a
} // ThreadPool
} channel_aux.put(file.getAbsolutePath(),
} Helper.combinePath(subDirectoryPath,
} file.getName()),
} new GuifySftpProgressMonitor());
System.out.println("File: " + file.getAbsolutePath()
+ " uploaded to remote path: "
+ Helper.combinePath(subDirectoryPath,
file.getName()));
} else if (file.isDirectory()) {
uploadDirectoriesRecursively_aux(channel_aux, file,
subDirectoryPath);
}
}
}
}
}
/* /*
* ========== END SFTP get() and put() methods ========== * ========== END SFTP get() and put() methods ==========
*/ */
/* /*
* ========== BEGIN File System operations ========== * ========== BEGIN File System operations ==========
*/ */
public static void mkdir(String path) throws SftpException { public static void mkdir(String path) throws SftpException {
ChannelSftp channelSftp = null; ChannelSftp channelSftp = null;
try { try {
@ -269,18 +297,16 @@ public class SshEngine {
channelSftp = (ChannelSftp) session.openChannel("sftp"); channelSftp = (ChannelSftp) session.openChannel("sftp");
channelSftp.connect(); channelSftp.connect();
channelSftp.mkdir(path); channelSftp.mkdir(path);
} } catch (SftpException sftpex) {
catch(SftpException sftpex) { throw sftpex;
throw sftpex; } catch (Exception e) {
}
catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} finally { } finally {
if (channelSftp != null) if (channelSftp != null)
channelSftp.disconnect(); channelSftp.disconnect();
} }
} }
public static String readFile(String filePath) { public static String readFile(String filePath) {
ChannelSftp channel = null; ChannelSftp channel = null;
try { try {
@ -296,14 +322,15 @@ public class SshEngine {
channel.disconnect(); channel.disconnect();
} }
} }
public static void writeFile(String content, String pathToFile) { public static void writeFile(String content, String pathToFile) {
ChannelSftp channelSftp = null; ChannelSftp channelSftp = null;
try { try {
checkValidityOrCreateSession(); checkValidityOrCreateSession();
channelSftp = (ChannelSftp) session.openChannel("sftp"); channelSftp = (ChannelSftp) session.openChannel("sftp");
channelSftp.connect(); channelSftp.connect();
channelSftp.put(new ByteArrayInputStream(content.getBytes()), pathToFile); channelSftp.put(new ByteArrayInputStream(content.getBytes()),
pathToFile);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} finally { } finally {
@ -311,29 +338,29 @@ public class SshEngine {
channelSftp.disconnect(); channelSftp.disconnect();
} }
} }
public static void rename(String oldPath, String newPath) throws SftpException { public static void rename(String oldPath, String newPath)
throws SftpException {
ChannelSftp channelSftp = null; ChannelSftp channelSftp = null;
try { try {
checkValidityOrCreateSession(); checkValidityOrCreateSession();
channelSftp = (ChannelSftp) session.openChannel("sftp"); channelSftp = (ChannelSftp) session.openChannel("sftp");
channelSftp.connect(); channelSftp.connect();
channelSftp.rename(oldPath, newPath); channelSftp.rename(oldPath, newPath);
} } catch (SftpException sftpex) {
catch(SftpException sftpex) {
throw sftpex; throw sftpex;
} } catch (Exception e) {
catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} finally { } finally {
if (channelSftp != null) if (channelSftp != null)
channelSftp.disconnect(); channelSftp.disconnect();
} }
} }
/** /**
* Creates an empty file in the specified remote file path * Creates an empty file in the specified remote file path
* @throws SftpException *
* @throws SftpException
*/ */
public static void touch(String remoteFilePath) throws SftpException { public static void touch(String remoteFilePath) throws SftpException {
ChannelSftp channelSftp = null; ChannelSftp channelSftp = null;
@ -341,19 +368,18 @@ public class SshEngine {
checkValidityOrCreateSession(); checkValidityOrCreateSession();
channelSftp = (ChannelSftp) session.openChannel("sftp"); channelSftp = (ChannelSftp) session.openChannel("sftp");
channelSftp.connect(); channelSftp.connect();
channelSftp.put(new ByteArrayInputStream(new byte[0]), remoteFilePath); channelSftp.put(new ByteArrayInputStream(new byte[0]),
} remoteFilePath);
catch(SftpException sftpex) { } catch (SftpException sftpex) {
throw sftpex; throw sftpex;
} } catch (Exception e) {
catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} finally { } finally {
if (channelSftp != null) if (channelSftp != null)
channelSftp.disconnect(); channelSftp.disconnect();
} }
} }
public static void rm(String remoteFilePath) throws SftpException { public static void rm(String remoteFilePath) throws SftpException {
ChannelSftp channelSftp = null; ChannelSftp channelSftp = null;
try { try {
@ -361,43 +387,40 @@ public class SshEngine {
channelSftp = (ChannelSftp) session.openChannel("sftp"); channelSftp = (ChannelSftp) session.openChannel("sftp");
channelSftp.connect(); channelSftp.connect();
channelSftp.rm(remoteFilePath); channelSftp.rm(remoteFilePath);
} } catch (SftpException sftpex) {
catch(SftpException sftpex) {
throw sftpex; throw sftpex;
} } catch (Exception e) {
catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} finally { } finally {
if (channelSftp != null) if (channelSftp != null)
channelSftp.disconnect(); channelSftp.disconnect();
} }
} }
public static void rm(List<String> remoteFilePaths) throws SftpException { public static void rm(List<String> remoteFilePaths) throws SftpException {
ChannelSftp channelSftp = null; ChannelSftp channelSftp = null;
try { try {
checkValidityOrCreateSession(); checkValidityOrCreateSession();
channelSftp = (ChannelSftp) session.openChannel("sftp"); channelSftp = (ChannelSftp) session.openChannel("sftp");
channelSftp.connect(); channelSftp.connect();
for(String remoteFilePath : remoteFilePaths) { for (String remoteFilePath : remoteFilePaths) {
rm(remoteFilePath, channelSftp); rm(remoteFilePath, channelSftp);
} }
} } catch (SftpException sftpex) {
catch(SftpException sftpex) {
throw sftpex; throw sftpex;
} } catch (Exception e) {
catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} finally { } finally {
if (channelSftp != null) if (channelSftp != null)
channelSftp.disconnect(); channelSftp.disconnect();
} }
} }
private static void rm(String remoteFilePath, ChannelSftp channelSftp) throws SftpException, JSchException { private static void rm(String remoteFilePath, ChannelSftp channelSftp)
throws SftpException, JSchException {
channelSftp.rm(remoteFilePath); channelSftp.rm(remoteFilePath);
} }
public static void rmdir(String remoteFilePath) throws SftpException { public static void rmdir(String remoteFilePath) throws SftpException {
ChannelSftp channelSftp = null; ChannelSftp channelSftp = null;
try { try {
@ -405,45 +428,43 @@ public class SshEngine {
channelSftp = (ChannelSftp) session.openChannel("sftp"); channelSftp = (ChannelSftp) session.openChannel("sftp");
channelSftp.connect(); channelSftp.connect();
channelSftp.rmdir(remoteFilePath); channelSftp.rmdir(remoteFilePath);
} } catch (SftpException sftpex) {
catch(SftpException sftpex) {
throw sftpex; throw sftpex;
} } catch (Exception e) {
catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} finally { } finally {
if (channelSftp != null) if (channelSftp != null)
channelSftp.disconnect(); channelSftp.disconnect();
} }
} }
public static void rmdir(List<String> remotePaths) throws SftpException { public static void rmdir(List<String> remotePaths) throws SftpException {
ChannelSftp channelSftp = null; ChannelSftp channelSftp = null;
try { try {
checkValidityOrCreateSession(); checkValidityOrCreateSession();
channelSftp = (ChannelSftp) session.openChannel("sftp"); channelSftp = (ChannelSftp) session.openChannel("sftp");
channelSftp.connect(); channelSftp.connect();
for(String remotePath : remotePaths) { for (String remotePath : remotePaths) {
rmdir(remotePath, channelSftp); rmdir(remotePath, channelSftp);
} }
} } catch (SftpException sftpex) {
catch(SftpException sftpex) {
throw sftpex; throw sftpex;
} } catch (Exception e) {
catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} finally { } finally {
if (channelSftp != null) if (channelSftp != null)
channelSftp.disconnect(); channelSftp.disconnect();
} }
} }
private static void rmdir(String remotePath, ChannelSftp channelSftp) throws SftpException, JSchException { private static void rmdir(String remotePath, ChannelSftp channelSftp)
throws SftpException, JSchException {
channelSftp.rmdir(remotePath); channelSftp.rmdir(remotePath);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Vector<ChannelSftp.LsEntry> ls(String path) throws SftpException{ public static Vector<ChannelSftp.LsEntry> ls(String path)
throws SftpException {
ChannelSftp channelSftp = null; ChannelSftp channelSftp = null;
try { try {
checkValidityOrCreateSession(); checkValidityOrCreateSession();
@ -451,13 +472,13 @@ public class SshEngine {
channelSftp.connect(); channelSftp.connect();
Vector<ChannelSftp.LsEntry> entries = channelSftp.ls(path); Vector<ChannelSftp.LsEntry> entries = channelSftp.ls(path);
// remove hidden directories (TODO create a setting for that) // remove hidden directories (TODO create a setting for that)
entries.removeIf(entry -> entry.getFilename().equals(".") || entry.getFilename().equals("..") || entry.getFilename().startsWith(".")); entries.removeIf(entry -> entry.getFilename().equals(".")
|| entry.getFilename().equals("..")
|| entry.getFilename().startsWith("."));
return entries; return entries;
} } catch (SftpException sftpex) {
catch(SftpException sftpex) {
throw sftpex; throw sftpex;
} } catch (Exception e) {
catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
return null; return null;
} finally { } finally {
@ -465,16 +486,15 @@ public class SshEngine {
channelSftp.disconnect(); channelSftp.disconnect();
} }
} }
/* /*
* ========== END File System operations ========== * ========== END File System operations ==========
*/ */
/* /*
* ========== BEGIN Other ========== * ========== BEGIN Other ==========
*/ */
public static String executeCommand(String command) { public static String executeCommand(String command) {
System.out.println("> " + command); System.out.println("> " + command);
Channel channel = null; Channel channel = null;
@ -485,7 +505,8 @@ public class SshEngine {
((ChannelExec) channel).setCommand(command); ((ChannelExec) channel).setCommand(command);
channel.connect(); channel.connect();
in = channel.getInputStream(); in = channel.getInputStream();
String returnText = new String(in.readAllBytes(), StandardCharsets.UTF_8); String returnText = new String(in.readAllBytes(),
StandardCharsets.UTF_8);
in.close(); in.close();
// Remove possible \r\n at the end of the string // Remove possible \r\n at the end of the string
returnText = returnText.replaceAll("[\r\n]+$", "").trim(); returnText = returnText.replaceAll("[\r\n]+$", "").trim();
@ -502,12 +523,11 @@ public class SshEngine {
} }
return null; return null;
} }
/* /*
* ========== END Other ========== * ========== END Other ==========
*/ */
} }
/* /*
* When executing a command on a remote server using SSH with Jsch in Java, we * When executing a command on a remote server using SSH with Jsch in Java, we

View File

@ -2,24 +2,24 @@ package code;
/** /**
* *
* An object representing the transfer progress of a * An object representing the transfer progress of a file between the server and
* file between the server and the host machine. * the host machine.
* *
*/ */
public class TransferProgress { public class TransferProgress {
// Transfer statuses // Transfer statuses
public static final int INIT = 0; public static final int INIT = 0;
public static final int UPDATING = 1; public static final int UPDATING = 1;
public static final int END = 2; public static final int END = 2;
private String source; private String source;
private String destination; private String destination;
private long totalBytes; private long totalBytes;
private long transferredBytes; private long transferredBytes;
private int operation; private int operation;
private int transferStatus; private int transferStatus;
public String getSource() { public String getSource() {
return source; return source;
} }

View File

@ -2,8 +2,7 @@ package code;
/** /**
* *
* A class representing a * A class representing a "tree -J" result
* "tree -J" result
* *
*/ */
public class TreeNode { public class TreeNode {

View File

@ -5,188 +5,191 @@ import javax.swing.JScrollPane;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
/** /**
* FlowLayout subclass that fully supports wrapping of components. * FlowLayout subclass that fully supports wrapping of components.
*/ */
public class WrapLayout extends FlowLayout public class WrapLayout extends FlowLayout {
{
/** /**
* *
*/ */
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* Constructs a new <code>WrapLayout</code> with a left * Constructs a new <code>WrapLayout</code> with a left alignment and a
* alignment and a default 5-unit horizontal and vertical gap. * default 5-unit horizontal and vertical gap.
*/ */
public WrapLayout() public WrapLayout() {
{
super(); super();
} }
/** /**
* Constructs a new <code>FlowLayout</code> with the specified * Constructs a new <code>FlowLayout</code> with the specified alignment and
* alignment and a default 5-unit horizontal and vertical gap. * a default 5-unit horizontal and vertical gap. The value of the alignment
* The value of the alignment argument must be one of * argument must be one of <code>WrapLayout</code>, <code>WrapLayout</code>,
* <code>WrapLayout</code>, <code>WrapLayout</code>, * or <code>WrapLayout</code>.
* or <code>WrapLayout</code>. *
* @param align the alignment value * @param align
*/ * the alignment value
public WrapLayout(int align) */
{ public WrapLayout(int align) {
super(align); super(align);
} }
/** /**
* Creates a new flow layout manager with the indicated alignment * Creates a new flow layout manager with the indicated alignment and the
* and the indicated horizontal and vertical gaps. * indicated horizontal and vertical gaps.
* <p> * <p>
* The value of the alignment argument must be one of * The value of the alignment argument must be one of
* <code>WrapLayout</code>, <code>WrapLayout</code>, * <code>WrapLayout</code>, <code>WrapLayout</code>, or
* or <code>WrapLayout</code>. * <code>WrapLayout</code>.
* @param align the alignment value *
* @param hgap the horizontal gap between components * @param align
* @param vgap the vertical gap between components * the alignment value
*/ * @param hgap
public WrapLayout(int align, int hgap, int vgap) * the horizontal gap between components
{ * @param vgap
* the vertical gap between components
*/
public WrapLayout(int align, int hgap, int vgap) {
super(align, hgap, vgap); super(align, hgap, vgap);
} }
/** /**
* Returns the preferred dimensions for this layout given the * Returns the preferred dimensions for this layout given the <i>visible</i>
* <i>visible</i> components in the specified target container. * components in the specified target container.
* @param target the component which needs to be laid out *
* @return the preferred dimensions to lay out the * @param target
* subcomponents of the specified container * the component which needs to be laid out
*/ * @return the preferred dimensions to lay out the subcomponents of the
* specified container
*/
@Override @Override
public Dimension preferredLayoutSize(Container target) public Dimension preferredLayoutSize(Container target) {
{
return layoutSize(target, true); return layoutSize(target, true);
} }
/** /**
* Returns the minimum dimensions needed to layout the <i>visible</i> * Returns the minimum dimensions needed to layout the <i>visible</i>
* components contained in the specified target container. * components contained in the specified target container.
* @param target the component which needs to be laid out *
* @return the minimum dimensions to lay out the * @param target
* subcomponents of the specified container * the component which needs to be laid out
*/ * @return the minimum dimensions to lay out the subcomponents of the
* specified container
*/
@Override @Override
public Dimension minimumLayoutSize(Container target) public Dimension minimumLayoutSize(Container target) {
{
Dimension minimum = layoutSize(target, false); Dimension minimum = layoutSize(target, false);
minimum.width -= (getHgap() + 1); minimum.width -= (getHgap() + 1);
return minimum; return minimum;
} }
/** /**
* Returns the minimum or preferred dimension needed to layout the target * Returns the minimum or preferred dimension needed to layout the target
* container. * container.
* *
* @param target target to get layout size for * @param target
* @param preferred should preferred size be calculated * target to get layout size for
* @return the dimension to layout the target container * @param preferred
*/ * should preferred size be calculated
private Dimension layoutSize(Container target, boolean preferred) * @return the dimension to layout the target container
{ */
synchronized (target.getTreeLock()) private Dimension layoutSize(Container target, boolean preferred) {
{ synchronized (target.getTreeLock()) {
// Each row must fit with the width allocated to the containter. // Each row must fit with the width allocated to the containter.
// When the container width = 0, the preferred width of the container // When the container width = 0, the preferred width of the
// has not yet been calculated so lets ask for the maximum. // container
// has not yet been calculated so lets ask for the maximum.
int targetWidth = target.getSize().width; int targetWidth = target.getSize().width;
Container container = target; Container container = target;
while (container.getSize().width == 0 && container.getParent() != null) while (container.getSize().width == 0
{ && container.getParent() != null) {
container = container.getParent(); container = container.getParent();
}
targetWidth = container.getSize().width;
if (targetWidth == 0)
targetWidth = Integer.MAX_VALUE;
int hgap = getHgap();
int vgap = getVgap();
Insets insets = target.getInsets();
int horizontalInsetsAndGap = insets.left + insets.right + (hgap * 2);
int maxWidth = targetWidth - horizontalInsetsAndGap;
// Fit components into the allowed width
Dimension dim = new Dimension(0, 0);
int rowWidth = 0;
int rowHeight = 0;
int nmembers = target.getComponentCount();
for (int i = 0; i < nmembers; i++)
{
Component m = target.getComponent(i);
if (m.isVisible())
{
Dimension d = preferred ? m.getPreferredSize() : m.getMinimumSize();
// Can't add the component to current row. Start a new row.
if (rowWidth + d.width > maxWidth)
{
addRow(dim, rowWidth, rowHeight);
rowWidth = 0;
rowHeight = 0;
}
// Add a horizontal gap for all components after the first
if (rowWidth != 0)
{
rowWidth += hgap;
}
rowWidth += d.width;
rowHeight = Math.max(rowHeight, d.height);
} }
targetWidth = container.getSize().width;
if (targetWidth == 0)
targetWidth = Integer.MAX_VALUE;
int hgap = getHgap();
int vgap = getVgap();
Insets insets = target.getInsets();
int horizontalInsetsAndGap = insets.left + insets.right
+ (hgap * 2);
int maxWidth = targetWidth - horizontalInsetsAndGap;
// Fit components into the allowed width
Dimension dim = new Dimension(0, 0);
int rowWidth = 0;
int rowHeight = 0;
int nmembers = target.getComponentCount();
for (int i = 0; i < nmembers; i++) {
Component m = target.getComponent(i);
if (m.isVisible()) {
Dimension d = preferred
? m.getPreferredSize()
: m.getMinimumSize();
// Can't add the component to current row. Start a new row.
if (rowWidth + d.width > maxWidth) {
addRow(dim, rowWidth, rowHeight);
rowWidth = 0;
rowHeight = 0;
}
// Add a horizontal gap for all components after the first
if (rowWidth != 0) {
rowWidth += hgap;
}
rowWidth += d.width;
rowHeight = Math.max(rowHeight, d.height);
}
}
addRow(dim, rowWidth, rowHeight);
dim.width += horizontalInsetsAndGap;
dim.height += insets.top + insets.bottom + vgap * 2;
// When using a scroll pane or the DecoratedLookAndFeel we need to
// make sure the preferred size is less than the size of the
// target containter so shrinking the container size works
// correctly. Removing the horizontal gap is an easy way to do this.
Container scrollPane = SwingUtilities
.getAncestorOfClass(JScrollPane.class, target);
if (scrollPane != null && target.isValid()) {
dim.width -= (hgap + 1);
}
return dim;
} }
addRow(dim, rowWidth, rowHeight);
dim.width += horizontalInsetsAndGap;
dim.height += insets.top + insets.bottom + vgap * 2;
// When using a scroll pane or the DecoratedLookAndFeel we need to
// make sure the preferred size is less than the size of the
// target containter so shrinking the container size works
// correctly. Removing the horizontal gap is an easy way to do this.
Container scrollPane = SwingUtilities.getAncestorOfClass(JScrollPane.class, target);
if (scrollPane != null && target.isValid())
{
dim.width -= (hgap + 1);
}
return dim;
}
} }
/* /*
* A new row has been completed. Use the dimensions of this row * A new row has been completed. Use the dimensions of this row to update
* to update the preferred size for the container. * the preferred size for the container.
* *
* @param dim update the width and height when appropriate * @param dim update the width and height when appropriate
* @param rowWidth the width of the row to add *
* @param rowHeight the height of the row to add * @param rowWidth the width of the row to add
*
* @param rowHeight the height of the row to add
*/ */
private void addRow(Dimension dim, int rowWidth, int rowHeight) private void addRow(Dimension dim, int rowWidth, int rowHeight) {
{
dim.width = Math.max(dim.width, rowWidth); dim.width = Math.max(dim.width, rowWidth);
if (dim.height > 0) if (dim.height > 0) {
{
dim.height += getVgap(); dim.height += getVgap();
} }

View File

@ -17,85 +17,81 @@ import java.io.File;
import java.util.*; import java.util.*;
import java.util.List; import java.util.List;
public class DesktopController { public class DesktopController {
/* /*
* ========== BEGIN Attributes ========== * ========== BEGIN Attributes ==========
*/ */
private IDesktopFrame frame; private IDesktopFrame frame;
private String currentWorkingDirectory = "~"; private String currentWorkingDirectory = "~";
private String lastSafeDirectory = null; private String lastSafeDirectory = null;
private List<IDirectoryNodeButton> selectedNodes = new ArrayList<IDirectoryNodeButton>(); private List<IDirectoryNodeButton> selectedNodes = new ArrayList<IDirectoryNodeButton>();
public CutCopyPasteController cutCopyPasteController = new CutCopyPasteController(); public CutCopyPasteController cutCopyPasteController = new CutCopyPasteController();
/* /*
* ========== END Attributes ========== * ========== END Attributes ==========
*/ */
/* /*
* ========== BEGIN Constructors ========== * ========== BEGIN Constructors ==========
*/ */
public DesktopController() { public DesktopController() {
try { try {
frame = (IDesktopFrame) JFrameFactory.createJFrame(JFrameFactory.DESKTOP, this); frame = (IDesktopFrame) JFrameFactory
.createJFrame(JFrameFactory.DESKTOP, this);
frame.drawComponentsForDirectory("~"); frame.drawComponentsForDirectory("~");
} } catch (Exception e) {
catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
/* /*
* ========== END Constructors ========== * ========== END Constructors ==========
*/ */
/* /*
* ========== BEGIN Getters and Setters ========== * ========== BEGIN Getters and Setters ==========
*/ */
public String getCurrentWorkingDirectory() { public String getCurrentWorkingDirectory() {
return currentWorkingDirectory; return currentWorkingDirectory;
} }
public void setCurrentWorkingDirectory(String directory) { public void setCurrentWorkingDirectory(String directory) {
if(directory.equals("~")) { if (directory.equals("~")) {
currentWorkingDirectory = SshEngine.executeCommand("pwd"); currentWorkingDirectory = SshEngine.executeCommand("pwd");
} } else {
else {
currentWorkingDirectory = directory.trim(); currentWorkingDirectory = directory.trim();
} }
} }
public String getLastSafeDirectory() { public String getLastSafeDirectory() {
return lastSafeDirectory; return lastSafeDirectory;
} }
public void setLastSafeDirectory(String directory) { public void setLastSafeDirectory(String directory) {
if(directory == null) { if (directory == null) {
lastSafeDirectory = null; lastSafeDirectory = null;
return; return;
} }
if(directory.equals("~")) { if (directory.equals("~")) {
lastSafeDirectory = SshEngine.executeCommand("pwd"); lastSafeDirectory = SshEngine.executeCommand("pwd");
} } else {
else {
lastSafeDirectory = directory.trim(); lastSafeDirectory = directory.trim();
} }
} }
/* /*
* ========== END Getters and Setters ========== * ========== END Getters and Setters ==========
*/ */
/* /*
* ========== BEGIN Create desktop helper methods ========== * ========== BEGIN Create desktop helper methods ==========
*/ */
public TreeNode getTree() { public TreeNode getTree() {
final int maxDepth = 3; final int maxDepth = 3;
StringBuilder command = new StringBuilder("tree -Ji -L "); StringBuilder command = new StringBuilder("tree -Ji -L ");
@ -104,222 +100,233 @@ public class DesktopController {
command.append(currentWorkingDirectory); command.append(currentWorkingDirectory);
String jsonTree = SshEngine.executeCommand(command.toString()); String jsonTree = SshEngine.executeCommand(command.toString());
TreeNode[] tree = null; TreeNode[] tree = null;
try { try {
// Might throw Invalid JSON exception because of incorrect // Might throw Invalid JSON exception because of incorrect
// JSON output returned from tree: // JSON output returned from tree:
// https://gitlab.com/OldManProgrammer/unix-tree/-/issues/11 // https://gitlab.com/OldManProgrammer/unix-tree/-/issues/11
// Fixed in tree 2.1.1 https://gitlab.com/OldManProgrammer/unix-tree/-/commit/84fa3ddff51b30835a0f9c4a9e4c9225970f9aff // Fixed in tree 2.1.1
// https://gitlab.com/OldManProgrammer/unix-tree/-/commit/84fa3ddff51b30835a0f9c4a9e4c9225970f9aff
// //
// For this reason, we temporarily explicitly avoid it to happen // For this reason, we temporarily explicitly avoid it to happen
jsonTree = jsonTree.replace("}{\"error\"", "},{\"error\""); jsonTree = jsonTree.replace("}{\"error\"", "},{\"error\"");
tree = new Gson().fromJson(jsonTree, TreeNode[].class); tree = new Gson().fromJson(jsonTree, TreeNode[].class);
return tree[0]; return tree[0];
} } catch (Exception ex) {
catch(Exception ex) {
return null; return null;
} }
} }
public Vector<ChannelSftp.LsEntry> getDirectoryElements() throws SftpException { public Vector<ChannelSftp.LsEntry> getDirectoryElements()
throws SftpException {
return SshEngine.ls(currentWorkingDirectory); return SshEngine.ls(currentWorkingDirectory);
} }
/* /*
* ========== END Create desktop helper methods ========== * ========== END Create desktop helper methods ==========
*/ */
/* /*
* ========== BEGIN Download and Upload section ========== * ========== BEGIN Download and Upload section ==========
*/ */
/** /**
* Downloads a file from the remote server to the local machine * Downloads a file from the remote server to the local machine
* @param sourcePath Remote file's full path *
* @param destinationPath Local file's full path * @param sourcePath
* Remote file's full path
* @param destinationPath
* Local file's full path
*/ */
public void downloadFile(String sourcePath, String destinationPath) { public void downloadFile(String sourcePath, String destinationPath) {
SshEngine.downloadFile(sourcePath, destinationPath); SshEngine.downloadFile(sourcePath, destinationPath);
} }
/** /**
* Uploads files and folders to the remote server * Uploads files and folders to the remote server
*
* @param selectedNodes * @param selectedNodes
* @throws SftpException * @throws SftpException
*/ */
public void uploadToRemoteServer(File[] selectedNodes) throws SftpException { public void uploadToRemoteServer(File[] selectedNodes)
if (selectedNodes.length > 0) { throws SftpException {
List<File> selectedFiles = new ArrayList<File>(); if (selectedNodes.length > 0) {
List<File> selectedDirectories = new ArrayList<File>(); List<File> selectedFiles = new ArrayList<File>();
for (java.io.File file : selectedNodes) { List<File> selectedDirectories = new ArrayList<File>();
if(file.isFile()) { for (java.io.File file : selectedNodes) {
selectedFiles.add(file); if (file.isFile()) {
} selectedFiles.add(file);
else if(file.isDirectory()) { } else if (file.isDirectory()) {
selectedDirectories.add(file); selectedDirectories.add(file);
} }
} }
for(File file : selectedFiles) { for (File file : selectedFiles) {
SshEngine.uploadFile(file, this.getCurrentWorkingDirectory()); SshEngine.uploadFile(file, this.getCurrentWorkingDirectory());
} }
if (selectedDirectories.size() > 0) {
if(selectedDirectories.size() > 0) { for (File directory : selectedDirectories) {
for(File directory : selectedDirectories) { SshEngine.uploadDirectoriesRecursively(directory,
SshEngine.uploadDirectoriesRecursively(directory, this.getCurrentWorkingDirectory()); this.getCurrentWorkingDirectory());
} }
} }
} }
} }
/* /*
* ========== END Download and Upload section ========== * ========== END Download and Upload section ==========
*/ */
/* /*
* ========== BEGIN Selected Nodes section ========== * ========== BEGIN Selected Nodes section ==========
*/ */
public void addSelectedNode(IDirectoryNodeButton node) { public void addSelectedNode(IDirectoryNodeButton node) {
selectedNodes.add(node); selectedNodes.add(node);
node.setSelected(true); node.setSelected(true);
} }
public void removeSelectedNode(IDirectoryNodeButton node) { public void removeSelectedNode(IDirectoryNodeButton node) {
selectedNodes.remove(node); selectedNodes.remove(node);
node.setSelected(false); node.setSelected(false);
} }
public void clearSelectedNodes() { public void clearSelectedNodes() {
if(selectedNodes != null) { if (selectedNodes != null) {
Iterator<IDirectoryNodeButton> iterator = selectedNodes.iterator(); Iterator<IDirectoryNodeButton> iterator = selectedNodes.iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
IDirectoryNodeButton node = iterator.next(); IDirectoryNodeButton node = iterator.next();
iterator.remove(); iterator.remove();
node.setSelected(false); node.setSelected(false);
} }
} }
} }
public List<IDirectoryNodeButton> getSelectedNodes() { public List<IDirectoryNodeButton> getSelectedNodes() {
return selectedNodes; return selectedNodes;
} }
public int countSelectedNodes() { public int countSelectedNodes() {
return selectedNodes.size(); return selectedNodes.size();
} }
public void deleteSelectedNodes() throws SftpException { public void deleteSelectedNodes() throws SftpException {
List<String> filesToDelete = new ArrayList<String>(); List<String> filesToDelete = new ArrayList<String>();
List<String> directoriesToDelete = new ArrayList<String>(); List<String> directoriesToDelete = new ArrayList<String>();
for(IDirectoryNodeButton node : selectedNodes) { for (IDirectoryNodeButton node : selectedNodes) {
if(node.getNode().getAttrs().isDir()) { if (node.getNode().getAttrs().isDir()) {
directoriesToDelete.add(Helper.combinePath(getCurrentWorkingDirectory(), node.getNode().getFilename()).replace("\"", "\\\"")); directoriesToDelete.add(Helper
} .combinePath(getCurrentWorkingDirectory(),
else { node.getNode().getFilename())
filesToDelete.add(Helper.combinePath(getCurrentWorkingDirectory(), node.getNode().getFilename()).replace("\"", "\\\"")); .replace("\"", "\\\""));
} else {
filesToDelete.add(Helper
.combinePath(getCurrentWorkingDirectory(),
node.getNode().getFilename())
.replace("\"", "\\\""));
} }
} }
SshEngine.rm(filesToDelete); SshEngine.rm(filesToDelete);
SshEngine.rmdir(directoriesToDelete); SshEngine.rmdir(directoriesToDelete);
clearSelectedNodes(); clearSelectedNodes();
} }
public void downloadSelectedNodes(String destinationPath) { public void downloadSelectedNodes(String destinationPath) {
List<String> directories = new ArrayList<String>(); List<String> directories = new ArrayList<String>();
List<String> files = new ArrayList<String>(); List<String> files = new ArrayList<String>();
String tmp; String tmp;
for(IDirectoryNodeButton node : selectedNodes) { for (IDirectoryNodeButton node : selectedNodes) {
tmp = Helper.combinePath(getCurrentWorkingDirectory(), node.getNode().getFilename()); tmp = Helper.combinePath(getCurrentWorkingDirectory(),
if(node.getNode().getAttrs().isDir()) { node.getNode().getFilename());
if (node.getNode().getAttrs().isDir()) {
directories.add(tmp); directories.add(tmp);
} } else {
else {
files.add(tmp); files.add(tmp);
} }
} }
for(String dir : directories) { for (String dir : directories) {
SshEngine.downloadDirectoryRecursively(dir, destinationPath); SshEngine.downloadDirectoryRecursively(dir, destinationPath);
} }
for(String file : files) { for (String file : files) {
SshEngine.downloadFile(file, destinationPath); SshEngine.downloadFile(file, destinationPath);
} }
} }
/* /*
* ========== END Selected Nodes section ========== * ========== END Selected Nodes section ==========
*/ */
/* /*
* ========== BEGIN CutCopyPasteController controller ========== * ========== BEGIN CutCopyPasteController controller ==========
*/ */
public class CutCopyPasteController{ public class CutCopyPasteController {
private List<String> sources = new ArrayList<String>(); private List<String> sources = new ArrayList<String>();
private int selectedOperation = Constants.Constants_FSOperations.NONE; private int selectedOperation = Constants.Constants_FSOperations.NONE;
public void startCopying(List<IDirectoryNodeButton> selectedNodes, String currentPath) { public void startCopying(List<IDirectoryNodeButton> selectedNodes,
String currentPath) {
String fullPath = null; String fullPath = null;
for(IDirectoryNodeButton nodeBtn : selectedNodes) { for (IDirectoryNodeButton nodeBtn : selectedNodes) {
fullPath = Helper.combinePath(currentPath, nodeBtn.getNode().getFilename()); fullPath = Helper.combinePath(currentPath,
nodeBtn.getNode().getFilename());
sources.add(fullPath); sources.add(fullPath);
} }
selectedOperation = Constants.Constants_FSOperations.COPY; selectedOperation = Constants.Constants_FSOperations.COPY;
} }
public void startCuttying(List<IDirectoryNodeButton> selectedNodes, String currentPath) { public void startCuttying(List<IDirectoryNodeButton> selectedNodes,
String currentPath) {
String fullPath = null; String fullPath = null;
for(IDirectoryNodeButton nodeBtn : selectedNodes) { for (IDirectoryNodeButton nodeBtn : selectedNodes) {
fullPath = Helper.combinePath(currentPath, nodeBtn.getNode().getFilename()); fullPath = Helper.combinePath(currentPath,
nodeBtn.getNode().getFilename());
sources.add(fullPath); sources.add(fullPath);
} }
selectedOperation = Constants.Constants_FSOperations.CUT; selectedOperation = Constants.Constants_FSOperations.CUT;
} }
public void paste(String destination) { public void paste(String destination) {
StringBuilder command = null; StringBuilder command = null;
// no source // no source
if(sources.size() == 0) { if (sources.size() == 0) {
return; return;
} }
// cannot write on destination // cannot write on destination
// we keep using isWriteable as // we keep using isWriteable as
// the executeCommand() does not fire // the executeCommand() does not fire
// an exception in case of fail // an exception in case of fail
if(!isWriteable(destination)) { if (!isWriteable(destination)) {
return; return;
} }
// copy // copy
if(selectedOperation == Constants.Constants_FSOperations.COPY) { if (selectedOperation == Constants.Constants_FSOperations.COPY) {
command = new StringBuilder("cp -r"); command = new StringBuilder("cp -r");
} }
// cut // cut
else if(selectedOperation == Constants.Constants_FSOperations.CUT) { else if (selectedOperation == Constants.Constants_FSOperations.CUT) {
command = new StringBuilder("mv"); command = new StringBuilder("mv");
} }
// invalid command // invalid command
else { else {
return; return;
} }
// execute // execute
for(String path : sources) { for (String path : sources) {
command.append(' '); command.append(' ');
command.append('"'); command.append('"');
command.append(path.replace("\"", "\\\"")); command.append(path.replace("\"", "\\\""));
@ -332,7 +339,7 @@ public class DesktopController {
SshEngine.executeCommand(command.toString()); SshEngine.executeCommand(command.toString());
selectedOperation = Constants_FSOperations.NONE; selectedOperation = Constants_FSOperations.NONE;
} }
public int getSelectedOperation() { public int getSelectedOperation() {
return selectedOperation; return selectedOperation;
} }
@ -341,41 +348,47 @@ public class DesktopController {
/* /*
* ========== END CutCopyPasteController controller ========== * ========== END CutCopyPasteController controller ==========
*/ */
/* /*
* ========== BEGIN File System Operations ========== * ========== BEGIN File System Operations ==========
*/ */
/** /**
* Creates a new folder * Creates a new folder
* @param newFolderPath Folder's path *
* @throws SftpException * @param newFolderPath
* Folder's path
* @throws SftpException
*/ */
public void mkdir(String newFolderPath) throws SftpException { public void mkdir(String newFolderPath) throws SftpException {
SshEngine.mkdir(newFolderPath); SshEngine.mkdir(newFolderPath);
} }
/** /**
* Creates a file in the remote file path * Creates a file in the remote file path
* @param remoteFilePath remote file path *
* @throws SftpException * @param remoteFilePath
* remote file path
* @throws SftpException
*/ */
public void touch(String remoteFilePath) throws SftpException { public void touch(String remoteFilePath) throws SftpException {
SshEngine.touch(remoteFilePath); SshEngine.touch(remoteFilePath);
} }
/** /**
* Renames a file * Renames a file
* @param oldNamePath Path of the old name *
* @param newNamePath Path of the new name * @param oldNamePath
* Path of the old name
* @param newNamePath
* Path of the new name
* @throws SftpException * @throws SftpException
*/ */
public void rename(String oldNamePath, String newNamePath) throws SftpException { public void rename(String oldNamePath, String newNamePath)
throws SftpException {
SshEngine.rename(oldNamePath, newNamePath); SshEngine.rename(oldNamePath, newNamePath);
} }
/* /*
* ========== END File System Operations ========== * ========== END File System Operations ==========
*/ */
@ -383,63 +396,66 @@ public class DesktopController {
/* /*
* ========== BEGIN Other ========== * ========== BEGIN Other ==========
*/ */
/** /**
* Given a remote file path, opens a graphical notepad for it * Given a remote file path, opens a graphical notepad for it
* @param filePath remote file path to display in the notepad *
* @param filePath
* remote file path to display in the notepad
*/ */
public void openNotepadForFile(String filePath) { public void openNotepadForFile(String filePath) {
new NotepadController(filePath).show(); new NotepadController(filePath).show();
} }
/** /**
* Disposes resources which need to be freed before exiting * Disposes resources which need to be freed before exiting the application
* the application
*/ */
public void disposeResources() { public void disposeResources() {
SshEngine.disconnectSession(); SshEngine.disconnectSession();
} }
/** /**
* @deprecated This method is deprecated. * @deprecated This method is deprecated. Catch SftpException and look for
* Catch SftpException * "Permission denied" instead. This prevents unnecessary
* and look for "Permission denied" instead. This prevents * overhead
* unnecessary overhead
*/ */
public boolean isReadable(String path) { public boolean isReadable(String path) {
StringBuilder command = new StringBuilder(); StringBuilder command = new StringBuilder();
command.append("[ -r \""); command.append("[ -r \"");
command.append(path.equals("~") ? SshEngine.executeCommand("pwd").replace("\"", "\\\"") : path.replace("\"", "\\\"")); command.append(path.equals("~")
? SshEngine.executeCommand("pwd").replace("\"", "\\\"")
: path.replace("\"", "\\\""));
command.append("\" ] && echo 1 || echo 0"); // short circuiting command.append("\" ] && echo 1 || echo 0"); // short circuiting
return SshEngine.executeCommand(command.toString()).trim().equals("1"); return SshEngine.executeCommand(command.toString()).trim().equals("1");
} }
/** /**
* @deprecated This method is deprecated. * @deprecated This method is deprecated. Catch SftpException and look for
* Catch SftpException * "Permission denied" instead
* and look for "Permission denied" instead
*/ */
public boolean isWriteable(String path) { public boolean isWriteable(String path) {
StringBuilder command = new StringBuilder(); StringBuilder command = new StringBuilder();
command.append("[ -w \""); command.append("[ -w \"");
command.append(path.equals("~") ? SshEngine.executeCommand("pwd").replace("\"", "\\\"") : path.replace("\"", "\\\"")); command.append(path.equals("~")
? SshEngine.executeCommand("pwd").replace("\"", "\\\"")
: path.replace("\"", "\\\""));
command.append("\" ] && echo 1 || echo 0"); // short circuiting command.append("\" ] && echo 1 || echo 0"); // short circuiting
return SshEngine.executeCommand(command.toString()).trim().equals("1"); return SshEngine.executeCommand(command.toString()).trim().equals("1");
} }
public void showFrame(boolean show) { public void showFrame(boolean show) {
frame.setVisible(show); frame.setVisible(show);
} }
public String getTitle() { public String getTitle() {
StringBuilder title = new StringBuilder(Constants.APP_NAME); StringBuilder title = new StringBuilder(Constants.APP_NAME);
title.append(" - "); title.append(" - ");
title.append(LoginCredentials.host); title.append(LoginCredentials.host);
return title.toString(); return title.toString();
} }
/* /*
* ========== END Other ========== * ========== END Other ==========
*/ */
} }

View File

@ -9,78 +9,82 @@ public class FindAndReplaceController {
private IGenericTextArea textArea; private IGenericTextArea textArea;
private IFindAndReplaceFrame frame; private IFindAndReplaceFrame frame;
public FindAndReplaceController(IGenericTextArea textArea) { public FindAndReplaceController(IGenericTextArea textArea) {
this.textArea = textArea; this.textArea = textArea;
try { try {
frame = (IFindAndReplaceFrame) JFrameFactory.createJFrame(IFrameFactory.FIND_AND_REPLACE, this); frame = (IFindAndReplaceFrame) JFrameFactory
.createJFrame(IFrameFactory.FIND_AND_REPLACE, this);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
/** /**
* Show frame centered to parent * Show frame centered to parent
*/ */
public void showAtTheCenterOfFrame(INotepadFrame notepadFrame) { public void showAtTheCenterOfFrame(INotepadFrame notepadFrame) {
int childX = notepadFrame.getX() + (notepadFrame.getWidth() - frame.getWidth()) / 2; int childX = notepadFrame.getX()
int childY = notepadFrame.getY() + (notepadFrame.getHeight() - frame.getHeight()) / 2; + (notepadFrame.getWidth() - frame.getWidth()) / 2;
frame.setLocation(childX, childY); int childY = notepadFrame.getY()
+ (notepadFrame.getHeight() - frame.getHeight()) / 2;
frame.setLocation(childX, childY);
frame.setVisible(true); frame.setVisible(true);
} }
public int findNext(String searchText) {
String text = textArea.getText();
int currentIndex = textArea.getCaretPosition();
int nextIndex = text.indexOf(searchText, currentIndex);
if (nextIndex != -1) { public int findNext(String searchText) {
textArea.selectText(nextIndex, nextIndex + searchText.length()); String text = textArea.getText();
return nextIndex; int currentIndex = textArea.getCaretPosition();
} int nextIndex = text.indexOf(searchText, currentIndex);
return -1;
if (nextIndex != -1) {
textArea.selectText(nextIndex, nextIndex + searchText.length());
return nextIndex;
}
return -1;
} }
public int findPrevious(String searchText) { public int findPrevious(String searchText) {
String text = textArea.getText(); String text = textArea.getText();
int cutAt; int cutAt;
if(textArea.hasHighlightedText()) { if (textArea.hasHighlightedText()) {
cutAt = textArea.getSelectionStart(); cutAt = textArea.getSelectionStart();
} } else {
else { cutAt = textArea.getCaretPosition();
cutAt = textArea.getCaretPosition(); }
} String firstPart = text.substring(0, cutAt);
String firstPart = text.substring(0, cutAt); int previousIndex = firstPart.lastIndexOf(searchText,
int previousIndex = firstPart.lastIndexOf(searchText, firstPart.length() - 1); firstPart.length() - 1);
if (previousIndex != -1) { if (previousIndex != -1) {
textArea.selectText(previousIndex, previousIndex + searchText.length()); textArea.selectText(previousIndex,
return previousIndex; previousIndex + searchText.length());
} return previousIndex;
else { } else {
return -1; return -1;
} }
} }
public int replaceNext(String toReplace, String replaceWith) { public int replaceNext(String toReplace, String replaceWith) {
int index = findNext(toReplace); int index = findNext(toReplace);
if(index != -1) { if (index != -1) {
textArea.replaceRange(replaceWith, index, index + toReplace.length()); textArea.replaceRange(replaceWith, index,
index + toReplace.length());
} }
return index; return index;
} }
public void replaceAll(String searchText, String replacement) { public void replaceAll(String searchText, String replacement) {
String text = textArea.getText(); String text = textArea.getText();
text = text.replaceAll(searchText, replacement); text = text.replaceAll(searchText, replacement);
textArea.setText(text); textArea.setText(text);
} }
public void disposeMyFrame() { public void disposeMyFrame() {
if(frame != null) { if (frame != null) {
frame.dispose(); frame.dispose();
} }
} }
} }

View File

@ -10,65 +10,65 @@ import code.GuiAbstractions.Interfaces.IFrameFactory;
import views.interfaces.ILoginFrame; import views.interfaces.ILoginFrame;
public class LoginController { public class LoginController {
private ILoginFrame frame; private ILoginFrame frame;
public LoginController() { public LoginController() {
try { try {
frame = (ILoginFrame) JFrameFactory.createJFrame(IFrameFactory.LOGIN, this); frame = (ILoginFrame) JFrameFactory
} .createJFrame(IFrameFactory.LOGIN, this);
catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
public boolean Login(String host, String username, String password, String port) throws IllegalArgumentException { public boolean Login(String host, String username, String password,
String port) throws IllegalArgumentException {
LoginCredentials.host = host; LoginCredentials.host = host;
LoginCredentials.username = username; LoginCredentials.username = username;
LoginCredentials.password = password; LoginCredentials.password = password;
LoginCredentials.port = Integer.parseInt(port); LoginCredentials.port = Integer.parseInt(port);
if (SshEngine.connetion()) { if (SshEngine.connetion()) {
frame.setVisible(false); frame.setVisible(false);
new DesktopController().showFrame(true);; new DesktopController().showFrame(true);;
return true; return true;
} } else {
else {
return false; return false;
} }
} }
public void ValidateInput(String host, String username, String password, String port) throws IllegalArgumentException { public void ValidateInput(String host, String username, String password,
String port) throws IllegalArgumentException {
// Host Validation. Consider its necessity. // Host Validation. Consider its necessity.
try { try {
InetAddress.getByName(host); InetAddress.getByName(host);
} catch (UnknownHostException ex) { } catch (UnknownHostException ex) {
throw new IllegalArgumentException("Host could not be found", ex); throw new IllegalArgumentException("Host could not be found", ex);
} }
// Port Validation // Port Validation
try { try {
Integer.parseInt(port); Integer.parseInt(port);
} } catch (NumberFormatException ex) {
catch(NumberFormatException ex) {
throw new IllegalArgumentException("Invalid port number", ex); throw new IllegalArgumentException("Invalid port number", ex);
} }
} }
public void showFrame(boolean show) { public void showFrame(boolean show) {
frame.setVisible(show); frame.setVisible(show);
} }
public String getTitle() { public String getTitle() {
return Constants.APP_NAME + " " + Constants.VERSION; return Constants.APP_NAME + " " + Constants.VERSION;
} }
public static class LoginCredentials{ public static class LoginCredentials {
public static String host; public static String host;
public static String username; public static String username;
public static String password; public static String password;
public static int port; public static int port;
} }
} }

View File

@ -6,13 +6,13 @@ import code.GuiAbstractions.Interfaces.IFrameFactory;
import code.GuiAbstractions.Interfaces.IGenericTextArea; import code.GuiAbstractions.Interfaces.IGenericTextArea;
import views.interfaces.INotepadFrame; import views.interfaces.INotepadFrame;
public class NotepadController { public class NotepadController {
private String filePath = null; private String filePath = null;
private INotepadFrame notepadFrame = null; private INotepadFrame notepadFrame = null;
private FindAndReplaceController myFindAndReplaceController; private FindAndReplaceController myFindAndReplaceController;
private boolean unsaved = false; private boolean unsaved = false;
private String initialText = null; private String initialText = null;
public boolean isUnsaved() { public boolean isUnsaved() {
return unsaved; return unsaved;
} }
@ -24,40 +24,41 @@ public class NotepadController {
public String getFilePath() { public String getFilePath() {
return this.filePath; return this.filePath;
} }
public String getInitialText() { public String getInitialText() {
return this.initialText; return this.initialText;
} }
public NotepadController(String filePath) { public NotepadController(String filePath) {
this.filePath = filePath; this.filePath = filePath;
initialText = SshEngine.readFile(filePath); initialText = SshEngine.readFile(filePath);
try { try {
notepadFrame = (INotepadFrame) JFrameFactory.createJFrame(IFrameFactory.NOTEPAD, this); notepadFrame = (INotepadFrame) JFrameFactory
.createJFrame(IFrameFactory.NOTEPAD, this);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
return; return;
} }
} }
public void show() { public void show() {
notepadFrame.setVisible(true); notepadFrame.setVisible(true);
} }
public void writeOnFile(String text) { public void writeOnFile(String text) {
SshEngine.writeFile(text, this.filePath); SshEngine.writeFile(text, this.filePath);
} }
public void showFindAndReplace(IGenericTextArea textArea) { public void showFindAndReplace(IGenericTextArea textArea) {
myFindAndReplaceController = new FindAndReplaceController(textArea); myFindAndReplaceController = new FindAndReplaceController(textArea);
myFindAndReplaceController.showAtTheCenterOfFrame(notepadFrame); myFindAndReplaceController.showAtTheCenterOfFrame(notepadFrame);
} }
public void disposeFindAndReplaceFrame() { public void disposeFindAndReplaceFrame() {
if(myFindAndReplaceController != null) if (myFindAndReplaceController != null)
myFindAndReplaceController.disposeMyFrame(); myFindAndReplaceController.disposeMyFrame();
} }
public String getTitle() { public String getTitle() {
return filePath + (unsaved ? " - UNSAVED" : ""); return filePath + (unsaved ? " - UNSAVED" : "");
} }

View File

@ -11,70 +11,84 @@ import views.interfaces.IQueueFrame;
import java.util.HashMap; import java.util.HashMap;
@SuppressWarnings("deprecation") // Observer - Observable are okay here @SuppressWarnings("deprecation") // Observer - Observable are okay here
public class QueueController implements Observer{ public class QueueController implements Observer {
/* /*
* ========== BEGIN Attributes ========== * ========== BEGIN Attributes ==========
*/ */
private IQueueFrame frame; private IQueueFrame frame;
// Accessed only through the EDT, so no need to use ConcurrentHashMap // Accessed only through the EDT, so no need to use ConcurrentHashMap
private HashMap<TransferProgress, Integer> indexHashMap = new HashMap<>(); private HashMap<TransferProgress, Integer> indexHashMap = new HashMap<>();
private long lastGuiExecutionTime = 0; private long lastGuiExecutionTime = 0;
private static final long THROTTLE_TIME_MS = 10; // 10ms = 1/100th of second private static final long THROTTLE_TIME_MS = 10; // 10ms = 1/100th of second
/* /*
* ========== END Attributes ========== * ========== END Attributes ==========
*/ */
// Executed by the EDT // Executed by the EDT
public QueueController() { public QueueController() {
try { try {
frame = (IQueueFrame) JFrameFactory.createJFrame(IFrameFactory.QUEUE, this); frame = (IQueueFrame) JFrameFactory
} .createJFrame(IFrameFactory.QUEUE, this);
catch (Exception e) {} } catch (Exception e) {
}
// Register observer of the changes // Register observer of the changes
QueueEventManager.getInstance().addObserver(this); QueueEventManager.getInstance().addObserver(this);
// Get previous enqueued elements. Do not place before addObserver(this) or some // Get previous enqueued elements. Do not place before addObserver(this)
// or some
// transfers could go lost. // transfers could go lost.
// //
// A necessary but not sufficient condition in order to claim that the Queue // A necessary but not sufficient condition in order to claim that the
// works well, is that when it gets opened at time x, all the non-finished // Queue
// works well, is that when it gets opened at time x, all the
// non-finished
// transfers initiated in a time t such that t < x must be shown // transfers initiated in a time t such that t < x must be shown
// in the table. // in the table.
// More specifically, x represents the time of completion of the instruction // More specifically, x represents the time of completion of the
// QueueEventManager.getInstance().addObserver(this); as // instruction
// any subsequent transfer initiated after this point will be guaranteed to // QueueEventManager.getInstance().addObserver(this); as
// any subsequent transfer initiated after this point will be guaranteed
// to
// be shown in the table (handled by the "update()" method). // be shown in the table (handled by the "update()" method).
// //
// Having understood this, we may now suppose t1 to be the time of completion of the // Having understood this, we may now suppose t1 to be the time of
// completion of the
// instruction QueueEventManager.getInstance().getQueue() and t2 to be // instruction QueueEventManager.getInstance().getQueue() and t2 to be
// the time of completion of the instruction // the time of completion of the instruction
// QueueEventManager.getInstance().addObserver(this) where t1 < t2. // QueueEventManager.getInstance().addObserver(this) where t1 < t2.
// This would've meant that any transfer initiated in a time t such that // This would've meant that any transfer initiated in a time t such that
// t1 < t < t2 would not have been adequately processed as "getQueue()" was // t1 < t < t2 would not have been adequately processed as "getQueue()"
// already executed, and "addObserver(this)" would not have been performed yet, // was
// making the transfer not visible in the queue when the Queue frame would've // already executed, and "addObserver(this)" would not have been
// performed yet,
// making the transfer not visible in the queue when the Queue frame
// would've
// been opened. // been opened.
// //
// One could argue that when any chunk of data is transferred at any time t // One could argue that when any chunk of data is transferred at any
// where t > t2, the update() method will be called, showing the transfer in // time t
// the queue. It's not guaranteed that this happens (as it may encounter an // where t > t2, the update() method will be called, showing the
// error before t2 and after t1 or simply in may complete in this time frame) // transfer in
// the queue. It's not guaranteed that this happens (as it may encounter
// an
// error before t2 and after t1 or simply in may complete in this time
// frame)
TransferProgress[] queued = QueueEventManager.getInstance().getQueue(); TransferProgress[] queued = QueueEventManager.getInstance().getQueue();
for(TransferProgress transferProgress : queued) { for (TransferProgress transferProgress : queued) {
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(new Runnable() {
@Override @Override
public void run() { public void run() {
frame.manageTransferProgress(transferProgress); frame.manageTransferProgress(transferProgress);
} }
}); });
} }
} }
// Executed on different threads. Called by notifyObservers in // Executed on different threads. Called by notifyObservers in
// QueueEventManager in turn called // QueueEventManager in turn called
// by the threads created in SshEngine. // by the threads created in SshEngine.
@ -83,8 +97,9 @@ public class QueueController implements Observer{
// For all distinct pairs of calls on the method update(o, arg) // For all distinct pairs of calls on the method update(o, arg)
// denoted as (update(o, arg)_1 , update(o, arg)_2) having the same // denoted as (update(o, arg)_1 , update(o, arg)_2) having the same
// object "arg", it holds that // object "arg", it holds that
// ((TransferProgress)arg).getTransferredBytes() evaluated during // ((TransferProgress)arg).getTransferredBytes() evaluated during
// update(o, arg)_1 is less or equal than ((TransferProgress)arg).getTransferredBytes() // update(o, arg)_1 is less or equal than
// ((TransferProgress)arg).getTransferredBytes()
// evaluated during update(o, arg)_2. // evaluated during update(o, arg)_2.
// In simple words, if update() is called at time t1 and at time t2, // In simple words, if update() is called at time t1 and at time t2,
// where arg is the same TransferProgress object, then the second time // where arg is the same TransferProgress object, then the second time
@ -93,7 +108,8 @@ public class QueueController implements Observer{
// than the value of // than the value of
// transferProgress.getTransferredBytes() evaluated the first time. // transferProgress.getTransferredBytes() evaluated the first time.
// This happens as the transfer of a single object is an operation executed // This happens as the transfer of a single object is an operation executed
// on a single thread, hence any update will have a getTransferredBytes() greater // on a single thread, hence any update will have a getTransferredBytes()
// greater
// or equal than the previous one. // or equal than the previous one.
// //
// Keep also in mind that SwingUtilities.invokeLater() called at time t1 // Keep also in mind that SwingUtilities.invokeLater() called at time t1
@ -107,78 +123,94 @@ public class QueueController implements Observer{
// will go down (e.g. from 50% to 49%), but this would be true even if // will go down (e.g. from 50% to 49%), but this would be true even if
// the concept described above would be false. This happens because // the concept described above would be false. This happens because
// the TransferProgress // the TransferProgress
// handled by manageTransferProgress will always have the latest updated values // handled by manageTransferProgress will always have the latest updated
// values
// for that specific object, as it is shared with the thread // for that specific object, as it is shared with the thread
// which continuously updates it. // which continuously updates it.
// We do not need any locks as no race conditions // We do not need any locks as no race conditions
// can happen because in the EDT thread we only read said object, nor any // can happen because in the EDT thread we only read said object, nor any
// inconsistencies can arise. // inconsistencies can arise.
// For more information you can view the comments at Queue@manageTransferProgress // For more information you can view the comments at
// Queue@manageTransferProgress
@Override @Override
public void update(Observable o, Object arg) { public void update(Observable o, Object arg) {
TransferProgress transferProgress = (TransferProgress)arg; TransferProgress transferProgress = (TransferProgress) arg;
// Do not invoke the Event Dispatch Thread too frequently as // Do not invoke the Event Dispatch Thread too frequently as
// it may impact the performance of low-end computer systems. // it may impact the performance of low-end computer systems.
if(System.currentTimeMillis() - lastGuiExecutionTime >= THROTTLE_TIME_MS || if (System.currentTimeMillis()
transferProgress.getTransferStatus() == TransferProgress.END) { - lastGuiExecutionTime >= THROTTLE_TIME_MS
|| transferProgress
.getTransferStatus() == TransferProgress.END) {
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(new Runnable() {
@Override @Override
public void run() { public void run() {
frame.manageTransferProgress(transferProgress); frame.manageTransferProgress(transferProgress);
lastGuiExecutionTime = System.currentTimeMillis(); lastGuiExecutionTime = System.currentTimeMillis();
} }
}); });
} }
} }
/** /**
* Computes the transfer completion percentage * Computes the transfer completion percentage
* @param transferProgress A transferProgress object *
* @return A value in the range [0, 100] indicating * @param transferProgress
* the transfer completion percentage * A transferProgress object
* @return A value in the range [0, 100] indicating the transfer completion
* percentage
*/ */
public int computePercentage(TransferProgress transferProgress) { public int computePercentage(TransferProgress transferProgress) {
// Avoid division by zero // Avoid division by zero
if(transferProgress.getTotalBytes() == 0) { if (transferProgress.getTotalBytes() == 0) {
// The percentage is 100% if ∀ byte in the file, byte was transferred. // The percentage is 100% if ∀ byte in the file, byte was
// If there are no bytes in the file, this logic proposition holds true (vacuous truth) // transferred.
// If there are no bytes in the file, this logic proposition holds
// true (vacuous truth)
return 100; return 100;
} } else {
else { return (int) Math
return (int) Math.round( ((transferProgress.getTransferredBytes() * 100F) / transferProgress.getTotalBytes()) ); .round(((transferProgress.getTransferredBytes() * 100F)
/ transferProgress.getTotalBytes()));
} }
} }
/** /**
* Given a TransferProgress object, retrieve its index * Given a TransferProgress object, retrieve its index
*
* @param transferProgress * @param transferProgress
* @return Its index or null if not present * @return Its index or null if not present
*/ */
public Integer getTableIndex(TransferProgress transferProgress) { public Integer getTableIndex(TransferProgress transferProgress) {
return indexHashMap.get(transferProgress); return indexHashMap.get(transferProgress);
} }
/** /**
* Put index in the HashMap * Put index in the HashMap
* @param transferProgress TransferProgress object *
* @param index An integer value representing the index * @param transferProgress
* TransferProgress object
* @param index
* An integer value representing the index
*/ */
public void putTableIndex(TransferProgress transferProgress, Integer index) { public void putTableIndex(TransferProgress transferProgress,
Integer index) {
indexHashMap.put(transferProgress, index); indexHashMap.put(transferProgress, index);
} }
/** /**
* Checks if a specific TransferProgress is contained in * Checks if a specific TransferProgress is contained in the HashMap
* the HashMap *
* @param transferProgress A TransferProgress object * @param transferProgress
* A TransferProgress object
* @return true if present, false otherwise * @return true if present, false otherwise
*/ */
public boolean isTransferProgressInHashMap(TransferProgress transferProgress) { public boolean isTransferProgressInHashMap(
TransferProgress transferProgress) {
return getTableIndex(transferProgress) != null; return getTableIndex(transferProgress) != null;
} }
public void showFrame(boolean visible) { public void showFrame(boolean visible) {
frame.setVisible(visible); frame.setVisible(visible);
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -12,94 +12,98 @@ import views.interfaces.IFindAndReplaceFrame;
public class FindAndReplace extends JFrame implements IFindAndReplaceFrame { public class FindAndReplace extends JFrame implements IFindAndReplaceFrame {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public FindAndReplace(Object controller) {
JLabel lab1 = new JLabel("Find:");
JLabel lab2 = new JLabel("Replace:");
JTextField findTextField = new JTextField(30);
JTextField replaceTextField = new JTextField(30);
JButton findNextBtn = new JButton("Find Next");
findNextBtn.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e){
((FindAndReplaceController) controller).findNext(findTextField.getText());
}
});
JButton findPreviousBtn = new JButton("Find Previous");
findPreviousBtn.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e){
((FindAndReplaceController) controller).findPrevious(findTextField.getText());
}
});
JButton replaceNextBtn = new JButton("Replace Next");
replaceNextBtn.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e){
((FindAndReplaceController) controller).replaceNext(findTextField.getText(), replaceTextField.getText());
}
});
JButton replaceAllBtn = new JButton("Replace All");
replaceAllBtn.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e){
((FindAndReplaceController) controller).replaceAll(findTextField.getText(), replaceTextField.getText());
}
});
JButton cancel = new JButton("Cancel");
cancel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e){
dispose();
}
});
setLayout(null); public FindAndReplace(Object controller) {
JLabel lab1 = new JLabel("Find:");
JLabel lab2 = new JLabel("Replace:");
JTextField findTextField = new JTextField(30);
JTextField replaceTextField = new JTextField(30);
JButton findNextBtn = new JButton("Find Next");
findNextBtn.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
((FindAndReplaceController) controller)
.findNext(findTextField.getText());
}
});
// Set the width and height of the label JButton findPreviousBtn = new JButton("Find Previous");
int labWidth = 80; findPreviousBtn.addMouseListener(new MouseAdapter() {
int labHeight = 20; @Override
public void mouseClicked(MouseEvent e) {
((FindAndReplaceController) controller)
.findPrevious(findTextField.getText());
}
});
// Adding labels JButton replaceNextBtn = new JButton("Replace Next");
lab1.setBounds(10,10, labWidth, labHeight); replaceNextBtn.addMouseListener(new MouseAdapter() {
add(lab1); @Override
findTextField.setBounds(10+labWidth, 10, 120, 20); public void mouseClicked(MouseEvent e) {
add(findTextField); ((FindAndReplaceController) controller).replaceNext(
lab2.setBounds(10, 10+labHeight+10, labWidth, labHeight); findTextField.getText(), replaceTextField.getText());
add(lab2); }
replaceTextField.setBounds(10+labWidth, 10+labHeight+10, 120, 20); });
add(replaceTextField);
// Adding buttons JButton replaceAllBtn = new JButton("Replace All");
findNextBtn.setBounds(225, 6, 115, 20); replaceAllBtn.addMouseListener(new MouseAdapter() {
add(findNextBtn); @Override
public void mouseClicked(MouseEvent e) {
((FindAndReplaceController) controller).replaceAll(
findTextField.getText(), replaceTextField.getText());
}
});
findPreviousBtn.setBounds(225, 28, 115, 20); JButton cancel = new JButton("Cancel");
add(findPreviousBtn); cancel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
dispose();
}
});
replaceNextBtn.setBounds(225, 50, 115, 20); setLayout(null);
add(replaceNextBtn);
replaceAllBtn.setBounds(225, 72, 115, 20); // Set the width and height of the label
add(replaceAllBtn); int labWidth = 80;
int labHeight = 20;
cancel.setBounds(225, 94, 115, 20); // Adding labels
add(cancel); lab1.setBounds(10, 10, labWidth, labHeight);
add(lab1);
findTextField.setBounds(10 + labWidth, 10, 120, 20);
add(findTextField);
lab2.setBounds(10, 10 + labHeight + 10, labWidth, labHeight);
add(lab2);
replaceTextField.setBounds(10 + labWidth, 10 + labHeight + 10, 120, 20);
add(replaceTextField);
// Set the width and height of the window // Adding buttons
int width = 360; findNextBtn.setBounds(225, 6, 115, 20);
int height = 160; add(findNextBtn);
// Set size window findPreviousBtn.setBounds(225, 28, 115, 20);
setSize(width, height); add(findPreviousBtn);
setResizable(false);
setTitle("Find/Replace"); replaceNextBtn.setBounds(225, 50, 115, 20);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); add(replaceNextBtn);
setAlwaysOnTop(true);
replaceAllBtn.setBounds(225, 72, 115, 20);
add(replaceAllBtn);
cancel.setBounds(225, 94, 115, 20);
add(cancel);
// Set the width and height of the window
int width = 360;
int height = 160;
// Set size window
setSize(width, height);
setResizable(false);
setTitle("Find/Replace");
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setAlwaysOnTop(true);
} }
} }

View File

@ -24,10 +24,10 @@ public class Login extends JFrame implements ILoginFrame {
private JTextField usernameField; private JTextField usernameField;
private JTextField hostField; private JTextField hostField;
private JTextField portField; private JTextField portField;
public Login(Object controller) { public Login(Object controller) {
this.controller = (LoginController) controller; this.controller = (LoginController) controller;
setTitle(this.controller.getTitle()); setTitle(this.controller.getTitle());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false); setResizable(false);
@ -39,26 +39,26 @@ public class Login extends JFrame implements ILoginFrame {
setContentPane(contentPane); setContentPane(contentPane);
contentPane.setLayout(null); contentPane.setLayout(null);
passwordField = new JPasswordField(); passwordField = new JPasswordField();
passwordField.setToolTipText("SSH Password"); passwordField.setToolTipText("SSH Password");
passwordField.setBounds(10, 159, 139, 20); passwordField.setBounds(10, 159, 139, 20);
contentPane.add(passwordField); contentPane.add(passwordField);
JLabel lblNewLabel = new JLabel("Username"); JLabel lblNewLabel = new JLabel("Username");
lblNewLabel.setBounds(10, 78, 139, 14); lblNewLabel.setBounds(10, 78, 139, 14);
contentPane.add(lblNewLabel); contentPane.add(lblNewLabel);
JLabel lblNewLabel_1 = new JLabel("Password"); JLabel lblNewLabel_1 = new JLabel("Password");
lblNewLabel_1.setBounds(10, 134, 139, 14); lblNewLabel_1.setBounds(10, 134, 139, 14);
contentPane.add(lblNewLabel_1); contentPane.add(lblNewLabel_1);
usernameField = new JTextField(); usernameField = new JTextField();
usernameField.setToolTipText("SSH Username"); usernameField.setToolTipText("SSH Username");
usernameField.setBounds(10, 103, 139, 20); usernameField.setBounds(10, 103, 139, 20);
contentPane.add(usernameField); contentPane.add(usernameField);
usernameField.setColumns(10); usernameField.setColumns(10);
JButton btnConnect = new JButton("Connect"); JButton btnConnect = new JButton("Connect");
btnConnect.setForeground(Color.WHITE); btnConnect.setForeground(Color.WHITE);
btnConnect.setBackground(GuifyColors.BLUE); btnConnect.setBackground(GuifyColors.BLUE);
@ -69,29 +69,28 @@ public class Login extends JFrame implements ILoginFrame {
}); });
btnConnect.setBounds(75, 297, 139, 30); btnConnect.setBounds(75, 297, 139, 30);
contentPane.add(btnConnect); contentPane.add(btnConnect);
JLabel lblNewLabel_2 = new JLabel("Host"); JLabel lblNewLabel_2 = new JLabel("Host");
lblNewLabel_2.setBounds(10, 22, 139, 14); lblNewLabel_2.setBounds(10, 22, 139, 14);
contentPane.add(lblNewLabel_2); contentPane.add(lblNewLabel_2);
hostField = new JTextField(); hostField = new JTextField();
hostField.setToolTipText("SSH Host"); hostField.setToolTipText("SSH Host");
hostField.setBounds(10, 47, 139, 20); hostField.setBounds(10, 47, 139, 20);
contentPane.add(hostField); contentPane.add(hostField);
hostField.setColumns(10); hostField.setColumns(10);
JLabel lblNewLabel_3 = new JLabel("Port"); JLabel lblNewLabel_3 = new JLabel("Port");
lblNewLabel_3.setBounds(10, 190, 139, 14); lblNewLabel_3.setBounds(10, 190, 139, 14);
contentPane.add(lblNewLabel_3); contentPane.add(lblNewLabel_3);
portField = new JTextField(); portField = new JTextField();
portField.setText("22"); portField.setText("22");
portField.setToolTipText("SSH Port"); portField.setToolTipText("SSH Port");
portField.setBounds(10, 215, 86, 20); portField.setBounds(10, 215, 86, 20);
contentPane.add(portField); contentPane.add(portField);
portField.setColumns(10); portField.setColumns(10);
} }
/** /**
@ -103,20 +102,21 @@ public class Login extends JFrame implements ILoginFrame {
String username = usernameField.getText(); String username = usernameField.getText();
String password = String.valueOf(passwordField.getPassword()); String password = String.valueOf(passwordField.getPassword());
String port = portField.getText(); String port = portField.getText();
// Perform validation // Perform validation
try { try {
controller.ValidateInput(host, username, password, port); controller.ValidateInput(host, username, password, port);
} } catch (IllegalArgumentException ex) {
catch(IllegalArgumentException ex) { JOptionPane.showMessageDialog(new JFrame(), ex.getMessage(),
JOptionPane.showMessageDialog(new JFrame(), ex.getMessage(), "Attention required", JOptionPane.ERROR_MESSAGE); "Attention required", JOptionPane.ERROR_MESSAGE);
return; return;
} }
// Perform login // Perform login
if(!controller.Login(host, username, password, port)) { if (!controller.Login(host, username, password, port)) {
JOptionPane.showMessageDialog(new JFrame(), "SSH Login failed", "SSH Login failed", JOptionPane.ERROR_MESSAGE); JOptionPane.showMessageDialog(new JFrame(), "SSH Login failed",
"SSH Login failed", JOptionPane.ERROR_MESSAGE);
} }
} }
} }

View File

@ -27,11 +27,11 @@ import javax.swing.JScrollPane;
import javax.swing.JPanel; import javax.swing.JPanel;
public class Notepad extends JFrame implements INotepadFrame { public class Notepad extends JFrame implements INotepadFrame {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private NotepadController controller; private NotepadController controller;
private JTextArea textArea; private JTextArea textArea;
public Notepad(Object controller) { public Notepad(Object controller) {
this.controller = (NotepadController) controller; this.controller = (NotepadController) controller;
setTitle(this.controller.getFilePath()); setTitle(this.controller.getFilePath());
@ -41,128 +41,141 @@ public class Notepad extends JFrame implements INotepadFrame {
JPanel contentPanel = new JPanel(new BorderLayout()); JPanel contentPanel = new JPanel(new BorderLayout());
JScrollPane scrollPane = new JScrollPane(textArea); JScrollPane scrollPane = new JScrollPane(textArea);
contentPanel.add(scrollPane, BorderLayout.CENTER); contentPanel.add(scrollPane, BorderLayout.CENTER);
contentPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10)); // We want to create a spaced JPanel contentPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10)); // We
// want
// to
// create
// a
// spaced
// JPanel
getContentPane().add(contentPanel, BorderLayout.CENTER); getContentPane().add(contentPanel, BorderLayout.CENTER);
textArea = new JTextArea(); textArea = new JTextArea();
scrollPane.setViewportView(textArea); scrollPane.setViewportView(textArea);
textArea.setTabSize(4); textArea.setTabSize(4);
textArea.setFont(new Font("Monospaced", Font.PLAIN, 14)); textArea.setFont(new Font("Monospaced", Font.PLAIN, 14));
textArea.setCaretPosition(0); textArea.setCaretPosition(0);
textArea.setText(((NotepadController)controller).getInitialText()); textArea.setText(((NotepadController) controller).getInitialText());
textArea.getDocument().addDocumentListener(new DocumentListener() { textArea.getDocument().addDocumentListener(new DocumentListener() {
@Override @Override
public void insertUpdate(DocumentEvent e) { public void insertUpdate(DocumentEvent e) {
// Called when text is inserted into the document // Called when text is inserted into the document
handleTextChange(); handleTextChange();
} }
@Override @Override
public void removeUpdate(DocumentEvent e) { public void removeUpdate(DocumentEvent e) {
// Called when text is removed from the document // Called when text is removed from the document
handleTextChange(); handleTextChange();
} }
@Override @Override
public void changedUpdate(DocumentEvent e) { public void changedUpdate(DocumentEvent e) {
// Called when attributes of the document change // Called when attributes of the document change
// NO OP // NO OP
} }
private void handleTextChange() {
if (!((NotepadController) controller).isUnsaved()) {
((NotepadController) controller).setUnsaved(true);
setTitle(((NotepadController) controller).getTitle());
}
}
});
private void handleTextChange() {
if(!((NotepadController)controller).isUnsaved()) {
((NotepadController)controller).setUnsaved(true);
setTitle(((NotepadController)controller).getTitle());
}
}
});
JButton saveBtn = new JButton(); JButton saveBtn = new JButton();
saveBtn.setBorderPainted(false); saveBtn.setBorderPainted(false);
saveBtn.setBorder(new EmptyBorder(0, 0, 0, 0)); // Set empty border saveBtn.setBorder(new EmptyBorder(0, 0, 0, 0)); // Set empty border
saveBtn.setToolTipText("Save"); saveBtn.setToolTipText("Save");
try { try {
saveBtn.setIcon(new ImageIcon(ImageIO.read(getClass().getClassLoader().getResource("save_icon.png")).getScaledInstance(25, 25, Image.SCALE_SMOOTH))); saveBtn.setIcon(new ImageIcon(ImageIO
.read(getClass().getClassLoader()
.getResource("save_icon.png"))
.getScaledInstance(25, 25, Image.SCALE_SMOOTH)));
saveBtn.setBackground(new Color(240, 240, 240)); saveBtn.setBackground(new Color(240, 240, 240));
saveBtn.setBorderPainted(false); saveBtn.setBorderPainted(false);
saveBtn.setEnabled(true); saveBtn.setEnabled(true);
}catch(IOException ex) { } catch (IOException ex) {
saveBtn.setText("Save"); saveBtn.setText("Save");
} }
saveBtn.addMouseListener(new MouseAdapter() { saveBtn.addMouseListener(new MouseAdapter() {
@Override @Override
public void mouseClicked(MouseEvent e) { public void mouseClicked(MouseEvent e) {
((NotepadController)controller).writeOnFile(textArea.getText()); ((NotepadController) controller)
((NotepadController)controller).setUnsaved(false); .writeOnFile(textArea.getText());
setTitle(((NotepadController)controller).getTitle()); ((NotepadController) controller).setUnsaved(false);
setTitle(((NotepadController) controller).getTitle());
} }
// Hover on // Hover on
@Override @Override
public void mouseEntered(MouseEvent e) { public void mouseEntered(MouseEvent e) {
if(saveBtn.isEnabled()) if (saveBtn.isEnabled())
saveBtn.setBackground(new Color(220, 220, 220)); saveBtn.setBackground(new Color(220, 220, 220));
} }
// Hover off // Hover off
@Override @Override
public void mouseExited(MouseEvent e) { public void mouseExited(MouseEvent e) {
saveBtn.setBackground(new Color(240, 240, 240)); saveBtn.setBackground(new Color(240, 240, 240));
} }
}); });
JButton searchBtn = new JButton(); JButton searchBtn = new JButton();
searchBtn.setBorderPainted(false); searchBtn.setBorderPainted(false);
searchBtn.setBorder(new EmptyBorder(0, 0, 0, 0)); // Set empty border; searchBtn.setBorder(new EmptyBorder(0, 0, 0, 0)); // Set empty border;
searchBtn.setToolTipText("Serch/Replace"); searchBtn.setToolTipText("Serch/Replace");
try { try {
searchBtn.setIcon(new ImageIcon(ImageIO.read(getClass().getClassLoader().getResource("search_icon.png")).getScaledInstance(25, 25, Image.SCALE_SMOOTH))); searchBtn.setIcon(new ImageIcon(ImageIO
.read(getClass().getClassLoader()
.getResource("search_icon.png"))
.getScaledInstance(25, 25, Image.SCALE_SMOOTH)));
searchBtn.setBackground(new Color(240, 240, 240)); searchBtn.setBackground(new Color(240, 240, 240));
searchBtn.setBorderPainted(false); searchBtn.setBorderPainted(false);
searchBtn.setEnabled(true); searchBtn.setEnabled(true);
}catch(IOException ex) { } catch (IOException ex) {
searchBtn.setText("Serch/Replace"); searchBtn.setText("Serch/Replace");
} }
searchBtn.addMouseListener(new MouseAdapter() { searchBtn.addMouseListener(new MouseAdapter() {
@Override @Override
public void mouseClicked(MouseEvent e) { public void mouseClicked(MouseEvent e) {
((NotepadController)controller).showFindAndReplace(new JGenericTextArea(textArea)); ((NotepadController) controller)
.showFindAndReplace(new JGenericTextArea(textArea));
} }
// Hover on // Hover on
@Override @Override
public void mouseEntered(MouseEvent e) { public void mouseEntered(MouseEvent e) {
if(searchBtn.isEnabled()) if (searchBtn.isEnabled())
searchBtn.setBackground(new Color(220, 220, 220)); searchBtn.setBackground(new Color(220, 220, 220));
} }
// Hover off // Hover off
@Override @Override
public void mouseExited(MouseEvent e) { public void mouseExited(MouseEvent e) {
searchBtn.setBackground(new Color(240, 240, 240)); searchBtn.setBackground(new Color(240, 240, 240));
} }
}); });
JToolBar toolBar = new JToolBar(); JToolBar toolBar = new JToolBar();
toolBar.setFloatable(false); toolBar.setFloatable(false);
JPanel toolBarPanel = new JPanel(new BorderLayout()); JPanel toolBarPanel = new JPanel(new BorderLayout());
toolBarPanel.setBorder(BorderFactory.createEmptyBorder(0, 7, 0, 0)); toolBarPanel.setBorder(BorderFactory.createEmptyBorder(0, 7, 0, 0));
toolBarPanel.add(toolBar, BorderLayout.LINE_START); toolBarPanel.add(toolBar, BorderLayout.LINE_START);
toolBar.setBackground(new Color(240, 240, 240)); toolBar.setBackground(new Color(240, 240, 240));
toolBar.add(saveBtn); toolBar.add(saveBtn);
toolBar.add(Box.createHorizontalStrut(15)); toolBar.add(Box.createHorizontalStrut(15));
toolBar.add(searchBtn); toolBar.add(searchBtn);
getContentPane().add(toolBarPanel, BorderLayout.NORTH); getContentPane().add(toolBarPanel, BorderLayout.NORTH);
/** /**
* Close "Find and Replace" if this window * Close "Find and Replace" if this window gets closed
* gets closed
*/ */
addWindowListener(new WindowAdapter() { addWindowListener(new WindowAdapter() {
@Override @Override
public void windowClosing(WindowEvent e) { public void windowClosing(WindowEvent e) {
((NotepadController)controller).disposeFindAndReplaceFrame(); ((NotepadController) controller).disposeFindAndReplaceFrame();
} }
}); });
} }
} }

View File

@ -19,111 +19,131 @@ public class Queue extends JFrame implements IQueueFrame {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private QueueController controller; private QueueController controller;
/** /**
* *
* Custom cell renderer in order to be able to display * Custom cell renderer in order to be able to display a progress bar in the
* a progress bar in the JTable * JTable
* *
*/ */
public static class ProgressBarTableCellRenderer extends DefaultTableCellRenderer { public static class ProgressBarTableCellRenderer
extends
DefaultTableCellRenderer {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private JProgressBar progressBar; private JProgressBar progressBar;
public ProgressBarTableCellRenderer() {
super();
progressBar = new JProgressBar();
progressBar.setStringPainted(true);
}
@Override public ProgressBarTableCellRenderer() {
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, super();
boolean hasFocus, int row, int column) { progressBar = new JProgressBar();
if (value instanceof Integer) { progressBar.setStringPainted(true);
int progressValue = (Integer) value; }
progressBar.setValue(progressValue);
progressBar.setString(progressValue + "%"); @Override
} public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
progressBar.setStringPainted(true); int column) {
progressBar.setForeground(Constants.GuifyColors.BLUE); if (value instanceof Integer) {
progressBar.setBackground(Color.WHITE); int progressValue = (Integer) value;
progressBar.setValue(progressValue);
return progressBar; progressBar.setString(progressValue + "%");
} }
progressBar.setStringPainted(true);
progressBar.setForeground(Constants.GuifyColors.BLUE);
progressBar.setBackground(Color.WHITE);
return progressBar;
}
} }
public DefaultTableModel tableModel; public DefaultTableModel tableModel;
public Queue(Object controller) { public Queue(Object controller) {
this.controller = (QueueController) controller; this.controller = (QueueController) controller;
setTitle("Queue"); setTitle("Queue");
String[] columnNames = {"Source", "Destination", "Operation", "Percentage"}; String[] columnNames = {"Source", "Destination", "Operation",
tableModel = new DefaultTableModel(columnNames, 0); "Percentage"};
JTable table = new JTable(tableModel); tableModel = new DefaultTableModel(columnNames, 0);
table.setEnabled(false); // Prevents user editing JTable table = new JTable(tableModel);
// Show percentage by using a custom cell renderer table.setEnabled(false); // Prevents user editing
TableColumn percentageColumn = table.getColumnModel().getColumn(3); // Show percentage by using a custom cell renderer
percentageColumn.setCellRenderer(new ProgressBarTableCellRenderer()); TableColumn percentageColumn = table.getColumnModel().getColumn(3);
JScrollPane scrollPane = new JScrollPane(table); percentageColumn.setCellRenderer(new ProgressBarTableCellRenderer());
this.getContentPane().add(scrollPane, BorderLayout.CENTER); JScrollPane scrollPane = new JScrollPane(table);
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); this.getContentPane().add(scrollPane, BorderLayout.CENTER);
this.pack(); this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
this.pack();
} }
/** /**
* Adds a row in the JTable * Adds a row in the JTable
*
* @return The index of the inserted row * @return The index of the inserted row
*/ */
public int addRow(String source, String destination, String operation, int percentage) { public int addRow(String source, String destination, String operation,
tableModel.addRow(new Object[]{source, destination, operation, percentage}); int percentage) {
return tableModel.getRowCount() - 1; tableModel.addRow(
new Object[]{source, destination, operation, percentage});
return tableModel.getRowCount() - 1;
} }
/** /**
* Given a value (representing the transfer completion percentage) * Given a value (representing the transfer completion percentage) and an
* and an index representing the 0-based index of the row to update, * index representing the 0-based index of the row to update, update that
* update that row with that value * row with that value
* @param rowIndex 0-base index of the row to update *
* @param percentage The transfer completion percentage to set * @param rowIndex
* 0-base index of the row to update
* @param percentage
* The transfer completion percentage to set
*/ */
public void updateRow(int rowIndex, int percentage) { public void updateRow(int rowIndex, int percentage) {
if(rowIndex < tableModel.getRowCount()) { if (rowIndex < tableModel.getRowCount()) {
tableModel.setValueAt(percentage, rowIndex, 3); tableModel.setValueAt(percentage, rowIndex, 3);
} }
} }
// This method can receive a transferProgress whose status can be INIT, UPDATING // This method can receive a transferProgress whose status can be INIT,
// UPDATING
// or END. // or END.
// In all of these cases it is possible that transferProgress is or is not in the HashMap, // In all of these cases it is possible that transferProgress is or is not
// in the HashMap,
// and we'll prove its correctness in all the cases: // and we'll prove its correctness in all the cases:
// //
// 1. Init: This method can receive a transferProgress whose status is INIT and // 1. Init: This method can receive a transferProgress whose status is INIT
// a. Not present in the HashMap: this can happen either when QueueController receives // and
// an update() or when it iterates in the constructor over the previously enqueued // a. Not present in the HashMap: this can happen either when
// elements. In both cases, the transfer gets correctly put in the table. // QueueController receives
// b. Present in the HashMap: despite it's counterintuitive, this can happen when // an update() or when it iterates in the constructor over the previously
// a transfer gets initialized after QueueEventManager.getInstance().addObserver(this); // enqueued
// and before QueueEventManager.getInstance().getQueue(). // elements. In both cases, the transfer gets correctly put in the table.
// This would lead either update() // b. Present in the HashMap: despite it's counterintuitive, this can happen
// or the QueueController's constructor to call this method over a transferProgress // when
// already in the HashMap (because inserted by the other one) // a transfer gets initialized after
// but whose status is INIT. In this case, updateRow() will // QueueEventManager.getInstance().addObserver(this);
// be called, but without any side effects as the percentage would be zero regardless. // and before QueueEventManager.getInstance().getQueue().
// This would lead either update()
// or the QueueController's constructor to call this method over a
// transferProgress
// already in the HashMap (because inserted by the other one)
// but whose status is INIT. In this case, updateRow() will
// be called, but without any side effects as the percentage would be zero
// regardless.
// //
// 2. Updating: // 2. Updating:
// a. Not present in the HashMap: This can happen when the Queue UI is opened // a. Not present in the HashMap: This can happen when the Queue UI is
// while an element is already being transferred. This happens because when // opened
// the transfer had a "INIT" status, this object did not exist yet. // while an element is already being transferred. This happens because when
// If it's not present in the HashMap // the transfer had a "INIT" status, this object did not exist yet.
// then it will be added. // If it's not present in the HashMap
// b. Present in the HashMap: then it will be correctly updated. // then it will be added.
// b. Present in the HashMap: then it will be correctly updated.
// //
// 3. End: Same case for Updating // 3. End: Same case for Updating
// //
// It's important to note that this method will always operate over the // It's important to note that this method will always operate over the
// last version of the same TransferProgress object as it is updated // last version of the same TransferProgress object as it is updated
// from another thread when any chunk of data is transmitted. // from another thread when any chunk of data is transmitted.
// This will not create any inconsistencies, because the only // This will not create any inconsistencies, because the only
// attribute that can be different is getTransferredBytes which will // attribute that can be different is getTransferredBytes which will
// be read just once per call, nor race conditions // be read just once per call, nor race conditions
@ -136,21 +156,25 @@ public class Queue extends JFrame implements IQueueFrame {
// will go down (e.g. from 50% to 49%). // will go down (e.g. from 50% to 49%).
@Override @Override
public void manageTransferProgress(TransferProgress transferProgress) { public void manageTransferProgress(TransferProgress transferProgress) {
// Remember that when QueueController calls frame.manageTransferProgress(transferProgress), // Remember that when QueueController calls
// here transferProgress might have different attributes than it was originally called on // frame.manageTransferProgress(transferProgress),
// here transferProgress might have different attributes than it was
// originally called on
// (as it's updated by a different thread). // (as it's updated by a different thread).
// We do not need a lock as we do not edit it, but just keep it in mind. // We do not need a lock as we do not edit it, but just keep it in mind.
if(!controller.isTransferProgressInHashMap(transferProgress)) { if (!controller.isTransferProgressInHashMap(transferProgress)) {
controller.putTableIndex(transferProgress, controller.putTableIndex(transferProgress, addRow(
addRow(transferProgress.getSource(), transferProgress.getSource(),
transferProgress.getDestination(), transferProgress.getDestination(),
transferProgress.getOperation() == SftpProgressMonitor.GET? "Download" : "Upload", transferProgress.getOperation() == SftpProgressMonitor.GET
controller.computePercentage(transferProgress))); ? "Download"
} : "Upload",
else { controller.computePercentage(transferProgress)));
updateRow(controller.getTableIndex(transferProgress), controller.computePercentage(transferProgress)); } else {
updateRow(controller.getTableIndex(transferProgress),
controller.computePercentage(transferProgress));
} }
} }
} }