chatbot improvements

This commit is contained in:
Bane Stojkovic
2025-04-04 21:49:52 +02:00
parent acc28c2e54
commit d097bcd740
23 changed files with 437 additions and 139 deletions
@@ -106,5 +106,13 @@ public enum EventType {
/** /**
* Signals the listeners to scroll to selection. * Signals the listeners to scroll to selection.
*/ */
SCROLL_TO; SCROLL_TO,
/**
* Signals that the Cloud account is logged in.
*/
CLOUD_LOGGED_IN,
/**
* Signals that the Cloud account is logged out.
*/
CLOUD_LOGGED_OUT;
} }
@@ -57,7 +57,7 @@ import org.diylc.test.ITestProcessor;
* @see EventType * @see EventType
*/ */
public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyProcessor, IVariantProcessor, public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyProcessor, IVariantProcessor,
IBlockProcessor, INetlistProcessor, ITestProcessor { IBlockProcessor, INetlistProcessor, ITestProcessor, IServiceManager {
public static final String ANTI_ALIASING_KEY = "antiAliasing"; public static final String ANTI_ALIASING_KEY = "antiAliasing";
public static final String HI_QUALITY_RENDER_KEY = "hiQualityRender"; public static final String HI_QUALITY_RENDER_KEY = "hiQualityRender";
@@ -0,0 +1,14 @@
package org.diylc.common;
import org.diylc.appframework.simplemq.MessageDispatcher;
import org.diylc.plugins.chatbot.service.ChatbotService;
import org.diylc.plugins.cloud.service.CloudService;
public interface IServiceManager {
CloudService getCloudService();
ChatbotService getChatbotService();
MessageDispatcher<EventType> getMessageDispatcher();
}
@@ -0,0 +1,76 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.plugins.chatbot.model;
import java.io.Serializable;
import java.util.Objects;
public class ChatMessageEntity implements Serializable {
private String prompt;
private String response;
private String createdOn;
public ChatMessageEntity(String prompt, String response, String createdOn) {
this.prompt = prompt;
this.response = response;
this.createdOn = createdOn;
}
public String getPrompt() {
return prompt;
}
public void setPrompt(String prompt) {
this.prompt = prompt;
}
public String getResponse() {
return response;
}
public void setResponse(String response) {
this.response = response;
}
public String getCreatedOn() {
return createdOn;
}
public void setCreatedOn(String createdOn) {
this.createdOn = createdOn;
}
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass())
return false;
ChatMessageEntity that = (ChatMessageEntity) o;
return Objects.equals(prompt, that.prompt) && Objects.equals(response,
that.response) && Objects.equals(createdOn, that.createdOn);
}
@Override
public int hashCode() {
return Objects.hash(prompt, response, createdOn);
}
}
@@ -23,6 +23,8 @@ package org.diylc.plugins.chatbot.model;
import com.diyfever.httpproxy.ParamName; import com.diyfever.httpproxy.ParamName;
import java.util.List;
public interface IChatbotAPI { public interface IChatbotAPI {
/** /**
@@ -39,4 +41,13 @@ public interface IChatbotAPI {
String promptChatbot(@ParamName("username") String username, @ParamName("token") String token, String promptChatbot(@ParamName("username") String username, @ParamName("token") String token,
@ParamName("machineId") String machineId, @ParamName("project") String project, @ParamName("machineId") String machineId, @ParamName("project") String project,
@ParamName("netlist") String netlist, @ParamName("prompt") String prompt); @ParamName("netlist") String netlist, @ParamName("prompt") String prompt);
SubscriptionEntity getSubscriptionInfo(@ParamName("username") String username, @ParamName("token") String token,
@ParamName("machineId") String machineId);
String deleteChatHistory(@ParamName("username") String username, @ParamName("token") String token,
@ParamName("machineId") String machineId, @ParamName("project") String project);
List<ChatMessageEntity> getChatHistory(@ParamName("username") String username, @ParamName("token") String token,
@ParamName("machineId") String machineId, @ParamName("project") String project);
} }
@@ -0,0 +1,75 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.plugins.chatbot.model;
import java.io.Serializable;
import java.util.Objects;
public class SubscriptionEntity implements Serializable {
private String tier;
private String endDate;
private int remainingCredits;
public SubscriptionEntity(String tier, String endDate, int remainingCredits) {
this.tier = tier;
this.endDate = endDate;
this.remainingCredits = remainingCredits;
}
public String getTier() {
return tier;
}
public void setTier(String tier) {
this.tier = tier;
}
public String getEndDate() {
return endDate;
}
public void setEndDate(String endDate) {
this.endDate = endDate;
}
public int getRemainingCredits() {
return remainingCredits;
}
public void setRemainingCredits(int remainingCredits) {
this.remainingCredits = remainingCredits;
}
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass())
return false;
SubscriptionEntity that = (SubscriptionEntity) o;
return remainingCredits == that.remainingCredits && Objects.equals(tier,
that.tier) && Objects.equals(endDate, that.endDate);
}
@Override
public int hashCode() {
return Objects.hash(tier, endDate, remainingCredits);
}
}
@@ -19,7 +19,7 @@
along with DIYLC. If not, see <http://www.gnu.org/licenses/>. along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.diylc.plugins.chatbot.presenter; package org.diylc.plugins.chatbot.service;
public class ChatbotException extends Exception { public class ChatbotException extends Exception {
@@ -19,15 +19,12 @@
along with DIYLC. If not, see <http://www.gnu.org/licenses/>. along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.diylc.plugins.chatbot.presenter; package org.diylc.plugins.chatbot.service;
import com.diyfever.httpproxy.PhpFlatProxy; import com.diyfever.httpproxy.PhpFlatProxy;
import com.diyfever.httpproxy.ProxyFactory; import com.diyfever.httpproxy.ProxyFactory;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.checkerframework.checker.units.qual.C;
import org.checkerframework.checker.units.qual.N;
import org.diylc.appframework.miscutils.ConfigurationManager; import org.diylc.appframework.miscutils.ConfigurationManager;
import org.diylc.common.ComponentType; import org.diylc.common.ComponentType;
import org.diylc.common.IPlugInPort; import org.diylc.common.IPlugInPort;
@@ -37,28 +34,15 @@ import org.diylc.netlist.Group;
import org.diylc.netlist.Netlist; import org.diylc.netlist.Netlist;
import org.diylc.netlist.NetlistException; import org.diylc.netlist.NetlistException;
import org.diylc.netlist.Node; import org.diylc.netlist.Node;
import org.diylc.plugins.chatbot.model.ChatMessageEntity;
import org.diylc.plugins.chatbot.model.IChatbotAPI; import org.diylc.plugins.chatbot.model.IChatbotAPI;
import org.diylc.plugins.cloud.model.CommentEntity; import org.diylc.plugins.chatbot.model.SubscriptionEntity;
import org.diylc.plugins.cloud.model.IServiceAPI; import org.diylc.plugins.cloud.model.IServiceAPI;
import org.diylc.plugins.cloud.model.ProjectEntity; import org.diylc.plugins.cloud.service.NotLoggedInException;
import org.diylc.plugins.cloud.model.UserEntity;
import org.diylc.plugins.cloud.presenter.CloudException;
import org.diylc.plugins.cloud.presenter.CloudPresenter;
import org.diylc.plugins.cloud.presenter.NotLoggedInException;
import org.diylc.presenter.ComparatorFactory;
import org.diylc.presenter.ComponentProcessor; import org.diylc.presenter.ComponentProcessor;
import org.diylc.utils.FileUtils;
import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.util.*; import java.util.*;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -66,29 +50,30 @@ import java.util.stream.Collectors;
import static org.diylc.utils.FileUtils.extractFileName; import static org.diylc.utils.FileUtils.extractFileName;
/** /**
* Contains all the back-end logic for using the cloud and manipulating projects on the cloud. * Contains all the back-end logic for using the chatbot.
* *
* @author Branislav Stojkovic * @author Branislav Stojkovic
*/ */
public class ChatbotPresenter { public class ChatbotService {
private static String ERROR = "Error"; public static final String LOG_IN_MESSAGE =
"Please log into your DIYLC Cloud account in order to use the AI Assistant";
private final static Logger LOG = Logger.getLogger(ChatbotPresenter.class); private final static Logger LOG = Logger.getLogger(ChatbotService.class);
private static final Object SUCCESS = "Success";
private final IPlugInPort plugInPort;
private static final ObjectMapper MAPPER = new ObjectMapper(); private static final ObjectMapper MAPPER = new ObjectMapper();
public static final String WELCOME_MESSAGE = "Welcome to the DIYLC AI Assistant!";
private final IPlugInPort plugInPort;
private IChatbotAPI service; private IChatbotAPI service;
private String serviceUrl;
public ChatbotPresenter(IPlugInPort plugInPort) { public ChatbotService(IPlugInPort plugInPort) {
this.plugInPort = plugInPort; this.plugInPort = plugInPort;
} }
private IChatbotAPI getService() { private IChatbotAPI getService() {
if (service == null) { if (service == null) {
serviceUrl = String serviceUrl =
ConfigurationManager.getInstance().readString(IServiceAPI.URL_KEY, "http://www.diy-fever.com/diylc/api/v1/ai"); ConfigurationManager.getInstance().readString(IServiceAPI.URL_KEY, "http://www.diy-fever.com/diylc/api/v1/ai");
ProxyFactory factory = new ProxyFactory(new PhpFlatProxy()); ProxyFactory factory = new ProxyFactory(new PhpFlatProxy());
service = factory.createProxy(IChatbotAPI.class, serviceUrl); service = factory.createProxy(IChatbotAPI.class, serviceUrl);
@@ -97,7 +82,7 @@ public class ChatbotPresenter {
} }
public String promptChatbot(String prompt) throws NotLoggedInException { public String promptChatbot(String prompt) throws NotLoggedInException {
if (!CloudPresenter.Instance.isLoggedIn()) if (!plugInPort.getCloudService().isLoggedIn())
throw new NotLoggedInException(); throw new NotLoggedInException();
String currentFile = plugInPort.getCurrentFileName(); String currentFile = plugInPort.getCurrentFileName();
@@ -111,9 +96,10 @@ public class ChatbotPresenter {
netlist = null; netlist = null;
} }
return getService().promptChatbot(CloudPresenter.Instance.getCurrentUsername(), return getService().promptChatbot(
CloudPresenter.Instance.getCurrentToken(), plugInPort.getCloudService().getCurrentUsername(),
CloudPresenter.Instance.getMachineId(), fileName, netlist, prompt); plugInPort.getCloudService().getCurrentToken(),
plugInPort.getCloudService().getMachineId(), fileName, netlist, prompt);
} }
private static final Set<Class<?>> PROPERTY_TYPES_TO_SKIP = Set.of(Font.class, Color.class); private static final Set<Class<?>> PROPERTY_TYPES_TO_SKIP = Set.of(Font.class, Color.class);
@@ -122,6 +108,10 @@ public class ChatbotPresenter {
private String extractNetlists() throws NetlistException { private String extractNetlists() throws NetlistException {
List<Netlist> netlists = plugInPort.extractNetlists(true); List<Netlist> netlists = plugInPort.extractNetlists(true);
if (netlists == null) {
return null;
}
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("Components: "); sb.append("Components: ");
@@ -183,7 +173,7 @@ public class ChatbotPresenter {
Random r = new Random(); Random r = new Random();
String chatHtml = String chatHtml =
"<div class='system'>Welcome to the DIYLC AI Assistant!</div><br><br>\n" + "<div class='system'>" + WELCOME_MESSAGE + "</div><br><br>\n" +
"<div class='assistant'>I'm here to help you design, build, and troubleshoot your electronics projects using DIY Layout Creator (DIYLC). You can ask me questions about:</div><br>\n" + "<div class='assistant'>I'm here to help you design, build, and troubleshoot your electronics projects using DIY Layout Creator (DIYLC). You can ask me questions about:</div><br>\n" +
// "<ul>\n" + // "<ul>\n" +
"\n" + "\n" +
@@ -195,13 +185,35 @@ public class ChatbotPresenter {
"<br>\n" + "<br>\n" +
"<div class='assistant'>Feel free to ask your own question or use one of these examples to get started!</div><br>\n"; "<div class='assistant'>Feel free to ask your own question or use one of these examples to get started!</div><br>\n";
if (!CloudPresenter.Instance.isLoggedIn()) {
chatHtml = chatHtml + "<div class='system' id='login'>Please log into your DIYLC Cloud account in order to use the AI Assistant.</div><br>\n";
}
return chatHtml; return chatHtml;
} }
public SubscriptionEntity getSubscriptionInfo() throws NotLoggedInException {
if (!plugInPort.getCloudService().isLoggedIn())
throw new NotLoggedInException();
return getService().getSubscriptionInfo(plugInPort.getCloudService().getCurrentUsername(),
plugInPort.getCloudService().getCurrentToken(), plugInPort.getCloudService().getMachineId());
}
public void deleteChatHistory() throws NotLoggedInException {
if (!plugInPort.getCloudService().isLoggedIn())
throw new NotLoggedInException();
getService().deleteChatHistory(plugInPort.getCloudService().getCurrentUsername(),
plugInPort.getCloudService().getCurrentToken(), plugInPort.getCloudService().getMachineId(),
FileUtils.extractFileName(plugInPort.getCurrentFileName()));
}
public List<ChatMessageEntity> getChatHistory() throws NotLoggedInException {
if (!plugInPort.getCloudService().isLoggedIn())
throw new NotLoggedInException();
return getService().getChatHistory(plugInPort.getCloudService().getCurrentUsername(),
plugInPort.getCloudService().getCurrentToken(), plugInPort.getCloudService().getMachineId(),
FileUtils.extractFileName(plugInPort.getCurrentFileName()));
}
public static final String ASSISTANT = "assistant"; public static final String ASSISTANT = "assistant";
public static final String SYSTEM = "system"; public static final String SYSTEM = "system";
public static final String USER = "user"; public static final String USER = "user";
@@ -19,7 +19,7 @@
along with DIYLC. If not, see <http://www.gnu.org/licenses/>. along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.diylc.plugins.cloud.presenter; package org.diylc.plugins.cloud.service;
public class CloudException extends Exception { public class CloudException extends Exception {
@@ -19,7 +19,7 @@
along with DIYLC. If not, see <http://www.gnu.org/licenses/>. along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.diylc.plugins.cloud.presenter; package org.diylc.plugins.cloud.service;
public interface CloudListener { public interface CloudListener {
@@ -19,7 +19,7 @@
along with DIYLC. If not, see <http://www.gnu.org/licenses/>. along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.diylc.plugins.cloud.presenter; package org.diylc.plugins.cloud.service;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
@@ -37,6 +37,8 @@ import org.diylc.appframework.miscutils.ConfigurationManager;
import com.diyfever.httpproxy.PhpFlatProxy; import com.diyfever.httpproxy.PhpFlatProxy;
import com.diyfever.httpproxy.ProxyFactory; import com.diyfever.httpproxy.ProxyFactory;
import org.diylc.common.EventType;
import org.diylc.common.IPlugInPort;
import org.diylc.common.PropertyWrapper; import org.diylc.common.PropertyWrapper;
import org.diylc.plugins.cloud.model.CommentEntity; import org.diylc.plugins.cloud.model.CommentEntity;
import org.diylc.plugins.cloud.model.IServiceAPI; import org.diylc.plugins.cloud.model.IServiceAPI;
@@ -50,17 +52,16 @@ import org.diylc.presenter.ComponentProcessor;
* *
* @author Branislav Stojkovic * @author Branislav Stojkovic
*/ */
public class CloudPresenter { public class CloudService {
public static final CloudPresenter Instance = new CloudPresenter();
private static String USERNAME_KEY = "cloud.Username"; private static String USERNAME_KEY = "cloud.Username";
private static String TOKEN_KEY = "cloud.token"; private static String TOKEN_KEY = "cloud.token";
private static String ERROR = "Error"; private static String ERROR = "Error";
private final static Logger LOG = Logger.getLogger(CloudPresenter.class); private final static Logger LOG = Logger.getLogger(CloudService.class);
private static final Object SUCCESS = "Success"; private static final Object SUCCESS = "Success";
private final IPlugInPort plugInPort;
private IServiceAPI service; private IServiceAPI service;
private String serviceUrl; private String serviceUrl;
@@ -69,7 +70,9 @@ public class CloudPresenter {
private boolean loggedIn = false; private boolean loggedIn = false;
private CloudPresenter() {} public CloudService(IPlugInPort plugInPort) {
this.plugInPort = plugInPort;
}
private IServiceAPI getService() { private IServiceAPI getService() {
if (service == null) { if (service == null) {
@@ -99,6 +102,7 @@ public class CloudPresenter {
ConfigurationManager.getInstance().writeValue(USERNAME_KEY, username); ConfigurationManager.getInstance().writeValue(USERNAME_KEY, username);
ConfigurationManager.getInstance().writeValue(TOKEN_KEY, res); ConfigurationManager.getInstance().writeValue(TOKEN_KEY, res);
this.loggedIn = true; this.loggedIn = true;
this.plugInPort.getMessageDispatcher().dispatchMessage(EventType.CLOUD_LOGGED_IN);
return true; return true;
} }
} }
@@ -121,6 +125,7 @@ public class CloudPresenter {
} else { } else {
LOG.info("Login success"); LOG.info("Login success");
this.loggedIn = true; this.loggedIn = true;
this.plugInPort.getMessageDispatcher().dispatchMessage(EventType.CLOUD_LOGGED_IN);
return true; return true;
} }
} else } else
@@ -130,6 +135,7 @@ public class CloudPresenter {
public void logOut() { public void logOut() {
LOG.info("Logged out"); LOG.info("Logged out");
ConfigurationManager.getInstance().writeValue(TOKEN_KEY, null); ConfigurationManager.getInstance().writeValue(TOKEN_KEY, null);
this.plugInPort.getMessageDispatcher().dispatchMessage(EventType.CLOUD_LOGGED_OUT);
this.loggedIn = false; this.loggedIn = false;
} }
@@ -19,7 +19,7 @@
along with DIYLC. If not, see <http://www.gnu.org/licenses/>. along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.diylc.plugins.cloud.presenter; package org.diylc.plugins.cloud.service;
public class NotConnectedException extends Exception { public class NotConnectedException extends Exception {
@@ -19,7 +19,7 @@
along with DIYLC. If not, see <http://www.gnu.org/licenses/>. along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.diylc.plugins.cloud.presenter; package org.diylc.plugins.cloud.service;
public class NotExistsException extends Exception { public class NotExistsException extends Exception {
@@ -19,7 +19,7 @@
along with DIYLC. If not, see <http://www.gnu.org/licenses/>. along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.diylc.plugins.cloud.presenter; package org.diylc.plugins.cloud.service;
public class NotLoggedInException extends Exception { public class NotLoggedInException extends Exception {
@@ -19,10 +19,11 @@
along with DIYLC. If not, see <http://www.gnu.org/licenses/>. along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.diylc.plugins.cloud.presenter; package org.diylc.plugins.cloud.service;
import java.util.List; import java.util.List;
import org.diylc.common.IPlugInPort;
import org.diylc.plugins.cloud.model.ProjectEntity; import org.diylc.plugins.cloud.model.ProjectEntity;
/** /**
@@ -34,7 +35,8 @@ import org.diylc.plugins.cloud.model.ProjectEntity;
* @author Branislav Stojkovic * @author Branislav Stojkovic
*/ */
public class SearchSession { public class SearchSession {
private final IPlugInPort plugInPort;
private String searchFor; private String searchFor;
private String category; private String category;
private String sort; private String sort;
@@ -43,7 +45,8 @@ public class SearchSession {
private int currentPage; private int currentPage;
private List<ProjectEntity> currentResults; private List<ProjectEntity> currentResults;
public SearchSession() { public SearchSession(IPlugInPort plugInPort) {
this.plugInPort = plugInPort;
} }
public List<ProjectEntity> startSession(String searchFor, String category, String sort) throws CloudException { public List<ProjectEntity> startSession(String searchFor, String category, String sort) throws CloudException {
@@ -52,7 +55,7 @@ public class SearchSession {
this.sort = sort; this.sort = sort;
this.currentPage = 1; this.currentPage = 1;
return currentResults = CloudPresenter.Instance.search(searchFor, category, sort, currentPage, itemsPerPage); return currentResults = plugInPort.getCloudService().search(searchFor, category, sort, currentPage, itemsPerPage);
} }
public boolean hasMoreData() { public boolean hasMoreData() {
@@ -61,6 +64,6 @@ public class SearchSession {
public List<ProjectEntity> requestMoreData() throws CloudException { public List<ProjectEntity> requestMoreData() throws CloudException {
currentPage++; currentPage++;
return currentResults = CloudPresenter.Instance.search(searchFor, category, sort, currentPage, itemsPerPage); return currentResults = plugInPort.getCloudService().search(searchFor, category, sort, currentPage, itemsPerPage);
} }
} }
@@ -47,7 +47,6 @@ import java.util.function.Supplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.diylc.appframework.miscutils.IConfigListener;
import org.diylc.appframework.miscutils.IConfigurationManager; import org.diylc.appframework.miscutils.IConfigurationManager;
import org.diylc.appframework.miscutils.Utils; import org.diylc.appframework.miscutils.Utils;
import org.diylc.appframework.simplemq.MessageDispatcher; import org.diylc.appframework.simplemq.MessageDispatcher;
@@ -78,6 +77,8 @@ import org.diylc.netlist.Netlist;
import org.diylc.netlist.AbstractNetlistAnalyzer; import org.diylc.netlist.AbstractNetlistAnalyzer;
import org.diylc.netlist.NetlistBuilder; import org.diylc.netlist.NetlistBuilder;
import org.diylc.netlist.NetlistException; import org.diylc.netlist.NetlistException;
import org.diylc.plugins.chatbot.service.ChatbotService;
import org.diylc.plugins.cloud.service.CloudService;
import org.diylc.serialization.ProjectFileManager; import org.diylc.serialization.ProjectFileManager;
import org.diylc.test.DIYTest; import org.diylc.test.DIYTest;
import org.diylc.test.Snapshot; import org.diylc.test.Snapshot;
@@ -2810,7 +2811,27 @@ public class Presenter implements IPlugInPort {
messageDispatcher.dispatchMessage(EventType.STATUS_MESSAGE_CHANGED); messageDispatcher.dispatchMessage(EventType.STATUS_MESSAGE_CHANGED);
} }
protected MessageDispatcher<EventType> getMessageDispatcher() { private CloudService cloudService;
@Override
public CloudService getCloudService() {
if (cloudService == null) {
cloudService = new CloudService(this);
}
return cloudService;
}
private ChatbotService chatbotService;
@Override
public ChatbotService getChatbotService() {
if (chatbotService == null) {
chatbotService = new ChatbotService(this);
}
return chatbotService;
}
public MessageDispatcher<EventType> getMessageDispatcher() {
return messageDispatcher; return messageDispatcher;
} }
} }
@@ -3,14 +3,16 @@ package org.diylc.swing.plugins.chatbot;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.diylc.common.IPlugInPort; import org.diylc.common.IPlugInPort;
import org.diylc.common.ITask; import org.diylc.common.ITask;
import org.diylc.plugins.chatbot.presenter.ChatbotPresenter; import org.diylc.plugins.chatbot.model.ChatMessageEntity;
import org.diylc.plugins.cloud.presenter.CloudPresenter; import org.diylc.plugins.chatbot.model.SubscriptionEntity;
import org.diylc.plugins.chatbot.service.ChatbotService;
import org.diylc.plugins.cloud.service.NotLoggedInException;
import org.diylc.swing.ISwingUI; import org.diylc.swing.ISwingUI;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.io.File; import java.util.List;
import java.util.Random; import java.util.Objects;
public class ChatbotPane extends JPanel { public class ChatbotPane extends JPanel {
@@ -22,22 +24,32 @@ public class ChatbotPane extends JPanel {
private static final Font MONOSPACED_FONT = new Font("Monospaced", Font.PLAIN, 12); private static final Font MONOSPACED_FONT = new Font("Monospaced", Font.PLAIN, 12);
private static final Color TERMINAL_BG = new Color(40, 40, 40); private static final Color TERMINAL_BG = new Color(40, 40, 40);
private static final Color TERMINAL_FG = new Color(200, 200, 200); private static final Color TERMINAL_FG = new Color(200, 200, 200);
public static final String HTML_STYLE = String.format(
"<style>" + "body { font-family: %s; font-size: %dpt; color: rgb(%d,%d,%d); background-color: rgb(%d,%d,%d); padding: 0px; margin: 0; }" + "pre { white-space: pre-wrap; margin: 0; }" + ".user { color: #98C379; }" + // Softer green that's easier on the eyes
".assistant { color: #61AFEF; }" + // Lighter, more vibrant blue
".system { color: #E5C07B; }" + // Warmer, muted yellow
".temporary { color: #555555; }" + "</style>", MONOSPACED_FONT.getFamily(),
MONOSPACED_FONT.getSize(), TERMINAL_FG.getRed(), TERMINAL_FG.getGreen(),
TERMINAL_FG.getBlue(), TERMINAL_BG.getRed(), TERMINAL_BG.getGreen(), TERMINAL_BG.getBlue());
private static final Color PROMPT_BG = new Color(60, 60, 60); // Slightly brighter than TERMINAL_BG private static final Color PROMPT_BG = new Color(60, 60, 60); // Slightly brighter than TERMINAL_BG
private ISwingUI swingUI; private ISwingUI swingUI;
private IPlugInPort plugInPort; private IPlugInPort plugInPort;
private ChatbotPresenter chatbotPresenter; private ChatbotService chatbotService;
private JTextArea promptArea; private JTextArea promptArea;
private JEditorPane chatEditorPane; private JEditorPane chatEditorPane;
private JButton askButton; private JButton askButton;
private JButton clearButton; private JButton clearButton;
private boolean loggedIn = false;
private String projectFileName = null;
public ChatbotPane(ISwingUI swingUI, IPlugInPort plugInPort) { public ChatbotPane(ISwingUI swingUI, IPlugInPort plugInPort) {
super(); super();
this.swingUI = swingUI; this.swingUI = swingUI;
this.plugInPort = plugInPort; this.plugInPort = plugInPort;
this.chatbotPresenter = new ChatbotPresenter(plugInPort); this.chatbotService = new ChatbotService(plugInPort);
setName("AI Assistant"); setName("AI Assistant");
// Set panel background color // Set panel background color
@@ -134,7 +146,7 @@ public class ChatbotPane extends JPanel {
promptArea.setPreferredSize(new Dimension(200, desiredHeight)); promptArea.setPreferredSize(new Dimension(200, desiredHeight));
// Add placeholder text behavior // Add placeholder text behavior
final String placeholder = "Type your question here..."; final String placeholder = "Ask me anything";
promptArea.setText(placeholder); promptArea.setText(placeholder);
promptArea.setForeground(new Color(128, 128, 128)); // Dimmer text for placeholder promptArea.setForeground(new Color(128, 128, 128)); // Dimmer text for placeholder
@@ -188,6 +200,41 @@ public class ChatbotPane extends JPanel {
return promptArea; return promptArea;
} }
public void refreshChat() {
boolean currentLoggedIn = plugInPort.getCloudService().isLoggedIn();
String currentProjectFileName = plugInPort.getCurrentFileName();
if (this.loggedIn == currentLoggedIn && Objects.equals(currentProjectFileName, this.projectFileName))
return;
this.loggedIn = currentLoggedIn;
this.projectFileName = currentProjectFileName;
resetChat();
try {
SubscriptionEntity subscriptionInfo = plugInPort.getChatbotService().getSubscriptionInfo();
appendSection(ChatbotService.SYSTEM, "Subscribed to " + subscriptionInfo.getTier() +
" tier with " + subscriptionInfo.getRemainingCredits() + " remaining credits.");
} catch (NotLoggedInException e) {
LOG.error("Error getting subscription info", e);
appendSection(ChatbotService.SYSTEM, "Error getting subscription info");
}
fetchChatHistory();
getAskButton().setEnabled(true);
}
private void fetchChatHistory() {
try {
List<ChatMessageEntity> chatHistory = plugInPort.getChatbotService().getChatHistory();
chatHistory.forEach(message -> {
appendSection(ChatbotService.USER, message.getPrompt());
appendSection(ChatbotService.ASSISTANT, message.getResponse());
});
} catch (NotLoggedInException e) {
appendSection(ChatbotService.SYSTEM, "Failed to retrieve chat history.");
}
}
public JEditorPane getChatEditorPane() { public JEditorPane getChatEditorPane() {
if (chatEditorPane == null) { if (chatEditorPane == null) {
chatEditorPane = new JEditorPane("text/html", "<html></html>"); chatEditorPane = new JEditorPane("text/html", "<html></html>");
@@ -196,30 +243,20 @@ public class ChatbotPane extends JPanel {
chatEditorPane.setBackground(TERMINAL_BG); chatEditorPane.setBackground(TERMINAL_BG);
chatEditorPane.setForeground(TERMINAL_FG); chatEditorPane.setForeground(TERMINAL_FG);
chatEditorPane.setCaretColor(TERMINAL_FG); // Make the cursor visible on dark background chatEditorPane.setCaretColor(TERMINAL_FG); // Make the cursor visible on dark background
// Set up HTML styling
String htmlStyle = String.format(
"<style>" +
"body { font-family: %s; font-size: %dpt; color: rgb(%d,%d,%d); background-color: rgb(%d,%d,%d); padding: 0px; margin: 0; }" +
"pre { white-space: pre-wrap; margin: 0; }" +
".user { color: #98C379; }" + // Softer green that's easier on the eyes
".assistant { color: #61AFEF; }" + // Lighter, more vibrant blue
".system { color: #E5C07B; }" + // Warmer, muted yellow
".temporary { color: #555555; }" +
"</style>",
MONOSPACED_FONT.getFamily(),
MONOSPACED_FONT.getSize(),
TERMINAL_FG.getRed(), TERMINAL_FG.getGreen(), TERMINAL_FG.getBlue(),
TERMINAL_BG.getRed(), TERMINAL_BG.getGreen(), TERMINAL_BG.getBlue());
String sampleChat = chatbotPresenter.getInitialChatContents();
chatEditorPane.setContentType("text/html"); chatEditorPane.setContentType("text/html");
chatEditorPane.setText(htmlStyle + "<body><pre>" + sampleChat + "</pre></body>"); chatEditorPane.setText(HTML_STYLE + "<body></body>");
} }
return chatEditorPane; return chatEditorPane;
} }
private void resetChat() {
String sampleChat = chatbotService.getInitialChatContents();
chatEditorPane.setContentType("text/html");
chatEditorPane.setText(HTML_STYLE + "<body>" + sampleChat + "</body>");
}
public JButton getAskButton() { public JButton getAskButton() {
if (askButton == null) { if (askButton == null) {
askButton = new JButton("Ask"); askButton = new JButton("Ask");
@@ -229,8 +266,8 @@ public class ChatbotPane extends JPanel {
askButton.setBorderPainted(true); askButton.setBorderPainted(true);
askButton.addActionListener(e -> { askButton.addActionListener(e -> {
final String prompt = getPromptArea().getText(); final String prompt = getPromptArea().getText();
appendSection(ChatbotPresenter.USER, prompt); appendSection(ChatbotService.USER, prompt);
appendSection(ChatbotPresenter.TEMPORARY, "Waiting for the response..."); appendSection(ChatbotService.TEMPORARY, "Waiting for the response...");
getPromptArea().setText(null); getPromptArea().setText(null);
@@ -240,19 +277,19 @@ public class ChatbotPane extends JPanel {
@Override @Override
public String doInBackground() throws Exception { public String doInBackground() throws Exception {
return chatbotPresenter.promptChatbot(prompt); return chatbotService.promptChatbot(prompt);
} }
@Override @Override
public void failed(Exception e) { public void failed(Exception e) {
appendSection(ChatbotPresenter.SYSTEM, "Failed to retrieve the response from the server. Error: " + e.getMessage()); appendSection(ChatbotService.SYSTEM, "Failed to retrieve the response from the server.");
LOG.error("Failed to retrieve the response from the server", e); LOG.error("Failed to retrieve the response from the server", e);
getClearButton().setEnabled(true); getClearButton().setEnabled(true);
} }
@Override @Override
public void complete(String result) { public void complete(String result) {
appendSection(ChatbotPresenter.ASSISTANT, result); appendSection(ChatbotService.ASSISTANT, result);
getClearButton().setEnabled(true); getClearButton().setEnabled(true);
} }
}, false); }, false);
@@ -261,7 +298,7 @@ public class ChatbotPane extends JPanel {
return askButton; return askButton;
} }
private void appendSection(String style, String insertText) { void appendSection(String style, String insertText) {
String text = getChatEditorPane().getText(); String text = getChatEditorPane().getText();
// remove any temporary divs // remove any temporary divs
String regex = "(?s)<div\\s+class=[\"']temporary[\"'][^>]*>.*?</div>\\s*<br>\\s*"; String regex = "(?s)<div\\s+class=[\"']temporary[\"'][^>]*>.*?</div>\\s*<br>\\s*";
@@ -281,6 +318,29 @@ public class ChatbotPane extends JPanel {
clearButton.setForeground(TERMINAL_FG); clearButton.setForeground(TERMINAL_FG);
clearButton.setFocusPainted(false); clearButton.setFocusPainted(false);
clearButton.setBorderPainted(true); clearButton.setBorderPainted(true);
clearButton.addActionListener(e -> {
swingUI.executeBackgroundTask(new ITask<Void>() {
@Override
public Void doInBackground() throws Exception {
chatbotService.deleteChatHistory();
return null;
}
@Override
public void failed(Exception e) {
appendSection(ChatbotService.SYSTEM, "Failed to delete chat history from the server.");
LOG.error("Failed to delete chat history from the server", e);
getClearButton().setEnabled(true);
}
@Override
public void complete(Void result) {
resetChat();
}
}, false);
});
} }
return clearButton; return clearButton;
} }
@@ -26,15 +26,11 @@ import org.diylc.common.BadPositionException;
import org.diylc.common.EventType; import org.diylc.common.EventType;
import org.diylc.common.IPlugIn; import org.diylc.common.IPlugIn;
import org.diylc.common.IPlugInPort; import org.diylc.common.IPlugInPort;
import org.diylc.core.IDIYComponent;
import org.diylc.core.Project;
import org.diylc.plugins.cloud.presenter.CloudPresenter;
import org.diylc.swing.ISwingUI; import org.diylc.swing.ISwingUI;
import org.diylc.swing.plugins.config.ConfigPlugin; import org.diylc.swing.plugins.config.ConfigPlugin;
import javax.swing.*; import javax.swing.*;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Set;
public class ChatbotPlugin implements IPlugIn { public class ChatbotPlugin implements IPlugIn {
@@ -47,31 +43,44 @@ public class ChatbotPlugin implements IPlugIn {
public ChatbotPlugin(ISwingUI swingUI) { public ChatbotPlugin(ISwingUI swingUI) {
super(); super();
this.swingUI = swingUI; this.swingUI = swingUI;
// Delay a test of logged in state to give it time to complete
Timer timer = new Timer(2000, e -> {
if (!plugInPort.getCloudService().isLoggedIn()) {
getChatbotPane().refreshChat();
}
});
timer.setRepeats(false); // Make it one-shot
timer.start();
} }
@Override @Override
public EnumSet<EventType> getSubscribedEventTypes() { public EnumSet<EventType> getSubscribedEventTypes() {
return EnumSet.of(EventType.FILE_STATUS_CHANGED, EventType.PROJECT_LOADED, return EnumSet.of(EventType.FILE_STATUS_CHANGED, EventType.PROJECT_LOADED,
EventType.PROJECT_MODIFIED, EventType.SELECTION_CHANGED); EventType.PROJECT_MODIFIED, EventType.SELECTION_CHANGED, EventType.CLOUD_LOGGED_IN,
EventType.CLOUD_LOGGED_OUT);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public void processMessage(EventType eventType, Object... params) { public void processMessage(EventType eventType, Object... params) {
// switch (eventType) { switch (eventType) {
// case PROJECT_MODIFIED: case PROJECT_MODIFIED:
// getChatbotPane().setComponents(((Project) params[1]).getComponents(), // getChatbotPane().setComponents(((Project) params[1]).getComponents(),
// plugInPort.getSelectedComponents()); // plugInPort.getSelectedComponents());
// break; break;
// case PROJECT_LOADED: case SELECTION_CHANGED:
// getChatbotPane().setComponents(((Project) params[0]).getComponents(),
// plugInPort.getSelectedComponents());
// break;
// case SELECTION_CHANGED:
// getChatbotPane().setSelection((Set<IDIYComponent<?>>) params[0]); // getChatbotPane().setSelection((Set<IDIYComponent<?>>) params[0]);
// default: break;
// break; case FILE_STATUS_CHANGED:
// } case PROJECT_LOADED:
case CLOUD_LOGGED_IN:
case CLOUD_LOGGED_OUT:
getChatbotPane().refreshChat();
break;
default:
break;
}
} }
@Override @Override
@@ -31,6 +31,7 @@ import javax.imageio.ImageIO;
import javax.swing.AbstractAction; import javax.swing.AbstractAction;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.diylc.appframework.miscutils.InMemoryConfigurationManager; import org.diylc.appframework.miscutils.InMemoryConfigurationManager;
import org.diylc.plugins.cloud.service.CloudService;
import org.diylc.swingframework.ButtonDialog; import org.diylc.swingframework.ButtonDialog;
import org.diylc.common.EventType; import org.diylc.common.EventType;
@@ -38,8 +39,7 @@ import org.diylc.common.IPlugIn;
import org.diylc.common.IPlugInPort; import org.diylc.common.IPlugInPort;
import org.diylc.common.ITask; import org.diylc.common.ITask;
import org.diylc.core.IView; import org.diylc.core.IView;
import org.diylc.plugins.cloud.presenter.CloudException; import org.diylc.plugins.cloud.service.CloudException;
import org.diylc.plugins.cloud.presenter.CloudPresenter;
import org.diylc.presenter.Presenter; import org.diylc.presenter.Presenter;
import org.diylc.swing.ISwingUI; import org.diylc.swing.ISwingUI;
import org.diylc.swing.gui.DialogFactory; import org.diylc.swing.gui.DialogFactory;
@@ -63,6 +63,7 @@ public class CloudPlugIn implements IPlugIn {
private IPlugInPort plugInPort; private IPlugInPort plugInPort;
private IPlugInPort thumbnailPresenter; private IPlugInPort thumbnailPresenter;
private ThumbnailGenerator thumbnailGenerator; private ThumbnailGenerator thumbnailGenerator;
private CloudService cloudService;
private LibraryAction libraryAction; private LibraryAction libraryAction;
@@ -106,6 +107,7 @@ public class CloudPlugIn implements IPlugIn {
@Override @Override
public void connect(IPlugInPort plugInPort) { public void connect(IPlugInPort plugInPort) {
this.plugInPort = plugInPort; this.plugInPort = plugInPort;
this.cloudService = plugInPort.getCloudService();
initialize(); initialize();
} }
@@ -115,7 +117,7 @@ public class CloudPlugIn implements IPlugIn {
@Override @Override
public Boolean doInBackground() throws Exception { public Boolean doInBackground() throws Exception {
return CloudPresenter.Instance.tryLogInWithToken(); return cloudService.tryLogInWithToken();
} }
@Override @Override
@@ -244,7 +246,7 @@ public class CloudPlugIn implements IPlugIn {
dialog.setVisible(true); dialog.setVisible(true);
if (ButtonDialog.OK.equals(dialog.getSelectedButtonCaption())) { if (ButtonDialog.OK.equals(dialog.getSelectedButtonCaption())) {
try { try {
if (CloudPresenter.Instance.logIn(dialog.getUserName(), dialog.getPassword())) { if (plugInPort.getCloudService().logIn(dialog.getUserName(), dialog.getPassword())) {
swingUI swingUI
.showMessage( .showMessage(
"You have successfully logged into the system. You will remain logged in from this machine until logged out.", "You have successfully logged into the system. You will remain logged in from this machine until logged out.",
@@ -277,7 +279,7 @@ public class CloudPlugIn implements IPlugIn {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
CloudPresenter.Instance.logOut(); cloudService.logOut();
loggedOut(); loggedOut();
} }
} }
@@ -301,7 +303,7 @@ public class CloudPlugIn implements IPlugIn {
@Override @Override
public Void doInBackground() throws Exception { public Void doInBackground() throws Exception {
CloudPresenter.Instance.createUserAccount(dialog.getUserName(), dialog.getPassword(), dialog.getEmail(), cloudService.createUserAccount(dialog.getUserName(), dialog.getPassword(), dialog.getEmail(),
dialog.getWebsite(), dialog.getBio()); dialog.getWebsite(), dialog.getBio());
return null; return null;
} }
@@ -335,14 +337,14 @@ public class CloudPlugIn implements IPlugIn {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
try { try {
final UserEditDialog dialog = final UserEditDialog dialog =
DialogFactory.getInstance().createUserEditDialog(CloudPresenter.Instance.getUserDetails()); DialogFactory.getInstance().createUserEditDialog(plugInPort.getCloudService().getUserDetails());
dialog.setVisible(true); dialog.setVisible(true);
if (ButtonDialog.OK.equals(dialog.getSelectedButtonCaption())) { if (ButtonDialog.OK.equals(dialog.getSelectedButtonCaption())) {
swingUI.executeBackgroundTask(new ITask<Void>() { swingUI.executeBackgroundTask(new ITask<Void>() {
@Override @Override
public Void doInBackground() throws Exception { public Void doInBackground() throws Exception {
CloudPresenter.Instance.updateUserDetails(dialog.getEmail(), dialog.getWebsite(), dialog.getBio()); cloudService.updateUserDetails(dialog.getEmail(), dialog.getWebsite(), dialog.getBio());
return null; return null;
} }
@@ -384,7 +386,7 @@ public class CloudPlugIn implements IPlugIn {
@Override @Override
public Void doInBackground() throws Exception { public Void doInBackground() throws Exception {
CloudPresenter.Instance.updatePassword(dialog.getOldPassword(), dialog.getNewPassword()); cloudService.updatePassword(dialog.getOldPassword(), dialog.getNewPassword());
return null; return null;
} }
@@ -431,7 +433,7 @@ public class CloudPlugIn implements IPlugIn {
public String[] doInBackground() throws Exception { public String[] doInBackground() throws Exception {
LOG.debug("Uploading from " + file.getAbsolutePath()); LOG.debug("Uploading from " + file.getAbsolutePath());
thumbnailPresenter.loadProjectFromFile(file.getAbsolutePath()); thumbnailPresenter.loadProjectFromFile(file.getAbsolutePath());
return CloudPresenter.Instance.getCategories(); return cloudService.getCategories();
} }
@Override @Override
@@ -448,7 +450,7 @@ public class CloudPlugIn implements IPlugIn {
@Override @Override
public Void doInBackground() throws Exception { public Void doInBackground() throws Exception {
CloudPresenter.Instance.uploadProject(dialog.getName(), dialog.getCategory(), dialog cloudService.uploadProject(dialog.getName(), dialog.getCategory(), dialog
.getDescription(), dialog.getKeywords(), plugInPort.getCurrentVersionNumber().toString(), .getDescription(), dialog.getKeywords(), plugInPort.getCurrentVersionNumber().toString(),
thumbnailFile, file, null); thumbnailFile, file, null);
return null; return null;
@@ -37,11 +37,11 @@ import javax.swing.JScrollPane;
import javax.swing.JSeparator; import javax.swing.JSeparator;
import javax.swing.JTextArea; import javax.swing.JTextArea;
import org.diylc.common.IPlugInPort;
import org.diylc.common.ITask; import org.diylc.common.ITask;
import org.diylc.core.IView; import org.diylc.core.IView;
import org.diylc.plugins.cloud.model.CommentEntity; import org.diylc.plugins.cloud.model.CommentEntity;
import org.diylc.plugins.cloud.model.ProjectEntity; import org.diylc.plugins.cloud.model.ProjectEntity;
import org.diylc.plugins.cloud.presenter.CloudPresenter;
import org.diylc.swing.ISimpleView; import org.diylc.swing.ISimpleView;
import org.diylc.swing.gui.components.HTMLTextArea; import org.diylc.swing.gui.components.HTMLTextArea;
@@ -57,6 +57,7 @@ public class CommentDialog extends JDialog {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private final IPlugInPort plugInPort;
private ProjectEntity project; private ProjectEntity project;
private List<CommentEntity> comments; private List<CommentEntity> comments;
@@ -69,8 +70,9 @@ public class CommentDialog extends JDialog {
private ISimpleView cloudUI; private ISimpleView cloudUI;
public CommentDialog(ISimpleView cloudUI, ProjectEntity project, List<CommentEntity> comments) { public CommentDialog(ISimpleView cloudUI, IPlugInPort plugInPort, ProjectEntity project, List<CommentEntity> comments) {
super(cloudUI.getOwnerFrame(), "Comments on " + project.getName()); super(cloudUI.getOwnerFrame(), "Comments on " + project.getName());
this.plugInPort = plugInPort;
this.project = project; this.project = project;
this.comments = comments; this.comments = comments;
this.cloudUI = cloudUI; this.cloudUI = cloudUI;
@@ -79,7 +81,7 @@ public class CommentDialog extends JDialog {
pack(); pack();
setLocationRelativeTo(cloudUI.getOwnerFrame()); setLocationRelativeTo(cloudUI.getOwnerFrame());
setModal(true); setModal(true);
if (!CloudPresenter.Instance.isLoggedIn()) { if (!plugInPort.getCloudService().isLoggedIn()) {
getReplyArea().setEnabled(false); getReplyArea().setEnabled(false);
getReplyArea().setText("Must be logged in to reply."); getReplyArea().setText("Must be logged in to reply.");
getSendButton().setEnabled(false); getSendButton().setEnabled(false);
@@ -162,7 +164,7 @@ public class CommentDialog extends JDialog {
@Override @Override
public Void doInBackground() throws Exception { public Void doInBackground() throws Exception {
CloudPresenter.Instance.postComment(project.getId(), comment); plugInPort.getCloudService().postComment(project.getId(), comment);
return null; return null;
} }
@@ -176,7 +178,7 @@ public class CommentDialog extends JDialog {
getReplyArea().setText(""); getReplyArea().setText("");
CommentEntity newComment = new CommentEntity(); CommentEntity newComment = new CommentEntity();
newComment.setPostedAt(JUST_NOW); newComment.setPostedAt(JUST_NOW);
newComment.setUsername(CloudPresenter.Instance.getCurrentUsername()); newComment.setUsername(plugInPort.getCloudService().getCurrentUsername());
newComment.setComment(comment); newComment.setComment(comment);
addComment(newComment).requestFocusInWindow(); addComment(newComment).requestFocusInWindow();
getListPanel().revalidate(); getListPanel().revalidate();
@@ -45,8 +45,7 @@ import org.diylc.common.IPlugInPort;
import org.diylc.common.ITask; import org.diylc.common.ITask;
import org.diylc.core.IView; import org.diylc.core.IView;
import org.diylc.plugins.cloud.model.ProjectEntity; import org.diylc.plugins.cloud.model.ProjectEntity;
import org.diylc.plugins.cloud.presenter.CloudPresenter; import org.diylc.plugins.cloud.service.SearchSession;
import org.diylc.plugins.cloud.presenter.SearchSession;
import org.diylc.swing.ISimpleView; import org.diylc.swing.ISimpleView;
import org.diylc.swing.ISwingUI; import org.diylc.swing.ISwingUI;
import org.diylc.utils.IconLoader; import org.diylc.utils.IconLoader;
@@ -84,7 +83,7 @@ public class CloudBrowserFrame extends JFrame implements ISimpleView {
this.setIconImage(IconLoader.Cloud.getImage()); this.setIconImage(IconLoader.Cloud.getImage());
this.setPreferredSize(new Dimension(700, 640)); this.setPreferredSize(new Dimension(700, 640));
this.plugInPort = plugInPort; this.plugInPort = plugInPort;
this.searchSession = new SearchSession(); this.searchSession = new SearchSession(plugInPort);
setContentPane(getSearchPanel()); setContentPane(getSearchPanel());
this.pack(); this.pack();
@@ -103,7 +102,9 @@ public class CloudBrowserFrame extends JFrame implements ISimpleView {
@Override @Override
public Pair<String[], String[]> doInBackground() throws Exception { public Pair<String[], String[]> doInBackground() throws Exception {
return new Pair<String[], String[]>(CloudPresenter.Instance.getCategories(), CloudPresenter.Instance.getSortings()); return new Pair<String[], String[]>(
plugInPort.getCloudService().getCategories(),
plugInPort.getCloudService().getSortings());
} }
@Override @Override
@@ -59,8 +59,7 @@ import org.diylc.common.PropertyWrapper;
import org.diylc.core.IView; import org.diylc.core.IView;
import org.diylc.plugins.cloud.model.CommentEntity; import org.diylc.plugins.cloud.model.CommentEntity;
import org.diylc.plugins.cloud.model.ProjectEntity; import org.diylc.plugins.cloud.model.ProjectEntity;
import org.diylc.plugins.cloud.presenter.CloudPresenter; import org.diylc.plugins.cloud.service.SearchSession;
import org.diylc.plugins.cloud.presenter.SearchSession;
import org.diylc.presenter.Presenter; import org.diylc.presenter.Presenter;
import org.diylc.swing.ISimpleView; import org.diylc.swing.ISimpleView;
import org.diylc.swing.ISwingUI; import org.diylc.swing.ISwingUI;
@@ -234,7 +233,7 @@ public class ResultsScrollPanel extends JScrollPane {
@Override @Override
public List<CommentEntity> doInBackground() throws Exception { public List<CommentEntity> doInBackground() throws Exception {
return CloudPresenter.Instance.getComments(project.getId()); return plugInPort.getCloudService().getComments(project.getId());
} }
@Override @Override
@@ -245,7 +244,7 @@ public class ResultsScrollPanel extends JScrollPane {
@Override @Override
public void complete(List<CommentEntity> result) { public void complete(List<CommentEntity> result) {
CommentDialog dialog = new CommentDialog(cloudUI, project, result); CommentDialog dialog = new CommentDialog(cloudUI, plugInPort, project, result);
dialog.setVisible(true); dialog.setVisible(true);
} }
@@ -343,7 +342,7 @@ public class ResultsScrollPanel extends JScrollPane {
editButton.addMouseListener(new MouseAdapter() { editButton.addMouseListener(new MouseAdapter() {
@Override @Override
public void mouseClicked(MouseEvent e) { public void mouseClicked(MouseEvent e) {
List<PropertyWrapper> projectProperties = CloudPresenter.Instance.getProjectProperties(project); List<PropertyWrapper> projectProperties = plugInPort.getCloudService().getProjectProperties(project);
PropertyEditorDialog editor = PropertyEditorDialog editor =
DialogFactory.getInstance().createPropertyEditorDialog(cloudUI.getOwnerFrame(), projectProperties, DialogFactory.getInstance().createPropertyEditorDialog(cloudUI.getOwnerFrame(), projectProperties,
"Edit Published Project", true); "Edit Published Project", true);
@@ -364,8 +363,8 @@ public class ResultsScrollPanel extends JScrollPane {
@Override @Override
public ProjectEntity doInBackground() throws Exception { public ProjectEntity doInBackground() throws Exception {
CloudPresenter.Instance.updateProjectDetails(project, plugInPort.getCurrentVersionNumber().toString()); plugInPort.getCloudService().updateProjectDetails(project, plugInPort.getCurrentVersionNumber().toString());
return CloudPresenter.Instance.fetchUserUploads(project.getId()).get(0); return plugInPort.getCloudService().fetchUserUploads(project.getId()).get(0);
} }
@Override @Override
@@ -418,11 +417,11 @@ public class ResultsScrollPanel extends JScrollPane {
thumbnailPresenter.loadProjectFromFile(file.getAbsolutePath()); thumbnailPresenter.loadProjectFromFile(file.getAbsolutePath());
final File thumbnailFile = File.createTempFile("upload-thumbnail", ".png"); final File thumbnailFile = File.createTempFile("upload-thumbnail", ".png");
if (ImageIO.write(thumbnailGenerator.getThumbnail(), "png", thumbnailFile)) { if (ImageIO.write(thumbnailGenerator.getThumbnail(), "png", thumbnailFile)) {
CloudPresenter.Instance.replaceProjectFile( plugInPort.getCloudService().replaceProjectFile(
plugInPort.getCurrentVersionNumber().toString(), thumbnailFile, file, plugInPort.getCurrentVersionNumber().toString(), thumbnailFile, file,
project.getId()); project.getId());
return new Pair<BufferedImage, ProjectEntity>(thumbnailGenerator.getThumbnail(), return new Pair<BufferedImage, ProjectEntity>(thumbnailGenerator.getThumbnail(),
CloudPresenter.Instance.fetchUserUploads(project.getId()).get(0)); plugInPort.getCloudService().fetchUserUploads(project.getId()).get(0));
} else { } else {
cloudUI.showMessage( cloudUI.showMessage(
"Could not prepare temporary files to be uploaded to the cloud.", "Could not prepare temporary files to be uploaded to the cloud.",
@@ -478,7 +477,7 @@ public class ResultsScrollPanel extends JScrollPane {
@Override @Override
public Void doInBackground() throws Exception { public Void doInBackground() throws Exception {
CloudPresenter.Instance.deleteProject(project.getId()); plugInPort.getCloudService().deleteProject(project.getId());
return null; return null;
} }
@@ -33,7 +33,6 @@ import org.diylc.common.IPlugInPort;
import org.diylc.common.ITask; import org.diylc.common.ITask;
import org.diylc.core.IView; import org.diylc.core.IView;
import org.diylc.plugins.cloud.model.ProjectEntity; import org.diylc.plugins.cloud.model.ProjectEntity;
import org.diylc.plugins.cloud.presenter.CloudPresenter;
import org.diylc.swing.ISimpleView; import org.diylc.swing.ISimpleView;
import org.diylc.swing.ISwingUI; import org.diylc.swing.ISwingUI;
import org.diylc.utils.IconLoader; import org.diylc.utils.IconLoader;
@@ -80,7 +79,7 @@ public class UploadManagerFrame extends JFrame implements ISimpleView {
@Override @Override
public List<ProjectEntity> doInBackground() throws Exception { public List<ProjectEntity> doInBackground() throws Exception {
return CloudPresenter.Instance.fetchUserUploads(null); return plugInPort.getCloudService().fetchUserUploads(null);
} }
@Override @Override