Changeset 101


Ignore:
Timestamp:
07/14/13 23:20:04 (11 years ago)
Author:
psniegowski
Message:

HIGHLIGHTS:

  • improve tree side notes
  • improve GUI layout
  • add foldable list of occured events to EventControl?
  • improve automatic type conversion in proxy listeners
  • implement several Access functionalities as algorithms independent of Access type
  • introduce draft base classes for distributed experiments
  • automatically register dependant Java classes to FramsClass? registry
  • add testing prime experiment and configuration
  • simplify and improve task dispatching

CHANGELOG:
Improve task dispatching in RemoteTree?.

GUI no longer hangs on connection problems.

Make all dispatchers joinables.

Refactorize Thread dispatcher.

Remove Task and PeriodicTask?.

Use Java utilities in those situations.

Reworking tasks dispatching.

Fix bug in EventControl? listener dispatching.

Minor improvements.

Add testing configuration for ExternalProcess? in GUI.

More improvement to prime.

Support for USERREADONLY in GUI.

Add that flag to various params in Java classes.

Remove redundant register clauses from several FramsClassAnnotations?.

Automatically gather and register dependant classes.

Add configuration for prime.

Improve Simulator class.

Add prime.xml configuration.

Introduce draft Experiment and Simulator classes.

Add prime experiment tests.

Enclose typical map with listeners into SimpleUniqueList?.

Needfile works in GUI.

Improve needfile handling in Browser.

More improvement with NeedFile?.

Implementing needfile.

Update test.

Rename ChangeEvent? to TestChangeEvent?.

Automatic argument type search in RemoteTree? listeners.

MultiParamLoader? uses AccessProvider?. By default old implementation
enclosed in AccessStash? or Registry.

Minor changes.

Rename SourceInterface? to Source.

Also improve toString of File and ListSource?.

Remove unused SimpleSource? class.

Add clearing in HistoryControl?.

Show entries in table at EventControl?.

Improve EventControl?.

Add listeners registration to EventControl?.

Add foldable table to HistoryControl?.

Add control row to Procedure and Event controls.

Improve layout of controls.

Another minor change to gui layout.

Minor improvement in the SliderControl?.

Minor changes.

Move ReflectionAccess?.Backend to separate file.

It was to cluttered.

Cleanup in ReflectionAccess?.

Move setMin, setMax, setDef to AccessOperations?.

Extract loading operation into AccessOperations?.

Append Framsticks to name of UnsupportedOperationException?.

The java.lang.UnsupportedOperationException? was shadowing this class.

Rename params.Util to params.ParamsUtil?.

Several improvements.

Minor changes.

Implement revert functionality.

Improve local changes management.

Minor improvement.

Remove methods rendered superfluous after SideNoteKey? improvement.

Improve SideNoteKey?.

It is now generic type, so explicit type specification at
call site is no more needed.

Introduce SideNoteKey? interface.

Only Objects implementing that key may be used as side note keys.

Minor improvements.

Use strings instead of ValueControls? in several gui mappings.

Location:
java/main
Files:
35 added
20 deleted
87 edited

Legend:

Unmodified
Added
Removed
  • java/main/pom.xml

    r100 r101  
    1717        <properties>
    1818                <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    19                 <framsticks.config>/configs/framsticks.xml</framsticks.config>
     19                <framsticks.config>/framsticks.xml</framsticks.config>
    2020        </properties>
    2121
  • java/main/src/main/java/com/framsticks/communication/ClientSideManagedConnection.java

    r100 r101  
    33import com.framsticks.communication.queries.ApplicationRequest;
    44import com.framsticks.communication.queries.CallRequest;
     5import com.framsticks.communication.queries.NeedFile;
     6import com.framsticks.communication.queries.NeedFileAcceptor;
    57import com.framsticks.communication.queries.ProtocolRequest;
    68import com.framsticks.communication.queries.RegisterRequest;
     
    4345        private boolean isHandshakeDone = false;
    4446
     47        protected NeedFileAcceptor needFileAcceptor;
     48
     49        /**
     50         * @return the needFileAcceptor
     51         */
     52        public NeedFileAcceptor getNeedFileAcceptor() {
     53                return needFileAcceptor;
     54        }
     55
     56        /**
     57         * @param needFileAcceptor the needFileAcceptor to set
     58         */
     59        public void setNeedFileAcceptor(NeedFileAcceptor needFileAcceptor) {
     60                this.needFileAcceptor = needFileAcceptor;
     61        }
    4562
    4663        /**
     
    6481                protocolVersion = -1;
    6582        }
    66 
    67 
    6883
    6984        protected List<String> readFileContent() {
     
    116131        }
    117132
    118         private Map<Integer, SentQuery<?>> queryMap = new HashMap<>();
    119 
    120         private SentQuery<?> currentlySentQuery;
    121 
    122133        public void send(ProtocolRequest request, ClientSideResponseFuture callback) {
    123134                //TODO RunAt
     
    154165                sentQuery.dispatcher = dispatcher;
    155166
     167
    156168                senderThread.dispatch(new RunAt<Connection>(callback) {
    157169                        @Override
    158170                        protected void runAt() {
    159                                 Integer id;
    160                                 synchronized (ClientSideManagedConnection.this) {
    161 
    162                                         while (!(requestIdEnabled || currentlySentQuery == null)) {
    163                                                 try {
    164                                                         ClientSideManagedConnection.this.wait();
    165                                                 } catch (InterruptedException ignored) {
    166                                                         break;
    167                                                 }
    168                                         }
    169                                         if (requestIdEnabled) {
    170                                                 queryMap.put(nextQueryId, sentQuery);
    171                                                 id = nextQueryId++;
    172                                         } else {
    173                                                 currentlySentQuery = sentQuery;
    174                                                 id = null;
    175                                         }
    176                                 }
     171                                Integer id = sentQueries.put(null, sentQuery);
     172
    177173                                String command = sentQuery.request.getCommand();
    178174                                StringBuilder message = new StringBuilder();
     
    188184                                flushOut();
    189185                                log.debug("sending query: {}", out);
    190 
    191186                        }
    192187                });
    193                 /*
    194                 synchronized (this) {
    195                         log.debug("queueing query: {}", query);
    196                         queryQueue.offer(sentQuery);
    197                         notifyAll();
    198                 }
    199                  */
    200188        }
    201189
     
    204192                return "client connection " + address;
    205193        }
    206 
    207194
    208195        private void sendQueryVersion(final int version, final Future<Void> future) {
     
    229216        }
    230217
    231         private synchronized @Nonnull SentQuery<?> fetchQuery(@Nullable Integer id, boolean remove) {
    232                 try {
    233                         if (id == null) {
    234                                 if (requestIdEnabled) {
    235                                         throw new FramsticksException().msg("request_id is enabled and id is missing");
    236                                 }
    237                                 SentQuery<?> result = currentlySentQuery;
    238                                 if (remove) {
    239                                         currentlySentQuery = null;
    240                                         notifyAll();
    241                                 }
    242                                 return result;
    243                         }
    244 
    245                         if (!queryMap.containsKey(id)) {
    246                                 throw new FramsticksException().msg("id is unknown").arg("id", id);
    247                         }
    248 
    249                         SentQuery<?> result = queryMap.get(id);
    250                         if (remove) {
    251                                 queryMap.remove(id);
    252                         }
    253                         return result;
    254 
    255                 } catch (FramsticksException e) {
    256                         throw new FramsticksException().msg("failed to match response to sent query").cause(e);
    257                 }
    258         }
     218        protected class IdCollection<T> {
     219
     220
     221                protected final Map<Integer, T> map = new HashMap<>();
     222                protected T current;
     223
     224                public Integer put(Integer idProposition, T value) {
     225                        synchronized (ClientSideManagedConnection.this) {
     226                                while (!(requestIdEnabled || current == null)) {
     227                                        try {
     228                                                ClientSideManagedConnection.this.wait();
     229                                        } catch (InterruptedException ignored) {
     230                                                break;
     231                                        }
     232                                }
     233                                if (!requestIdEnabled) {
     234                                        current = value;
     235                                        return null;
     236                                }
     237                                if (idProposition == null) {
     238                                        idProposition = nextQueryId++;
     239                                }
     240                                map.put(idProposition, value);
     241                                return idProposition;
     242                        }
     243                }
     244
     245                public void clear(Integer id) {
     246                        if (requestIdEnabled) {
     247                                current = null;
     248                        } else {
     249                                map.remove(id);
     250                        }
     251                }
     252
     253                public @Nonnull T fetch(@Nullable Integer id, boolean remove) {
     254                        synchronized (ClientSideManagedConnection.this) {
     255                                try {
     256                                        if (id == null) {
     257                                                if (requestIdEnabled) {
     258                                                        throw new FramsticksException().msg("request_id is enabled and id is missing");
     259                                                }
     260                                                T result = current;
     261                                                current = null;
     262                                                ClientSideManagedConnection.this.notifyAll();
     263                                                return result;
     264                                        }
     265                                        if (!map.containsKey(id)) {
     266                                                throw new FramsticksException().msg("id is unknown").arg("id", id);
     267                                        }
     268
     269                                        T result = map.get(id);
     270                                        if (remove) {
     271                                                map.remove(id);
     272                                        }
     273                                        return result;
     274
     275                                } catch (FramsticksException e) {
     276                                        throw new FramsticksException().msg("failed to match response to sent query").cause(e);
     277                                }
     278                        }
     279                }
     280        }
     281
     282        protected IdCollection<SentQuery<?>> sentQueries = new IdCollection<>();
     283        protected IdCollection<NeedFile> needFiles = new IdCollection<>();
    259284
    260285        private int nextQueryId = 0;
     
    269294                        throw new FramsticksException().msg("expected file line").arg("got", fileLine);
    270295                }
    271                 String eventObjectPath = Request.takeGroup(rest, matcher, 1).toString();
    272                 String eventCalleePath = Request.takeGroup(rest, matcher, 2).toString();
     296                String eventObjectPath = Strings.takeGroup(rest, matcher, 1).toString();
     297                String eventCalleePath = Strings.takeGroup(rest, matcher, 2).toString();
    273298                final File file = new File("", new ListSource(readFileContent()));
    274299                log.debug("firing event {}", eventObjectPath);
     
    277302                        listener = registeredListeners.get(eventObjectPath);
    278303                }
    279                 if (listener  == null) {
     304                if (listener == null) {
    280305                        throw new FramsticksException().msg("failed to find registered event").arg("event path", eventObjectPath).arg("object", eventCalleePath);
    281306                }
     
    283308        }
    284309
     310        protected void processNeedFile(Pair<Integer, CharSequence> rest) {
     311                final Integer id = rest.first;
     312                String suggestedName = null;
     313                String description = null;
     314                Pair<CharSequence, CharSequence> s = Request.takeString(rest.second);
     315                if (s != null) {
     316                        suggestedName = s.first.toString();
     317                        Pair<CharSequence, CharSequence> d = Request.takeString(s.second);
     318                        if (d != null) {
     319                                description = d.first.toString();
     320                        }
     321                }
     322
     323                final Future<File> future = new Future<File>() {
     324
     325                        protected void send(final File result) {
     326                                log.info("sending file: " + result);
     327                                needFiles.clear(id);
     328                                sendFile(null, result, id, ClientSideManagedConnection.this);
     329
     330                        }
     331
     332                        @Override
     333                        protected void result(File result) {
     334                                send(result);
     335                        }
     336
     337                        @Override
     338                        public void handle(FramsticksException exception) {
     339                                send(new File("", ListSource.createFrom("# invalid", "# " + exception.getMessage())));
     340                        }
     341                };
     342
     343                NeedFile needFile = new NeedFile(suggestedName, description, future);
     344
     345                if (needFileAcceptor.acceptNeed(needFile)) {
     346                        return;
     347                }
     348
     349                future.handle(new FramsticksException().msg("acceptor did not accepted need"));
     350        }
     351
    285352        protected void processFile(Pair<Integer, CharSequence> rest) {
    286                 final SentQuery<?> sentQuery = fetchQuery(rest.first, false);
     353                final SentQuery<?> sentQuery = sentQueries.fetch(rest.first, false);
    287354
    288355                String currentFilePath = rest.second.toString();
     
    292359
    293360                sentQuery.files.add(new File(currentFilePath, new ListSource(readFileContent())));
    294 
    295361        }
    296362
     
    318384                        if (keyword.equals("ok") || keyword.equals("error")) {
    319385
    320                                 final SentQuery<?> sentQuery = fetchQuery(rest.first, true);
     386                                final SentQuery<?> sentQuery = sentQueries.fetch(rest.first, true);
    321387
    322388                                log.debug("parsing response for request {}", sentQuery);
    323389
    324390                                sentQuery.dispatchResponseProcess(new Response(command.first.equals("ok"), rest.second.toString(), sentQuery.getFiles()));
     391                                return;
     392                        }
     393                        if (keyword.equals("needfile")) {
     394                                processNeedFile(rest);
    325395                                return;
    326396                        }
     
    336406                @Override
    337407                public void handle(FramsticksException exception) {
    338                         interrupt();
     408                        interruptJoinable();
    339409                        // finish();
    340410                }
  • java/main/src/main/java/com/framsticks/communication/Connection.java

    r100 r101  
    11package com.framsticks.communication;
    22
     3import com.framsticks.params.Source;
    34import com.framsticks.params.annotations.AutoAppendAnnotation;
    45import com.framsticks.params.annotations.FramsClassAnnotation;
     
    6061                threads.add(senderThread);
    6162                threads.add(receiverThread);
    62 
    6363        }
    6464
     
    242242                        protected void runAt() {
    243243                                receiverThreadRoutine();
    244                                 interrupt();
    245                                 finish();
     244                                interruptJoinable();
     245                                finishJoinable();
    246246                        }
    247247                });
     
    251251        protected void joinableInterrupt() {
    252252                Dispatching.drop(threads, this);
    253                 finish();
     253                finishJoinable();
    254254        }
    255255
     
    331331
    332332
     333        protected static String idToString(Integer id) {
     334                return id != null ? " " + id.toString() : "";
     335        }
     336
     337        protected final void putFile(File file, Integer outId) {
     338                putLine("file" + idToString(outId)/* + " " + f.getPath()*/);
     339                Source content = file.getContent();
     340                String line;
     341                while ((line = content.readLine()) != null) {
     342                        putLine(line);
     343                }
     344                putLine("eof");
     345        }
     346
     347        public final void sendFile(final String header, final File file, final Integer id, ExceptionResultHandler handler) {
     348                senderThread.dispatch(new RunAt<Connection>(handler) {
     349                        @Override
     350                        protected void runAt() {
     351                                if (header != null) {
     352                                        putLine(header);
     353                                }
     354                                putFile(file, id);
     355                                flushOut();
     356                        }
     357                });
     358        }
     359
    333360}
  • java/main/src/main/java/com/framsticks/communication/File.java

    r96 r101  
    66import javax.annotation.Nonnull;
    77
    8 import com.framsticks.params.SourceInterface;
     8import com.framsticks.params.Source;
    99// import com.framsticks.util.lang.Strings;
     10import com.framsticks.util.lang.Strings;
    1011
    1112/**
     
    1415public final class File {
    1516        protected final String path;
    16         protected final SourceInterface content;
     17        protected final Source content;
    1718
    18         public File(@Nonnull String path, @Nonnull SourceInterface content) {
     19        public File(@Nonnull String path, @Nonnull Source content) {
    1920                // assert Strings.notEmpty(path);
    2021                this.path = path;
     
    2627        }
    2728
    28         public SourceInterface getContent() {
     29        public Source getContent() {
    2930                return content;
    3031        }
     
    3536                return result;
    3637        }
     38
     39        @Override
     40        public String toString() {
     41                StringBuilder b = new StringBuilder();
     42                if (Strings.notEmpty(path)) {
     43                        b.append(path).append(": ");
     44                }
     45                b.append(content.toString());
     46                return b.toString();
     47        }
     48
    3749}
  • java/main/src/main/java/com/framsticks/communication/Request.java

    r99 r101  
    77import com.framsticks.util.FramsticksException;
    88import com.framsticks.util.lang.Pair;
     9import com.framsticks.util.lang.Strings;
    910
    1011/**
     
    7879        }
    7980
    80         public static CharSequence takeGroup(CharSequence input, Matcher matcher, int group) {
    81                 // return (matcher.start(group) == matcher.end(group)) ? null : input.subSequence(matcher.start(group), matcher.end(group));
    82                 return input.subSequence(matcher.start(group), matcher.end(group));
    83         }
    8481
    8582        public static Pair<CharSequence, CharSequence> takeString(CharSequence line) {
     
    8986                }
    9087                assert ((matcher.start(1) == -1) != (matcher.start(2) == -1));
    91                 return new Pair<CharSequence, CharSequence>(takeGroup(line, matcher, (matcher.start(1) != -1 ? 1 : 2)), takeGroup(line, matcher, 3));
     88                return new Pair<CharSequence, CharSequence>(Strings.takeGroup(line, matcher, (matcher.start(1) != -1 ? 1 : 2)), Strings.takeGroup(line, matcher, 3));
    9289        }
    9390
    94         protected static final Pattern REQUEST_ID_BREAKER_PATTERN = Pattern.compile("^\\s*([0-9]+)\\s*(.*)$");
     91        protected static final Pattern REQUEST_ID_BREAKER_PATTERN = Pattern.compile("^\\s*(-?[0-9]+)\\s*(.*)$");
    9592
    9693        protected final static Pair<Integer, CharSequence> takeRequestId(boolean withId, CharSequence line) {
     
    10097                                return null;
    10198                        }
    102                         return new Pair<Integer, CharSequence>(Integer.valueOf(takeGroup(line, matcher, 1).toString()), takeGroup(line, matcher, 2));
     99                        return new Pair<Integer, CharSequence>(Integer.valueOf(Strings.takeGroup(line, matcher, 1).toString()), Strings.takeGroup(line, matcher, 2));
    103100                }
    104101                return new Pair<Integer, CharSequence>(null, line);
  • java/main/src/main/java/com/framsticks/communication/ServerSideManagedConnection.java

    r100 r101  
    22
    33import com.framsticks.communication.queries.*;
    4 import com.framsticks.params.SourceInterface;
    54import com.framsticks.util.FramsticksException;
    65import com.framsticks.util.lang.Holder;
     
    6968        }
    7069
    71         protected final void putFile(File file, String outId) {
    72                 putLine("file" + outId/* + " " + f.getPath()*/);
    73                 SourceInterface content = file.getContent();
    74                 String line;
    75                 while ((line = content.readLine()) != null) {
    76                         putLine(line);
    77                 }
    78                 putLine("eof");
    79         }
    8070
    81         public final void sendFile(final String header, final File file) {
    82                 senderThread.dispatch(new RunAt<Connection>(requestHandler) {
    83                         @Override
    84                         protected void runAt() {
    85                                 putLine(header);
    86                                 putFile(file, "");
    87                                 flushOut();
    88                         }
    89                 });
    90         }
    9171
    9272        protected final void respond(final Response response, final Integer id) {
     
    9474                        @Override
    9575                        protected void runAt() {
    96                                 String outId = id != null ? " " + id : "";
    9776                                if (response.getFiles() != null) {
    9877                                        for (File f : response.getFiles()) {
    99                                                 putFile(f, outId);
     78                                                putFile(f, id);
    10079                                        }
    10180                                }
    10281                                StringBuilder statusLine = new StringBuilder();
    103                                 statusLine.append(response.getOk() ? "ok" : "error").append(outId);
     82                                statusLine.append(response.getOk() ? "ok" : "error").append(idToString(id));
    10483                                if (Strings.notEmpty(response.getComment())) {
    10584                                        Request.quoteValue(statusLine.append(" "), response.getComment());
  • java/main/src/main/java/com/framsticks/communication/queries/CallRequest.java

    r96 r101  
    1717
    1818        public CallRequest addArguments(String arguments) {
    19                 // this.arguments = arguments;
    2019                return this;
    2120        }
  • java/main/src/main/java/com/framsticks/core/AbstractTree.java

    r100 r101  
    11package com.framsticks.core;
    22
     3import java.util.Comparator;
     4import java.util.Iterator;
    35import java.util.Map;
     6import java.util.PriorityQueue;
    47
    58import javax.annotation.Nonnull;
     
    912import org.apache.logging.log4j.LogManager;
    1013
     14import com.framsticks.communication.queries.NeedFile;
     15import com.framsticks.communication.queries.NeedFileAcceptor;
    1116import com.framsticks.params.Access;
    1217import com.framsticks.params.CompositeParam;
    1318import com.framsticks.params.FramsClass;
     19import com.framsticks.params.ParamFlags;
    1420import com.framsticks.params.ParamsPackage;
    1521import com.framsticks.params.Registry;
     
    2026import com.framsticks.util.Misc;
    2127import com.framsticks.util.dispatching.AbstractJoinable;
     28import com.framsticks.util.dispatching.BufferedDispatcher;
    2229import com.framsticks.util.dispatching.Dispatcher;
    2330import com.framsticks.util.dispatching.Dispatching;
    2431import com.framsticks.util.dispatching.ExceptionResultHandler;
    2532import com.framsticks.util.dispatching.Joinable;
    26 import com.framsticks.util.dispatching.JoinableDispatcher;
    2733import com.framsticks.util.dispatching.JoinableParent;
    2834import com.framsticks.util.dispatching.JoinableState;
     
    3036import com.framsticks.util.dispatching.Thread;
    3137import com.framsticks.util.dispatching.ThrowExceptionHandler;
    32 import com.framsticks.util.lang.Casting;
     38import com.framsticks.util.lang.Pair;
    3339
    3440/**
     
    3642 */
    3743@FramsClassAnnotation
    38 public abstract class AbstractTree extends AbstractJoinable implements Dispatcher<Tree>, Tree, JoinableParent {
     44public abstract class AbstractTree extends AbstractJoinable implements Dispatcher<Tree>, Tree, JoinableParent, NeedFileAcceptor {
    3945
    4046        private static final Logger log = LogManager.getLogger(AbstractTree.class);
     
    4349        private ExceptionResultHandler handler = ThrowExceptionHandler.getInstance();
    4450
    45         private JoinableDispatcher<Tree> dispatcher;
     51        protected final BufferedDispatcher<Tree> bufferedDispatcher = new BufferedDispatcher<>();
     52
     53        protected final PriorityQueue<Pair<Integer, NeedFileAcceptor>> needFileAcceptors = new PriorityQueue<>(32, new Comparator<Pair<Integer, NeedFileAcceptor>>() {
     54
     55                @Override
     56                public int compare(Pair<Integer, NeedFileAcceptor> arg0, Pair<Integer, NeedFileAcceptor> arg1) {
     57                        if (arg0.first < arg1.first) {
     58                                return -1;
     59                        }
     60                        if (arg0.first > arg1.first) {
     61                                return 1;
     62                        }
     63                        return 0;
     64                }
     65        });
    4666
    4767        @Override
     
    152172         */
    153173        @Override
    154         public JoinableDispatcher<Tree> getDispatcher() {
    155                 return dispatcher;
     174        public Dispatcher<Tree> getDispatcher() {
     175                return bufferedDispatcher.getTargetDispatcher();
    156176        }
    157177
     
    160180         */
    161181        @Override
    162         public void setDispatcher(JoinableDispatcher<Tree> dispatcher) {
    163                 if (this.dispatcher != null) {
    164                         throw new FramsticksException().msg("dispatcher is already set").arg("tree", this).arg("dispatcher", dispatcher);
    165                 }
    166                 this.dispatcher = dispatcher;
     182        public void setDispatcher(Dispatcher<Tree> dispatcher) {
     183                if (bufferedDispatcher.getTargetDispatcher() != null) {
     184                        throw new FramsticksException().msg("dispatcher is already set").arg("tree", this).arg("dispatcher", bufferedDispatcher.getTargetDispatcher());
     185                }
     186                bufferedDispatcher.setTargetDispatcher(dispatcher);
    167187        }
    168188
     
    170190         * @return the name
    171191         */
    172         @ParamAnnotation
     192        @ParamAnnotation(flags = ParamFlags.USERREADONLY)
    173193        public String getName() {
    174194                return name;
     
    193213        @Override
    194214        protected void joinableStart() {
    195                 if (dispatcher == null) {
    196                         dispatcher = new Thread<Tree>();
    197                 }
    198                 Dispatching.use(dispatcher, this);
     215                if (bufferedDispatcher.getTargetDispatcher() == null) {
     216                        bufferedDispatcher.setTargetDispatcher(new Thread<Tree>());
     217                }
     218                Dispatching.use(bufferedDispatcher.getTargetDispatcher(), this);
    199219        }
    200220
    201221        @Override
    202222        protected void joinableInterrupt() {
    203                 Dispatching.drop(dispatcher, this);
     223                Dispatching.drop(bufferedDispatcher.getTargetDispatcher(), this);
    204224        }
    205225
     
    211231        @Override
    212232        protected void joinableJoin() throws InterruptedException {
    213                 Dispatching.join(dispatcher);
     233                Dispatching.join(bufferedDispatcher.getTargetDispatcher());
    214234        }
    215235
    216236        @Override
    217237        public void childChangedState(Joinable joinable, JoinableState state) {
    218                 if (joinable == dispatcher) {
     238                if (joinable == bufferedDispatcher.getTargetDispatcher()) {
    219239                        proceedToState(state);
    220240                }
     
    223243        @Override
    224244        public boolean isActive() {
    225                 if (dispatcher == null) {
    226                         throw new FramsticksException().msg("no dispatcher is set for tree yet").arg("tree", this);
    227                 }
    228                 return dispatcher.isActive();
     245                return bufferedDispatcher.isActive();
    229246        }
    230247
    231248        @Override
    232249        public void dispatch(RunAt<? extends Tree> runnable) {
    233                 if (dispatcher == null) {
    234                         throw new FramsticksException().msg("no dispatcher is set for tree yet").arg("tree", this);
    235                 }
    236                 dispatcher.dispatch(runnable);
     250                bufferedDispatcher.dispatch(runnable);
    237251        }
    238252
     
    242256
    243257        @Override
    244         public void putSideNote(Object object, Object key, Object value) {
     258        public <T> void putSideNote(Object object, SideNoteKey<T> key, T value) {
    245259                assert isActive();
    246260                Misc.throwIfNull(object);
     
    253267                }
    254268                @SuppressWarnings("unchecked")
    255                 Map<Object, Object> sideNotesMap = (Map<Object, Object>) sideNote;
     269                Map<SideNoteKey<?>, Object> sideNotesMap = (Map<SideNoteKey<?>, Object>) sideNote;
    256270                sideNotesMap.put(key, value);
    257271        }
    258272
    259         @Override
    260         public <T> T getSideNote(Object object, Object key, Class<T> valueType) {
     273        @SuppressWarnings("unchecked")
     274        @Override
     275        public <T> T getSideNote(Object object, SideNoteKey<T> key) {
    261276                assert isActive();
    262277                Misc.throwIfNull(object);
     
    266281                        return null;
    267282                }
    268                 return Casting.nullOrThrowCast(valueType, ((Map<?, ?>) sideNote).get(key));
    269         }
    270 
    271         @Override
    272         public boolean removeSideNote(Object object, Object key) {
     283                Object value = ((Map<SideNoteKey<?>, Object>) sideNote).get(key);
     284                if (value == null) {
     285                        return null;
     286                }
     287                return (T) value;
     288        }
     289
     290        @Override
     291        public boolean removeSideNote(Object object, SideNoteKey<?> key) {
     292                assert isActive();
    273293                Object sideNote = sideNotes.get(object);
    274294                if (sideNote == null) {
     
    276296                }
    277297                @SuppressWarnings("unchecked")
    278                 Map<Object, Object> sideNotesMap = (Map<Object, Object>) sideNote;
     298                Map<SideNoteKey<?>, Object> sideNotesMap = (Map<SideNoteKey<?>, Object>) sideNote;
    279299                boolean result = (sideNotesMap.remove(key) != null);
    280300                if (sideNotesMap.isEmpty()) {
     
    284304        }
    285305
     306        @Override
     307        public void addNeedFileAcceptor(int priority, NeedFileAcceptor acceptor) {
     308                assert isActive();
     309                needFileAcceptors.add(Pair.make(priority, acceptor));
     310        }
     311
     312        @Override
     313        public void removeNeedFileAcceptor(NeedFileAcceptor acceptor) {
     314                assert isActive();
     315                Iterator<Pair<Integer, NeedFileAcceptor>> i = needFileAcceptors.iterator();
     316                while (i.hasNext()) {
     317                        if (i.next().second == acceptor) {
     318                                i.remove();
     319                                break;
     320                        }
     321                }
     322        }
     323
     324        @Override
     325        public boolean acceptNeed(final NeedFile needFile) {
     326                Dispatching.dispatchIfNotActive(this, new RunAt<AbstractTree>(needFile.getFuture()) {
     327
     328                        @Override
     329                        protected void runAt() {
     330                                for (Pair<Integer, NeedFileAcceptor> acceptor : needFileAcceptors) {
     331                                        if (acceptor.second.acceptNeed(needFile)) {
     332                                                return;
     333                                        }
     334                                }
     335                                throw new FramsticksException().msg("failed to find need file acceptor in tree").arg("tree", AbstractTree.this);
     336                        }
     337                });
     338                return true;
     339        }
     340
    286341}
    287342
  • java/main/src/main/java/com/framsticks/core/Framsticks.java

    r100 r101  
    2929        public static void main(final String[] args) {
    3030
    31                 String config = "/configs/framsticks.xml";
     31                String config = "/framsticks.xml";
    3232                if (args.length != 0) {
    3333                        config = args[0];
  • java/main/src/main/java/com/framsticks/core/LocalTree.java

    r100 r101  
    1515import com.framsticks.params.types.ProcedureParam;
    1616import com.framsticks.util.FramsticksException;
     17import com.framsticks.util.dispatching.Dispatching;
    1718import com.framsticks.util.dispatching.Future;
     19import com.framsticks.util.dispatching.Joinable;
     20import com.framsticks.util.dispatching.JoinableState;
    1821
    1922import static com.framsticks.core.TreeOperations.*;
     
    2326        private static final Logger log = LogManager.getLogger(LocalTree.class);
    2427
    25         protected Object rootObject;
     28        protected Joinable joinableRootObject;
    2629
    2730        /**
     
    4245                assignRootParam(access.buildParam(new ParamBuilder()).id(getName()).finish(CompositeParam.class));
    4346                assignRootObject(object);
     47
     48                if (object instanceof Joinable) {
     49                        joinableRootObject = (Joinable) object;
     50                }
    4451        }
    4552
     
    6976        // @Override
    7077        // public void get(Path path, ValueParam param, Future<Object> future) {
    71         //      assert isActive();
    72         //      path = resolveTopSync(path);
    73         //      future.pass(bindAccess(path).get(param, Object.class));
     78        //      assert isActive();
     79        //      path = resolveTopSync(path);
     80        //      future.pass(bindAccess(path).get(param, Object.class));
    7481        // }
    7582
     
    137144                }
    138145        }
     146
     147        @Override
     148        protected void joinableStart() {
     149                super.joinableStart();
     150                if (joinableRootObject != null) {
     151                        Dispatching.use(joinableRootObject, this);
     152                }
     153        }
     154
     155        @Override
     156        protected void joinableInterrupt() {
     157                if (joinableRootObject != null) {
     158                        Dispatching.drop(joinableRootObject, this);
     159                }
     160                super.joinableInterrupt();
     161        }
     162
     163        @Override
     164        protected void joinableFinish() {
     165                super.joinableFinish();
     166        }
     167
     168        @Override
     169        protected void joinableJoin() throws InterruptedException {
     170                if (joinableRootObject != null) {
     171                        Dispatching.join(joinableRootObject);
     172                }
     173                super.joinableJoin();
     174        }
     175
     176        @Override
     177        public void childChangedState(Joinable joinable, JoinableState state) {
     178                super.childChangedState(joinable, state);
     179                if (joinable == joinableRootObject) {
     180                        proceedToState(state);
     181                }
     182        }
    139183}
  • java/main/src/main/java/com/framsticks/core/Path.java

    r100 r101  
    3131        final LinkedList<Node> nodes;
    3232
     33        public static final SideNoteKey<CompositeParam> OBJECT_PARAM_KEY = SideNoteKey.make(CompositeParam.class);
     34
    3335        protected static Object getKnownChild(Tree tree, Access access, CompositeParam param, ExceptionResultHandler handler) {
    3436                Object child = access.get(param, Object.class);
     
    3840                try {
    3941                        tree.prepareAccess(param);
    40                         tree.putSideNote(child, CompositeParam.class, param);
     42                        tree.putSideNote(child, OBJECT_PARAM_KEY, param);
    4143                        return child;
    4244                } catch (FramsticksException e) {
     
    164166                                b.append("/").append(e);
    165167                                access.select(current.getObject());
    166                                 tree.putSideNote(current.getObject(), CompositeParam.class, current.getParam());
     168                                tree.putSideNote(current.getObject(), OBJECT_PARAM_KEY, current.getParam());
    167169                                current = new Node(current.getTree(), c, getKnownChild(tree, access, c, handler));
    168170                                nodes.add(current);
  • java/main/src/main/java/com/framsticks/core/Tree.java

    r100 r101  
    33import javax.annotation.Nonnull;
    44
     5import com.framsticks.communication.queries.NeedFileAcceptor;
    56import com.framsticks.params.Access;
    67import com.framsticks.params.CompositeParam;
     
    1516import com.framsticks.util.dispatching.Future;
    1617import com.framsticks.util.dispatching.Joinable;
    17 import com.framsticks.util.dispatching.JoinableDispatcher;
    1818
    1919public interface Tree extends Dispatcher<Tree>, Joinable, ExceptionResultHandler {
     
    5454        public ExceptionResultHandler getExceptionHandler();
    5555
    56         public void setDispatcher(JoinableDispatcher<Tree> dispatcher);
     56        public void setDispatcher(Dispatcher<Tree> dispatcher);
    5757
    58         public JoinableDispatcher<Tree> getDispatcher();
     58        public Dispatcher<Tree> getDispatcher();
    5959
    6060        public <A> void addListener(Path path, EventParam param, EventListener<A> listener, Class<A> argumentType, Future<Void> future);
     
    6464        public Registry getRegistry();
    6565
    66         public void putSideNote(Object object, Object key, Object value);
     66        public <T> void putSideNote(Object object, SideNoteKey<T> key, T value);
    6767
    68         public boolean removeSideNote(Object object, Object key);
     68        public boolean removeSideNote(Object object, SideNoteKey<?> key);
    6969
    70         public <T> T getSideNote(Object object, Object key, Class<T> valueType);
     70        public <T> T getSideNote(Object object, SideNoteKey<T> key);
     71
     72        public void addNeedFileAcceptor(int priority, NeedFileAcceptor acceptor);
     73
     74        public void removeNeedFileAcceptor(NeedFileAcceptor acceptor);
    7175
    7276}
  • java/main/src/main/java/com/framsticks/core/TreeOperations.java

    r100 r101  
    11package com.framsticks.core;
    2 
    32
    43import java.util.HashSet;
     
    2221import com.framsticks.params.PropertiesAccess;
    2322import com.framsticks.params.UniqueListAccess;
    24 import com.framsticks.params.Util;
     23import com.framsticks.params.ParamsUtil;
    2524import com.framsticks.params.types.EventParam;
    2625import com.framsticks.params.types.ObjectParam;
     
    4342        }
    4443
    45         public static final Object FETCHED_MARK = new Object();
    46 
    47         public static @Nonnull FramsClass processFetchedInfo(Tree tree, File file) {
     44        public static final SideNoteKey<Boolean> FETCHED_MARK = SideNoteKey.make(Boolean.class);
     45
     46        public static @Nonnull
     47        FramsClass processFetchedInfo(Tree tree, File file) {
    4848                assert tree.isActive();
    4949                FramsClass framsClass = Loaders.loadFramsClass(file.getContent());
     
    8080                assert path.isTheSame(files.get(0).getPath());
    8181
    82 
    8382                try {
    8483                        log.debug("process fetched values: {}", path);
     
    9897                                        if (path.getTop().getParam() instanceof ObjectParam) {
    9998                                                assert results.size() == 1;
    100                                                 Util.takeAllNonNullValues(bindAccess(result), parsingAccess.select(results.get(0)));
     99                                                ParamsUtil.takeAllNonNullValues(bindAccess(result), parsingAccess.select(results.get(0)));
    101100                                                mark(result.getTree(), result.getTopObject(), FETCHED_MARK, true);
    102101                                                future.pass(result);
    103102                                                return;
    104103                                        }
    105 
    106104
    107105                                        final ListAccess listAccess = (ListAccess) access;
     
    139137
    140138                                                targetAccess.select(childTo);
    141                                                 Util.takeAllNonNullValues(targetAccess, parsingAccess);
     139                                                ParamsUtil.takeAllNonNullValues(targetAccess, parsingAccess);
    142140                                                if (newOne) {
    143141                                                        listAccess.set(id, childTo);
     
    188186        }
    189187
    190 
    191         public static @Nonnull Access bindAccessFromSideNote(Tree tree, Object object) {
    192                 CompositeParam param = tree.getSideNote(object, CompositeParam.class, CompositeParam.class);
     188        public static @Nonnull
     189        Access bindAccessFromSideNote(Tree tree, Object object) {
     190                CompositeParam param = tree.getSideNote(object, Path.OBJECT_PARAM_KEY);
    193191                if (param == null) {
    194192                        throw new FramsticksException().msg("failed to bind access from side node").arg("tree", tree).arg("object", object).arg("type", object.getClass());
     
    197195        }
    198196
    199         public static @Nonnull Access bindAccess(Tree tree, String path) {
     197        public static @Nonnull
     198        Access bindAccess(Tree tree, String path) {
    200199                log.debug("bind access for textual: {} in {}", path, tree);
    201200                return bindAccess(Path.to(tree, path));
    202201        }
    203202
    204         public static @Nonnull Access bindAccess(Node node) {
     203        public static @Nonnull
     204        Access bindAccess(Node node) {
    205205                Tree tree = node.getTree();
    206206                assert tree.isActive();
     
    209209                try {
    210210                        Access access = tree.prepareAccess(node.getParam());
    211                         tree.putSideNote(node.getObject(), CompositeParam.class, node.getParam());
     211                        tree.putSideNote(node.getObject(), Path.OBJECT_PARAM_KEY, node.getParam());
    212212
    213213                        return access.select(node.getObject());
     
    218218        }
    219219
    220         public static @Nonnull Access bindAccess(Path path) {
     220        public static @Nonnull
     221        Access bindAccess(Path path) {
    221222                assert path.getTree().isActive();
    222223                path.assureResolved();
     
    280281                });
    281282        }
    282 
    283283
    284284        /**
     
    323323        public static Object createAccessee(Tree tree, CompositeParam param) {
    324324                Object object = tree.prepareAccess(param).createAccessee();
    325                 tree.putSideNote(object, CompositeParam.class, param);
     325                tree.putSideNote(object, Path.OBJECT_PARAM_KEY, param);
    326326                return object;
    327327        }
     
    329329        public static Object createAccessee(Tree tree, Access access) {
    330330                Object object = access.createAccessee();
    331                 tree.putSideNote(object, CompositeParam.class, access.buildParam(new ParamBuilder()).finish(CompositeParam.class));
     331                tree.putSideNote(object, Path.OBJECT_PARAM_KEY, access.buildParam(new ParamBuilder()).finish(CompositeParam.class));
    332332                return object;
    333333        }
    334334
    335         public static boolean isMarked(Tree tree, Object object, Object mark, boolean defValue) {
    336                 assert tree.isActive();
    337                 Boolean v = tree.getSideNote(object, mark, Boolean.class);
     335        public static boolean isMarked(Tree tree, Object object, SideNoteKey<Boolean> mark, boolean defValue) {
     336                assert tree.isActive();
     337                Boolean v = tree.getSideNote(object, mark);
    338338                return (v != null ? v : defValue);
    339339        }
    340340
    341         public static void mark(Tree tree, Object object, Object mark, boolean value) {
     341        public static void mark(Tree tree, Object object, SideNoteKey<Boolean> mark, boolean value) {
    342342                assert tree.isActive();
    343343                tree.putSideNote(object, mark, value);
     
    348348        }
    349349
     350        public static <T extends Param> T getParam(Path path, String id, Class<T> type) {
     351                return getFramsClass(path).getParamEntry(id, type);
     352        }
     353
     354        public static <T> T getOrCreateSideNote(Tree tree, Object object, SideNoteKey<T> key) {
     355                T result = tree.getSideNote(object, key);
     356                if (result == null) {
     357                        result = key.newValue();
     358                        tree.putSideNote(object, key, result);
     359                }
     360                return result;
     361        }
     362
     363        public static <T> boolean hasSideNotes(Tree tree, Object object, SideNoteKey<T> key) {
     364                return tree.getSideNote(object, key) != null;
     365        }
     366
     367        public static <T> boolean hasSideNote(Path path, SideNoteKey<T> key) {
     368                return path.getTree().getSideNote(path.getTopObject(), key) != null;
     369        }
     370
     371        public static <T> T getSideNote(Path path, SideNoteKey<T> key) {
     372                assert path.isResolved();
     373                return path.getTree().getSideNote(path.getTopObject(), key);
     374        }
     375
     376        public static <T> void putSideNote(Path path, SideNoteKey<T> key, T value) {
     377                path.getTree().putSideNote(path.getTopObject(), key, value);
     378        }
     379
     380        public static boolean removeSideNote(Path path, SideNoteKey<?> key) {
     381                assert path.isResolved();
     382                return path.getTree().removeSideNote(path.getTopObject(), key);
     383        }
     384
    350385}
  • java/main/src/main/java/com/framsticks/gui/Browser.java

    r100 r101  
    11package com.framsticks.gui;
    22
     3import com.framsticks.communication.File;
     4import com.framsticks.communication.queries.NeedFile;
     5import com.framsticks.communication.queries.NeedFileAcceptor;
    36import com.framsticks.core.*;
    47import com.framsticks.gui.console.Console;
     
    912import com.framsticks.params.annotations.FramsClassAnnotation;
    1013import com.framsticks.params.annotations.ParamAnnotation;
     14import com.framsticks.parsers.FileSource;
    1115import com.framsticks.remote.RemoteTree;
    1216import com.framsticks.util.FramsticksException;
     
    2226
    2327import javax.swing.*;
     28import javax.swing.filechooser.FileNameExtensionFilter;
    2429
    2530import org.apache.logging.log4j.Logger;
     
    3035import java.awt.datatransfer.StringSelection;
    3136import java.awt.event.ActionEvent;
     37import java.awt.event.ActionListener;
     38import java.awt.event.WindowAdapter;
     39import java.awt.event.WindowEvent;
     40import java.io.IOException;
    3241import java.util.ArrayList;
    3342import java.util.LinkedList;
    3443import java.util.List;
     44import java.util.regex.Matcher;
     45import java.util.regex.Pattern;
     46
    3547import com.framsticks.util.dispatching.RunAt;
     48import com.framsticks.util.lang.Strings;
    3649
    3750/**
     
    132145        }
    133146
     147        protected static final Pattern extensionFilterPattern = Pattern.compile("\\*\\.(\\S+)");
     148
    134149        @AutoAppendAnnotation
    135         public void addTree(Tree tree) {
     150        public void addTree(final Tree tree) {
    136151                log.debug("adding tree: {}", tree);
    137152                tree.setDispatcher(new SwingDispatcher<Tree>());
    138153                tree.setExceptionHandler(this);
    139154                trees.add(tree);
     155
     156                final NeedFileAcceptor acceptor = new NeedFileAcceptor() {
     157
     158                        protected boolean done = false;
     159
     160                        @Override
     161                        public boolean acceptNeed(final NeedFile needFile) {
     162                                final JFileChooser chooser = new JFileChooser();
     163                                final JFrame frame = new JFrame();
     164
     165                                frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
     166
     167                                frame.addWindowListener(new WindowAdapter() {
     168                                        @Override
     169                                        public void windowClosing(WindowEvent e) {
     170                                                if (!done) {
     171                                                        needFile.getFuture().handle(new FramsticksException().msg("user closed the window"));
     172                                                }
     173                                                frame.setVisible(false);
     174                                                frame.dispose();
     175                                        }
     176                                });
     177
     178                                frame.setTitle(Strings.toStringEmptyProof(needFile.getDescription(), "Choose file"));
     179                                chooser.setMultiSelectionEnabled(false);
     180                                Matcher matcher = extensionFilterPattern.matcher(needFile.getSuggestedName());
     181                                if (matcher.matches()) {
     182                                        chooser.setFileFilter(new FileNameExtensionFilter(Strings.toStringEmptyProof(needFile.getDescription(), "file"), Strings.takeGroup(needFile.getSuggestedName(), matcher, 1).toString()));
     183                                }
     184
     185                                frame.getContentPane().add(chooser);
     186
     187                                chooser.addActionListener(new ActionListener() {
     188
     189                                        @Override
     190                                        public void actionPerformed(ActionEvent event) {
     191                                                if (event.getActionCommand().equals("CancelSelection")) {
     192                                                        needFile.getFuture().handle(new FramsticksException().msg("user cancelled choose"));
     193                                                        frame.setVisible(false);
     194                                                        frame.dispose();
     195                                                }
     196                                                if (event.getActionCommand().equals("ApproveSelection")) {
     197                                                        File file = null;
     198                                                        String filename = chooser.getSelectedFile().getAbsolutePath();
     199                                                        try {
     200                                                                file = new File("", new FileSource(filename));
     201                                                        } catch (IOException e) {
     202                                                                needFile.getFuture().handle(new FramsticksException().msg("failed to open choosed file").arg("filename", filename).cause(e));
     203                                                        }
     204                                                        if (file != null) {
     205                                                                done = true;
     206                                                                needFile.getFuture().pass(file);
     207                                                        }
     208                                                        frame.setVisible(false);
     209                                                        frame.dispose();
     210                                                }
     211                                        }
     212                                });
     213                                frame.setVisible(true);
     214                                return true;
     215                        }
     216                };
     217
     218                tree.dispatch(new RunAt<Tree>(this) {
     219                        @Override
     220                        protected void runAt() {
     221                                log.debug("adding need file acceptor: {}", acceptor);
     222                                tree.addNeedFileAcceptor(Integer.MAX_VALUE, acceptor);
     223                        }
     224                });
     225
    140226        }
    141227
     
    143229                // final Tree i = trees.get("localhost");
    144230                // i.dispatch(new RunAt<Tree>(future) {
    145                 //      @Override
    146                 //      protected void runAt() {
    147                 //              TreeOperations.tryGet(i, path, new FutureHandler<Path>(future) {
    148                 //                      @Override
    149                 //                      protected void result(final Path p) {
    150                 //                              future.pass(p);
    151                 //                              mainFrame.dispatch(new RunAt<Frame>(future) {
    152                 //                                      @Override
    153                 //                                      protected void runAt() {
    154                 //                                              mainFrame.goTo(p);
    155                 //                                      }
    156                 //                              });
    157                 //                      }
    158                 //              });
    159                 //      }
     231                //      @Override
     232                //      protected void runAt() {
     233                //              TreeOperations.tryGet(i, path, new FutureHandler<Path>(future) {
     234                //                      @Override
     235                //                      protected void result(final Path p) {
     236                //                              future.pass(p);
     237                //                              mainFrame.dispatch(new RunAt<Frame>(future) {
     238                //                                      @Override
     239                //                                      protected void runAt() {
     240                //                                              mainFrame.goTo(p);
     241                //                                      }
     242                //                              });
     243                //                      }
     244                //              });
     245                //      }
    160246                // });
    161247        }
     
    183269                                                protected void runAt() {
    184270                                                        final Path p = Path.to(i, "/");
     271                                                        log.debug("adding path: {}", p);
    185272                                                        dispatch(new RunAt<Browser>(this) {
    186273                                                                @Override
  • java/main/src/main/java/com/framsticks/gui/Frame.java

    r100 r101  
    243243                        @Override
    244244                        public void actionPerformed(ActionEvent actionEvent) {
    245                                 interrupt();
     245                                interruptJoinable();
    246246                        }
    247247                });
     
    268268                log.debug("trying mount: {}", path);
    269269                if (!tree.getAssignedRoot().isResolved()) {
     270                        log.debug("root not yet assigned, geting root");
    270271                        tree.get(path, new FutureHandler<Path>(this) {
    271272
  • java/main/src/main/java/com/framsticks/gui/FrameJoinable.java

    r100 r101  
    3131         */
    3232        public FrameJoinable() {
    33                 statusBar = new StatusBar();
     33                statusBar = new StatusBar(this);
    3434        }
    3535
     
    101101                        @Override
    102102                        protected void runAt() {
    103                                 finish();
     103                                finishJoinable();
    104104                        }
    105105                });
     
    135135                        public void windowClosing(WindowEvent e) {
    136136                                log.info("received closing");
    137                                 interrupt();
     137                                interruptJoinable();
    138138                        }
    139139                });
  • java/main/src/main/java/com/framsticks/gui/Gui.java

    r100 r101  
    77import javax.swing.Box;
    88import javax.swing.BoxLayout;
     9import javax.swing.JComponent;
    910import javax.swing.JLabel;
    1011import javax.swing.JPanel;
     12import javax.swing.border.TitledBorder;
    1113
    1214import org.apache.logging.log4j.Logger;
     
    2426import com.framsticks.params.CompositeParam;
    2527import com.framsticks.params.Param;
     28import com.framsticks.params.ParamFlags;
    2629import com.framsticks.params.PrimitiveParam;
    2730import com.framsticks.params.types.BinaryParam;
     
    101104        }
    102105
    103         public static <P extends Param, C extends Control> void fillWithControls(ControlOwner owner, Collection<P> params, Map<P, C> components, Class<C> controlType) {
    104                 JPanel panel = owner.getPanelForControls();
     106        public static <P extends Param, C extends Control> void fillWithControls(ControlOwner owner, JPanel panel, Collection<P> params, Map<String, C> components, Class<C> controlType) {
     107                panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
    105108                for (P param : params) {
    106                         if (param.isUserHidden()) {
     109                        if (param.hasFlag(ParamFlags.USERHIDDEN)) {
    107110                                continue;
    108111                        }
     
    122125                        line.setLayout(new BoxLayout(line, BoxLayout.LINE_AXIS));
    123126                        line.setAlignmentX(JPanel.LEFT_ALIGNMENT);
    124                         JLabel label = new JLabel(Strings.notEmpty(param.getName()) ? param.getName() : (Strings.notEmpty(param.getId()) ? param.getId() : "?"));
    125                         label.setToolTipText(control.getToolTipText());
    126                         label.setHorizontalAlignment(JLabel.RIGHT);
    127                         Dimension labelSize = new Dimension(150, 30);
    128                         label.setMaximumSize(labelSize);
    129                         label.setMinimumSize(labelSize);
    130                         label.setPreferredSize(labelSize);
    131                         line.add(label);
    132                         line.add(Box.createRigidArea(new Dimension(8, 0)));
     127
    133128                        line.add(control);
    134129                        line.revalidate();
    135130                        panel.add(line);
    136131                        panel.add(Box.createRigidArea(new Dimension(0, 8)));
     132                        components.put(param.getId(), control);
    137133                        //component.setAlignmentX(LEFT_ALIGNMENT);
    138                         components.put(param, control);
     134                        // components.put(param.getId(), control);
    139135                }
    140136
    141137        }
     138
     139        public static String getBestName(Param param) {
     140                if (Strings.notEmpty(param.getName())) {
     141                        return param.getName();
     142                }
     143                if (Strings.notEmpty(param.getId())) {
     144                        return param.getId();
     145                }
     146                return "?";
     147        }
     148
     149        public static void setupTitledControl(Control control, JComponent... components) {
     150
     151                control.setLayout(new BoxLayout(control, BoxLayout.PAGE_AXIS));
     152                control.setBorder(new TitledBorder(Gui.getBestName(control.getParam())));
     153                for (JComponent c : components) {
     154                        // control.add(Box.createRigidArea(new Dimension(0, 4)));
     155                        control.add(c);
     156                }
     157        }
     158
     159        public static void layoutInRow(JPanel panel, JComponent first, JComponent... components) {
     160                panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS));
     161                panel.setAlignmentX(JPanel.LEFT_ALIGNMENT);
     162
     163                panel.add(first);
     164                for (JComponent c : components) {
     165                        panel.add(Box.createRigidArea(new Dimension(8, 0)));
     166                        panel.add(c);
     167                }
     168        }
     169
     170        public static void addLeftToLabel(Control control, JComponent... components) {
     171
     172                JLabel label = new JLabel(getBestName(control.getParam()));
     173                label.setToolTipText(control.getToolTipText());
     174                label.setHorizontalAlignment(JLabel.LEFT);
     175                Dimension labelSize = new Dimension(150, 30);
     176                label.setMaximumSize(labelSize);
     177                label.setMinimumSize(labelSize);
     178                label.setPreferredSize(labelSize);
     179
     180                layoutInRow(control, label, components);
     181
     182        }
    142183}
  • java/main/src/main/java/com/framsticks/gui/MainFrame.java

    r100 r101  
    7373        }
    7474
    75         // private void onConnectionEstablished() {
    76                 // assert isActive();
    77 
    78                 // addNodeActionToTreePopupMenu("Open in console", new NodeAction() {
    79                         // @Override
    80                         // public void actionPerformed(TreeNode treeNode) {
    81                                 // assert isActive();
    82                         // }
    83                 // });
    84 
    85 
    86 
    87 
    88         //      // browser.addNodeActionToTreePopupMenu("Resolve recursively", new NodeAction() {
    89         //      //      @Override
    90         //      //      public void actionPerformed(TreeNode treeNode) {
    91         //      //              final Child child = treeNode.getChild();
    92         //      //              //server.invokeLater(new Runnable() {
    93         //              //              @Override
    94         //              //              public void run() {
    95         //              //                      resolveRecursively(child);
    96         //              //              }
    97         //              //      });
    98         //      // }
    99         //      // });
    100 
    101 
    102                 // // addNodeActionToTreePopupMenu("Store in file", new NodeAction() {
    103                 // //     @Override
    104                 // //     public void actionPerformed(final TreeNode treeNode) {
    105                 // //         // final Node node = treeNode.getNode();
    106                 // //         // server.invokeLater(new Runnable() {
    107                 // //         //     @Override
    108                 // //         //     public void run() {
    109                 // //         //         try {
    110                 // //         //             log.info("storing");
    111                 // //         //             //File file = new File();
    112                 // //         //             StoreStream stream = new StoreStream(file, server.getManager());
    113                 // //         //             stream.store(node);
    114                 // //         //         } catch (FileNotFoundException e) {
    115                 // //         //             e.printStackTrace();
    116                 // //         //         }
    117                 // //         //     }
    118                 // //         // });
    119                 // //     }
    120                 // // });
    121 
    122 
    123         //      // arguments.forEach("resolve", new UnaryFunctor<Boolean, String>() {
    124         //      //      @Override
    125         //      //      public Boolean call(final String s) {
    126         //      //              server.getManager().resolvePath(s, new StateFunctor() {
    127         //      //                      @Override
    128         //      //                      public void call(Exception e) {
    129         //      //                              if (e != null) {
    130         //      //                                      log.error("failed to resolve: {}", s);
    131         //      //                                      return;
    132         //      //                              }
    133         //      //                              log.info("succeeded to resolve: {}", s);
    134         //      //                      }
    135         //      //              });
    136         //      //              return true;
    137         //      //      }
    138         //      // });
    139 
    140 
    141         //      // arguments.forEach("console", new UnaryFunctor<Boolean, String>() {
    142         //      //      @Override
    143         //      //      public Boolean call(String s) {
    144         //      //              showConsoleFrame().setCommandLine(s);
    145         //      //              return true;
    146         //      //      }
    147         //      // });
    148         // }
    149 
    150 
    151         // /**
    152         //  * Creates panel with start, step, stop buttons.
    153         //  */
    154         // @Override
    155         // protected JPanel createLeftTopPanel() {
    156         //      assert isActive();
    157         //      Dimension buttonDimension = new Dimension(45, 45);
    158 
    159         //      JPanel panel = new JPanel();
    160 
    161         //      stop = new JButton(ImageProvider.loadImage(ImageProvider.SIM_STOP));
    162         //      stop.addActionListener(new ActionListener() {
    163 
    164         //              public void actionPerformed(ActionEvent e) {
    165         //                      setSimulationRunning(false);
    166         //              }
    167 
    168         //      });
    169 
    170         //      stop.setPreferredSize(buttonDimension);
    171         //      stop.setToolTipText("Simulation Stop");
    172         //      stop.setEnabled(false);
    173 
    174         //      step = new JButton(ImageProvider.loadImage(ImageProvider.SIM_STEP));
    175         //      /*
    176         //      step.addActionListener(new ActionListener() {
    177 
    178         //              public void actionPerformed(ActionEvent e) {
    179         //                      connection.send(new CallQuery().setMethod("step").setPath("/simulator"));
    180         //              }
    181 
    182         //      });
    183         //      */
    184 
    185         //      step.setPreferredSize(buttonDimension);
    186         //      step.setToolTipText("Simulation Step");
    187 
    188         //      start = new JButton(ImageProvider.loadImage(ImageProvider.SIM_START));
    189         //      start.addActionListener(new ActionListener() {
    190 
    191         //              public void actionPerformed(ActionEvent e) {
    192         //                      setSimulationRunning(true);
    193         //              }
    194 
    195         //      });
    196 
    197         //      start.setPreferredSize(buttonDimension);
    198         //      start.setToolTipText("Start Simulation");
    199 
    200         //      JPanel buttonPanel = new JPanel();
    201         //      buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.LINE_AXIS));
    202         //      buttonPanel.add(Box.createHorizontalStrut(5));
    203         //      buttonPanel.add(stop);
    204         //      buttonPanel.add(Box.createHorizontalStrut(10));
    205         //      buttonPanel.add(step);
    206         //      buttonPanel.add(Box.createHorizontalStrut(10));
    207         //      buttonPanel.add(start);
    208         //      buttonPanel.add(Box.createHorizontalStrut(5));
    209 
    210         //      buttonPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory
    211         //                      .createRaisedBevelBorder(), "Simulation Control",
    212         //                      TitledBorder.CENTER, TitledBorder.DEFAULT_POSITION
    213         //                      ));
    214 
    215         //      panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS));
    216         //      panel.add(Box.createHorizontalGlue());
    217         //      panel.add(buttonPanel);
    218         //      panel.add(Box.createHorizontalGlue());
    219         //      return panel;
    220         // }
    22175
    22276        /**
     
    248102        }
    249103
    250         // public ConsoleFrame showConsoleFrame() {
    251         //      assert isActive();
    252         //      /*
    253         //      ConsoleFrame consoleFrame = new ConsoleFrame(connection);
    254         //      consoleFrame.show(MainFrame.this);
    255         //      return consoleFrame;
    256         //      */
    257         //      return null;
    258         // }
    259 
    260104        /**
    261105         * Closes connection with manager.
  • java/main/src/main/java/com/framsticks/gui/ModifiablePanel.java

    r100 r101  
    99import java.awt.event.ActionEvent;
    1010import java.awt.event.ActionListener;
     11import static com.framsticks.core.TreeOperations.*;
    1112
    1213/**
     
    2425        protected final JLabel label;
    2526        protected final JButton applyButton;
     27        protected final JButton revertButton;
    2628        protected final JPanel centerPanel;
    2729
     
    3234                log.debug("create panel for type: {}", className);
    3335
    34 
    35 
    3636                JPanel pageEndPanel = new JPanel();
    3737                pageEndPanel.setLayout(new BoxLayout(pageEndPanel, BoxLayout.X_AXIS));
     
    4141                applyButton.setName("apply");
    4242
     43                revertButton = new JButton("Revert");
     44                revertButton.setName("revert");
     45
     46                pageEndPanel.add(applyButton);
     47                pageEndPanel.add(Box.createHorizontalStrut(10));
     48
     49                pageEndPanel.add(revertButton);
     50                pageEndPanel.add(Box.createHorizontalStrut(10));
     51
     52                pageEndPanel.setPreferredSize(new Dimension(0, 30));
     53
    4354                applyButton.addActionListener(new ActionListener() {
    4455                        public void actionPerformed(ActionEvent e) {
     
    4657                        }
    4758                });
    48                 pageEndPanel.add(applyButton);
    4959
    50                 pageEndPanel.add(Box.createHorizontalStrut(10));
    51                 pageEndPanel.setPreferredSize(new Dimension(0, 30));
     60                revertButton.addActionListener(new ActionListener() {
     61                        public void actionPerformed(ActionEvent e) {
     62                                revertChanges();
     63                        }
     64                });
    5265
    5366                label = new JLabel();
     
    6780
    6881        protected abstract void applyChanges();
     82        protected abstract void revertChanges();
    6983
    7084        protected void setupContentComponent(Component contentComponent) {
     
    7387        }
    7488
     89        protected void refreshControlButtons() {
     90                assert frame.isActive();
     91                boolean hasChanges = hasSideNotes(getTree(), getCurrentObject(), treeAtFrame.getUserChangesKey());
     92                applyButton.setEnabled(hasChanges);
     93                revertButton.setEnabled(hasChanges);
     94        }
     95
    7596}
  • java/main/src/main/java/com/framsticks/gui/ObjectPanel.java

    r100 r101  
    55import com.framsticks.gui.controls.ControlOwner;
    66import com.framsticks.gui.controls.ValueControl;
    7 import com.framsticks.gui.controls.ValueControlListener;
    87import com.framsticks.params.Access;
    98import com.framsticks.params.Param;
    10 import com.framsticks.params.ValueParam;
    119
    1210import org.apache.logging.log4j.Logger;
     
    1614
    1715import java.util.Collection;
    18 import java.util.IdentityHashMap;
     16import java.util.HashMap;
    1917import java.util.Map;
    2018import static com.framsticks.util.lang.Containers.filterInstanceof;
    2119
    2220import com.framsticks.util.FramsticksException;
     21
     22import static com.framsticks.core.TreeOperations.*;
    2323
    2424@SuppressWarnings("serial")
     
    2727        private static final Logger log = LogManager.getLogger(ObjectPanel.class);
    2828
    29         final protected Map<Param, Control> components = new IdentityHashMap<Param, Control>();
    30         final protected Map<ValueParam, ValueControl> valueControls = new IdentityHashMap<ValueParam, ValueControl>();
     29        final protected Map<String, Control> controls = new HashMap<String, Control>();
     30        final protected Map<String, ValueControl> valueControls = new HashMap<String, ValueControl>();
    3131
    3232        protected final JPanel contentPanel;
     
    3838                contentPanel = new JPanel();
    3939                scrollPane = new JScrollPane(contentPanel);
    40                 contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.PAGE_AXIS));
     40
    4141                setupContentComponent(scrollPane);
    4242
    43                 Gui.fillWithControls(this, params, components, Control.class);
     43                Gui.fillWithControls(this, contentPanel, params, controls, Control.class);
    4444                setName(framsClass.getId());
    4545
    46                 for (final ValueControl c : filterInstanceof(components.values(), ValueControl.class)) {
    47                         valueControls.put(c.getParam(), c);
     46                for (final ValueControl c : filterInstanceof(controls.values(), ValueControl.class)) {
     47                        valueControls.put(c.getParam().getId(), c);
    4848                        c.setUserEnabled(true);
    49                         c.setListener(new ValueControlListener() {
    50                                 @Override
    51                                 public boolean onChange(Object newValue) {
    52                                         if (currentPath == null) {
    53                                                 return true;
    54                                         }
    55                                         boolean result = treeAtFrame.changeValue(currentPath.assureResolved().getTopObject(), c, newValue);
    56                                         refreshControlButtons();
    57                                         return result;
    58                                 }
    59                         });
    6049                }
    6150
     
    6857                assert frame.isActive();
    6958                assert currentPath != null;
    70                 treeAtFrame.pushLocalChanges(currentPath);
     59                treeAtFrame.pushUserChangesToTree(currentPath);
     60                refreshControlButtons();
    7161        }
    7262
    73         protected void refreshControlButtons() {
    74                 assert frame.isActive();
    75                 applyButton.setEnabled(treeAtFrame.hasLocalChanges(currentPath.getTopObject()));
     63
     64        @Override
     65        protected void revertChanges() {
     66                assert currentPath != null;
     67                removeSideNote(currentPath, treeAtFrame.getUserChangesKey());
     68                pullValuesFromLocalToUser(bindAccess(currentPath));
    7669        }
    7770
     
    8174                log.debug("refreshing components");
    8275
    83                 final Map<ValueControl, Object> values = new IdentityHashMap<ValueControl, Object>();
    84                 for (Map.Entry<ValueParam, ValueControl> e : valueControls.entrySet()) {
    85                         values.put(e.getValue(), access.get(e.getKey().getId(), Object.class));
     76                UserChanges userChanges = getSideNote(currentPath, treeAtFrame.getUserChangesKey());
     77
     78
     79                for (Map.Entry<String, ValueControl> e : valueControls.entrySet()) {
     80                        String id = e.getKey();
     81                        Object value;
     82                        if (userChanges != null && userChanges.changes.containsKey(id)) {
     83                                value = userChanges.changes.get(id);
     84                        } else {
     85                                value = access.get(id, Object.class);
     86                        }
     87
     88                        e.getValue().pushValueToUserInterface(value);
    8689                }
    8790
    88 
    89                 NodeAtFrame nodeAtFrame = treeAtFrame.getLocalInfo(currentPath.getTopObject());
    90                 if (nodeAtFrame != null) {
    91                         for (Map.Entry<ValueControl, Object> e : nodeAtFrame.localChanges.entrySet()) {
    92                                 values.put(e.getKey(), e.getValue());
    93                         }
     91                for (Map.Entry<String, Control> e : controls.entrySet()) {
     92                        e.getValue().refreshState();
    9493                }
    9594
    96                 for (Map.Entry<ValueControl, Object> e : values.entrySet()) {
    97                         e.getKey().pushValueToUserInterface(e.getValue());
    98                 }
    9995                refreshControlButtons();
    100                 ObjectPanel.this.revalidate();
    101 
     96                // ObjectPanel.this.revalidate();
    10297        }
    10398
     
    105100        public String getTitle() {
    106101                return "Properties";
    107         }
    108 
    109         @Override
    110         public JPanel getPanelForControls() {
    111                 return contentPanel;
    112102        }
    113103
     
    122112        }
    123113
     114        @Override
     115        public boolean onValueChange(ValueControl control, Object newValue) {
     116                if (currentPath == null) {
     117                        return true;
     118                }
     119                boolean result = treeAtFrame.changeValue(currentPath.assureResolved().getTopObject(), control, newValue);
     120                refreshControlButtons();
     121                return result;
     122        }
     123
    124124}
  • java/main/src/main/java/com/framsticks/gui/StatusBar.java

    r100 r101  
    1515import com.framsticks.util.FramsticksException;
    1616import com.framsticks.util.dispatching.Dispatcher;
     17import com.framsticks.util.dispatching.Dispatching;
    1718import com.framsticks.util.dispatching.ExceptionResultHandler;
    1819import com.framsticks.util.dispatching.RunAt;
    1920
    20 public class StatusBar implements ExceptionResultHandler, Dispatcher<StatusBar> {
     21public class StatusBar implements ExceptionResultHandler {
    2122        private static final Logger log = LogManager.getLogger(StatusBar.class);
    2223
     
    2425        protected JPanel swing;
    2526        protected ExceptionResultHandler exceptionHandler;
     27        protected final Dispatcher<?> dispatcher;
    2628
    2729        /**
    2830         *
    2931         */
    30         public StatusBar() {
     32        public StatusBar(Dispatcher<?> dispatcher) {
     33                this.dispatcher = dispatcher;
     34        }
     35
     36        @SuppressWarnings({"rawtypes", "unchecked"})
     37        public void showInfo(final Object value) {
     38                Dispatching.dispatchIfNotActive(dispatcher, new RunAt(this) {
     39
     40                        @Override
     41                        protected void runAt() {
     42                                String text = value.toString();
     43                                log.info("info: {}", text);
     44                                statusBar.setText(text);
     45
     46                        }
     47                });
    3148        }
    3249
    3350        @Override
     51        @SuppressWarnings({"rawtypes", "unchecked"})
    3452        public void handle(final FramsticksException exception) {
    35                 dispatch(new RunAt<StatusBar>(this) {
     53                dispatcher.dispatch(new RunAt(this) {
    3654
    3755                        @Override
     
    5876        }
    5977
    60         @Override
    61         public boolean isActive() {
    62                 return SwingDispatcher.getInstance().isActive();
    63         }
    64 
    65         @Override
    66         public void dispatch(RunAt<? extends StatusBar> runnable) {
    67                 SwingDispatcher.getInstance().dispatch(runnable);
    68         }
    69 
    7078        /**
    7179         * @return the swing
  • java/main/src/main/java/com/framsticks/gui/SwingDispatcher.java

    r98 r101  
    11package com.framsticks.gui;
    22
    3 import java.awt.event.ActionEvent;
    4 import java.awt.event.ActionListener;
    53
    64import com.framsticks.util.dispatching.AbstractJoinable;
    75import com.framsticks.util.dispatching.Dispatcher;
    8 import com.framsticks.util.dispatching.JoinableDispatcher;
    9 import com.framsticks.util.dispatching.Task;
    106import com.framsticks.util.dispatching.ThrowExceptionHandler;
    117
     
    1612 * @author Piotr Sniegowski
    1713 */
    18 public class SwingDispatcher<C> extends AbstractJoinable implements JoinableDispatcher<C> {
     14public class SwingDispatcher<C> extends AbstractJoinable implements Dispatcher<C> {
    1915
    2016        @SuppressWarnings("rawtypes")
     
    4238        @Override
    4339        public final void dispatch(RunAt<? extends C> runnable) {
    44                 if (runnable instanceof Task) {
    45                         final Task<?> task = (Task<?>) runnable;
    46                         Timer timer = new Timer(0, null);
    47                         timer.addActionListener(new ActionListener() {
    48 
    49                                 @Override
    50                                 public void actionPerformed(ActionEvent event) {
    51                                         task.run();
    52                                 }
    53 
    54                         });
    55                         timer.setInitialDelay((int) (task.getMoment() - System.currentTimeMillis()));
    56                         timer.setRepeats(false);
    57                         timer.start();
    58                         return;
    59                 }
    6040                SwingUtilities.invokeLater(runnable);
    6141        }
     
    7353        @Override
    7454        protected void joinableInterrupt() {
    75                 finish();
     55                finishJoinable();
    7656        }
    7757
  • java/main/src/main/java/com/framsticks/gui/TreeAtFrame.java

    r100 r101  
    44import org.apache.logging.log4j.LogManager;
    55
     6import com.framsticks.core.SideNoteKey;
    67import com.framsticks.core.Tree;
    78import com.framsticks.core.Node;
    89import com.framsticks.core.Path;
    9 import com.framsticks.core.TreeOperations;
     10import static com.framsticks.core.TreeOperations.*;
    1011import com.framsticks.gui.controls.ValueControl;
    1112import com.framsticks.params.CompositeParam;
    1213import com.framsticks.params.FramsClass;
     14import com.framsticks.params.PrimitiveParam;
    1315
    1416import java.util.*;
     
    3032        protected Node rootNode;
    3133
     34        protected final SideNoteKey<UserChanges> userChangesKey = SideNoteKey.make(UserChanges.class);
     35
    3236        public TreeAtFrame(Tree tree, Frame frame) {
    3337                this.frame = frame;
     
    4448        public Tree getTree() {
    4549                return tree;
     50        }
     51
     52        /**
     53         * @return the userChangesKey
     54         */
     55        public SideNoteKey<UserChanges> getUserChangesKey() {
     56                return userChangesKey;
    4657        }
    4758
     
    7182                if (panels.isEmpty()) {
    7283                        panel = new EmptyTreePanel(parameters);
    73                 } else  if (panels.size() == 1) {
     84                } else  if (panels.size() == 1) {
    7485                        panel = panels.get(0);
    7586                } else {
     
    8394        }
    8495
    85 
    86         public boolean hasLocalChanges(Object object) {
    87                 NodeAtFrame nodeAtFrame = tree.getSideNote(object, this, NodeAtFrame.class);
    88                 if (nodeAtFrame == null) {
    89                         return false;
    90                 }
    91                 return !nodeAtFrame.localChanges.isEmpty();
    92         }
    93 
    94         public NodeAtFrame assureLocalInfo(Object object) {
    95                 assert frame.isActive();
    96                 NodeAtFrame nodeAtFrame = tree.getSideNote(object, this, NodeAtFrame.class);
    97 
    98                 if (nodeAtFrame == null) {
    99                         nodeAtFrame = new NodeAtFrame();
    100                         // log.debug();
    101                         tree.putSideNote(object, this, nodeAtFrame);
    102                 }
    103                 return nodeAtFrame;
    104         }
    105 
    106         public NodeAtFrame getLocalInfo(Object object) {
    107                 return tree.getSideNote(object, this, NodeAtFrame.class);
    108         }
    109 
    11096        public boolean changeValue(Object object, ValueControl component, Object newValue) {
    11197                log.debug("changing value of {} to '{}'", component, newValue);
    11298
    113                 assureLocalInfo(object).localChanges.put(component, newValue);
     99                getOrCreateSideNote(tree, object, userChangesKey).changes.put(component.getParam().getId(), newValue);
    114100
    115101                return true;
    116102        }
    117103
    118         public void pushLocalChanges(Path path) {
     104
     105        public void pushUserChangesToTree(final Path path) {
    119106                assert frame.isActive();
    120107                path.assureResolved();
    121108
    122                 NodeAtFrame nodeAtFrame = getLocalInfo(path.getTopObject());
    123                 if (nodeAtFrame == null) {
     109                final UserChanges userChanges = getSideNote(path, userChangesKey);
     110                if (userChanges == null) {
    124111                        return;
    125112                }
    126                 for (Map.Entry<ValueControl, Object> e : nodeAtFrame.localChanges.entrySet()) {
    127                         TreeOperations.set(path, e.getKey().getParam(), e.getValue(), new FutureHandler<Integer>(frame) {
     113                removeSideNote(path, userChangesKey);
     114
     115                for (final Map.Entry<String, Object> e : userChanges.changes.entrySet()) {
     116                        set(path, getParam(path, e.getKey(), PrimitiveParam.class), e.getValue(), new FutureHandler<Integer>(frame) {
    128117                                @Override
    129118                                protected void result(Integer flag) {
     119                                        assert frame.isActive();
     120                                        userChanges.changes.remove(e.getKey());
    130121                                }
    131122                        });
  • java/main/src/main/java/com/framsticks/gui/TreePanel.java

    r100 r101  
    22
    33import com.framsticks.core.Path;
    4 import com.framsticks.core.TreeOperations;
     4import com.framsticks.core.Tree;
     5import static com.framsticks.core.TreeOperations.*;
    56import com.framsticks.gui.tree.AbstractNode;
    67import com.framsticks.gui.tree.TreeNode;
     
    2829                }
    2930                setCurrentPath(path);
    30                 pullValuesFromLocalToUser(TreeOperations.bindAccess(path));
     31                pullValuesFromLocalToUser(bindAccess(path));
    3132        }
    3233
     
    7980                return treeAtFrame;
    8081        }
    81 
     82        public final Object getCurrentObject() {
     83                assert currentPath != null;
     84                return currentPath.getTopObject();
     85        }
     86        public final Tree getTree() {
     87                assert currentPath != null;
     88                return currentPath.getTree();
     89        }
    8290
    8391        public final String getClassName() {
  • java/main/src/main/java/com/framsticks/gui/controls/CheckBoxControl.java

    r100 r101  
    1010import org.apache.logging.log4j.LogManager;
    1111
     12import com.framsticks.gui.Gui;
    1213import com.framsticks.params.types.BooleanParam;
    1314
     
    3132                });
    3233                this.setMaximumSize(new Dimension(Integer.MAX_VALUE, Control.LINE_HEIGHT));
    33                 addAsOnlyChild(checkBox);
     34                Gui.addLeftToLabel(this, checkBox);
    3435        }
    3536
  • java/main/src/main/java/com/framsticks/gui/controls/Control.java

    r100 r101  
    11package com.framsticks.gui.controls;
    22
    3 import java.awt.BorderLayout;
     3// import java.awt.BorderLayout;
    44
    5 import javax.swing.JComponent;
     5
    66import javax.swing.JPanel;
    77
     8import com.framsticks.core.Path;
    89import com.framsticks.params.ParamFlags;
    910import com.framsticks.params.Param;
    1011import com.framsticks.util.FramsticksException;
     12import com.framsticks.util.Misc;
    1113import com.framsticks.util.dispatching.ExceptionResultHandler;
    1214
     
    5759
    5860        public final boolean isReadonly() {
    59                 return !userEnabled || param.hasFlag(ParamFlags.READONLY);
     61                return !userEnabled || param.hasFlag(ParamFlags.READONLY) || param.hasFlag(ParamFlags.USERREADONLY);
    6062        }
    6163
    62         protected void addAsOnlyChild(JComponent component) {
    63                 this.setLayout(new BorderLayout());
    64                 this.add(component, BorderLayout.CENTER);
    65         }
    6664
    6765        @Override
     
    7472                owner.handle(exception);
    7573        }
     74
     75        public Path getCurrentPath() {
     76                return owner.getCurrentPath();
     77        }
     78
     79        public Path assureCurrentPath() {
     80                return Misc.throwIfNull(owner.getCurrentPath());
     81        }
     82
     83        public void refreshState() {
     84        }
    7685}
  • java/main/src/main/java/com/framsticks/gui/controls/ControlOwner.java

    r100 r101  
    11package com.framsticks.gui.controls;
    22
    3 import javax.swing.JPanel;
    43
    54import com.framsticks.core.Path;
     
    98public interface ControlOwner extends ExceptionResultHandler {
    109
    11         public JPanel getPanelForControls();
    1210        public Path getCurrentPath();
    1311        public Frame getFrame();
     12        public boolean onValueChange(ValueControl control, Object newValue);
    1413
    1514}
  • java/main/src/main/java/com/framsticks/gui/controls/EnumControl.java

    r100 r101  
    11package com.framsticks.gui.controls;
    22
     3import com.framsticks.gui.Gui;
    34import com.framsticks.params.types.EnumParam;
    45import com.framsticks.util.lang.Numbers;
     
    3536                        }
    3637                });
    37                 addAsOnlyChild(list);
     38                Gui.addLeftToLabel(this, list);
    3839        }
    3940
  • java/main/src/main/java/com/framsticks/gui/controls/EventControl.java

    r100 r101  
    11package com.framsticks.gui.controls;
    22
    3 import java.awt.Dimension;
    43import java.awt.event.ActionEvent;
    54import java.awt.event.ActionListener;
    6 
    7 import javax.swing.JButton;
    8 
     5import java.text.SimpleDateFormat;
     6import java.util.ArrayList;
     7import java.util.Date;
     8import java.util.List;
     9
     10
     11
     12import com.framsticks.core.Path;
     13import com.framsticks.core.SideNoteKey;
     14import com.framsticks.gui.Frame;
     15import com.framsticks.gui.Gui;
     16import com.framsticks.gui.table.AbstractTableModel;
     17import com.framsticks.params.EventListener;
    918import com.framsticks.params.types.EventParam;
     19import com.framsticks.util.FramsticksUnsupportedOperationException;
     20import com.framsticks.util.dispatching.Dispatching;
     21import com.framsticks.util.dispatching.FutureHandler;
     22import com.framsticks.util.dispatching.RunAt;
     23import com.framsticks.util.lang.Pair;
     24
     25import static com.framsticks.core.TreeOperations.*;
    1026
    1127/**
     
    1329 */
    1430@SuppressWarnings("serial")
    15 public class EventControl extends Control {
     31public class EventControl extends HistoryControl {
    1632        // private static final Logger log = LogManager.getLogger(EventControl.class.getName());
    1733
    18         protected final JButton button;
    19         boolean subscribed = true;
     34        @SuppressWarnings("rawtypes")
     35        protected final SideNoteKey<EventListener> listenerKey = SideNoteKey.make(EventListener.class);
     36
     37        public static class History {
     38                protected final List<Pair<Date, Object>> entries = new ArrayList<>();
     39        };
     40
     41        protected final SideNoteKey<History> historyKey = SideNoteKey.make(History.class);
     42        protected TableModel tableModel;
    2043
    2144        public EventControl(final EventParam eventParam) {
    2245                super(eventParam);
    2346
    24                 button = new JButton("subscribe");
    25                 this.add(button);
    26                 this.setMaximumSize(new Dimension(Integer.MAX_VALUE, Control.LINE_HEIGHT));
    27 
    28                 button.addActionListener(new ActionListener() {
     47                mainButton.setText("Subscribe");
     48                mainButton.setName("subscription");
     49
     50                tableModel = new TableModel();
     51                resultsTable.setModel(tableModel);
     52
     53                mainButton.addActionListener(new ActionListener() {
    2954                        @Override
    3055                        public void actionPerformed(ActionEvent e) {
    31                                 if (subscribed) {
    32                                         //panel.getCurrentTreeNode().unsubscribe(eventParam);
    33                                 } else {
    34                                         //panel.getCurrentTreeNode().subscribe(eventParam);
     56                                final Path path = assureCurrentPath();
     57                                EventListener<?> listener = getSideNote(path, listenerKey);
     58                                if (listener != null) {
     59                                        removeSideNote(path, listenerKey);
     60                                        refreshState();
     61                                        path.getTree().removeListener(path, getParam(), listener, FutureHandler.doNothing(Void.class, owner.getFrame()));
     62                                        return;
    3563                                }
     64
     65                                final EventListener<Object> newListener = new EventListener<Object>() {
     66                                        @Override
     67                                        public void action(final Object argument) {
     68                                                /** actions can be invoked from anywhere */
     69                                                Dispatching.dispatchIfNotActive(owner.getFrame(), new RunAt<Frame>(owner.getFrame()) {
     70
     71                                                        @Override
     72                                                        protected void runAt() {
     73                                                                getOrCreateSideNote(path.getTree(), path.getTopObject(), historyKey).entries.add(Pair.make(new Date(), argument));
     74                                                                refreshTable();
     75                                                        }
     76                                                });
     77                                                // owner.getFrame().getStatusBar().showInfo("event " + param + " happened: " + argument);
     78                                        }
     79                                };
     80
     81                                path.getTree().addListener(path, getParam(), newListener, Object.class, new FutureHandler<Void>(owner.getFrame()) {
     82
     83                                        @Override
     84                                        protected void result(Void result) {
     85                                                putSideNote(path, listenerKey, newListener);
     86                                                refreshState();
     87                                        }
     88                                });
     89
    3690                        }
    3791                });
    3892
     93                updateFoldState();
     94                Gui.setupTitledControl(this, controlRow, resultsScrollPane);
    3995        }
    4096
    4197        @Override
    4298        protected void updateEnabled(boolean enabled) {
    43                 button.setEnabled(enabled);
    44         }
    45 
    46         /*
    47         @Override
    48         public void refresh() {
    49                 subscribed = panel.getCurrentTreeNode().hasSubscribed((EventParam)param);
    50                 button.setText(subscribed ? "unsubscribe" : "subscribe");
    51                 this.revalidate();
    52         }
    53         */
     99                mainButton.setEnabled(enabled);
     100        }
     101
     102        public boolean isListening() {
     103                return hasSideNote(getCurrentPath(), listenerKey);
     104        }
     105
     106        protected void refreshButtonState() {
     107                mainButton.setText(isListening() ? "Don't listen" : "Listen");
     108        }
     109
     110        @Override
     111        protected void refreshTable() {
     112                History history = getSideNote(assureCurrentPath(), historyKey);
     113                tableModel.entries = history != null ? history.entries : null;
     114                tableModel.refreshAll();
     115        }
     116
     117        @Override
     118        protected void clearTable() {
     119                History history = getSideNote(assureCurrentPath(), historyKey);
     120                if (history != null) {
     121                        history.entries.clear();
     122                }
     123                refreshTable();
     124        }
     125
     126        public void refreshState() {
     127                refreshButtonState();
     128                refreshTable();
     129        }
     130
     131        @Override
     132        public EventParam getParam() {
     133                return (EventParam) param;
     134        }
     135
     136
     137        public class TableModel extends AbstractTableModel {
     138
     139                List<Pair<Date, Object>> entries;
     140                SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss:SSS");
     141
     142                @Override
     143                public Class<?> getColumnClass(int columnIndex) {
     144                        return String.class;
     145                }
     146
     147                @Override
     148                public int getColumnCount() {
     149                        return 2;
     150                }
     151
     152                @Override
     153                public String getColumnName(int columnIndex) {
     154                        return columnIndex == 0 ? "Occured at" : "Argument";
     155                }
     156
     157                @Override
     158                public int getRowCount() {
     159                        if (entries == null) {
     160                                return 0;
     161                        }
     162                        if (isFolded()) {
     163                                return entries.isEmpty() ? 0 : 1;
     164                        }
     165                        return entries.size();
     166                }
     167
     168                @Override
     169                public Object getValueAt(int rowIndex, int columnIndex) {
     170                        if (entries == null) {
     171                                return null;
     172                        }
     173                        Pair<Date, Object> entry;
     174                        if (isFolded()) {
     175                                if (rowIndex > 0) {
     176                                        return null;
     177                                }
     178                                if (entries.isEmpty()) {
     179                                        return null;
     180                                }
     181                                entry = entries.get(entries.size() - 1);
     182                        } else {
     183                                entry = entries.get(rowIndex);
     184                        }
     185                        return columnIndex == 0 ? format.format(entry.first) : entry.second;
     186                }
     187
     188                @Override
     189                public boolean isCellEditable(int rowIndex, int columnIndex) {
     190                        return false;
     191                }
     192
     193                @Override
     194                public void setValueAt(Object value, int rowIndex, int columnIndex) {
     195                        throw new FramsticksUnsupportedOperationException().msg("setting value in event history");
     196                }
     197
     198
     199        }
    54200}
  • java/main/src/main/java/com/framsticks/gui/controls/ProcedureControl.java

    r100 r101  
    55import com.framsticks.gui.Gui;
    66import com.framsticks.params.Param;
    7 import com.framsticks.params.ValueParam;
    87import com.framsticks.params.types.ProcedureParam;
    98import com.framsticks.util.dispatching.ExceptionResultHandler;
    109import com.framsticks.util.dispatching.FutureHandler;
    1110import com.framsticks.util.dispatching.ThrowExceptionHandler;
    12 import com.framsticks.util.swing.TooltipConstructor;
    1311
    1412import javax.swing.*;
    15 import javax.swing.border.BevelBorder;
    1613
    1714import org.apache.logging.log4j.Logger;
     
    2017import java.awt.event.ActionEvent;
    2118import java.awt.event.ActionListener;
    22 import java.util.IdentityHashMap;
     19import java.util.HashMap;
    2320import java.util.LinkedList;
    2421import java.util.List;
     
    2623
    2724@SuppressWarnings("serial")
    28 public class ProcedureControl extends Control implements ControlOwner {
     25public class ProcedureControl extends HistoryControl implements ControlOwner {
    2926
    3027        private static final Logger log = LogManager.getLogger(ProcedureControl.class);
    3128
    32         protected final JButton procedureButton;
     29        protected final JPanel argumentsPanel;
    3330
    34         final protected Map<ValueParam, ValueControl> components = new IdentityHashMap<>();
     31        final protected Map<String, ValueControl> components = new HashMap<>();
    3532
    3633        public ProcedureControl(ProcedureParam procedureParam) {
    3734                super(procedureParam);
    3835
    39                 this.setToolTipText(new TooltipConstructor()
    40                         .append("name", procedureParam.getName())
    41                         .append("id", procedureParam.getId())
    42                         .append("help", procedureParam.getHelp())
    43                         .build());
    4436
    45                 procedureButton = new JButton("Call");
    46                 procedureButton.setName("call");
     37                mainButton.setText("Call");
     38                mainButton.setName("call");
    4739
    48                 this.setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
    4940
    50                 Gui.fillWithControls(this, procedureParam.getArgumentsType(), components, ValueControl.class);
     41                argumentsPanel = new JPanel();
     42                argumentsPanel.setName("arguments");
     43
     44                Gui.fillWithControls(this, argumentsPanel, procedureParam.getArgumentsType(), components, ValueControl.class);
    5145
    5246                if (components.size() != procedureParam.getArgumentsType().size()) {
    53                         procedureButton.setEnabled(false);
    54                 }
    55                 if (!components.isEmpty()) {
    56                         this.setBorder(new BevelBorder(BevelBorder.RAISED));
     47                        mainButton.setEnabled(false);
    5748                }
    5849
    59                 procedureButton.addActionListener(new ActionListener() {
     50                mainButton.addActionListener(new ActionListener() {
    6051                        @Override
    6152                        public void actionPerformed(ActionEvent e) {
     
    6556                                final List<Object> arguments = new LinkedList<Object>();
    6657                                for (Param arg : getParam().getArgumentsType()) {
    67                                         Object value = components.get(arg).getCurrentValue();
     58                                        Object value = components.get(arg.getId()).getCurrentValue();
    6859                                        arguments.add(value);
    6960                                        log.debug("argument {}: {}", arg, value);
     
    7465                        }
    7566                });
    76                 this.add(procedureButton);
     67
     68                updateFoldState();
     69                Gui.setupTitledControl(this, argumentsPanel, controlRow, resultsScrollPane);
    7770
    7871        }
     72
    7973
    8074        public static void callProcedure(final Path path, final ProcedureParam param, Object[] arguments) {
     
    9387
    9488        @Override
    95         public JPanel getPanelForControls() {
    96                 return this;
    97         }
    98 
    99         @Override
    10089        public ProcedureParam getParam() {
    10190                return (ProcedureParam) param;
     
    10493        @Override
    10594        protected void updateEnabled(boolean enabled) {
    106                 procedureButton.setEnabled(enabled);
     95                mainButton.setEnabled(enabled);
    10796                for (ValueControl vc : components.values()) {
    10897                        vc.setUserEnabled(enabled);
     
    120109        }
    121110
     111        @Override
     112        public boolean onValueChange(ValueControl control, Object newValue) {
     113                return true;
     114        }
     115
     116        @Override
     117        protected void refreshTable() {
     118                // TODO Auto-generated method stub
     119
     120        }
     121
     122        @Override
     123        protected void clearTable() {
     124                // TODO Auto-generated method stub
     125
     126        }
     127
    122128}
  • java/main/src/main/java/com/framsticks/gui/controls/SliderControl.java

    r100 r101  
    1818import org.apache.logging.log4j.LogManager;
    1919
     20import com.framsticks.gui.Gui;
    2021import com.framsticks.params.types.DecimalParam;
    2122import com.framsticks.params.types.FloatParam;
     
    9899                slider.setPaintTicks(true);
    99100
    100                 this.setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
    101                 this.setAlignmentX(Box.CENTER_ALIGNMENT);
    102                 this.setAlignmentY(Box.CENTER_ALIGNMENT);
    103 
    104                 JPanel sliderPanel = new JPanel();
    105                 // sliderPanel.setLayout(new BoxLayout(sliderPanel, BoxLayout.LINE_AXIS));
     101
    106102
    107103
     
    140136                }));
    141137
    142                 JPanel sVPanel = new JPanel();
    143                 sVPanel.setLayout(new BoxLayout(sVPanel, BoxLayout.LINE_AXIS));
    144                 sVPanel.add(text);
    145                 Layout.copyComponentDimensions(sVPanel, text);
    146 
    147                 JPanel sPanel = new JPanel();
    148                 sPanel.setLayout(new BoxLayout(sPanel, BoxLayout.LINE_AXIS));
    149 
     138                JPanel valuePanel = new JPanel();
     139                valuePanel.setLayout(new BoxLayout(valuePanel, BoxLayout.LINE_AXIS));
     140                valuePanel.add(text);
     141                Layout.copyComponentDimensions(valuePanel, text);
     142
     143
     144                JPanel sliderPanel = new JPanel();
    150145                sliderPanel.setLayout(new BorderLayout());
    151146                sliderPanel.add(slider, BorderLayout.CENTER);
     
    153148                sliderPanel.setMinimumSize(new Dimension(0, 60));
    154149
    155                 sPanel.add(sVPanel);
    156                 sPanel.add(sliderPanel);
    157 
    158                 this.add(sPanel);
     150
     151                this.setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
     152                this.setAlignmentX(Box.CENTER_ALIGNMENT);
     153                this.setAlignmentY(Box.CENTER_ALIGNMENT);
     154
     155                Gui.addLeftToLabel(this, valuePanel, sliderPanel);
    159156        }
    160157
  • java/main/src/main/java/com/framsticks/gui/controls/TextAreaControl.java

    r100 r101  
    11package com.framsticks.gui.controls;
    22
     3import com.framsticks.gui.Gui;
    34import com.framsticks.params.PrimitiveParam;
    45
     
    2728                textArea.setMaximumSize(new Dimension(Integer.MAX_VALUE, maxSize));
    2829
    29                 this.revalidate();
     30                Gui.setupTitledControl(this, textScrollPane);
     31                // this.revalidate();
    3032        }
    3133
  • java/main/src/main/java/com/framsticks/gui/controls/TextFieldControl.java

    r98 r101  
    11package com.framsticks.gui.controls;
    22
     3import com.framsticks.gui.Gui;
    34import com.framsticks.params.PrimitiveParam;
    45import com.framsticks.util.lang.Strings;
     
    3334                addDefaultDocumentListener(textField);
    3435
    35                 addAsOnlyChild(textField);
     36                Gui.addLeftToLabel(this, textField);
    3637        }
    3738
  • java/main/src/main/java/com/framsticks/gui/controls/ValueControl.java

    r100 r101  
    1212import com.framsticks.util.lang.FlagsUtil;
    1313import com.framsticks.util.swing.TooltipConstructor;
     14// import static com.framsticks.core.TreeOperations.*;
    1415
    1516/**
     
    2021        private static final Logger log =
    2122                LogManager.getLogger(ValueControl.class);
    22 
    23         /**
    24          *
    25          */
    26         protected ValueControlListener listener;
    2723
    2824        public ValueControl(PrimitiveParam<?> primitiveParam) {
     
    6460        public abstract Object pullValueFromUserInterface();
    6561
    66         public void setListener(ValueControlListener listener) {
    67                 this.listener = listener;
    68         }
    69 
    7062        protected Object filterValueThroughConstraints(Object candidate) {
    71                 Object oldValue = pullValueFromUserInterface();
     63                Object oldValue = pullValueFromUserInterface();//bindAccess(owner.getCurrentPath()).get(getParam(), Object.class);
    7264                try {
    7365                        ReassignResult<?> res = getParam().reassign(candidate, oldValue);
     
    9284        protected boolean notifyOfChange() {
    9385                if (!programmaticChange) {
    94                         if (listener == null) {
    95                                 return true;
    96                         }
    97                         return listener.onChange(getCurrentValue());
     86                        return owner.onValueChange(this, getCurrentValue());
    9887                }
    9988                return true;
  • java/main/src/main/java/com/framsticks/gui/table/ListPanel.java

    r100 r101  
    5454                table = new JTable(tableModel);
    5555                tableModel.setupTable();
     56                table.setShowGrid(false);
    5657
    5758                scrollPane = new JScrollPane(table);
     
    7273
    7374        @Override
     75        protected void revertChanges() {
     76        }
     77
     78        @Override
    7479        public void pullValuesFromLocalToUser(Access access) {
    7580                tableModel.attachSource(Casting.throwCast(ListAccess.class, access));
     81                refreshControlButtons();
    7682        }
    7783
     
    8793                return table;
    8894        }
     95
    8996}
  • java/main/src/main/java/com/framsticks/gui/table/PrimitiveColumn.java

    r100 r101  
    22
    33import com.framsticks.params.PrimitiveParam;
    4 import com.framsticks.util.UnsupportedOperationException;
     4import com.framsticks.util.FramsticksUnsupportedOperationException;
    55
    66public class PrimitiveColumn extends Column {
     
    3131        @Override
    3232        public int setValueAt(int rowIndex, Object value) {
    33                 throw new UnsupportedOperationException().msg("setting value in table");
     33                throw new FramsticksUnsupportedOperationException().msg("setting value in table");
    3434        }
    3535
  • java/main/src/main/java/com/framsticks/gui/table/TableModel.java

    r100 r101  
    33import java.util.ArrayList;
    44import java.util.Collections;
    5 import java.util.LinkedList;
    65import java.util.List;
    76
     
    109import javax.swing.JTable;
    1110import javax.swing.UIManager;
    12 import javax.swing.event.TableModelEvent;
    13 import javax.swing.event.TableModelListener;
    1411
    1512import org.apache.logging.log4j.Logger;
     
    2320import com.framsticks.util.lang.Casting;
    2421
    25 public class TableModel implements javax.swing.table.TableModel {
     22public class TableModel extends AbstractTableModel {
    2623
    2724        private static final Logger log = LogManager.getLogger(TableModel.class);
    2825
    29         protected List<TableModelListener> listeners = new LinkedList<>();
    3026        protected ListAccess access;
    3127        protected Access elementAccess;
     
    5248        }
    5349
    54         protected void refreshAll() {
    55                 for (TableModelListener l : listeners) {
    56                         l.tableChanged(new TableModelEvent(this));
    57                 }
    58         }
    5950
    6051        /**
     
    7465        }
    7566
    76         @Override
    77         public void addTableModelListener(TableModelListener listener) {
    78                 listeners.add(listener);
    79         }
    8067
    8168        @Override
     
    114101        }
    115102
    116         @Override
    117         public void removeTableModelListener(TableModelListener listener) {
    118                 listeners.remove(listener);
    119         }
    120103
    121104
  • java/main/src/main/java/com/framsticks/gui/tree/TreeModel.java

    r100 r101  
    1717import com.framsticks.core.Node;
    1818import com.framsticks.core.Path;
     19import com.framsticks.core.SideNoteKey;
    1920import com.framsticks.core.TreeOperations;
    2021import com.framsticks.gui.Frame;
     
    2425import com.framsticks.params.ListAccess;
    2526import com.framsticks.params.PrimitiveParam;
    26 import com.framsticks.params.Util;
     27import com.framsticks.params.ParamsUtil;
    2728import com.framsticks.params.ValueParam;
    2829import com.framsticks.params.types.EventParam;
    2930import com.framsticks.util.FramsticksException;
    3031import com.framsticks.util.Misc;
    31 import com.framsticks.util.UnsupportedOperationException;
     32import com.framsticks.util.FramsticksUnsupportedOperationException;
    3233import com.framsticks.util.dispatching.FutureHandler;
    3334import com.framsticks.util.lang.Casting;
     
    9192        @Override
    9293        public void valueForPathChanged(TreePath path, Object value) {
    93                 throw new UnsupportedOperationException().msg("changing value of tree node");
     94                throw new FramsticksUnsupportedOperationException().msg("changing value of tree node");
    9495        }
    9596
     
    133134        public TreeModelEvent prepareModelEventRegarding(Access access, String id, TreePath treeListPath) {
    134135
    135                 int number = Util.getNumberOfCompositeParamChild(access, access.get(id, Object.class));
     136                int number = ParamsUtil.getNumberOfCompositeParamChild(access, access.get(id, Object.class));
    136137                if (number == -1) {
    137138                        log.debug("encountered minor tree inconsistency in {}", treeListPath);
     
    438439
    439440
    440         protected final Object createdTag = new Object();
     441        protected final SideNoteKey<Boolean> createdTag = SideNoteKey.make(Boolean.class);
    441442
    442443
  • java/main/src/main/java/com/framsticks/gui/tree/TreeNode.java

    r100 r101  
    44import java.util.Iterator;
    55import java.util.LinkedList;
    6 import java.util.List;
    76
    87import org.apache.logging.log4j.LogManager;
     
    1110import com.framsticks.core.Node;
    1211import com.framsticks.core.Path;
     12import com.framsticks.core.SideNoteKey;
    1313import com.framsticks.core.Tree;
    1414import com.framsticks.gui.Frame;
     
    5959                hashCode = System.identityHashCode(path.getTopObject());
    6060
    61                 if (getTree().getSideNote(path.getTopObject(), getTreeModel().createdTag, Object.class) == getTreeModel().createdTag) {
     61                if (isMarked(path.getTree(), path.getTopObject(), getTreeModel().createdTag, false)) {
    6262                        return;
    6363                }
    6464
    6565                // path.getTree().putSideNote(path.getTopObject(), Textual.class, path.getTextual());
    66                 path.getTree().putSideNote(path.getTopObject(), getTreeModel().createdTag, getTreeModel().createdTag);
     66                mark(path.getTree(), path.getTopObject(), getTreeModel().createdTag, true);
    6767
    6868                /** Iterate over all EventParams and for matching ValueParams register listeners. */
     
    239239                }
    240240                Access access = bindAccessForTreeObject(child);
    241                 CompositeParam param = getTree().getSideNote(child, CompositeParam.class, CompositeParam.class);
     241                CompositeParam param = getTree().getSideNote(child, Path.OBJECT_PARAM_KEY);
    242242                String name = param.getId();
    243243
     
    262262        }
    263263
    264         // public static class Textual {
    265         // }
    266264
    267265        public String getTextual() {
    268266                return textual;
    269                 // return getTree().getSideNote(lock(), Textual.class, String.class);
    270         }
    271 
    272         protected final Object listenersTag = new Object();
    273 
    274         public List<EventListener<?>> getListeners() {
    275                 @SuppressWarnings("unchecked")
    276                 List<EventListener<?>> result = getTree().getSideNote(lock(), listenersTag, List.class);
    277                 if (result == null) {
    278                         result = new LinkedList<>();
    279                         getTree().putSideNote(lock(), listenersTag, result);
    280                 }
    281 
    282                 return result;
    283         }
     267        }
     268
     269        @SuppressWarnings("rawtypes")
     270        protected final SideNoteKey<LinkedList> listenersTag = SideNoteKey.make(LinkedList.class);
    284271
    285272        protected <A> void tryAddListener(final Path path, final EventParam eventParam, Class<A> argumentType, final EventListener<A> listener) {
    286273                getTree().addListener(path, eventParam, listener, argumentType, new FutureHandler<Void>(getFrame()) {
     274                        @SuppressWarnings("unchecked")
    287275                        @Override
    288276                        protected void result(Void result) {
    289277                                assert getFrame().isActive();
    290278                                log.debug("registered gui listener for {} at {}", eventParam, path);
    291                                 getListeners().add(listener);
     279                                getOrCreateSideNote(getTree(), lock(), listenersTag).add(listener);
    292280                        }
    293281                });
  • java/main/src/main/java/com/framsticks/hosting/Cli.java

    r100 r101  
    5858                                client.connection.sendFile(
    5959                                                "event " + event.pathToEvent + " " + event.name,
    60                                                 ClientAtServer.printToFile("", tree.getRegistry().createAccess(argument.getClass()).select(argument))
     60                                                ClientAtServer.printToFile("", tree.getRegistry().createAccess(argument.getClass()).select(argument)),
     61                                                null,
     62                                                client
    6163                                        );
    6264                        }
  • java/main/src/main/java/com/framsticks/hosting/Server.java

    r100 r101  
    66
    77import com.framsticks.core.Tree;
     8import com.framsticks.params.ParamFlags;
    89import com.framsticks.params.annotations.AutoAppendAnnotation;
    910import com.framsticks.params.annotations.FramsClassAnnotation;
     
    1718import com.framsticks.util.dispatching.JoinableState;
    1819import com.framsticks.util.dispatching.RunAt;
    19 import com.framsticks.util.dispatching.Task;
    2020import com.framsticks.util.dispatching.ThrowExceptionHandler;
    2121
     
    2424import java.net.ServerSocket;
    2525import java.net.Socket;
     26import java.util.TimerTask;
     27
    2628import com.framsticks.util.dispatching.Thread;
    2729
     
    6163         * @param port the port to set
    6264         */
    63         @ParamAnnotation
     65        @ParamAnnotation(flags = ParamFlags.USERREADONLY)
    6466        public void setPort(int port) {
    6567                this.port = port;
     
    7678                        log.debug("exception caught during socket closing: ", e);
    7779                }
    78                 finish();
     80                finishJoinable();
    7981        }
    8082
     
    150152
    151153        protected void tryBind(int when) {
    152                 acceptThread.dispatch(new Task<Accept>(ThrowExceptionHandler.getInstance(), when) {
     154                Dispatching.getTimer().schedule(new TimerTask() {
     155
    153156                        @Override
    154                         protected void runAt() {
    155                                 try {
    156                                         acceptSocket.bind(new InetSocketAddress(port));
    157                                         log.debug("started accepting on port {}", port);
    158                                         acceptNext();
    159                                         return;
    160                                 } catch (IOException e) {
    161                                         log.warn("failed to accept on port {} (repeating): ", port, e);
    162                                 }
    163                                 tryBind(1000);
     157                        public void run() {
     158                                acceptThread.dispatch(new RunAt<Accept>(ThrowExceptionHandler.getInstance()) {
     159                                        @Override
     160                                        protected void runAt() {
     161                                                try {
     162                                                        acceptSocket.bind(new InetSocketAddress(port));
     163                                                        log.debug("started accepting on port {}", port);
     164                                                        acceptNext();
     165                                                        return;
     166                                                } catch (IOException e) {
     167                                                        log.warn("failed to accept on port {} (repeating): ", port, e);
     168                                                }
     169                                                tryBind(1000);
     170                                        }
     171                                });
    164172                        }
    165                 });
     173
     174                }, when);
    166175        }
    167176
     
    178187        }
    179188
    180         // @Override
    181         // public FramsClass getInfoFromCache(String id) {
    182         //      assert isActive();
    183         //      if (id == null) {
    184         //              return null;
    185         //      }
    186         //      FramsClass cached = registry.getFramsClass(id);
    187         //      if (cached != null) {
    188         //              return cached;
    189         //      }
    190         //      try {
    191         //              Class<?> nativeClass = Class.forName(id);
    192         //              FramsClass framsClass = FramsClass.build().forClass(nativeClass);
    193 
    194         //              if (!framsClass.getId().equals(id)) {
    195         //                      log.error("no matching id");
    196         //                      return null;
    197         //              }
    198 
    199         //              registry.registerReflectedClass(null, id, nativeClass);
    200         //              registry.putFramsClass(framsClass);
    201         //              return framsClass;
    202         //      } catch (ClassNotFoundException ignored) {
    203         //      } catch (ConstructionException e) {
    204         //              log.error("failed to use info from cache: {}", e);
    205         //      }
    206 
    207         //      return null;
    208         // }
    209 
    210         // @Override
    211         // protected void fetchInfo(Path path, Future<FramsClass> future) {
    212         //      assert isActive();
    213 
    214         //      FramsClass framsClass = getInfoFromCache(path.getTop().getObject().getClass().getCanonicalName());
    215         //      if (framsClass == null) {
    216         //              log.error("failed to create frams class for: {}", path.getTop().getObject().getClass());
    217         //              future.result(null, new Exception());
    218         //              return;
    219         //      }
    220         //      future.result(framsClass, null);
    221         // }
    222189}
  • java/main/src/main/java/com/framsticks/model/ModelBuilder.java

    r100 r101  
    77
    88import com.framsticks.model.f0.Schema;
    9 import com.framsticks.params.Util;
     9import com.framsticks.params.ParamsUtil;
    1010import com.framsticks.params.annotations.AutoAppendAnnotation;
    1111import com.framsticks.params.annotations.FramsClassAnnotation;
     
    3535                        }
    3636                        F0Parser parser = new F0Parser(schema, stream);
    37                         components.addAll(Util.stripAccess(parser.parse(), ModelComponent.class));
     37                        components.addAll(ParamsUtil.stripAccess(parser.parse(), ModelComponent.class));
    3838                }
    3939                return build();
  • java/main/src/main/java/com/framsticks/params/Access.java

    r100 r101  
    4444        void regRemove(EventParam param, EventListener<?> listener);
    4545
    46         void setDefault(boolean numericOnly);
    47 
    48         void setDefault(int i, boolean numericOnly);
    49 
    50         void setMin();
    51 
    52         void setMin(int i);
    53 
    54         void setMax();
    55 
    56         void setMax(int i);
    57 
    5846        void save(SinkInterface sink);
    59 
    60         void load(SourceInterface stream);
    6147
    6248        /**
     
    6955        Object getSelected();
    7056
    71         Access cloneAccess() throws ConstructionException;
     57        Access cloneAccess();
    7258
    7359        Object createAccessee();
  • java/main/src/main/java/com/framsticks/params/ArrayListAccess.java

    r100 r101  
    2424
    2525        @Override
    26         public ArrayListAccess cloneAccess() throws ConstructionException {
     26        public ArrayListAccess cloneAccess() {
    2727                return new ArrayListAccess(elementAccess.cloneAccess());
    2828        }
     
    124124        @Override
    125125        public ArrayListAccess select(Object object) {
    126                 list = Util.selectObjectForAccess(this, object, List.class);
     126                list = ParamsUtil.selectObjectForAccess(this, object, List.class);
    127127                return this;
    128128        }
  • java/main/src/main/java/com/framsticks/params/FramsClassBuilder.java

    r100 r101  
    55import java.lang.reflect.Member;
    66import java.lang.reflect.Method;
    7 import java.lang.reflect.ParameterizedType;
    8 import java.lang.reflect.Type;
    97import java.util.ArrayList;
    108import java.util.Collections;
     
    4038        }
    4139
    42         public static ParamBuilder induceParamType(ParamBuilder builder, Type type) {
    43                 // if (type.equals(Void.TYPE)) {
    44                 //      throw new ConstructionException().msg("void is not a valid type");
    45                 // }
    46 
    47                 if (type instanceof ParameterizedType) {
    48                         ParameterizedType p = (ParameterizedType) type;
    49                         Type rawType = p.getRawType();
    50                         Type containedType = null;
    51                         //TODO make implementation here
    52                         boolean map = false;
    53                         StringBuilder b = new StringBuilder();
    54                         if (rawType.equals(Map.class)) {
    55                                 containedType = p.getActualTypeArguments()[1];
    56                                 map = true;
    57                                 b.append("l");
    58                         } else if (rawType.equals(List.class)) {
    59                                 containedType = p.getActualTypeArguments()[0];
    60                                 b.append("l");
    61                         } else if (rawType.equals(EventListener.class)) {
    62                                 containedType = p.getActualTypeArguments()[0];
    63                                 b.append("e");
    64                         }
    65                         if (!(containedType instanceof Class)) {
    66                                 return builder;
    67                         }
    68                         b.append(" ");
    69 
    70                         Class<?> containedClass = (Class<?>) containedType;
    71                         FramsClassAnnotation fca = containedClass.getAnnotation(FramsClassAnnotation.class);
    72                         if (fca == null) {
    73                                 throw new ConstructionException().msg("the contained class is not annotated").arg("class", containedClass);
    74                         }
    75                         b.append(getName(fca, containedClass));
    76                         //TODO parametrize this
    77                         if (map) {
    78                                 b.append(" uid");
    79                         }
    80 
    81                         builder.type(b.toString());
    82                         return builder;
    83                 }
    84 
    85                 if (type instanceof Class) {
    86 
    87                         Class<?> cl = (Class<?>) type;
    88 
    89                         // TODO: future support for enum
    90                         // if (cl.isEnum()) {
    91                         //      Class<? extends Enum<?>> enumType = (Class<? extends Enum<?>>) cl;
    92                         //      Enum<?>[] enums = enumType.getEnumConstants();
    93                         //      StringBuilder b = new StringBuilder();
    94 
    95                         //      b.append("d 0 ").append(enums.length - 1).append(" 0 ");
    96                         //      for (Enum<?> e : enums) {
    97                         //              b.append("~").append(e.name());
    98                         //      }
    99                         //      return b.toString();
    100                         // }
    101                         if (cl.equals(Integer.class) || cl.equals(int.class)) {
    102                                 builder.type("d");
    103                                 return builder;
    104                         }
    105                         if (cl.equals(String.class)) {
    106                                 builder.type("s");
    107                                 return builder;
    108                         }
    109                         if (cl.equals(Double.class) || cl.equals(double.class)) {
    110                                 builder.type("f");
    111                                 return builder;
    112                         }
    113                         if (cl.equals(Boolean.class) || cl.equals(boolean.class)) {
    114                                 builder.type( "d 0 1");
    115                                 return builder;
    116                         }
    117                         if (cl.equals(Object.class)) {
    118                                 builder.type("x");
    119                                 return builder;
    120                         }
    121 
    122 
    123                         // builder.type("o " + (cl).getCanonicalName());
    124                         builder.type("o " + cl.getSimpleName());
    125                         builder.fillStorageType(cl);
    126                         return builder;
    127                 }
    128 
    129                 throw new ConstructionException().msg("failed to find framsticks for native type").arg("type", type);
    130         }
    131 
    132 
    133         public static ParamBuilder induceParamType(ParamBuilder builder, ParamCandidate candidate) {
    134                 Method method = candidate.getCaller();
    135                 if (method == null) {
    136                         return induceParamType(builder, candidate.getType());
    137                 }
    138 
    139                 if (!method.getReturnType().equals(Void.TYPE)) {
    140                         builder.resultType(induceParamType(Param.build(), method.getGenericReturnType()).finish(ValueParam.class));
    141                 }
    142 
    143                 List<ValueParam> arguments = new ArrayList<>();
    144                 int number = 0;
    145                 for (Type arg : method.getGenericParameterTypes()) {
    146                         arguments.add(induceParamType(Param.build(), arg).idAndName("arg" + (number++)).finish(ValueParam.class));
    147                 }
    148                 builder.argumentsType(arguments);
    149 
    150                 return builder;
    151         }
    15240
    15341        public static final String GENERATE_HELP_PREFIX = "automatically generated from: ";
     
    238126                        ParamBuilder builder = Param.build().id(pc.getId()).name(pc.getName()).flags(pc.getFlags());
    239127
    240                         induceParamType(builder, pc);
     128                        pc.induceParamType(builder);
    241129
    242130                        for (ParamAnnotation pa : pc.getAnnotations()) {
     
    365253        }
    366254
     255
     256
    367257}
  • java/main/src/main/java/com/framsticks/params/InvalidOperationException.java

    r99 r101  
    11package com.framsticks.params;
    22
    3 import com.framsticks.util.UnsupportedOperationException;
     3import com.framsticks.util.FramsticksUnsupportedOperationException;
    44
    55@SuppressWarnings("serial")
    6 public class InvalidOperationException extends UnsupportedOperationException {
     6public class InvalidOperationException extends FramsticksUnsupportedOperationException {
    77
    88}
  • java/main/src/main/java/com/framsticks/params/ListAccess.java

    r100 r101  
    77import com.framsticks.params.types.EventParam;
    88import com.framsticks.params.types.ProcedureParam;
    9 import com.framsticks.util.UnimplementedException;
    109
    1110/**
     
    3029        // }
    3130
    32         @Override
    33         public void setDefault(boolean numericOnly) {
    34         }
    35 
    36         @Override
    37         public void setDefault(int i, boolean numericOnly) {
    38         }
    39 
    40         @Override
    41         public void setMin() {
    42         }
    43 
    44         @Override
    45         public void setMin(int i) {
    46         }
    47 
    48         @Override
    49         public void setMax() {
    50         }
    51 
    52         @Override
    53         public void setMax(int i) {
    54         }
    5531
    5632        @Override
     
    6339                        elementAccess.save(sink);
    6440                }
    65         }
    66 
    67         @Override
    68         public void load(SourceInterface stream) {
    69                 throw new UnimplementedException().msg("load in list access");
    7041        }
    7142
  • java/main/src/main/java/com/framsticks/params/ListSource.java

    r86 r101  
    55import java.util.List;
    66
    7 public class ListSource implements SourceInterface {
     7public class ListSource implements Source {
    88
    99        private Iterator<String> iterator = null;
    10         //private final List<String> source;
     10        private final List<String> list;
    1111
    12         public ListSource(List<String> source) {
    13                 //this.source = source;
    14                 iterator = source.iterator();
     12        public ListSource(List<String> list) {
     13                this.list = list;
     14                iterator = list.iterator();
    1515        }
    1616
     
    3838
    3939        @Override
    40         public SourceInterface openInclude(String include) {
     40        public Source openInclude(String include) {
    4141                return null;
    4242        }
     
    5959                return iterator == null;
    6060        }
     61
     62        @Override
     63        public String toString() {
     64                if (list.isEmpty()) {
     65                        return "?";
     66                }
     67                StringBuilder b = new StringBuilder();
     68                int print = Math.min(list.size(), 3);
     69                for (int i = 0; i < print; ++i) {
     70                        if (i != 0) {
     71                                b.append(" ");
     72                        }
     73                        b.append(list.get(i));
     74                }
     75                return b.toString();
     76        }
     77
    6178}
  • java/main/src/main/java/com/framsticks/params/Param.java

    r99 r101  
    9696        }
    9797
    98         public boolean isUserHidden() {
    99                 return (flags & ParamFlags.USERHIDDEN) != 0;
    100         }
    101 
    10298        public static ParamBuilder build() {
    10399                return new ParamBuilder();
  • java/main/src/main/java/com/framsticks/params/ParamCandidate.java

    r100 r101  
    1010import java.lang.reflect.ParameterizedType;
    1111import java.lang.reflect.Type;
     12import java.util.ArrayList;
    1213import java.util.Arrays;
    1314import java.util.Collection;
     
    1516import java.util.Comparator;
    1617import java.util.HashMap;
     18import java.util.HashSet;
     19import java.util.IdentityHashMap;
    1720import java.util.LinkedList;
    1821import java.util.List;
     
    7578        protected final OneTime<Method> adder = new OneTime<>("adder");
    7679        protected final OneTime<Method> remover = new OneTime<>("remover");
     80        protected int flags = 0;
    7781
    7882        protected final List<ParamAnnotation> annotations = new LinkedList<>();
     
    162166        public List<ParamAnnotation> getAnnotations() {
    163167                return Collections.unmodifiableList(annotations);
     168        }
     169
     170        protected final java.util.Set<Class<?>> dependantClasses = new HashSet<>();
     171
     172        // public void addDependantClass(Class<?> javaClass) {
     173        //      dependantClasses.add(javaClass);
     174        // }
     175
     176        /**
     177         * @return the dependantClasses
     178         */
     179        public java.util.Set<Class<?>> getDependantClasses() {
     180                return Collections.unmodifiableSet(dependantClasses);
    164181        }
    165182
     
    247264                this.name.set(name);
    248265                annotations.add(paramAnnotation);
     266                flags |= paramAnnotation.flags();
    249267                if (member instanceof Field) {
    250268                        field.set((Field) member);
     
    299317
    300318        public int getFlags() {
    301                 int f = 0;
     319                int f = flags;
    302320                if (isReadOnly()) {
    303321                        f |= ParamFlags.READONLY;
     
    341359                protected final Map<String, ParamCandidate> candidates;
    342360                protected final List<ParamCandidate> order;
     361                protected final java.util.Set<Class<?>> dependantClasses = new HashSet<>();
    343362
    344363                /**
     
    364383                        return order;
    365384                }
    366         }
     385
     386                public java.util.Set<Class<?>> getDependentClasses() {
     387                        return dependantClasses;
     388                }
     389        }
     390
     391        protected static final Map<Class<?>, Set> setsCache = Collections.synchronizedMap(new IdentityHashMap<Class<?>, Set>());
    367392
    368393        public static Set getAllCandidates(Class<?> javaClass) throws ConstructionException {
     394                Set result = setsCache.get(javaClass);
     395                if (result != null) {
     396                        return result;
     397                }
    369398
    370399                List<Class<?>> javaClasses = new LinkedList<>();
     
    374403                }
    375404
    376                 Set resultSet = new Set(new HashMap<String, ParamCandidate>(), new LinkedList<ParamCandidate>());
     405                result = new Set(new HashMap<String, ParamCandidate>(), new LinkedList<ParamCandidate>());
    377406
    378407                for (Class<?> j : javaClasses) {
    379                         Set set = new Set(resultSet.getCandidates(), new LinkedList<ParamCandidate>());
     408                        Set set = new Set(result.getCandidates(), new LinkedList<ParamCandidate>());
     409
    380410                        filterParamsCandidates(set, j.getDeclaredFields());
    381411                        filterParamsCandidates(set, j.getDeclaredMethods());
     
    383413                        FramsClassAnnotation fa = j.getAnnotation(FramsClassAnnotation.class);
    384414                        if (fa != null) {
     415
     416                                if (j != javaClass) {
     417                                        result.dependantClasses.add(j);
     418                                }
     419                                for (Class<?> r : fa.register()) {
     420                                        result.dependantClasses.add(r);
     421                                }
     422
     423
    385424                                final List<String> order = Arrays.asList(fa.order());
    386425                                Collections.sort(set.getOrder(), new Comparator<ParamCandidate>() {
     
    396435                                });
    397436                        }
    398                         resultSet.getOrder().addAll(0, set.getOrder());
    399                 }
    400 
    401                 for (ParamCandidate pc : resultSet.getOrder()) {
     437                        result.getOrder().addAll(0, set.getOrder());
     438                }
     439
     440                for (ParamCandidate pc : result.getOrder()) {
    402441                        pc.validate();
    403                 }
    404 
    405                 return resultSet;
     442                        pc.induceParamType(Param.build());
     443                        result.dependantClasses.addAll(pc.getDependantClasses());
     444                }
     445
     446                setsCache.put(javaClass, result);
     447
     448                return result;
    406449        }
    407450
     
    425468        }
    426469
     470        protected ParamBuilder induceParamType(ParamBuilder builder, Type type) {
     471                // if (type.equals(Void.TYPE)) {
     472                //      throw new ConstructionException().msg("void is not a valid type");
     473                // }
     474
     475                if (type instanceof ParameterizedType) {
     476                        ParameterizedType p = (ParameterizedType) type;
     477                        Type rawType = p.getRawType();
     478                        Type containedType = null;
     479                        //TODO make implementation here
     480                        boolean map = false;
     481                        StringBuilder b = new StringBuilder();
     482                        if (rawType.equals(Map.class)) {
     483                                containedType = p.getActualTypeArguments()[1];
     484                                map = true;
     485                                b.append("l");
     486                        } else if (rawType.equals(List.class)) {
     487                                containedType = p.getActualTypeArguments()[0];
     488                                b.append("l");
     489                        } else if (rawType.equals(EventListener.class)) {
     490                                containedType = p.getActualTypeArguments()[0];
     491                                b.append("e");
     492                        }
     493                        if (!(containedType instanceof Class)) {
     494                                return builder;
     495                        }
     496                        b.append(" ");
     497
     498                        Class<?> containedClass = (Class<?>) containedType;
     499                        FramsClassAnnotation fca = containedClass.getAnnotation(FramsClassAnnotation.class);
     500                        if (fca == null) {
     501                                throw new ConstructionException().msg("the contained class is not annotated").arg("class", containedClass);
     502                        }
     503                        dependantClasses.add(containedClass);
     504                        b.append(FramsClassBuilder.getName(fca, containedClass));
     505                        //TODO parameterize this
     506                        if (map) {
     507                                b.append(" uid");
     508                        }
     509
     510                        builder.type(b.toString());
     511                        return builder;
     512                }
     513
     514                if (type instanceof Class) {
     515
     516                        Class<?> cl = (Class<?>) type;
     517
     518                        // TODO: future support for enum
     519                        // if (cl.isEnum()) {
     520                        //      Class<? extends Enum<?>> enumType = (Class<? extends Enum<?>>) cl;
     521                        //      Enum<?>[] enums = enumType.getEnumConstants();
     522                        //      StringBuilder b = new StringBuilder();
     523
     524                        //      b.append("d 0 ").append(enums.length - 1).append(" 0 ");
     525                        //      for (Enum<?> e : enums) {
     526                        //              b.append("~").append(e.name());
     527                        //      }
     528                        //      return b.toString();
     529                        // }
     530                        if (cl.equals(Integer.class) || cl.equals(int.class)) {
     531                                builder.type("d");
     532                                return builder;
     533                        }
     534                        if (cl.equals(String.class)) {
     535                                builder.type("s");
     536                                return builder;
     537                        }
     538                        if (cl.equals(Double.class) || cl.equals(double.class)) {
     539                                builder.type("f");
     540                                return builder;
     541                        }
     542                        if (cl.equals(Boolean.class) || cl.equals(boolean.class)) {
     543                                builder.type( "d 0 1");
     544                                return builder;
     545                        }
     546                        if (cl.equals(Object.class)) {
     547                                builder.type("x");
     548                                return builder;
     549                        }
     550
     551
     552                        // builder.type("o " + (cl).getCanonicalName());
     553                        builder.type("o " + cl.getSimpleName());
     554                        dependantClasses.add(cl);
     555                        builder.fillStorageType(cl);
     556                        return builder;
     557                }
     558
     559                throw new ConstructionException().msg("failed to find framsticks for native type").arg("type", type);
     560        }
     561
     562
     563        public ParamBuilder induceParamType(ParamBuilder builder) {
     564                Method method = getCaller();
     565                if (method == null) {
     566                        return induceParamType(builder, getType());
     567                }
     568
     569                if (!method.getReturnType().equals(Void.TYPE)) {
     570                        builder.resultType(induceParamType(Param.build(), method.getGenericReturnType()).finish(ValueParam.class));
     571                }
     572
     573                List<ValueParam> arguments = new ArrayList<>();
     574                int number = 0;
     575                for (Type arg : method.getGenericParameterTypes()) {
     576                        arguments.add(induceParamType(Param.build(), arg).idAndName("arg" + (number++)).finish(ValueParam.class));
     577                }
     578                builder.argumentsType(arguments);
     579
     580                return builder;
     581        }
     582
    427583};
  • java/main/src/main/java/com/framsticks/params/PropertiesAccess.java

    r100 r101  
    7676        @Override
    7777        public PropertiesAccess select(Object object) {
    78                 properties = Util.selectObjectForAccess(this, object, Map.class);
     78                properties = ParamsUtil.selectObjectForAccess(this, object, Map.class);
    7979                return this;
    8080        }
  • java/main/src/main/java/com/framsticks/params/ReflectionAccess.java

    r100 r101  
    11package com.framsticks.params;
    22
    3 import java.lang.reflect.Field;
    43import java.lang.reflect.InvocationTargetException;
    54import java.lang.reflect.Method;
    6 import java.util.ArrayList;
    7 import java.util.Collections;
    8 import java.util.Comparator;
    9 import java.util.HashMap;
    10 import java.util.IdentityHashMap;
    11 import java.util.List;
    12 import java.util.Map;
    13 
    14 import javax.annotation.concurrent.Immutable;
     5
    156
    167import org.apache.logging.log4j.Logger;
    178import org.apache.logging.log4j.LogManager;
    189
    19 import com.framsticks.params.annotations.AutoAppendAnnotation;
    2010import com.framsticks.params.types.EventParam;
    2111import com.framsticks.params.types.ProcedureParam;
    2212import com.framsticks.util.FramsticksException;
    23 import com.framsticks.util.lang.Pair;
    2413
    2514import static com.framsticks.util.lang.Containers.*;
     
    3726
    3827        protected final Class<?> javaClass;
    39         protected final Backend backend;
     28        protected final ReflectionAccessBackend backend;
    4029
    4130        private Object object;
    42 
    43         @Immutable
    44         public static class Backend {
    45 
    46                 protected static final Map<Pair<Class<?>, FramsClass>, Backend> synchronizedCache = Collections.synchronizedMap(new HashMap<Pair<Class<?>, FramsClass>, Backend>());
    47 
    48 
    49                 public interface ReflectedGetter {
    50                         public <T> T get(Object object, Class<T> type) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException;
    51                 }
    52 
    53                 public interface ReflectedSetter {
    54                         public <T> void set(Object object, T value) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException;
    55                 }
    56 
    57                 public interface ReflectedCaller {
    58                         public Object call(Object object, Object[] arguments) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException;
    59                 }
    60 
    61                 public interface ReflectedAdder{
    62                         public void reg(Object object, EventListener<?> listener) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException;
    63                 }
    64 
    65                 public interface ReflectedRemover{
    66                         public void regRemove(Object object, EventListener<?> listener) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException;
    67                 }
    68 
    69                 protected final Map<ValueParam, ReflectedSetter> setters = new IdentityHashMap<>();
    70                 protected final Map<ValueParam, ReflectedGetter> getters = new IdentityHashMap<>();
    71                 protected final Map<ProcedureParam, ReflectedCaller> callers = new IdentityHashMap<>();
    72                 protected final Map<EventParam, ReflectedAdder> adders = new IdentityHashMap<>();
    73                 protected final Map<EventParam, ReflectedRemover> removers = new IdentityHashMap<>();
    74 
    75                 protected final List<Method> autoAppendMethods = new ArrayList<>();
    76 
    77                 /**
    78                  * @param params
    79                  */
    80                 public Backend() {
    81                 }
    82 
    83                 public static Backend getOrCreateFor(Class<?> reflectedClass, FramsClass framsClass) {
    84 
    85                         Pair<Class<?>, FramsClass> id = new Pair<Class<?>, FramsClass>(reflectedClass, framsClass);
    86                         Backend backend = synchronizedCache.get(id);
    87                         if (backend != null) {
    88                                 return backend;
    89                         }
    90 
    91                         log.debug("constructing backend for {}", id);
    92                         backend = new Backend();
    93 
    94                         Map<String, ParamCandidate> candidates = ParamCandidate.getAllCandidates(reflectedClass).getCandidates();
    95 
    96                         try {
    97                                 for (final ProcedureParam pp : filterInstanceof(framsClass.getParamEntries(), ProcedureParam.class)) {
    98                                         if (!candidates.containsKey(pp.getId())) {
    99                                                 log.trace("java class does implement method {}", pp);
    100                                                 continue;
    101                                         }
    102                                         ParamCandidate pc = candidates.get(pp.getId());
    103                                         final Method method = pc.getCaller();
    104 
    105                                         backend.callers.put(pp, new ReflectedCaller() {
    106 
    107                                                 @Override
    108                                                 public Object call(Object object, Object[] arguments) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
    109                                                         return method.invoke(object, arguments);
    110                                                 }
    111                                         });
    112 
    113                                 }
    114 
    115                                 for (final EventParam ep : filterInstanceof(framsClass.getParamEntries(), EventParam.class)) {
    116                                         if (!candidates.containsKey(ep.getId())) {
    117                                                 log.trace("java class does not implement the event param {}", ep);
    118                                                 continue;
    119                                         }
    120                                         ParamCandidate ec = candidates.get(ep.getId());
    121                                         final Method adder = ec.getAdder();
    122                                         final Method remover = ec.getRemover();
    123 
    124                                         backend.adders.put(ep, new ReflectedAdder() {
    125 
    126                                                 @Override
    127                                                 public void reg(Object object, EventListener<?> listener) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
    128                                                         adder.invoke(object, listener);
    129                                                 }
    130                                         });
    131 
    132                                         backend.removers.put(ep, new ReflectedRemover() {
    133 
    134                                                 @Override
    135                                                 public void regRemove(Object object, EventListener<?> listener) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
    136                                                         remover.invoke(object, listener);
    137                                                 }
    138                                         });
    139                                 }
    140 
    141                                 for (final ValueParam vp : filterInstanceof(framsClass.getParamEntries(), ValueParam.class)) {
    142                                         if (!candidates.containsKey(vp.getId())) {
    143                                                 throw new ConstructionException().msg("missing candidate for param").arg("param", vp);
    144                                         }
    145                                         ParamCandidate pc = candidates.get(vp.getId());
    146                                         if (pc.isReadOnly() && !vp.hasFlag(ParamFlags.READONLY)) {
    147                                                 throw new ConstructionException().msg("readonly state conflict").arg("param", vp);
    148                                         }
    149                                         if (!typeMatch(pc.getRawType(), vp.getStorageType())) {
    150                                                 throw new ConstructionException().msg("types mismatch for param").arg("param", vp).arg("candidate", pc.getType()).arg("storage", vp.getStorageType());
    151                                         }
    152 
    153                                         final boolean primitive = pc.isPrimitive();
    154                                         if (pc.getField() != null) {
    155                                                 final Field f = pc.getField();
    156                                                 backend.getters.put(vp, new ReflectedGetter() {
    157                                                         @Override
    158                                                         public <T> T get(Object object, Class<T> type) throws IllegalArgumentException, IllegalAccessException {
    159                                                                 return type.cast(f.get(object));
    160                                                         }
    161                                                 });
    162                                                 if (!pc.isFinal()) {
    163                                                         backend.setters.put(vp, new ReflectedSetter() {
    164                                                                 @Override
    165                                                                 public <T> void set(Object object, T value) throws IllegalArgumentException, IllegalAccessException {
    166                                                                         if (value == null && primitive) {
    167                                                                                 throw new FramsticksException().msg("setting null to primitive value");
    168                                                                         }
    169                                                                         f.set(object, value);
    170                                                                 }
    171                                                         });
    172                                                 }
    173                                         } else {
    174                                                 final Method g = pc.getGetter();
    175 
    176                                                 backend.getters.put(vp, new ReflectedGetter() {
    177                                                         @Override
    178                                                         public <T> T get(Object object, Class<T> type) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
    179                                                                 return type.cast(g.invoke(object));
    180                                                         }
    181                                                 });
    182 
    183                                                 if (!pc.isFinal()) {
    184                                                         final Method s = pc.getSetter();
    185                                                         backend.setters.put(vp, new ReflectedSetter() {
    186                                                                 @Override
    187                                                                 public <T> void set(Object object, T value) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
    188                                                                         if (value == null && primitive) {
    189                                                                                 throw new FramsticksException().msg("setting null to primitive value");
    190                                                                         }
    191                                                                         s.invoke(object, value);
    192                                                                 }
    193                                                         });
    194                                                 }
    195                                         }
    196                                 }
    197                         } catch (ConstructionException e) {
    198                                 throw e.arg("java class", reflectedClass).arg("framsClass", framsClass);
    199                         }
    200 
    201                         Class<?> javaClass = reflectedClass;
    202                         while (javaClass != null) {
    203 
    204                                 for (Method m : javaClass.getDeclaredMethods()) {
    205                                         AutoAppendAnnotation a = m.getAnnotation(AutoAppendAnnotation.class);
    206                                         if (a == null) {
    207                                                 continue;
    208                                         }
    209                                         Class<?>[] args = m.getParameterTypes();
    210                                         if (args.length != 1) {
    211                                                 throw new ConstructionException().msg("invalid number of arguments in AutoAppend marked method").arg("method", m).arg("arguments", args.length);
    212                                         }
    213                                         backend.autoAppendMethods.add(m);
    214                                 }
    215 
    216                                 javaClass = javaClass.getSuperclass();
    217                         }
    218 
    219                         Collections.sort(backend.autoAppendMethods, new Comparator<Method>() {
    220 
    221                                 @Override
    222                                 public int compare(Method m0, Method m1) {
    223                                         Class<?> arg0 = m0.getParameterTypes()[0];
    224                                         Class<?> arg1 = m1.getParameterTypes()[0];
    225                                         if (arg0.isAssignableFrom(arg1)) {
    226                                                 return 1;
    227                                         }
    228                                         if (arg1.isAssignableFrom(arg0)) {
    229                                                 return -1;
    230                                         }
    231                                         return 0;
    232                                 }
    233                         });
    234 
    235                         synchronizedCache.put(id, backend);
    236                         return backend;
    237                 }
    238 
    239         }
    240 
    241         public static boolean typeMatch(Class<?> a, Class<?> b) {
    242                 if (b.isPrimitive()) {
    243                         throw new FramsticksException().msg("failed to match type, right argument is primitive").arg("left", a).arg("right", b);
    244                 }
    245                 if (!a.isPrimitive()) {
    246                         return a.equals(b);
    247                 }
    248 
    249                 if (a.equals(int.class)) {
    250                         return b.equals(Integer.class);
    251                 }
    252                 if (a.equals(double.class)) {
    253                         return b.equals(Double.class);
    254                 }
    255                 if (a.equals(boolean.class)) {
    256                         return b.equals(Boolean.class);
    257                 }
    258                 throw new FramsticksException().msg("failed to match types").arg("left", a).arg("right", b);
    259         }
    260 
    261 
    262 
    26331
    26432        public ReflectionAccess(Class<?> javaClass) throws ConstructionException {
     
    26836
    26937        public ReflectionAccess(Class<?> javaClass, FramsClass framsClass) throws ConstructionException {
    270                 this(javaClass, framsClass, Backend.getOrCreateFor(javaClass, framsClass));
    271         }
    272 
    273         protected ReflectionAccess(Class<?> javaClass, FramsClass framsClass, Backend backend) throws ConstructionException {
     38                this(javaClass, framsClass, ReflectionAccessBackend.getOrCreateFor(javaClass, framsClass));
     39        }
     40
     41        protected ReflectionAccess(Class<?> javaClass, FramsClass framsClass, ReflectionAccessBackend backend) throws ConstructionException {
    27442                super(framsClass);
    27543                this.javaClass = javaClass;
     
    27846
    27947        @Override
    280         public ReflectionAccess cloneAccess() throws ConstructionException {
     48        public ReflectionAccess cloneAccess() {
    28149                return new ReflectionAccess(javaClass, framsClass, backend);
    28250        }
     
    29058                                }
    29159
    292                                 return backend.getters.get(param).get(object, type);
     60                                return backend.getters.get(param.getId()).get(object, type);
    29361                        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
    29462                                throw new FramsticksException().msg("failed to get").cause(e);
     
    31078                                        throw new FramsticksException().msg("no object set");
    31179                                }
    312                                 Backend.ReflectedSetter s = backend.setters.get(param);
     80                                ReflectionAccessBackend.ReflectedSetter s = backend.setters.get(param.getId());
    31381                                if (s == null) {
    31482                                        throw new FramsticksException().msg("trying to set unsettable");
     
    334102                                }
    335103
    336                                 backend.adders.get(param).reg(object, listener);
     104                                backend.adders.get(param.getId()).reg(object, listener);
    337105                                return;
    338106                        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
     
    352120                                }
    353121
    354                                 backend.removers.get(param).regRemove(object, listener);
     122                                backend.removers.get(param.getId()).regRemove(object, listener);
    355123                                return;
    356124                        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
     
    364132        @Override
    365133        public Object call(String id, Object[] arguments) {
    366                 return call(framsClass.getParamEntry(id, ProcedureParam.class), arguments);
    367         }
    368 
    369         @Override
    370         public Object call(ProcedureParam param, Object[] arguments) {
    371                 try {
    372                         try {
    373                                 if (object == null) {
    374                                         throw new FramsticksException().msg("no object set");
    375                                 }
    376                                 Backend.ReflectedCaller c = backend.callers.get(param);
     134                try {
     135                        try {
     136                                if (object == null) {
     137                                        throw new FramsticksException().msg("no object set");
     138                                }
     139                                ReflectionAccessBackend.ReflectedCaller c = backend.callers.get(id);
    377140                                if (c == null) {
    378141                                        throw new FramsticksException().msg("method is not bound");
     
    383146                        }
    384147                } catch (FramsticksException e) {
    385                         throw e.arg("param", param).arg("access", this);
    386                 }
    387         }
    388 
    389         void resetErrors() {
    390                 //TODO this replaces returnedObject.resetErrors();
     148                        throw e.arg("param", framsClass.getParam(id)).arg("access", this);
     149                }
     150        }
     151
     152        @Override
     153        public Object call(ProcedureParam param, Object[] arguments) {
     154                return call(param.getId(), arguments);
    391155        }
    392156
     
    396160                        return;
    397161                }
    398 
    399                 resetErrors();
    400162
    401163                try {
     
    416178        @Override
    417179        public ReflectionAccess select(Object object) {
    418                 this.object = Util.selectObjectForAccess(this, object, javaClass);
     180                this.object = ParamsUtil.selectObjectForAccess(this, object, javaClass);
    419181                return this;
    420182        }
     
    425187        }
    426188
    427         // TODO: find a better place for it
    428         public static String objectToString(Object object) {
    429                 StringBuilder b = new StringBuilder();
    430                 for (Field f : object.getClass().getFields()) {
    431                         b.append(f.getName());
    432                         b.append(":");
    433                         try {
    434                                 Object value = f.get(object);
    435                                 b.append((value != null) ? value.toString() : "<null>");
    436                         } catch (IllegalAccessException e) {
    437                                 e.printStackTrace();
    438                         }
    439                         b.append("\n");
    440                 }
    441                 return b.toString();
    442         }
    443 
    444 
    445189        @Override
    446190        public Object createAccessee() {
     
    448192                        return javaClass.newInstance();
    449193                } catch (InstantiationException | IllegalAccessException e) {
    450                         e.printStackTrace();
    451                 }
    452                 log.fatal("failed to create reflected object of class {} for frams type {}", javaClass.getCanonicalName(), framsClass.getId());
    453                 return null;
    454         }
    455 
     194                        throw new FramsticksException().msg("failed to create reflected object").arg("java class", javaClass).arg("frams class", framsClass).cause(e);
     195                }
     196        }
    456197
    457198        @Override
  • java/main/src/main/java/com/framsticks/params/Registry.java

    r100 r101  
    88import com.framsticks.util.DoubleMap;
    99import com.framsticks.util.FramsticksException;
     10import com.framsticks.util.FramsticksUnsupportedOperationException;
    1011import com.framsticks.util.lang.Strings;
    1112
     
    2021 */
    2122@FramsClassAnnotation
    22 public class Registry {
     23public class Registry implements AccessProvider {
    2324        private static final Logger log = LogManager.getLogger(Registry.class.getName());
    2425
     
    4546
    4647        public Registry registerAndBuild(Class<?> javaClass) {
     48                if (javaToFramsAssociation.containsKey(javaClass)) {
     49                        return this;
     50                }
    4751                register(javaClass);
    4852                associate(javaClass, putFramsClass(FramsClass.build().forClass(javaClass)));
    49                 for (Class<?> r : javaClass.getAnnotation(FramsClassAnnotation.class).register()) {
     53                for (Class<?> r : ParamCandidate.getAllCandidates(javaClass).getDependentClasses()) {
    5054                        registerAndBuild(r);
    5155                }
     
    157161        }
    158162
     163        @Override
     164        public Access getAccess(String name) {
     165                return createAccess(name);
     166        }
     167
     168        @Override
     169        public void addAccess(Access access) {
     170                throw new FramsticksUnsupportedOperationException().msg("adding accesses to Registry");
     171        }
     172
    159173}
  • java/main/src/main/java/com/framsticks/params/SimpleAbstractAccess.java

    r100 r101  
    44import static com.framsticks.util.lang.Containers.filterInstanceof;
    55
    6 import org.apache.logging.log4j.Logger;
    7 import org.apache.logging.log4j.LogManager;
    86
    97import com.framsticks.params.types.ObjectParam;
    108import com.framsticks.util.FramsticksException;
    11 import static com.framsticks.params.SetStateFlags.*;
    129
    1310/**
     
    2320 * @author Piotr Sniegowski
    2421 */
    25 public abstract class SimpleAbstractAccess implements Access {
    26 
    27         private final static Logger log = LogManager.getLogger(SimpleAbstractAccess.class.getName());
     22public abstract class SimpleAbstractAccess implements ObjectAccess {
    2823
    2924        protected final FramsClass framsClass;
     
    4035                return framsClass;
    4136        }
    42 
    43         /**
    44          * Simple String key, value class.
    45          */
    46         public static class Entry {
    47 
    48                 public final String key;
    49                 public final String value;
    50 
    51                 public Entry(String key, String value) {
    52                         this.key = key;
    53                         this.value = value;
    54                 }
    55 
    56                 @Override
    57                 public String toString() {
    58                         return key + " = " + value;
    59                 }
    60         }
    61 
    6237
    6338        @Override
     
    129104
    130105        @Override
    131         public void setDefault(boolean numericOnly) {
    132                 for (int i = 0; i < framsClass.getParamCount(); i++) {
    133                         setDefault(i, numericOnly);
    134                 }
    135         }
    136 
    137         @Override
    138         public void setDefault(int i, boolean numericOnly) {
    139                 ValueParam entry = framsClass.getParamEntry(i, ValueParam.class);
    140                 if ((entry != null)     && (!numericOnly || entry.isNumeric())) {
    141                         set(i, entry.getDef(entry.getStorageType()));
    142                 }
    143         }
    144 
    145         @Override
    146         public void setMin() {
    147                 for (int i = 0; i < framsClass.getParamCount(); i++) {
    148                         setMin(i);
    149                 }
    150         }
    151 
    152         @Override
    153         public void setMin(int i) {
    154                 PrimitiveParam<?> entry = framsClass.getParamEntry(i, PrimitiveParam.class);
    155                 Object min = entry.getMin(entry.getStorageType());
    156                 if (min != null) {
    157                         set(i, min);
    158                 }
    159         }
    160 
    161         @Override
    162         public void setMax() {
    163                 for (int i = 0; i < framsClass.getParamCount(); i++) {
    164                         setMax(i);
    165                 }
    166         }
    167 
    168         @Override
    169         public void setMax(int i) {
    170                 PrimitiveParam<?> entry = framsClass.getParamEntry(i, PrimitiveParam.class);
    171                 Object max = entry.getMax(entry.getStorageType());
    172                 if (max != null) {
    173                         set(i, max);
    174                 }
    175         }
    176 
    177         @Override
    178106        public void save(SinkInterface sink) {
    179107                assert framsClass != null;
     
    189117                }
    190118                sink.breakLine();
    191         }
    192 
    193         private static Entry readEntry(SourceInterface source) {
    194 
    195                 String line;
    196                 String key = null;
    197                 StringBuilder value = null;
    198                 while ((line = source.readLine()) != null) {
    199                         if (key == null) {
    200                                 int colonIndex = line.indexOf(':');
    201                                 if (colonIndex == -1) {
    202                                         return null;
    203                                 }
    204                                 key = line.substring(0, colonIndex);
    205                                 String inlineValue = line.substring(colonIndex + 1);
    206 
    207 
    208                                 if (!inlineValue.startsWith("~")) {
    209                                         return new Entry(key, inlineValue);
    210                                 }
    211                                 value = new StringBuilder();
    212                                 value.append(inlineValue.substring(1));
    213                                 continue;
    214                         }
    215                         if (value.length() != 0) {
    216                                 value.append(System.getProperty("line.separator"));
    217                         }
    218                         if (line.endsWith("~") && !line.endsWith("\\~")) {
    219                                 value.append(line.substring(0, line.length() - 1));
    220                                 return new Entry(key, value.toString().replaceAll("\\\\~", "~"));
    221                         }
    222                         value.append(line);
    223                 }
    224                 return null;
    225         }
    226 
    227         @Override
    228         public void load(SourceInterface source) {
    229                 //TODO not clearing values, because get from manager gives only fields, not children
    230                 //this.clearValues();
    231 
    232                 Entry entry;
    233                 while ((entry = readEntry(source)) != null) {
    234                         Param param = getParam(entry.key);
    235                         if (param == null) {
    236                                 throw new FramsticksException().msg("param not found in access").arg("name", entry.key).arg("access", this);
    237                         }
    238                         if (!(param instanceof ValueParam)) {
    239                                 throw new FramsticksException().msg("param is not a value param").arg("param", param).arg("access", this);
    240                         }
    241                         if ((param.getFlags() & ParamFlags.DONTLOAD) == 0) {
    242                                 int retFlags = this.set((ValueParam) param, entry.value);
    243                                 if ((retFlags & (PSET_HITMIN | PSET_HITMAX)) != 0) {
    244                                         String which = ((retFlags & PSET_HITMIN) != 0) ? "small" : "big";
    245                                         log.warn("value of key '{}' was too {}, adjusted", entry.key, which);
    246                                 }
    247                         }
    248                 }
    249119        }
    250120
     
    266136        }
    267137
    268         /*
    269         protected <T extends Comparable<T>> int setAndCut(Param param, Object value, Class<T> type) {
    270                 int flags = 0;
    271                 T val = type.cast(value);
    272                 T min = param.getMin(type);
    273                 T max = param.getMax(type);
    274                 if (min != null && val.compareTo(min) < 0) {
    275                         val = min;
    276                         flags |= Flags.PSET_HITMIN;
    277                 }
    278                 if (max != null && val.compareTo(max) > 0) {
    279                         val = max;
    280                         flags |= Flags.PSET_HITMAX;
    281                 }
    282                 internalSet(param, val);
    283                 return flags;
    284         }*/
    285 
    286 
    287138        @Override
    288139        public ParamBuilder buildParam(ParamBuilder builder) {
  • java/main/src/main/java/com/framsticks/params/UniqueListAccess.java

    r100 r101  
    44import com.framsticks.util.FramsticksException;
    55import com.framsticks.util.UnimplementedException;
    6 import com.framsticks.util.UnsupportedOperationException;
     6import com.framsticks.util.FramsticksUnsupportedOperationException;
    77import com.framsticks.util.lang.Casting;
    88import com.framsticks.util.lang.Numbers;
     
    205205        @Override
    206206        public <T> int set(int i, T value) {
    207                 throw new UnsupportedOperationException().msg("accesing unique list through index");
     207                throw new FramsticksUnsupportedOperationException().msg("accesing unique list through index");
    208208        }
    209209
     
    251251        @Override
    252252        public UniqueListAccess select(Object object) {
    253                 map = Util.selectObjectForAccess(this, object, Map.class);
     253                map = ParamsUtil.selectObjectForAccess(this, object, Map.class);
    254254                return this;
    255255        }
  • java/main/src/main/java/com/framsticks/params/annotations/ParamAnnotation.java

    r90 r101  
    2222
    2323        String help() default "";
    24         // int flags() default 0;
     24        int flags() default 0;
    2525        int extra() default 0;
    2626        // String group() default "";
  • java/main/src/main/java/com/framsticks/parsers/F0Parser.java

    r100 r101  
    1212import com.framsticks.model.f0.Schema;
    1313
    14 import static com.framsticks.params.SimpleAbstractAccess.*;
    1514
    1615import com.framsticks.params.Param;
     
    2625import com.framsticks.params.FramsClass;
    2726import com.framsticks.params.Access;
     27import com.framsticks.params.AccessOperations.Entry;
    2828import static com.framsticks.params.ParamFlags.*;
    2929import static com.framsticks.params.SetStateFlags.*;
  • java/main/src/main/java/com/framsticks/parsers/FileSource.java

    r86 r101  
    11package com.framsticks.parsers;
    22
    3 import com.framsticks.params.SourceInterface;
     3import com.framsticks.params.Source;
    44import com.framsticks.util.io.Encoding;
    55
     
    77
    88
    9 public class FileSource implements SourceInterface {
     9public class FileSource implements Source {
    1010
    1111        private BufferedReader reader;
     
    6060
    6161        @Override
    62         public SourceInterface openInclude(String include)
     62        public Source openInclude(String include)
    6363        {
    6464                try
     
    8989        }
    9090
     91        @Override
     92        public String toString() {
     93                return filename;
     94        }
     95
    9196}
  • java/main/src/main/java/com/framsticks/parsers/Loaders.java

    r100 r101  
    1313        // private static final Logger log = LogManager.getLogger(Loaders.class.getName());
    1414
    15         public static @Nonnull FramsClass loadFramsClass(SourceInterface source) throws ConstructionException {
     15        public static @Nonnull FramsClass loadFramsClass(Source source) throws ConstructionException {
    1616                final MultiParamLoader loader = new MultiParamLoader();
    1717                loader.setNewSource(source);
  • java/main/src/main/java/com/framsticks/parsers/MultiParamLoader.java

    r100 r101  
    6868         * File from which data should be read.
    6969         */
    70         private SourceInterface currentSource;
     70        private Source currentSource;
    7171
    7272        protected String currentLine;
     
    8383         * actual reader.
    8484         */
    85         private Map<String, SourceInterface> fileMap = new HashMap<String, SourceInterface>();
     85        private Map<String, Source> fileMap = new HashMap<String, Source>();
    8686
    8787        /**
    8888         * List of known classes.
    8989         */
    90         private Map<String, Access> knownParamInterfaces = new HashMap<String, Access>();
     90        protected AccessProvider accessProvider = new AccessStash();
    9191
    9292        /**
     
    100100        public String getCurrentLine() {
    101101                return currentLine;
     102        }
     103
     104        /**
     105         * @return the accessProvider
     106         */
     107        public AccessProvider getAccessProvider() {
     108                return accessProvider;
     109        }
     110
     111        /**
     112         * @param accessProvider the accessProvider to set
     113         */
     114        public void setAccessProvider(AccessProvider accessProvider) {
     115                this.accessProvider = accessProvider;
    102116        }
    103117
     
    184198                        }
    185199                        log.trace("loading into {}", lastAccess);
    186                         lastAccess.load(currentSource);
     200                        AccessOperations.load(lastAccess, currentSource);
    187201
    188202                        if (changeStatus(Status.AfterObject)) {
     
    194208
    195209                        // found unknown object
    196                         emptyParam.load(currentSource);
     210                        AccessOperations.load(emptyParam, currentSource);
    197211                        if (changeStatus(Status.AfterObject)) {
    198212                                return LoopAction.Break;
     
    262276                if (line.charAt(line.length() - 1) == ':') {
    263277                        String typeName = line.substring(0, line.length() - 1);
    264                         lastAccess = knownParamInterfaces.get(typeName);
     278                        lastAccess = accessProvider.getAccess(typeName);
    265279
    266280                        if (lastAccess != null) {
     
    300314         */
    301315        public void addAccess(Access access) {
    302                 /**TODO: by id or by name? rather by id, because from file is always lowercase*/
    303                 knownParamInterfaces.put(access.getId(), access);
     316                accessProvider.addAccess(access);
    304317        }
    305318
     
    324337         */
    325338
    326         public boolean setNewSource(SourceInterface source) {
     339        public boolean setNewSource(Source source) {
    327340                log.debug("switching current source to {}...", source.getFilename());
    328341
     
    351364                log.info("including file {}...", includeFilename);
    352365
    353                 SourceInterface newSource = currentSource.openInclude(includeFilename);
     366                Source newSource = currentSource.openInclude(includeFilename);
    354367                if (newSource == null) {
    355368                        return;
     
    426439        }
    427440
    428         public static List<Object> loadAll(SourceInterface source, Access access) {
     441        public static List<Object> loadAll(Source source, Access access) {
    429442                final List<Object> result = new LinkedList<>();
    430443
  • java/main/src/main/java/com/framsticks/parsers/XmlLoader.java

    r100 r101  
    2020
    2121import com.framsticks.params.Access;
     22import com.framsticks.params.ParamFlags;
     23import com.framsticks.params.PrimitiveParam;
    2224import com.framsticks.params.Registry;
    2325import com.framsticks.util.AutoBuilder;
     
    107109                for (int i = 0; i < attributes.getLength(); ++i) {
    108110                        Node attributeNode = attributes.item(i);
    109                         access.set(mangleAttribute(attributeNode.getNodeName()), attributeNode.getNodeValue());
     111                        PrimitiveParam<?> param = access.getFramsClass().getParamEntry(mangleAttribute(attributeNode.getNodeName()), PrimitiveParam.class);
     112                        if (param.hasFlag(ParamFlags.READONLY)) {
     113                                throw new FramsticksException().msg("cannot configure readonly param").arg("param", param).arg("in", access);
     114                        }
     115                        access.set(param, attributeNode.getNodeValue());
    110116                }
    111117
  • java/main/src/main/java/com/framsticks/remote/RemoteTree.java

    r100 r101  
    77import com.framsticks.communication.queries.SetRequest;
    88import com.framsticks.core.AbstractTree;
     9import com.framsticks.core.ListChange;
    910import com.framsticks.core.Path;
     11import com.framsticks.core.ValueChange;
    1012import com.framsticks.params.*;
    1113import com.framsticks.params.EventListener;
    12 import com.framsticks.params.annotations.AutoAppendAnnotation;
    1314import com.framsticks.params.annotations.FramsClassAnnotation;
    1415import com.framsticks.params.annotations.ParamAnnotation;
     
    1718import com.framsticks.parsers.Loaders;
    1819import com.framsticks.parsers.MultiParamLoader;
    19 import com.framsticks.core.Tree;
    2020import com.framsticks.util.*;
    2121import com.framsticks.util.dispatching.AtOnceDispatcher;
    2222import c