diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/lda/Analyzer.java b/vipra-cmd/src/main/java/de/vipra/cmd/lda/Analyzer.java index 1e04b318e3a8010b883e00b2b3f6a7809d5e8303..be212bc682da4ad02d1c47b0077f06da0cbb35c7 100644 --- a/vipra-cmd/src/main/java/de/vipra/cmd/lda/Analyzer.java +++ b/vipra-cmd/src/main/java/de/vipra/cmd/lda/Analyzer.java @@ -1,5 +1,6 @@ package de.vipra.cmd.lda; +import java.awt.Color; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; @@ -12,6 +13,7 @@ import java.util.Comparator; import java.util.Date; import java.util.List; import java.util.ListIterator; +import java.util.Random; import java.util.function.Consumer; import org.bson.types.ObjectId; @@ -21,6 +23,7 @@ import de.vipra.cmd.file.FilebaseIDDateIndexEntry; import de.vipra.cmd.file.FilebaseWindowIndex; import de.vipra.cmd.file.FilebaseWordIndex; import de.vipra.util.ArrayUtils; +import de.vipra.util.ColorUtils; import de.vipra.util.CompareMap; import de.vipra.util.Config; import de.vipra.util.ConsoleUtils; @@ -207,6 +210,9 @@ public class Analyzer { final List<SequenceFull> newSequences = new ArrayList<>(topicCount * windowCount); final List<TopicFull> newTopics = new ArrayList<>(topicCount); + if (topicModel.getColorSeed() == null) + topicModel.setColorSeed(new Random().nextLong()); + final List<Color> newColors = ColorUtils.generateRandomColors(topicCount, topicModel.getColorSeed()); topicModel.setWordCount((long) wordCount); topicModel.setWindowCount((long) windowCount); @@ -226,6 +232,7 @@ public class Analyzer { // create new topic final TopicFull newTopic = new TopicFull(); newTopic.setTopicModel(new TopicModel(topicModel.getId())); + newTopic.setColor(ColorUtils.toHexString(newColors.get(idxTopic))); newTopics.add(newTopic); in = new BufferedReader(new InputStreamReader(new FileInputStream(seqFile))); diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/option/CreateModelCommand.java b/vipra-cmd/src/main/java/de/vipra/cmd/option/CreateModelCommand.java index 0c44072fd2f38605b73eb51c15a5d0a837a6c13e..a4235dfdeec330aa536e67558e04825be711544c 100644 --- a/vipra-cmd/src/main/java/de/vipra/cmd/option/CreateModelCommand.java +++ b/vipra-cmd/src/main/java/de/vipra/cmd/option/CreateModelCommand.java @@ -2,6 +2,7 @@ package de.vipra.cmd.option; import java.io.File; import java.io.IOException; +import java.util.Random; import org.bson.types.ObjectId; @@ -20,6 +21,7 @@ public class CreateModelCommand implements Command { private final String[] names; private Config config; private MongoService<TopicModelFull, ObjectId> dbTopicModels; + private Random random; public CreateModelCommand(final String[] names) { this.names = names; @@ -30,6 +32,7 @@ public class CreateModelCommand implements Command { modelConfig.setName(name); modelConfig.saveToFile(modelDir); final TopicModelFull topicModel = new TopicModelFull(name, modelConfig); + topicModel.setColorSeed(random.nextLong()); dbTopicModels.createSingle(topicModel); config.getTopicModelConfigs().put(name, modelConfig); } @@ -41,6 +44,7 @@ public class CreateModelCommand implements Command { config = Config.getConfig(); dbTopicModels = MongoService.getDatabaseService(config, TopicModelFull.class); + random = new Random(); final TopicModelConfig modelConfig; diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/option/ImportCommand.java b/vipra-cmd/src/main/java/de/vipra/cmd/option/ImportCommand.java index c3ca6cbe58493901ebc5dd61742b84d592200f54..4f7a5b3fe1e457d9465bac192a6828cf7daac66b 100644 --- a/vipra-cmd/src/main/java/de/vipra/cmd/option/ImportCommand.java +++ b/vipra-cmd/src/main/java/de/vipra/cmd/option/ImportCommand.java @@ -296,16 +296,6 @@ public class ImportCommand implements Command { */ filebase.sync(); - /* - * update topic model - */ - topicModelFull.setWindows(filebase.getWindowIndex().getWindows()); - topicModelFull.setArticleCount((long) filebase.getIdDateIndex().size()); - topicModelFull.setWordCount((long) filebase.getWordIndex().size()); - final long entityCount = dbEntities.count(QueryBuilder.builder().eq("topicModel", topicModel)); - topicModelFull.setEntityCount(entityCount); - dbTopicModels.replaceSingle(topicModelFull); - /* * add new words */ @@ -333,6 +323,15 @@ public class ImportCommand implements Command { } dbWindows.createMultiple(newWindows); + /* + * update topic model + */ + topicModelFull.setWindows(filebase.getWindowIndex().getWindows()); + topicModelFull.setArticleCount((long) filebase.getIdDateIndex().size()); + topicModelFull.setWordCount((long) filebase.getWordIndex().size()); + topicModelFull.setEntityCount(dbEntities.count(QueryBuilder.builder().eq("topicModel", topicModel))); + dbTopicModels.replaceSingle(topicModelFull); + /* * run information */ diff --git a/vipra-ui/app/html/articles/index.html b/vipra-ui/app/html/articles/index.html index 61662e45884561e9e63dd3eafc154c5d2e1b41ac..6479cf27dd8575314c1e14c93a66a095e84aa670 100644 --- a/vipra-ui/app/html/articles/index.html +++ b/vipra-ui/app/html/articles/index.html @@ -54,11 +54,6 @@ </div> </div> </div> - <div class="row"> - <div class="col-md-12 text-center"> - <pagination total="articlesTotal" page="articlesIndexModels.page" limit="articlesIndexModels.limit" /> - </div> - </div> </div> </div> <div ng-cloak ui-view></div> diff --git a/vipra-ui/app/html/directives/article-link.html b/vipra-ui/app/html/directives/article-link.html index 1e7d04ab33a358c2f2b348966165bc4ba860294a..52198c121d9d281efddf6a49b4269143640d15c8 100644 --- a/vipra-ui/app/html/directives/article-link.html +++ b/vipra-ui/app/html/directives/article-link.html @@ -13,7 +13,7 @@ <div ng-if="detailsShown" class="details"> <span ng-bind="::articleDetails.text"></span> <div> - <a ui-sref="topics.show({id:topic.topic.id})" class="badge" ng-bind="::topic.topic.name" ng-attr-title="::topic.topic.name" ng-repeat="topic in articleDetails.topics"></a> + <a ui-sref="topics.show({id:topic.topic.id})" class="badge topic-badge text-outline" ng-bind="::topic.topic.name" ng-style="{'background':topic.topic.color}" ng-attr-title="{{::topic.topic.name}}" ng-repeat="topic in articleDetails.topics"></a> </div> </div> </div> \ No newline at end of file diff --git a/vipra-ui/app/html/entities/index.html b/vipra-ui/app/html/entities/index.html index 5cf739fd136182f6d6336abd3a69838616cd1716..5bc4a38b80475c233ee4ab7794139c877993c6fe 100644 --- a/vipra-ui/app/html/entities/index.html +++ b/vipra-ui/app/html/entities/index.html @@ -51,11 +51,6 @@ </div> </div> </div> - <div class="row"> - <div class="col-md-12 text-center"> - <pagination total="entitiesTotal" page="entitiesIndexModels.page" limit="entitiesIndexModels.limit" /> - </div> - </div> </div> </div> <div ng-cloak ui-view></div> diff --git a/vipra-ui/app/html/index.html b/vipra-ui/app/html/index.html index fac08c019dd57c2012badca338c9859630d43580..4d959af5956b19dc2d9988f434645beea39f382d 100644 --- a/vipra-ui/app/html/index.html +++ b/vipra-ui/app/html/index.html @@ -75,7 +75,7 @@ </div> </div> <div class="col-xs-5 text-center"> - <h3>Introduction slides</h3> + <h3>Slides</h3> <div class="embed-responsive embed-responsive-16by9 media-box"> <a ui-sref="slides"> <img src="img/vipra-slides.png" class="slides-thumb"> diff --git a/vipra-ui/app/html/partials/topicmodel-popover.html b/vipra-ui/app/html/partials/topicmodel-popover.html index ab7142f10a066bdc9f262d1871cbb1a61af42927..585b8ee94eb9e5f10cbb96691054b4806ccf3133 100644 --- a/vipra-ui/app/html/partials/topicmodel-popover.html +++ b/vipra-ui/app/html/partials/topicmodel-popover.html @@ -1,30 +1,30 @@ <table class="td-padded"> <tr> <th>Articles</th> - <td ng-bind="::topicModel.articleCount"></td> + <td ng-bind="::topicModel.articleCount || 0"></td> </tr> <tr> <th>Topics</th> - <td ng-bind="::topicModel.topicCount"></td> + <td ng-bind="::topicModel.topicCount || 0"></td> </tr> <tr> <th>Words</th> - <td ng-bind="::topicModel.wordCount"></td> + <td ng-bind="::topicModel.wordCount || 0"></td> </tr> <tr> <th>Entities</th> - <td ng-bind="::topicModel.entityCount"></td> + <td ng-bind="::topicModel.entityCount || 0"></td> </tr> <tr> <th>Windows</th> - <td ng-bind="::topicModel.windowCount"></td> + <td ng-bind="::topicModel.windowCount || 0"></td> </tr> <tr> <th>Last generated</th> - <td ng-bind-template="{{::Vipra.formatDateTime(topicModel.lastGenerated)}}"></td> + <td ng-bind-template="{{::topicModel.lastGeneratedString}}"></td> </tr> <tr> <th>Last indexed</th> - <td ng-bind-template="{{::Vipra.formatDateTime(topicModel.lastIndexed)}}"></td> + <td ng-bind-template="{{::topicModel.lastIndexedString}}"></td> </tr> </table> \ No newline at end of file diff --git a/vipra-ui/app/html/topics/index.html b/vipra-ui/app/html/topics/index.html index 2ffc0069a225a8235f6d9f9cb03b0dd20edcb691..aeefbc3a78234797e3bc53e488992b00dce556e8 100644 --- a/vipra-ui/app/html/topics/index.html +++ b/vipra-ui/app/html/topics/index.html @@ -53,11 +53,6 @@ </div> </div> </div> - <div class="row"> - <div class="col-md-12 text-center"> - <pagination total="topicsTotal" page="topicsIndexModels.page" limit="topicsIndexModels.limit" /> - </div> - </div> </div> </div> <div ng-cloak ui-view></div> diff --git a/vipra-ui/app/html/words/index.html b/vipra-ui/app/html/words/index.html index 2f6c91c889e18a2318132f720cde5c6e3d5b924a..33be9812ed3ef443bcfb1c24155b68681a587d44 100644 --- a/vipra-ui/app/html/words/index.html +++ b/vipra-ui/app/html/words/index.html @@ -51,11 +51,6 @@ </div> </div> </div> - <div class="row"> - <div class="col-md-12 text-center"> - <pagination total="wordsTotal" page="wordsIndexModels.page" limit="wordsIndexModels.limit" /> - </div> - </div> </div> </div> <div ng-cloak ui-view></div> diff --git a/vipra-ui/app/index.html b/vipra-ui/app/index.html index 4cbc1dc855c6ebccc7d4ec9d4502d8b2aff8275b..cf072fde2ade401475f1f8eb470269d0f1b171e1 100644 --- a/vipra-ui/app/index.html +++ b/vipra-ui/app/index.html @@ -5,7 +5,7 @@ <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <base href="/"> - <title>Vipra</title> + <title ng-bind-template="VIPRA - {{rootModels.title}}"></title> <!-- stylesheets --> <link href="css/vendor.css" rel="stylesheet"> <link href="css/app.css" rel="stylesheet"> @@ -85,10 +85,7 @@ </div> <div class="modal-body"> <ul class="list-group nomargin" ng-show="topicModels.length" ng-cloak> - <button type="button" class="list-group-item topic-model" ng-repeat="topicModel in topicModels" ng-click="changeTopicModel(topicModel)" ng-class="{'active selected-model':rootModels.topicModel.id===topicModel.id}" analytics-on analytics-event="Topic model" analytics-category="Topic model actions"> - <span class="badge" bs-popover popover-title="{{::topicModel.name}}" popover-template="partials/topicmodel-popover.html" popover-placement="left"> - <i class="fa fa-info"></i> - </span> + <button type="button" class="list-group-item topic-model" ng-repeat="topicModel in topicModels" ng-click="changeTopicModel(topicModel)" ng-class="{'active selected-model':rootModels.topicModel.id===topicModel.id}" analytics-on analytics-event="Topic model" analytics-category="Topic model actions" bs-popover popover-title="{{::topicModel.name}}" popover-template="partials/topicmodel-popover.html" popover-placement="bottom"> <span class="badge badge-group"> <span class="badge-part" ng-if="!topicModel.lastGenerated" title="Model was never generated">Non-generated</span> <span class="badge-part" ng-bind="::topicModel.articleCount" ng-show="topicModel.articleCount" ng-attr-title="{{::topicModel.articleCount + ' article(s)'}}" ng-cloak></span> diff --git a/vipra-ui/app/js/controllers.js b/vipra-ui/app/js/controllers.js index 397e7b01c659fc95129d08b577fc3790f93e3ecb..b66a6f1d301689b4ccbbae6b9acd09efe4c7df4a 100644 --- a/vipra-ui/app/js/controllers.js +++ b/vipra-ui/app/js/controllers.js @@ -14,7 +14,8 @@ $scope.rootModels = { topicModel: null, - search: null + search: null, + title: 'Home' }; var prevTopicModelLoading = false; @@ -48,6 +49,10 @@ TopicModelFactory.query({ fields: '_all' }, function(data) { + for(var i = 0; i < data.length; i++) { + data[i].lastGeneratedString = data[i].lastGenerated ? Vipra.formatDateTime(data[i].lastGenerated) : 'never'; + data[i].lastIndexedString = data[i].lastIndexed ? Vipra.formatDateTime(data[i].lastIndexed) : 'never'; + } $scope.topicModels = data; }); }; @@ -67,6 +72,7 @@ $scope.changeTopicModel = function(topicModel) { $scope.rootModels.topicModel = topicModel; $('#topicModelModal').modal('hide'); + $('.popover').popover('hide'); localStorage.tm = topicModel.id; if($state.current.name != 'index') $state.transitionTo('index'); @@ -94,7 +100,7 @@ $state.transitionTo('index'); }); } - } + }; $scope.goBack = function() { $window.history.back(); @@ -197,6 +203,7 @@ */ app.controller('IndexController', ['$scope', '$stateParams', '$location', '$timeout', 'ArticleFactory', 'TopicFactory', 'SearchFactory', function($scope, $stateParams, $location, $timeout, ArticleFactory, TopicFactory, SearchFactory) { + $scope.rootModels.title = 'Home'; if (!$scope.rootModels.topicModel) $scope.chooseTopicModel(); @@ -268,6 +275,7 @@ */ app.controller('AboutController', ['$scope', 'InfoFactory', function($scope, InfoFactory) { + $scope.rootModels.title = 'About'; InfoFactory.get(function(data) { $scope.info = data; @@ -283,6 +291,7 @@ */ app.controller('NetworkController', ['$scope', '$state', '$stateParams', '$timeout', 'ArticleFactory', 'TopicFactory', 'WordFactory', function($scope, $state, $stateParams, $timeout, ArticleFactory, TopicFactory, WordFactory) { + $scope.rootModels.title = 'Network'; var id = 0, ids = {}, @@ -663,10 +672,11 @@ app.controller('ExplorerController', ['$scope', '$state', '$templateCache', '$timeout', 'TopicFactory', function($scope, $state, $templateCache, $timeout, TopicFactory) { + $scope.rootModels.title = 'Explorer'; $scope.checkTopicModel('explorer', function() { TopicFactory.query({ - fields: 'name,sequences,avgRelevance,varRelevance,risingRelevance,fallingRelevance,risingDecayRelevance,words', + fields: 'name,sequences,avgRelevance,varRelevance,risingRelevance,fallingRelevance,risingDecayRelevance,words,color', topicModel: $scope.rootModels.topicModel.id }, function(data) { $scope.topics = data; @@ -675,7 +685,7 @@ }); for (var i = 0, t; i < $scope.topics.length; i++) { t = $scope.topics[i]; - t.color = colors[i]; + t.color = t.color || colors[i]; avgMax = Math.max(t.avgRelevance, avgMax); varMax = Math.max(t.varRelevance, varMax); fallingMax = Math.max(t.fallingRelevance, fallingMax); @@ -941,6 +951,7 @@ */ app.controller('ArticlesIndexController', ['$scope', '$state', 'ArticleFactory', function($scope, $state, ArticleFactory) { + $scope.rootModels.title = 'Articles'; $scope.checkTopicModel('articles', function() { $scope.articlesIndexModels = { @@ -988,6 +999,7 @@ */ app.controller('ArticlesShowController', ['$scope', '$state', '$stateParams', '$timeout', 'ArticleFactory', function($scope, $state, $stateParams, $timeout, ArticleFactory) { + $scope.rootModels.title = 'Article'; $scope.articlesShowModels = { topicsSort: '-share', @@ -1003,6 +1015,7 @@ $scope.articleDate = Vipra.formatDate($scope.article.date); $scope.articleCreated = Vipra.formatDateTime($scope.article.created); $scope.articleModified = Vipra.formatDateTime($scope.article.modified); + $scope.rootModels.title = $scope.article.title; // calculate share from divergence if ($scope.article.similarArticles) { @@ -1027,12 +1040,12 @@ d = { name: topics[topicIndex].topic.name, y: topics[topicIndex].share, - color: colors[topicIndex], + color: topics[topicIndex].topic.color || colors[topicIndex], id: topics[topicIndex].topic.id }; topicShareSeries.push(d); - $scope.article.topics[topicIndex].color = colors[topicIndex]; + $scope.article.topics[topicIndex].color = $scope.article.topics[topicIndex].color || colors[topicIndex]; } } @@ -1118,6 +1131,7 @@ */ app.controller('TopicsIndexController', ['$scope', '$state', 'TopicFactory', function($scope, $state, TopicFactory) { + $scope.rootModels.title = 'Topics'; $scope.checkTopicModel('topics', function() { $scope.topicsIndexModels = { @@ -1165,6 +1179,7 @@ */ app.controller('TopicsShowController', ['$scope', '$state', '$stateParams', '$timeout', 'TopicFactory', 'SequenceFactory', function($scope, $state, $stateParams, $timeout, TopicFactory, SequenceFactory) { + $scope.rootModels.title = 'Topic'; $scope.topicsShowModels = { relSeqstyle: 'absolute', @@ -1180,6 +1195,7 @@ $scope.topic = data; $scope.topicCreated = Vipra.formatDateTime($scope.topic.created); $scope.topicModified = Vipra.formatDateTime($scope.topic.modified); + $scope.rootModels.title = $scope.topic.name; // take topic model from topic if (!angular.isObject($scope.rootModels.topicModel)) @@ -1355,6 +1371,7 @@ app.controller('EntitiesIndexController', ['$scope', '$state', 'EntityFactory', function($scope, $state, EntityFactory) { + $scope.rootModels.title = 'Entities'; $scope.checkTopicModel('entities', function() { $scope.entitiesIndexModels = { @@ -1399,6 +1416,7 @@ app.controller('EntitiesShowController', ['$scope', '$state', '$stateParams', 'EntityFactory', function($scope, $state, $stateParams, EntityFactory) { + $scope.rootModels.title = 'Entity'; $scope.checkTopicModel('entities.show', function() { EntityFactory.get({ @@ -1408,6 +1426,7 @@ $scope.entity = data; $scope.entityCreated = Vipra.formatDateTime($scope.entity.created); $scope.entityModified = Vipra.formatDateTime($scope.entity.modified); + $scope.rootModels.title = $scope.entity.entity; }); }); } @@ -1418,6 +1437,7 @@ $scope.checkTopicModel('entities.show.articles', function() { $scope.entity = $stateParams.id; + $scope.rootModels.title = $scope.entity; $scope.entitiesArticlesModels = { sortkey: 'date', @@ -1453,6 +1473,7 @@ app.controller('WordsIndexController', ['$scope', '$state', 'WordFactory', function($scope, $state, WordFactory) { + $scope.rootModels.title = 'Words'; $scope.checkTopicModel('words', function() { $scope.wordsIndexModels = { @@ -1495,6 +1516,7 @@ app.controller('WordsShowController', ['$scope', '$state', '$stateParams', 'WordFactory', function($scope, $state, $stateParams, WordFactory) { + $scope.rootModels.title = 'Word'; $scope.checkTopicModel('words.show', function() { WordFactory.get({ @@ -1502,6 +1524,7 @@ topicModel: $scope.rootModels.topicModel.id }, function(data) { $scope.word = data; + $scope.rootModels.title = $scope.word.word; }); }); } @@ -1512,6 +1535,7 @@ $scope.checkTopicModel('words.show.topics', function() { $scope.word = $stateParams.id; + $scope.rootModels.title = $scope.word; $scope.wordsTopicsModels = { sortkey: 'name', @@ -1542,6 +1566,7 @@ $scope.checkTopicModel('words.show.articles', function() { $scope.word = $stateParams.id; + $scope.rootModels.title = $scope.word; $scope.wordsArticlesModels = { sortkey: 'date', @@ -1573,6 +1598,7 @@ app.controller('SlidesController', ['$scope', function($scope) { + $scope.rootModels.title = 'Slides'; $scope.current = 1; var folder = '//ftp.cochu.io/vipra/slides/'; @@ -1601,6 +1627,7 @@ function($scope, $state, $stateParams) { $scope.code = $stateParams.code; $scope.title = Vipra.statusMsg($scope.code); + $scope.rootModels.title = 'Error: ' + $scope.code; } ]); diff --git a/vipra-ui/app/less/app.less b/vipra-ui/app/less/app.less index abe1031957f48f889cb89ae46511ab5b525caa3f..92792d737fe6b9ae14f982d3430c805686d43d51 100644 --- a/vipra-ui/app/less/app.less +++ b/vipra-ui/app/less/app.less @@ -699,7 +699,7 @@ entity-menu { } .pagination { - margin: 10px 0; + margin: 5px 0; } } @@ -964,6 +964,14 @@ entity-menu { position: relative; } +.topic-badge + .topic-badge { + margin-left: 3px; +} + +.text-outline { + text-shadow: 1px 1px 1px #888, 1px -1px 1px #888, -1px 1px 1px #888, -1px -1px 1px #888; +} + @keyframes spin { 100% { -webkit-transform: rotateY(360deg); diff --git a/vipra-util/src/main/java/de/vipra/util/ColorUtils.java b/vipra-util/src/main/java/de/vipra/util/ColorUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..534d7783e39b77b0a9eae741cd34151f6dd03f0f --- /dev/null +++ b/vipra-util/src/main/java/de/vipra/util/ColorUtils.java @@ -0,0 +1,83 @@ +package de.vipra.util; + +import java.awt.Color; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +public class ColorUtils { + + /** + * @see {@link #generateRandomColor(Long)} + */ + public static Color generateRandomColor() { + return generateRandomColor(null); + } + + /** + * Generate a random color, using an optional seed. + * + * @param seed + * optional random seed, null for default seed + * @return generated random color + */ + public static Color generateRandomColor(final Long seed) { + Random random = seed != null ? new Random(seed) : new Random(); + int red = (random.nextInt(256) + 255) / 2; + int green = (random.nextInt(256) + 255) / 2; + int blue = (random.nextInt(256) + 255) / 2; + Color color = new Color(red, green, blue); + return color; + } + + /** + * @see {@link #generateRandomColors(int, Long)} + */ + public static List<Color> generateRandomColors(final int number) { + return generateRandomColors(number, null); + } + + /** + * Generate random colors, using an optional seed. + * + * @param number + * how many colors to generate + * @param seed + * optional random seed, null for default seed + * @return generated random colors + */ + public static List<Color> generateRandomColors(final int number, final Long seed) { + Random random = seed != null ? new Random(seed) : new Random(); + final List<Color> colors = new ArrayList<>(number); + for (int i = 0; i < number; i++) { + int red = (random.nextInt(256) + 255) / 2; + int green = (random.nextInt(256) + 255) / 2; + int blue = (random.nextInt(256) + 255) / 2; + colors.add(new Color(red, green, blue)); + } + return colors; + } + + /** + * Turns a Color object into a hexadecimal string of format #ABCDEF. + * + * @param color + * Color to transform into hex string + * @return hex string + */ + public static String toHexString(final Color color) { + return String.format("#%02X%02X%02X", color.getRed(), color.getGreen(), color.getBlue()); + } + + /** + * Parses a hexadecimal string into a Color object. + * + * @param hex + * hexadecimal string + * @return Color object + */ + public static Color fromHexString(final String hex) { + return Color.decode(hex); + } + +} diff --git a/vipra-util/src/main/java/de/vipra/util/model/Topic.java b/vipra-util/src/main/java/de/vipra/util/model/Topic.java index ef9696e175b1e6f0f96924ad2abdd352f380221c..2f6e0b880e8faa63c2275b9d0784e6fbb331c4c1 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/Topic.java +++ b/vipra-util/src/main/java/de/vipra/util/model/Topic.java @@ -25,17 +25,14 @@ public class Topic implements Model<ObjectId>, Serializable { private Integer articlesCount; + private String color; + public Topic() {} public Topic(final ObjectId id) { this.id = id; } - public Topic(final ObjectId id, final String name) { - this.id = id; - this.name = name; - } - @Override public ObjectId getId() { return id; @@ -66,6 +63,14 @@ public class Topic implements Model<ObjectId>, Serializable { this.articlesCount = articlesCount; } + public String getColor() { + return color; + } + + public void setColor(String color) { + this.color = color; + } + @Override public boolean equals(final Object o) { if (o == null) diff --git a/vipra-util/src/main/java/de/vipra/util/model/TopicFull.java b/vipra-util/src/main/java/de/vipra/util/model/TopicFull.java index d74dc24cec63e1fab2e5274619e7b7059c2596ad..2e61b2743564e0da1dfe499899c9f582a7bf682e 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/TopicFull.java +++ b/vipra-util/src/main/java/de/vipra/util/model/TopicFull.java @@ -66,6 +66,8 @@ public class TopicFull implements Model<ObjectId>, Serializable { private Integer articlesCount; + private String color; + @QueryIgnore(multi = true) private Date created; @@ -174,6 +176,14 @@ public class TopicFull implements Model<ObjectId>, Serializable { this.articlesCount = articlesCount; } + public String getColor() { + return color; + } + + public void setColor(String color) { + this.color = color; + } + public Date getCreated() { return created; } diff --git a/vipra-util/src/main/java/de/vipra/util/model/TopicModelFull.java b/vipra-util/src/main/java/de/vipra/util/model/TopicModelFull.java index 8ae0afae9919186bbcc67860659b0d4e1a638220..50c7e4b23494a3d0e0d8cb5274b3a6925cb9cbf3 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/TopicModelFull.java +++ b/vipra-util/src/main/java/de/vipra/util/model/TopicModelFull.java @@ -39,6 +39,8 @@ public class TopicModelFull implements Model<ObjectId>, Comparable<TopicModelFul private Date lastIndexed; + private Long colorSeed; + @Embedded @QueryIgnore(multi = true) private List<Window> windows; @@ -146,6 +148,14 @@ public class TopicModelFull implements Model<ObjectId>, Comparable<TopicModelFul this.lastIndexed = lastIndexed; } + public Long getColorSeed() { + return colorSeed; + } + + public void setColorSeed(Long colorSeed) { + this.colorSeed = colorSeed; + } + public List<Window> getWindows() { return windows; }