commit 87e8edeafb1401d26f57bff78b8a35deb8fad802 Author: Kurisu Date: Sat Oct 18 18:42:15 2014 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..75c107b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.pro.user diff --git a/KonaClient b/KonaClient new file mode 100755 index 0000000..65568ff Binary files /dev/null and b/KonaClient differ diff --git a/KonaClient.pro b/KonaClient.pro new file mode 100755 index 0000000..ccd72f4 --- /dev/null +++ b/KonaClient.pro @@ -0,0 +1,38 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2012-09-03T13:51:11 +# +#------------------------------------------------- + +QT += core gui network xml + +TARGET = KonaClient +TEMPLATE = app + + +SOURCES += main.cpp\ + mainwindow.cpp \ + konasearch.cpp \ + konaclient.cpp \ + konaimage.cpp \ + flowlayout.cpp \ + konapreviewimageview.cpp \ + konatags.cpp \ + konatag.cpp \ + konarelatedtags.cpp \ + imageviewer.cpp + +HEADERS += mainwindow.h \ + konasearch.h \ + konaclient.h \ + konaimage.h \ + flowlayout.h \ + konapreviewimageview.h \ + konatags.h \ + konatag.h \ + konarelatedtags.h \ + imageviewer.h + +FORMS += mainwindow.ui \ + konapreviewimageview.ui \ + imageviewer.ui diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6691d76 --- /dev/null +++ b/Makefile @@ -0,0 +1,404 @@ +############################################################################# +# Makefile for building: KonaClient +# Generated by qmake (2.01a) (Qt 4.8.3) on: Do. Mär 28 10:46:21 2013 +# Project: KonaClient.pro +# Template: app +# Command: /usr/bin/qmake-qt4 -spec /usr/share/qt4/mkspecs/linux-g++ CONFIG+=debug CONFIG+=declarative_debug -o Makefile KonaClient.pro +############################################################################# + +####### Compiler, tools and options + +CC = gcc +CXX = g++ +DEFINES = -DQT_WEBKIT -DQT_XML_LIB -DQT_GUI_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -DQT_SHARED +CFLAGS = -pipe -g -Wall -W -D_REENTRANT $(DEFINES) +CXXFLAGS = -pipe -g -Wall -W -D_REENTRANT $(DEFINES) +INCPATH = -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtNetwork -I/usr/include/qt4/QtGui -I/usr/include/qt4/QtXml -I/usr/include/qt4 -I. -I. +LINK = g++ +LFLAGS = +LIBS = $(SUBLIBS) -L/usr/lib/x86_64-linux-gnu -lQtXml -lQtGui -lQtNetwork -lQtCore -lpthread +AR = ar cqs +RANLIB = +QMAKE = /usr/bin/qmake-qt4 +TAR = tar -cf +COMPRESS = gzip -9f +COPY = cp -f +SED = sed +COPY_FILE = $(COPY) +COPY_DIR = $(COPY) -r +STRIP = strip +INSTALL_FILE = install -m 644 -p +INSTALL_DIR = $(COPY_DIR) +INSTALL_PROGRAM = install -m 755 -p +DEL_FILE = rm -f +SYMLINK = ln -f -s +DEL_DIR = rmdir +MOVE = mv -f +CHK_DIR_EXISTS= test -d +MKDIR = mkdir -p + +####### Output directory + +OBJECTS_DIR = ./ + +####### Files + +SOURCES = main.cpp \ + mainwindow.cpp \ + konasearch.cpp \ + konaclient.cpp \ + konaimage.cpp \ + flowlayout.cpp \ + konapreviewimageview.cpp \ + konatags.cpp \ + konatag.cpp \ + konarelatedtags.cpp \ + imageviewer.cpp moc_mainwindow.cpp \ + moc_konasearch.cpp \ + moc_konaclient.cpp \ + moc_konaimage.cpp \ + moc_konapreviewimageview.cpp \ + moc_konatags.cpp \ + moc_konatag.cpp \ + moc_konarelatedtags.cpp \ + moc_imageviewer.cpp +OBJECTS = main.o \ + mainwindow.o \ + konasearch.o \ + konaclient.o \ + konaimage.o \ + flowlayout.o \ + konapreviewimageview.o \ + konatags.o \ + konatag.o \ + konarelatedtags.o \ + imageviewer.o \ + moc_mainwindow.o \ + moc_konasearch.o \ + moc_konaclient.o \ + moc_konaimage.o \ + moc_konapreviewimageview.o \ + moc_konatags.o \ + moc_konatag.o \ + moc_konarelatedtags.o \ + moc_imageviewer.o +DIST = /usr/share/qt4/mkspecs/common/unix.conf \ + /usr/share/qt4/mkspecs/common/linux.conf \ + /usr/share/qt4/mkspecs/common/gcc-base.conf \ + /usr/share/qt4/mkspecs/common/gcc-base-unix.conf \ + /usr/share/qt4/mkspecs/common/g++-base.conf \ + /usr/share/qt4/mkspecs/common/g++-unix.conf \ + /usr/share/qt4/mkspecs/qconfig.pri \ + /usr/share/qt4/mkspecs/modules/qt_webkit_version.pri \ + /usr/share/qt4/mkspecs/features/qt_functions.prf \ + /usr/share/qt4/mkspecs/features/qt_config.prf \ + /usr/share/qt4/mkspecs/features/exclusive_builds.prf \ + /usr/share/qt4/mkspecs/features/default_pre.prf \ + /usr/share/qt4/mkspecs/features/debug.prf \ + /usr/share/qt4/mkspecs/features/default_post.prf \ + /usr/share/qt4/mkspecs/features/declarative_debug.prf \ + /usr/share/qt4/mkspecs/features/unix/gdb_dwarf_index.prf \ + /usr/share/qt4/mkspecs/features/warn_on.prf \ + /usr/share/qt4/mkspecs/features/qt.prf \ + /usr/share/qt4/mkspecs/features/unix/thread.prf \ + /usr/share/qt4/mkspecs/features/moc.prf \ + /usr/share/qt4/mkspecs/features/resources.prf \ + /usr/share/qt4/mkspecs/features/uic.prf \ + /usr/share/qt4/mkspecs/features/yacc.prf \ + /usr/share/qt4/mkspecs/features/lex.prf \ + /usr/share/qt4/mkspecs/features/include_source_dir.prf \ + KonaClient.pro +QMAKE_TARGET = KonaClient +DESTDIR = +TARGET = KonaClient + +first: all +####### Implicit rules + +.SUFFIXES: .o .c .cpp .cc .cxx .C + +.cpp.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<" + +.cc.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<" + +.cxx.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<" + +.C.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<" + +.c.o: + $(CC) -c $(CFLAGS) $(INCPATH) -o "$@" "$<" + +####### Build rules + +all: Makefile $(TARGET) + +$(TARGET): ui_mainwindow.h ui_konapreviewimageview.h ui_imageviewer.h $(OBJECTS) + $(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJCOMP) $(LIBS) + { test -n "$(DESTDIR)" && DESTDIR="$(DESTDIR)" || DESTDIR=.; } && test $$(gdb --version | sed -e 's,[^0-9]\+\([0-9]\)\.\([0-9]\).*,\1\2,;q') -gt 72 && gdb --nx --batch --quiet -ex 'set confirm off' -ex "save gdb-index $$DESTDIR" -ex quit '$(TARGET)' && test -f $(TARGET).gdb-index && objcopy --add-section '.gdb_index=$(TARGET).gdb-index' --set-section-flags '.gdb_index=readonly' '$(TARGET)' '$(TARGET)' && rm -f $(TARGET).gdb-index || true + +Makefile: KonaClient.pro /usr/share/qt4/mkspecs/linux-g++/qmake.conf /usr/share/qt4/mkspecs/common/unix.conf \ + /usr/share/qt4/mkspecs/common/linux.conf \ + /usr/share/qt4/mkspecs/common/gcc-base.conf \ + /usr/share/qt4/mkspecs/common/gcc-base-unix.conf \ + /usr/share/qt4/mkspecs/common/g++-base.conf \ + /usr/share/qt4/mkspecs/common/g++-unix.conf \ + /usr/share/qt4/mkspecs/qconfig.pri \ + /usr/share/qt4/mkspecs/modules/qt_webkit_version.pri \ + /usr/share/qt4/mkspecs/features/qt_functions.prf \ + /usr/share/qt4/mkspecs/features/qt_config.prf \ + /usr/share/qt4/mkspecs/features/exclusive_builds.prf \ + /usr/share/qt4/mkspecs/features/default_pre.prf \ + /usr/share/qt4/mkspecs/features/debug.prf \ + /usr/share/qt4/mkspecs/features/default_post.prf \ + /usr/share/qt4/mkspecs/features/declarative_debug.prf \ + /usr/share/qt4/mkspecs/features/unix/gdb_dwarf_index.prf \ + /usr/share/qt4/mkspecs/features/warn_on.prf \ + /usr/share/qt4/mkspecs/features/qt.prf \ + /usr/share/qt4/mkspecs/features/unix/thread.prf \ + /usr/share/qt4/mkspecs/features/moc.prf \ + /usr/share/qt4/mkspecs/features/resources.prf \ + /usr/share/qt4/mkspecs/features/uic.prf \ + /usr/share/qt4/mkspecs/features/yacc.prf \ + /usr/share/qt4/mkspecs/features/lex.prf \ + /usr/share/qt4/mkspecs/features/include_source_dir.prf \ + /usr/lib/x86_64-linux-gnu/libQtXml.prl \ + /usr/lib/x86_64-linux-gnu/libQtGui.prl \ + /usr/lib/x86_64-linux-gnu/libQtNetwork.prl \ + /usr/lib/x86_64-linux-gnu/libQtCore.prl + $(QMAKE) -spec /usr/share/qt4/mkspecs/linux-g++ CONFIG+=debug CONFIG+=declarative_debug -o Makefile KonaClient.pro +/usr/share/qt4/mkspecs/common/unix.conf: +/usr/share/qt4/mkspecs/common/linux.conf: +/usr/share/qt4/mkspecs/common/gcc-base.conf: +/usr/share/qt4/mkspecs/common/gcc-base-unix.conf: +/usr/share/qt4/mkspecs/common/g++-base.conf: +/usr/share/qt4/mkspecs/common/g++-unix.conf: +/usr/share/qt4/mkspecs/qconfig.pri: +/usr/share/qt4/mkspecs/modules/qt_webkit_version.pri: +/usr/share/qt4/mkspecs/features/qt_functions.prf: +/usr/share/qt4/mkspecs/features/qt_config.prf: +/usr/share/qt4/mkspecs/features/exclusive_builds.prf: +/usr/share/qt4/mkspecs/features/default_pre.prf: +/usr/share/qt4/mkspecs/features/debug.prf: +/usr/share/qt4/mkspecs/features/default_post.prf: +/usr/share/qt4/mkspecs/features/declarative_debug.prf: +/usr/share/qt4/mkspecs/features/unix/gdb_dwarf_index.prf: +/usr/share/qt4/mkspecs/features/warn_on.prf: +/usr/share/qt4/mkspecs/features/qt.prf: +/usr/share/qt4/mkspecs/features/unix/thread.prf: +/usr/share/qt4/mkspecs/features/moc.prf: +/usr/share/qt4/mkspecs/features/resources.prf: +/usr/share/qt4/mkspecs/features/uic.prf: +/usr/share/qt4/mkspecs/features/yacc.prf: +/usr/share/qt4/mkspecs/features/lex.prf: +/usr/share/qt4/mkspecs/features/include_source_dir.prf: +/usr/lib/x86_64-linux-gnu/libQtXml.prl: +/usr/lib/x86_64-linux-gnu/libQtGui.prl: +/usr/lib/x86_64-linux-gnu/libQtNetwork.prl: +/usr/lib/x86_64-linux-gnu/libQtCore.prl: +qmake: FORCE + @$(QMAKE) -spec /usr/share/qt4/mkspecs/linux-g++ CONFIG+=debug CONFIG+=declarative_debug -o Makefile KonaClient.pro + +dist: + @$(CHK_DIR_EXISTS) .tmp/KonaClient1.0.0 || $(MKDIR) .tmp/KonaClient1.0.0 + $(COPY_FILE) --parents $(SOURCES) $(DIST) .tmp/KonaClient1.0.0/ && $(COPY_FILE) --parents mainwindow.h konasearch.h konaclient.h konaimage.h flowlayout.h konapreviewimageview.h konatags.h konatag.h konarelatedtags.h imageviewer.h .tmp/KonaClient1.0.0/ && $(COPY_FILE) --parents main.cpp mainwindow.cpp konasearch.cpp konaclient.cpp konaimage.cpp flowlayout.cpp konapreviewimageview.cpp konatags.cpp konatag.cpp konarelatedtags.cpp imageviewer.cpp .tmp/KonaClient1.0.0/ && $(COPY_FILE) --parents mainwindow.ui konapreviewimageview.ui imageviewer.ui .tmp/KonaClient1.0.0/ && (cd `dirname .tmp/KonaClient1.0.0` && $(TAR) KonaClient1.0.0.tar KonaClient1.0.0 && $(COMPRESS) KonaClient1.0.0.tar) && $(MOVE) `dirname .tmp/KonaClient1.0.0`/KonaClient1.0.0.tar.gz . && $(DEL_FILE) -r .tmp/KonaClient1.0.0 + + +clean:compiler_clean + -$(DEL_FILE) $(OBJECTS) + -$(DEL_FILE) *~ core *.core + + +####### Sub-libraries + +distclean: clean + -$(DEL_FILE) $(TARGET) + -$(DEL_FILE) Makefile + + +check: first + +mocclean: compiler_moc_header_clean compiler_moc_source_clean + +mocables: compiler_moc_header_make_all compiler_moc_source_make_all + +compiler_moc_header_make_all: moc_mainwindow.cpp moc_konasearch.cpp moc_konaclient.cpp moc_konaimage.cpp moc_konapreviewimageview.cpp moc_konatags.cpp moc_konatag.cpp moc_konarelatedtags.cpp moc_imageviewer.cpp +compiler_moc_header_clean: + -$(DEL_FILE) moc_mainwindow.cpp moc_konasearch.cpp moc_konaclient.cpp moc_konaimage.cpp moc_konapreviewimageview.cpp moc_konatags.cpp moc_konatag.cpp moc_konarelatedtags.cpp moc_imageviewer.cpp +moc_mainwindow.cpp: konaclient.h \ + konasearch.h \ + konaimage.h \ + konatags.h \ + konatag.h \ + konarelatedtags.h \ + flowlayout.h \ + imageviewer.h \ + mainwindow.h + /usr/bin/moc-qt4 $(DEFINES) $(INCPATH) mainwindow.h -o moc_mainwindow.cpp + +moc_konasearch.cpp: konaclient.h \ + konaimage.h \ + konasearch.h + /usr/bin/moc-qt4 $(DEFINES) $(INCPATH) konasearch.h -o moc_konasearch.cpp + +moc_konaclient.cpp: konaclient.h + /usr/bin/moc-qt4 $(DEFINES) $(INCPATH) konaclient.h -o moc_konaclient.cpp + +moc_konaimage.cpp: konaclient.h \ + konaimage.h + /usr/bin/moc-qt4 $(DEFINES) $(INCPATH) konaimage.h -o moc_konaimage.cpp + +moc_konapreviewimageview.cpp: konaimage.h \ + konaclient.h \ + konapreviewimageview.h + /usr/bin/moc-qt4 $(DEFINES) $(INCPATH) konapreviewimageview.h -o moc_konapreviewimageview.cpp + +moc_konatags.cpp: konatag.h \ + konaclient.h \ + konatags.h + /usr/bin/moc-qt4 $(DEFINES) $(INCPATH) konatags.h -o moc_konatags.cpp + +moc_konatag.cpp: konatag.h + /usr/bin/moc-qt4 $(DEFINES) $(INCPATH) konatag.h -o moc_konatag.cpp + +moc_konarelatedtags.cpp: konaclient.h \ + konatag.h \ + konarelatedtags.h + /usr/bin/moc-qt4 $(DEFINES) $(INCPATH) konarelatedtags.h -o moc_konarelatedtags.cpp + +moc_imageviewer.cpp: konaimage.h \ + konaclient.h \ + imageviewer.h + /usr/bin/moc-qt4 $(DEFINES) $(INCPATH) imageviewer.h -o moc_imageviewer.cpp + +compiler_rcc_make_all: +compiler_rcc_clean: +compiler_image_collection_make_all: qmake_image_collection.cpp +compiler_image_collection_clean: + -$(DEL_FILE) qmake_image_collection.cpp +compiler_moc_source_make_all: +compiler_moc_source_clean: +compiler_uic_make_all: ui_mainwindow.h ui_konapreviewimageview.h ui_imageviewer.h +compiler_uic_clean: + -$(DEL_FILE) ui_mainwindow.h ui_konapreviewimageview.h ui_imageviewer.h +ui_mainwindow.h: mainwindow.ui + /usr/bin/uic-qt4 mainwindow.ui -o ui_mainwindow.h + +ui_konapreviewimageview.h: konapreviewimageview.ui + /usr/bin/uic-qt4 konapreviewimageview.ui -o ui_konapreviewimageview.h + +ui_imageviewer.h: imageviewer.ui + /usr/bin/uic-qt4 imageviewer.ui -o ui_imageviewer.h + +compiler_yacc_decl_make_all: +compiler_yacc_decl_clean: +compiler_yacc_impl_make_all: +compiler_yacc_impl_clean: +compiler_lex_make_all: +compiler_lex_clean: +compiler_clean: compiler_moc_header_clean compiler_uic_clean + +####### Compile + +main.o: main.cpp mainwindow.h \ + konaclient.h \ + konasearch.h \ + konaimage.h \ + konatags.h \ + konatag.h \ + konarelatedtags.h \ + flowlayout.h \ + imageviewer.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o main.o main.cpp + +mainwindow.o: mainwindow.cpp mainwindow.h \ + konaclient.h \ + konasearch.h \ + konaimage.h \ + konatags.h \ + konatag.h \ + konarelatedtags.h \ + flowlayout.h \ + imageviewer.h \ + ui_mainwindow.h \ + konapreviewimageview.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o mainwindow.o mainwindow.cpp + +konasearch.o: konasearch.cpp konasearch.h \ + konaclient.h \ + konaimage.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o konasearch.o konasearch.cpp + +konaclient.o: konaclient.cpp konaclient.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o konaclient.o konaclient.cpp + +konaimage.o: konaimage.cpp konaimage.h \ + konaclient.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o konaimage.o konaimage.cpp + +flowlayout.o: flowlayout.cpp flowlayout.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o flowlayout.o flowlayout.cpp + +konapreviewimageview.o: konapreviewimageview.cpp konapreviewimageview.h \ + konaimage.h \ + konaclient.h \ + ui_konapreviewimageview.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o konapreviewimageview.o konapreviewimageview.cpp + +konatags.o: konatags.cpp konatags.h \ + konatag.h \ + konaclient.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o konatags.o konatags.cpp + +konatag.o: konatag.cpp konatag.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o konatag.o konatag.cpp + +konarelatedtags.o: konarelatedtags.cpp konarelatedtags.h \ + konaclient.h \ + konatag.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o konarelatedtags.o konarelatedtags.cpp + +imageviewer.o: imageviewer.cpp imageviewer.h \ + konaimage.h \ + konaclient.h \ + ui_imageviewer.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o imageviewer.o imageviewer.cpp + +moc_mainwindow.o: moc_mainwindow.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_mainwindow.o moc_mainwindow.cpp + +moc_konasearch.o: moc_konasearch.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_konasearch.o moc_konasearch.cpp + +moc_konaclient.o: moc_konaclient.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_konaclient.o moc_konaclient.cpp + +moc_konaimage.o: moc_konaimage.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_konaimage.o moc_konaimage.cpp + +moc_konapreviewimageview.o: moc_konapreviewimageview.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_konapreviewimageview.o moc_konapreviewimageview.cpp + +moc_konatags.o: moc_konatags.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_konatags.o moc_konatags.cpp + +moc_konatag.o: moc_konatag.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_konatag.o moc_konatag.cpp + +moc_konarelatedtags.o: moc_konarelatedtags.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_konarelatedtags.o moc_konarelatedtags.cpp + +moc_imageviewer.o: moc_imageviewer.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_imageviewer.o moc_imageviewer.cpp + +####### Install + +install: FORCE + +uninstall: FORCE + +FORCE: + diff --git a/flowlayout.cpp b/flowlayout.cpp new file mode 100755 index 0000000..1a2a33c --- /dev/null +++ b/flowlayout.cpp @@ -0,0 +1,195 @@ +/**************************************************************************** + ** + ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + ** All rights reserved. + ** Contact: Nokia Corporation (qt-info@nokia.com) + ** + ** This file is part of the examples of the Qt Toolkit. + ** + ** $QT_BEGIN_LICENSE:BSD$ + ** You may use this file under the terms of the BSD license as follows: + ** + ** "Redistribution and use in source and binary forms, with or without + ** modification, are permitted provided that the following conditions are + ** met: + ** * Redistributions of source code must retain the above copyright + ** notice, this list of conditions and the following disclaimer. + ** * Redistributions in binary form must reproduce the above copyright + ** notice, this list of conditions and the following disclaimer in + ** the documentation and/or other materials provided with the + ** distribution. + ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor + ** the names of its contributors may be used to endorse or promote + ** products derived from this software without specific prior written + ** permission. + ** + ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ + + #include + + #include "flowlayout.h" + FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing) + : QLayout(parent), m_hSpace(hSpacing), m_vSpace(vSpacing) + { + setContentsMargins(margin, margin, margin, margin); + } + + FlowLayout::FlowLayout(int margin, int hSpacing, int vSpacing) + : m_hSpace(hSpacing), m_vSpace(vSpacing) + { + setContentsMargins(margin, margin, margin, margin); + } + + FlowLayout::~FlowLayout() + { + QLayoutItem *item; + while ((item = takeAt(0))) + delete item; + } + + void FlowLayout::addItem(QLayoutItem *item) + { + itemList.append(item); + } + + int FlowLayout::horizontalSpacing() const + { + if (m_hSpace >= 0) { + return m_hSpace; + } else { + return smartSpacing(QStyle::PM_LayoutHorizontalSpacing); + } + } + + int FlowLayout::verticalSpacing() const + { + if (m_vSpace >= 0) { + return m_vSpace; + } else { + return smartSpacing(QStyle::PM_LayoutVerticalSpacing); + } + } + + int FlowLayout::count() const + { + return itemList.size(); + } + + QLayoutItem *FlowLayout::itemAt(int index) const + { + return itemList.value(index); + } + + QLayoutItem *FlowLayout::takeAt(int index) + { + if (index >= 0 && index < itemList.size()) + return itemList.takeAt(index); + else + return 0; + } + + Qt::Orientations FlowLayout::expandingDirections() const + { + return 0; + } + + bool FlowLayout::hasHeightForWidth() const + { + return true; + } + + int FlowLayout::heightForWidth(int width) const + { + int height = doLayout(QRect(0, 0, width, 0), true); + return height; + } + + void FlowLayout::setGeometry(const QRect &rect) + { + QLayout::setGeometry(rect); + doLayout(rect, false); + } + + QSize FlowLayout::sizeHint() const + { + return minimumSize(); + } + + QSize FlowLayout::minimumSize() const + { + QSize size; + QLayoutItem *item; + foreach (item, itemList) + size = size.expandedTo(item->minimumSize()); + + size += QSize(2*margin(), 2*margin()); + return size; + } + + int FlowLayout::doLayout(const QRect &rect, bool testOnly) const + { + int left, top, right, bottom; + getContentsMargins(&left, &top, &right, &bottom); + QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom); + int x = effectiveRect.x(); + int y = effectiveRect.y(); + int lineHeight = 0; + + QLayoutItem *item; + foreach (item, itemList) { + QWidget *wid = item->widget(); + int spaceX = horizontalSpacing(); + if (spaceX == -1) + spaceX = wid->style()->layoutSpacing( + QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal); + int spaceY = verticalSpacing(); + if (spaceY == -1) + spaceY = wid->style()->layoutSpacing( + QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical); + int nextX = x + item->sizeHint().width() + spaceX; + if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) { + x = effectiveRect.x(); + y = y + lineHeight + spaceY; + nextX = x + item->sizeHint().width() + spaceX; + lineHeight = 0; + } + + if (!testOnly) + item->setGeometry(QRect(QPoint(x, y), item->sizeHint())); + + x = nextX; + lineHeight = qMax(lineHeight, item->sizeHint().height()); + } + return y + lineHeight - rect.y() + bottom; + } + int FlowLayout::smartSpacing(QStyle::PixelMetric pm) const + { + QObject *parent = this->parent(); + if (!parent) { + return -1; + } else if (parent->isWidgetType()) { + QWidget *pw = static_cast(parent); + return pw->style()->pixelMetric(pm, 0, pw); + } else { + return static_cast(parent)->spacing(); + } + } + void FlowLayout::insertWidgetAt(QWidget *widget, int index) + { + addWidget(widget); + this->itemList.move(this->itemList.count()-1, 0); + //this->itemList.insert(index, new QWidgetItem(widget)); + } diff --git a/flowlayout.h b/flowlayout.h new file mode 100755 index 0000000..f92bee3 --- /dev/null +++ b/flowlayout.h @@ -0,0 +1,77 @@ +/**************************************************************************** + ** + ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + ** All rights reserved. + ** Contact: Nokia Corporation (qt-info@nokia.com) + ** + ** This file is part of the examples of the Qt Toolkit. + ** + ** $QT_BEGIN_LICENSE:BSD$ + ** You may use this file under the terms of the BSD license as follows: + ** + ** "Redistribution and use in source and binary forms, with or without + ** modification, are permitted provided that the following conditions are + ** met: + ** * Redistributions of source code must retain the above copyright + ** notice, this list of conditions and the following disclaimer. + ** * Redistributions in binary form must reproduce the above copyright + ** notice, this list of conditions and the following disclaimer in + ** the documentation and/or other materials provided with the + ** distribution. + ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor + ** the names of its contributors may be used to endorse or promote + ** products derived from this software without specific prior written + ** permission. + ** + ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ + + #ifndef FLOWLAYOUT_H + #define FLOWLAYOUT_H + + #include + #include + #include + class FlowLayout : public QLayout + { + public: + FlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1); + FlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1); + ~FlowLayout(); + + void addItem(QLayoutItem *item); + int horizontalSpacing() const; + int verticalSpacing() const; + Qt::Orientations expandingDirections() const; + bool hasHeightForWidth() const; + int heightForWidth(int) const; + int count() const; + QLayoutItem *itemAt(int index) const; + QSize minimumSize() const; + void setGeometry(const QRect &rect); + QSize sizeHint() const; + QLayoutItem *takeAt(int index); + void insertWidgetAt(QWidget *widget, int index); + + private: + int doLayout(const QRect &rect, bool testOnly) const; + int smartSpacing(QStyle::PixelMetric pm) const; + + QList itemList; + int m_hSpace; + int m_vSpace; + }; + + #endif diff --git a/imageviewer.cpp b/imageviewer.cpp new file mode 100755 index 0000000..f4949bc --- /dev/null +++ b/imageviewer.cpp @@ -0,0 +1,200 @@ +#include "imageviewer.h" +#include "ui_imageviewer.h" +#include +#include + +ImageViewer::ImageViewer(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::ImageViewer) +{ + ui->setupUi(this); + + EventFilterizer* interceptor = new EventFilterizer; + ui->centralwidget->installEventFilter(interceptor); + + connect(interceptor, SIGNAL(onMove(int,int)), + this, SLOT(move(int,int))); + + connect(interceptor, SIGNAL(onZoom(int)), + this, SLOT(zoom(int))); +} + +ImageViewer::~ImageViewer() +{ + delete ui; +} + +void ImageViewer::setImage(KonaImage *Ki) { // TODO: (no todo but a notice: This function requires the image to be available locally when called!) + //ki = Ki; //TODO: <-- + + disconnect(Ki, SIGNAL(imageDownloaded(KonaImage*,QString)), + this, SLOT(setImage(KonaImage*))); + + currentID = Ki->getId(); + + pix.load(Ki->getLocalImagePath()); + + + // We're doing this a bit complicated. (It's to remove any frame from the label) + QPixmap temp = pix.scaled(this->width(), this->height(), Qt::KeepAspectRatio, Qt::SmoothTransformation); + ui->imgLabel->setGeometry(0,0,this->width(), this->height()); + + ui->imgLabel->setPixmap(temp); + + ui->imgLabel->setGeometry((ui->imgLabel->width()-temp.width()) / 2, + (ui->imgLabel->height()-temp.height()) / 2, + temp.width(), temp.height()); + + setWindowTitle(tr("KonaClient - Image viewer: %1 (%2x%3)").arg(QString::number(Ki->getId()),QString::number(Ki->getWidth()),QString::number(Ki->getHeight()))); +} + +void ImageViewer::showLoading() { + ui->imgLabel->setText("Loading image..."); + setWindowTitle(tr("KonaClient - Image viewer")); + ui->imgLabel->setGeometry(0,0,this->width(),this->height()); +} + +void ImageViewer::move(int dx, int dy) { + ui->imgLabel->setGeometry(ui->imgLabel->x() + dx, ui->imgLabel->y() + dy, ui->imgLabel->width(),ui->imgLabel->height()); + checkPos(); +} + +void ImageViewer::zoom(int mode) { + if (mode == ZOOM_OUT) { + ui->imgLabel->setGeometry(ui->imgLabel->x() + (pix.width()/20)/2, + ui->imgLabel->y() + (pix.height()/20)/2, + ui->imgLabel->width() - pix.width()/20, + ui->imgLabel->height() - pix.height()/20); + } + else if (mode == ZOOM_IN) { + ui->imgLabel->setGeometry(ui->imgLabel->x() - (pix.width()/20)/2, + ui->imgLabel->y() - (pix.height()/20)/2, + ui->imgLabel->width() + pix.width()/20, + ui->imgLabel->height() + pix.height()/20); + } + + checkPos(); + ui->imgLabel->setPixmap(pix.scaled(ui->imgLabel->width(), ui->imgLabel->height(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); +} + +void ImageViewer::checkPos() { + if (ui->imgLabel->width() < this->width()) { + if (ui->imgLabel->x() < 0) { + ui->imgLabel->setGeometry(0, + ui->imgLabel->y(), + ui->imgLabel->width(), + ui->imgLabel->height()); + } + else if (ui->imgLabel->x() + ui->imgLabel->width() > this->width()) { + ui->imgLabel->setGeometry(this->width() - ui->imgLabel->width(), + ui->imgLabel->y(), + ui->imgLabel->width(), + ui->imgLabel->height()); + } + } + else { + // if (ui->imgLabel->x() ) + } + + if (ui->imgLabel->height() < this->height()) { + if (ui->imgLabel->y() < 0) { + ui->imgLabel->setGeometry(ui->imgLabel->x(), + 0, + ui->imgLabel->width(), + ui->imgLabel->height()); + + } + else if (ui->imgLabel->y() + ui->imgLabel->height() > this->height()) { + ui->imgLabel->setGeometry(ui->imgLabel->x(), + this->height() - ui->imgLabel->height(), + ui->imgLabel->width(), + ui->imgLabel->height()); + } + } + else { + if (ui->imgLabel->y() + ui->imgLabel->height() < this->height()) { + ui->imgLabel->setGeometry(ui->imgLabel->x(), + this->height() - ui->imgLabel->height(), + ui->imgLabel->width(), + ui->imgLabel->height()); + } + else if (ui->imgLabel->y() > 0) { + ui->imgLabel->setGeometry(ui->imgLabel->x(), + 0, + ui->imgLabel->width(), + ui->imgLabel->height()); + } + + if (ui->imgLabel->x() + ui->imgLabel->width() < this->width()) { + ui->imgLabel->setGeometry(this->width() - ui->imgLabel->width(), + ui->imgLabel->y(), + ui->imgLabel->width(), + ui->imgLabel->height()); + } + else if (ui->imgLabel->x() > 0) { + ui->imgLabel->setGeometry(0, + ui->imgLabel->y(), + ui->imgLabel->width(), + ui->imgLabel->height()); + } + } +} + +void ImageViewer::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Left || e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Shift) { + emit loadPrev(); + } + else if (e->key() == Qt::Key_Right || e->key() == Qt::Key_Return || e->key() == Qt::Key_Control) { + emit loadNext(); + } +} + + + + + + +// MOUSE EVENT +EventFilterizer::EventFilterizer(QObject *parent) : + QObject(parent) +{ +} + +bool EventFilterizer::eventFilter(QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::Wheel) { + QWheelEvent *wheelEvent = static_cast< QWheelEvent * >( event ); + if (wheelEvent->delta() > 0) { + emit onZoom(ZOOM_IN); + } + else if (wheelEvent->delta() < 0) { + emit onZoom(ZOOM_OUT); + } + + return true; + } + else if (event->type() == QEvent::MouseButtonPress) { + QMouseEvent *mouseEvent = static_cast< QMouseEvent * >( event ); + + lastX = mouseEvent->x(); + lastY = mouseEvent->y(); + return true; + } + else if (event->type() == QEvent::MouseMove) { // ONLY CALLED WHEN PRESSED + //qDebug() << "MOVE"; + QMouseEvent *mouseEvent = static_cast< QMouseEvent * >( event ); + + emit onMove(mouseEvent->x() - lastX, + mouseEvent->y() - lastY); + + + lastX = mouseEvent->x(); + lastY = mouseEvent->y(); + return true; + } + else + { + // standard event processing + return QObject::eventFilter(obj, event); + } +} diff --git a/imageviewer.h b/imageviewer.h new file mode 100755 index 0000000..71c526e --- /dev/null +++ b/imageviewer.h @@ -0,0 +1,71 @@ +#ifndef IMAGEVIEWER_H +#define IMAGEVIEWER_H + +#include +#include "konaimage.h" +#include + +namespace Ui { +class ImageViewer; +} + +class ImageViewer : public QMainWindow +{ + Q_OBJECT + +#define ZOOM_IN 1 +#define ZOOM_OUT 2 + + +public: + explicit ImageViewer(QWidget *parent = 0); + ~ImageViewer(); + void showLoading(); + //void mouseMoveEvent(QMouseEvent *e); + void keyPressEvent(QKeyEvent* e); + int getCurrentId() {return currentID;} + +private: + QPixmap pix; + int currentID; + +public slots: + void setImage(KonaImage *Ki); + void move(int dx, int dy); + void zoom(int mode); + void checkPos(); + +signals: + void loadPrev(); + void loadNext(); + +private: + Ui::ImageViewer *ui; +}; + + +class EventFilterizer : public QObject +{ + Q_OBJECT +public: + explicit EventFilterizer(QObject *parent = 0); + void setIv(ImageViewer *Iv) {iv = Iv;} + +private: + ImageViewer *iv; + int lastX; + int lastY; + +protected: + bool eventFilter(QObject *obj, QEvent *event); + +signals: + void onMove(int, int); + void onZoom(int); + +public slots: + +}; + + +#endif // IMAGEVIEWER_H diff --git a/imageviewer.ui b/imageviewer.ui new file mode 100755 index 0000000..8163e8f --- /dev/null +++ b/imageviewer.ui @@ -0,0 +1,58 @@ + + + ImageViewer + + + + 0 + 0 + 800 + 600 + + + + PointingHandCursor + + + KonaChan - Image viewer + + + background-color: black; + + + + + + 80 + 70 + 640 + 480 + + + + + 0 + 0 + + + + PointingHandCursor + + + + + + Loading image... + + + Qt::AlignCenter + + + + + + + + onResize() + + diff --git a/konaclient.cpp b/konaclient.cpp new file mode 100755 index 0000000..fd37f7f --- /dev/null +++ b/konaclient.cpp @@ -0,0 +1,46 @@ +#include "konaclient.h" + +KonaClient::KonaClient(QString TempDir, QString CacheDir, QString ArchiveDir, QString Server) +{ + // Copy info to RAM + tempDir = TempDir; + cacheDir = CacheDir; + archiveDir = ArchiveDir; + server = Server; + + // Create all directories + QDir aD(archiveDir); + if (!aD.exists()) aD.mkpath(archiveDir); + + QDir cD(cacheDir); + if (!cD.exists()) cD.mkpath(cacheDir); + + QDir tD(tempDir); + if (!tD.exists()) tD.mkpath(tempDir); +} + +KonaClient::~KonaClient() +{ + // Remove temp dir + QDir tD(tempDir); + if (tD.exists()) removeDir(tempDir); +} + +// Copied from http://www.qtcentre.org/threads/4166-remove-directory-empty-or-not-empty +// Removes all files and subdirectories of a specific directory. +void KonaClient::removeDir(const QString &path) +{ + QFileInfo fileInfo(path); + if(fileInfo.isDir()){ + QDir dir(path); + QStringList fileList = dir.entryList(); + for(int i = 0; i < fileList.count(); ++i){ + + QFile::remove(fileList.at(i)); + } + dir.rmdir(path); + } + else{ + QFile::remove(path); + } +} diff --git a/konaclient.h b/konaclient.h new file mode 100755 index 0000000..1c12685 --- /dev/null +++ b/konaclient.h @@ -0,0 +1,50 @@ +#ifndef KONACLIENT_H +#define KONACLIENT_H + +#include +#include + + + +// ERROR CODES +#define ERROR_TAGS_TEMPFILE 1 +#define ERROR_TAGS_FORMAT 2 + +#define ERROR_SEARCH_TEMPFILE 1 +#define ERROR_SEARCH_FORMAT 2 +#define ERROR_SEARCH_XML 3 +#define ERROR_SEARCH_HTTP 4 + + + + +// Windows-Compatibility +#ifdef _WIN32 + #define SLASH "\\" +#else + #define SLASH "/" +#endif + + + +class KonaClient : public QObject +{ + Q_OBJECT +public: + KonaClient(QString TempDir, QString CacheDir, QString ArchiveDir, QString Server = "konachan.com"); + ~KonaClient(); + QString getTempDir() {return tempDir;} + QString getCacheDir() {return cacheDir;} + QString getArchiveDir() {return archiveDir;} + QString getServer() {return server;} + +private: + QString tempDir; + QString cacheDir; + QString archiveDir; + QString server; + + void removeDir(const QString &path); +}; + +#endif // KONACLIENT_H diff --git a/konaimage.cpp b/konaimage.cpp new file mode 100755 index 0000000..f1c42da --- /dev/null +++ b/konaimage.cpp @@ -0,0 +1,208 @@ +#include "konaimage.h" +#include + +KonaImage::KonaImage(KonaClient *Kc, int Id, QStringList Tags, int CreatedAt, int CreatorId, QString Author, int Change, QString Source, int Score, QString Md5, int FileSize, QString FileUrl, bool IsShownInIndex, QString PreviewUrl, int PreviewWidth, int PreviewHeight, int ActualPreviewWidth, int ActualPreviewHeight, QString SampleUrl, int SampleWidth, int SampleHeight, int SampleFileSize, QString JpegUrl, int JpegWidth, int JpegHeight, int JpegFileSize, QString Rating, bool HasChildren, int ParentID, QString Status, int Width, int Height, bool IsHeld, QString FramesPendingString, QString FramesString) +{ + // Reset + previewStatusCode = 1; + imageStatusCode = 1; + jpegStatusCode = 1; + sampleStatusCode = 1; + + // Copy to RAM + kc = Kc; + id = Id; + tags = Tags; + createdAt = CreatedAt; + creatorId = CreatorId; + author = Author; + change = Change; + source = Source; + score = Score; + md5 = Md5; + fileSize = FileSize; + fileUrl = FileUrl; + isShownInIndex = IsShownInIndex; + previewUrl = PreviewUrl; + previewWidth = PreviewWidth; + previewHeight = PreviewHeight; + actualPreviewWidth = ActualPreviewWidth; + actualPreviewHeight = ActualPreviewHeight; + sampleUrl = SampleUrl; + sampleWidth = SampleWidth; + sampleHeight = SampleHeight; + sampleFileSize = SampleFileSize; + jpegUrl = JpegUrl; + jpegWidth = JpegWidth; + jpegHeight = JpegHeight; + jpegFileSize = JpegFileSize; + rating = Rating; + hasChildren = HasChildren; + parentID = ParentID; + status = Status; + width = Width; + height = Height; + isHeld = IsHeld; + framesPendingString = FramesPendingString; + framesString = FramesString; + + // Initialize preview file + previewFile = new QFile(); + previewFile->setFileName(KONAIMAGE_PREVIEWPATH); + + // Prepare preview HTTP + previewHttp = new QHttp("konachan.com"); //TODO: all these konachans.com should be Kc->getServer() + connect(previewHttp, SIGNAL(responseHeaderReceived(QHttpResponseHeader)), + this, SLOT(previewResponseHeaderReceived(QHttpResponseHeader))); + connect(previewHttp, SIGNAL(requestFinished(int,bool)), + this, SLOT(previewRequestFinished())); + + + // Initialize image file (highres) + imageFile = new QFile(); + imageFile->setFileName(KONAIMAGE_LOCALPATH); + + // Prepare image HTTP + imageHttp = new QHttp("konachan.com"); + connect(imageHttp, SIGNAL(responseHeaderReceived(QHttpResponseHeader)), + this, SLOT(imageResponseHeaderReceived(QHttpResponseHeader))); + connect(imageHttp, SIGNAL(requestFinished(int,bool)), + this, SLOT(imageRequestFinished())); + + + // Initialize jpeg file + jpegFile = new QFile(); + jpegFile->setFileName(KONAIMAGE_JPEGPATH); + + // Prepare jpeg HTTP + jpegHttp = new QHttp("konachan.com"); + connect(jpegHttp, SIGNAL(responseHeaderReceived(QHttpResponseHeader)), + this, SLOT(jpegResponseHeaderReceived(QHttpResponseHeader))); + connect(jpegHttp, SIGNAL(requestFinished(int,bool)), + this, SLOT(jpegRequestFinished())); + + + // Initialize sample file + sampleFile = new QFile(); + sampleFile->setFileName(KONAIMAGE_SAMPLEPATH); + + // Prepare sample HTTP + sampleHttp = new QHttp("konachan.com"); + connect(sampleHttp, SIGNAL(responseHeaderReceived(QHttpResponseHeader)), + this, SLOT(sampleResponseHeaderReceived(QHttpResponseHeader))); + connect(sampleHttp, SIGNAL(requestFinished(int,bool)), + this, SLOT(sampleRequestFinished())); +} + +void KonaImage::DownloadPreview(bool overwrite) { + if (previewStatusCode != 1) return; // Already in progress + if (!previewFile->exists() || overwrite) { + previewFile->open(QFile::ReadWrite); + previewStatusCode = 0; + previewHttp->get(previewUrl, previewFile); + } + else if (previewFile->exists()) { + previewStatusCode = 200; // Fake HTTP OK + previewRequestFinished(); + } +} + +void KonaImage::previewRequestFinished() { + //qDebug() << "PREVIEW FINISHED WITH HTTP " << previewStatusCode; + previewFile->close(); + if (previewStatusCode == 200) previewStatusCode = 1; + emit previewDownloaded(this, previewFile->fileName()); +} + +void KonaImage::previewResponseHeaderReceived(QHttpResponseHeader resp) { + previewStatusCode = resp.statusCode(); +} + +// "real" image +void KonaImage::DownloadImage(bool overwrite) { + qDebug() << "Download request of real image: " << this->id; + if (imageStatusCode != 1) return; // Already in progress + + if (!imageFile->exists() || overwrite) { + imageFile->open(QFile::ReadWrite); + imageStatusCode = 0; + imageHttp->get(fileUrl, imageFile); + } + else if (imageFile->exists()) { + imageFile->open(QFile::ReadWrite); + QCryptographicHash md5sum(QCryptographicHash::Md5); + md5sum.addData(imageFile->readAll()); + imageFile->reset(); + + if (md5sum.result().toHex() == md5) { + imageStatusCode = 200; // Fake HTTP OK + imageRequestFinished(); + } + else { + qDebug() << "ERROR: KonaImage: MD5 checksum verification failed!"; + imageStatusCode = 0; + imageHttp->get(fileUrl, imageFile); + } + } +} + +void KonaImage::imageRequestFinished() { + imageFile->close(); + if (imageStatusCode == 200) imageStatusCode = 1; + emit imageDownloaded(this, imageFile->fileName()); +} + +void KonaImage::imageResponseHeaderReceived(QHttpResponseHeader resp) { + imageStatusCode = resp.statusCode(); +} + +// jpeg image +void KonaImage::DownloadJpeg(bool overwrite) { + if (jpegStatusCode != 1) return; // Already in progress + if (!jpegFile->exists() || overwrite) { + jpegFile->open(QFile::ReadWrite); + jpegStatusCode = 0; + jpegHttp->get(jpegUrl, jpegFile); + } + else if (jpegFile->exists()) { + jpegStatusCode = 200; // Fake HTTP OK + jpegRequestFinished(); + } +} + +void KonaImage::jpegRequestFinished() { + //qDebug() << "Jpeg FINISHED WITH HTTP " << JpegStatusCode; + jpegFile->close(); + if (jpegStatusCode == 200) jpegStatusCode = 1; + emit jpegDownloaded(this, jpegFile->fileName()); +} + +void KonaImage::jpegResponseHeaderReceived(QHttpResponseHeader resp) { + jpegStatusCode = resp.statusCode(); +} + + +// sample image +void KonaImage::DownloadSample(bool overwrite) { + if (sampleStatusCode != 1) return; // Already in progress + if (!sampleFile->exists() || overwrite) { + sampleFile->open(QFile::ReadWrite); + sampleStatusCode = 0; + sampleHttp->get(sampleUrl, sampleFile); + } + else if (sampleFile->exists()) { + sampleStatusCode = 200; // Fake HTTP OK + sampleRequestFinished(); + } +} + +void KonaImage::sampleRequestFinished() { + //qDebug() << "sample FINISHED WITH HTTP " << sampleStatusCode; + sampleFile->close(); + if (sampleStatusCode == 200) sampleStatusCode = 1; + emit sampleDownloaded(this, sampleFile->fileName()); +} + +void KonaImage::sampleResponseHeaderReceived(QHttpResponseHeader resp) { + sampleStatusCode = resp.statusCode(); +} diff --git a/konaimage.h b/konaimage.h new file mode 100755 index 0000000..eb70537 --- /dev/null +++ b/konaimage.h @@ -0,0 +1,118 @@ +#ifndef KONAIMAGE_H +#define KONAIMAGE_H + +#include +#include +#include +#include +#include + +#include "konaclient.h" + + +#define KONAIMAGE_PREVIEWPATH kc->getCacheDir() + SLASH + "preview_" + QString::number(id) + ".jpg" +#define KONAIMAGE_LOCALPATH kc->getArchiveDir() + SLASH + QString::number(id) + fileUrl.right(4) +#define KONAIMAGE_JPEGPATH kc->getCacheDir() + SLASH + "jpeg_" + QString::number(id) + ".jpg" +#define KONAIMAGE_SAMPLEPATH kc->getCacheDir() + SLASH + "sample_" + QString::number(id) + sampleUrl.right(4) + +class KonaImage : public QObject +{ + Q_OBJECT +public: + KonaImage(KonaClient *kc, int Id, QStringList Tags, int CreatedAt, int CreatorId, QString Author, int Change, QString Source, int Score, QString Md5, int FileSize, QString FileUrl, bool IsShownInIndex, QString PreviewUrl, int PreviewWidth, int PreviewHeight, int ActualPreviewWidth, int ActualPreviewHeight, QString SampleUrl, int SampleWidth, int SampleHeight, int SampleFileSize, QString JpegUrl, int JpegWidth, int JpegHeight, int JpegFileSize, QString Rating, bool HasChildren, int ParentID, QString Status, int Width, int Height, bool IsHeld, QString FramesPendingString, QString FramesString); + + int getId() {return id;} + int getWidth() {return width;} + int getHeight() {return height;} + + + + QString getLocalPreviewPath() {return KONAIMAGE_PREVIEWPATH;} + QString getLocalImagePath() {return KONAIMAGE_LOCALPATH;} + QString getLocalJpegPath() {return KONAIMAGE_JPEGPATH;} + QString getLocalSamplePath() {return KONAIMAGE_SAMPLEPATH;} + +private: + KonaClient *kc; + int id; + QStringList tags; + int createdAt; + int creatorId; + QString author; + int change; + QString source; + int score; + QString md5; + int fileSize; + QString fileUrl; + bool isShownInIndex; + QString previewUrl; + int previewWidth; + int previewHeight; + int actualPreviewWidth; + int actualPreviewHeight; + QString sampleUrl; + int sampleWidth; + int sampleHeight; + int sampleFileSize; + QString jpegUrl; + int jpegWidth; + int jpegHeight; + int jpegFileSize; + QString rating; + bool hasChildren; + int parentID; + QString status; + int width; + int height; + bool isHeld; + QString framesPendingString; + QString framesString; + // Eventuell fehlen noch children + + // Preview image + QHttp *previewHttp; + QFile *previewFile; + int previewStatusCode; + + // "real" image + QHttp *imageHttp; + QFile *imageFile; + int imageStatusCode; + + // jpeg image + QHttp *jpegHttp; + QFile *jpegFile; + int jpegStatusCode; + + // sample image + QHttp *sampleHttp; + QFile *sampleFile; + int sampleStatusCode; + +signals: + void previewDownloaded(KonaImage *ki, QString localPath); + void imageDownloaded(KonaImage *ki, QString localPath); + void jpegDownloaded(KonaImage *ki, QString localPath); + void sampleDownloaded(KonaImage *ki, QString localPath); + +public slots: + void previewRequestFinished(); + void previewResponseHeaderReceived(QHttpResponseHeader resp); + + void imageRequestFinished(); + void imageResponseHeaderReceived(QHttpResponseHeader resp); + + void jpegRequestFinished(); + void jpegResponseHeaderReceived(QHttpResponseHeader resp); + + void sampleRequestFinished(); + void sampleResponseHeaderReceived(QHttpResponseHeader resp); + + void DownloadPreview(bool overwrite = false); + void DownloadImage(bool overwrite = false); + void DownloadJpeg(bool overwrite = false); + void DownloadSample(bool overwrite = false); +}; + +#endif // KONAIMAGE_H diff --git a/konapreviewimageview.cpp b/konapreviewimageview.cpp new file mode 100755 index 0000000..c693fa0 --- /dev/null +++ b/konapreviewimageview.cpp @@ -0,0 +1,56 @@ +#include "konapreviewimageview.h" +#include "ui_konapreviewimageview.h" + +#include + +KonaPreviewImageView::KonaPreviewImageView(QWidget *parent) : + QWidget(parent), + ui(new Ui::KonaPreviewImageView) +{ + ui->setupUi(this); + + ui->imgLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + // ui->imgLabel->setPixmap(QPixmap ("/home/markus/Bilder/temp.jpg")); + + imgReloadCounter = 0; +} + +KonaPreviewImageView::~KonaPreviewImageView() +{ + delete ui; +} + +void KonaPreviewImageView::OpenImage() +{ + emit imageClicked(ki); +} + +void KonaPreviewImageView::RMB() { + qDebug() << "RMB"; +} + +void KonaPreviewImageView::downloadImage() +{ + emit buttonClicked(ki); +} + +void KonaPreviewImageView::previewDownloaded(KonaImage *Ki, QString localPath) { + ki = Ki; + + QPixmap pix (localPath); + if (pix.width() > 0) { + pix = pix.scaled(200,150, Qt::KeepAspectRatio, Qt::SmoothTransformation); + ui->imgLabel->setPixmap(pix); + } + else { + imgReloadCounter++; + if (imgReloadCounter < 3) { + qDebug() << "ERROR: KonaPreviewImageView: Corrupt image. Reload #" << imgReloadCounter; + ki->DownloadPreview(true); + } + } +} + +void KonaPreviewImageView::setCaption(QString text) { + ui->btnResolution->setText(text); +} diff --git a/konapreviewimageview.h b/konapreviewimageview.h new file mode 100755 index 0000000..33d9e93 --- /dev/null +++ b/konapreviewimageview.h @@ -0,0 +1,39 @@ +#ifndef KONAPREVIEWIMAGEVIEW_H +#define KONAPREVIEWIMAGEVIEW_H + +#include +#include "konaimage.h" + +namespace Ui { +class KonaPreviewImageView; +} + +class KonaPreviewImageView : public QWidget +{ + Q_OBJECT + +public: + explicit KonaPreviewImageView(QWidget *parent = 0); + ~KonaPreviewImageView(); + KonaImage* getKonaImage() {return ki;} + +private: + KonaImage *ki; + int imgReloadCounter; + +public slots: + void OpenImage(); + void previewDownloaded(KonaImage *Ki, QString localPath); + void setCaption(QString text); + void RMB(); + void downloadImage(); + +signals: + void imageClicked(KonaImage*); + void buttonClicked(KonaImage*); + +private: + Ui::KonaPreviewImageView *ui; +}; + +#endif // KONAPREVIEWIMAGEVIEW_H diff --git a/konapreviewimageview.ui b/konapreviewimageview.ui new file mode 100755 index 0000000..9778495 --- /dev/null +++ b/konapreviewimageview.ui @@ -0,0 +1,133 @@ + + + KonaPreviewImageView + + + + 0 + 0 + 200 + 170 + + + + + 200 + 170 + + + + PointingHandCursor + + + Form + + + background: rgb(0, 0, 0); + + + + + 2 + 152 + 196 + 16 + + + + PointingHandCursor + + + Qt::NoFocus + + + color: #333; +border: 1px solid #555; +background: qradialgradient(cx: 0.3, cy: -0.4, fx: 0.3, fy: -0.4, radius: 1.35, stop: 0 #fff, stop: 1 #888); + + + 0000 x 0000 + + + true + + + + + + 0 + 0 + 200 + 150 + + + + + 0 + 0 + + + + + + + + + + 0 + 0 + 200 + 150 + + + + border: none; +background: none; + + + + + + + + + + + btnResolution + clicked() + KonaPreviewImageView + downloadImage() + + + 34 + 157 + + + 40 + 150 + + + + + btnImage + clicked() + KonaPreviewImageView + OpenImage() + + + 134 + 93 + + + 184 + 151 + + + + + + OpenImage() + RMB() + downloadImage() + + diff --git a/konarelatedtags.cpp b/konarelatedtags.cpp new file mode 100755 index 0000000..32d3767 --- /dev/null +++ b/konarelatedtags.cpp @@ -0,0 +1,116 @@ +#include "konarelatedtags.h" +#include + +KonaRelatedTags::KonaRelatedTags(KonaClient *Kc, QString Tags, QString Type) +{ + kc = Kc; + tags = Tags; + type = Type; + + + // Initialize temp file + int fileID = 0; + file = new QFile(kc->getTempDir() + SLASH + "relTags_0"); + + while (file->exists()) { + fileID++; + file->setFileName(kc->getTempDir() + SLASH + "relTags_" + QString::number(fileID)); + } + + // Prepare HTTP + http = new QHttp(kc->getServer()); + connect(http, SIGNAL(responseHeaderReceived(QHttpResponseHeader)), + this, SLOT(responseHeaderReceived(QHttpResponseHeader))); + connect(http, SIGNAL(requestFinished(int,bool)), + this, SLOT(requestFinished())); + + // Search + if (Tags == "") { + searchIsDone = true; + } + else { + searchAgain(); + } +} + +void KonaRelatedTags::newSearch(QString Tags, QString Type) +{ + if (Tags != "__KEEPOLD__") tags = Tags; + if (Type != "__KEEPOLD__") type = Type; + + searchAgain(); +} + +void KonaRelatedTags::searchAgain() { + result.clear(); + searchIsDone = false; + + statusCode = 0; + if (!file->open(QIODevice::ReadWrite)) { + qDebug() << "KonaRelatedTags: ERROR: Can't open temp file for search!"; + emit searchFailed(this, ERROR_TAGS_TEMPFILE); + return; + } + + QUrl url("/tag/related.xml?tags=" + tags + (type != "" ? "&type=" + type : "")); + qDebug() << url.toString(); + http->get(url.toString(), file); +} + +void KonaRelatedTags::requestFinished() { + if (statusCode == 200) { + file->flush(); + file->reset(); + + QDomDocument doc ("search"); + if (!doc.setContent(file)) { + qDebug() << "KonaRelatedTags: ERROR: Can't parse xml!"; + emit searchFailed(this, ERROR_SEARCH_XML); + file->close(); + file->remove(); + return; + } + file->close(); + file->remove(); // We don't need it anymore + + QDomElement root = doc.documentElement(); + if (root.tagName() != "tags") { + qDebug() << "KonaRelatedTags: ERROR: Wrong root element!"; + emit searchFailed(this, ERROR_TAGS_FORMAT); + return; + } + + QDomElement el = root.elementsByTagName("tag").at(1).toElement(); + if (el.isNull()) { + qDebug() << "KonaRelatedTags: ERROR: Couldn't get first element!"; + emit searchFailed(this, ERROR_TAGS_FORMAT); + return; + } + + +#define toBool(a) (a == "true" ? true : false) + + int x = 1; + while (!el.isNull()) { //TODO: Filter doubles + result.append(new KonaTag(el.attribute("id", "0").toInt(), + el.attribute("name", ""), + el.attribute("count", "0").toInt(), + el.attribute("type", "unknown").toInt(), + toBool(el.attribute("ambiguous", "false")))); + x++; + el = root.elementsByTagName("tag").at(x).toElement(); + } + + qDebug() << "KonaRelatedTags: Search finished!"; + searchIsDone = true; + emit searchFinished(this); + } + else { + qDebug() << "KonaRelatedTags: ERROR: " << "Received HTTP error code: " << statusCode; + emit searchFailed(this, ERROR_SEARCH_HTTP); + } +} + +void KonaRelatedTags::responseHeaderReceived(QHttpResponseHeader resp) { + statusCode = resp.statusCode(); +} diff --git a/konarelatedtags.h b/konarelatedtags.h new file mode 100755 index 0000000..3e65b76 --- /dev/null +++ b/konarelatedtags.h @@ -0,0 +1,48 @@ +#ifndef KONARELATEDTAGS_H +#define KONARELATEDTAGS_H + +#include +#include "konaclient.h" +#include +#include +#include +#include "konatag.h" + +class KonaRelatedTags : public QObject +{ + Q_OBJECT +public: + KonaRelatedTags(KonaClient *Kc, QString Tags, QString Type); + QString getSourceTags() {return tags;} + QString getType() {return type;} + QList getTags() {return result;} + void newSearch(QString Tags = "__KEEPOLD__", QString Type = "__KEEPOLD__"); + void searchAgain(); + + +private: + KonaClient *kc; + QString tags; + QString type; + + + QHttp *http; + QFile *file; + int statusCode; + + int searchIsDone; + + QList result; + +signals: + void searchFinished(KonaRelatedTags *krt); + void searchFailed(KonaRelatedTags *krt, int errorCode); + +public slots: + void requestFinished(); + void responseHeaderReceived(QHttpResponseHeader resp); + + +}; + +#endif // KONARELATEDTAGS_H diff --git a/konasearch.cpp b/konasearch.cpp new file mode 100755 index 0000000..97b6b20 --- /dev/null +++ b/konasearch.cpp @@ -0,0 +1,195 @@ +#include "konasearch.h" + +#include +#include + +KonaSearch::KonaSearch(KonaClient *Kc, QString Tags, int Page, int Limit) +{ + // Reset + searchIsDone = false; + + // Copy search info to RAM + kc = Kc; + + tags = Tags; + page = Page; + + if (Limit < 100) { + limit = Limit; + } + else { + limit = 100; + } + + // Initialize temp file + int fileID = 0; + file = new QFile(kc->getTempDir() + SLASH + "search_0"); + + while (file->exists()) { + fileID++; + file->setFileName(kc->getTempDir() + SLASH + "search_" + QString::number(fileID)); + } + + // Prepare HTTP + http = new QHttp(kc->getServer()); + connect(http, SIGNAL(responseHeaderReceived(QHttpResponseHeader)), + this, SLOT(responseHeaderReceived(QHttpResponseHeader))); + connect(http, SIGNAL(requestFinished(int,bool)), + this, SLOT(requestFinished())); + + // Search + if (limit == 0) { + searchIsDone = true; + file->close(); + } + else { + searchAgain(); + } +} + +KonaSearch::~KonaSearch() +{ + file->close(); + file->remove(); + file->deleteLater(); + + http->closeConnection(); + http->close(); + http->deleteLater(); +} + +void KonaSearch::newSearch(QString Tags, int Page, int Limit) { + // Reset + searchIsDone = false; + result.clear(); + + // Update search info to RAM + tags = Tags; + page = Page; + + if (Limit < 100) { + limit = Limit; + } + else { + limit = 100; + } + + file->close(); + file->remove(); + file->open(QFile::ReadWrite); + + + searchAgain(); +} + +void KonaSearch::searchAgain() +{ + searchIsDone = false; + file->close(); + + statusCode = 0; + if (!file->open(QIODevice::ReadWrite)) { + qDebug() << "KonaSearch: ERROR: Can't open temp file for search!"; + emit searchFailed(this, ERROR_SEARCH_TEMPFILE); + return; + } + + QUrl url("/post/index.xml?limit=" + QString::number(limit) + "&page=" + QString::number(page) + "&tags=" + tags); + http->get(url.toString(), file); +} + +void KonaSearch::requestFinished() { + if (statusCode == 200) { + file->flush(); + file->reset(); + + QDomDocument doc ("search"); + if (!doc.setContent(file)) { + qDebug() << "KonaSearch: ERROR: Can't parse xml!"; + searchIsDone = true; + emit searchFailed(this, ERROR_SEARCH_XML); + file->close(); + file->remove(); + return; + } + file->close(); + file->remove(); // We don't need it anymore + + QDomElement root = doc.documentElement(); + if (root.tagName() != "posts") { + qDebug() << "KonaSearch: ERROR: Wrong root element!"; + searchIsDone = true; + emit searchFailed(this, ERROR_SEARCH_FORMAT); + return; + } + + QDomElement el = root.firstChildElement("post"); + if (el.isNull()) { + qDebug() << "KonaSearch: ERROR: Couldn't get first element!"; + searchIsDone = true; + emit searchFailed(this, ERROR_SEARCH_FORMAT); + return; + } + + + totalImages = root.attribute("count","-1").toInt(); + offset = root.attribute("offset","-1").toInt(); + +#define toBool(a) (a == "true" ? true : false) + + int x = 0; + while (!el.isNull()) { + QStringList Tags = el.attribute("tags", "").split(" "); + result.append(new KonaImage(kc, + el.attribute("id", "-1").toInt(), + Tags, + el.attribute("created_at", "-1").toInt(), + el.attribute("creator_id", "-1").toInt(), + el.attribute("author", ""), + el.attribute("change","-1").toInt(), + el.attribute("source", ""), + el.attribute("score", "-1").toInt(), + el.attribute("md5"), + el.attribute("file_size", "-1").toInt(), + el.attribute("file_url", ""), + toBool(el.attribute("is_shown_in_index", "")), + el.attribute("preview_url", ""), + el.attribute("preview_width", "-1").toInt(), + el.attribute("preview_height", "-1").toInt(), + el.attribute("actual_preview_width", "-1").toInt(), + el.attribute("actual_preview_height", "-1").toInt(), + el.attribute("sample_url", ""), + el.attribute("sample_width", "-1").toInt(), + el.attribute("sample_height", "-1").toInt(), + el.attribute("sample_file_size", "-1").toInt(), + el.attribute("jpeg_url", ""), + el.attribute("jpeg_width", "-1").toInt(), + el.attribute("jpeg_height", "-1").toInt(), + el.attribute("jpeg_file_size", "-1").toInt(), + el.attribute("rating", ""), + el.attribute("has_children", "").toInt(), + el.attribute("parent_id", "-1").toInt(), + el.attribute("status", ""), + el.attribute("width", "-1").toInt(), + el.attribute("height", "-1").toInt(), + toBool(el.attribute("is_held")), + el.attribute("frames_pending_string", ""), + el.attribute("frames_string") + )); + x++; + el = root.elementsByTagName("post").at(x).toElement(); + } + + qDebug() << "KonaSearch: Search finished!"; + searchIsDone = true; + emit searchFinished(this); + } + else { + qDebug() << "KonaSearch: ERROR: " << "Received HTTP error code: " << statusCode; + emit searchFailed(this, ERROR_SEARCH_HTTP); + } +} + +void KonaSearch::responseHeaderReceived(QHttpResponseHeader resp) { + statusCode = resp.statusCode(); +} diff --git a/konasearch.h b/konasearch.h new file mode 100755 index 0000000..7d2ecb4 --- /dev/null +++ b/konasearch.h @@ -0,0 +1,54 @@ +#ifndef KONASEARCH_H +#define KONASEARCH_H + +#include +#include +#include +#include + +#include "konaclient.h" +#include "konaimage.h" + +class KonaSearch : public QObject +{ + Q_OBJECT +public: + KonaSearch(KonaClient *Kc, QString Tags = "", int Page=1, int Limit = 50); + ~KonaSearch(); + QString getTags() {return tags;} + int getPage() {return page;} + int getLimit() {return limit;} + void searchAgain(); + QList getImages() {return result;} + bool isDone() {return searchIsDone;} + void newSearch(QString Tags = "", int Page=1, int Limit = 50); + int getTotalImages() {return totalImages;} + int getOffset() {return offset;} + +private: + KonaClient *kc; + + QString tags; + int page; + int limit; + + QHttp *http; + QFile *file; + int statusCode; + + int searchIsDone; + + QList result; + int totalImages; + int offset; + +signals: + void searchFinished(KonaSearch *ks); + void searchFailed(KonaSearch *ks, int errorCode); + +public slots: + void requestFinished(); + void responseHeaderReceived(QHttpResponseHeader resp); +}; + +#endif // KONASEARCH_H diff --git a/konatag.cpp b/konatag.cpp new file mode 100755 index 0000000..c78c100 --- /dev/null +++ b/konatag.cpp @@ -0,0 +1,10 @@ +#include "konatag.h" + +KonaTag::KonaTag(int Id, QString Name, int Count, int Type, bool Ambiguous) +{ + id = Id; + name = Name; + count = Count; + type = Type; + ambiguous = Ambiguous; +} diff --git a/konatag.h b/konatag.h new file mode 100755 index 0000000..193f9dc --- /dev/null +++ b/konatag.h @@ -0,0 +1,25 @@ +#ifndef KONATAG_H +#define KONATAG_H + +#include + +class KonaTag : public QObject +{ + Q_OBJECT +public: + KonaTag(int Id, QString Name, int Count, int Type, bool Ambiguous); + int getId() {return id;} + QString getName() {return name;} + int getCount() {return count;} + int getType() {return type;} + bool getAmbiguous() {return ambiguous;} + +private: + int id; + QString name; + int count; + int type; + bool ambiguous; +}; + +#endif // KONATAG_H diff --git a/konatags.cpp b/konatags.cpp new file mode 100755 index 0000000..b5b3d81 --- /dev/null +++ b/konatags.cpp @@ -0,0 +1,131 @@ +#include "konatags.h" +#include + +KonaTags::KonaTags(KonaClient *Kc, QString Name, int Limit, int Page, QString Order, int Id, int AfterId, QString NamePattern) +{ + kc = Kc; + name = Name; + limit = Limit; + page = Page; + order = Order; + id = Id; + afterId = AfterId; + namePattern = NamePattern; + + + // Initialize temp file + int fileID = 0; + file = new QFile(kc->getTempDir() + SLASH + "tags_0"); + + while (file->exists()) { + fileID++; + file->setFileName(kc->getTempDir() + SLASH + "tags_" + QString::number(fileID)); + } + + + // Prepare HTTP + http = new QHttp(kc->getServer()); + connect(http, SIGNAL(responseHeaderReceived(QHttpResponseHeader)), + this, SLOT(responseHeaderReceived(QHttpResponseHeader))); + connect(http, SIGNAL(requestFinished(int,bool)), + this, SLOT(requestFinished())); + + + if (limit != -1) searchAgain(); + else searchIsDone = true; +} + +void KonaTags::searchAgain() { + searchIsDone = false; + + statusCode = 0; + if (!file->open(QIODevice::ReadWrite)) { + qDebug() << "KonaTags: ERROR: Can't open temp file for search!"; + emit searchFailed(this, ERROR_TAGS_TEMPFILE); + return; + } + + QString optParams; + optParams += (id != -1 ? "&id=" + QString::number(id) : ""); + optParams += (afterId != -1 ? "&after_id=" + QString::number(afterId) : ""); + QUrl url("/tag/index.xml?name=" + name + "&page=" + QString::number(page) + "&limit=" + QString::number(limit) + "&order=" + order + "&name_pattern=" + namePattern + optParams); + http->get(url.toString(), file); +} + +void KonaTags::requestFinished() { + if (statusCode == 200) { + file->flush(); + file->reset(); + + QDomDocument doc ("search"); + if (!doc.setContent(file)) { + qDebug() << "KonaSearch: ERROR: Can't parse xml!"; + emit searchFailed(this, ERROR_SEARCH_XML); + file->close(); + file->remove(); + return; + } + file->close(); + file->remove(); // We don't need it anymore + + QDomElement root = doc.documentElement(); + if (root.tagName() != "tags") { + qDebug() << "KonaTags: ERROR: Wrong root element!"; + emit searchFailed(this, ERROR_TAGS_FORMAT); + return; + } + + QDomElement el = root.firstChildElement("tag"); + if (el.isNull()) { + qDebug() << "KonaTags: ERROR: Couldn't get first element!"; + emit searchFailed(this, ERROR_TAGS_FORMAT); + return; + } + + +#define toBool(a) (a == "true" ? true : false) + + int x = 0; + while (!el.isNull()) { + result.append(new KonaTag(el.attribute("id", "0").toInt(), + el.attribute("name"), + el.attribute("count").toInt(), + el.attribute("type").toInt(), + toBool(el.attribute("ambiguous")))); + x++; + el = root.elementsByTagName("tag").at(x).toElement(); + } + + qDebug() << "KonaTags: Search finished!"; + searchIsDone = true; + emit searchFinished(this); + } + else { + qDebug() << "KonaTags: ERROR: " << "Received HTTP error code: " << statusCode; + emit searchFailed(this, ERROR_SEARCH_HTTP); + } +} + +void KonaTags::responseHeaderReceived(QHttpResponseHeader resp) { + statusCode = resp.statusCode(); +} + +void KonaTags::newSearch(QString Name, int Limit, int Page, QString Order, int Id, int AfterId, QString NamePattern) { + // Reset + searchIsDone = false; + result.clear(); + + // Update search info to RAM + if (Name != "__KEEPOLD__") name = Name; + if (Limit != -1) limit = Limit; + if (Page != -1) page = Page; + if (Order != "__KEEPOLD__") order = Order; + if (Id != -1) id = Id; + if (AfterId != -1) afterId = AfterId; + if (NamePattern != "__KEEPOLD__") namePattern = NamePattern; + + file->close(); + file->remove(); + + searchAgain(); +} diff --git a/konatags.h b/konatags.h new file mode 100755 index 0000000..f053c28 --- /dev/null +++ b/konatags.h @@ -0,0 +1,56 @@ +#ifndef KONATAGS_H +#define KONATAGS_H + +#include +#include +#include +#include +#include + +#include "konatag.h" +#include "konaclient.h" + +#define ERROR_TAGS_TEMPFILE 1 +#define ERROR_TAGS_FORMAT 2 +#define ERROR_SEARCH_XML 3 +#define ERROR_SEARCH_HTTP 4 + +class KonaTags : public QObject +{ + Q_OBJECT +public: + // order can be date, count or name + KonaTags(KonaClient *Kc, QString Name, int Limit=20, int Page=1, QString Order="count", int Id = -1, int AfterId = -1, QString NamePattern=""); + void searchAgain(); + bool isDone() {return searchIsDone;} + QList getTags() {return result;} + void newSearch(QString Name = "__KEEPOLD__", int Limit = -1, int Page = -1, QString Order="__KEEPOLD__", int Id = -1, int AfterId = -1, QString NamePattern = "__KEEPOLD__"); + +private: + KonaClient *kc; + QString name; + int limit; + int page; + QString order; + int id; + int afterId; + QString namePattern; + + QHttp *http; + QFile *file; + int statusCode; + + int searchIsDone; + + QList result; + +signals: + void searchFinished(KonaTags *kt); + void searchFailed(KonaTags *kt, int errorCode); + +public slots: + void requestFinished(); + void responseHeaderReceived(QHttpResponseHeader resp); +}; + +#endif // KONATAGS_H diff --git a/main.cpp b/main.cpp new file mode 100755 index 0000000..9eaa18f --- /dev/null +++ b/main.cpp @@ -0,0 +1,18 @@ +#include +#include "mainwindow.h" + +/* +TODO: + - Change "show image" source to jpeg. + - Add jpeg-download to KonaImage. -> CacheDir +*/ + + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + + return a.exec(); +} diff --git a/mainwindow.cpp b/mainwindow.cpp new file mode 100755 index 0000000..a440895 --- /dev/null +++ b/mainwindow.cpp @@ -0,0 +1,297 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" +#include + +#include "konapreviewimageview.h" + +#include + +/* + NOTE #1: round results to get correct page maximum + TODO: Too much to list here. +*/ + + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + ui->setupUi(this); + + bottomPage = 1; + insertAtBeginning = false; + + kc = new KonaClient(QDir::tempPath() + "/KonaClient", "/home/markus/Bilder/KonaChan/Cache", "/home/markus/Bilder/KonaChan/Archive"); + + + flowLayout = new FlowLayout; + ui->listLayout->addLayout(flowLayout); + + connect(ui->scrollList->verticalScrollBar(), SIGNAL(valueChanged(int)), + this, SLOT(onScroll(int))); + + + search = new KonaSearch(kc, ui->txtSearch->text().toStdString().data(), 1); + if (search->isDone()) searchFinished(search); + else connect(search, SIGNAL(searchFinished(KonaSearch*)), + this, SLOT(searchFinished(KonaSearch*))); + + tags = new KonaTags(kc, "", RELATED_TAGS_AMOUNT); + if (tags->isDone()) tagsFinished(tags); + else connect(tags, SIGNAL(searchFinished(KonaTags*)), + this, SLOT(tagsFinished(KonaTags*))); + + relatedTags = new KonaRelatedTags(kc, "", ""); + connect(relatedTags, SIGNAL(searchFinished(KonaRelatedTags*)), + this, SLOT(relatedTagsFinished(KonaRelatedTags*))); + + imageViewer = new ImageViewer(this); + + connect(imageViewer, SIGNAL(loadNext()), + this, SLOT(jumpNext())); + connect(imageViewer, SIGNAL(loadPrev()), + this, SLOT(jumpPrev())); +} + +MainWindow::~MainWindow() +{ + //search->deleteLater(); + //kc->deleteLater(); + delete ui; +} + +void MainWindow::jumpPrev() { + QList kpiv = findChildren(); + + int x; + for (x=0; x < kpiv.count(); x++) { + if (x == 0) { + qDebug() << "MainWindow: RELOAD <"; + ui->scrollList->verticalScrollBar()->setValue(1); + ui->scrollList->verticalScrollBar()->setValue(0); + } + if (x < 1) { // Make sure we don't try to load non existent images + qDebug() << "WARN! MainWindow: NOT LOADED YET OR END OF LIST"; + } + else if (kpiv.at(x)->getKonaImage()->getId() == imageViewer->getCurrentId()) { + qDebug() << "JUMP"; + showImage(kpiv.at(x-1)->getKonaImage()); + break; + } + } + if (x == kpiv.count()) showImage(kpiv.at(0)->getKonaImage()); +} + +void MainWindow::jumpNext() { + QList kpiv = findChildren(); + + int x; + for (x=0; x < kpiv.count(); x++) { // Loop through curerntly available images + if (x + 1 + PRELOAD_AMOUNT == kpiv.count()) { + qDebug() << "MainWindow: RELOAD >"; + ui->scrollList->verticalScrollBar()->setValue(ui->scrollList->verticalScrollBar()->maximum()); + } + if (x + 1 >= kpiv.count()) { // Make sure we don't try to load non existent images + qDebug() << "WARN! MainWindow: NOT LOADED YET OR END OF LIST"; + } + else if (kpiv.at(x)->getKonaImage()->getId() == imageViewer->getCurrentId()) { + showImage(kpiv.at(x+1)->getKonaImage()); + break; + } + } + if (x == kpiv.count()) showImage(kpiv.at(0)->getKonaImage()); +} + +void MainWindow::onScroll(int value) { + if (!search->isDone()) return; // Wait for current search to finish + if (ui->scrollList->verticalScrollBar()->maximum() <= 0) return; + if ((value/ui->scrollList->verticalScrollBar()->maximum())) { + // hit lower end + if (bottomPage <= ui->pageJumpNum->maximum()) { // TODO: might be wrong + //ui->scrollList->verticalScrollBar()->setValue(1); //allow user to continue scrolling up + insertAtBeginning = false; + search->newSearch(currentSearch.toStdString().data(), ++bottomPage); + } + } + else if (((float) value/ (float)ui->scrollList->verticalScrollBar()->maximum()) == 0){ + // hit upper end + if (upperPage > 1) {// TODO: Sort the other way round on receive + insertAtBeginning=true; + search->newSearch(currentSearch.toStdString().data(), --upperPage); + } + } +} + +void MainWindow::jumpToPage() { + insertAtBeginning = false; + ui->scrollList->verticalScrollBar()->setValue(1); + upperPage = ui->pageJumpNum->value(); + bottomPage = ui->pageJumpNum->value(); + clearList(); + search->newSearch(currentSearch.toStdString().data(), ui->pageJumpNum->value()); +} + +void MainWindow::searchPools() { + qDebug() << "POOLS not implemented yet!"; +} + +void MainWindow::searchPosts() { + insertAtBeginning=false; + ui->scrollList->verticalScrollBar()->setValue(0); + ui->btnJump->setEnabled(false); + upperPage = 1; + bottomPage = 1; + clearList(); + currentSearch = ui->txtSearch->text(); + search->newSearch(currentSearch.toStdString().data(), 1); + + if (ui->txtSearch->text() == "") { + tags->newSearch(currentSearch); + } + else { + relatedTags->newSearch(currentSearch); + } +} + + +void MainWindow::searchFinished(KonaSearch *ks) { + ui->btnJump->setEnabled(true); + ui->pageJumpNum->setMaximum(ks->getTotalImages() / ITEMS_PER_SEARCH); // TODO: ROUND to get correct values (NOTE #1) + ui->statusBar->showMessage("Search returned " + QString::number(ks->getTotalImages()) + " results."); + + for (int x=0; x < ks->getImages().count(); x++) { + // Get the KonaImage + KonaImage *ki = ks->getImages().at(x); + + // Check whether it already exists (shouldn't be possible but who knows...) + QList elEx = findChildren(QString::number(ki->getId())); + if (elEx.count() > 0) { + qDebug() << "Main: searchFinished: Item already existed: " << ki->getId(); + } + else { + // Add new frame to list + KonaPreviewImageView *temp = new KonaPreviewImageView(); + temp->setObjectName(QString::number(ki->getId())); + if (insertAtBeginning) { + flowLayout->insertWidgetAt(temp, 0); // Add @ beginning + } + else { + flowLayout->addWidget(temp); // Add @ end + } + + + // Grab the new handle + KonaPreviewImageView* kpiv = findChild(QString::number(ki->getId())); + + // Update image + connect(ki, SIGNAL(previewDownloaded(KonaImage*,QString)), + kpiv, SLOT(previewDownloaded(KonaImage*,QString))); + + connect(kpiv, SIGNAL(buttonClicked(KonaImage*)), + this, SLOT(downloadImage(KonaImage*))); + + connect(kpiv, SIGNAL(imageClicked(KonaImage*)), + this, SLOT(showImage(KonaImage*))); + + kpiv->setCaption("Download @ " + QString::number(ki->getWidth()) + " x " + QString::number(ki->getHeight())); //temp + ki->DownloadPreview(); //Download! + } + } +} + +void MainWindow::showImage(KonaImage *Ki) { + qDebug() << "MainWindow: SHOW " << Ki->getId(); + imageViewer->showLoading(); + + connect(Ki, SIGNAL(imageDownloaded(KonaImage*,QString)), + imageViewer, SLOT(setImage(KonaImage*))); + + Ki->DownloadImage(); + + if (!imageViewer->isVisible()) { + imageViewer->show(); + } + + + + + // PRELOADING (not clean but functional) + QList kpiv = findChildren(); + + int x; + for (x=0; x < kpiv.count(); x++) { + if (x < 1) { // Make sure we don't try to load non existent images + + } + else if (kpiv.at(x)->getKonaImage()->getId() == Ki->getId()) { + // Preloading + int y; + for (y=0; y < PRELOAD_AMOUNT; y++) { // TODO: Add preload limit to appconfig + if (x+1+y < kpiv.count()) { + qDebug() << "MainWindow: Will preload image " << kpiv.at(x+1+y)->getKonaImage()->getId(); + //downloadImage(kpiv.at(x+1+y)->getKonaImage(), false); + connect(kpiv.at(x+y)->getKonaImage(), SIGNAL(imageDownloaded(KonaImage*,QString)), + kpiv.at(x+1+y)->getKonaImage(), SLOT(DownloadImage())); + } + } + break; + } + } +} + +void MainWindow::downloadImage(KonaImage *Ki) { + qDebug() << "MainWindow: downloadImage " + Ki->getId(); + qDebug() << "MainWindow: downloadImage: THIS FUNCTION IS DEPRECTAED AND WILL BE REMOVED!"; + downloadImage(Ki, true); +} + +void MainWindow::downloadImage(KonaImage *Ki, bool overwrite) { + qDebug() << "DOWNLOAD " << Ki->getId(); + ui->statusBar->showMessage("Downloading image " + QString::number(Ki->getId()) + "..."); + Ki->DownloadImage(overwrite); // TODO: Do we want to have true here? +} + +void MainWindow::tagClicked(QString link) { + QStringList temp = link.split("?"); + + if (temp.at(0) == "srcTag") { + ui->txtSearch->setText(temp.at(1)); + searchPosts(); // TODO: later it needs to support pools! + } + else if (temp.at(0) == "addTag") { + if (ui->txtSearch->text().toLower().indexOf(temp.at(1).toLower()) == -1) { + ui->txtSearch->setText(ui->txtSearch->text() + " " + temp.at(1)); + searchPosts(); // TODO: support pools + } + } +} + +void MainWindow::tagsFinished(KonaTags *kt) +{ + QString out; + for (int x=0; x < kt->getTags().count(); x++) { + KonaTag *tag = kt->getTags().at(x); + out.append("+" + tag->getName() + " (" + QString::number(tag->getCount()) + ")
"); + } + + ui->lblTags->setText(out); +} + +void MainWindow::relatedTagsFinished(KonaRelatedTags *krt) //TODO: Merge with tagsFinished() +{ + QString out; + for (int x=0; x < krt->getTags().count(); x++) { + KonaTag *tag = krt->getTags().at(x); + out.append("+" + tag->getName() + " (" + QString::number(tag->getCount()) + ")
"); + } + ui->lblTags->setText(out); +} + +void MainWindow::clearList() { + QLayoutItem* item; + while ( ( item = flowLayout->takeAt( 0 ) ) != NULL ) + { + delete item->widget(); + delete item; + } +} diff --git a/mainwindow.h b/mainwindow.h new file mode 100755 index 0000000..b370469 --- /dev/null +++ b/mainwindow.h @@ -0,0 +1,80 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include + +#include "konaclient.h" +#include "konasearch.h" +#include "konaimage.h" +#include "konatags.h" +#include "konatag.h" +#include "konarelatedtags.h" +#include +#include "flowlayout.h" +#include "imageviewer.h" + +#define ITEMS_PER_SEARCH 50 +#define RELATED_TAGS_AMOUNT 10 + + +#define SEARCHTYPE_POSTS 0 +#define SEARCHTYPE_POOLS 1 + + + +// SETTINGS +#define PRELOAD_AMOUNT 3 // TODO: + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + +public slots: + // GUI Events + void onScroll(int value); + void searchPosts(); + void searchPools(); + void jumpToPage(); + void tagClicked(QString link); + + // Int + void searchFinished(KonaSearch *ks); + void tagsFinished(KonaTags *kt); + void relatedTagsFinished(KonaRelatedTags *krt); + void downloadImage(KonaImage *Ki); + void downloadImage(KonaImage *Ki, bool overwrite); + void showImage(KonaImage *Ki); + void jumpNext(); + void jumpPrev(); + +private: + Ui::MainWindow *ui; + + KonaClient *kc; + KonaSearch *search; + KonaTags *tags; + KonaRelatedTags *relatedTags; + + FlowLayout *flowLayout; + + ImageViewer *imageViewer; + + bool insertAtBeginning; + + void clearList(); + + int upperPage; + int bottomPage; + + QString currentSearch; +}; + +#endif // MAINWINDOW_H diff --git a/mainwindow.ui b/mainwindow.ui new file mode 100755 index 0000000..293f1c1 --- /dev/null +++ b/mainwindow.ui @@ -0,0 +1,503 @@ + + + MainWindow + + + + 0 + 0 + 880 + 600 + + + + + 640 + 480 + + + + KonaClient + + + + + + + /* background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(0, 0, 0, 255), stop:1 rgba(122, 122, 122, 255));*/ + + + true + + + + + 0 + 0 + 663 + 533 + + + + + + + 6 + + + + + + + + + + + + + 0 + 0 + 880 + 25 + + + + + &File + + + + + + &View + + + + &Widgets + + + + + + + + + + &Help + + + + + + + + + + Qt::LeftToRight + + + false + + + QDockWidget::AllDockWidgetFeatures + + + Search + + + 1 + + + + + + + Remember to replace spaces per underscores. For example "Suzumiya Haruhi" -> suzumiya_haruhi +You can use * as a wildcard. For example "higurashi*" + + + Enter tags seperated by a space. + + + + + + + + + Search in posts + + + &Posts + + + + + + + Search in pools + + + P&ools + + + + + + + + + + + Qt::LeftToRight + + + Navigation + + + 1 + + + + + + + + + Jump to page: + + + + + + + 1 + + + 1 + + + + + + + + + false + + + Go! + + + + + + + + + Tags + + + 1 + + + + + 0 + + + 0 + + + + + true + + + + + 0 + 0 + 194 + 304 + + + + + + + [Tags] + + + + + + + Qt::Vertical + + + + 20 + 1000 + + + + + + + + + + + + + + &Quit + + + + + true + + + true + + + &Search + + + Alt+S + + + + + true + + + true + + + &Navigation + + + Alt+N + + + + + true + + + true + + + &Tags + + + Alt+T + + + + + + + + btnSearchPosts + clicked() + MainWindow + searchPosts() + + + 58 + 117 + + + 69 + 148 + + + + + btnSearchPools + clicked() + MainWindow + searchPools() + + + 172 + 119 + + + 200 + 146 + + + + + txtSearch + returnPressed() + MainWindow + searchPosts() + + + 146 + 83 + + + 26 + 145 + + + + + btnJump + clicked() + MainWindow + jumpToPage() + + + 186 + 232 + + + 285 + 348 + + + + + lblTags + linkActivated(QString) + MainWindow + tagClicked(QString) + + + 61 + 298 + + + 200 + 558 + + + + + tagsWidget + visibilityChanged(bool) + actionTags + setChecked(bool) + + + 127 + 265 + + + 282 + 261 + + + + + actionTags + toggled(bool) + tagsWidget + setVisible(bool) + + + -1 + -1 + + + 97 + 412 + + + + + searchWidget + visibilityChanged(bool) + actionSearch + setChecked(bool) + + + 97 + 82 + + + -1 + -1 + + + + + actionSearch + toggled(bool) + searchWidget + setVisible(bool) + + + -1 + -1 + + + 97 + 82 + + + + + navigationWidget + visibilityChanged(bool) + actionNavigation + setChecked(bool) + + + 97 + 193 + + + 97 + 82 + + + + + actionNavigation + toggled(bool) + navigationWidget + setVisible(bool) + + + -1 + -1 + + + 97 + 193 + + + + + actionQuit + triggered() + MainWindow + close() + + + -1 + -1 + + + 439 + 299 + + + + + + searchPosts() + searchPools() + jumpToPage() + tagClicked(QString) + +