Add context menues when hovering over avatar images.
[Sone.git] / src / main / java / net / pterodactylus / sone / core / Core.java
index 1e68c63..7ecf0fa 100644 (file)
@@ -54,7 +54,10 @@ import net.pterodactylus.util.config.Configuration;
 import net.pterodactylus.util.config.ConfigurationException;
 import net.pterodactylus.util.logging.Logging;
 import net.pterodactylus.util.number.Numbers;
+import net.pterodactylus.util.thread.Ticker;
+import net.pterodactylus.util.validation.EqualityValidator;
 import net.pterodactylus.util.validation.IntegerRangeValidator;
+import net.pterodactylus.util.validation.OrValidator;
 import net.pterodactylus.util.validation.Validation;
 import net.pterodactylus.util.version.Version;
 import freenet.client.FetchResult;
@@ -65,7 +68,7 @@ import freenet.keys.FreenetURI;
  *
  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
  */
-public class Core implements IdentityListener, UpdateListener {
+public class Core implements IdentityListener, UpdateListener, SoneProvider, PostProvider {
 
        /**
         * Enumeration for the possible states of a {@link Sone}.
@@ -179,6 +182,9 @@ public class Core implements IdentityListener, UpdateListener {
        /** Trusted identities, sorted by own identities. */
        private Map<OwnIdentity, Set<Identity>> trustedIdentities = Collections.synchronizedMap(new HashMap<OwnIdentity, Set<Identity>>());
 
+       /** Ticker for threads that mark own elements as known. */
+       private Ticker localElementTicker = new Ticker();
+
        /**
         * Creates a new core.
         *
@@ -352,6 +358,7 @@ public class Core implements IdentityListener, UpdateListener {
         * @return The Sone with the given ID, or {@code null} if there is no such
         *         Sone
         */
+       @Override
        public Sone getSone(String id, boolean create) {
                if (isLocalSone(id)) {
                        return getLocalSone(id);
@@ -574,6 +581,7 @@ public class Core implements IdentityListener, UpdateListener {
         *            exists, {@code false} to return {@code null}
         * @return The post, or {@code null} if there is no such post
         */
+       @Override
        public Post getPost(String postId, boolean create) {
                synchronized (posts) {
                        Post post = posts.get(postId);
@@ -1500,7 +1508,7 @@ public class Core implements IdentityListener, UpdateListener {
                        logger.log(Level.FINE, "Tried to create post for non-local Sone: %s", sone);
                        return null;
                }
-               Post post = new Post(sone, time, text);
+               final Post post = new Post(sone, time, text);
                if (recipient != null) {
                        post.setRecipient(recipient);
                }
@@ -1513,6 +1521,16 @@ public class Core implements IdentityListener, UpdateListener {
                }
                sone.addPost(post);
                saveSone(sone);
+               localElementTicker.registerEvent(System.currentTimeMillis() + 10 * 1000, new Runnable() {
+
+                       /**
+                        * {@inheritDoc}
+                        */
+                       @Override
+                       public void run() {
+                               markPostKnown(post);
+                       }
+               }, "Mark " + post + " read.");
                return post;
        }
 
@@ -1633,7 +1651,7 @@ public class Core implements IdentityListener, UpdateListener {
                        logger.log(Level.FINE, "Tried to create reply for non-local Sone: %s", sone);
                        return null;
                }
-               Reply reply = new Reply(sone, post, System.currentTimeMillis(), text);
+               final Reply reply = new Reply(sone, post, System.currentTimeMillis(), text);
                synchronized (replies) {
                        replies.put(reply.getId(), reply);
                }
@@ -1643,6 +1661,16 @@ public class Core implements IdentityListener, UpdateListener {
                }
                sone.addReply(reply);
                saveSone(sone);
+               localElementTicker.registerEvent(System.currentTimeMillis() + 10 * 1000, new Runnable() {
+
+                       /**
+                        * {@inheritDoc}
+                        */
+                       @Override
+                       public void run() {
+                               markReplyKnown(reply);
+                       }
+               }, "Mark " + reply + " read.");
                return reply;
        }
 
@@ -1731,6 +1759,7 @@ public class Core implements IdentityListener, UpdateListener {
                        configuration.getIntValue("Option/ConfigurationVersion").setValue(0);
                        configuration.getIntValue("Option/InsertionDelay").setValue(options.getIntegerOption("InsertionDelay").getReal());
                        configuration.getIntValue("Option/PostsPerPage").setValue(options.getIntegerOption("PostsPerPage").getReal());
+                       configuration.getIntValue("Option/CharactersPerPost").setValue(options.getIntegerOption("CharactersPerPost").getReal());
                        configuration.getBooleanValue("Option/RequireFullAccess").setValue(options.getBooleanOption("RequireFullAccess").getReal());
                        configuration.getIntValue("Option/PositiveTrust").setValue(options.getIntegerOption("PositiveTrust").getReal());
                        configuration.getIntValue("Option/NegativeTrust").setValue(options.getIntegerOption("NegativeTrust").getReal());
@@ -1808,6 +1837,7 @@ public class Core implements IdentityListener, UpdateListener {
 
                }));
                options.addIntegerOption("PostsPerPage", new DefaultOption<Integer>(10, new IntegerRangeValidator(1, Integer.MAX_VALUE)));
+               options.addIntegerOption("CharactersPerPost", new DefaultOption<Integer>(200, new OrValidator<Integer>(new IntegerRangeValidator(50, Integer.MAX_VALUE), new EqualityValidator<Integer>(-1))));
                options.addBooleanOption("RequireFullAccess", new DefaultOption<Boolean>(false));
                options.addIntegerOption("PositiveTrust", new DefaultOption<Integer>(75, new IntegerRangeValidator(0, 100)));
                options.addIntegerOption("NegativeTrust", new DefaultOption<Integer>(-25, new IntegerRangeValidator(-100, 100)));
@@ -1846,6 +1876,7 @@ public class Core implements IdentityListener, UpdateListener {
 
                loadConfigurationValue("InsertionDelay");
                loadConfigurationValue("PostsPerPage");
+               loadConfigurationValue("CharactersPerPost");
                options.getBooleanOption("RequireFullAccess").set(configuration.getBooleanValue("Option/RequireFullAccess").getValue(null));
                loadConfigurationValue("PositiveTrust");
                loadConfigurationValue("NegativeTrust");
@@ -2142,6 +2173,41 @@ public class Core implements IdentityListener, UpdateListener {
                }
 
                /**
+                * Returns the number of characters per post, or <code>-1</code> if the
+                * posts should not be cut off.
+                *
+                * @return The numbers of characters per post
+                */
+               public int getCharactersPerPost() {
+                       return options.getIntegerOption("CharactersPerPost").get();
+               }
+
+               /**
+                * Validates the number of characters per post.
+                *
+                * @param charactersPerPost
+                *            The number of characters per post
+                * @return {@code true} if the number of characters per post was valid,
+                *         {@code false} otherwise
+                */
+               public boolean validateCharactersPerPost(Integer charactersPerPost) {
+                       return options.getIntegerOption("CharactersPerPost").validate(charactersPerPost);
+               }
+
+               /**
+                * Sets the number of characters per post.
+                *
+                * @param charactersPerPost
+                *            The number of characters per post, or <code>-1</code> to
+                *            not cut off the posts
+                * @return This preferences objects
+                */
+               public Preferences setCharactersPerPost(Integer charactersPerPost) {
+                       options.getIntegerOption("CharactersPerPost").set(charactersPerPost);
+                       return this;
+               }
+
+               /**
                 * Returns whether Sone requires full access to be even visible.
                 *
                 * @return {@code true} if Sone requires full access, {@code false}