#include <QPainter>
#include <QDebug>
#include <QPixmapCache>
#include <QTimerEvent>
#include <QKeyEvent>
#include <QImageReader>
#include <QDir>
#include <QTimer>
#include <QLabel>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include "iconview.h"
IconView::IconView(QWidget *parent) : QWidget(parent)
{
paintTimerId = 0;
thumbTimerId = 0;
index = 0;
changeDirectory("Internal");
QPixmapCache::setCacheLimit(64000);
QPixmapCache::insert("folder", QPixmap("icons/b/folder.png"));
QPixmapCache::insert("thumb", QPixmap("icons/b/thumb.png"));
curItemX = 0;
curItemY = 0;
offset = 0;
}
IconView::~IconView()
{
}
static void addIconToCache(QString filename, QString label, QPixmap icon)
{
QFont font("Arial",11);
QPixmap dummy(88,68);
if (!QPixmapCache::find(filename, dummy)) {
dummy.fill(QColor(0,0,0,0));
QPainter p(&dummy);
p.setPen(Qt::NoPen);
p.setBrush(QColor(178,178,178,64));
p.drawRect(0, 0, 88, 68);
p.drawPixmap(20, 3, icon);
QFontMetrics fm(font);
p.setFont(font);
QString str = fm.elidedText(label, Qt::ElideRight, 88);
int w = fm.width(str);
p.setPen(QColor(64,64,64));
p.drawText((88-w)/2+1, 66, str);
p.setPen(Qt::white);
p.drawText((88-w)/2, 65, str);
p.end();
QPixmapCache::insert(filename, dummy);
}
}
void IconView::stopAllTimers()
{
if (paintTimerId)
killTimer(paintTimerId);
if (thumbTimerId)
killTimer(thumbTimerId);
paintTimerId = 0;
thumbTimerId = 0;
}
//
// Setup test Flickr accounts
// a) dpftestone@yahoo.com (dpftestone) - usual password
// b) john_adrift@yahoo.com (DPF_TEST) - usual password
//
// Flickr API Keys
//
// Public: eb80500c583ad16715f96267ff4c5097
// Private: 45cfaca66221b89b
// Auth-URL: http://www.flickr.com/auth-72157616485890735
// FROB: 523-690-296
// Auth-Token: 72157616498836181-d98bf47cc39a6a2b
//
void IconView::getSharesList(QString machine)
{
stopAllTimers();
index = 0;
curItemX = -1;
curItemY = -1;
offset = 0;
directory = "Network/" + machine;
if ( machineSharesMap[machine].count() )
entryList = machineSharesMap[machine];
repaint();
emit directoryChanged(directory);
if ( machineSharesMap[machine].count() )
return;
entryList.clear();
machineSharesMap[machine] << QString(".");
entryList << QString(".");
QPixmap folder = QPixmap("icons/b/folder.png");
QString cmd = "smbclient -N -L \\\\" + machine + " -g";
qDebug() << cmd;
#ifndef _WIN32
FILE *fd = popen(cmd.toLatin1().data(), "r");
char *okay = (char*)1;
while ( okay ) {
char buf[1024];
okay = fgets(buf, 1024, fd);
fprintf(stderr, "A: %i %s\n", (int)okay, buf);
if ( okay ) {
char *start = strnstr(buf, "|", 1024);
fprintf(stderr, "B: %s\n", start);
if ( start ) {
char *end = strnstr(start + 1, "|", 1024);
if ( end )
end[0] = '\0';
fprintf(stderr, "C: %s\n", start + 1);
machineSharesMap[machine] << QString(start + 1);
entryList << QString(start + 1);
}
}
}
pclose(fd);
#endif // _WIN32
for (int i = 0; i < (int)entryList.count(); i++) {
QString label = entryList[i];
QString filename = "photos/Network/" + machine + "/" + label;
addIconToCache(filename, label, folder);
}
paintTimerId = startTimer(30);
}
void IconView::getMachineList()
{
stopAllTimers();
if ( machines.count() ) {
// XXX always uses cached values for machine list
// perhaps should refresh sometimes
entryList = machines;
}
index = 0;
curItemX = -1;
curItemY = -1;
offset = 0;
directory = "Network";
repaint();
emit directoryChanged("Network");
if ( machines.count() ) {
return;
}
entryList.clear();
machines.clear();
machines << QString(".");
entryList << QString(".");
#ifndef _WIN32
FILE *fd = popen("smbtree -b -N -S", "r");
char *okay = (char*)1;
while ( okay ) {
char buf[1024];
okay = fgets(buf, 1024, fd);
if ( okay ) {
char *start = strnstr(buf, "\\\\", 1024);
if ( start ) {
char *end = strnstr(start, " ", 1024);
if ( end )
end[0] = '\0';
machines << QString(start + 2);
entryList << QString(start + 2);
}
}
}
pclose(fd);
#endif // _WIN32
QPixmap folder = QPixmap("icons/b/folder.png");
for (int i = 0; i < (int)machines.count(); i++) {
QString label = machines[i];
QString filename = "photos/Network/" + label;
addIconToCache(filename, label, folder);
}
// thumbTimerId = startTimer(5);
// XXX Need to consider iterative population of the machines on the network
// and also perhaps test case of if there are more than 30 machines on the network!
paintTimerId = startTimer(30);
}
void IconView::changeDirectory(QString dirStr)
{
stopAllTimers();
QDir d1("photos/" + dirStr);
dirStr = d1.absolutePath();
QDir d2("photos");
directory = d2.relativeFilePath(dirStr);
index = 0;
curItemX = -1;
curItemY = -1;
offset = 0;
repaint();
if ( !QFile::exists("photos/" + directory) )
return;
emit directoryChanged(directory);
dir = QDir("photos/" + directory);
dir.setSorting(QDir::Name | QDir::DirsFirst);
entryList = dir.entryList();
entryInfoList = dir.entryInfoList();
QPixmap folder = QPixmap("icons/b/folder.png");
QPixmap thumb = QPixmap("icons/b/thumb.png");
QPixmap back = QPixmap("icons/b/back.png");
QFont font("Arial",11);
for (int i = 0; i < (int)dir.count(); i++) {
QFileInfo fi = entryInfoList[i];
QString filename = "photos/" + directory + "/" + fi.fileName();
QPixmap dummy(88,68);
if (!QPixmapCache::find(filename, dummy)) {
dummy.fill(QColor(0,0,0,0));
QPainter p(&dummy);
p.setPen(Qt::NoPen);
p.setBrush(QColor(178,178,178,64));
p.drawRect(0, 0, 88, 68);
QString label = fi.fileName();
if ( fi.isFile() ) {
p.drawPixmap(20, 3, thumb);
} else if ( fi.isDir() ) {
if (label == "..") {
label = "Up";
p.drawPixmap(20, 3, back);
} else {
p.drawPixmap(20, 3, folder);
}
}
QFontMetrics fm(font);
p.setFont(font);
QString str = fm.elidedText(label, Qt::ElideRight, 88);
int w = fm.width(str);
p.setPen(QColor(64,64,64));
p.drawText((88-w)/2+1, 66, str);
p.setPen(Qt::white);
p.drawText((88-w)/2, 65, str);
p.end();
QPixmapCache::insert(filename, dummy);
}
}
thumbTimerId = startTimer(5);
paintTimerId = startTimer(30);
}
static QPixmap loadThumbnail(QString filename, QSize size)
{
QPixmap thumb;
ExifLoader *loader = exif_loader_new();
if ( !loader )
return thumb;
exif_loader_write_file(loader, filename.toLatin1().data());
ExifData *ed = exif_loader_get_data(loader);
if (ed && ed->data && ed->size) {
thumb.loadFromData(ed->data, ed->size);
thumb = thumb.scaled(size.width(), size.height());
} else {
QImageReader iio(filename);
iio.setScaledSize(size);
iio.setQuality(0);
QImage img = iio.read();
if ( img.isNull() )
return thumb;
thumb = thumb.fromImage(img);
}
exif_data_unref(ed);
exif_loader_unref(loader);
return thumb;
}
void IconView::timerEvent(QTimerEvent *te)
{
if (te->timerId() == thumbTimerId) {
int cnt = 4;
if ( directory.left(8) == "Network/" )
cnt = 1;
for (int i = 0; i < cnt; i++) {
QFileInfo fi = entryInfoList[index];
QString filename = "photos/" + directory + "/" + fi.fileName();
if ( fi.isFile() ) {
QPixmap thumb = loadThumbnail(filename, QSize(88,68));
if (!thumb.isNull())
QPixmapCache::insert(filename, thumb);
}
index++;
if (index >= dir.count()) {
killTimer(thumbTimerId);
thumbTimerId = 0;
return;
}
/*
else if (index >= 21 ) {
killTimer(thumbTimerId);
thumbTimerId = startTimer(200);
}
*/
}
} else if (te->timerId() == paintTimerId) {
update();
if (index >= offset + 30 || index >= dir.count()) {
// deliberately seperate to the killTimer for thumbTimerId
// because doing it here will allow the last update() to happpen
killTimer(paintTimerId);
paintTimerId = 0;
}
}
}
void IconView::setFocusItem(int x, int y)
{
curItemX = x;
curItemY = y;
offset = 1;
repaint();
}
class FadeInOutPreview : public QWidget
{
public:
int speed;
bool autoOut;
FadeInOutPreview(QWidget *parent, QString file, int _x, int _y, int exp, int s, bool ao = false) : QWidget(parent) {
expandFactor = exp;
autoOut = ao;
speed = s;
tick = 0;
x = _x;
y = _y;
pix = QPixmap(file);
QSize size = pix.size();
size.scale(600,350,Qt::KeepAspectRatio);
pix = pix.scaled(size);
setGeometry(0, 0, 800, 480);
//QTimer::singleShot(2000, this, SLOT(deleteLater()));
fadeInId = 0;
fadeOutId = 0;
tmp = 0;
}
~FadeInOutPreview() { }
void fadeIn() {
show();
fadeInId = startTimer(speed);
}
void fadeOut() {
fadeOutId = startTimer(speed);
}
int fadeInId;
int fadeOutId;
int tmp;
void timerEvent(QTimerEvent *te) {
if (te->timerId() == fadeInId) {
tick++;
if (tick > 30) {
tick = 30;
tmp++;
if (tmp > 40) {
killTimer(fadeInId);
fadeInId = 0;
if (autoOut)
fadeOut();
}
}
}
if (te->timerId() == fadeOutId) {
tick++;
if ( tick > 60 ) {
hide();
killTimer(fadeOutId);
fadeOutId = 0;
}
}
update();
}
void paintEvent(QPaintEvent *pe) {
QPainter p(this);
QPixmap p2;
QSize size = pix.size();
float ratio = 1.0;
float fadeRatio = 1.0;
if ( tick < 20 - expandFactor ) {
ratio = tick / 20.0;
} else if ( tick < 40 + expandFactor ) {
ratio = (60.0 - 40 - expandFactor) / 20.0;
} else {
ratio = (60.0 - tick) / 20.0;
}
if ( tick < 20 ) {
fadeRatio = tick / 20.0;
} else if ( tick < 40 ) {
fadeRatio = 1.0;
} else {
fadeRatio = (60.0 - tick) / 20.0;
}
size.scale(ratio*(800-90)+90, ratio*(480-70)+70, Qt::KeepAspectRatio);
p2 = pix.scaled(size);
int _x = -15+(1.0-ratio)*x+((ratio*(800-90)+90)/2)-size.width()/2;
int _y = -15+(1.0-ratio)*y+((ratio*(480-70)+70)/2)-size.height()/2;
p.setPen(Qt::NoPen);
p.setBrush(QColor(32,32,32,128));
p.drawRect(12 + _x, 12 + _y, size.width(), size.height());
p.setOpacity(fadeRatio);
p.drawPixmap(_x, _y, p2);
}
QPixmap pix;
int tick;
int x, y;
int expandFactor;
};
void IconView::keyPressEvent(QKeyEvent *ke)
{
/*
static FadeInOutPreview *oldI = 0;
static FadeInOutPreview *newI = 0;
static int oldCurItemX = 0;
static int oldCurItemY = 0;
QString filename = "photos/" + directory + "/" + entryList[curItemX+curItemY*5+offset];
if (oldI)
oldI->deleteLater();
oldI = new FadeInOutPreview(parentWidget(), filename, curItemX*100+320, curItemY*80+180, 17, 1);
oldI->fadeIn();
oldCurItemX = curItemX;
oldCurItemY = curItemY;
*/
if (ke->key() == Qt::Key_Down) {
if ( (unsigned)entryList.count() > (offset + (unsigned)curItemX + (unsigned)curItemY * 5 + 5) )
curItemY++;
if (curItemY > 3) {
curItemY = 3;
if ( entryList.count() - offset >= 21 + (unsigned)curItemX ) {
offset += 5;
}
}
}
if (ke->key() == Qt::Key_Right) {
if ( (unsigned)entryList.count() > (offset + (unsigned)curItemX + (unsigned)curItemY * 5 + 1) )
curItemX++;
if (curItemX > 4) {
if (curItemY > 2) {
if ( entryList.count() - offset <= 20 ) {
curItemX = 4;
curItemY = 3;
} else {
curItemX = 0;
curItemY = 3;
offset += 5;
}
} else {
curItemX = 0;
curItemY++;
}
}
}
if (ke->key() == Qt::Key_Up) {
curItemY--;
if (curItemY < 0) {
curItemY = 0;
if ( offset > 5 ) {
offset -= 5;
}
}
}
if (ke->key() == Qt::Key_Left) {
curItemX--;
if (curItemX < -1) {
curItemX = -1;
}
if (curItemX == -1) {
if (curItemY == 0) {
if ( offset > 5 ) {
curItemX = 4;
offset -= 5;
} else {
emit switchFocus();
}
} else {
curItemY--;
curItemX = 4;
}
}
}
/*
if ( curItemX != oldCurItemX || curItemY != oldCurItemY ) {
oldI->fadeOut();
if (newI)
newI->deleteLater();
QString filename = "photos/" + directory + "/" + entryList[curItemX+curItemY*5+offset];
newI = new FadeInOutPreview(parentWidget(), filename, curItemX*100+320, curItemY*80+180, 17, 1);
newI->fadeIn();
oldCurItemX = curItemX;
oldCurItemY = curItemY;
FadeInOutPreview *oldITmp = oldI;
oldI = newI;
newI = oldITmp;
}
*/
if (ke->key() == Qt::Key_Return) {
if ( directory == "Network" ) {
fprintf(stderr, "opening computer shares");
QString computer = entryList[curItemX+curItemY*5+offset];
getSharesList(computer);
setFocusItem(0,0);
repaint();
return;
} else if ( directory.left(8) == "Network/" ) {
char *dirname = directory.toLatin1().data() + 8;
QString computer = dirname;
QString shareName = entryList[curItemX+curItemY*5+offset];
char *okay = strstr(dirname, "/");
#ifndef _WIN32
if (!okay) { // It's a share name
QString tmp = "photos/Network/" + computer;
qDebug() << "makeing dir " << tmp;
mkdir(tmp.toLatin1().data(), 0777);
tmp = "photos/Network/" + computer + "/" + shareName;
qDebug() << "makeing dir " << tmp;
mkdir(tmp.toLatin1().data(), 0777);
//mountShare(directory);
QString cmd = "mount_smbfs -N //guest:@" + computer + "/" + shareName + " " + tmp;
qDebug() << "exec: " << cmd;
system(cmd.toLatin1().data());
// XXX need to undo
//QString cmd = "umount " + tmp;
}
#endif // _WIN32
}
QString filename = "photos/" + directory + "/" + entryList[curItemX+curItemY*5+offset];
if (QFileInfo(filename).isDir()) {
changeDirectory(directory + "/" + entryList[curItemX+curItemY*5+offset]);
setFocusItem(0,0);
} else {
// QPoint topLeft = mapToGlobal(QPoint(0,0));
int _x = 280;//topLeft.x();
int _y = 140;//topLeft.y();
FadeInOutPreview *tmp = new FadeInOutPreview(parentWidget(), filename, curItemX*100+_x, curItemY*80+_y, 3, 3, true);
// FadeInOutPreview *tmp = new FadeInOutPreview(parentWidget(), filename, curItemX*100+320, curItemY*80+180, 13, 5, true);
tmp->fadeIn();
/*
static QLabel *lab = 0;
if (lab) {
lab->hide();
delete lab;
}
lab = new QLabel(parentWidget());
QPixmap pix = QPixmap(filename);
QSize size = pix.size();
size.scale(700,380,Qt::KeepAspectRatio);
pix.fill(QColor(0,0,0,0));
QPainter p(&pix);
p.setOpacity(0.8);
p.drawPixmap(0, 0, QPixmap(filename));
p.end();
lab->setPixmap(pix.scaled(size));
lab->setGeometry((800 - size.width()) / 2, (480 - size.height()) / 2, size.width(), size.height());
lab->show();
QTimer::singleShot(2000, lab, SLOT(hide()));
*/
}
}
repaint();
}
void IconView::paintEvent(QPaintEvent *pe)
{
QPainter p(this);
p.setPen(QColor(32,32,64));
for (int y = 0; y < 320; y+=80)
for (int x = 0; x < 500; x+=100)
p.drawRect(x, y, 90, 70);
p.setPen(QColor(178,178,255));
for (int y = 1; y < 321; y+=80)
for (int x = 1; x < 501; x+=100)
p.drawRect(x, y, 90, 70);
p.setPen(Qt::NoPen);
p.setBrush(QColor(178,178,178,64));
for (int y = 2; y < 322; y+=80)
for (int x = 2; x < 502; x+=100)
p.drawRect(x, y, 88, 68);
int x2 = curItemX * 100;
int y2 = curItemY * 80;
if (x2 >= 0) {
p.setPen(QColor(255,255,255));
p.drawRect(x2, y2, 88+2, 68+2);
p.drawRect(x2, y2, 88+3, 68+3);
}
int i = offset;
for (int y = 0; y < 4; y++)
for (int x = 0; x < 5; x++) {
QPixmap thumb;
// if ( (int)dir.count() > i ) {
if ( (int)entryList.count() > i ) {
if ( entryList[i] == "." )
i++;
QString filename = "photos/" + directory + "/" + entryList[i];
if (QPixmapCache::find(filename, thumb)) {
p.drawPixmap(x*100+2, y*80+2, thumb.scaled(88,68));
//} else {
//p.drawPixmap(x*100+2, y*80+2, QPixmap(filename).scaled(88,68));
}
i++;
}
}
if (x2 >= 0) {
p.setPen(Qt::NoPen);
QRadialGradient g1(x2+80,y2-45,80,x2+60,y2-2);
g1.setColorAt(0,QColor(255,255,255,255));
g1.setColorAt(1,QColor(255,255,255,12));
p.setBrush(g1);
p.drawRect(x2+2, y2+2, 88, 68);
QRadialGradient g2(x2+50,y2-50,140,x2+90,y2+50);
g2.setColorAt(0,QColor(255,255,255,0));
g2.setColorAt(0.50,QColor(255,255,255,0));
g2.setColorAt(0.51,QColor(200,200,245,100));
g2.setColorAt(1,QColor(200,200,245,100));
p.setBrush(g2);
p.drawRect(x2+2, y2+2, 88, 68);
}
}