=== modified file 'pl/p2jpl.ddr' --- pl/p2jpl.ddr 2018-09-02 18:06:34 +0000 +++ pl/p2jpl.ddr 2019-01-29 22:02:56 +0000 @@ -2,7 +2,7 @@ ** Module : p2jpl.ddr ** Abstract : deployment descriptor for p2jpl.jar ** -** Copyright (c) 2004-2018, Golden Code Development Corporation. +** Copyright (c) 2004-2019, Golden Code Development Corporation. ** ** _#_ _I_ __Date__ __JPRM__ ____________________________Description_____________________________ ** 001 ECF 20060821 @28594 Created initial version. An implementation of @@ -63,6 +63,7 @@ ** 027 OM 20160912 Added new trimws variant. ** 028 OM 20180618 Added support for fill function. ** 029 ECF 20180830 Added support for contains function. +** 030 ECF 20190129 Added support for toDate(timestamp) signature. */ /* @@ -1512,6 +1513,13 @@ java.lang.Integer)' language java immutable; + create function toDate(timestamp) + returns date as + 'java.sql.Date= + com.goldencode.p2j.persist.pl.Functions.toDate( + java.sql.Timestamp)' + language java immutable; + create function toDatetime(date, bigint) returns timestamp as @@ -2004,6 +2012,7 @@ drop function toDate(integer); drop function toDate(text); drop function toDate(text, text, integer); + drop function toDate(timestamp); drop function toDatetime(text); drop function toDatetime(text, text, integer); === modified file 'src/com/goldencode/p2j/main/ClientCore.java' --- src/com/goldencode/p2j/main/ClientCore.java 2017-09-14 12:22:38 +0000 +++ src/com/goldencode/p2j/main/ClientCore.java 2019-01-30 14:54:29 +0000 @@ -302,6 +302,8 @@ daemon.setDefaultEnvironment(ininame); } } + // initialize the Ease Access Manager + EaseAccessManager.init(remoteDir); } ThinClient.loadEnvironment(config); === modified file 'src/com/goldencode/p2j/persist/ConnectionManager.java' --- src/com/goldencode/p2j/persist/ConnectionManager.java 2019-01-14 20:04:26 +0000 +++ src/com/goldencode/p2j/persist/ConnectionManager.java 2019-02-01 21:32:19 +0000 @@ -126,7 +126,7 @@ ** are closed. ** 048 CA 20181128 Added support for GET-DB-CLIENT and SET-DB-CLIENT. ** 049 ECF 20181208 Stubbed dbTaskId method. -** 101 OM 20190111 Avoided circular indirect recursivity at initialization when _Connect +** 050 OM 20190111 Avoided circular indirect recursivity at initialization when _Connect ** meta-table is active. */ === modified file 'src/com/goldencode/p2j/persist/RecordBuffer.java' --- src/com/goldencode/p2j/persist/RecordBuffer.java 2019-01-14 20:04:26 +0000 +++ src/com/goldencode/p2j/persist/RecordBuffer.java 2019-02-01 21:32:19 +0000 @@ -1008,6 +1008,7 @@ ** deep-copying current record. ** 301 OM 20190111 Added support for VST R/O checking. Using annotations to manipulate ** tables. +** 302 OM 20190202 Fixed VST R/O checking (including create and delete). */ /* @@ -1459,6 +1460,17 @@ /** Flags this record buffer as readonly. Readonly buffers cannot be assigned. */ private boolean readonly = false; + /** This flags that the record held is a VST. */ + private final boolean vst; + + /** + * Flags whether the record stored has been write-touched. That is, whether a setter was + * invoked on the DMO, regardless whether the value was not actually changed since the last + * load of the record. Unlike {@code recordChanged} that tracks external changes (from other + * users), this boolean value tracks write-touches only from current user. + */ + private boolean isTouched = false; + /** Determines if this buffer is dynamic. */ private boolean dynamic = false; @@ -1633,6 +1645,10 @@ // instantiate a helper for trigger support triggerTracker = new TriggerTracker((Class) dmoBufIface); + + // + LegacyTable table = dmoClass.getAnnotation(LegacyTable.class); + vst = table.category().equalsIgnoreCase("VST"); } /** @@ -5779,6 +5795,16 @@ } /** + * Checks whether the record contained is a virtual system table (VST). + * + * @return {@code true} when the record contained is a VST. + */ + public boolean isVst() + { + return vst; + } + + /** * Return a reference to this object instance. This is implemented to * satisfy the BufferReference interface, and provides a * means for the persistence layer to retrieve a reference to the backing @@ -5980,13 +6006,9 @@ public void flush() throws ValidationException { - LegacyTable table = dmoClass.getAnnotation(LegacyTable.class); - if (table.name().equalsIgnoreCase("_Lock")) - { - persistence.flushMetaLockEvents(); - } - if (checkReadOnlyVstBuffer(table)) - { + if (vst) + { + checkReadOnlyVstBuffer(dmoClass.getAnnotation(LegacyTable.class)); return; } @@ -6083,27 +6105,24 @@ * not allow the modified data to be persisted then the flush event should be discarded. Note * that some VST tables will silently discard the flush event while some of them will also * display the 14378 error message. - * + * * @param table * The {@code LegacyTable} of current DMO class. - * - * @return {@code true} if the current DMO belongs to a (VST) table that does not allow the - * modified data to be persisted. */ - private boolean checkReadOnlyVstBuffer(LegacyTable table) + private void checkReadOnlyVstBuffer(LegacyTable table) { - if (table.category().equalsIgnoreCase("VST")) - { - if (table.name().equalsIgnoreCase("_Connect")) - { - String msg = "Updating " + table.name() + " Virtual System Table is not supported"; - ErrorManager.recordOrShowError(14378, msg, true); - } - - return table.isFrozen(); - } - - return false; + String legacyName = table.name(); + + if (isTouched) + { + String msg = "Updating " + legacyName + " Virtual System Table is not supported"; + ErrorManager.recordOrShowError(14378, msg, true); + } + + if (legacyName.equalsIgnoreCase("_Lock")) + { + persistence.flushMetaLockEvents(); + } } /** @@ -7040,6 +7059,14 @@ protected void delete() throws PersistenceException { + if (vst) + { + // this is quite fatal, NO-ERROR will not prevent it from stopping the procedure + ErrorManager.throwError(6311, + "Deleting Virtual System Tables is not allowed", + null, false); + } + if (currentRecord == null) { // Nothing to delete! @@ -9057,6 +9084,13 @@ */ void create() { + if (vst) + { + // this is quite fatal, NO-ERROR will not prevent it from stopping the procedure + ErrorManager.throwError(6248, + "Creating records in a Virtual System Table is not allowed", null, false); + } + initialize(); Long recId = null; @@ -10851,6 +10885,7 @@ this.undoable.checkUndoable(true); } this.currentRecord = newCrtRecord; + this.isTouched = false; // invalidate CURRENT-CHANGED flag. it will be re-set at the end of // armCurrentChanged/updateCurrentChanged bracketing if the case @@ -10867,6 +10902,7 @@ } this.currentRecord = newCrtRecord; this.recordChanged = false; // invalidate CURRENT-CHANGED flag (see above) + this.isTouched = false; this.newlyCreated = newlyCreated; this.dirtyCopy = dirtyCopy; @@ -11861,6 +11897,8 @@ detectChange(null, property, getter, (BaseDataType) args[0], changeCodes); } + isTouched = true; + changed = changeCodes[0]; processChange = changeCodes[1] && !batchAssign; === added file 'src/com/goldencode/p2j/ui/client/EaseAccessManager.java' --- src/com/goldencode/p2j/ui/client/EaseAccessManager.java 1970-01-01 00:00:00 +0000 +++ src/com/goldencode/p2j/ui/client/EaseAccessManager.java 2019-01-30 21:06:50 +0000 @@ -0,0 +1,144 @@ +/* +** Module : EaseAccessManager.java +** Abstract : Defines the ease access functionality. +** +** Copyright (c) 2019, Golden Code Development Corporation. +** +** -#- -I- --Date-- ---------------------------------Description--------------------------------- +** 001 SBI 20190129 Defines the ease access functionality. +*/ + +/* +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU Affero General Public License as +** published by the Free Software Foundation, either version 3 of the +** License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Affero General Public License for more details. +** +** You may find a copy of the GNU Affero GPL version 3 at the following +** location: https://www.gnu.org/licenses/agpl-3.0.en.html +** +** Additional terms under GNU Affero GPL version 3 section 7: +** +** Under Section 7 of the GNU Affero GPL version 3, the following additional +** terms apply to the works covered under the License. These additional terms +** are non-permissive additional terms allowed under Section 7 of the GNU +** Affero GPL version 3 and may not be removed by you. +** +** 0. Attribution Requirement. +** +** You must preserve all legal notices or author attributions in the covered +** work or Appropriate Legal Notices displayed by works containing the covered +** work. You may not remove from the covered work any author or developer +** credit already included within the covered work. +** +** 1. No License To Use Trademarks. +** +** This license does not grant any license or rights to use the trademarks +** Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks +** of Golden Code Development Corporation. You are not authorized to use the +** name Golden Code, FWD, or the names of any author or contributor, for +** publicity purposes without written authorization. +** +** 2. No Misrepresentation of Affiliation. +** +** You may not represent yourself as Golden Code Development Corporation or FWD. +** +** You may not represent yourself for publicity purposes as associated with +** Golden Code Development Corporation, FWD, or any author or contributor to +** the covered work, without written authorization. +** +** 3. No Misrepresentation of Source or Origin. +** +** You may not represent the covered work as solely your work. All modified +** versions of the covered work must be marked in a reasonable way to make it +** clear that the modified work is not originating from Golden Code Development +** Corporation or FWD. All modified versions must contain the notices of +** attribution required in this license. +*/ + +package com.goldencode.p2j.ui.client; + +import java.util.*; + +import com.goldencode.p2j.directory.*; +import com.goldencode.p2j.security.*; + +/** + * Defines the ease access functionality. + * + */ +public class EaseAccessManager +{ + /** + * The manager instance container. + */ + private static final ContextLocal instance = new ContextLocal<>(); + + /** + * The directory exported API + */ + private final Directory directory; + + /** + * The cached value of "clientConfig/underline-keyboard-shortcuts". + */ + private final boolean underlineShortcuts; + /** + * Creates the instance of this class. + * + * @param directory + * The directory exported API + */ + private EaseAccessManager(Directory directory) + { + this.directory = directory; + + underlineShortcuts = directory.getBoolean(Directory.ID_RELATIVE, + "clientConfig/underline-keyboard-shortcuts", + true); + } + + /** + * Creates and initializes this singleton instance. + * + * @param directory + * The directory exported API + */ + public static synchronized void init(Directory directory) + { + EaseAccessManager eam = instance.get(); + + if (eam == null) + { + eam = new EaseAccessManager(directory); + instance.set(eam); + } + } + + /** + * Gets the ease access manager if it has been initialized. + * + * @return The EaseAccessManager instance if it has been initialized. + */ + public static Optional getInstance() + { + return Optional.of(instance.get()); + } + + /** + * Retrieves the cached value of the "Underline keyboard shortcuts and access keys" property + * defined by this directory path "clientConfig/underline-keyboard-shortcuts". The default + * value is to underline keyboard shortcuts and access keys. + * + * @return The boolean value at this directory path "clientConfig/underline-keyboard-shortcuts". + */ + public boolean isUnderlineKeyboardShortcutsAndAccessKeys() + { + return underlineShortcuts; + } +} === modified file 'src/com/goldencode/p2j/ui/client/gui/ButtonGuiImpl.java' --- src/com/goldencode/p2j/ui/client/gui/ButtonGuiImpl.java 2018-11-14 22:19:54 +0000 +++ src/com/goldencode/p2j/ui/client/gui/ButtonGuiImpl.java 2019-01-30 20:37:44 +0000 @@ -83,6 +83,9 @@ ** with valid non-zero offset. The loaded UP image changes effective client ** button size if it was not already set. Making the image insets within button ** to be theme dependent. +** 045 SBI 20190130 Changed isMenemonicSupported() in order to check if EaseAccessManager is +** available and "to underline shortcuts" is disabled, the default value is +** true (enabled). */ /* @@ -143,6 +146,7 @@ // this usage of AWT events is intentional, they are being used separately from the // AWT/Swing event model itself; no other AWT/Swing usage is occurring in this class import java.awt.event.MouseEvent; +import java.util.*; import com.goldencode.p2j.ui.*; import com.goldencode.p2j.ui.chui.*; @@ -1121,6 +1125,13 @@ */ public boolean isMnemonicSupported() { + Optional easeAccessManager = EaseAccessManager.getInstance(); + + if (easeAccessManager.isPresent()) + { + return easeAccessManager.get().isUnderlineKeyboardShortcutsAndAccessKeys(); + } + return true; } === modified file 'src/com/goldencode/p2j/ui/client/gui/FillInGuiImpl.java' --- src/com/goldencode/p2j/ui/client/gui/FillInGuiImpl.java 2019-01-11 14:34:18 +0000 +++ src/com/goldencode/p2j/ui/client/gui/FillInGuiImpl.java 2019-01-31 01:21:25 +0000 @@ -112,6 +112,9 @@ ** classes code. ** 070 SBI 20190111 Changed isUnitialized() to redraw fillin if its variable is set but its ** configuration state is UNINITIALIZED. +** 071 EVL 20190130 Fix for inconsistent screen/buffer values for GUI fill-in. When the ENTRY +** event is coming from server the modified flag should be set to TRUE to sync +** valid screen buffer value between client and server sides. */ /* @@ -944,6 +947,13 @@ parentCont.paintOnTop(getId()); } } + // this event came from server side business logic + // GUI fill-in must be set as modified to keep valid screen buffer value + else if (ke.id() == EventType.KEY_TYPED) + { + ConfigHelper.setModified(config, true); + } + return; } === modified file 'src/com/goldencode/p2j/ui/client/gui/TextGuiImpl.java' --- src/com/goldencode/p2j/ui/client/gui/TextGuiImpl.java 2019-01-11 00:26:02 +0000 +++ src/com/goldencode/p2j/ui/client/gui/TextGuiImpl.java 2019-01-30 03:39:46 +0000 @@ -28,6 +28,9 @@ ** 016 CA 20180521 Added mouse events to allow mouse triggers. ** 017 OM 20180912 Improved Theme support. ** 018 EVL 20190110 Fixed the text drawing in tab usage. +** 019 EVL 20190129 Fixed the text drawing regressions from previous change. Almost complete +** undo except three additional pixels to compensate rounding error and text +** antialiasing. */ /* @@ -212,8 +215,9 @@ NativePoint p = physicalLocation(); NativeDimension dim = physicalDimension(); - // sometimes clipping rectangle need to be set to all visible part of the text - int clipWidth = Math.max(nativeWidth(true), dim.width); + // adding one pixel more width to compensate text rounding error and another two pixels + // more to compensate possible web client text smooth + int clipWidth = dim.width + 3; NativeRectangle clip = clipRectangle(p, new NativeDimension(clipWidth, dim.height)); gd.draw(getId(), p, clip, () -> === modified file 'src/com/goldencode/p2j/ui/client/gui/driver/AbstractGuiDriver.java' --- src/com/goldencode/p2j/ui/client/gui/driver/AbstractGuiDriver.java 2018-11-21 02:52:42 +0000 +++ src/com/goldencode/p2j/ui/client/gui/driver/AbstractGuiDriver.java 2019-01-29 10:29:11 +0000 @@ -99,6 +99,8 @@ ** 045 OM 20181001 Tracked document output using an UUID. ** 046 SBI 20181019 Changed drawStringWithMnemonic to use PaintPrimitives.TEXT_SHIFT. ** 047 EVL 20181116 Separating direct manipulation handler to provide Web driver specifics. +** 048 SBI 20190129 Added drawStringWithinBox, drawStringWithinBoxWithMnemonic and +** drawStringWithinBoxScaled. */ /* @@ -851,7 +853,193 @@ translatePop(); } - + + /** + * Draw a string with a mnemonic within a given box. + * + * @param text + * The full text, which needs to be drawn. + * @param xPosition + * The box horizontal position + * @param yPosition + * The box vertical position + * @param boxWidth + * The box width + * @param boxHeight + * The box height + * @param info + * The mnemonic details. + * @param gf + * The widget's font details. + * @param widget + * The widget instance to which the text belongs. + * @param centered + * Flag indicating if the text needs to be centered vertically. + */ + @Override + public void drawStringWithinBoxWithMnemonic(String text, + int xPosition, + int yPosition, + int boxWidth, + int boxHeight, + MnemonicInfo info, + GuiFontResolver gf, + AbstractWidget widget, + boolean centered) + { + FontCache fc = gf.font(); + + Integer ampIdx = info.getMnemIdx(); + + if (ampIdx > 0) + { + drawStringWithinBox(xPosition, + yPosition, + boxWidth, + boxHeight, + text, + new int[] {0, ampIdx}, + centered); + } + + // set temporarily underlined font + setFontStyle(FontStyle.createStyle(fc.font.style.isBold(), fc.font.style.isItalic(), true)); + + drawStringWithinBox(xPosition, + yPosition, + boxWidth, + boxHeight, + text, + new int[] {ampIdx, ampIdx + 1}, + centered); + + setGuiFont((FontDetails) fc.font); + setFontStyle(fc.font.style); + + if (text.length() > (ampIdx + 1)) + { + drawStringWithinBox(xPosition, + yPosition, + boxWidth, + boxHeight, + text, + new int[] {ampIdx + 1, text.length()}, + centered); + } + } + + /** + * Draw a given text within a box given by its relative coordinates. + * + * @param xPosition + * The box horizontal position + * @param yPosition + * The box vertical position + * @param boxWidth + * The box width + * @param boxHeight + * The box height + * @param text + * The given text + * @param indices + * Represents a text segment within the given text that should be drawn; if it isn't + * given, then all given text should be drawn + * @param centered + * Flag indicating if the text needs to be centered vertically. + */ + @Override + public void drawStringWithinBox(int xPosition, + int yPosition, + int boxWidth, + int boxHeight, + String text, + int[] indices, + boolean centered) + { + PaintStructure ps = new PaintStructure(PaintPrimitives.DRAW_STRING_WITHIN_BOX); + + drawStringWithinBox(ps, xPosition, yPosition, boxWidth, boxHeight, text, indices, centered); + } + + /** + * Draw a given text within a box given by its relative coordinates. + * + * @param xPosition + * The box horizontal position + * @param yPosition + * The box vertical position + * @param boxWidth + * The box width + * @param boxHeight + * The box height + * @param text + * The given text + * @param indices + * Represents a text segment within the given text that should be drawn; if it isn't + * given, then all given text should be drawn + * @param centered + * Flag indicating if the text needs to be centered vertically. + */ + @Override + public void drawStringWithinBoxScaled(int xPosition, + int yPosition, + int boxWidth, + int boxHeight, + String text, + int[] indices, + boolean centered) + { + PaintStructure ps = new PaintStructure(PaintPrimitives.DRAW_STRING_WITHIN_BOX_SCALED); + + drawStringWithinBox(ps, xPosition, yPosition, boxWidth, boxHeight, text, indices, centered); + } + + /** + * Fill and enqueue a given paint structure for drawing a given text within a box. + * + * @param ps + * The paint structure + * @param xPosition + * The box horizontal position + * @param yPosition + * The box vertical position + * @param boxWidth + * The box width + * @param boxHeight + * The box height + * @param text + * The given text + * @param indices + * Represents a text segment within the given text that should be drawn; if it isn't + * given, then all given text should be drawn + * @param centered + * Flag indicating if the text needs to be centered vertically. + */ + private void drawStringWithinBox(PaintStructure ps, + int xPosition, + int yPosition, + int boxWidth, + int boxHeight, + String text, + int[] indices, + boolean centered) + { + ps.x = xPosition; + ps.y = yPosition; + ps.width = boxWidth; + ps.height = boxHeight; + ps.text = text; + if (indices != null && indices.length > 0) + { + ps.nPoints = indices.length; + ps.xPoints = indices; + } + + ps.centered = centered; + + ews.offer(ps); + } + /** * Draw a string at the specified location. * === modified file 'src/com/goldencode/p2j/ui/client/gui/driver/GuiDriver.java' --- src/com/goldencode/p2j/ui/client/gui/driver/GuiDriver.java 2018-10-02 18:24:05 +0000 +++ src/com/goldencode/p2j/ui/client/gui/driver/GuiDriver.java 2019-01-29 10:29:11 +0000 @@ -114,6 +114,8 @@ ** 065 EVL 20180824 Adding method to draw I-Beam cursor for text fields. ** 066 OM 20180906 Added getBasicWebPalette() for querying the custom palette from a web page. ** 067 OM 20181001 Tracked document output using an UUID. +** 068 SBI 20190129 Added drawStringWithinBox, drawStringWithinBoxWithMnemonic and +** drawStringWithinBoxScaled. */ /* @@ -246,6 +248,92 @@ boolean centered); /** + * Draw a string with a mnemonic within the given box. + * + * @param text + * The full text, which needs to be drawn. + * @param xPosition + * The box horizontal position + * @param yPosition + * The box vertical position + * @param boxWidth + * The box width + * @param boxHeight + * The box height + * @param info + * The mnemonic details. + * @param gf + * The widget's font details. + * @param widget + * The widget instance to which the text belongs. + * @param centered + * Flag indicating if the text needs to be centered vertically. + */ + public void drawStringWithinBoxWithMnemonic(String text, + int xPosition, + int yPosition, + int boxWidth, + int boxHeight, + MnemonicInfo info, + GuiFontResolver gf, + AbstractWidget widget, + boolean centered); + + /** + * Draw a given text within a box given by its relative coordinates. + * + * @param xPosition + * The box horizontal position + * @param yPosition + * The box vertical position + * @param boxWidth + * The box width + * @param boxHeight + * The box height + * @param text + * The given text + * @param indices + * Represents a text segment within the given text that should be drawn; if it isn't + * given, then all given text should be drawn + * @param centered + * Flag indicating if the text needs to be centered vertically. + */ + public void drawStringWithinBox(int xPosition, + int yPosition, + int boxWidth, + int boxHeight, + String text, + int[] indices, + boolean centered); + + /** + * Draw a given text within a box given by its relative coordinates. + * + * @param xPosition + * The box horizontal position + * @param yPosition + * The box vertical position + * @param boxWidth + * The box width + * @param boxHeight + * The box height + * @param text + * The given text + * @param indices + * Represents a text segment within the given text that should be drawn; if it isn't + * given, then all given text should be drawn + * @param centered + * Flag indicating if the text needs to be centered vertically. + */ + public void drawStringWithinBoxScaled(int xPadding, + int yPadding, + int boxWidth, + int boxHeight, + String text, + int[] indices, + boolean centered); + + /** * Draw a string at the specified location. * * @param text === modified file 'src/com/goldencode/p2j/ui/client/gui/driver/PaintPrimitives.java' --- src/com/goldencode/p2j/ui/client/gui/driver/PaintPrimitives.java 2018-11-21 02:52:42 +0000 +++ src/com/goldencode/p2j/ui/client/gui/driver/PaintPrimitives.java 2019-01-29 10:29:11 +0000 @@ -35,6 +35,7 @@ ** 019 OM 20180815 Added support for drawing ellipse primitives. ** 020 EVL 20180824 Adding support for drawing I-Beam cursor in text fields. ** 021 EVL 20181119 Adding direct manipulation start operation to be used in Web client JS. +** 022 SBI 20190129 Added DRAW_STRING_WITHIN_BOX and DRAW_STRING_WITHIN_BOX_SCALED. */ /* @@ -158,5 +159,7 @@ DRAW_ELLIPSE, FILL_ELLIPSE, DRAW_IBEAM, - START_DIRECT_MANIPULATION + START_DIRECT_MANIPULATION, + DRAW_STRING_WITHIN_BOX, + DRAW_STRING_WITHIN_BOX_SCALED, } === modified file 'src/com/goldencode/p2j/ui/client/gui/driver/swing/SwingEmulatedWindow.java' --- src/com/goldencode/p2j/ui/client/gui/driver/swing/SwingEmulatedWindow.java 2018-08-28 01:06:13 +0000 +++ src/com/goldencode/p2j/ui/client/gui/driver/swing/SwingEmulatedWindow.java 2019-01-30 10:23:02 +0000 @@ -134,6 +134,7 @@ ** via the business logic, we must wait for Swing to process the window activated ** event and process the activation after this. ** EVL 20180824 Adding support for drawing I-Beam cursor in text fields. +** 063 SBI 20190129 Added DRAW_STRING_WITHIN_BOX and DRAW_STRING_WITHIN_BOX_SCALED primitives. */ /* @@ -1115,6 +1116,56 @@ drawStringScaled(ps, g2); break; + case DRAW_STRING_WITHIN_BOX_SCALED: + case DRAW_STRING_WITHIN_BOX: + int[] indices = ps.xPoints; + + String text = ps.text; + + int textLength = text.length(); + + int numberIndices = ps.nPoints; + + if (numberIndices == 0) + { + indices = new int [] {0, textLength}; + numberIndices = 2; + } + FontMetrics fm = g2.getFontMetrics(); + + int nativeWidth = fm.stringWidth(text); + + int x = ps.x + (ps.width - nativeWidth) /2; + + for (int k = 0; k < numberIndices / 2; k++) + { + int delta; + + ps.text = text.substring(indices[k], indices[k+1]); + + if (indices[k] != 0) + { + delta = fm.stringWidth(text.substring(0, indices[k])); + } + else + { + delta = 0; + } + + ps.x = x + delta; + + if (ps.id == PaintPrimitives.DRAW_STRING_WITHIN_BOX) + { + drawString(ps, g2); + } + else + { + drawStringScaled(ps, g2); + } + } + + break; + case DRAW_PARAGRAPH: layoutParagraphWorker(g2, ps.text, ps.font, ps.width, true, ps.x, ps.y); break; @@ -1701,6 +1752,26 @@ } /** + * Draw a string using the current font. + * + * @param ps + * The structure with the drawing details. + * @param g2 + * Graphic context for operation + */ + private void drawTextWithinBoxCentered(PaintStructure ps, Graphics2D g2) + { + int y = ps.y; + if (ps.centered) + { + FontMetrics fm = g2.getFontMetrics(); + y = ps.y + fm.getAscent() / 2; + } + + g2.drawString(ps.text, ps.x, y); + } + + /** * The method performs a layout operation on the supplied text and returns the resulting * paragraph height while maintaining the supplied maximum width. *

=== modified file 'src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebEmulatedWindow.java' --- src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebEmulatedWindow.java 2018-10-19 22:00:50 +0000 +++ src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebEmulatedWindow.java 2019-01-29 00:27:55 +0000 @@ -458,6 +458,24 @@ case FILL_RECT_AROUND_TEXT: websock.fillRectAroundText(ps.x, ps.y, ps.width, ps.height, ps.text); break; + case DRAW_STRING_WITHIN_BOX: + websock.drawStringWithinBox(ps.x, + ps.y, + ps.width, + ps.height, + ps.text, + ps.xPoints, + ps.centered); + break; + case DRAW_STRING_WITHIN_BOX_SCALED: + websock.drawStringWithinBoxScaled(ps.x, + ps.y, + ps.width, + ps.height, + ps.text, + ps.xPoints, + ps.centered); + break; case FILL_ROUND_RECT: websock.fillRoundRect(ps.x, ps.y, ps.width, ps.height, ps.arcDiameter); break; === modified file 'src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebSocket.java' --- src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebSocket.java 2019-01-16 01:08:49 +0000 +++ src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebSocket.java 2019-01-29 00:27:55 +0000 @@ -759,13 +759,113 @@ writeMessageInt32(message, 1, x); writeMessageInt32(message, 5, y); - writeMessageInt32(message, 9, textHeightHint); + writeMessageInt32(message, 9, textWidthHint); writeMessageInt32(message, 13, textHeightHint); writeMessageInt32(message, 17, textLength); writeMessageText(message, 21, text); } /** + * Draw a given text within a box given by its relative coordinates. + * + * @param xPosition + * The box horizontal position + * @param yPosition + * The box vertical position + * @param boxWidth + * The box width + * @param boxHeight + * The box height + * @param text + * The given text + * @param indices + * Represents a text segment within the given text that should be drawn; if it isn't + * given, then all given text should be drawn + * @param centered + * Flag indicating if the text needs to be centered vertically. + */ + public void drawStringWithinBox(int xPosition, + int yPosition, + int boxWidth, + int boxHeight, + String text, + int[] indices, + boolean centered) + { + int textLength = text.length(); + int numberIndices = indices != null ? indices.length : 0; + int idx = 2 * textLength + 29; + int msgLengthInBytes = idx + 4 * numberIndices; + + byte[] message = allocateDrawingOp(PaintPrimitives.DRAW_STRING_WITHIN_BOX, msgLengthInBytes); + + writeMessageInt32(message, 1, xPosition); + writeMessageInt32(message, 5, yPosition); + writeMessageInt32(message, 9, boxWidth); + writeMessageInt32(message, 13, boxHeight); + writeMessageInt32(message, 17, centered ? 1 : 0); + writeMessageInt32(message, 21, textLength); + writeMessageInt32(message, 25, numberIndices); + writeMessageText(message, 29, text); + + for (int i = 0; i < numberIndices; i++) + { + writeMessageInt32(message, idx, indices[i]); + idx += 4; + } + } + + /** + * Draw a given text within a box given by its relative coordinates. + * + * @param xPosition + * The box horizontal position + * @param yPosition + * The box vertical position + * @param boxWidth + * The box width + * @param boxHeight + * The box height + * @param text + * The given text + * @param indices + * Represents a text segment within the given text that should be drawn; if it isn't + * given, then all given text should be drawn + * @param centered + * Flag indicating if the text needs to be centered vertically. + */ + public void drawStringWithinBoxScaled(int xPosition, + int yPosition, + int boxWidth, + int boxHeight, + String text, + int[] indices, + boolean centered) + { + int textLength = text.length(); + int numberIndices = indices != null ? indices.length : 0; + int idx = 2 * textLength + 29; + int msgLengthInBytes = idx + 4 * numberIndices; + + byte[] message = allocateDrawingOp(PaintPrimitives.DRAW_STRING_WITHIN_BOX_SCALED, msgLengthInBytes); + + writeMessageInt32(message, 1, xPosition); + writeMessageInt32(message, 5, yPosition); + writeMessageInt32(message, 9, boxWidth); + writeMessageInt32(message, 13, boxHeight); + writeMessageInt32(message, 17, centered ? 1 : 0); + writeMessageInt32(message, 21, textLength); + writeMessageInt32(message, 25, numberIndices); + writeMessageText(message, 29, text); + + for (int i = 0; i < numberIndices; i++) + { + writeMessageInt32(message, idx, indices[i]); + idx += 4; + } + } + + /** * Draw a rounded stroked rectangle in the current color/stroke. * * @param x === modified file 'src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.screen.js' --- src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.screen.js 2018-11-22 22:51:34 +0000 +++ src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.screen.js 2019-01-29 10:29:11 +0000 @@ -94,6 +94,7 @@ ** trips to the Java side until operation completes. Fixed the bug in cancelDrag ** implementation. We need to clean dragTimeout when it is not null, meaning ** there is pending code waiting to be called we need to cancel. +** 039 SBI 20190129 Added DRAW_STRING_WITHIN_BOX and DRAW_STRING_WITHIN_BOX_SCALED primitives. */ /* @@ -235,7 +236,9 @@ DRAW_ELLIPSE : 46, FILL_ELLIPSE : 47, DRAW_IBEAM : 48, - START_DIRECT_MANIPULATION : 49 + START_DIRECT_MANIPULATION : 49, + DRAW_STRING_WITHIN_BOX : 50, + DRAW_STRING_WITHIN_BOX_SCALED : 51 }; /* map cursor id to name */ @@ -2031,6 +2034,79 @@ "; centered = " + centered + "; lwidth = " + lwidth + "; lheight = " + lheight; break; + case ops.DRAW_STRING_WITHIN_BOX: + case ops.DRAW_STRING_WITHIN_BOX_SCALED: + offset = 1; + + var xPosition = p2j.socket.readInt32BinaryMessage(message, idx + 1); + + var yPosition = p2j.socket.readInt32BinaryMessage(message, idx + 5); + + width = p2j.socket.readInt32BinaryMessage(message, idx + 9); + + height = p2j.socket.readInt32BinaryMessage(message, idx + 13); + + centered = (p2j.socket.readInt32BinaryMessage(message, idx + 17) == 1); + + textLength = p2j.socket.readInt32BinaryMessage(message, idx + 21); + + var numberIndices = p2j.socket.readInt32BinaryMessage(message, idx + 25); + + text = p2j.socket.readStringBinaryMessageByLength(message, idx + 29, textLength); + + offset = 29 + 2 * textLength; + + var indices = []; + + for (var j = 0; j < numberIndices; j++) + { + indices[j] = p2j.socket.readInt32BinaryMessage(message, idx + offset); + offset += 4; + } + + if (numberIndices == 0) + { + indices[0] = 0; + indices[1] = textLength; + numberIndices = 2; + } + var nativeWidth = p2j.fonts.getTextWidth(currentFont, text); + + x = xPosition + (width - nativeWidth)/2; + y = yPosition; + for (var k = 0; k < numberIndices / 2; k++) + { + var delta; + + if (indices[k] != 0) + { + delta = p2j.fonts.getTextWidth(currentFont, text.substring(0, indices[k])); + } + else + { + delta = 0; + } + if (type == ops.DRAW_STRING_WITHIN_BOX) + { + this.canvasRenderer.drawText(text.substring(indices[k], indices[k+1]), + x + delta, + y, + centered); + } + else + { + this.canvasRenderer.drawScaledText(currentFont, + text.substring(indices[k], indices[k+1]), + x + delta, + y, + centered, + width, + height); + } + + } + + break; case ops.DRAW_PARAGRAPH: offset = 1; === modified file 'src/com/goldencode/p2j/ui/client/gui/theme/ClassicTheme.java' --- src/com/goldencode/p2j/ui/client/gui/theme/ClassicTheme.java 2019-01-10 03:36:22 +0000 +++ src/com/goldencode/p2j/ui/client/gui/theme/ClassicTheme.java 2019-01-29 10:29:11 +0000 @@ -47,6 +47,7 @@ ** 028 HC 20181124 Implemented TREEVIEW widget and related changes. ** 029 HC 20181228 Various draw fixes - connected dots, node icon of the expanded node. ** 030 EVL 20190109 Adding fix for label clipping in some conditions. +** 031 SBI 20190129 Changed drawButtonInternal to calculate label's offsets on GUI driver side. */ /* @@ -1263,9 +1264,10 @@ gd.setGuiFont(fnt); int fontNum = gf.resolveFontNum(); int fontHeight = FontManager.getFontHeight(WindowManager.resolveWindow(button), fontNum, gd); - int xt = orig.x + (dim.width - button.getTextWidthNative(label, fontNum)) / 2; + // do not simplify the line below, this makes the font height to be up nearest even number int yt = orig.y + (dim.height + fontHeight + 1)/2 - 3; + gd.setFontStyle(fnt.style); // enabled state controls text drawing if (button.isEnabled()) @@ -1273,27 +1275,34 @@ gd.setColor(gc.fgColor); if (pressed) { - gd.drawString(label, xt + 1, yt + 1); + gd.drawStringWithinBox(orig.x + 1, yt + 1, dim.width, dim.height, label, null, false); } else { if (labelInfo != null && labelInfo.getMnemIdx() != null) { - NativePoint tp = new NativePoint(xt, yt); - gd.drawStringWithMnemonic(label, tp, labelInfo, gf, button, false); + gd.drawStringWithinBoxWithMnemonic(label, + orig.x, + yt, + dim.width, + dim.height, + labelInfo, + gf, + button, + false); } else { - gd.drawString(label, xt, yt); + gd.drawStringWithinBox(orig.x, yt, dim.width, dim.height, label, null, false); } } } else { gd.setColor(lightShadow); - gd.drawString(label, xt + 1, yt + 1); + gd.drawStringWithinBox(orig.x + 1, yt + 1, dim.width, dim.height, label, null, false); gd.setColor(darkShadow); - gd.drawString(label, xt, yt); + gd.drawStringWithinBox(orig.x, yt, dim.width, dim.height, label, null, false); } // draw dotted rectangle around focused button text === modified file 'src/com/goldencode/p2j/ui/client/gui/theme/MaterialTheme.java' --- src/com/goldencode/p2j/ui/client/gui/theme/MaterialTheme.java 2018-10-04 17:04:18 +0000 +++ src/com/goldencode/p2j/ui/client/gui/theme/MaterialTheme.java 2019-01-29 10:29:11 +0000 @@ -9,7 +9,8 @@ ** 002 OM 20180905 Added configuration support from the web page. ** SVL 20180930 Row and column separators can be drawn independently. ** 003 OM 20181004 Minor fixes. - */ + ** 004 SBI 20190129 Changed drawButton to calculate label's offsets on GUI driver side. +*/ /* ** This program is free software: you can redistribute it and/or modify @@ -426,7 +427,7 @@ // do not simplify the line below, this makes the font height to be up nearest even number int tY = y + (height - 1) / 2; - int tX = x + (width - button.getTextWidthNative(label, fontNum)) / 2; + gd.setFontStyle(fnt.style); Color fillBackground = null; // by default background is not filled @@ -529,13 +530,20 @@ if (labelInfo != null && labelInfo.getMnemIdx() != null) { - NativePoint tp = new NativePoint(tX, tY); - gd.drawStringWithMnemonic(label, tp, labelInfo, gf, button, true); + gd.drawStringWithinBoxWithMnemonic(label, + x, + tY, + width, + height, + labelInfo, + gf, + button, + true); } else { // no mnemonic available - gd.drawStringCentered(label, tX, tY); + gd.drawStringWithinBox(x, tY, width, height, label, null, true); } } } === modified file 'src/com/goldencode/p2j/ui/client/gui/theme/Windows10Theme.java' --- src/com/goldencode/p2j/ui/client/gui/theme/Windows10Theme.java 2018-09-30 12:31:23 +0000 +++ src/com/goldencode/p2j/ui/client/gui/theme/Windows10Theme.java 2019-01-29 10:29:11 +0000 @@ -33,6 +33,7 @@ ** 020 EVL 20180822 Fix for regression caused by previous button feedback fix. ** SVL 20180901 Support for enhanced sorting. Row and column separators can be drawn ** independently. +** 021 SBI 20190129 Changed drawButton to calculate label's offsets on GUI driver side. */ /* @@ -1022,13 +1023,18 @@ // draw button text FontDetails fnt = gf.font().font; + gd.setGuiFont(fnt); + int fontNum = gf.resolveFontNum(); + MnemonicInfo labelInfo = button.getMnemonic(); + String label = (labelInfo == null) ? button.textLabel() : labelInfo.getPrepLabel(); + // do not simplify the line below, this makes the font height to be up nearest even number int tY = y + (height - 1) / 2; - int tX = x + (width - button.getTextWidthNative(label, fontNum)) / 2; + gd.setFontStyle(fnt.style); if (!button.isEnabled()) // disabled button @@ -1130,13 +1136,20 @@ } if (labelInfo != null && labelInfo.getMnemIdx() != null) { - NativePoint tp = new NativePoint(tX, tY); - gd.drawStringWithMnemonic(label, tp, labelInfo, gf, button, true); + gd.drawStringWithinBoxWithMnemonic(label, + x, + tY, + width, + height, + labelInfo, + gf, + button, + true); } else { // no mnemonic available - gd.drawStringCentered(label, tX, tY); + gd.drawStringWithinBox(x, tY, width, height, label, null, true); } } === modified file 'src/com/goldencode/p2j/ui/client/gui/theme/Windows8Theme.java' --- src/com/goldencode/p2j/ui/client/gui/theme/Windows8Theme.java 2018-11-15 20:57:53 +0000 +++ src/com/goldencode/p2j/ui/client/gui/theme/Windows8Theme.java 2019-01-29 10:29:11 +0000 @@ -20,6 +20,7 @@ ** when the mouse is not over widget. ** 013 EVL 20180822 Fix for regression caused by previous button feedback fix. ** 014 EVL 20181113 Small change for regular button border color and some related changes. +** 015 SBI 20190129 Changed drawButton to calculate label's offsets on GUI driver side. */ /* @@ -867,7 +868,7 @@ // do not simplify the line below, this makes the font height to be up nearest even number int tY = y + (height - 1) / 2; - int tX = x + (width - button.getTextWidthNative(label, fontNum)) / 2; + gd.setFontStyle(fnt.style); if (!button.isEnabled()) // disabled button @@ -962,15 +963,15 @@ { gd.setColor(new Color(0x848284)); // disabled text, not in palette ? } + if (labelInfo != null && labelInfo.getMnemIdx() != null) { - NativePoint tp = new NativePoint(tX, tY); - gd.drawStringWithMnemonic(label, tp, labelInfo, gf, button, true); + gd.drawStringWithinBoxWithMnemonic(label, x, tY, width, height, labelInfo, gf, button, true); } else { // no mnemonic available - gd.drawStringCentered(label, tX, tY); + gd.drawStringWithinBox(x, tY, width, height, label, null, true); } } === modified file 'src/com/goldencode/p2j/util/SharedVariableManager.java' --- src/com/goldencode/p2j/util/SharedVariableManager.java 2018-01-02 19:25:57 +0000 +++ src/com/goldencode/p2j/util/SharedVariableManager.java 2019-01-28 18:54:56 +0000 @@ -2,7 +2,7 @@ ** Module : SharedVariableManager.java ** Abstract : provides context-local scoped resource pools. ** -** Copyright (c) 2004-2018, Golden Code Development Corporation. +** Copyright (c) 2004-2019, Golden Code Development Corporation. ** ** -#- -I- --Date-- --JPRM-- ----------------------------Description---------------------------- ** 001 GES 20050729 @21924 Provides context-local scoped variable and stream pools. @@ -76,6 +76,9 @@ ** this-procedure and if not found, go back in the stack and look in ** each procedure's state. ** 027 GES 20180102 Changed a comment. +** 028 EVL 20190128 Changed the approach to keep NO-UNDO option and check the variable +** against it. Now all variables are storing in no-undo map with true +** or false value for option. */ /* @@ -515,11 +518,8 @@ addWorker(sr, scope, name, var); - if (noUndo) - { - // save this variable as NO-UNDO - addWorker(vr.noUndoVars, scope, name, var); - } + // the no-undo map now keeps the option value for every variable + addWorker(vr.noUndoVars, scope, name, noUndo); if (extent) { @@ -1838,7 +1838,8 @@ SharedRegistry noUndoWa = v.noUndoVars; Object sharedNoUndoVar = noUndoWa.shared.lookupSymbol(name); - boolean sharedNoUndo = (sharedNoUndoVar != null); + boolean sharedNoUndo = (sharedNoUndoVar != null && + ((Boolean)sharedNoUndoVar).booleanValue()); if (sharedNoUndo != noUndo) {