Skip to content

Commit

Permalink
Merge pull request #75 from gyorokpeter/reapply
Browse files Browse the repository at this point in the history
Reapply
  • Loading branch information
gyorokpeter authored Mar 14, 2022
2 parents 9c05f58 + 48dbd44 commit a53ec90
Show file tree
Hide file tree
Showing 17 changed files with 594 additions and 154 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ build/
.classpath
.project
.settings
Thumbs.db
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ dependencies {
implementation group: 'org.jfree', name: 'jfreechart', version: '1.5.3'
implementation group: 'org.apache.poi', name: 'poi', version: '5.1.0'
implementation group: 'org.apache.poi', name: 'poi-ooxml', version: '5.1.0'
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version:'2.11.2'
implementation group: 'org.drjekyll', name: 'fontchooser', version: '2.4'
implementation group: 'net.java.dev.jna', name: 'jna', version: '5.10.0'

Expand Down
3 changes: 2 additions & 1 deletion src/main/kx/c.java
Original file line number Diff line number Diff line change
Expand Up @@ -590,7 +590,8 @@ private K.KBase k(ProgressCallback progress) throws K4Exception, IOException {

if (b[0] == -128) {
j = 1;
throw new K4Exception(rs().toString());
//showType=false because an error is NOT a symbol, this would cause confusion with novice users who can't tell the difference
throw new K4Exception(rs().toString(false));
}
return r();
}
Expand Down
File renamed without changes.
8 changes: 7 additions & 1 deletion src/main/studio/core/Studio.java
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,13 @@ private static void initTaskbarIcon() {
Class taskbarClass = Class.forName("java.awt.Taskbar");
Object taskbar = taskbarClass.getDeclaredMethod("getTaskbar").invoke(taskbarClass);
taskbarClass.getDeclaredMethod("setIconImage", Image.class).invoke(taskbar, Util.LOGO_ICON.getImage());
} catch (Exception e) {
}catch (java.lang.reflect.InvocationTargetException e) {
if (e.getCause() instanceof java.lang.UnsupportedOperationException) {
//no need to report - always happens on Windows
} else {
log.error("Failed to set Taskbar icon", e);
}
}catch (Exception e) {
log.error("Failed to set Taskbar icon", e);
}
}
Expand Down
234 changes: 215 additions & 19 deletions src/main/studio/kdb/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import studio.core.Credentials;
import studio.core.DefaultAuthenticationMechanism;
import studio.ui.ServerList;
import studio.ui.Util;
import studio.utils.HistoricalList;
import studio.utils.LineEnding;
import studio.utils.QConnection;
Expand All @@ -22,6 +23,10 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.swing.tree.TreeNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.JsonNode;

public class Config {
private static final Logger log = LogManager.getLogger();
Expand Down Expand Up @@ -85,6 +90,7 @@ private enum ConfigType { STRING, INT, DOUBLE, BOOLEAN, FONT, BOUNDS, COLOR, ENU
public static final String OPEN_FILE_CHOOSER = configDefault("openFileChooser", ConfigType.FILE_CHOOSER, new FileChooserConfig());
public static final String SAVE_FILE_CHOOSER = configDefault("saveFileChooser", ConfigType.FILE_CHOOSER, new FileChooserConfig());
public static final String EXPORT_FILE_CHOOSER = configDefault("exportFileChooser", ConfigType.FILE_CHOOSER, new FileChooserConfig());
public static final String SERVERLIST_FILE_CHOOSER = configDefault("serverListFileChooser", ConfigType.FILE_CHOOSER, new FileChooserConfig());

private enum FontStyle {
Plain(Font.PLAIN), Bold(Font.BOLD), Italic(Font.ITALIC), ItalicAndBold(Font.BOLD|Font.ITALIC);
Expand All @@ -96,6 +102,9 @@ private enum FontStyle {
public int getStyle() {
return style;
}
public static FontStyle getStyle(int fontStyle) {
return FontStyle.values()[fontStyle];
}
}

// The folder is also referenced in lon4j2.xml config
Expand Down Expand Up @@ -164,20 +173,20 @@ public synchronized static void setEnvironment(String env) {
}
}

public Workspace loadWorkspace() {
Workspace workspace = new Workspace();
File workspaceFile = new File(getWorkspaceFilename());
if (workspaceFile.exists()) {
try (InputStream inp = new FileInputStream(workspaceFile)) {
Properties p = new Properties();
p.load(inp);
workspace.load(p);
} catch (IOException e) {
log.error("Can't load workspace", e);
}
}
return workspace;
}
public Workspace loadWorkspace() {
Workspace workspace = new Workspace();
File workspaceFile = new File(getWorkspaceFilename());
if (workspaceFile.exists()) {
try (InputStream inp = new FileInputStream(workspaceFile)) {
Properties p = new Properties();
p.load(inp);
workspace.load(p);
} catch (IOException e) {
log.error("Can't load workspace", e);
}
}
return workspace;
}

public void saveWorkspace(Workspace workspace) {
try {
Expand Down Expand Up @@ -306,6 +315,33 @@ private void init(String filename, Properties properties) {
}
}

if (!Files.exists(file) && Util.WINDOWS) {
log.info("Config not found in userprofile. Trying legacy path.");
//Old Java versions returned a different place for user.home on Windows.
//A user upgrading from such old directory would suddenly "lose" their config.
String oldpath = null;
try {
Process process = Runtime.getRuntime().exec("reg query \"HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders\" /v Desktop");
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = null;
while ((line = reader.readLine()) != null) {
if (line.contains("Desktop") && line.contains("REG_SZ")) {
// Desktop REG_SZ \\path\to\Desktop
String[] tokens = line.split("[ \t]");
int tc=0;
for (int i=0; i<tokens.length; ++i) {
if (tokens[i].length() > 0) ++tc;
if (tc==3) oldpath = tokens[i];
}
}
}
} catch (IOException e) {
//ignore
}
log.info("Old path: "+oldpath);
if (oldpath != null) file = Paths.get(oldpath.substring(0,oldpath.lastIndexOf('\\'))+"\\.studioforkdb\\studio.properties");
}

if (properties != null) {
p = (Properties) properties.clone();
} else {
Expand Down Expand Up @@ -407,6 +443,148 @@ public void save() {
}
}

public Object serverTreeToObj(ServerTreeNode root) {
//converts the server tree to an object that can be saved into JSON
LinkedHashMap<String,Object> result = new LinkedHashMap<>();
result.put("name", root.getName());
if(root.isFolder()) {
ArrayList<Object> children = new ArrayList<>();
result.put("children", children);
for (Enumeration<TreeNode> e = root.children(); e.hasMoreElements();) {
children.add(serverTreeToObj((ServerTreeNode) e.nextElement()));
}
}
return result;
}

public void exportServerListToJSON(File f) {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
Map<String,Object> cfg = new LinkedHashMap<>();
ArrayList<Map<String,Object>> svs = new ArrayList<>();
for (Server s : servers.values()) {
LinkedHashMap<String,Object> ps = new LinkedHashMap<>();
svs.add(ps);
ps.put("name", s.getName());
ps.put("host", s.getHost());
ps.put("port", s.getPort());
ps.put("username", s.getUsername());
ps.put("password", s.getPassword());
ps.put("useTls", s.getUseTLS());
ps.put("authMethod", s.getAuthenticationMechanism());
ArrayList<Integer> color = new ArrayList<>(3);
Color bgc = s.getBackgroundColor();
color.add(bgc.getRed());
color.add(bgc.getGreen());
color.add(bgc.getBlue());
ps.put("color", color);
}
cfg.put("servers",svs);
cfg.put("serverTree", serverTreeToObj(serverTree));
try {
FileWriter sw = new FileWriter(f);
objectMapper.writeValue(sw, cfg);
} catch(IOException e) {
e.printStackTrace(System.err);
}
}

private void importServerTreeFromJSON(HashMap<String, Server> serverMap, boolean isRoot, JsonNode jn, ServerTreeNode tn) {
if (jn.has("children")) { //is a folder
ServerTreeNode ntn = tn;
if (!isRoot) {
String folderName = jn.get("name").asText("");
ntn = tn.getChild(folderName);
if (ntn == null) {
ntn = new ServerTreeNode(folderName);
tn.add(ntn);
}
};
JsonNode children = jn.get("children");
if (children.isArray()) {
for (JsonNode child : (Iterable<JsonNode>) ()->children.elements()) {
importServerTreeFromJSON(serverMap, false, child, ntn);
}
}
} else {
if (jn.has("name")) {
String name = jn.get("name").asText("");
if (name.length() > 0) {
if (serverMap.containsKey(name)) {
Server s = serverMap.get(name);
s.setFolder(tn);
addServer(s);
serverMap.remove(s);
}
}
}
}
}

public String importServerListFromJSON(File f) {
ObjectMapper objectMapper = new ObjectMapper();
StringBuilder sb = new StringBuilder();
ArrayList<String> alreadyExist = new ArrayList<>();
ArrayList<Integer> noName = new ArrayList<>();
try {
JsonNode root = objectMapper.readTree(f);
if (!root.isObject()) return "JSON root node is not an object";
if (!root.has("servers")) return "JSON root node doesn't have a \"servers\" property";
if (!root.has("serverTree")) return "JSON root node doesn't have a \"serverTree\" property";
JsonNode serversNode = root.get("servers");
JsonNode serverTreeNode = root.get("serverTree");
if (!serversNode.isArray()) return "\"servers\" node is not an array";
HashSet<String> existingServers = new HashSet<>();
for (Server s : servers.values()) existingServers.add(s.getName());
HashMap<String, Server> serverMap = new HashMap<>();
int i=0;
for (JsonNode serverNode : (Iterable<JsonNode>) ()->serversNode.elements()) {
if (!serverNode.isObject()) {
sb.append("Non-object found inside \"servers\" array at index "+i+"\n");
} else if (!serverNode.has("name")) {
sb.append("Server at index "+i+" has no name\n");
} else {
String sname = serverNode.get("name").asText();
if (sname.length() == 0) {
noName.add(i);
} else if (existingServers.contains(sname)) {
alreadyExist.add(sname);
} else {
Server s = new Server();
s.setName(sname);
if (serverNode.has("host")) s.setHost(serverNode.get("host").asText(""));
if (serverNode.has("port")) s.setPort(serverNode.get("port").asInt(0));
if (serverNode.has("username")) s.setUsername(serverNode.get("username").asText(""));
if (serverNode.has("password")) s.setPassword(serverNode.get("password").asText(""));
if (serverNode.has("useTls")) s.setUseTLS(serverNode.get("useTls").asBoolean(false));
if (serverNode.has("authMethod")) s.setAuthenticationMechanism(serverNode.get("authMethod").asText(""));
if (serverNode.has("color")) {
JsonNode color = serverNode.get("color");
if (color.isArray() && color.size() >= 3) {
s.setBackgroundColor(new Color(color.get(0).asInt(255),color.get(1).asInt(255),color.get(2).asInt(255)));
}
}
serverMap.put(sname, s);
}
}
++i;
}
if (serverTreeNode.isObject()) {
importServerTreeFromJSON(serverMap, true, serverTreeNode, serverTree);
}
if (0<noName.size()) sb.append("The servers at the following indices have no names: "+noName);
if (0<alreadyExist.size()) sb.append("The following servers already exist and were not imported: "+alreadyExist);
} catch(IOException e) {
return e.toString();
}
int i = 0;
final int wordLength = 150;
while (i + wordLength < sb.length() && (i = sb.lastIndexOf(" ", i + wordLength)) != -1) {
sb.replace(i, i + 1, "\n");
}
return sb.toString();
}

// "".split(",") return {""}; we need to get zero length array
private String[] split(String str) {
str = str.trim();
Expand Down Expand Up @@ -498,7 +676,9 @@ public void setDefaultCredentials(String authenticationMechanism, Credentials cr
}

public String getDefaultAuthMechanism() {
return p.getProperty("auth", DefaultAuthenticationMechanism.NAME);
String result = p.getProperty("auth", null);
if (result == null) result = System.getenv().getOrDefault("KDB_STUDIO_AUTH_METHOD", DefaultAuthenticationMechanism.NAME);
return result;
}

public void setDefaultAuthMechanism(String authMechanism) {
Expand All @@ -516,7 +696,7 @@ public void setShowServerComboBox(boolean value) {
}

public int getResultTabsCount() {
return Integer.parseInt(p.getProperty("resultTabsCount","5"));
return Integer.parseInt(p.getProperty("resultTabsCount","6"));
}

public void setResultTabsCount(int value) {
Expand Down Expand Up @@ -564,7 +744,9 @@ private Server initServerFromKey(String key) {
String username = p.getProperty("server." + key + ".user", "");
String password = p.getProperty("server." + key + ".password", "");
Color backgroundColor = get("server." + key + ".backgroundColor", Color.WHITE);
String authenticationMechanism = p.getProperty("server." + key + ".authenticationMechanism", DefaultAuthenticationMechanism.NAME);
String authenticationMechanism = p.getProperty("server." + key + ".authenticationMechanism", null);
if (authenticationMechanism == null)
authenticationMechanism = System.getenv().getOrDefault("KDB_STUDIO_AUTH_METHOD", DefaultAuthenticationMechanism.NAME);
boolean useTLS = Boolean.parseBoolean(p.getProperty("server." + key + ".useTLS", "false"));
return new Server("", host, port, username, password, backgroundColor, authenticationMechanism, useTLS);
}
Expand Down Expand Up @@ -673,10 +855,10 @@ private void addServerInternal(Server server) {
throw new IllegalArgumentException("Server name can't be empty");
}
if (name.contains(",")) {
throw new IllegalArgumentException("Server name can't contains ,");
throw new IllegalArgumentException("Server name can't contain ,");
}
if (name.contains("/")) {
throw new IllegalArgumentException("Server name can't contains /");
throw new IllegalArgumentException("Server name ("+name+") can't contain /");
}
if (AuthenticationManager.getInstance().lookup(server.getAuthenticationMechanism()) == null) {
throw new IllegalArgumentException("Unknown Authentication Mechanism: " + server.getAuthenticationMechanism());
Expand Down Expand Up @@ -789,6 +971,11 @@ private static String configDefault(String key, ConfigType type, Object defaultV
FileChooserConfig config = (FileChooserConfig) defaultValue;
configDefault(key + ".filename", ConfigType.STRING, config.getFilename());
configDefault(key + ".prefSize", ConfigType.SIZE, config.getPreferredSize());
} else if (type == ConfigType.FONT) {
Font font = (Font) defaultValue;
configDefault(key + ".size", ConfigType.INT, font.getSize());
configDefault(key + ".name", ConfigType.STRING, font.getName());
configDefault(key + ".style", ConfigType.ENUM, FontStyle.getStyle(font.getStyle()));
}

return key;
Expand Down Expand Up @@ -1074,6 +1261,14 @@ private Font get(String key, Font defaultValue) {
return new Font(name, style, size);
}

public String getFontName() {
return p.getProperty("font.name", "Monospaced");
}

public int getFontSize() {
return Integer.parseInt(p.getProperty("font.size","14"));
}

public Font getFont(String key) {
return get(key, (Font) checkAndGetDefaultValue(key, ConfigType.FONT));
}
Expand All @@ -1096,4 +1291,5 @@ public boolean setFont(String key, Font value) {
save();
return true;
}

}
4 changes: 4 additions & 0 deletions src/main/studio/kdb/K.java
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,10 @@ public KSymbol(String s) {
this.s = s;
}

public String toString(boolean showType) {
return showType ? "`" + s : s;
}

public boolean isNull() {
return s.length() == 0;
}
Expand Down
4 changes: 4 additions & 0 deletions src/main/studio/kdb/ServerTreeNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -177,4 +177,8 @@ public String toString() {
public String fullPath() {
return Stream.of(getPath()).skip(1).map(n->n.toString()).collect(Collectors.joining("/"));
}

public String getName() {
return isFolder() ? getFolder() : getServer().getName();
}
}
Loading

0 comments on commit a53ec90

Please sign in to comment.