Newer
Older
Import / applications / Photoframe / src / iconview.cpp
#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;
    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);
	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(".");
    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);

	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, "/");
            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;
            }
        }
        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);
	}
}