From: Mathieu Baudier Date: Sun, 10 Jul 2022 10:10:24 +0000 (+0200) Subject: Make MiniDesktop RAP compatible. X-Git-Tag: v2.3.10~127 X-Git-Url: https://git.argeo.org/?a=commitdiff_plain;h=59fb5931076a3a22b81b5ac33290523fc941fe2b;p=lgpl%2Fargeo-commons.git Make MiniDesktop RAP compatible. --- diff --git a/rcp/org.argeo.swt.minidesktop/.classpath b/rcp/org.argeo.swt.minidesktop/.classpath deleted file mode 100644 index eca7bdba8..000000000 --- a/rcp/org.argeo.swt.minidesktop/.classpath +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/rcp/org.argeo.swt.minidesktop/.gitignore b/rcp/org.argeo.swt.minidesktop/.gitignore deleted file mode 100644 index 97adb723b..000000000 --- a/rcp/org.argeo.swt.minidesktop/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/bin/ -/target/ -*.log \ No newline at end of file diff --git a/rcp/org.argeo.swt.minidesktop/.project b/rcp/org.argeo.swt.minidesktop/.project deleted file mode 100644 index b6c2c1ae4..000000000 --- a/rcp/org.argeo.swt.minidesktop/.project +++ /dev/null @@ -1,28 +0,0 @@ - - - org.argeo.swt.minidesktop - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.pde.ManifestBuilder - - - - - org.eclipse.pde.SchemaBuilder - - - - - - org.eclipse.pde.PluginNature - org.eclipse.jdt.core.javanature - - diff --git a/rcp/org.argeo.swt.minidesktop/META-INF/.gitignore b/rcp/org.argeo.swt.minidesktop/META-INF/.gitignore deleted file mode 100644 index 4854a41b9..000000000 --- a/rcp/org.argeo.swt.minidesktop/META-INF/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/MANIFEST.MF diff --git a/rcp/org.argeo.swt.minidesktop/bnd.bnd b/rcp/org.argeo.swt.minidesktop/bnd.bnd deleted file mode 100644 index f3c13bec5..000000000 --- a/rcp/org.argeo.swt.minidesktop/bnd.bnd +++ /dev/null @@ -1,2 +0,0 @@ -Import-Package: org.eclipse.swt,\ -* diff --git a/rcp/org.argeo.swt.minidesktop/build.properties b/rcp/org.argeo.swt.minidesktop/build.properties deleted file mode 100644 index 34d2e4d2d..000000000 --- a/rcp/org.argeo.swt.minidesktop/build.properties +++ /dev/null @@ -1,4 +0,0 @@ -source.. = src/ -output.. = bin/ -bin.includes = META-INF/,\ - . diff --git a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniBrowser.java b/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniBrowser.java deleted file mode 100644 index 406382bce..000000000 --- a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniBrowser.java +++ /dev/null @@ -1,187 +0,0 @@ -package org.argeo.minidesktop; - -import java.util.Arrays; -import java.util.List; - -import org.eclipse.swt.SWT; -import org.eclipse.swt.browser.Browser; -import org.eclipse.swt.browser.LocationAdapter; -import org.eclipse.swt.browser.LocationEvent; -import org.eclipse.swt.events.KeyAdapter; -import org.eclipse.swt.events.KeyEvent; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.graphics.Rectangle; -import org.eclipse.swt.layout.FillLayout; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Text; - -/** A very minimalistic web browser based on {@link Browser}. */ -public class MiniBrowser { - private static Point defaultShellSize = new Point(800, 480); - - private Browser browser; - private Text addressT; - - private final boolean fullscreen; - private final boolean appMode; - - public MiniBrowser(Composite composite, String url, boolean fullscreen, boolean appMode) { - this.fullscreen = fullscreen; - this.appMode = appMode; - createUi(composite); - setUrl(url); - } - - public Control createUi(Composite parent) { - parent.setLayout(noSpaceGridLayout(new GridLayout())); - if (!isAppMode()) { - Control toolBar = createToolBar(parent); - toolBar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); - } - Control body = createBody(parent); - body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - return body; - } - - protected Control createToolBar(Composite parent) { - Composite toolBar = new Composite(parent, SWT.NONE); - toolBar.setLayout(new FillLayout()); - addressT = new Text(toolBar, SWT.SINGLE); - addressT.addSelectionListener(new SelectionAdapter() { - - @Override - public void widgetDefaultSelected(SelectionEvent e) { - setUrl(addressT.getText().trim()); - } - }); - return toolBar; - } - - protected Control createBody(Composite parent) { - browser = new Browser(parent, SWT.NONE); - if (isFullScreen()) - browser.addKeyListener(new KeyAdapter() { - @Override - public void keyPressed(KeyEvent e) { - if (e.keyCode == 0x77 && e.stateMask == 0x40000) {// Ctrl+W - browser.getShell().dispose(); - } - } - }); - browser.addLocationListener(new LocationAdapter() { - @Override - public void changed(LocationEvent event) { - System.out.println(event); - if (addressT != null) - addressT.setText(event.location); - } - - }); - browser.addTitleListener(e -> titleChanged(e.title)); - browser.addOpenWindowListener((e) -> { - e.browser = openNewBrowserWindow(); - }); - return browser; - } - - protected Browser openNewBrowserWindow() { - - if (isFullScreen()) { - // TODO manage multiple tabs? - return browser; - } else { - Shell newShell = new Shell(browser.getDisplay(), SWT.SHELL_TRIM); - MiniBrowser newMiniBrowser = new MiniBrowser(newShell, null, false, isAppMode()); - newShell.setSize(defaultShellSize); - newShell.open(); - return newMiniBrowser.browser; - } - } - - protected boolean isFullScreen() { - return fullscreen; - } - - void setUrl(String url) { - if (browser != null && url != null && !url.equals(browser.getUrl())) - browser.setUrl(url.toString()); - } - - /** Called when URL changed; to be overridden, does nothing by default. */ - protected void urlChanged(String url) { - } - - /** Called when title changed; to be overridden, does nothing by default. */ - protected void titleChanged(String title) { - } - - protected Browser getBrowser() { - return browser; - } - - protected boolean isAppMode() { - return appMode; - } - - private static GridLayout noSpaceGridLayout(GridLayout layout) { - layout.horizontalSpacing = 0; - layout.verticalSpacing = 0; - layout.marginWidth = 0; - layout.marginHeight = 0; - return layout; - } - - public static void main(String[] args) { - List options = Arrays.asList(args); - if (options.contains("--help")) { - System.out.println("Usage: java " + MiniBrowser.class.getName().replace('.', '/') + " [OPTION] [URL]"); - System.out.println("A minimalistic web browser Eclipse SWT Browser integration."); - System.out.println(" --fullscreen : take control of the whole screen (default is to run in a window)"); - System.out.println(" --app : open without an address bar and a toolbar"); - System.out.println(" --help : print this help and exit"); - System.exit(1); - } - boolean fullscreen = options.contains("--fullscreen"); - boolean appMode = options.contains("--app"); - String url = "https://start.duckduckgo.com/"; - if (options.size() > 0) { - String last = options.get(options.size() - 1); - if (!last.startsWith("--")) - url = last.trim(); - } - - Display display = Display.getCurrent() == null ? new Display() : Display.getCurrent(); - Shell shell; - if (fullscreen) { - shell = new Shell(display, SWT.NO_TRIM); - shell.setFullScreen(true); - Rectangle bounds = display.getBounds(); - shell.setSize(bounds.width, bounds.height); - } else { - shell = new Shell(display, SWT.SHELL_TRIM); - shell.setSize(defaultShellSize); - } - - new MiniBrowser(shell, url, fullscreen, appMode) { - - @Override - protected void titleChanged(String title) { - shell.setText(title); - } - }; - shell.open(); - - while (!shell.isDisposed()) { - if (!display.readAndDispatch()) - display.sleep(); - } - } - -} diff --git a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniDesktopImages.java b/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniDesktopImages.java deleted file mode 100644 index db5e6f273..000000000 --- a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniDesktopImages.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.argeo.minidesktop; - -import java.io.IOException; -import java.io.InputStream; - -import org.eclipse.swt.SWTException; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.widgets.Display; - -/** Icons. */ -public class MiniDesktopImages { - - public final Image homeIcon; - public final Image exitIcon; - - public final Image terminalIcon; - public final Image browserIcon; - public final Image explorerIcon; - public final Image textEditorIcon; - - public final Image folderIcon; - public final Image fileIcon; - - public MiniDesktopImages(Display display) { - homeIcon = loadImage(display, "nav_home@2x.png"); - exitIcon = loadImage(display, "delete@2x.png"); - - terminalIcon = loadImage(display, "console_view@2x.png"); - browserIcon = loadImage(display, "external_browser@2x.png"); - explorerIcon = loadImage(display, "fldr_obj@2x.png"); - textEditorIcon = loadImage(display, "cheatsheet_obj@2x.png"); - - folderIcon = loadImage(display, "fldr_obj@2x.png"); - fileIcon = loadImage(display, "file_obj@2x.png"); - } - - static Image loadImage(Display display, String path) { - InputStream stream = MiniDesktopImages.class.getResourceAsStream(path); - if (stream == null) - throw new IllegalArgumentException("Image " + path + " not found"); - Image image = null; - try { - image = new Image(display, stream); - } catch (SWTException ex) { - } finally { - try { - stream.close(); - } catch (IOException ex) { - } - } - return image; - } -} diff --git a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniDesktopManager.java b/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniDesktopManager.java deleted file mode 100644 index e0f483d49..000000000 --- a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniDesktopManager.java +++ /dev/null @@ -1,349 +0,0 @@ -package org.argeo.minidesktop; - -import java.lang.management.ManagementFactory; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.nio.file.Path; -import java.util.Arrays; -import java.util.List; - -import org.eclipse.swt.SWT; -import org.eclipse.swt.custom.CTabFolder; -import org.eclipse.swt.custom.CTabItem; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Color; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.ImageData; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.graphics.Rectangle; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.program.Program; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.ToolBar; -import org.eclipse.swt.widgets.ToolItem; - -/** A very minimalistic desktop manager based on Java and Eclipse SWT. */ -public class MiniDesktopManager { - private Display display; - - private Shell rootShell; - private Shell toolBarShell; - private CTabFolder tabFolder; - private int maxTabTitleLength = 16; - - private final boolean fullscreen; - private final boolean stacking; - - private MiniDesktopImages images; - - public MiniDesktopManager(boolean fullscreen, boolean stacking) { - this.fullscreen = fullscreen; - this.stacking = stacking; - } - - public void init() { - Display.setAppName("Mini SWT Desktop"); - display = Display.getCurrent(); - if (display != null) - throw new IllegalStateException("Already a display " + display); - display = new Display(); - - if (display.getTouchEnabled()) { - System.out.println("Touch enabled."); - } - - images = new MiniDesktopImages(display); - - int toolBarSize = 48; - - if (isFullscreen()) { - rootShell = new Shell(display, SWT.NO_TRIM); - rootShell.setFullScreen(true); - Rectangle bounds = display.getBounds(); - rootShell.setLocation(0, 0); - rootShell.setSize(bounds.width, bounds.height); - } else { - rootShell = new Shell(display, SWT.CLOSE | SWT.RESIZE); - Rectangle shellArea = rootShell.computeTrim(200, 200, 800, 480); - rootShell.setSize(shellArea.width, shellArea.height); - rootShell.setText(Display.getAppName()); - rootShell.setImage(images.terminalIcon); - } - - rootShell.setLayout(noSpaceGridLayout(new GridLayout(2, false))); - Composite toolBarArea = new Composite(rootShell, SWT.NONE); - toolBarArea.setLayoutData(new GridData(toolBarSize, rootShell.getSize().y)); - - ToolBar toolBar; - if (isFullscreen()) { - toolBarShell = new Shell(rootShell, SWT.NO_TRIM | SWT.ON_TOP); - toolBar = new ToolBar(toolBarShell, SWT.VERTICAL | SWT.FLAT | SWT.BORDER); - createDock(toolBar); - toolBarShell.pack(); - toolBarArea.setLayoutData(new GridData(toolBar.getSize().x, toolBar.getSize().y)); - } else { - toolBar = new ToolBar(toolBarArea, SWT.VERTICAL | SWT.FLAT | SWT.BORDER); - createDock(toolBar); - toolBarArea.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false)); - } - - if (isStacking()) { - tabFolder = new CTabFolder(rootShell, SWT.MULTI | SWT.BORDER | SWT.BOTTOM); - tabFolder.setLayout(noSpaceGridLayout(new GridLayout())); - tabFolder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - - Color selectionBackground = display.getSystemColor(SWT.COLOR_LIST_SELECTION); - tabFolder.setSelectionBackground(selectionBackground); - - // background - Control background = createBackground(tabFolder); - CTabItem homeTabItem = new CTabItem(tabFolder, SWT.NONE); - homeTabItem.setText("Home"); - homeTabItem.setImage(images.homeIcon); - homeTabItem.setControl(background); - tabFolder.setFocus(); - } else { - createBackground(rootShell); - } - - rootShell.open(); - // rootShell.layout(true, true); - - if (toolBarShell != null) { - int toolBarShellY = (display.getBounds().height - toolBar.getSize().y) / 2; - toolBarShell.setLocation(0, toolBarShellY); - toolBarShell.open(); - } - - long jvmUptime = ManagementFactory.getRuntimeMXBean().getUptime(); - System.out.println("SWT Mini Desktop Manager available in " + jvmUptime + " ms."); - } - - protected void createDock(ToolBar toolBar) { - // Terminal - addToolItem(toolBar, images.terminalIcon, "Terminal", () -> { - String url = System.getProperty("user.home"); - AppContext appContext = createAppParent(images.terminalIcon); - new MiniTerminal(appContext.getAppParent(), url) { - - @Override - protected void exitCalled() { - if (appContext.shell != null) - appContext.shell.dispose(); - if (appContext.tabItem != null) - appContext.tabItem.dispose(); - } - }; - String title; - try { - title = System.getProperty("user.name") + "@" + InetAddress.getLocalHost().getHostName(); - } catch (UnknownHostException e) { - title = System.getProperty("user.name") + "@localhost"; - } - if (appContext.shell != null) - appContext.shell.setText(title); - if (appContext.tabItem != null) { - appContext.tabItem.setText(tabTitle(title)); - appContext.tabItem.setToolTipText(title); - } - openApp(appContext); - }); - - // Web browser - addToolItem(toolBar, images.browserIcon, "Browser", () -> { - String url = "https://start.duckduckgo.com/"; - AppContext appContext = createAppParent(images.browserIcon); - new MiniBrowser(appContext.getAppParent(), url, false, false) { - @Override - protected void titleChanged(String title) { - if (appContext.shell != null) - appContext.shell.setText(title); - if (appContext.tabItem != null) { - appContext.tabItem.setText(tabTitle(title)); - appContext.tabItem.setToolTipText(title); - } - } - }; - openApp(appContext); - }); - - // File explorer - addToolItem(toolBar, images.explorerIcon, "Explorer", () -> { - String url = System.getProperty("user.home"); - AppContext appContext = createAppParent(images.explorerIcon); - new MiniExplorer(appContext.getAppParent(), url) { - - @Override - protected void pathChanged(Path path) { - if (appContext.shell != null) - appContext.shell.setText(path.toString()); - if (appContext.tabItem != null) { - appContext.tabItem.setText(path.getFileName().toString()); - appContext.tabItem.setToolTipText(path.toString()); - } - } - }; - openApp(appContext); - }); - - // Separator - new ToolItem(toolBar, SWT.SEPARATOR); - - // Exit - addToolItem(toolBar, images.exitIcon, "Exit", () -> rootShell.dispose()); - - toolBar.pack(); - } - - protected String tabTitle(String title) { - return title.length() > maxTabTitleLength ? title.substring(0, maxTabTitleLength) : title; - } - - protected void addToolItem(ToolBar toolBar, Image icon, String name, Runnable action) { - ToolItem searchI = new ToolItem(toolBar, SWT.PUSH); - searchI.setImage(icon); - searchI.setToolTipText(name); - searchI.addSelectionListener(new SelectionAdapter() { - - @Override - public void widgetSelected(SelectionEvent e) { - action.run(); - } - - }); - } - - protected AppContext createAppParent(Image icon) { - if (isStacking()) { - Composite appParent = new Composite(tabFolder, SWT.CLOSE); - appParent.setLayout(noSpaceGridLayout(new GridLayout())); - CTabItem item = new CTabItem(tabFolder, SWT.CLOSE); - item.setImage(icon); - item.setControl(appParent); - return new AppContext(item); - } else { - Shell shell = isFullscreen() ? new Shell(rootShell, SWT.SHELL_TRIM) - : new Shell(rootShell.getDisplay(), SWT.SHELL_TRIM); - shell.setImage(icon); - return new AppContext(shell); - } - } - - protected void openApp(AppContext appContext) { - if (appContext.shell != null) { - Shell shell = (Shell) appContext.shell; - shell.open(); - shell.setSize(new Point(800, 480)); - } - if (appContext.tabItem != null) { - tabFolder.setFocus(); - tabFolder.setSelection(appContext.tabItem); - } - } - - protected Control createBackground(Composite parent) { - Composite backgroundArea = new Composite(parent, SWT.NONE); - backgroundArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - initBackground(backgroundArea); - return backgroundArea; - } - - protected void initBackground(Composite backgroundArea) { - MiniHomePart homePart = new MiniHomePart() { - - @Override - protected void fillAppsToolBar(ToolBar toolBar) { - createDock(toolBar); - } - }; - homePart.createUiPart(backgroundArea, null); - } - - public void run() { - while (!rootShell.isDisposed()) { - if (!display.readAndDispatch()) - display.sleep(); - } - } - - public void dispose() { - if (!rootShell.isDisposed()) - rootShell.dispose(); - } - - protected boolean isFullscreen() { - return fullscreen; - } - - protected boolean isStacking() { - return stacking; - } - - protected Image getIconForExt(String ext) { - Program program = Program.findProgram(ext); - if (program == null) - return display.getSystemImage(SWT.ICON_INFORMATION); - - ImageData iconData = program.getImageData(); - if (iconData == null) { - return display.getSystemImage(SWT.ICON_INFORMATION); - } else { - return new Image(display, iconData); - } - - } - - private static GridLayout noSpaceGridLayout(GridLayout layout) { - layout.horizontalSpacing = 0; - layout.verticalSpacing = 0; - layout.marginWidth = 0; - layout.marginHeight = 0; - return layout; - } - - public static void main(String[] args) { - List options = Arrays.asList(args); - if (options.contains("--help")) { - System.out.println("Usage: java " + MiniDesktopManager.class.getName().replace('.', '/') + " [OPTION]"); - System.out.println("A minimalistic desktop manager based on Java and Eclipse SWT."); - System.out.println(" --fullscreen : take control of the whole screen (default is to run in a window)"); - System.out.println(" --stacking : open apps as tabs (default is to create new windows)"); - System.out.println(" --help : print this help and exit"); - System.exit(1); - } - boolean fullscreen = options.contains("--fullscreen"); - boolean stacking = options.contains("--stacking"); - - MiniDesktopManager desktopManager = new MiniDesktopManager(fullscreen, stacking); - desktopManager.init(); - desktopManager.run(); - desktopManager.dispose(); - System.exit(0); - } - - class AppContext { - private Shell shell; - private CTabItem tabItem; - - public AppContext(Shell shell) { - this.shell = shell; - } - - public AppContext(CTabItem tabItem) { - this.tabItem = tabItem; - } - - Composite getAppParent() { - if (shell != null) - return shell; - if (tabItem != null) - return (Composite) tabItem.getControl(); - throw new IllegalStateException(); - } - } -} diff --git a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniExplorer.java b/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniExplorer.java deleted file mode 100644 index 1395c02cf..000000000 --- a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniExplorer.java +++ /dev/null @@ -1,165 +0,0 @@ -package org.argeo.minidesktop; - -import java.io.IOException; -import java.nio.file.DirectoryStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; - -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.MouseAdapter; -import org.eclipse.swt.events.MouseEvent; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.layout.FillLayout; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.program.Program; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableItem; -import org.eclipse.swt.widgets.Text; - -public class MiniExplorer { - private Path path; - private Text addressT; - private Table browser; - - private boolean showHidden = false; - - public MiniExplorer(Composite parent, String url) { - this(parent); - setUrl(url); - } - - public MiniExplorer(Composite parent) { - parent.setLayout(noSpaceGridLayout(new GridLayout())); - - Composite toolBar = new Composite(parent, SWT.NONE); - toolBar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); - toolBar.setLayout(new FillLayout()); - addressT = new Text(toolBar, SWT.SINGLE); - addressT.addSelectionListener(new SelectionAdapter() { - - @Override - public void widgetDefaultSelected(SelectionEvent e) { - setUrl(addressT.getText().trim()); - } - }); - browser = createTable(parent, this.path); - - } - - public void setPath(Path url) { - this.path = url; - if (addressT != null) - addressT.setText(url.toString()); - if (browser != null) { - Composite parent = browser.getParent(); - browser.dispose(); - browser = createTable(parent, this.path); - parent.layout(true, true); - } - pathChanged(url); - } - - protected void pathChanged(Path path) { - - } - - protected Table createTable(Composite parent, Path path) { - Table table = new Table(parent, SWT.BORDER); - table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - table.addMouseListener(new MouseAdapter() { - - @Override - public void mouseDoubleClick(MouseEvent e) { - Point pt = new Point(e.x, e.y); - TableItem item = table.getItem(pt); - Path path = (Path) item.getData(); - if (Files.isDirectory(path)) { - setPath(path); - } else { - Program.launch(path.toString()); - } - } - }); - - if (path != null) { - if (path.getParent() != null) { - TableItem parentTI = new TableItem(table, SWT.NONE); - parentTI.setText(".."); - parentTI.setData(path.getParent()); - } - - try { - // directories - DirectoryStream ds = Files.newDirectoryStream(path, p -> Files.isDirectory(p) && isShown(p)); - ds.forEach(p -> { - TableItem ti = new TableItem(table, SWT.NONE); - ti.setText(p.getFileName().toString() + "/"); - ti.setData(p); - }); - // files - ds = Files.newDirectoryStream(path, p -> !Files.isDirectory(p) && isShown(p)); - ds.forEach(p -> { - TableItem ti = new TableItem(table, SWT.NONE); - ti.setText(p.getFileName().toString()); - ti.setData(p); - }); - } catch (IOException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } - } - return table; - } - - protected boolean isShown(Path path) { - if (showHidden) - return true; - try { - return !Files.isHidden(path); - } catch (IOException e) { - throw new IllegalArgumentException("Cannot check " + path, e); - } - } - - public void setUrl(String url) { - setPath(Paths.get(url)); - } - - private static GridLayout noSpaceGridLayout(GridLayout layout) { - layout.horizontalSpacing = 0; - layout.verticalSpacing = 0; - layout.marginWidth = 0; - layout.marginHeight = 0; - return layout; - } - - public static void main(String[] args) { - Display display = Display.getCurrent() == null ? new Display() : Display.getCurrent(); - Shell shell = new Shell(display, SWT.SHELL_TRIM); - - String url = args.length > 0 ? args[0] : System.getProperty("user.home"); - new MiniExplorer(shell, url) { - - @Override - protected void pathChanged(Path path) { - shell.setText(path.toString()); - } - - }; - - shell.open(); - shell.setSize(new Point(800, 480)); - while (!shell.isDisposed()) { - if (!display.readAndDispatch()) - display.sleep(); - } - } - -} diff --git a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniHomePart.java b/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniHomePart.java deleted file mode 100644 index 877f64384..000000000 --- a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniHomePart.java +++ /dev/null @@ -1,161 +0,0 @@ -package org.argeo.minidesktop; - -import java.net.InetAddress; -import java.net.InterfaceAddress; -import java.net.NetworkInterface; -import java.net.SocketException; -import java.net.UnknownHostException; -import java.util.Enumeration; - -import org.eclipse.swt.SWT; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Group; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.ProgressBar; -import org.eclipse.swt.widgets.ToolBar; - -/** A start page displaying network information and resources. */ -public class MiniHomePart { - - public Control createUiPart(Composite parent, Object context) { - parent.setLayout(new GridLayout(2, false)); - Display display = parent.getDisplay(); - - // Apps - Group appsGroup = new Group(parent, SWT.NONE); - appsGroup.setText("Apps"); - appsGroup.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false, 2, 1)); - ToolBar appsToolBar = new ToolBar(appsGroup, SWT.HORIZONTAL | SWT.FLAT); - fillAppsToolBar(appsToolBar); - - // Host - Group hostGroup = new Group(parent, SWT.NONE); - hostGroup.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false)); - hostGroup.setText("Host"); - hostGroup.setLayout(new GridLayout(2, false)); - label(hostGroup, "Hostname: "); - try { - InetAddress defaultAddr = InetAddress.getLocalHost(); - String hostname = defaultAddr.getHostName(); - label(hostGroup, hostname); - label(hostGroup, "Address: "); - label(hostGroup, defaultAddr.getHostAddress()); - } catch (UnknownHostException e) { - label(hostGroup, e.getMessage()); - } - - Enumeration netInterfaces = null; - try { - netInterfaces = NetworkInterface.getNetworkInterfaces(); - } catch (SocketException e) { - label(hostGroup, "Interfaces: "); - label(hostGroup, e.getMessage()); - } - if (netInterfaces != null) - while (netInterfaces.hasMoreElements()) { - NetworkInterface netInterface = netInterfaces.nextElement(); - byte[] hardwareAddress = null; - try { - hardwareAddress = netInterface.getHardwareAddress(); - if (hardwareAddress != null) { - label(hostGroup, convertHardwareAddress(hardwareAddress)); - label(hostGroup, netInterface.getName()); - for (InterfaceAddress addr : netInterface.getInterfaceAddresses()) { - label(hostGroup, cleanHostAddress(addr.getAddress().getHostAddress())); - label(hostGroup, Short.toString(addr.getNetworkPrefixLength())); - } - } - } catch (SocketException e) { - label(hostGroup, e.getMessage()); - } - } - - // Resources - Group resGroup = new Group(parent, SWT.NONE); - resGroup.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); - resGroup.setText("Resources"); - resGroup.setLayout(new GridLayout(3, false)); - - Runtime runtime = Runtime.getRuntime(); - - String maxMemoryStr = Long.toString(runtime.maxMemory() / (1024 * 1024)) + " MB"; - label(resGroup, "Max Java memory: "); - label(resGroup, maxMemoryStr); - label(resGroup, "Java version: " + Runtime.version().toString()); - - label(resGroup, "Usable Java memory: "); - Label totalMemory = label(resGroup, maxMemoryStr); - ProgressBar totalOnMax = new ProgressBar(resGroup, SWT.SMOOTH); - totalOnMax.setMaximum(100); - label(resGroup, "Used Java memory: "); - Label usedMemory = label(resGroup, maxMemoryStr); - ProgressBar usedOnTotal = new ProgressBar(resGroup, SWT.SMOOTH); - totalOnMax.setMaximum(100); - new Thread() { - @Override - public void run() { - while (!totalOnMax.isDisposed()) { - display.asyncExec(() -> { - if (totalOnMax.isDisposed()) - return; - totalOnMax.setSelection(javaTotalOnMaxPerct(runtime)); - usedOnTotal.setSelection(javaUsedOnTotalPerct(runtime)); - totalMemory.setText(Long.toString(runtime.totalMemory() / (1024 * 1024)) + " MB"); - usedMemory.setText( - Long.toString((runtime.totalMemory() - runtime.freeMemory()) / (1024 * 1024)) + " MB"); - }); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - return; - } - } - } - }.start(); - return parent; - } - - protected void fillAppsToolBar(ToolBar toolBar) { - - } - - protected int javaUsedOnTotalPerct(Runtime runtime) { - return Math.toIntExact((runtime.totalMemory() - runtime.freeMemory()) * 100 / runtime.totalMemory()); - } - - protected int javaTotalOnMaxPerct(Runtime runtime) { - return Math.toIntExact((runtime.totalMemory()) * 100 / runtime.maxMemory()); - } - - protected Label label(Composite parent, String text) { - Label label = new Label(parent, SWT.WRAP); - label.setText(text); - return label; - } - - protected String cleanHostAddress(String hostAddress) { - // remove % from Ipv6 addresses - int index = hostAddress.indexOf('%'); - if (index > 0) - return hostAddress.substring(0, index); - else - return hostAddress; - } - - protected String convertHardwareAddress(byte[] hardwareAddress) { - if (hardwareAddress == null) - return ""; - // from https://stackoverflow.com/a/2797498/7878010 - StringBuilder sb = new StringBuilder(18); - for (byte b : hardwareAddress) { - if (sb.length() > 0) - sb.append(':'); - sb.append(String.format("%02x", b).toUpperCase()); - } - return sb.toString(); - } -} diff --git a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniImageViewer.java b/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniImageViewer.java deleted file mode 100644 index 86ff53fee..000000000 --- a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniImageViewer.java +++ /dev/null @@ -1,129 +0,0 @@ -package org.argeo.minidesktop; - -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.file.Path; -import java.nio.file.Paths; - -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.PaintEvent; -import org.eclipse.swt.events.PaintListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.ImageData; -import org.eclipse.swt.graphics.ImageLoader; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.layout.RowLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Canvas; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.FileDialog; -import org.eclipse.swt.widgets.Shell; - -public class MiniImageViewer implements PaintListener { - private URL url; - private Canvas area; - - private Image image; - - public MiniImageViewer(Composite parent, int style) { - parent.setLayout(new GridLayout()); - - Composite toolBar = new Composite(parent, SWT.NONE); - toolBar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); - toolBar.setLayout(new RowLayout()); - Button load = new Button(toolBar, SWT.FLAT); - load.setText("\u2191");// up arrow - load.addSelectionListener(new SelectionAdapter() { - - @Override - public void widgetSelected(SelectionEvent e) { - FileDialog fileDialog = new FileDialog(area.getShell()); - String path = fileDialog.open(); - if (path != null) { - setUrl(path); - } - } - - }); - - area = new Canvas(parent, SWT.NONE); - area.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - area.addPaintListener(this); - } - - protected void load(URL url) { - try { - ImageLoader imageLoader = new ImageLoader(); - ImageData[] data = imageLoader.load(url.openStream()); - image = new Image(area.getDisplay(), data[0]); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - @Override - public void paintControl(PaintEvent e) { - e.gc.drawImage(image, 0, 0); - - } - - protected Path url2path(URL url) { - try { - Path path = Paths.get(url.toURI()); - return path; - } catch (URISyntaxException e) { - throw new IllegalStateException("Cannot convert " + url + " to uri", e); - } - } - - public void setUrl(URL url) { - this.url = url; - if (area != null) - load(this.url); - } - - public void setUrl(String url) { - try { - setUrl(new URL(url)); - } catch (MalformedURLException e) { - // try with http - try { - setUrl(new URL("file://" + url)); - return; - } catch (MalformedURLException e1) { - // nevermind... - } - throw new IllegalArgumentException("Cannot interpret URL " + url, e); - } - } - - public static void main(String[] args) { - Display display = Display.getCurrent() == null ? new Display() : Display.getCurrent(); - Shell shell = new Shell(display, SWT.SHELL_TRIM); - - MiniImageViewer miniBrowser = new MiniImageViewer(shell, SWT.NONE); - String url = args.length > 0 ? args[0] : ""; - if (!url.trim().equals("")) { - miniBrowser.setUrl(url); - shell.setText(url); - } else { - shell.setText("*"); - } - - shell.open(); - shell.setSize(new Point(800, 480)); - while (!shell.isDisposed()) { - if (!display.readAndDispatch()) - display.sleep(); - } - } - -} diff --git a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniTerminal.java b/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniTerminal.java deleted file mode 100644 index 196ad0c57..000000000 --- a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniTerminal.java +++ /dev/null @@ -1,342 +0,0 @@ -package org.argeo.minidesktop; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.StringTokenizer; - -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.KeyEvent; -import org.eclipse.swt.events.KeyListener; -import org.eclipse.swt.events.PaintEvent; -import org.eclipse.swt.events.PaintListener; -import org.eclipse.swt.graphics.Font; -import org.eclipse.swt.graphics.GC; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Canvas; -import org.eclipse.swt.widgets.Caret; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Shell; - -public class MiniTerminal implements KeyListener, PaintListener { - - private Canvas area; - private Caret caret; - - private StringBuffer buf = new StringBuffer(""); - private StringBuffer userInput = new StringBuffer(""); - private List history = new ArrayList<>(); - - private Point charExtent = null; - private int charsPerLine = 0; - private String[] lines = new String[0]; - private List logicalLines = new ArrayList<>(); - - private Font mono; - private Charset charset; - - private Path currentDir; - private Path homeDir; - private String host = "localhost"; - private String username; - - // Sub process - private Process process; - private boolean running = false; - private OutputStream stdIn = null; - - private Thread readOut; - - public MiniTerminal(Composite parent, String url) { - this(parent); - setPath(url); - } - - public MiniTerminal(Composite parent) { - charset = StandardCharsets.UTF_8; - - Display display = parent.getDisplay(); - // Linux-specific - mono = new Font(display, "Monospace", 10, SWT.NONE); - - parent.setLayout(new GridLayout()); - area = new Canvas(parent, SWT.NONE); - area.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - caret = new Caret(area, SWT.NONE); - area.setCaret(caret); - - area.addKeyListener(this); - area.addPaintListener(this); - - username = System.getProperty("user.name"); - try { - host = InetAddress.getLocalHost().getHostName(); - if (host.indexOf('.') > 0) - host = host.substring(0, host.indexOf('.')); - } catch (UnknownHostException e) { - host = "localhost"; - } - homeDir = Paths.get(System.getProperty("user.home")); - currentDir = homeDir; - - buf = new StringBuffer(prompt()); - } - - @Override - public void keyPressed(KeyEvent e) { - } - - @Override - public void keyReleased(KeyEvent e) { - if (e.keyLocation != 0) - return;// weird characters - // System.out.println(e.character); - if (e.keyCode == 0xd) {// return - markLogicalLine(); - if (!running) - processUserInput(); - // buf.append(prompt()); - } else if (e.keyCode == 0x8) {// delete - if (userInput.length() == 0) - return; - userInput.setLength(userInput.length() - 1); - if (!running && buf.length() > 0) - buf.setLength(buf.length() - 1); - } else if (e.stateMask == 0x40000 && e.keyCode == 0x63) {// Ctrl+C - if (process != null) - process.destroy(); - } else if (e.stateMask == 0x40000 && e.keyCode == 0xdf) {// Ctrl+\ - if (process != null) { - process.destroyForcibly(); - } - } else { - // if (!running) - buf.append(e.character); - userInput.append(e.character); - } - - if (area.isDisposed()) - return; - area.redraw(); - // System.out.println("Append " + e); - - if (running) { - if (stdIn != null) { - try { - stdIn.write(Character.toString(e.character).getBytes(charset)); - } catch (IOException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } - } - } - } - - protected String prompt() { - String fileName = currentDir.equals(homeDir) ? "~" : currentDir.getFileName().toString(); - String end = username.equals("root") ? "]# " : "]$ "; - return "[" + username + "@" + host + " " + fileName + end; - } - - private void displayPrompt() { - buf.append(prompt() + userInput); - } - - protected void markLogicalLine() { - String str = buf.toString().trim(); - logicalLines.add(str); - buf = new StringBuffer(""); - } - - private void processUserInput() { - String cmd = userInput.toString(); - userInput = new StringBuffer(""); - processUserInput(cmd); - history.add(cmd); - } - - protected void processUserInput(String input) { - try { - StringTokenizer st = new StringTokenizer(input); - List args = new ArrayList<>(); - while (st.hasMoreTokens()) - args.add(st.nextToken()); - if (args.size() == 0) { - displayPrompt(); - return; - } - - // change directory - if (args.get(0).equals("cd")) { - if (args.size() == 1) { - setPath(homeDir); - } else { - Path newPath = currentDir.resolve(args.get(1)); - if (!Files.exists(newPath) || !Files.isDirectory(newPath)) { - println(newPath + ": No such file or directory"); - return; - } - setPath(newPath); - } - displayPrompt(); - return; - } - // show current directory - else if (args.get(0).equals("pwd")) { - println(currentDir); - displayPrompt(); - return; - } - // exit - else if (args.get(0).equals("exit")) { - println("logout"); - exitCalled(); - return; - } - - ProcessBuilder pb = new ProcessBuilder(args); - pb.redirectErrorStream(true); - pb.directory(currentDir.toFile()); -// Process process = Runtime.getRuntime().exec(input, null, currentPath.toFile()); - process = pb.start(); - - stdIn = process.getOutputStream(); - readOut = new Thread("MiniTerminal read out") { - @Override - public void run() { - running = true; - try (BufferedReader in = new BufferedReader( - new InputStreamReader(process.getInputStream(), charset))) { - String line = null; - while ((line = in.readLine()) != null) { - println(line); - } - } catch (IOException e) { - println(e.getMessage()); - } - stdIn = null; - displayPrompt(); - running = false; - readOut = null; - process = null; - } - }; - readOut.start(); - } catch (IOException e) { - println(e.getMessage()); - displayPrompt(); - } - } - - protected int linesForLogicalLine(char[] line) { - return line.length / charsPerLine + 1; - } - - protected void println(Object line) { - buf.append(line); - markLogicalLine(); - } - - protected void refreshLines(int charPerLine, int nbrOfLines) { - if (lines.length != nbrOfLines) { - lines = new String[nbrOfLines]; - Arrays.fill(lines, null); - } - if (this.charsPerLine != charPerLine) - this.charsPerLine = charPerLine; - - int currentLine = nbrOfLines - 1; - // current line - if (buf.length() > 0) { - lines[currentLine] = buf.toString(); - } else { - lines[currentLine] = ""; - } - currentLine--; - - logicalLines: for (int i = logicalLines.size() - 1; i >= 0; i--) { - char[] logicalLine = logicalLines.get(i).toCharArray(); - int linesNeeded = linesForLogicalLine(logicalLine); - for (int j = linesNeeded - 1; j >= 0; j--) { - int from = j * charPerLine; - int to = j == linesNeeded - 1 ? from + charPerLine : Math.min(from + charPerLine, logicalLine.length); - lines[currentLine] = new String(Arrays.copyOfRange(logicalLine, from, to)); -// System.out.println("Set line " + currentLine + " to : " + lines[currentLine]); - currentLine--; - if (currentLine < 0) - break logicalLines; - } - } - } - - @Override - public void paintControl(PaintEvent e) { - GC gc = e.gc; - gc.setFont(mono); - if (charExtent == null) - charExtent = gc.textExtent("a"); - - Point areaSize = area.getSize(); - int charPerLine = areaSize.x / charExtent.x; - int nbrOfLines = areaSize.y / charExtent.y; - refreshLines(charPerLine, nbrOfLines); - - for (int i = 0; i < lines.length; i++) { - String line = lines[i]; - if (line != null) - gc.drawString(line, 0, i * charExtent.y); - } -// String toDraw = buf.toString(); -// gc.drawString(toDraw, 0, 0); -// area.setCaret(caret); - } - - protected void exitCalled() { - - } - - public void setPath(String path) { - this.currentDir = Paths.get(path); - } - - public void setPath(Path path) { - this.currentDir = path; - } - - public static void main(String[] args) { - Display display = Display.getCurrent() == null ? new Display() : Display.getCurrent(); - Shell shell = new Shell(display, SWT.SHELL_TRIM); - - String url = args.length > 0 ? args[0] : System.getProperty("user.home"); - new MiniTerminal(shell, url) { - - @Override - protected void exitCalled() { - shell.dispose(); - System.exit(0); - } - }; - - shell.open(); - shell.setSize(new Point(800, 480)); - while (!shell.isDisposed()) { - if (!display.readAndDispatch()) - display.sleep(); - } - } - -} diff --git a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniTextEditor.java b/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniTextEditor.java deleted file mode 100644 index 91cd19e90..000000000 --- a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniTextEditor.java +++ /dev/null @@ -1,161 +0,0 @@ -package org.argeo.minidesktop; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.net.MalformedURLException; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; - -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.layout.RowLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.FileDialog; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Text; - -public class MiniTextEditor { - private URL url; - private Text text; - - public MiniTextEditor(Composite parent, int style) { - parent.setLayout(new GridLayout()); - - Composite toolBar = new Composite(parent, SWT.NONE); - toolBar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); - toolBar.setLayout(new RowLayout()); - Button load = new Button(toolBar, SWT.FLAT); - load.setText("\u2191");// up arrow - load.addSelectionListener(new SelectionAdapter() { - - @Override - public void widgetSelected(SelectionEvent e) { - FileDialog fileDialog = new FileDialog(text.getShell()); - String path = fileDialog.open(); - if (path != null) { - setUrl(path); - } - } - - }); - - Button save = new Button(toolBar, SWT.FLAT); - save.setText("\u2193");// down arrow - // save.setText("\u1F609");// emoji - save.addSelectionListener(new SelectionAdapter() { - - @Override - public void widgetSelected(SelectionEvent e) { - save(url); - } - - }); - - text = new Text(parent, SWT.WRAP | SWT.MULTI | SWT.BORDER | SWT.V_SCROLL); - text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - } - - protected void load(URL url) { - text.setText(""); - // TODO deal with encoding and binary data - try (BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8))) { - String line = null; - while ((line = in.readLine()) != null) { - text.append(line + "\n"); - } - text.setEditable(true); - } catch (IOException e) { - if (e instanceof FileNotFoundException) { - Path path = url2path(url); - try { - Files.createFile(path); - load(url); - return; - } catch (IOException e1) { - e = e1; - } - } - text.setText(e.getMessage()); - text.setEditable(false); - e.printStackTrace(); - // throw new IllegalStateException("Cannot load " + url, e); - } - } - - protected Path url2path(URL url) { - try { - Path path = Paths.get(url.toURI()); - return path; - } catch (URISyntaxException e) { - throw new IllegalStateException("Cannot convert " + url + " to uri", e); - } - } - - protected void save(URL url) { - if (!url.getProtocol().equals("file")) - throw new IllegalArgumentException(url.getProtocol() + " protocol is not supported for write"); - Path path = url2path(url); - try (BufferedWriter out = new BufferedWriter(new OutputStreamWriter(Files.newOutputStream(path)))) { - out.write(text.getText()); - } catch (IOException e) { - throw new IllegalStateException("Cannot save " + url + " to " + path, e); - } - } - - public void setUrl(URL url) { - this.url = url; - if (text != null) - load(url); - } - - public void setUrl(String url) { - try { - setUrl(new URL(url)); - } catch (MalformedURLException e) { - // try with http - try { - setUrl(new URL("file://" + url)); - return; - } catch (MalformedURLException e1) { - // nevermind... - } - throw new IllegalArgumentException("Cannot interpret URL " + url, e); - } - } - - public static void main(String[] args) { - Display display = Display.getCurrent() == null ? new Display() : Display.getCurrent(); - Shell shell = new Shell(display, SWT.SHELL_TRIM); - - MiniTextEditor miniBrowser = new MiniTextEditor(shell, SWT.NONE); - String url = args.length > 0 ? args[0] : ""; - if (!url.trim().equals("")) { - miniBrowser.setUrl(url); - shell.setText(url); - } else { - shell.setText("*"); - } - - shell.open(); - shell.setSize(new Point(800, 480)); - while (!shell.isDisposed()) { - if (!display.readAndDispatch()) - display.sleep(); - } - } - -} diff --git a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/cheatsheet_obj@2x.png b/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/cheatsheet_obj@2x.png deleted file mode 100644 index 55c614dfa..000000000 Binary files a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/cheatsheet_obj@2x.png and /dev/null differ diff --git a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/console_view@2x.png b/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/console_view@2x.png deleted file mode 100644 index 54ecae20f..000000000 Binary files a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/console_view@2x.png and /dev/null differ diff --git a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/delete@2x.png b/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/delete@2x.png deleted file mode 100644 index eb2fc720b..000000000 Binary files a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/delete@2x.png and /dev/null differ diff --git a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/external_browser@2x.png b/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/external_browser@2x.png deleted file mode 100644 index 06d337a43..000000000 Binary files a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/external_browser@2x.png and /dev/null differ diff --git a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/file_obj@2x.png b/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/file_obj@2x.png deleted file mode 100644 index 31e671c46..000000000 Binary files a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/file_obj@2x.png and /dev/null differ diff --git a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/fldr_obj@2x.png b/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/fldr_obj@2x.png deleted file mode 100644 index adb7c2cc2..000000000 Binary files a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/fldr_obj@2x.png and /dev/null differ diff --git a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/nav_home@2x.png b/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/nav_home@2x.png deleted file mode 100644 index 4c9a16c0f..000000000 Binary files a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/nav_home@2x.png and /dev/null differ diff --git a/swt/org.argeo.swt.minidesktop/.classpath b/swt/org.argeo.swt.minidesktop/.classpath new file mode 100644 index 000000000..eca7bdba8 --- /dev/null +++ b/swt/org.argeo.swt.minidesktop/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/swt/org.argeo.swt.minidesktop/.gitignore b/swt/org.argeo.swt.minidesktop/.gitignore new file mode 100644 index 000000000..97adb723b --- /dev/null +++ b/swt/org.argeo.swt.minidesktop/.gitignore @@ -0,0 +1,3 @@ +/bin/ +/target/ +*.log \ No newline at end of file diff --git a/swt/org.argeo.swt.minidesktop/.project b/swt/org.argeo.swt.minidesktop/.project new file mode 100644 index 000000000..b6c2c1ae4 --- /dev/null +++ b/swt/org.argeo.swt.minidesktop/.project @@ -0,0 +1,28 @@ + + + org.argeo.swt.minidesktop + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/swt/org.argeo.swt.minidesktop/META-INF/.gitignore b/swt/org.argeo.swt.minidesktop/META-INF/.gitignore new file mode 100644 index 000000000..4854a41b9 --- /dev/null +++ b/swt/org.argeo.swt.minidesktop/META-INF/.gitignore @@ -0,0 +1 @@ +/MANIFEST.MF diff --git a/swt/org.argeo.swt.minidesktop/bnd.bnd b/swt/org.argeo.swt.minidesktop/bnd.bnd new file mode 100644 index 000000000..f3c13bec5 --- /dev/null +++ b/swt/org.argeo.swt.minidesktop/bnd.bnd @@ -0,0 +1,2 @@ +Import-Package: org.eclipse.swt,\ +* diff --git a/swt/org.argeo.swt.minidesktop/build.properties b/swt/org.argeo.swt.minidesktop/build.properties new file mode 100644 index 000000000..34d2e4d2d --- /dev/null +++ b/swt/org.argeo.swt.minidesktop/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniBrowser.java b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniBrowser.java new file mode 100644 index 000000000..d4da349ce --- /dev/null +++ b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniBrowser.java @@ -0,0 +1,189 @@ +package org.argeo.minidesktop; + +import java.util.Arrays; +import java.util.List; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.browser.Browser; +import org.eclipse.swt.browser.LocationAdapter; +import org.eclipse.swt.browser.LocationEvent; +import org.eclipse.swt.events.KeyAdapter; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +/** A very minimalistic web browser based on {@link Browser}. */ +public class MiniBrowser { + private static Point defaultShellSize = new Point(800, 480); + + private Browser browser; + private Text addressT; + + private final boolean fullscreen; + private final boolean appMode; + + public MiniBrowser(Composite composite, String url, boolean fullscreen, boolean appMode) { + this.fullscreen = fullscreen; + this.appMode = appMode; + createUi(composite); + setUrl(url); + } + + public Control createUi(Composite parent) { + parent.setLayout(noSpaceGridLayout(new GridLayout())); + if (!isAppMode()) { + Control toolBar = createToolBar(parent); + toolBar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + } + Control body = createBody(parent); + body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + return body; + } + + protected Control createToolBar(Composite parent) { + Composite toolBar = new Composite(parent, SWT.NONE); + toolBar.setLayout(new FillLayout()); + addressT = new Text(toolBar, SWT.SINGLE); + addressT.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + setUrl(addressT.getText().trim()); + } + }); + return toolBar; + } + + protected Control createBody(Composite parent) { + browser = new Browser(parent, SWT.NONE); + if (isFullScreen()) + browser.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.keyCode == 0x77 && e.stateMask == 0x40000) {// Ctrl+W + browser.getShell().dispose(); + } + } + }); + browser.addLocationListener(new LocationAdapter() { + @Override + public void changed(LocationEvent event) { + System.out.println(event); + if (addressT != null) + addressT.setText(event.location); + } + + }); + + // FIXME make it portable +// browser.addTitleListener(e -> titleChanged(e.title)); +// browser.addOpenWindowListener((e) -> { +// e.browser = openNewBrowserWindow(); +// }); + return browser; + } + + protected Browser openNewBrowserWindow() { + + if (isFullScreen()) { + // TODO manage multiple tabs? + return browser; + } else { + Shell newShell = new Shell(browser.getDisplay(), SWT.SHELL_TRIM); + MiniBrowser newMiniBrowser = new MiniBrowser(newShell, null, false, isAppMode()); + newShell.setSize(defaultShellSize); + newShell.open(); + return newMiniBrowser.browser; + } + } + + protected boolean isFullScreen() { + return fullscreen; + } + + void setUrl(String url) { + if (browser != null && url != null && !url.equals(browser.getUrl())) + browser.setUrl(url.toString()); + } + + /** Called when URL changed; to be overridden, does nothing by default. */ + protected void urlChanged(String url) { + } + + /** Called when title changed; to be overridden, does nothing by default. */ + protected void titleChanged(String title) { + } + + protected Browser getBrowser() { + return browser; + } + + protected boolean isAppMode() { + return appMode; + } + + private static GridLayout noSpaceGridLayout(GridLayout layout) { + layout.horizontalSpacing = 0; + layout.verticalSpacing = 0; + layout.marginWidth = 0; + layout.marginHeight = 0; + return layout; + } + + public static void main(String[] args) { + List options = Arrays.asList(args); + if (options.contains("--help")) { + System.out.println("Usage: java " + MiniBrowser.class.getName().replace('.', '/') + " [OPTION] [URL]"); + System.out.println("A minimalistic web browser Eclipse SWT Browser integration."); + System.out.println(" --fullscreen : take control of the whole screen (default is to run in a window)"); + System.out.println(" --app : open without an address bar and a toolbar"); + System.out.println(" --help : print this help and exit"); + System.exit(1); + } + boolean fullscreen = options.contains("--fullscreen"); + boolean appMode = options.contains("--app"); + String url = "https://start.duckduckgo.com/"; + if (options.size() > 0) { + String last = options.get(options.size() - 1); + if (!last.startsWith("--")) + url = last.trim(); + } + + Display display = Display.getCurrent() == null ? new Display() : Display.getCurrent(); + Shell shell; + if (fullscreen) { + shell = new Shell(display, SWT.NO_TRIM); + shell.setFullScreen(true); + Rectangle bounds = display.getBounds(); + shell.setSize(bounds.width, bounds.height); + } else { + shell = new Shell(display, SWT.SHELL_TRIM); + shell.setSize(defaultShellSize); + } + + new MiniBrowser(shell, url, fullscreen, appMode) { + + @Override + protected void titleChanged(String title) { + shell.setText(title); + } + }; + shell.open(); + + while (!shell.isDisposed()) { + if (!display.readAndDispatch()) + display.sleep(); + } + } + +} diff --git a/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniDesktopImages.java b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniDesktopImages.java new file mode 100644 index 000000000..db5e6f273 --- /dev/null +++ b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniDesktopImages.java @@ -0,0 +1,53 @@ +package org.argeo.minidesktop; + +import java.io.IOException; +import java.io.InputStream; + +import org.eclipse.swt.SWTException; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Display; + +/** Icons. */ +public class MiniDesktopImages { + + public final Image homeIcon; + public final Image exitIcon; + + public final Image terminalIcon; + public final Image browserIcon; + public final Image explorerIcon; + public final Image textEditorIcon; + + public final Image folderIcon; + public final Image fileIcon; + + public MiniDesktopImages(Display display) { + homeIcon = loadImage(display, "nav_home@2x.png"); + exitIcon = loadImage(display, "delete@2x.png"); + + terminalIcon = loadImage(display, "console_view@2x.png"); + browserIcon = loadImage(display, "external_browser@2x.png"); + explorerIcon = loadImage(display, "fldr_obj@2x.png"); + textEditorIcon = loadImage(display, "cheatsheet_obj@2x.png"); + + folderIcon = loadImage(display, "fldr_obj@2x.png"); + fileIcon = loadImage(display, "file_obj@2x.png"); + } + + static Image loadImage(Display display, String path) { + InputStream stream = MiniDesktopImages.class.getResourceAsStream(path); + if (stream == null) + throw new IllegalArgumentException("Image " + path + " not found"); + Image image = null; + try { + image = new Image(display, stream); + } catch (SWTException ex) { + } finally { + try { + stream.close(); + } catch (IOException ex) { + } + } + return image; + } +} diff --git a/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniDesktopManager.java b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniDesktopManager.java new file mode 100644 index 000000000..6af59d9d6 --- /dev/null +++ b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniDesktopManager.java @@ -0,0 +1,347 @@ +package org.argeo.minidesktop; + +import java.lang.management.ManagementFactory; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.List; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.CTabFolder; +import org.eclipse.swt.custom.CTabItem; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.ToolBar; +import org.eclipse.swt.widgets.ToolItem; + +/** A very minimalistic desktop manager based on Java and Eclipse SWT. */ +public class MiniDesktopManager { + private Display display; + + private Shell rootShell; + private Shell toolBarShell; + private CTabFolder tabFolder; + private int maxTabTitleLength = 16; + + private final boolean fullscreen; + private final boolean stacking; + + private MiniDesktopImages images; + + public MiniDesktopManager(boolean fullscreen, boolean stacking) { + this.fullscreen = fullscreen; + this.stacking = stacking; + } + + public void init() { + Display.setAppName("Mini SWT Desktop"); + display = Display.getCurrent(); + if (display != null) + throw new IllegalStateException("Already a display " + display); + display = new Display(); + + if (display.getTouchEnabled()) { + System.out.println("Touch enabled."); + } + + images = new MiniDesktopImages(display); + + int toolBarSize = 48; + + if (isFullscreen()) { + rootShell = new Shell(display, SWT.NO_TRIM); + rootShell.setFullScreen(true); + Rectangle bounds = display.getBounds(); + rootShell.setLocation(0, 0); + rootShell.setSize(bounds.width, bounds.height); + } else { + rootShell = new Shell(display, SWT.CLOSE | SWT.RESIZE); + Rectangle shellArea = rootShell.computeTrim(200, 200, 800, 480); + rootShell.setSize(shellArea.width, shellArea.height); + rootShell.setText(Display.getAppName()); + rootShell.setImage(images.terminalIcon); + } + + rootShell.setLayout(noSpaceGridLayout(new GridLayout(2, false))); + Composite toolBarArea = new Composite(rootShell, SWT.NONE); + toolBarArea.setLayoutData(new GridData(toolBarSize, rootShell.getSize().y)); + + ToolBar toolBar; + if (isFullscreen()) { + toolBarShell = new Shell(rootShell, SWT.NO_TRIM | SWT.ON_TOP); + toolBar = new ToolBar(toolBarShell, SWT.VERTICAL | SWT.FLAT | SWT.BORDER); + createDock(toolBar); + toolBarShell.pack(); + toolBarArea.setLayoutData(new GridData(toolBar.getSize().x, toolBar.getSize().y)); + } else { + toolBar = new ToolBar(toolBarArea, SWT.VERTICAL | SWT.FLAT | SWT.BORDER); + createDock(toolBar); + toolBarArea.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false)); + } + + if (isStacking()) { + tabFolder = new CTabFolder(rootShell, SWT.MULTI | SWT.BORDER | SWT.BOTTOM); + tabFolder.setLayout(noSpaceGridLayout(new GridLayout())); + tabFolder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + Color selectionBackground = display.getSystemColor(SWT.COLOR_LIST_SELECTION); + tabFolder.setSelectionBackground(selectionBackground); + + // background + Control background = createBackground(tabFolder); + CTabItem homeTabItem = new CTabItem(tabFolder, SWT.NONE); + homeTabItem.setText("Home"); + homeTabItem.setImage(images.homeIcon); + homeTabItem.setControl(background); + tabFolder.setFocus(); + } else { + createBackground(rootShell); + } + + rootShell.open(); + // rootShell.layout(true, true); + + if (toolBarShell != null) { + int toolBarShellY = (display.getBounds().height - toolBar.getSize().y) / 2; + toolBarShell.setLocation(0, toolBarShellY); + toolBarShell.open(); + } + + long jvmUptime = ManagementFactory.getRuntimeMXBean().getUptime(); + System.out.println("SWT Mini Desktop Manager available in " + jvmUptime + " ms."); + } + + protected void createDock(ToolBar toolBar) { + // Terminal + addToolItem(toolBar, images.terminalIcon, "Terminal", () -> { + String url = System.getProperty("user.home"); + AppContext appContext = createAppParent(images.terminalIcon); + new MiniTerminal(appContext.getAppParent(), url) { + + @Override + protected void exitCalled() { + if (appContext.shell != null) + appContext.shell.dispose(); + if (appContext.tabItem != null) + appContext.tabItem.dispose(); + } + }; + String title; + try { + title = System.getProperty("user.name") + "@" + InetAddress.getLocalHost().getHostName(); + } catch (UnknownHostException e) { + title = System.getProperty("user.name") + "@localhost"; + } + if (appContext.shell != null) + appContext.shell.setText(title); + if (appContext.tabItem != null) { + appContext.tabItem.setText(tabTitle(title)); + appContext.tabItem.setToolTipText(title); + } + openApp(appContext); + }); + + // Web browser + addToolItem(toolBar, images.browserIcon, "Browser", () -> { + String url = "https://start.duckduckgo.com/"; + AppContext appContext = createAppParent(images.browserIcon); + new MiniBrowser(appContext.getAppParent(), url, false, false) { + @Override + protected void titleChanged(String title) { + if (appContext.shell != null) + appContext.shell.setText(title); + if (appContext.tabItem != null) { + appContext.tabItem.setText(tabTitle(title)); + appContext.tabItem.setToolTipText(title); + } + } + }; + openApp(appContext); + }); + + // File explorer + addToolItem(toolBar, images.explorerIcon, "Explorer", () -> { + String url = System.getProperty("user.home"); + AppContext appContext = createAppParent(images.explorerIcon); + new MiniExplorer(appContext.getAppParent(), url) { + + @Override + protected void pathChanged(Path path) { + if (appContext.shell != null) + appContext.shell.setText(path.toString()); + if (appContext.tabItem != null) { + appContext.tabItem.setText(path.getFileName().toString()); + appContext.tabItem.setToolTipText(path.toString()); + } + } + }; + openApp(appContext); + }); + + // Separator + new ToolItem(toolBar, SWT.SEPARATOR); + + // Exit + addToolItem(toolBar, images.exitIcon, "Exit", () -> rootShell.dispose()); + + toolBar.pack(); + } + + protected String tabTitle(String title) { + return title.length() > maxTabTitleLength ? title.substring(0, maxTabTitleLength) : title; + } + + protected void addToolItem(ToolBar toolBar, Image icon, String name, Runnable action) { + ToolItem searchI = new ToolItem(toolBar, SWT.PUSH); + searchI.setImage(icon); + searchI.setToolTipText(name); + searchI.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + action.run(); + } + + }); + } + + protected AppContext createAppParent(Image icon) { + if (isStacking()) { + Composite appParent = new Composite(tabFolder, SWT.CLOSE); + appParent.setLayout(noSpaceGridLayout(new GridLayout())); + CTabItem item = new CTabItem(tabFolder, SWT.CLOSE); + item.setImage(icon); + item.setControl(appParent); + return new AppContext(item); + } else { + Shell shell = isFullscreen() ? new Shell(rootShell, SWT.SHELL_TRIM) + : new Shell(rootShell.getDisplay(), SWT.SHELL_TRIM); + shell.setImage(icon); + return new AppContext(shell); + } + } + + protected void openApp(AppContext appContext) { + if (appContext.shell != null) { + Shell shell = (Shell) appContext.shell; + shell.open(); + shell.setSize(new Point(800, 480)); + } + if (appContext.tabItem != null) { + tabFolder.setFocus(); + tabFolder.setSelection(appContext.tabItem); + } + } + + protected Control createBackground(Composite parent) { + Composite backgroundArea = new Composite(parent, SWT.NONE); + backgroundArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + initBackground(backgroundArea); + return backgroundArea; + } + + protected void initBackground(Composite backgroundArea) { + MiniHomePart homePart = new MiniHomePart() { + + @Override + protected void fillAppsToolBar(ToolBar toolBar) { + createDock(toolBar); + } + }; + homePart.createUiPart(backgroundArea, null); + } + + public void run() { + while (!rootShell.isDisposed()) { + if (!display.readAndDispatch()) + display.sleep(); + } + } + + public void dispose() { + if (!rootShell.isDisposed()) + rootShell.dispose(); + } + + protected boolean isFullscreen() { + return fullscreen; + } + + protected boolean isStacking() { + return stacking; + } + + protected Image getIconForExt(String ext) { +// Program program = Program.findProgram(ext); +// if (program == null) + return display.getSystemImage(SWT.ICON_INFORMATION); + +// ImageData iconData = program.getImageData(); +// if (iconData == null) { +// return display.getSystemImage(SWT.ICON_INFORMATION); +// } else { +// return new Image(display, iconData); +// } + + } + + private static GridLayout noSpaceGridLayout(GridLayout layout) { + layout.horizontalSpacing = 0; + layout.verticalSpacing = 0; + layout.marginWidth = 0; + layout.marginHeight = 0; + return layout; + } + + public static void main(String[] args) { + List options = Arrays.asList(args); + if (options.contains("--help")) { + System.out.println("Usage: java " + MiniDesktopManager.class.getName().replace('.', '/') + " [OPTION]"); + System.out.println("A minimalistic desktop manager based on Java and Eclipse SWT."); + System.out.println(" --fullscreen : take control of the whole screen (default is to run in a window)"); + System.out.println(" --stacking : open apps as tabs (default is to create new windows)"); + System.out.println(" --help : print this help and exit"); + System.exit(1); + } + boolean fullscreen = options.contains("--fullscreen"); + boolean stacking = options.contains("--stacking"); + + MiniDesktopManager desktopManager = new MiniDesktopManager(fullscreen, stacking); + desktopManager.init(); + desktopManager.run(); + desktopManager.dispose(); + System.exit(0); + } + + class AppContext { + private Shell shell; + private CTabItem tabItem; + + public AppContext(Shell shell) { + this.shell = shell; + } + + public AppContext(CTabItem tabItem) { + this.tabItem = tabItem; + } + + Composite getAppParent() { + if (shell != null) + return shell; + if (tabItem != null) + return (Composite) tabItem.getControl(); + throw new IllegalStateException(); + } + } +} diff --git a/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniExplorer.java b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniExplorer.java new file mode 100644 index 000000000..9a967a2d4 --- /dev/null +++ b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniExplorer.java @@ -0,0 +1,164 @@ +package org.argeo.minidesktop; + +import java.io.IOException; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.MouseAdapter; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableItem; +import org.eclipse.swt.widgets.Text; + +public class MiniExplorer { + private Path path; + private Text addressT; + private Table browser; + + private boolean showHidden = false; + + public MiniExplorer(Composite parent, String url) { + this(parent); + setUrl(url); + } + + public MiniExplorer(Composite parent) { + parent.setLayout(noSpaceGridLayout(new GridLayout())); + + Composite toolBar = new Composite(parent, SWT.NONE); + toolBar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + toolBar.setLayout(new FillLayout()); + addressT = new Text(toolBar, SWT.SINGLE); + addressT.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + setUrl(addressT.getText().trim()); + } + }); + browser = createTable(parent, this.path); + + } + + public void setPath(Path url) { + this.path = url; + if (addressT != null) + addressT.setText(url.toString()); + if (browser != null) { + Composite parent = browser.getParent(); + browser.dispose(); + browser = createTable(parent, this.path); + parent.layout(true, true); + } + pathChanged(url); + } + + protected void pathChanged(Path path) { + + } + + protected Table createTable(Composite parent, Path path) { + Table table = new Table(parent, SWT.BORDER); + table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + table.addMouseListener(new MouseAdapter() { + + @Override + public void mouseDoubleClick(MouseEvent e) { + Point pt = new Point(e.x, e.y); + TableItem item = table.getItem(pt); + Path path = (Path) item.getData(); + if (Files.isDirectory(path)) { + setPath(path); + } else { + //Program.launch(path.toString()); + } + } + }); + + if (path != null) { + if (path.getParent() != null) { + TableItem parentTI = new TableItem(table, SWT.NONE); + parentTI.setText(".."); + parentTI.setData(path.getParent()); + } + + try { + // directories + DirectoryStream ds = Files.newDirectoryStream(path, p -> Files.isDirectory(p) && isShown(p)); + ds.forEach(p -> { + TableItem ti = new TableItem(table, SWT.NONE); + ti.setText(p.getFileName().toString() + "/"); + ti.setData(p); + }); + // files + ds = Files.newDirectoryStream(path, p -> !Files.isDirectory(p) && isShown(p)); + ds.forEach(p -> { + TableItem ti = new TableItem(table, SWT.NONE); + ti.setText(p.getFileName().toString()); + ti.setData(p); + }); + } catch (IOException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + } + return table; + } + + protected boolean isShown(Path path) { + if (showHidden) + return true; + try { + return !Files.isHidden(path); + } catch (IOException e) { + throw new IllegalArgumentException("Cannot check " + path, e); + } + } + + public void setUrl(String url) { + setPath(Paths.get(url)); + } + + private static GridLayout noSpaceGridLayout(GridLayout layout) { + layout.horizontalSpacing = 0; + layout.verticalSpacing = 0; + layout.marginWidth = 0; + layout.marginHeight = 0; + return layout; + } + + public static void main(String[] args) { + Display display = Display.getCurrent() == null ? new Display() : Display.getCurrent(); + Shell shell = new Shell(display, SWT.SHELL_TRIM); + + String url = args.length > 0 ? args[0] : System.getProperty("user.home"); + new MiniExplorer(shell, url) { + + @Override + protected void pathChanged(Path path) { + shell.setText(path.toString()); + } + + }; + + shell.open(); + shell.setSize(new Point(800, 480)); + while (!shell.isDisposed()) { + if (!display.readAndDispatch()) + display.sleep(); + } + } + +} diff --git a/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniHomePart.java b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniHomePart.java new file mode 100644 index 000000000..877f64384 --- /dev/null +++ b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniHomePart.java @@ -0,0 +1,161 @@ +package org.argeo.minidesktop; + +import java.net.InetAddress; +import java.net.InterfaceAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.Enumeration; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.ProgressBar; +import org.eclipse.swt.widgets.ToolBar; + +/** A start page displaying network information and resources. */ +public class MiniHomePart { + + public Control createUiPart(Composite parent, Object context) { + parent.setLayout(new GridLayout(2, false)); + Display display = parent.getDisplay(); + + // Apps + Group appsGroup = new Group(parent, SWT.NONE); + appsGroup.setText("Apps"); + appsGroup.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false, 2, 1)); + ToolBar appsToolBar = new ToolBar(appsGroup, SWT.HORIZONTAL | SWT.FLAT); + fillAppsToolBar(appsToolBar); + + // Host + Group hostGroup = new Group(parent, SWT.NONE); + hostGroup.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false)); + hostGroup.setText("Host"); + hostGroup.setLayout(new GridLayout(2, false)); + label(hostGroup, "Hostname: "); + try { + InetAddress defaultAddr = InetAddress.getLocalHost(); + String hostname = defaultAddr.getHostName(); + label(hostGroup, hostname); + label(hostGroup, "Address: "); + label(hostGroup, defaultAddr.getHostAddress()); + } catch (UnknownHostException e) { + label(hostGroup, e.getMessage()); + } + + Enumeration netInterfaces = null; + try { + netInterfaces = NetworkInterface.getNetworkInterfaces(); + } catch (SocketException e) { + label(hostGroup, "Interfaces: "); + label(hostGroup, e.getMessage()); + } + if (netInterfaces != null) + while (netInterfaces.hasMoreElements()) { + NetworkInterface netInterface = netInterfaces.nextElement(); + byte[] hardwareAddress = null; + try { + hardwareAddress = netInterface.getHardwareAddress(); + if (hardwareAddress != null) { + label(hostGroup, convertHardwareAddress(hardwareAddress)); + label(hostGroup, netInterface.getName()); + for (InterfaceAddress addr : netInterface.getInterfaceAddresses()) { + label(hostGroup, cleanHostAddress(addr.getAddress().getHostAddress())); + label(hostGroup, Short.toString(addr.getNetworkPrefixLength())); + } + } + } catch (SocketException e) { + label(hostGroup, e.getMessage()); + } + } + + // Resources + Group resGroup = new Group(parent, SWT.NONE); + resGroup.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + resGroup.setText("Resources"); + resGroup.setLayout(new GridLayout(3, false)); + + Runtime runtime = Runtime.getRuntime(); + + String maxMemoryStr = Long.toString(runtime.maxMemory() / (1024 * 1024)) + " MB"; + label(resGroup, "Max Java memory: "); + label(resGroup, maxMemoryStr); + label(resGroup, "Java version: " + Runtime.version().toString()); + + label(resGroup, "Usable Java memory: "); + Label totalMemory = label(resGroup, maxMemoryStr); + ProgressBar totalOnMax = new ProgressBar(resGroup, SWT.SMOOTH); + totalOnMax.setMaximum(100); + label(resGroup, "Used Java memory: "); + Label usedMemory = label(resGroup, maxMemoryStr); + ProgressBar usedOnTotal = new ProgressBar(resGroup, SWT.SMOOTH); + totalOnMax.setMaximum(100); + new Thread() { + @Override + public void run() { + while (!totalOnMax.isDisposed()) { + display.asyncExec(() -> { + if (totalOnMax.isDisposed()) + return; + totalOnMax.setSelection(javaTotalOnMaxPerct(runtime)); + usedOnTotal.setSelection(javaUsedOnTotalPerct(runtime)); + totalMemory.setText(Long.toString(runtime.totalMemory() / (1024 * 1024)) + " MB"); + usedMemory.setText( + Long.toString((runtime.totalMemory() - runtime.freeMemory()) / (1024 * 1024)) + " MB"); + }); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + return; + } + } + } + }.start(); + return parent; + } + + protected void fillAppsToolBar(ToolBar toolBar) { + + } + + protected int javaUsedOnTotalPerct(Runtime runtime) { + return Math.toIntExact((runtime.totalMemory() - runtime.freeMemory()) * 100 / runtime.totalMemory()); + } + + protected int javaTotalOnMaxPerct(Runtime runtime) { + return Math.toIntExact((runtime.totalMemory()) * 100 / runtime.maxMemory()); + } + + protected Label label(Composite parent, String text) { + Label label = new Label(parent, SWT.WRAP); + label.setText(text); + return label; + } + + protected String cleanHostAddress(String hostAddress) { + // remove % from Ipv6 addresses + int index = hostAddress.indexOf('%'); + if (index > 0) + return hostAddress.substring(0, index); + else + return hostAddress; + } + + protected String convertHardwareAddress(byte[] hardwareAddress) { + if (hardwareAddress == null) + return ""; + // from https://stackoverflow.com/a/2797498/7878010 + StringBuilder sb = new StringBuilder(18); + for (byte b : hardwareAddress) { + if (sb.length() > 0) + sb.append(':'); + sb.append(String.format("%02x", b).toUpperCase()); + } + return sb.toString(); + } +} diff --git a/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniImageViewer.java b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniImageViewer.java new file mode 100644 index 000000000..86ff53fee --- /dev/null +++ b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniImageViewer.java @@ -0,0 +1,129 @@ +package org.argeo.minidesktop; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.events.PaintListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.ImageLoader; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.layout.RowLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Canvas; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Shell; + +public class MiniImageViewer implements PaintListener { + private URL url; + private Canvas area; + + private Image image; + + public MiniImageViewer(Composite parent, int style) { + parent.setLayout(new GridLayout()); + + Composite toolBar = new Composite(parent, SWT.NONE); + toolBar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + toolBar.setLayout(new RowLayout()); + Button load = new Button(toolBar, SWT.FLAT); + load.setText("\u2191");// up arrow + load.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + FileDialog fileDialog = new FileDialog(area.getShell()); + String path = fileDialog.open(); + if (path != null) { + setUrl(path); + } + } + + }); + + area = new Canvas(parent, SWT.NONE); + area.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + area.addPaintListener(this); + } + + protected void load(URL url) { + try { + ImageLoader imageLoader = new ImageLoader(); + ImageData[] data = imageLoader.load(url.openStream()); + image = new Image(area.getDisplay(), data[0]); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Override + public void paintControl(PaintEvent e) { + e.gc.drawImage(image, 0, 0); + + } + + protected Path url2path(URL url) { + try { + Path path = Paths.get(url.toURI()); + return path; + } catch (URISyntaxException e) { + throw new IllegalStateException("Cannot convert " + url + " to uri", e); + } + } + + public void setUrl(URL url) { + this.url = url; + if (area != null) + load(this.url); + } + + public void setUrl(String url) { + try { + setUrl(new URL(url)); + } catch (MalformedURLException e) { + // try with http + try { + setUrl(new URL("file://" + url)); + return; + } catch (MalformedURLException e1) { + // nevermind... + } + throw new IllegalArgumentException("Cannot interpret URL " + url, e); + } + } + + public static void main(String[] args) { + Display display = Display.getCurrent() == null ? new Display() : Display.getCurrent(); + Shell shell = new Shell(display, SWT.SHELL_TRIM); + + MiniImageViewer miniBrowser = new MiniImageViewer(shell, SWT.NONE); + String url = args.length > 0 ? args[0] : ""; + if (!url.trim().equals("")) { + miniBrowser.setUrl(url); + shell.setText(url); + } else { + shell.setText("*"); + } + + shell.open(); + shell.setSize(new Point(800, 480)); + while (!shell.isDisposed()) { + if (!display.readAndDispatch()) + display.sleep(); + } + } + +} diff --git a/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniTerminal.java b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniTerminal.java new file mode 100644 index 000000000..cd1a9f224 --- /dev/null +++ b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniTerminal.java @@ -0,0 +1,342 @@ +package org.argeo.minidesktop; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.StringTokenizer; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.events.PaintListener; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Canvas; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; + +public class MiniTerminal implements KeyListener, PaintListener { + + private Canvas area; +// private Caret caret; + + private StringBuffer buf = new StringBuffer(""); + private StringBuffer userInput = new StringBuffer(""); + private List history = new ArrayList<>(); + + private Point charExtent = null; + private int charsPerLine = 0; + private String[] lines = new String[0]; + private List logicalLines = new ArrayList<>(); + + private Font mono; + private Charset charset; + + private Path currentDir; + private Path homeDir; + private String host = "localhost"; + private String username; + + // Sub process + private Process process; + private boolean running = false; + private OutputStream stdIn = null; + + private Thread readOut; + + public MiniTerminal(Composite parent, String url) { + this(parent); + setPath(url); + } + + public MiniTerminal(Composite parent) { + charset = StandardCharsets.UTF_8; + + Display display = parent.getDisplay(); + // Linux-specific + mono = new Font(display, "Monospace", 10, SWT.NONE); + + parent.setLayout(new GridLayout()); + area = new Canvas(parent, SWT.NONE); + area.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); +// caret = new Caret(area, SWT.NONE); +// area.setCaret(caret); + + area.addKeyListener(this); + area.addPaintListener(this); + + username = System.getProperty("user.name"); + try { + host = InetAddress.getLocalHost().getHostName(); + if (host.indexOf('.') > 0) + host = host.substring(0, host.indexOf('.')); + } catch (UnknownHostException e) { + host = "localhost"; + } + homeDir = Paths.get(System.getProperty("user.home")); + currentDir = homeDir; + + buf = new StringBuffer(prompt()); + } + + @Override + public void keyPressed(KeyEvent e) { + } + + @Override + public void keyReleased(KeyEvent e) { +// if (e.keyLocation != 0) +// return;// weird characters + + // System.out.println(e.character); + if (e.keyCode == 0xd) {// return + markLogicalLine(); + if (!running) + processUserInput(); + // buf.append(prompt()); + } else if (e.keyCode == 0x8) {// delete + if (userInput.length() == 0) + return; + userInput.setLength(userInput.length() - 1); + if (!running && buf.length() > 0) + buf.setLength(buf.length() - 1); + } else if (e.stateMask == 0x40000 && e.keyCode == 0x63) {// Ctrl+C + if (process != null) + process.destroy(); + } else if (e.stateMask == 0x40000 && e.keyCode == 0xdf) {// Ctrl+\ + if (process != null) { + process.destroyForcibly(); + } + } else { + // if (!running) + buf.append(e.character); + userInput.append(e.character); + } + + if (area.isDisposed()) + return; + area.redraw(); + // System.out.println("Append " + e); + + if (running) { + if (stdIn != null) { + try { + stdIn.write(Character.toString(e.character).getBytes(charset)); + } catch (IOException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + } + } + } + + protected String prompt() { + String fileName = currentDir.equals(homeDir) ? "~" : currentDir.getFileName().toString(); + String end = username.equals("root") ? "]# " : "]$ "; + return "[" + username + "@" + host + " " + fileName + end; + } + + private void displayPrompt() { + buf.append(prompt() + userInput); + } + + protected void markLogicalLine() { + String str = buf.toString().trim(); + logicalLines.add(str); + buf = new StringBuffer(""); + } + + private void processUserInput() { + String cmd = userInput.toString(); + userInput = new StringBuffer(""); + processUserInput(cmd); + history.add(cmd); + } + + protected void processUserInput(String input) { + try { + StringTokenizer st = new StringTokenizer(input); + List args = new ArrayList<>(); + while (st.hasMoreTokens()) + args.add(st.nextToken()); + if (args.size() == 0) { + displayPrompt(); + return; + } + + // change directory + if (args.get(0).equals("cd")) { + if (args.size() == 1) { + setPath(homeDir); + } else { + Path newPath = currentDir.resolve(args.get(1)); + if (!Files.exists(newPath) || !Files.isDirectory(newPath)) { + println(newPath + ": No such file or directory"); + return; + } + setPath(newPath); + } + displayPrompt(); + return; + } + // show current directory + else if (args.get(0).equals("pwd")) { + println(currentDir); + displayPrompt(); + return; + } + // exit + else if (args.get(0).equals("exit")) { + println("logout"); + exitCalled(); + return; + } + + ProcessBuilder pb = new ProcessBuilder(args); + pb.redirectErrorStream(true); + pb.directory(currentDir.toFile()); +// Process process = Runtime.getRuntime().exec(input, null, currentPath.toFile()); + process = pb.start(); + + stdIn = process.getOutputStream(); + readOut = new Thread("MiniTerminal read out") { + @Override + public void run() { + running = true; + try (BufferedReader in = new BufferedReader( + new InputStreamReader(process.getInputStream(), charset))) { + String line = null; + while ((line = in.readLine()) != null) { + println(line); + } + } catch (IOException e) { + println(e.getMessage()); + } + stdIn = null; + displayPrompt(); + running = false; + readOut = null; + process = null; + } + }; + readOut.start(); + } catch (IOException e) { + println(e.getMessage()); + displayPrompt(); + } + } + + protected int linesForLogicalLine(char[] line) { + return line.length / charsPerLine + 1; + } + + protected void println(Object line) { + buf.append(line); + markLogicalLine(); + } + + protected void refreshLines(int charPerLine, int nbrOfLines) { + if (lines.length != nbrOfLines) { + lines = new String[nbrOfLines]; + Arrays.fill(lines, null); + } + if (this.charsPerLine != charPerLine) + this.charsPerLine = charPerLine; + + int currentLine = nbrOfLines - 1; + // current line + if (buf.length() > 0) { + lines[currentLine] = buf.toString(); + } else { + lines[currentLine] = ""; + } + currentLine--; + + logicalLines: for (int i = logicalLines.size() - 1; i >= 0; i--) { + char[] logicalLine = logicalLines.get(i).toCharArray(); + int linesNeeded = linesForLogicalLine(logicalLine); + for (int j = linesNeeded - 1; j >= 0; j--) { + int from = j * charPerLine; + int to = j == linesNeeded - 1 ? from + charPerLine : Math.min(from + charPerLine, logicalLine.length); + lines[currentLine] = new String(Arrays.copyOfRange(logicalLine, from, to)); +// System.out.println("Set line " + currentLine + " to : " + lines[currentLine]); + currentLine--; + if (currentLine < 0) + break logicalLines; + } + } + } + + @Override + public void paintControl(PaintEvent e) { + GC gc = e.gc; + gc.setFont(mono); + if (charExtent == null) + charExtent = gc.textExtent("a"); + + Point areaSize = area.getSize(); + int charPerLine = areaSize.x / charExtent.x; + int nbrOfLines = areaSize.y / charExtent.y; + refreshLines(charPerLine, nbrOfLines); + + for (int i = 0; i < lines.length; i++) { + String line = lines[i]; + if (line != null) + gc.drawString(line, 0, i * charExtent.y); + } +// String toDraw = buf.toString(); +// gc.drawString(toDraw, 0, 0); +// area.setCaret(caret); + } + + protected void exitCalled() { + + } + + public void setPath(String path) { + this.currentDir = Paths.get(path); + } + + public void setPath(Path path) { + this.currentDir = path; + } + + public static void main(String[] args) { + Display display = Display.getCurrent() == null ? new Display() : Display.getCurrent(); + Shell shell = new Shell(display, SWT.SHELL_TRIM); + + String url = args.length > 0 ? args[0] : System.getProperty("user.home"); + new MiniTerminal(shell, url) { + + @Override + protected void exitCalled() { + shell.dispose(); + System.exit(0); + } + }; + + shell.open(); + shell.setSize(new Point(800, 480)); + while (!shell.isDisposed()) { + if (!display.readAndDispatch()) + display.sleep(); + } + } + +} diff --git a/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniTextEditor.java b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniTextEditor.java new file mode 100644 index 000000000..91cd19e90 --- /dev/null +++ b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniTextEditor.java @@ -0,0 +1,161 @@ +package org.argeo.minidesktop; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.layout.RowLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +public class MiniTextEditor { + private URL url; + private Text text; + + public MiniTextEditor(Composite parent, int style) { + parent.setLayout(new GridLayout()); + + Composite toolBar = new Composite(parent, SWT.NONE); + toolBar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + toolBar.setLayout(new RowLayout()); + Button load = new Button(toolBar, SWT.FLAT); + load.setText("\u2191");// up arrow + load.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + FileDialog fileDialog = new FileDialog(text.getShell()); + String path = fileDialog.open(); + if (path != null) { + setUrl(path); + } + } + + }); + + Button save = new Button(toolBar, SWT.FLAT); + save.setText("\u2193");// down arrow + // save.setText("\u1F609");// emoji + save.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + save(url); + } + + }); + + text = new Text(parent, SWT.WRAP | SWT.MULTI | SWT.BORDER | SWT.V_SCROLL); + text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + } + + protected void load(URL url) { + text.setText(""); + // TODO deal with encoding and binary data + try (BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8))) { + String line = null; + while ((line = in.readLine()) != null) { + text.append(line + "\n"); + } + text.setEditable(true); + } catch (IOException e) { + if (e instanceof FileNotFoundException) { + Path path = url2path(url); + try { + Files.createFile(path); + load(url); + return; + } catch (IOException e1) { + e = e1; + } + } + text.setText(e.getMessage()); + text.setEditable(false); + e.printStackTrace(); + // throw new IllegalStateException("Cannot load " + url, e); + } + } + + protected Path url2path(URL url) { + try { + Path path = Paths.get(url.toURI()); + return path; + } catch (URISyntaxException e) { + throw new IllegalStateException("Cannot convert " + url + " to uri", e); + } + } + + protected void save(URL url) { + if (!url.getProtocol().equals("file")) + throw new IllegalArgumentException(url.getProtocol() + " protocol is not supported for write"); + Path path = url2path(url); + try (BufferedWriter out = new BufferedWriter(new OutputStreamWriter(Files.newOutputStream(path)))) { + out.write(text.getText()); + } catch (IOException e) { + throw new IllegalStateException("Cannot save " + url + " to " + path, e); + } + } + + public void setUrl(URL url) { + this.url = url; + if (text != null) + load(url); + } + + public void setUrl(String url) { + try { + setUrl(new URL(url)); + } catch (MalformedURLException e) { + // try with http + try { + setUrl(new URL("file://" + url)); + return; + } catch (MalformedURLException e1) { + // nevermind... + } + throw new IllegalArgumentException("Cannot interpret URL " + url, e); + } + } + + public static void main(String[] args) { + Display display = Display.getCurrent() == null ? new Display() : Display.getCurrent(); + Shell shell = new Shell(display, SWT.SHELL_TRIM); + + MiniTextEditor miniBrowser = new MiniTextEditor(shell, SWT.NONE); + String url = args.length > 0 ? args[0] : ""; + if (!url.trim().equals("")) { + miniBrowser.setUrl(url); + shell.setText(url); + } else { + shell.setText("*"); + } + + shell.open(); + shell.setSize(new Point(800, 480)); + while (!shell.isDisposed()) { + if (!display.readAndDispatch()) + display.sleep(); + } + } + +} diff --git a/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/cheatsheet_obj@2x.png b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/cheatsheet_obj@2x.png new file mode 100644 index 000000000..55c614dfa Binary files /dev/null and b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/cheatsheet_obj@2x.png differ diff --git a/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/console_view@2x.png b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/console_view@2x.png new file mode 100644 index 000000000..54ecae20f Binary files /dev/null and b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/console_view@2x.png differ diff --git a/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/delete@2x.png b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/delete@2x.png new file mode 100644 index 000000000..eb2fc720b Binary files /dev/null and b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/delete@2x.png differ diff --git a/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/external_browser@2x.png b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/external_browser@2x.png new file mode 100644 index 000000000..06d337a43 Binary files /dev/null and b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/external_browser@2x.png differ diff --git a/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/file_obj@2x.png b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/file_obj@2x.png new file mode 100644 index 000000000..31e671c46 Binary files /dev/null and b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/file_obj@2x.png differ diff --git a/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/fldr_obj@2x.png b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/fldr_obj@2x.png new file mode 100644 index 000000000..adb7c2cc2 Binary files /dev/null and b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/fldr_obj@2x.png differ diff --git a/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/nav_home@2x.png b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/nav_home@2x.png new file mode 100644 index 000000000..4c9a16c0f Binary files /dev/null and b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/nav_home@2x.png differ diff --git a/swt/rap/org.argeo.cms.swt.rap.cli/src/org/argeo/cms/swt/rap/cli/RwtRunner.java b/swt/rap/org.argeo.cms.swt.rap.cli/src/org/argeo/cms/swt/rap/cli/RwtRunner.java index 6b678a83c..b03939f81 100644 --- a/swt/rap/org.argeo.cms.swt.rap.cli/src/org/argeo/cms/swt/rap/cli/RwtRunner.java +++ b/swt/rap/org.argeo.cms.swt.rap.cli/src/org/argeo/cms/swt/rap/cli/RwtRunner.java @@ -9,6 +9,7 @@ import java.util.Objects; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; +import org.argeo.minidesktop.MiniDesktopManager; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; @@ -17,9 +18,10 @@ import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.thread.QueuedThreadPool; -import org.eclipse.rap.rwt.application.AbstractEntryPoint; import org.eclipse.rap.rwt.application.ApplicationConfiguration; import org.eclipse.rap.rwt.application.ApplicationRunner; +import org.eclipse.rap.rwt.application.EntryPoint; +import org.eclipse.rap.rwt.application.Application.OperationMode; import org.eclipse.rap.rwt.engine.RWTServlet; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; @@ -52,7 +54,7 @@ public class RwtRunner { context.setContextPath("/"); server.setHandler(context); - String entryPoint = "data"; + String entryPoint = "app"; // rwt-resources requires a file system try { @@ -119,16 +121,18 @@ public class RwtRunner { RwtRunner rwtRunner = new RwtRunner(); String entryPoint = "app"; - ApplicationConfiguration applicationConfiguration = (application) -> application.addEntryPoint("/" + entryPoint, - () -> new AbstractEntryPoint() { - private static final long serialVersionUID = 5678385921969090733L; - - @Override - protected void createContents(Composite parent) { - Label label = new Label(parent, 0); - label.setText("Hello world!"); - } - }, null); + ApplicationConfiguration applicationConfiguration = (application) -> { + application.setOperationMode(OperationMode.SWT_COMPATIBILITY); + application.addEntryPoint("/" + entryPoint, () -> new EntryPoint() { + @Override + public int createUI() { + MiniDesktopManager miniDesktopManager = new MiniDesktopManager(false, false); + miniDesktopManager.init(); + miniDesktopManager.run(); + return 0; + } + }, null); + }; rwtRunner.setApplicationConfiguration(applicationConfiguration); rwtRunner.init();