Commit 7cb9b272 authored by Julien Wintz's avatar Julien Wintz
Browse files

Adding tag cloud in widgets layer. Together with *manual* test.

parent 72aba805
......@@ -3,9 +3,9 @@
## Author: Julien Wintz
## Created: Mon Feb 4 10:17:21 2013 (+0100)
## Version:
## Last-Updated: Wed Apr 10 16:30:55 2013 (+0200)
## By: Thibaud Kloczko
## Update #: 173
## Last-Updated: Mon Apr 15 12:13:04 2013 (+0200)
## By: Julien Wintz
## Update #: 179
######################################################################
##
### Change Log:
......@@ -82,11 +82,12 @@ find_package(Qt53D QUIET)
include_directories(${PROJECT_SOURCE_DIR}/src)
include_directories(${PROJECT_SOURCE_DIR}/src/dtk)
include_directories(${PROJECT_SOURCE_DIR}/src/dtkLog)
include_directories(${PROJECT_SOURCE_DIR}/src/dtkTest)
include_directories(${PROJECT_SOURCE_DIR}/src/dtkComposer)
include_directories(${PROJECT_SOURCE_DIR}/src/dtkCore)
include_directories(${PROJECT_SOURCE_DIR}/src/dtkDistributed)
include_directories(${PROJECT_SOURCE_DIR}/src/dtkComposer)
include_directories(${PROJECT_SOURCE_DIR}/src/dtkLog)
include_directories(${PROJECT_SOURCE_DIR}/src/dtkTest)
include_directories(${PROJECT_SOURCE_DIR}/src/dtkWidgets)
if(Qt53D_FOUND)
include_directories(${PROJECT_SOURCE_DIR}/src/dtk3D)
include_directories(${PROJECT_SOURCE_DIR}/src/dtk3DQuick)
......
......@@ -3,9 +3,9 @@
## Author: Julien Wintz
## Created: Mon Feb 4 10:29:13 2013 (+0100)
## Version:
## Last-Updated: Tue Apr 9 13:13:57 2013 (+0200)
## By: Thibaud Kloczko
## Update #: 64
## Last-Updated: Mon Apr 15 11:48:22 2013 (+0200)
## By: Julien Wintz
## Update #: 78
######################################################################
##
### Change Log:
......@@ -13,11 +13,12 @@
######################################################################
add_subdirectory(dtk)
add_subdirectory(dtkLog)
add_subdirectory(dtkTest)
add_subdirectory(dtkCore)
add_subdirectory(dtkDistributed)
add_subdirectory(dtkComposer)
add_subdirectory(dtkDistributed)
add_subdirectory(dtkLog)
add_subdirectory(dtkTest)
add_subdirectory(dtkWidgets)
if(Qt53D_FOUND)
add_subdirectory(dtk3D)
......@@ -27,8 +28,9 @@ endif(Qt53D_FOUND)
set(DTK_TARGETS)
set(DTK_TARGETS ${DTK_TARGETS} dtkLog)
set(DTK_TARGETS ${DTK_TARGETS} dtkCore)
set(DTK_TARGETS ${DTK_TARGETS} dtkDistributed)
set(DTK_TARGETS ${DTK_TARGETS} dtkComposer)
set(DTK_TARGETS ${DTK_TARGETS} dtkDistributed)
set(DTK_TARGETS ${DTK_TARGETS} dtkWidgets)
if(Qt53D_FOUND)
set(DTK_TARGETS ${DTK_TARGETS} dtk3D)
......
### CMakeLists.txt ---
##
## Author: Julien Wintz
## Created: Mon Apr 15 11:46:27 2013 (+0200)
## Version:
## Last-Updated: Mon Apr 15 15:42:28 2013 (+0200)
## By: Julien Wintz
## Update #: 57
######################################################################
##
### Change Log:
##
######################################################################
project(dtkWidgets)
## #################################################################
## Input
## #################################################################
set(${PROJECT_NAME}_HEADERS
dtkWidgetsTag.h
dtkWidgetsTagCloud.h
dtkWidgetsTagCloudController.h
dtkWidgetsTagCloudDesc.h
dtkWidgetsTagCloudItem.h
dtkWidgetsTagCloudLayout.h
dtkWidgetsTagCloudList.h
dtkWidgetsTagCloudScope.h
dtkWidgetsTagCloudScopeItem.h
dtkWidgetsTagCloudView.h)
set(${PROJECT_NAME}_SOURCES
dtkWidgetsTag.cpp
dtkWidgetsTagCloud.cpp
dtkWidgetsTagCloudController.cpp
dtkWidgetsTagCloudDesc.cpp
dtkWidgetsTagCloudItem.cpp
dtkWidgetsTagCloudLayout.cpp
dtkWidgetsTagCloudList.cpp
dtkWidgetsTagCloudScope.cpp
dtkWidgetsTagCloudScopeItem.cpp
dtkWidgetsTagCloudView.cpp)
set(${PROJECT_NAME}_SOURCES_RCC
dtkWidgetsTagCloud.qrc)
## #################################################################
## Build rules
## #################################################################
qt5_add_resources(${PROJECT_NAME}_SOURCES_QRC ${${PROJECT_NAME}_SOURCES_RCC})
add_library(${PROJECT_NAME} SHARED
${${PROJECT_NAME}_SOURCES_QRC}
${${PROJECT_NAME}_SOURCES}
${${PROJECT_NAME}_HEADERS})
# target_link_libraries(${PROJECT_NAME} ...)
## ###################################################################
## Link rules
## ###################################################################
qt5_use_modules(${PROJECT_NAME} Core)
qt5_use_modules(${PROJECT_NAME} Gui)
qt5_use_modules(${PROJECT_NAME} Widgets)
## ###################################################################
## Install rules - files
## ###################################################################
install(FILES ${${PROJECT_NAME}_HEADERS}
DESTINATION include/${PROJECT_NAME}
COMPONENT widgets)
## ###################################################################
## Install rules - targets
## ###################################################################
install(TARGETS ${PROJECT_NAME}
DESTINATION lib
COMPONENT widgets
EXPORT dtkDepends)
#include "dtkWidgetsTag.h"
#include "dtkWidgetsTagCloud.h"
#include "dtkWidgetsTagCloudController.h"
#include "dtkWidgetsTagCloudDesc.h"
#include "dtkWidgetsTagCloudItem.h"
#include "dtkWidgetsTagCloudLayout.h"
#include "dtkWidgetsTagCloudList.h"
#include "dtkWidgetsTagCloudScope.h"
#include "dtkWidgetsTagCloudView.h"
#include "dtkWidgetsTagCloudLayout.h"
#include "dtkWidgetsTag.h"
/* dtkWidgetsTag.cpp ---
*
* Author: Julien Wintz
* Created: Mon Apr 15 11:52:23 2013 (+0200)
* Version:
* Last-Updated: Mon Apr 15 11:56:24 2013 (+0200)
* By: Julien Wintz
* Update #: 7
*/
/* Change Log:
*
*/
#include "dtkWidgetsTag.h"
class dtkWidgetsTagPrivate
{
public:
int count;
QString text;
QString color;
QStringList items;
};
dtkWidgetsTag::dtkWidgetsTag(void) : d(new dtkWidgetsTagPrivate)
{
}
dtkWidgetsTag::dtkWidgetsTag(QString text, int count) : d(new dtkWidgetsTagPrivate)
{
d->text = text;
d->count = count;
}
dtkWidgetsTag::dtkWidgetsTag(QString text, int count, QStringList items) : d(new dtkWidgetsTagPrivate)
{
d->text = text;
d->count = count;
d->items = items;
}
dtkWidgetsTag::dtkWidgetsTag(QString text, int count, QStringList items, QString color) : d(new dtkWidgetsTagPrivate)
{
d->text = text;
d->count = count;
d->items = items;
d->color = color;
}
dtkWidgetsTag::dtkWidgetsTag(const dtkWidgetsTag& other) : d(new dtkWidgetsTagPrivate)
{
d->text = other.d->text;
d->count = other.d->count;
d->items = other.d->items;
d->color = other.d->color;
}
dtkWidgetsTag::~dtkWidgetsTag(void)
{
delete d;
d = NULL;
}
int dtkWidgetsTag::count(void) const
{
return d->count;
}
QString dtkWidgetsTag::text(void) const
{
return d->text;
}
QStringList dtkWidgetsTag::items(void) const
{
return d->items;
}
QString dtkWidgetsTag::color(void) const
{
return d->color;
}
void dtkWidgetsTag::setCount(int count)
{
if (count > 0)
d->count = count;
else
d->count = count;
}
void dtkWidgetsTag::setText(QString text)
{
if (!text.isNull())
d->text = text;
else
d->text = "";
}
void dtkWidgetsTag::setItems(QStringList items)
{
if (!items.isEmpty())
d->items = items;
else
d->items = QStringList();
}
void dtkWidgetsTag::setColor(QString color)
{
if (!color.isNull())
d->color = color;
else
d->color = "";
}
/* dtkWidgetsTag.h ---
*
* Author: Julien Wintz
* Created: Mon Apr 15 11:51:10 2013 (+0200)
* Version:
* Last-Updated: Mon Apr 15 11:56:48 2013 (+0200)
* By: Julien Wintz
* Update #: 10
*/
/* Change Log:
*
*/
#pragma once
#include <QtWidgets>
class dtkWidgetsTagPrivate;
class dtkWidgetsTag
{
public:
dtkWidgetsTag(void);
dtkWidgetsTag(QString text, int instances);
dtkWidgetsTag(QString text, int instances, QStringList items);
dtkWidgetsTag(QString text, int instances, QStringList items, QString color);
dtkWidgetsTag(const dtkWidgetsTag& other);
~dtkWidgetsTag(void);
int count(void) const;
QString text(void) const;
QString color(void) const;
QStringList items(void) const;
void setCount(int count);
void setText(QString text);
void setColor(QString color);
void setItems(QStringList items);
protected:
dtkWidgetsTagPrivate *d;
};
#include "dtkWidgetsTagCloud.h"
/* dtkWidgetsTagCloud.cpp ---
*
* Author: Julien Wintz
* Created: Mon Apr 15 12:00:34 2013 (+0200)
* Version:
* Last-Updated: Mon Apr 15 12:05:31 2013 (+0200)
* By: Julien Wintz
* Update #: 17
*/
/* Change Log:
*
*/
#include "dtkWidgetsTag.h"
#include "dtkWidgetsTagCloud.h"
// /////////////////////////////////////////////////////////////////
// Helper functions
// /////////////////////////////////////////////////////////////////
bool dtkWidgetsTagAlphaLessThan(const dtkWidgetsTag &t1, const dtkWidgetsTag &t2) {
return t1.text() < t2.text();
}
bool dtkWidgetsTagNumLessThan(const dtkWidgetsTag &t1, const dtkWidgetsTag &t2) {
return t1.count() < t2.count();
}
bool dtkWidgetsTagAlphaMoreThan(const dtkWidgetsTag &t1, const dtkWidgetsTag &t2) {
return t1.text() >= t2.text();
}
bool dtkWidgetsTagNumMoreThan(const dtkWidgetsTag &t1, const dtkWidgetsTag &t2) {
return t1.count() >= t2.count();
}
// /////////////////////////////////////////////////////////////////
// dtkWidgetsTagCloudHasher
// /////////////////////////////////////////////////////////////////
class dtkWidgetsTagCloudHasher
{
public:
dtkWidgetsTagCloudHasher(int buckets, int min, int max) {
if (buckets < 1)
qDebug() << "dtkWidgetsTagCloudHasher: Must have at least one bucket.";
this->buckets = buckets;
this->min = min;
this->max = max+1;
this->width = ((double)(this->max-this->min))/((double)(this->buckets));
}
int bucket(dtkWidgetsTag tag) {
return ((float)(tag.count()-this->min))/((float)(this->width));
}
private:
int min, max, buckets;
private:
double width;
};
// ///////////////////////////////////////////////////////////////////
// dtkWidgetsTagCloudPrivate
// ///////////////////////////////////////////////////////////////////
class dtkWidgetsTagCloudPrivate
{
public:
QList<dtkWidgetsTag> tags;
int averageFontSize;
int fontSizeRange;
int mincount;
int maxcount;
int tagCount;
dtkWidgetsTagCloud::SortingType sortingType;
dtkWidgetsTagCloud::SortingOrder sortingOrder;
};
// /////////////////////////////////////////////////////////////////
// dtkWidgetsTagCloud
// /////////////////////////////////////////////////////////////////
dtkWidgetsTagCloud::dtkWidgetsTagCloud(QWidget *parent) : QTextBrowser(parent)
{
d = new dtkWidgetsTagCloudPrivate;
d->averageFontSize = 0;
d->fontSizeRange = 0;
d->sortingType = Alpha;
d->sortingOrder = Asc;
this->setFrameShape(QFrame::NoFrame);
connect(this, SIGNAL(anchorClicked(const QUrl&)), this, SLOT(onLinkClicked(const QUrl&)));
}
dtkWidgetsTagCloud::~dtkWidgetsTagCloud(void)
{
delete d;
d = NULL;
}
void dtkWidgetsTagCloud::addTag(QString text, int count)
{
d->tags << dtkWidgetsTag(text, count);
}
void dtkWidgetsTagCloud::addTag(QString text, int count, QStringList items)
{
d->tags << dtkWidgetsTag(text, count, items);
}
void dtkWidgetsTagCloud::addTag(QString text, int count, QStringList items, QString color)
{
d->tags << dtkWidgetsTag(text, count, items, color);
}
void dtkWidgetsTagCloud::addTag(dtkWidgetsTag tag)
{
d->tags << tag;
}
void dtkWidgetsTagCloud::setFontSize(int size)
{
d->averageFontSize = (size > 0) ? size : 0;
}
void dtkWidgetsTagCloud::setFontRange(int range)
{
d->fontSizeRange = (range > 0) ? range: 0;
}
void dtkWidgetsTagCloud::setSortingType(SortingType type)
{
d->sortingType = type;
}
void dtkWidgetsTagCloud::setSortingOrder(SortingOrder order)
{
d->sortingOrder = order;
}
void dtkWidgetsTagCloud::sort(void)
{
if(d->sortingType == Alpha && d->sortingOrder == Asc)
qSort(d->tags.begin(), d->tags.end(), dtkWidgetsTagAlphaLessThan);
if(d->sortingType == Alpha && d->sortingOrder == Desc)
qSort(d->tags.begin(), d->tags.end(), dtkWidgetsTagAlphaMoreThan);
if(d->sortingType == Num && d->sortingOrder == Asc)
qSort(d->tags.begin(), d->tags.end(), dtkWidgetsTagNumLessThan);
if(d->sortingType == Num && d->sortingOrder == Desc)
qSort(d->tags.begin(), d->tags.end(), dtkWidgetsTagNumMoreThan);
}
void dtkWidgetsTagCloud::clear(void)
{
d->tags.clear();
this->render();
}
void dtkWidgetsTagCloud::render(void)
{
if (d->averageFontSize <= 0)
qDebug() << "AverageFontSize must be non-zero and non-negative.";
if (d->fontSizeRange <= 0)
qDebug() << "FontSizeRange must be non-zero and non-negative.";
if (d->tags.isEmpty())
return;
d->mincount = 100000000;
d->maxcount = 0;
d->tagCount = 0;
foreach (dtkWidgetsTag tag, d->tags) {
if (tag.count() < d->mincount)
d->mincount = tag.count();
if (tag.count() > d->maxcount)
d->maxcount = tag.count();
d->tagCount++;
}
dtkWidgetsTagCloudHasher hasher(d->fontSizeRange, d->mincount, d->maxcount);
int baseFontSize = d->averageFontSize - ((double)(d->fontSizeRange-1)/2);
QString cloud; cloud.append(QString("<div align=\"justify\">\n"));
foreach (dtkWidgetsTag tag, d->tags) {
int fontSize = baseFontSize + hasher.bucket(tag);
QString color = "";
if (!tag.color().isEmpty()) {
color = "color: ";
color += (!tag.color().startsWith("#")) ? "#" : "";
color += tag.color();
color += ";";
} else {
color = "color: #6a769d;";
}
QString count = QString::number(tag.count()) + " item" + ((tag.count() != 1) ? "s" : "");
cloud.append(QString("<a href=\"tag://%1\" title=\"%2\" style=\"font-size: %4px; text-decoration: none; %5\" item=\"%3\">%1</a> ")
.arg(tag.text())
.arg(count)
.arg(tag.items().first())
.arg(fontSize)
.arg(color));
}
cloud.append("</div>\n");
this->setHtml(cloud);
}
void dtkWidgetsTagCloud::onLinkClicked(const QUrl& url)
{
emit tagClicked(url.host());
}
/* dtkWidgetsTagCloud.h ---
*
* Author: Julien Wintz
* Created: Mon Apr 15 11:58:05 2013 (+0200)
* Version:
* Last-Updated: Mon Apr 15 12:04:40 2013 (+0200)
* By: Julien Wintz
* Update #: 21
*/
/* Change Log:
*
*/
#pragma once
#include "dtkWidgetsTag.h"
#include <QtWidgets>
class dtkWidgetsTagCloudPrivate;
class dtkWidgetsTagCloud : public QTextBrowser
{
Q_OBJECT
public:
enum SortingType {
Alpha,
Num
};
enum SortingOrder {
Asc,
Desc
};
public:
dtkWidgetsTagCloud(QWidget *parent = 0);
~dtkWidgetsTagCloud(void);
#pragma mark -
#pragma mark Tag management