Merge remote-tracking branch 'origin/master' into editor-sorting-v5

This commit is contained in:
Daenyth 2014-06-22 08:10:22 -04:00
commit e99c1bbe6d
88 changed files with 4775 additions and 2615 deletions

2
.gitignore vendored
View file

@ -1,4 +1,4 @@
tags
build
build*
*.qm
.directory

View file

@ -1,17 +1,107 @@
# Cockatrice's main CMakeLists.txt
#
# This is basically a wrapper to enable/disable the compilation
# of the different projects: servatrice, cockatrice, test
# This file sets all the variables shared between the projects
# like the installation path, compilation flags etc..
cmake_minimum_required(VERSION 2.6)
set(PROJECT_NAME "Cockatrice")
set(PROJECT_VERSION_MAJOR 0)
set(PROJECT_VERSION_MINOR 0)
set(PROJECT_VERSION_PATCH 1)
set(PROJECT_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH} )
# Defualt to "Release" build type
# User-provided value for CMAKE_BUILD_TYPE must be checked before the PROJECT() call
IF(DEFINED CMAKE_BUILD_TYPE)
SET(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "Type of build")
ELSE()
SET(CMAKE_BUILD_TYPE Release CACHE STRING "Type of build")
ENDIF()
# A project name is needed for CPack
PROJECT("${PROJECT_NAME}")
# Set conventional loops
set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true)
# Define a proper install path
if(UNIX)
if(APPLE)
# MacOS X
# Due to the special bundle structure ignore
# the prefix eventually set by the user.
set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/release)
else()
# Linux / BSD
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
#fix package build
if(PREFIX)
set(CMAKE_INSTALL_PREFIX ${PREFIX})
else()
set(CMAKE_INSTALL_PREFIX /usr/local)
endif()
endif()
endif()
elseif(WIN32)
set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/release)
endif()
# Define proper compilation flags
IF(MSVC)
# Visual Studio:
# Maximum optimization
set(CMAKE_CXX_FLAGS_RELEASE "/Ox")
# Generate complete debugging information
#set(CMAKE_CXX_FLAGS_DEBUG "/Zi")
ELSEIF (CMAKE_COMPILER_IS_GNUCXX)
# linux/gcc, bsd/gcc, windows/mingw
set(CMAKE_CXX_FLAGS_RELEASE "-s -O2")
set(CMAKE_CXX_FLAGS_DEBUG "-ggdb -O0")
ELSE()
# other: osx/llvm, bsd/llvm
set(CMAKE_CXX_FLAGS_RELEASE "-O2")
set(CMAKE_CXX_FLAGS_DEBUG "-g -O0")
ENDIF()
# GNU systems need to define the Mersenne exponent for the RNG to compile w/o warning
IF(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
ADD_DEFINITIONS("-DSFMT_MEXP=19937")
ENDIF()
#Find Qt4 and enable the needed features
FIND_PACKAGE(Qt4 REQUIRED)
set(CMAKE_AUTOMOC TRUE)
# Find other needed libraries
FIND_PACKAGE(Protobuf REQUIRED)
# Compile servatrice (default off)
option(WITH_SERVER "build servatrice" OFF)
add_subdirectory(common)
if(WITH_SERVER)
add_subdirectory(servatrice)
endif(WITH_SERVER)
if (NOT WITHOUT_CLIENT)
add_subdirectory(cockatrice)
add_subdirectory(oracle)
endif(NOT WITHOUT_CLIENT)
if (WITH_TESTCLIENT)
add_subdirectory(testclient)
endif(WITH_TESTCLIENT)
add_subdirectory(servatrice)
endif()
FILE(GLOB sounds "${CMAKE_CURRENT_SOURCE_DIR}/sounds/*.raw")
INSTALL(FILES ${sounds} DESTINATION share/cockatrice/sounds)
FILE(GLOB zonebg "${CMAKE_CURRENT_SOURCE_DIR}/zonebg/*.*")
INSTALL(FILES ${zonebg} DESTINATION share/cockatrice/zonebg)
# Compile cockatrice (default on)
option(WITH_CLIENT "build cockatrice" ON)
if(WITH_CLIENT)
add_subdirectory(cockatrice)
add_subdirectory(sounds)
add_subdirectory(zonebg)
endif()
# Compile oracle (default on)
option(WITH_ORACLE "build oracle" ON)
if(WITH_ORACLE)
add_subdirectory(oracle)
endif()
# Compile testclient (default off)
option(WITH_TESTCLIENT "build testclient" OFF)
if (WITH_TESTCLIENT)
add_subdirectory(testclient)
endif()

View file

@ -1,216 +1,149 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR})
# CMakeLists for cockatrice directory
#
# provides the cockatrice binary
PROJECT(cockatrice)
SET(cockatrice_SOURCES
src/abstractcounter.cpp
src/counter_general.cpp
src/dlg_creategame.cpp
src/dlg_filter_games.cpp
src/dlg_connect.cpp
src/dlg_create_token.cpp
src/dlg_edit_tokens.cpp
src/abstractclient.cpp
src/remoteclient.cpp
src/main.cpp
src/window_main.cpp
src/gamesmodel.cpp
src/player.cpp
src/playertarget.cpp
src/cardzone.cpp
src/selectzone.cpp
src/cardlist.cpp
src/abstractcarditem.cpp
src/carditem.cpp
src/tablezone.cpp
src/handzone.cpp
src/handcounter.cpp
src/carddatabase.cpp
src/gameview.cpp
src/gameselector.cpp
src/decklistmodel.cpp
src/deck_loader.cpp
src/dlg_load_deck_from_clipboard.cpp
src/dlg_load_remote_deck.cpp
src/cardinfowidget.cpp
src/messagelogwidget.cpp
src/zoneviewzone.cpp
src/zoneviewwidget.cpp
src/pilezone.cpp
src/stackzone.cpp
src/carddragitem.cpp
src/carddatabasemodel.cpp
src/setsmodel.cpp
src/window_sets.cpp
src/abstractgraphicsitem.cpp
src/abstractcarddragitem.cpp
src/dlg_settings.cpp
src/dlg_cardsearch.cpp
src/phasestoolbar.cpp
src/gamescene.cpp
src/arrowitem.cpp
src/arrowtarget.cpp
src/tab.cpp
src/tab_server.cpp
src/tab_room.cpp
src/tab_message.cpp
src/tab_game.cpp
src/tab_deck_storage.cpp
src/tab_replays.cpp
src/tab_supervisor.cpp
src/tab_admin.cpp
src/tab_userlists.cpp
src/tab_deck_editor.cpp
src/replay_timeline_widget.cpp
src/deckstats_interface.cpp
src/chatview.cpp
src/userlist.cpp
src/userinfobox.cpp
src/user_context_menu.cpp
src/remotedecklist_treewidget.cpp
src/remotereplaylist_treewidget.cpp
src/deckview.cpp
src/playerlistwidget.cpp
src/pixmapgenerator.cpp
src/settingscache.cpp
src/localserver.cpp
src/localserverinterface.cpp
src/localclient.cpp
src/priceupdater.cpp
src/qt-json/json.cpp
src/soundengine.cpp
${CMAKE_CURRENT_BINARY_DIR}/version_string.cpp
)
SET(cockatrice_HEADERS
src/abstractcounter.h
src/counter_general.h
src/dlg_creategame.h
src/dlg_filter_games.h
src/dlg_connect.h
src/dlg_create_token.h
src/dlg_edit_tokens.h
src/gamesmodel.h
src/abstractclient.h
src/remoteclient.h
src/window_main.h
src/cardzone.h
src/selectzone.h
src/player.h
src/playertarget.h
src/abstractcarditem.h
src/carditem.h
src/tablezone.h
src/handzone.h
src/handcounter.h
src/carddatabase.h
src/gameview.h
src/gameselector.h
src/decklistmodel.h
src/deck_loader.h
src/dlg_load_deck_from_clipboard.h
src/dlg_load_remote_deck.h
src/cardinfowidget.h
src/messagelogwidget.h
src/zoneviewzone.h
src/zoneviewwidget.h
src/pilezone.h
src/stackzone.h
src/carddragitem.h
src/carddatabasemodel.h
src/setsmodel.h
src/window_sets.h
src/abstractgraphicsitem.h
src/abstractcarddragitem.h
src/dlg_settings.h
src/dlg_cardsearch.h
src/phasestoolbar.h
src/gamescene.h
src/arrowitem.h
src/arrowtarget.h
src/tab.h
src/tab_server.h
src/tab_room.h
src/tab_message.h
src/tab_game.h
src/tab_deck_storage.h
src/tab_replays.h
src/tab_supervisor.h
src/tab_admin.h
src/tab_userlists.h
src/tab_deck_editor.h
src/replay_timeline_widget.h
src/deckstats_interface.h
src/chatview.h
src/userlist.h
src/userinfobox.h
src/user_context_menu.h
src/remotedecklist_treewidget.h
src/remotereplaylist_treewidget.h
src/deckview.h
src/playerlistwidget.h
src/settingscache.h
src/localserver.h
src/localserverinterface.h
src/localclient.h
src/priceupdater.h
src/soundengine.h
src/pending_command.h
src/abstractcounter.cpp
src/counter_general.cpp
src/dlg_creategame.cpp
src/dlg_filter_games.cpp
src/dlg_connect.cpp
src/dlg_create_token.cpp
src/dlg_edit_tokens.cpp
src/abstractclient.cpp
src/remoteclient.cpp
src/main.cpp
src/window_main.cpp
src/gamesmodel.cpp
src/player.cpp
src/playertarget.cpp
src/cardzone.cpp
src/selectzone.cpp
src/cardlist.cpp
src/abstractcarditem.cpp
src/carditem.cpp
src/tablezone.cpp
src/handzone.cpp
src/handcounter.cpp
src/carddatabase.cpp
src/keysignals.cpp
src/gameview.cpp
src/gameselector.cpp
src/decklistmodel.cpp
src/deck_loader.cpp
src/dlg_load_deck_from_clipboard.cpp
src/dlg_load_remote_deck.cpp
src/cardinfowidget.cpp
src/cardframe.cpp
src/cardinfopicture.cpp
src/cardinfotext.cpp
src/filterbuilder.cpp
src/cardfilter.cpp
src/filtertreemodel.cpp
src/filtertree.cpp
src/messagelogwidget.cpp
src/zoneviewzone.cpp
src/zoneviewwidget.cpp
src/pilezone.cpp
src/stackzone.cpp
src/carddragitem.cpp
src/carddatabasemodel.cpp
src/setsmodel.cpp
src/window_sets.cpp
src/abstractgraphicsitem.cpp
src/abstractcarddragitem.cpp
src/dlg_settings.cpp
src/dlg_cardsearch.cpp
src/phasestoolbar.cpp
src/gamescene.cpp
src/arrowitem.cpp
src/arrowtarget.cpp
src/tab.cpp
src/tab_server.cpp
src/tab_room.cpp
src/tab_message.cpp
src/tab_game.cpp
src/tab_deck_storage.cpp
src/tab_replays.cpp
src/tab_supervisor.cpp
src/tab_admin.cpp
src/tab_userlists.cpp
src/tab_deck_editor.cpp
src/replay_timeline_widget.cpp
src/deckstats_interface.cpp
src/chatview.cpp
src/userlist.cpp
src/userinfobox.cpp
src/user_context_menu.cpp
src/remotedecklist_treewidget.cpp
src/remotereplaylist_treewidget.cpp
src/deckview.cpp
src/playerlistwidget.cpp
src/pixmapgenerator.cpp
src/settingscache.cpp
src/localserver.cpp
src/localserverinterface.cpp
src/localclient.cpp
src/priceupdater.cpp
src/qt-json/json.cpp
src/soundengine.cpp
src/pending_command.cpp
${CMAKE_CURRENT_BINARY_DIR}/version_string.cpp
)
if (UNIX AND NOT APPLE)
set_source_files_properties(src/main.cpp PROPERTIES COMPILE_FLAGS -DTRANSLATION_PATH=\\"${CMAKE_INSTALL_PREFIX}/share/cockatrice/translations\\")
set_source_files_properties(src/main.cpp PROPERTIES COMPILE_FLAGS -DTRANSLATION_PATH=\\"${CMAKE_INSTALL_PREFIX}/share/cockatrice/translations\\")
endif (UNIX AND NOT APPLE)
set(cockatrice_RESOURCES cockatrice.qrc)
set(cockatrice_TS
# translations/cockatrice_cs.ts
translations/cockatrice_de.ts
translations/cockatrice_en.ts
translations/cockatrice_es.ts
# translations/cockatrice_fr.ts
translations/cockatrice_it.ts
translations/cockatrice_ja.ts
# translations/cockatrice_pl.ts
# translations/cockatrice_pt-br.ts
translations/cockatrice_pt.ts
# translations/cockatrice_ru.ts
# translations/cockatrice_sk.ts
translations/cockatrice_sv.ts
# translations/cockatrice_zh_CN.ts
# translations/cockatrice_cs.ts
translations/cockatrice_de.ts
translations/cockatrice_en.ts
translations/cockatrice_es.ts
# translations/cockatrice_fr.ts
translations/cockatrice_it.ts
translations/cockatrice_ja.ts
# translations/cockatrice_pl.ts
# translations/cockatrice_pt-br.ts
translations/cockatrice_pt.ts
# translations/cockatrice_ru.ts
# translations/cockatrice_sk.ts
translations/cockatrice_sv.ts
# translations/cockatrice_zh_CN.ts
)
if(WIN32)
set(cockatrice_SOURCES ${cockatrice_SOURCES} cockatrice.rc)
set(cockatrice_SOURCES ${cockatrice_SOURCES} cockatrice.rc)
endif(WIN32)
if(APPLE)
set(MACOSX_BUNDLE_ICON_FILE appicon.icns)
set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/resources/appicon.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
set(cockatrice_SOURCES ${cockatrice_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/resources/appicon.icns)
set(MACOSX_BUNDLE_ICON_FILE appicon.icns)
set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/resources/appicon.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
set(cockatrice_SOURCES ${cockatrice_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/resources/appicon.icns)
ENDIF(APPLE)
if (NOT QT_QTMULTIMEDIA_FOUND)
FIND_PACKAGE(QtMobility REQUIRED)
endif (NOT QT_QTMULTIMEDIA_FOUND)
SET(QT_USE_QTNETWORK TRUE)
SET(QT_USE_QTMULTIMEDIA TRUE)
SET(QT_USE_QTXML TRUE)
SET(QT_USE_QTSVG TRUE)
FIND_PACKAGE(Qt4 REQUIRED)
if (NOT QT_QTMULTIMEDIA_FOUND)
FIND_PACKAGE(QtMobility REQUIRED)
endif (NOT QT_QTMULTIMEDIA_FOUND)
FIND_PACKAGE(Protobuf REQUIRED)
FIND_PACKAGE(Threads)
set(CMAKE_CXX_FLAGS_DEBUG "-ggdb -O0")
set(CMAKE_CXX_FLAGS_RELEASE "-s -O2")
# paths
# Declare path variables
set(ICONDIR share/icons CACHE STRING "icon dir")
set(DESKTOPDIR share/applications CACHE STRING "desktop file destination")
QT4_WRAP_CPP(cockatrice_HEADERS_MOC ${cockatrice_HEADERS})
# Let cmake chew Qt4's translations and resource files
# Note: header files are MOC-ed automatically by cmake
QT4_ADD_TRANSLATION(cockatrice_QM ${cockatrice_TS})
QT4_ADD_RESOURCES(cockatrice_RESOURCES_RCC ${cockatrice_RESOURCES})
# Include directories
INCLUDE(${QT_USE_FILE})
INCLUDE_DIRECTORIES(../common)
INCLUDE_DIRECTORIES(${PROTOBUF_INCLUDE_DIR})
@ -219,23 +152,61 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
INCLUDE_DIRECTORIES(${QT_MOBILITY_INCLUDE_DIR})
INCLUDE_DIRECTORIES(${QT_MOBILITY_MULTIMEDIAKIT_INCLUDE_DIR})
ADD_EXECUTABLE(cockatrice WIN32 MACOSX_BUNDLE ${cockatrice_SOURCES} ${cockatrice_QM} ${cockatrice_RESOURCES_RCC} ${cockatrice_HEADERS_MOC})
TARGET_LINK_LIBRARIES(cockatrice cockatrice_common ${QT_LIBRARIES} ${QT_MOBILITY_MULTIMEDIAKIT_LIBRARY} ${CMAKE_THREAD_LIBS_INIT})
# Build cockatrice binary and link it
ADD_EXECUTABLE(cockatrice WIN32 MACOSX_BUNDLE ${cockatrice_SOURCES} ${cockatrice_QM} ${cockatrice_RESOURCES_RCC} ${cockatrice_MOC_SRCS})
TARGET_LINK_LIBRARIES(cockatrice cockatrice_common ${QT_QTMAIN_LIBRARY} ${QT_LIBRARIES} ${QT_MOBILITY_MULTIMEDIAKIT_LIBRARY})
IF (NOT APPLE)
INSTALL(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/cockatrice DESTINATION bin)
ELSE (APPLE)
INSTALL(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/cockatrice.app DESTINATION bin)
ENDIF (NOT APPLE)
if (NOT WIN32 AND NOT APPLE)
INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/cockatrice.png DESTINATION ${ICONDIR}/hicolor/48x48/apps)
INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/cockatrice.svg DESTINATION ${ICONDIR}/hicolor/scalable/apps)
INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/cockatrice.desktop DESTINATION ${DESKTOPDIR})
INSTALL(FILES ${cockatrice_QM} DESTINATION share/cockatrice/translations)
ENDIF(NOT WIN32 AND NOT APPLE)
if(MSVC)
set_target_properties(cockatrice PROPERTIES LINK_FLAGS "/SUBSYSTEM:WINDOWS")
endif(MSVC)
if(UNIX)
if(APPLE)
INSTALL(TARGETS cockatrice BUNDLE DESTINATION ./)
INSTALL(FILES ${cockatrice_QM} DESTINATION ./cockatrice.app/Contents/Resources/translations)
else()
# Assume linux
INSTALL(TARGETS cockatrice RUNTIME DESTINATION bin/)
INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/cockatrice.png DESTINATION ${ICONDIR}/hicolor/48x48/apps)
INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/cockatrice.svg DESTINATION ${ICONDIR}/hicolor/scalable/apps)
INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/cockatrice.desktop DESTINATION ${DESKTOPDIR})
INSTALL(FILES ${cockatrice_QM} DESTINATION share/cockatrice/translations)
endif()
elseif(WIN32)
INSTALL(TARGETS cockatrice RUNTIME DESTINATION ./)
INSTALL(FILES ${cockatrice_QM} DESTINATION ./translations)
endif()
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/version_string.cpp ${CMAKE_CURRENT_BINARY_DIR}/version_string.h
COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR} -P ${CMAKE_CURRENT_SOURCE_DIR}/../common/getversion.cmake
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/version_string.cpp ${CMAKE_CURRENT_BINARY_DIR}/version_string.h
COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR} -P ${CMAKE_CURRENT_SOURCE_DIR}/../common/getversion.cmake
)
if(APPLE)
set(plugin_dest_dir ./cockatrice.app/Contents/Plugins)
set(qtconf_dest_dir ./cockatrice.app/Contents/Resources)
# note: no codecs in qt5
# note: phonon_backend => mediaservice
# note: needs platform on osx
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
install(DIRECTORY "${QT_PLUGINS_DIR}/" DESTINATION ${plugin_dest_dir} COMPONENT Runtime
FILES_MATCHING REGEX "(codecs|iconengines|imageformats|mediaservice|phonon_backend|platforms)/.*_debug\\.dylib")
else()
install(DIRECTORY "${QT_PLUGINS_DIR}/" DESTINATION ${plugin_dest_dir} COMPONENT Runtime
FILES_MATCHING REGEX "(codecs|iconengines|imageformats|mediaservice|phonon_backend|platforms)/[^_]*\\.dylib")
endif()
install(CODE "
file(WRITE \"${qtconf_dest_dir}/qt.conf\" \"[Paths]
Plugins = Plugins\")
" COMPONENT Runtime)
install(CODE "
file(GLOB_RECURSE QTPLUGINS
\"${plugin_dest_dir}/*.dylib\")
include(BundleUtilities)
fixup_bundle(\"\${CMAKE_INSTALL_PREFIX}/cockatrice.app\" \"\${QTPLUGINS}\" \"${QT_LIBRARY_DIR}\")
" COMPONENT Runtime)
endif()

View file

@ -2,7 +2,10 @@
#include <QGraphicsScene>
#include <QCursor>
#include <QGraphicsSceneMouseEvent>
#include <math.h>
#include <cmath>
#ifdef _WIN32
#include "round.h"
#endif /* _WIN32 */
#include "carddatabase.h"
#include "cardinfowidget.h"
#include "abstractcarditem.h"
@ -143,7 +146,7 @@ void AbstractCardItem::paintPicture(QPainter *painter, const QSizeF &translatedS
painter->restore();
}
void AbstractCardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/)
void AbstractCardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
{
painter->save();

View file

@ -1,9 +1,11 @@
#define _USE_MATH_DEFINES
#include <cmath>
#include "arrowitem.h"
#include "playertarget.h"
#include "carditem.h"
#include "cardzone.h"
#include "player.h"
#include "math.h"
#include <QPainter>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsScene>
@ -64,7 +66,7 @@ void ArrowItem::updatePath(const QPointF &endPoint)
{
const double arrowWidth = 15.0;
const double headWidth = 40.0;
const double headLength = headWidth / sqrt(2);
const double headLength = headWidth / pow(2, 0.5); // aka headWidth / sqrt (2) but this produces a compile error with MSVC++
const double phi = 15;
if (!startItem)

View file

@ -80,11 +80,13 @@ bool PictureToLoad::nextSet()
return true;
}
PictureLoader::PictureLoader(const QString &__picsPath, bool _picDownload, QObject *parent)
: QObject(parent), _picsPath(__picsPath), picDownload(_picDownload), downloadRunning(false), loadQueueRunning(false)
PictureLoader::PictureLoader(const QString &__picsPath, bool _picDownload, bool _picDownloadHq, QObject *parent)
: QObject(parent),
_picsPath(__picsPath), picDownload(_picDownload), picDownloadHq(_picDownloadHq),
downloadRunning(false), loadQueueRunning(false)
{
connect(this, SIGNAL(startLoadQueue()), this, SLOT(processLoadQueue()), Qt::QueuedConnection);
networkManager = new QNetworkAccessManager(this);
connect(networkManager, SIGNAL(finished(QNetworkReply *)), this, SLOT(picDownloadFinished(QNetworkReply *)));
}
@ -99,7 +101,7 @@ void PictureLoader::processLoadQueue()
{
if (loadQueueRunning)
return;
loadQueueRunning = true;
forever {
mutex.lock();
@ -113,7 +115,7 @@ void PictureLoader::processLoadQueue()
QString correctedName = ptl.getCard()->getCorrectedName();
QString picsPath = _picsPath;
QString setName = ptl.getSetName();
QImage image;
if (!image.load(QString("%1/%2/%3.full.jpg").arg(picsPath).arg(setName).arg(correctedName)))
if (!image.load(QString("%1/%2/%3%4.full.jpg").arg(picsPath).arg(setName).arg(correctedName).arg(1)))
@ -135,6 +137,20 @@ void PictureLoader::processLoadQueue()
}
}
QString PictureLoader::getPicUrl(CardInfo *card)
{
if (!picDownload) return 0;
QString picUrl = picDownloadHq ? settingsCache->getPicUrlHq() : settingsCache->getPicUrl();
picUrl.replace("!name!", QUrl::toPercentEncoding(card->getCorrectedName()));
CardSet *set = card->getPreferredSet();
picUrl.replace("!setcode!", QUrl::toPercentEncoding(set->getShortName()));
picUrl.replace("!setname!", QUrl::toPercentEncoding(set->getLongName()));
picUrl.replace("!cardid!", QUrl::toPercentEncoding(QString::number(card->getPreferredMuId())));
return picUrl;
}
void PictureLoader::startNextPicDownload()
{
if (cardsToDownload.isEmpty()) {
@ -142,23 +158,16 @@ void PictureLoader::startNextPicDownload()
downloadRunning = false;
return;
}
downloadRunning = true;
cardBeingDownloaded = cardsToDownload.takeFirst();
QString picUrl;
if (cardBeingDownloaded.getStripped())
picUrl = cardBeingDownloaded.getCard()->getPicURLSt(cardBeingDownloaded.getSetName());
else if (cardBeingDownloaded.getHq()) {
picUrl = cardBeingDownloaded.getCard()->getPicURLHq(cardBeingDownloaded.getSetName());
if (picUrl.isEmpty()) {
picUrl = cardBeingDownloaded.getCard()->getPicURL(cardBeingDownloaded.getSetName());
cardBeingDownloaded.setHq(false);
}
} else
picUrl = cardBeingDownloaded.getCard()->getPicURL(cardBeingDownloaded.getSetName());
// TODO: Do something useful when picUrl is 0 or empty, etc
QString picUrl = getPicUrl(cardBeingDownloaded.getCard());
QUrl url(picUrl);
QNetworkRequest req(url);
qDebug() << "starting picture download:" << req.url();
networkManager->get(req);
@ -232,6 +241,12 @@ void PictureLoader::setPicDownload(bool _picDownload)
picDownload = _picDownload;
}
void PictureLoader::setPicDownloadHq(bool _picDownloadHq)
{
QMutexLocker locker(&mutex);
picDownloadHq = _picDownloadHq;
}
CardInfo::CardInfo(CardDatabase *_db,
const QString &_name,
bool _isToken,
@ -244,22 +259,18 @@ CardInfo::CardInfo(CardDatabase *_db,
bool _cipt,
int _tableRow,
const SetList &_sets,
const QMap<QString, QString> &_picURLs,
const QMap<QString, QString> &_picURLsHq,
const QMap<QString, QString> &_picURLsSt)
QMap<QString, int> _muIds)
: db(_db),
name(_name),
isToken(_isToken),
sets(_sets),
muIds(_muIds),
manacost(_manacost),
cardtype(_cardtype),
powtough(_powtough),
text(_text),
colors(_colors),
loyalty(_loyalty),
picURLs(_picURLs),
picURLsHq(_picURLsHq),
picURLsSt(_picURLsSt),
cipt(_cipt),
tableRow(_tableRow),
pixmap(NULL)
@ -284,6 +295,8 @@ QString CardInfo::getMainCardType() const
int pos;
if ((pos = result.indexOf('-')) != -1)
result.remove(pos, result.length());
if ((pos = result.indexOf("")) != -1)
result.remove(pos, result.length());
if ((pos = result.indexOf("//")) != -1)
result.remove(pos, result.length());
result = result.simplified();
@ -315,19 +328,12 @@ void CardInfo::addToSet(CardSet *set)
sets << set;
}
QString CardInfo::getPicURL() const
{
SetList sortedSets = sets;
sortedSets.sortByKey();
return picURLs.value(sortedSets.first()->getShortName());
}
QPixmap *CardInfo::loadPixmap()
{
if (pixmap)
return pixmap;
pixmap = new QPixmap();
if (getName().isEmpty()) {
pixmap->load(settingsCache->getCardBackPicturePath());
return pixmap;
@ -400,18 +406,33 @@ void CardInfo::updatePixmapCache()
emit pixmapUpdated();
}
CardSet* CardInfo::getPreferredSet()
{
SetList sortedSets = sets;
sortedSets.sortByKey();
return sortedSets.first();
}
int CardInfo::getPreferredMuId()
{
return muIds[getPreferredSet()->getShortName()];
}
QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfo *info)
{
xml.writeStartElement("card");
xml.writeTextElement("name", info->getName());
const SetList &sets = info->getSets();
QString tmpString;
QString tmpSet;
for (int i = 0; i < sets.size(); i++) {
xml.writeStartElement("set");
xml.writeAttribute("picURL", info->getPicURL(sets[i]->getShortName()));
xml.writeAttribute("picURLHq", info->getPicURLHq(sets[i]->getShortName()));
xml.writeAttribute("picURLSt", info->getPicURLSt(sets[i]->getShortName()));
xml.writeCharacters(sets[i]->getShortName());
tmpSet=sets[i]->getShortName();
xml.writeAttribute("muId", QString::number(info->getMuId(tmpSet)));
xml.writeCharacters(tmpSet);
xml.writeEndElement();
}
const QStringList &colors = info->getColors();
@ -442,12 +463,13 @@ CardDatabase::CardDatabase(QObject *parent)
connect(settingsCache, SIGNAL(cardDatabasePathChanged()), this, SLOT(loadCardDatabase()));
connect(settingsCache, SIGNAL(tokenDatabasePathChanged()), this, SLOT(loadTokenDatabase()));
connect(settingsCache, SIGNAL(picDownloadChanged()), this, SLOT(picDownloadChanged()));
connect(settingsCache, SIGNAL(picDownloadHqChanged()), this, SLOT(picDownloadHqChanged()));
loadCardDatabase();
loadTokenDatabase();
pictureLoaderThread = new QThread;
pictureLoader = new PictureLoader(settingsCache->getPicsPath(), settingsCache->getPicDownload());
pictureLoader = new PictureLoader(settingsCache->getPicsPath(), settingsCache->getPicDownload(), settingsCache->getPicDownloadHq());
pictureLoader->moveToThread(pictureLoaderThread);
connect(pictureLoader, SIGNAL(imageLoaded(CardInfo *, const QImage &)), this, SLOT(imageLoaded(CardInfo *, const QImage &)));
pictureLoaderThread->start(QThread::LowPriority);
@ -572,7 +594,7 @@ void CardDatabase::loadCardsFromXml(QXmlStreamReader &xml)
if (xml.name() == "card") {
QString name, manacost, type, pt, text;
QStringList colors;
QMap<QString, QString> picURLs, picURLsHq, picURLsSt;
QMap<QString, int> muids;
SetList sets;
int tableRow = 0;
int loyalty = 0;
@ -592,14 +614,12 @@ void CardDatabase::loadCardsFromXml(QXmlStreamReader &xml)
else if (xml.name() == "text")
text = xml.readElementText();
else if (xml.name() == "set") {
QString picURL = xml.attributes().value("picURL").toString();
QString picURLHq = xml.attributes().value("picURLHq").toString();
QString picURLSt = xml.attributes().value("picURLSt").toString();
QXmlStreamAttributes attrs = xml.attributes();
QString setName = xml.readElementText();
sets.append(getSet(setName));
picURLs.insert(setName, picURL);
picURLsHq.insert(setName, picURLHq);
picURLsSt.insert(setName, picURLSt);
if (attrs.hasAttribute("muId")) {
muids[setName] = attrs.value("muId").toString().toInt();
}
} else if (xml.name() == "color")
colors << xml.readElementText();
else if (xml.name() == "tablerow")
@ -611,7 +631,7 @@ void CardDatabase::loadCardsFromXml(QXmlStreamReader &xml)
else if (xml.name() == "token")
isToken = xml.readElementText().toInt();
}
cardHash.insert(name, new CardInfo(this, name, isToken, manacost, type, pt, text, colors, loyalty, cipt, tableRow, sets, picURLs, picURLsHq, picURLsSt));
cardHash.insert(name, new CardInfo(this, name, isToken, manacost, type, pt, text, colors, loyalty, cipt, tableRow, sets, muids));
}
}
}
@ -717,6 +737,16 @@ void CardDatabase::picDownloadChanged()
}
}
void CardDatabase::picDownloadHqChanged()
{
pictureLoader->setPicDownloadHq(settingsCache->getPicDownloadHq());
if (settingsCache->getPicDownloadHq()) {
QHashIterator<QString, CardInfo *> cardIterator(cardHash);
while (cardIterator.hasNext())
cardIterator.next().value()->clearPixmapCacheMiss();
}
}
bool CardDatabase::loadCardDatabase(const QString &path, bool tokens)
{
bool tempLoadSuccess = false;

View file

@ -68,13 +68,15 @@ private:
QNetworkAccessManager *networkManager;
QList<PictureToLoad> cardsToDownload;
PictureToLoad cardBeingDownloaded;
bool picDownload, downloadRunning, loadQueueRunning;
bool picDownload, picDownloadHq, downloadRunning, loadQueueRunning;
void startNextPicDownload();
QString getPicUrl(CardInfo* card);
public:
PictureLoader(const QString &__picsPath, bool _picDownload, QObject *parent = 0);
PictureLoader(const QString &__picsPath, bool _picDownload, bool _picDownloadHq, QObject *parent = 0);
~PictureLoader();
void setPicsPath(const QString &path);
void setPicDownload(bool _picDownload);
void setPicDownloadHq(bool _picDownloadHq);
void loadImage(CardInfo *card, bool stripped);
private slots:
void picDownloadFinished(QNetworkReply *reply);
@ -99,7 +101,7 @@ private:
QString text;
QStringList colors;
int loyalty;
QMap<QString, QString> picURLs, picURLsHq, picURLsSt;
QMap<QString, int> muIds;
bool cipt;
int tableRow;
QPixmap *pixmap;
@ -117,9 +119,7 @@ public:
bool _cipt = false,
int _tableRow = 0,
const SetList &_sets = SetList(),
const QStringMap &_picURLs = QStringMap(),
const QStringMap &_picURLsHq = QStringMap(),
const QStringMap &_picURLsSt = QStringMap());
QMap<QString, int> muids = QMap<QString, int>());
~CardInfo();
const QString &getName() const { return name; }
bool getIsToken() const { return isToken; }
@ -136,25 +136,21 @@ public:
void setText(const QString &_text) { text = _text; emit cardInfoChanged(this); }
void setColors(const QStringList &_colors) { colors = _colors; emit cardInfoChanged(this); }
const QStringList &getColors() const { return colors; }
QString getPicURL(const QString &set) const { return picURLs.value(set); }
QString getPicURLHq(const QString &set) const { return picURLsHq.value(set); }
QString getPicURLSt(const QString &set) const { return picURLsSt.value(set); }
QString getPicURL() const;
const QMap<QString, QString> &getPicURLs() const { return picURLs; }
int getMuId(const QString &set) const { return muIds.value(set); }
QString getMainCardType() const;
QString getCorrectedName() const;
int getTableRow() const { return tableRow; }
void setTableRow(int _tableRow) { tableRow = _tableRow; }
void setLoyalty(int _loyalty) { loyalty = _loyalty; emit cardInfoChanged(this); }
void setPicURL(const QString &_set, const QString &_picURL) { picURLs.insert(_set, _picURL); }
void setPicURLHq(const QString &_set, const QString &_picURL) { picURLsHq.insert(_set, _picURL); }
void setPicURLSt(const QString &_set, const QString &_picURL) { picURLsSt.insert(_set, _picURL); }
void setMuId(const QString &_set, const int &_muId) { muIds.insert(_set, _muId); }
void addToSet(CardSet *set);
QPixmap *loadPixmap();
QPixmap *getPixmap(QSize size);
void clearPixmapCache();
void clearPixmapCacheMiss();
void imageLoaded(const QImage &image);
CardSet *getPreferredSet();
int getPreferredMuId();
public slots:
void updatePixmapCache();
signals:
@ -169,7 +165,7 @@ protected:
QHash<QString, CardSet *> setHash;
bool loadSuccess;
CardInfo *noCard;
QThread *pictureLoaderThread;
PictureLoader *pictureLoader;
private:
@ -199,6 +195,7 @@ public slots:
private slots:
void imageLoaded(CardInfo *card, QImage image);
void picDownloadChanged();
void picDownloadHqChanged();
void picsPathChanged();
void loadCardDatabase();

View file

@ -1,4 +1,5 @@
#include "carddatabasemodel.h"
#include "filtertree.h"
CardDatabaseModel::CardDatabaseModel(CardDatabase *_db, QObject *parent)
: QAbstractListModel(parent), db(_db)
@ -109,6 +110,7 @@ CardDatabaseDisplayModel::CardDatabaseDisplayModel(QObject *parent)
: QSortFilterProxyModel(parent),
isToken(ShowAll)
{
filterTree = NULL;
setFilterCaseSensitivity(Qt::CaseInsensitive);
setSortCaseSensitivity(Qt::CaseInsensitive);
}
@ -116,7 +118,6 @@ CardDatabaseDisplayModel::CardDatabaseDisplayModel(QObject *parent)
bool CardDatabaseDisplayModel::filterAcceptsRow(int sourceRow, const QModelIndex & /*sourceParent*/) const
{
CardInfo const *info = static_cast<CardDatabaseModel *>(sourceModel())->getCard(sourceRow);
if (((isToken == ShowTrue) && !info->getIsToken()) || ((isToken == ShowFalse) && info->getIsToken()))
return false;
@ -144,6 +145,9 @@ bool CardDatabaseDisplayModel::filterAcceptsRow(int sourceRow, const QModelIndex
if (!cardTypes.contains(info->getMainCardType()))
return false;
if (filterTree != NULL)
return filterTree->acceptsCard(info);
return true;
}
@ -153,5 +157,22 @@ void CardDatabaseDisplayModel::clearSearch()
cardText.clear();
cardTypes.clear();
cardColors.clear();
if (filterTree != NULL)
filterTree->clear();
invalidateFilter();
}
void CardDatabaseDisplayModel::setFilterTree(FilterTree *filterTree)
{
if (this->filterTree != NULL)
disconnect(this->filterTree, 0, this, 0);
this->filterTree = filterTree;
connect(this->filterTree, SIGNAL(changed()), this, SLOT(filterTreeChanged()));
invalidate();
}
void CardDatabaseDisplayModel::filterTreeChanged()
{
invalidate();
}

View file

@ -7,6 +7,8 @@
#include <QSet>
#include "carddatabase.h"
class FilterTree;
class CardDatabaseModel : public QAbstractListModel {
Q_OBJECT
public:
@ -36,8 +38,10 @@ private:
FilterBool isToken;
QString cardNameBeginning, cardName, cardText;
QSet<QString> cardNameSet, cardTypes, cardColors;
FilterTree *filterTree;
public:
CardDatabaseDisplayModel(QObject *parent = 0);
void setFilterTree(FilterTree *filterTree);
void setIsToken(FilterBool _isToken) { isToken = _isToken; invalidate(); }
void setCardNameBeginning(const QString &_beginning) { cardNameBeginning = _beginning; invalidate(); }
void setCardName(const QString &_cardName) { cardName = _cardName; invalidate(); }
@ -48,6 +52,8 @@ public:
void clearSearch();
protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
private slots:
void filterTreeChanged();
};
#endif

View file

@ -0,0 +1,37 @@
#include "cardfilter.h"
const char *CardFilter::typeName(Type t)
{
switch (t) {
case TypeAnd:
return "and";
case TypeOr:
return "or";
case TypeAndNot:
return "and not";
case TypeOrNot:
return "or not";
default:
return "";
}
}
const char *CardFilter::attrName(Attr a)
{
switch (a) {
case AttrName:
return "name";
case AttrType:
return "type";
case AttrColor:
return "color";
case AttrText:
return "text";
case AttrSet:
return "set";
case AttrManaCost:
return "mana cost";
default:
return "";
}
}

View file

@ -0,0 +1,44 @@
#ifndef CARDFILTER_H
#define CARDFILTER_H
#include <QString>
class CardFilter {
public:
enum Type {
TypeAnd = 0,
TypeOr,
TypeAndNot,
TypeOrNot,
TypeEnd
};
/* if you add an atribute here you also need to
* add its string representation in attrName */
enum Attr {
AttrName = 0,
AttrType,
AttrColor,
AttrText,
AttrSet,
AttrManaCost,
AttrEnd
};
private:
enum Type t;
enum Attr a;
QString trm;
public:
CardFilter(QString term, Type type, Attr attr) : trm(term), t(type), a(attr) {};
Type type() const { return t; }
const QString &term() const { return trm; }
Attr attr() const { return a; }
static const char *typeName(Type t);
static const char *attrName(Attr a);
};
#endif

View file

@ -0,0 +1,59 @@
#include "cardframe.h"
#include "carditem.h"
#include "carddatabase.h"
#include "main.h"
#include "cardinfopicture.h"
#include "cardinfotext.h"
CardFrame::CardFrame(int width, int height,
const QString &cardName, QWidget *parent)
: QStackedWidget(parent)
, info(0)
, cardTextOnly(false)
{
setFrameStyle(QFrame::Panel | QFrame::Raised);
setMaximumWidth(width);
setMinimumWidth(width);
setMaximumHeight(height);
setMinimumHeight(height);
pic = new CardInfoPicture(width);
addWidget(pic);
text = new CardInfoText();
addWidget(text);
connect(pic, SIGNAL(hasPictureChanged()), this, SLOT(hasPictureChanged()));
setCard(db->getCard(cardName));
}
void CardFrame::setCard(CardInfo *card)
{
if (info)
disconnect(info, 0, this, 0);
info = card;
connect(info, SIGNAL(destroyed()), this, SLOT(clear()));
text->setCard(info);
pic->setCard(info);
}
void CardFrame::setCard(const QString &cardName)
{
setCard(db->getCard(cardName));
}
void CardFrame::setCard(AbstractCardItem *card)
{
setCard(card->getInfo());
}
void CardFrame::clear()
{
setCard(db->getCard());
}
void CardFrame::hasPictureChanged()
{
if (pic->hasPicture() && !cardTextOnly)
setCurrentWidget(pic);
else
setCurrentWidget(text);
}

View file

@ -0,0 +1,36 @@
#ifndef CARDFRAME_H
#define CARDFRAME_H
#include <QStackedWidget>
class AbstractCardItem;
class CardInfo;
class CardInfoPicture;
class CardInfoText;
class CardFrame : public QStackedWidget {
Q_OBJECT
private:
CardInfo *info;
CardInfoPicture *pic;
CardInfoText *text;
bool cardTextOnly;
public:
CardFrame(int width, int height, const QString &cardName = QString(),
QWidget *parent = 0);
void setCardTextOnly(bool status) { cardTextOnly = status; hasPictureChanged(); }
public slots:
void setCard(CardInfo *card);
void setCard(const QString &cardName);
void setCard(AbstractCardItem *card);
void clear();
private slots:
void hasPictureChanged();
void toggleCardTextOnly() { setCardTextOnly(!cardTextOnly); }
};
#endif

View file

@ -0,0 +1,53 @@
#include "cardinfopicture.h"
#include <QLabel>
#include "carditem.h"
#include "carddatabase.h"
#include "main.h"
CardInfoPicture::CardInfoPicture(int maximumWidth, QWidget *parent)
: QLabel(parent)
, info(0)
, noPicture(true)
{
setMaximumWidth(maximumWidth);
}
void CardInfoPicture::setNoPicture(bool status)
{
if (noPicture != status) {
noPicture = status;
emit hasPictureChanged();
}
}
void CardInfoPicture::setCard(CardInfo *card)
{
if (info)
disconnect(info, 0, this, 0);
info = card;
connect(info, SIGNAL(pixmapUpdated()), this, SLOT(updatePixmap()));
updatePixmap();
}
void CardInfoPicture::updatePixmap()
{
qreal aspectRatio = (qreal) CARD_HEIGHT / (qreal) CARD_WIDTH;
qreal pixmapWidth = this->width();
if (pixmapWidth == 0) {
setNoPicture(true);
return;
}
QPixmap *resizedPixmap = info->getPixmap(QSize(pixmapWidth, pixmapWidth * aspectRatio));
if (resizedPixmap) {
setNoPicture(false);
this->setPixmap(*resizedPixmap);
}
else {
setNoPicture(true);
this->setPixmap(*(db->getCard()->getPixmap(QSize(pixmapWidth, pixmapWidth * aspectRatio))));
}
}

View file

@ -0,0 +1,34 @@
#ifndef CARDINFOPICTURE_H
#define CARDINFOPICTURE_H
#include <QLabel>
class AbstractCardItem;
class CardInfo;
class CardInfoPicture : public QLabel {
Q_OBJECT
signals:
void hasPictureChanged();
private:
CardInfo *info;
bool noPicture;
public:
CardInfoPicture(int maximumWidth, QWidget *parent = 0);
bool hasPicture() const { return !noPicture; }
private:
void setNoPicture(bool status);
public slots:
void setCard(CardInfo *card);
private slots:
void updatePixmap();
};
#endif

View file

@ -0,0 +1,67 @@
#include "cardinfotext.h"
#include <QLabel>
#include <QTextEdit>
#include <QGridLayout>
#include "carditem.h"
#include "carddatabase.h"
#include "main.h"
CardInfoText::CardInfoText(QWidget *parent)
: QFrame(parent)
, info(0)
{
nameLabel1 = new QLabel;
nameLabel2 = new QLabel;
nameLabel2->setWordWrap(true);
manacostLabel1 = new QLabel;
manacostLabel2 = new QLabel;
manacostLabel2->setWordWrap(true);
cardtypeLabel1 = new QLabel;
cardtypeLabel2 = new QLabel;
cardtypeLabel2->setWordWrap(true);
powtoughLabel1 = new QLabel;
powtoughLabel2 = new QLabel;
loyaltyLabel1 = new QLabel;
loyaltyLabel2 = new QLabel;
textLabel = new QTextEdit();
textLabel->setReadOnly(true);
QGridLayout *grid = new QGridLayout(this);
int row = 0;
grid->addWidget(nameLabel1, row, 0);
grid->addWidget(nameLabel2, row++, 1);
grid->addWidget(manacostLabel1, row, 0);
grid->addWidget(manacostLabel2, row++, 1);
grid->addWidget(cardtypeLabel1, row, 0);
grid->addWidget(cardtypeLabel2, row++, 1);
grid->addWidget(powtoughLabel1, row, 0);
grid->addWidget(powtoughLabel2, row++, 1);
grid->addWidget(loyaltyLabel1, row, 0);
grid->addWidget(loyaltyLabel2, row++, 1);
grid->addWidget(textLabel, row, 0, -1, 2);
grid->setRowStretch(row, 1);
grid->setColumnStretch(1, 1);
retranslateUi();
}
void CardInfoText::setCard(CardInfo *card)
{
nameLabel2->setText(card->getName());
manacostLabel2->setText(card->getManaCost());
cardtypeLabel2->setText(card->getCardType());
powtoughLabel2->setText(card->getPowTough());
loyaltyLabel2->setText(card->getLoyalty() > 0 ? QString::number(card->getLoyalty()) : QString());
textLabel->setText(card->getText());
}
void CardInfoText::retranslateUi()
{
nameLabel1->setText(tr("Name:"));
manacostLabel1->setText(tr("Mana cost:"));
cardtypeLabel1->setText(tr("Card type:"));
powtoughLabel1->setText(tr("P / T:"));
loyaltyLabel1->setText(tr("Loyalty:"));
}

View file

@ -0,0 +1,31 @@
#ifndef CARDINFOTEXT_H
#define CARDINFOTEXT_H
#include <QFrame>
class QLabel;
class QTextEdit;
class CardInfo;
class CardInfoText : public QFrame {
Q_OBJECT
private:
QLabel *nameLabel1, *nameLabel2;
QLabel *manacostLabel1, *manacostLabel2;
QLabel *cardtypeLabel1, *cardtypeLabel2;
QLabel *powtoughLabel1, *powtoughLabel2;
QLabel *loyaltyLabel1, *loyaltyLabel2;
QTextEdit *textLabel;
CardInfo *info;
public:
CardInfoText(QWidget *parent = 0);
void retranslateUi();
public slots:
void setCard(CardInfo *card);
};
#endif

View file

@ -148,7 +148,7 @@ QString CardZone::getTranslatedName(bool hisOwn, GrammaticalCase gc) const
return QString();
}
void CardZone::mouseDoubleClickEvent(QGraphicsSceneMouseEvent */*event*/)
void CardZone::mouseDoubleClickEvent(QGraphicsSceneMouseEvent * /*event*/)
{
if (doubleClickAction)
doubleClickAction->trigger();

View file

@ -13,7 +13,7 @@ QRectF GeneralCounter::boundingRect() const
return QRectF(0, 0, radius * 2, radius * 2);
}
void GeneralCounter::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/)
void GeneralCounter::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
{
QRectF mapRect = painter->combinedTransform().mapRect(boundingRect());
int translatedHeight = mapRect.size().height();

View file

@ -169,8 +169,7 @@ Qt::ItemFlags DeckListModel::flags(const QModelIndex &index) const
return 0;
Qt::ItemFlags result = Qt::ItemIsEnabled;
if (getNode<DecklistModelCardNode *>(index))
result |= Qt::ItemIsSelectable;
result |= Qt::ItemIsSelectable;
return result;
}
@ -236,6 +235,38 @@ InnerDecklistNode *DeckListModel::createNodeIfNeeded(const QString &name, InnerD
return newNode;
}
DecklistModelCardNode *DeckListModel::findCardNode(const QString &cardName, const QString &zoneName) const
{
InnerDecklistNode *zoneNode, *typeNode;
CardInfo *info;
QString cardType;
zoneNode = dynamic_cast<InnerDecklistNode *>(root->findChild(zoneName));
if(!zoneNode)
return NULL;
info = db->getCard(cardName);
if(!info)
return NULL;
cardType = info->getMainCardType();
typeNode = dynamic_cast<InnerDecklistNode *>(zoneNode->findChild(cardType));
if(!typeNode)
return NULL;
return dynamic_cast<DecklistModelCardNode *>(typeNode->findChild(cardName));
}
QModelIndex DeckListModel::findCard(const QString &cardName, const QString &zoneName) const
{
DecklistModelCardNode *cardNode;
cardNode = findCardNode(cardName, zoneName);
if(!cardNode)
return QModelIndex();
return nodeToIndex(cardNode);
}
QModelIndex DeckListModel::addCard(const QString &cardName, const QString &zoneName)
{
InnerDecklistNode *zoneNode = createNodeIfNeeded(zoneName, root);

View file

@ -19,7 +19,7 @@ public:
int getNumber() const { return dataNode->getNumber(); }
void setNumber(int _number) { dataNode->setNumber(_number); }
float getPrice() const { return dataNode->getPrice(); }
void setPrice(float _price) { dataNode->setPrice(_price); }
void setPrice(const float _price) { dataNode->setPrice(_price); }
QString getName() const { return dataNode->getName(); }
void setName(const QString &_name) { dataNode->setName(_name); }
DecklistCardNode *getDataNode() const { return dataNode; }
@ -45,6 +45,7 @@ public:
Qt::ItemFlags flags(const QModelIndex &index) const;
bool setData(const QModelIndex &index, const QVariant &value, int role);
bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
QModelIndex findCard(const QString &cardName, const QString &zoneName) const;
QModelIndex addCard(const QString &cardName, const QString &zoneName);
void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);
void cleanList();
@ -58,6 +59,7 @@ private:
Qt::SortOrder lastKnownOrder;
InnerDecklistNode *createNodeIfNeeded(const QString &name, InnerDecklistNode *parent);
QModelIndex nodeToIndex(AbstractDecklistNode *node) const;
DecklistModelCardNode *findCardNode(const QString &cardName, const QString &zoneName) const;
void emitRecursiveUpdates(const QModelIndex &index);
void sortHelper(InnerDecklistNode *node, Qt::SortOrder order);

View file

@ -27,7 +27,7 @@ GeneralSettingsPage::GeneralSettingsPage()
{
languageLabel = new QLabel;
languageBox = new QComboBox;
QString setLanguage = settingsCache->getLang();
QStringList qmFiles = findQmFiles();
for (int i = 0; i < qmFiles.size(); i++) {
@ -36,27 +36,32 @@ GeneralSettingsPage::GeneralSettingsPage()
if ((qmFiles[i] == setLanguage) || (setLanguage.isEmpty() && langName == tr("English")))
languageBox->setCurrentIndex(i);
}
picDownloadCheckBox = new QCheckBox;
picDownloadCheckBox->setChecked(settingsCache->getPicDownload());
picDownloadHqCheckBox = new QCheckBox;
picDownloadHqCheckBox->setChecked(settingsCache->getPicDownloadHq());
connect(languageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(languageBoxChanged(int)));
connect(picDownloadCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setPicDownload(int)));
connect(picDownloadHqCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setPicDownloadHq(int)));
QGridLayout *personalGrid = new QGridLayout;
personalGrid->addWidget(languageLabel, 0, 0);
personalGrid->addWidget(languageBox, 0, 1);
personalGrid->addWidget(picDownloadCheckBox, 1, 0, 1, 2);
personalGrid->addWidget(picDownloadHqCheckBox, 2, 0, 1, 2);
personalGroupBox = new QGroupBox;
personalGroupBox->setLayout(personalGrid);
deckPathLabel = new QLabel;
deckPathEdit = new QLineEdit(settingsCache->getDeckPath());
deckPathEdit->setReadOnly(true);
QPushButton *deckPathButton = new QPushButton("...");
connect(deckPathButton, SIGNAL(clicked()), this, SLOT(deckPathButtonClicked()));
replaysPathLabel = new QLabel;
replaysPathEdit = new QLineEdit(settingsCache->getReplaysPath());
replaysPathEdit->setReadOnly(true);
@ -183,6 +188,7 @@ void GeneralSettingsPage::retranslateUi()
personalGroupBox->setTitle(tr("Personal settings"));
languageLabel->setText(tr("Language:"));
picDownloadCheckBox->setText(tr("Download card pictures on the fly"));
picDownloadHqCheckBox->setText(tr("Download high-quality card pictures"));
pathsGroupBox->setTitle(tr("Paths"));
deckPathLabel->setText(tr("Decks directory:"));
replaysPathLabel->setText(tr("Replays directory:"));

View file

@ -40,6 +40,7 @@ private:
QGroupBox *personalGroupBox, *pathsGroupBox;
QComboBox *languageBox;
QCheckBox *picDownloadCheckBox;
QCheckBox *picDownloadHqCheckBox;
QLabel *languageLabel, *deckPathLabel, *replaysPathLabel, *picsPathLabel, *cardDatabasePathLabel, *tokenDatabasePathLabel;
};

View file

@ -0,0 +1,84 @@
#include "filterbuilder.h"
#include <QHBoxLayout>
#include <QComboBox>
#include <QPushButton>
#include <QLineEdit>
#include "cardfilter.h"
FilterBuilder::FilterBuilder(QWidget *parent)
: QFrame(parent)
{
int i;
QVBoxLayout *layout = new QVBoxLayout;
QHBoxLayout *addFilter = new QHBoxLayout;
filterCombo = new QComboBox;
for (i = 0; i < CardFilter::AttrEnd; i++)
filterCombo->addItem(
tr(CardFilter::attrName(static_cast<CardFilter::Attr>(i))),
QVariant(i)
);
typeCombo = new QComboBox;
for (i = 0; i < CardFilter::TypeEnd; i++)
typeCombo->addItem(
tr(CardFilter::typeName(static_cast<CardFilter::Type>(i))),
QVariant(i)
);
QPushButton *ok = new QPushButton("+");
ok->setMaximumSize(20, 20);
addFilter->addWidget(ok);
addFilter->addWidget(typeCombo);
addFilter->addWidget(filterCombo, Qt::AlignLeft);
edit = new QLineEdit;
edit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
layout->addLayout(addFilter);
layout->addWidget(edit);
setFrameStyle(QFrame::Panel | QFrame::Raised);
layout->setAlignment(Qt::AlignTop);
setLayout(layout);
connect(edit, SIGNAL(returnPressed()), this, SLOT(emit_add()));
connect(ok, SIGNAL(released()), this, SLOT(emit_add()));
connect(filterCombo, SIGNAL(currentIndexChanged(int)), edit, SLOT(clear()));
fltr = NULL;
}
FilterBuilder::~FilterBuilder()
{
destroyFilter();
}
void FilterBuilder::destroyFilter()
{
if (fltr)
delete fltr;
}
static int comboCurrentIntData(const QComboBox *combo)
{
return combo->itemData(combo->currentIndex()).toInt();
}
void FilterBuilder::emit_add()
{
QString txt;
txt = edit->text();
if (txt.length() < 1)
return;
destroyFilter();
fltr = new CardFilter(txt,
static_cast<CardFilter::Type>(comboCurrentIntData(typeCombo)),
static_cast<CardFilter::Attr>(comboCurrentIntData(filterCombo)));
emit add(fltr);
edit->clear();
}

View file

@ -0,0 +1,35 @@
#ifndef FILTERBUILDER_H
#define FILTERBUILDER_H
#include <QFrame>
class QCheckBox;
class QComboBox;
class QLineEdit;
class CardFilter;
class FilterBuilder : public QFrame {
Q_OBJECT
private:
QComboBox *typeCombo;
QComboBox *filterCombo;
QLineEdit *edit;
CardFilter *fltr;
void destroyFilter();
public:
FilterBuilder(QWidget *parent = 0);
~FilterBuilder();
signals:
void add(const CardFilter *f);
public slots:
private slots:
void emit_add();
protected:
};
#endif

View file

@ -0,0 +1,339 @@
#include "filtertree.h"
#include "cardfilter.h"
#include "carddatabase.h"
#include <QList>
template <class T>
FilterTreeNode *FilterTreeBranch<T>::nodeAt(int i) const
{
return ((childNodes.size() > i)? childNodes.at(i) : NULL);
}
template <class T>
void FilterTreeBranch<T>::deleteAt(int i)
{
preRemoveChild(this, i);
delete childNodes.takeAt(i);
postRemoveChild(this, i);
nodeChanged();
}
template <class T>
int FilterTreeBranch<T>::childIndex(const FilterTreeNode *node) const
{
FilterTreeNode *unconst;
T downcasted;
/* to do the dynamic cast to T we will lose const'ness, but we can
* trust QList::indexOf */
unconst = (FilterTreeNode *) node;
downcasted = dynamic_cast<T>(unconst);
if (downcasted == NULL)
return -1;
return childNodes.indexOf(downcasted);
}
template <class T>
FilterTreeBranch<T>::~FilterTreeBranch()
{
while (!childNodes.isEmpty())
delete childNodes.takeFirst();
}
const FilterItemList *LogicMap::findTypeList(CardFilter::Type type) const
{
QList<FilterItemList *>::const_iterator i;
for (i = childNodes.constBegin(); i != childNodes.constEnd(); i++)
if ((*i)->type == type)
return *i;
return NULL;
}
FilterItemList *LogicMap::typeList(CardFilter::Type type)
{
QList<FilterItemList *>::iterator i;
int count;
count = 0;
for (i = childNodes.begin(); i != childNodes.end(); i++) {
if ((*i)->type == type)
break;
count++;
}
if (i == childNodes.end()) {
preInsertChild(this, count);
i = childNodes.insert(i, new FilterItemList(type, this));
postInsertChild(this, count);
nodeChanged();
}
return *i;
}
FilterTreeNode *LogicMap::parent() const
{
return p;
}
int FilterItemList::termIndex(const QString &term) const
{
int i;
for (i = 0; i < childNodes.count(); i++)
if ((childNodes.at(i))->term == term)
return i;
return -1;
}
FilterTreeNode *FilterItemList::termNode(const QString &term)
{
int i, count;
FilterItem *fi;
i = termIndex(term);
if (i < 0) {
fi = new FilterItem(term, this);
count = childNodes.count();
preInsertChild(this, count);
childNodes.append(fi);
postInsertChild(this, count);
nodeChanged();
return fi;
}
return childNodes.at(i);
}
bool FilterItemList::testTypeAnd(const CardInfo *info, CardFilter::Attr attr) const
{
QList<FilterItem *>::const_iterator i;
for (i = childNodes.constBegin(); i != childNodes.constEnd(); i++) {
if (!(*i)->isEnabled())
continue;
if (!(*i)->acceptCardAttr(info, attr))
return false;
}
return true;
}
bool FilterItemList::testTypeAndNot(const CardInfo *info, CardFilter::Attr attr) const
{
// if any one in the list is true, return false
return !testTypeOr(info, attr);
}
bool FilterItemList::testTypeOr(const CardInfo *info, CardFilter::Attr attr) const
{
QList<FilterItem *>::const_iterator i;
for (i = childNodes.constBegin(); i != childNodes.constEnd(); i++) {
if (!(*i)->isEnabled())
continue;
if ((*i)->acceptCardAttr(info, attr))
return true;
}
return false;
}
bool FilterItemList::testTypeOrNot(const CardInfo *info, CardFilter::Attr attr) const
{
// if any one in the list is false, return true
return !testTypeAnd(info, attr);
}
bool FilterItem::acceptName(const CardInfo *info) const
{
return info->getName().contains(term, Qt::CaseInsensitive);
}
bool FilterItem::acceptType(const CardInfo *info) const
{
return info->getCardType().contains(term, Qt::CaseInsensitive);
}
bool FilterItem::acceptColor(const CardInfo *info) const
{
QStringList::const_iterator i;
bool status;
status = false;
for (i = info->getColors().constBegin(); i != info->getColors().constEnd(); i++)
if ((*i).contains(term, Qt::CaseInsensitive)) {
status = true;
break;
}
return status;
}
bool FilterItem::acceptText(const CardInfo *info) const
{
return info->getText().contains(term, Qt::CaseInsensitive);
}
bool FilterItem::acceptSet(const CardInfo *info) const
{
SetList::const_iterator i;
bool status;
status = false;
for (i = info->getSets().constBegin(); i != info->getSets().constEnd(); i++)
if ((*i)->getShortName() == term
|| (*i)->getLongName().contains(term, Qt::CaseInsensitive)) {
status = true;
break;
}
return status;
}
bool FilterItem::acceptManaCost(const CardInfo *info) const
{
return (info->getManaCost() == term);
}
bool FilterItem::acceptCardAttr(const CardInfo *info, CardFilter::Attr attr) const
{
bool status;
switch (attr) {
case CardFilter::AttrName:
status = acceptName(info);
break;
case CardFilter::AttrType:
status = acceptType(info);
break;
case CardFilter::AttrColor:
status = acceptColor(info);
break;
case CardFilter::AttrText:
status = acceptText(info);
break;
case CardFilter::AttrSet:
status = acceptSet(info);
break;
case CardFilter::AttrManaCost:
status = acceptManaCost(info);
break;
default:
status = true; /* ignore this attribute */
}
return status;
}
/* need to define these here to make QT happy, otherwise
* moc doesnt find some of the FilterTreeBranch symbols.
*/
FilterTree::FilterTree() {}
FilterTree::~FilterTree() {}
LogicMap *FilterTree::attrLogicMap(CardFilter::Attr attr)
{
QList<LogicMap *>::iterator i;
int count;
count = 0;
for (i = childNodes.begin(); i != childNodes.end(); i++) {
if ((*i)->attr == attr)
break;
count++;
}
if (i == childNodes.end()) {
preInsertChild(this, count);
i = childNodes.insert(i, new LogicMap(attr, this));
postInsertChild(this, count);
nodeChanged();
}
return *i;
}
FilterItemList *FilterTree::attrTypeList(CardFilter::Attr attr,
CardFilter::Type type)
{
return attrLogicMap(attr)->typeList(type);
}
int FilterTree::findTermIndex(CardFilter::Attr attr, CardFilter::Type type,
const QString &term)
{
return attrTypeList(attr, type)->termIndex(term);
}
int FilterTree::findTermIndex(const CardFilter *f)
{
return findTermIndex(f->attr(), f->type(), f->term());
}
FilterTreeNode *FilterTree::termNode(CardFilter::Attr attr, CardFilter::Type type,
const QString &term)
{
return attrTypeList(attr, type)->termNode(term);
}
FilterTreeNode *FilterTree::termNode(const CardFilter *f)
{
return termNode(f->attr(), f->type(), f->term());
}
FilterTreeNode *FilterTree::attrTypeNode(CardFilter::Attr attr,
CardFilter::Type type)
{
return attrTypeList(attr, type);
}
bool FilterTree::testAttr(const CardInfo *info, const LogicMap *lm) const
{
const FilterItemList *fil;
bool status;
status = true;
fil = lm->findTypeList(CardFilter::TypeAnd);
if (fil != NULL && fil->isEnabled() && !fil->testTypeAnd(info, lm->attr))
return false;
fil = lm->findTypeList(CardFilter::TypeAndNot);
if (fil != NULL && fil->isEnabled() && !fil->testTypeAndNot(info, lm->attr))
return false;
fil = lm->findTypeList(CardFilter::TypeOr);
if (fil != NULL && fil->isEnabled()) {
status = false;
// if this is true we can return because it is OR'd with the OrNot list
if (fil->testTypeOr(info, lm->attr))
return true;
}
fil = lm->findTypeList(CardFilter::TypeOrNot);
if (fil != NULL && fil->isEnabled() && fil->testTypeOrNot(info, lm->attr))
return true;
return status;
}
bool FilterTree::acceptsCard(const CardInfo *info) const
{
QList<LogicMap *>::const_iterator i;
for (i = childNodes.constBegin(); i != childNodes.constEnd(); i++)
if ((*i)->isEnabled() && !testAttr(info, *i))
return false;
return true;
}
void FilterTree::clear()
{
while(childCount() > 0)
deleteAt(0);
}

163
cockatrice/src/filtertree.h Normal file
View file

@ -0,0 +1,163 @@
#ifndef FILTERTREE_H
#define FILTERTREE_H
#include <QList>
#include <QMap>
#include <QObject>
#include "cardfilter.h"
class CardInfo;
class FilterTreeNode {
private:
bool enabled;
public:
FilterTreeNode() : enabled(true) {}
virtual bool isEnabled() const { return enabled; }
virtual void enable() { enabled = true; nodeChanged(); }
virtual void disable() { enabled = false; nodeChanged(); }
virtual FilterTreeNode *parent() const { return NULL; }
virtual FilterTreeNode *nodeAt(int i) const { return NULL; }
virtual void deleteAt(int i) {}
virtual int childCount() const { return 0; }
virtual int childIndex(const FilterTreeNode *node) const { return -1; }
virtual int index() const { return (parent() != NULL)? parent()->childIndex(this) : -1; }
virtual QString text() const { return QString(textCStr()); }
virtual bool isLeaf() const { return false; }
virtual const char *textCStr() const { return ""; }
virtual void nodeChanged() const {
if (parent() != NULL) parent()->nodeChanged();
}
virtual void preInsertChild(const FilterTreeNode *p, int i) const {
if (parent() != NULL) parent()->preInsertChild(p, i);
}
virtual void postInsertChild(const FilterTreeNode *p, int i) const {
if (parent() != NULL) parent()->postInsertChild(p, i);
}
virtual void preRemoveChild(const FilterTreeNode *p, int i) const {
if (parent() != NULL) parent()->preRemoveChild(p, i);
}
virtual void postRemoveChild(const FilterTreeNode *p, int i) const {
if (parent() != NULL) parent()->postRemoveChild(p, i);
}
};
template <class T>
class FilterTreeBranch : public FilterTreeNode {
protected:
QList<T> childNodes;
public:
~FilterTreeBranch();
FilterTreeNode *nodeAt(int i) const;
void deleteAt(int i);
int childCount() const { return childNodes.size(); }
int childIndex(const FilterTreeNode *node) const;
};
class FilterItemList;
class FilterTree;
class LogicMap : public FilterTreeBranch<FilterItemList *> {
private:
FilterTree *const p;
public:
const CardFilter::Attr attr;
LogicMap(CardFilter::Attr a, FilterTree *parent)
: attr(a), p(parent) {}
const FilterItemList *findTypeList(CardFilter::Type type) const;
FilterItemList *typeList(CardFilter::Type type);
FilterTreeNode *parent() const;
const char* textCStr() const { return CardFilter::attrName(attr); }
};
class FilterItem;
class FilterItemList : public FilterTreeBranch<FilterItem *> {
private:
LogicMap *const p;
public:
const CardFilter::Type type;
FilterItemList(CardFilter::Type t, LogicMap *parent)
: type(t), p(parent) {}
CardFilter::Attr attr() const { return p->attr; }
FilterTreeNode *parent() const { return p; }
int termIndex(const QString &term) const;
FilterTreeNode *termNode(const QString &term);
const char *textCStr() const { return CardFilter::typeName(type); }
bool testTypeAnd(const CardInfo *info, CardFilter::Attr attr) const;
bool testTypeAndNot(const CardInfo *info, CardFilter::Attr attr) const;
bool testTypeOr(const CardInfo *info, CardFilter::Attr attr) const;
bool testTypeOrNot(const CardInfo *info, CardFilter::Attr attr) const;
};
class FilterItem : public FilterTreeNode {
private:
FilterItemList *const p;
public:
const QString term;
FilterItem(QString trm, FilterItemList *parent)
: p(parent), term(trm) {}
CardFilter::Attr attr() const { return p->attr(); }
CardFilter::Type type() const { return p->type; }
FilterTreeNode *parent() const { return p; }
QString text() const { return term; }
const char *textCStr() const { return term.toStdString().c_str(); }
bool isLeaf() const { return true; }
bool acceptName(const CardInfo *info) const;
bool acceptType(const CardInfo *info) const;
bool acceptColor(const CardInfo *info) const;
bool acceptText(const CardInfo *info) const;
bool acceptSet(const CardInfo *info) const;
bool acceptManaCost(const CardInfo *info) const;
bool acceptCardAttr(const CardInfo *info, CardFilter::Attr attr) const;
};
class FilterTree : public QObject, public FilterTreeBranch<LogicMap *> {
Q_OBJECT
signals:
void preInsertRow(const FilterTreeNode *parent, int i) const;
void postInsertRow(const FilterTreeNode *parent, int i) const;
void preRemoveRow(const FilterTreeNode *parent, int i) const;
void postRemoveRow(const FilterTreeNode *parent, int i) const;
void changed() const;
private:
LogicMap *attrLogicMap(CardFilter::Attr attr);
FilterItemList *attrTypeList(CardFilter::Attr attr,
CardFilter::Type type);
bool testAttr(const CardInfo *info, const LogicMap *lm) const;
void nodeChanged() const { emit changed(); }
void preInsertChild(const FilterTreeNode *p, int i) const { emit preInsertRow(p, i); }
void postInsertChild(const FilterTreeNode *p, int i) const { emit postInsertRow(p, i); }
void preRemoveChild(const FilterTreeNode *p, int i) const { emit preRemoveRow(p, i); }
void postRemoveChild(const FilterTreeNode *p, int i) const { emit postRemoveRow(p, i); }
public:
FilterTree();
~FilterTree();
int findTermIndex(CardFilter::Attr attr, CardFilter::Type type,
const QString &term);
int findTermIndex(const CardFilter *f);
FilterTreeNode *termNode(CardFilter::Attr attr, CardFilter::Type type,
const QString &term);
FilterTreeNode *termNode(const CardFilter *f);
FilterTreeNode *attrTypeNode(CardFilter::Attr attr,
CardFilter::Type type);
const char *textCStr() { return "root"; }
int index() const { return 0; }
bool acceptsCard(const CardInfo *info) const;
void clear();
};
#endif

View file

@ -0,0 +1,272 @@
#include <QFont>
#include "filtertreemodel.h"
#include "filtertree.h"
#include "cardfilter.h"
FilterTreeModel::FilterTreeModel(QObject *parent)
: QAbstractItemModel(parent)
{
fTree = new FilterTree;
connect(fTree,
SIGNAL(preInsertRow(const FilterTreeNode *, int)),
this, SLOT(proxyBeginInsertRow(const FilterTreeNode *, int)));
connect(fTree,
SIGNAL(postInsertRow(const FilterTreeNode *, int)),
this, SLOT(proxyEndInsertRow(const FilterTreeNode *, int)));
connect(fTree,
SIGNAL(preRemoveRow(const FilterTreeNode *, int)),
this, SLOT(proxyBeginRemoveRow(const FilterTreeNode *, int)));
connect(fTree,
SIGNAL(postRemoveRow(const FilterTreeNode *, int)),
this, SLOT(proxyEndRemoveRow(const FilterTreeNode *, int)));
}
FilterTreeModel::~FilterTreeModel()
{
delete fTree;
}
void FilterTreeModel::proxyBeginInsertRow(const FilterTreeNode *node, int i)
{
int idx;
idx = node->index();
if (idx >= 0)
beginInsertRows(createIndex(idx, 0, (void *) node), i, i);
}
void FilterTreeModel::proxyEndInsertRow(const FilterTreeNode *node, int)
{
int idx;
idx = node->index();
if (idx >= 0)
endInsertRows();
}
void FilterTreeModel::proxyBeginRemoveRow(const FilterTreeNode *node, int i)
{
int idx;
idx = node->index();
if (idx >= 0)
beginRemoveRows(createIndex(idx, 0, (void *) node), i, i);
}
void FilterTreeModel::proxyEndRemoveRow(const FilterTreeNode *node, int)
{
int idx;
idx = node->index();
if (idx >= 0)
endRemoveRows();
}
FilterTreeNode *FilterTreeModel::indexToNode(const QModelIndex &idx) const
{
void *ip;
FilterTreeNode *node;
if (!idx.isValid())
return fTree;
ip = idx.internalPointer();
if (ip == NULL)
return fTree;
node = static_cast<FilterTreeNode *>(ip);
return node;
}
void FilterTreeModel::addFilter(const CardFilter *f)
{
emit layoutAboutToBeChanged();
fTree->termNode(f);
emit layoutChanged();
}
int FilterTreeModel::rowCount(const QModelIndex &parent) const
{
const FilterTreeNode *node;
int result;
if (parent.column() > 0)
return 0;
node = indexToNode(parent);
if (node)
result = node->childCount();
else
result = 0;
return result;
}
int FilterTreeModel::columnCount(const QModelIndex &/*parent*/) const
{
return 1;
}
QVariant FilterTreeModel::data(const QModelIndex &index, int role) const
{
const FilterTreeNode *node;
if (!index.isValid())
return QVariant();
if (index.column() >= columnCount())
return QVariant();
node = indexToNode(index);
if (node == NULL)
return QVariant();
switch (role) {
case Qt::FontRole:
if (!node->isLeaf()) {
QFont f;
f.setBold(true);
return f;
}
break;
case Qt::DisplayRole:
case Qt::EditRole:
case Qt::ToolTipRole:
case Qt::StatusTipRole:
case Qt::WhatsThisRole:
if(!node->isLeaf())
return tr(node->textCStr());
else
return node->text();
case Qt::CheckStateRole:
if (node->isEnabled())
return Qt::Checked;
else
return Qt::Unchecked;
default:
return QVariant();
}
return QVariant();
}
bool FilterTreeModel::setData(const QModelIndex &index,
const QVariant &value, int role)
{
FilterTreeNode *node;
if (!index.isValid())
return false;
if (index.column() >= columnCount())
return false;
if (role != Qt::CheckStateRole )
return false;
node = indexToNode(index);
if (node == NULL || node == fTree)
return false;
Qt::CheckState state = static_cast<Qt::CheckState>(value.toInt());
if (state == Qt::Checked)
node->enable();
else
node->disable();
emit dataChanged(index, index);
return true;
}
Qt::ItemFlags FilterTreeModel::flags(const QModelIndex &index) const
{
const FilterTreeNode *node;
Qt::ItemFlags result;
if (!index.isValid())
return 0;
node = indexToNode(index);
if (node == NULL)
return 0;
result = Qt::ItemIsEnabled;
if (node == fTree)
return result;
result |= Qt::ItemIsSelectable;
result |= Qt::ItemIsUserCheckable;
return result;
}
QModelIndex FilterTreeModel::nodeIndex(const FilterTreeNode *node, int row, int column) const
{
FilterTreeNode *child;
if (column > 0 || row >= node->childCount())
return QModelIndex();
child = node->nodeAt(row);
return createIndex(row, column, child);
}
QModelIndex FilterTreeModel::index(int row, int column,
const QModelIndex &parent) const
{
const FilterTreeNode *node;
if (!hasIndex(row, column, parent))
return QModelIndex();
node = indexToNode(parent);
if (node == NULL)
return QModelIndex();
return nodeIndex(node, row, column);
}
QModelIndex FilterTreeModel::parent(const QModelIndex &ind) const
{
const FilterTreeNode *node;
FilterTreeNode *parent;
int row;
QModelIndex idx;
if (!ind.isValid())
return QModelIndex();
node = indexToNode(ind);
if (node == NULL || node == fTree)
return QModelIndex();
parent = node->parent();
if (parent) {
row = parent->index();
if (row < 0)
return QModelIndex();
idx = createIndex(row, 0, parent);
return idx;
}
return QModelIndex();
}
bool FilterTreeModel::removeRows(int row, int count, const QModelIndex & parent)
{
FilterTreeNode *node;
int i, last;
last = row+count-1;
if (!parent.isValid() || count < 1 || row < 0)
return false;
node = indexToNode(parent);
if (node == NULL || last >= node->childCount())
return false;
for (i = 0; i < count; i++)
node->deleteAt(row);
if (node != fTree && node->childCount() < 1)
return removeRow(parent.row(), parent.parent());
return true;
}

View file

@ -0,0 +1,44 @@
#ifndef FILTERTREEMODEL_H
#define FILTERTREEMODEL_H
#include <QAbstractItemModel>
class FilterTree;
class CardFilter;
class FilterTreeNode;
class FilterTreeModel : public QAbstractItemModel {
Q_OBJECT
private:
FilterTree *fTree;
public slots:
void addFilter(const CardFilter *f);
private slots:
void proxyBeginInsertRow(const FilterTreeNode *, int);
void proxyEndInsertRow(const FilterTreeNode *, int);
void proxyBeginRemoveRow(const FilterTreeNode *, int);
void proxyEndRemoveRow(const FilterTreeNode *, int);
private:
FilterTreeNode *indexToNode(const QModelIndex &idx) const;
QModelIndex nodeIndex(const FilterTreeNode *node, int row, int column) const;
public:
FilterTreeModel(QObject *parent = 0);
~FilterTreeModel();
FilterTree *filterTree() const { return fTree; }
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &/*parent*/ = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role) const;
bool setData(const QModelIndex &index, const QVariant &value,
int role = Qt::EditRole);
Qt::ItemFlags flags(const QModelIndex &index) const;
QModelIndex parent(const QModelIndex &ind) const;
QModelIndex index(int row, int column,
const QModelIndex &parent) const;
bool removeRows(int row, int count, const QModelIndex & parent);
};
#endif

View file

@ -180,9 +180,9 @@ bool GamesProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &/*sourc
if (!gameTypeFilter.isEmpty() && gameTypes.intersect(gameTypeFilter).isEmpty())
return false;
if ((maxPlayersFilterMin != -1) && (game.max_players() < maxPlayersFilterMin))
if ((maxPlayersFilterMin != -1) && ((int)game.max_players() < maxPlayersFilterMin))
return false;
if ((maxPlayersFilterMax != -1) && (game.max_players() > maxPlayersFilterMax))
if ((maxPlayersFilterMax != -1) && ((int)game.max_players() > maxPlayersFilterMax))
return false;
return true;

View file

@ -75,7 +75,7 @@ QRectF HandZone::boundingRect() const
return QRectF(0, 0, 100, zoneHeight);
}
void HandZone::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/)
void HandZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
{
if (bgPixmap.isNull())
painter->fillRect(boundingRect(), Qt::darkGreen);

View file

@ -0,0 +1,65 @@
#include "keysignals.h"
#include <QKeyEvent>
bool KeySignals::eventFilter(QObject * /*object*/, QEvent *event) {
QKeyEvent *kevent;
if(event->type() != QEvent::KeyPress)
return false;
kevent = static_cast<QKeyEvent *>(event);
switch(kevent->key()) {
case Qt::Key_Return:
case Qt::Key_Enter:
if (kevent->modifiers().testFlag(Qt::AltModifier)
&& kevent->modifiers().testFlag(Qt::ControlModifier) )
emit onCtrlAltEnter();
else if (kevent->modifiers() & Qt::ControlModifier)
emit onCtrlEnter();
else
emit onEnter();
break;
case Qt::Key_Right:
emit onRight();
break;
case Qt::Key_Left:
emit onLeft();
break;
case Qt::Key_Delete:
case Qt::Key_Backspace:
emit onDelete();
break;
case Qt::Key_Minus:
if (kevent->modifiers().testFlag(Qt::AltModifier)
&& kevent->modifiers().testFlag(Qt::ControlModifier) )
emit onCtrlAltMinus();
break;
case Qt::Key_Equal:
if (kevent->modifiers().testFlag(Qt::AltModifier)
&& kevent->modifiers().testFlag(Qt::ControlModifier) )
emit onCtrlAltEqual();
break;
case Qt::Key_BracketLeft:
if (kevent->modifiers().testFlag(Qt::AltModifier)
&& kevent->modifiers().testFlag(Qt::ControlModifier) )
emit onCtrlAltLBracket();
break;
case Qt::Key_BracketRight:
if (kevent->modifiers().testFlag(Qt::AltModifier)
&& kevent->modifiers().testFlag(Qt::ControlModifier) )
emit onCtrlAltRBracket();
break;
default:
return false;
}
return false;
}

View file

@ -0,0 +1,26 @@
#ifndef KEYSIGNALS_H
#define KEYSIGNALS_H
#include <QObject>
#include <QEvent>
class KeySignals : public QObject {
Q_OBJECT
signals:
void onEnter();
void onCtrlEnter();
void onCtrlAltEnter();
void onLeft();
void onRight();
void onDelete();
void onCtrlAltMinus();
void onCtrlAltEqual();
void onCtrlAltLBracket();
void onCtrlAltRBracket();
protected:
virtual bool eventFilter(QObject *, QEvent *event);
};
#endif

View file

@ -19,6 +19,8 @@
***************************************************************************/
#include <QApplication>
#include <QFile>
#include <QTextStream>
#include <QTextCodec>
#include <QtPlugin>
#include <QTranslator>
@ -28,7 +30,6 @@
#include <QIcon>
#include <QDir>
#include <QDesktopServices>
#include <stdio.h>
#include "main.h"
#include "window_main.h"
@ -56,11 +57,11 @@ QString translationPath = QString();
void myMessageOutput(QtMsgType /*type*/, const char *msg)
{
static FILE *f = NULL;
if (!f)
f = fopen("qdebug.txt", "w");
fprintf(f, "%s\n", msg);
fflush(f);
QFile file("qdebug.txt");
file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text);
QTextStream out(&file);
out << msg << endl;
file.close();
}
void installNewTranslator()
@ -115,9 +116,9 @@ int main(int argc, char *argv[])
qtTranslator = new QTranslator;
translator = new QTranslator;
installNewTranslator();
qsrand(QDateTime::currentDateTime().toTime_t());
bool startMainProgram = true;
const QString dataDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
if (!db->getLoadSuccess())

View file

@ -0,0 +1,31 @@
#include "pending_command.h"
PendingCommand::PendingCommand(const CommandContainer &_commandContainer, QVariant _extraData)
: commandContainer(_commandContainer), extraData(_extraData), ticks(0)
{
}
CommandContainer & PendingCommand::getCommandContainer()
{
return commandContainer;
}
void PendingCommand::setExtraData(const QVariant &_extraData) {
extraData = _extraData;
}
QVariant PendingCommand::getExtraData() const {
return extraData;
}
void PendingCommand::processResponse(const Response &response)
{
emit finished(response, commandContainer, extraData);
emit finished(response.response_code());
}
int PendingCommand::tick()
{
return ++ticks;
}

View file

@ -15,17 +15,12 @@ private:
QVariant extraData;
int ticks;
public:
PendingCommand(const CommandContainer &_commandContainer, QVariant _extraData = QVariant())
: commandContainer(_commandContainer), extraData(_extraData), ticks(0) { }
CommandContainer &getCommandContainer() { return commandContainer; }
void setExtraData(const QVariant &_extraData) { extraData = _extraData; }
QVariant getExtraData() const { return extraData; }
void processResponse(const Response &response)
{
emit finished(response, commandContainer, extraData);
emit finished(response.response_code());
}
int tick() { return ++ticks; }
PendingCommand(const CommandContainer &_commandContainer, QVariant _extraData = QVariant());
CommandContainer &getCommandContainer();
void setExtraData(const QVariant &_extraData);
QVariant getExtraData() const;
void processResponse(const Response &response);
int tick();
};
#endif

View file

@ -3,7 +3,10 @@
#include <QPen>
#include <QTimer>
#include <QDebug>
#include <math.h>
#include <cmath>
#ifdef _WIN32
#include "round.h"
#endif /* _WIN32 */
#include "phasestoolbar.h"
#include "pixmapgenerator.h"
@ -85,7 +88,7 @@ void PhaseButton::mousePressEvent(QGraphicsSceneMouseEvent * /*event*/)
emit clicked();
}
void PhaseButton::mouseDoubleClickEvent(QGraphicsSceneMouseEvent */*event*/)
void PhaseButton::mouseDoubleClickEvent(QGraphicsSceneMouseEvent * /*event*/)
{
triggerDoubleClickAction();
}

View file

@ -105,7 +105,7 @@ void PileZone::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
setCursor(Qt::OpenHandCursor);
}
void PileZone::mouseReleaseEvent(QGraphicsSceneMouseEvent */*event*/)
void PileZone::mouseReleaseEvent(QGraphicsSceneMouseEvent * /*event*/)
{
setCursor(Qt::OpenHandCursor);
}

View file

@ -2,7 +2,10 @@
#include "pb/serverinfo_user.pb.h"
#include <QPainter>
#include <QSvgRenderer>
#include <math.h>
#include <cmath>
#ifdef _WIN32
#include "round.h"
#endif /* _WIN32 */
#include <QDebug>
QMap<QString, QPixmap> PhasePixmapGenerator::pmCache;

View file

@ -85,7 +85,7 @@ void PlayerArea::updateBgPixmap()
update();
}
void PlayerArea::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/)
void PlayerArea::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
{
painter->fillRect(bRect, bgPixmapBrush);
}
@ -1430,7 +1430,7 @@ QRectF Player::boundingRect() const
return bRect;
}
void Player::paint(QPainter * /*painter*/, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/)
void Player::paint(QPainter * /*painter*/, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
{
}

View file

@ -5,7 +5,10 @@
#include <QPainter>
#include <QPixmapCache>
#include <QDebug>
#include <math.h>
#include <cmath>
#ifdef _WIN32
#include "round.h"
#endif /* _WIN32 */
PlayerCounter::PlayerCounter(Player *_player, int _id, const QString &_name, int _value, QGraphicsItem *parent)
: AbstractCounter(_player, _id, _name, false, _value, parent)
@ -87,7 +90,8 @@ void PlayerTarget::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*o
cachedPixmap = QPixmap(translatedSize.width(), translatedSize.height());
QPainter tempPainter(&cachedPixmap);
QRadialGradient grad(translatedRect.center(), sqrt(translatedSize.width() * translatedSize.width() + translatedSize.height() * translatedSize.height()) / 2);
// pow(foo, 0.5) equals to sqrt(foo), but using sqrt(foo) in this context will produce a compile error with MSVC++
QRadialGradient grad(translatedRect.center(), pow(translatedSize.width() * translatedSize.width() + translatedSize.height() * translatedSize.height(), 0.5) / 2);
grad.setColorAt(1, Qt::black);
grad.setColorAt(0, QColor(180, 180, 180));
tempPainter.fillRect(QRectF(0, 0, translatedSize.width(), translatedSize.height()), grad);

View file

@ -2,7 +2,10 @@
#include <QPainter>
#include <QPalette>
#include <QTimer>
#include <math.h>
#include <cmath>
#ifdef _WIN32
#include "round.h"
#endif /* _WIN32 */
ReplayTimelineWidget::ReplayTimelineWidget(QWidget *parent)
: QWidget(parent), maxBinValue(1), maxTime(1), timeScaleFactor(1.0), currentTime(0), currentEvent(0)

12
cockatrice/src/round.h Normal file
View file

@ -0,0 +1,12 @@
#ifndef MSVC_ROUND_FIX
#define MSVC_ROUND_FIX
/**
* This helper function exists only because MS VC++ 2010 does not support round() in
* <cmath>. round() works with g++ and clang++ but is formally a C++11 extension.
* So this file exists for MS VC++ only.
*/
inline double round(double val) {
return floor(val + 0.5);
}
#endif /* MSVC_ROUND_FIX */

View file

@ -4,23 +4,27 @@
SettingsCache::SettingsCache()
{
settings = new QSettings(this);
lang = settings->value("personal/lang").toString();
deckPath = settings->value("paths/decks").toString();
replaysPath = settings->value("paths/replays").toString();
picsPath = settings->value("paths/pics").toString();
cardDatabasePath = settings->value("paths/carddatabase").toString();
tokenDatabasePath = settings->value("paths/tokendatabase").toString();
handBgPath = settings->value("zonebg/hand").toString();
stackBgPath = settings->value("zonebg/stack").toString();
tableBgPath = settings->value("zonebg/table").toString();
playerBgPath = settings->value("zonebg/playerarea").toString();
cardBackPicturePath = settings->value("paths/cardbackpicture").toString();
mainWindowGeometry = settings->value("interface/main_window_geometry").toByteArray();
picDownload = settings->value("personal/picturedownload", true).toBool();
picDownloadHq = settings->value("personal/picturedownloadhq", false).toBool();
picUrl = settings->value("personal/picUrl", PIC_URL_DEFAULT).toString();
picUrlHq = settings->value("personal/picUrlHq", PIC_URL_HQ_DEFAULT).toString();
mainWindowGeometry = settings->value("interface/main_window_geometry").toByteArray();
notificationsEnabled = settings->value("interface/notificationsenabled", true).toBool();
doubleClickToPlay = settings->value("interface/doubleclicktoplay", true).toBool();
playToStack = settings->value("interface/playtostack", false).toBool();
@ -31,15 +35,15 @@ SettingsCache::SettingsCache()
invertVerticalCoordinate = settings->value("table/invert_vertical", false).toBool();
minPlayersForMultiColumnLayout = settings->value("interface/min_players_multicolumn", 5).toInt();
tapAnimation = settings->value("cards/tapanimation", true).toBool();
zoneViewSortByName = settings->value("zoneview/sortbyname", true).toBool();
zoneViewSortByType = settings->value("zoneview/sortbytype", true).toBool();
soundEnabled = settings->value("sound/enabled", false).toBool();
soundPath = settings->value("sound/path").toString();
priceTagFeature = settings->value("deckeditor/pricetags", false).toBool();
ignoreUnregisteredUsers = settings->value("chat/ignore_unregistered", false).toBool();
}
@ -125,6 +129,25 @@ void SettingsCache::setPicDownload(int _picDownload)
emit picDownloadChanged();
}
void SettingsCache::setPicDownloadHq(int _picDownloadHq)
{
picDownloadHq = _picDownloadHq;
settings->setValue("personal/picturedownloadhq", picDownloadHq);
emit picDownloadHqChanged();
}
void SettingsCache::setPicUrl(const QString &_picUrl)
{
picUrl = _picUrl;
settings->setValue("personal/picUrl", picUrl);
}
void SettingsCache::setPicUrlHq(const QString &_picUrlHq)
{
picUrlHq = _picUrlHq;
settings->setValue("personal/picUrlHq", picUrlHq);
}
void SettingsCache::setNotificationsEnabled(int _notificationsEnabled)
{
notificationsEnabled = _notificationsEnabled;

View file

@ -3,6 +3,9 @@
#include <QObject>
#define PIC_URL_DEFAULT "http://gatherer.wizards.com/Handlers/Image.ashx?multiverseid=!cardid!&type=card"
#define PIC_URL_HQ_DEFAULT "http://mtgimage.com/multiverseid/!cardid!.jpg"
class QSettings;
class SettingsCache : public QObject {
@ -18,6 +21,7 @@ signals:
void playerBgPathChanged();
void cardBackPicturePathChanged();
void picDownloadChanged();
void picDownloadHqChanged();
void displayCardNamesChanged();
void horizontalHandChanged();
void invertVerticalCoordinateChanged();
@ -33,6 +37,7 @@ private:
QString deckPath, replaysPath, picsPath, cardDatabasePath, tokenDatabasePath;
QString handBgPath, stackBgPath, tableBgPath, playerBgPath, cardBackPicturePath;
bool picDownload;
bool picDownloadHq;
bool notificationsEnabled;
bool doubleClickToPlay;
bool playToStack;
@ -48,6 +53,8 @@ private:
QString soundPath;
bool priceTagFeature;
bool ignoreUnregisteredUsers;
QString picUrl;
QString picUrlHq;
public:
SettingsCache();
const QByteArray &getMainWindowGeometry() const { return mainWindowGeometry; }
@ -63,6 +70,7 @@ public:
QString getPlayerBgPath() const { return playerBgPath; }
QString getCardBackPicturePath() const { return cardBackPicturePath; }
bool getPicDownload() const { return picDownload; }
bool getPicDownloadHq() const { return picDownloadHq; }
bool getNotificationsEnabled() const { return notificationsEnabled; }
bool getDoubleClickToPlay() const { return doubleClickToPlay; }
bool getPlayToStack() const { return playToStack; }
@ -79,6 +87,8 @@ public:
QString getSoundPath() const { return soundPath; }
bool getPriceTagFeature() const { return priceTagFeature; }
bool getIgnoreUnregisteredUsers() const { return ignoreUnregisteredUsers; }
QString getPicUrl() const { return picUrl; }
QString getPicUrlHq() const { return picUrlHq; }
public slots:
void setMainWindowGeometry(const QByteArray &_mainWindowGeometry);
void setLang(const QString &_lang);
@ -93,6 +103,7 @@ public slots:
void setPlayerBgPath(const QString &_playerBgPath);
void setCardBackPicturePath(const QString &_cardBackPicturePath);
void setPicDownload(int _picDownload);
void setPicDownloadHq(int _picDownloadHq);
void setNotificationsEnabled(int _notificationsEnabled);
void setDoubleClickToPlay(int _doubleClickToPlay);
void setPlayToStack(int _playToStack);
@ -109,6 +120,8 @@ public slots:
void setSoundPath(const QString &_soundPath);
void setPriceTagFeature(int _priceTagFeature);
void setIgnoreUnregisteredUsers(bool _ignoreUnregisteredUsers);
void setPicUrl(const QString &_picUrl);
void setPicUrlHq(const QString &_picUrlHq);
};
extern SettingsCache *settingsCache;

View file

@ -46,7 +46,7 @@ QRectF StackZone::boundingRect() const
return QRectF(0, 0, 100, zoneHeight);
}
void StackZone::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/)
void StackZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
{
if (bgPixmap.isNull())
painter->fillRect(boundingRect(), QColor(113, 43, 43));

View file

@ -22,7 +22,6 @@
#include "carddatabasemodel.h"
#include "decklistmodel.h"
#include "cardinfowidget.h"
#include "dlg_cardsearch.h"
#include "dlg_load_deck_from_clipboard.h"
#include "dlg_edit_tokens.h"
#include "main.h"
@ -34,6 +33,9 @@
#include "pending_command.h"
#include "pb/response.pb.h"
#include "pb/command_deck_upload.pb.h"
#include "filtertreemodel.h"
#include "cardframe.h"
#include "filterbuilder.h"
void SearchLineEdit::keyPressEvent(QKeyEvent *event)
{
@ -45,9 +47,6 @@ void SearchLineEdit::keyPressEvent(QKeyEvent *event)
TabDeckEditor::TabDeckEditor(TabSupervisor *_tabSupervisor, QWidget *parent)
: Tab(_tabSupervisor, parent), modified(false)
{
aSearch = new QAction(QString(), this);
aSearch->setIcon(QIcon(":/resources/icon_search.svg"));
connect(aSearch, SIGNAL(triggered()), this, SLOT(actSearch()));
aClearSearch = new QAction(QString(), this);
aClearSearch->setIcon(QIcon(":/resources/icon_clearsearch.svg"));
connect(aClearSearch, SIGNAL(triggered()), this, SLOT(actClearSearch()));
@ -55,25 +54,36 @@ TabDeckEditor::TabDeckEditor(TabSupervisor *_tabSupervisor, QWidget *parent)
searchLabel = new QLabel();
searchEdit = new SearchLineEdit;
searchLabel->setBuddy(searchEdit);
setFocusProxy(searchEdit);
setFocusPolicy(Qt::ClickFocus);
searchEdit->installEventFilter(&searchKeySignals);
connect(searchEdit, SIGNAL(textChanged(const QString &)), this, SLOT(updateSearch(const QString &)));
connect(searchEdit, SIGNAL(returnPressed()), this, SLOT(actAddCard()));
QToolButton *searchButton = new QToolButton;
searchButton->setDefaultAction(aSearch);
QToolButton *clearSearchButton = new QToolButton;
clearSearchButton->setDefaultAction(aClearSearch);
connect(&searchKeySignals, SIGNAL(onEnter()), this, SLOT(actAddCard()));
connect(&searchKeySignals, SIGNAL(onCtrlAltEqual()), this, SLOT(actAddCard()));
connect(&searchKeySignals, SIGNAL(onCtrlAltRBracket()), this, SLOT(actAddCardToSideboard()));
connect(&searchKeySignals, SIGNAL(onCtrlAltMinus()), this, SLOT(actDecrementCard()));
connect(&searchKeySignals, SIGNAL(onCtrlAltLBracket()), this, SLOT(actDecrementCardFromSideboard()));
connect(&searchKeySignals, SIGNAL(onCtrlAltEnter()), this, SLOT(actAddCardToSideboard()));
connect(&searchKeySignals, SIGNAL(onCtrlEnter()), this, SLOT(actAddCardToSideboard()));
QToolBar *deckEditToolBar = new QToolBar;
deckEditToolBar->setOrientation(Qt::Horizontal);
deckEditToolBar->setIconSize(QSize(24, 24));
QHBoxLayout *searchLayout = new QHBoxLayout;
searchLayout->addWidget(deckEditToolBar);
searchLayout->addWidget(searchLabel);
searchLayout->addWidget(searchEdit);
searchLayout->addWidget(searchButton);
searchLayout->addWidget(clearSearchButton);
databaseModel = new CardDatabaseModel(db, this);
databaseDisplayModel = new CardDatabaseDisplayModel(this);
databaseDisplayModel->setSourceModel(databaseModel);
databaseDisplayModel->setFilterKeyColumn(0);
databaseDisplayModel->sort(0, Qt::AscendingOrder);
databaseView = new QTreeView();
databaseView->setFocusProxy(searchEdit);
databaseView->setModel(databaseDisplayModel);
databaseView->setUniformRowHeights(true);
databaseView->setRootIsDecorated(false);
@ -89,21 +99,33 @@ TabDeckEditor::TabDeckEditor(TabSupervisor *_tabSupervisor, QWidget *parent)
leftFrame->addLayout(searchLayout);
leftFrame->addWidget(databaseView);
cardInfo = new CardInfoWidget(CardInfoWidget::ModeDeckEditor);
cardInfo->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
cardInfo = new CardFrame(250, 356);
aCardTextOnly = new QAction(QString(), this);
aCardTextOnly->setCheckable(true);
connect(aCardTextOnly, SIGNAL(triggered()), cardInfo, SLOT(toggleCardTextOnly()));
QToolBar *verticalToolBar = new QToolBar;
verticalToolBar->setOrientation(Qt::Vertical);
verticalToolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
verticalToolBar->setIconSize(QSize(24, 24));
QHBoxLayout *verticalToolBarLayout = new QHBoxLayout;
verticalToolBarLayout->addStretch();
verticalToolBarLayout->addWidget(verticalToolBar);
verticalToolBarLayout->addStretch();
filterModel = new FilterTreeModel();
databaseDisplayModel->setFilterTree(filterModel->filterTree());
filterView = new QTreeView;
filterView->setModel(filterModel);
filterView->setMaximumWidth(250);
filterView->setUniformRowHeights(true);
filterView->setHeaderHidden(true);
filterView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(filterModel, SIGNAL(layoutChanged()), filterView, SLOT(expandAll()));
connect(filterView, SIGNAL(customContextMenuRequested(const QPoint &)),
this, SLOT(filterViewCustomContextMenu(const QPoint &)));
FilterBuilder *filterBuilder = new FilterBuilder;
filterBuilder->setMaximumWidth(250);
connect(filterBuilder, SIGNAL(add(const CardFilter *)), filterModel, SLOT(addFilter(const CardFilter *)));
QVBoxLayout *filter = new QVBoxLayout;
filter->addWidget(filterBuilder, 0, Qt::AlignTop);
filter->addWidget(filterView, 10);
QVBoxLayout *middleFrame = new QVBoxLayout;
middleFrame->addWidget(cardInfo, 10);
middleFrame->addLayout(verticalToolBarLayout);
middleFrame->addWidget(cardInfo, 0, Qt::AlignTop);
middleFrame->addLayout(filter, 10);
deckModel = new DeckListModel(this);
connect(deckModel, SIGNAL(deckHashChanged()), this, SLOT(updateHash()));
@ -113,7 +135,14 @@ TabDeckEditor::TabDeckEditor(TabSupervisor *_tabSupervisor, QWidget *parent)
deckView->setSortingEnabled(true);
deckView->sortByColumn(1, Qt::AscendingOrder);
deckView->header()->setResizeMode(QHeaderView::ResizeToContents);
deckView->installEventFilter(&deckViewKeySignals);
connect(deckView->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(updateCardInfoRight(const QModelIndex &, const QModelIndex &)));
connect(&deckViewKeySignals, SIGNAL(onEnter()), this, SLOT(actIncrement()));
connect(&deckViewKeySignals, SIGNAL(onCtrlAltEqual()), this, SLOT(actIncrement()));
connect(&deckViewKeySignals, SIGNAL(onCtrlAltMinus()), this, SLOT(actDecrement()));
connect(&deckViewKeySignals, SIGNAL(onRight()), this, SLOT(actIncrement()));
connect(&deckViewKeySignals, SIGNAL(onLeft()), this, SLOT(actDecrement()));
connect(&deckViewKeySignals, SIGNAL(onDelete()), this, SLOT(actRemoveCard()));
nameLabel = new QLabel();
nameEdit = new QLineEdit;
@ -133,36 +162,36 @@ TabDeckEditor::TabDeckEditor(TabSupervisor *_tabSupervisor, QWidget *parent)
grid->addWidget(commentsLabel, 1, 0);
grid->addWidget(commentsEdit, 1, 1);
grid->addWidget(hashLabel1, 2, 0);
grid->addWidget(hashLabel, 2, 1);
// Update price
aUpdatePrices = new QAction(QString(), this);
aUpdatePrices->setIcon(QIcon(":/resources/icon_update.png"));
connect(aUpdatePrices, SIGNAL(triggered()), this, SLOT(actUpdatePrices()));
// Update price
aUpdatePrices = new QAction(QString(), this);
aUpdatePrices->setIcon(QIcon(":/resources/icon_update.png"));
connect(aUpdatePrices, SIGNAL(triggered()), this, SLOT(actUpdatePrices()));
if (!settingsCache->getPriceTagFeature())
aUpdatePrices->setVisible(false);
QToolBar *deckToolBar = new QToolBar;
deckToolBar->setOrientation(Qt::Vertical);
deckToolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
deckToolBar->setIconSize(QSize(24, 24));
deckToolBar->addAction(aUpdatePrices);
QHBoxLayout *deckToolbarLayout = new QHBoxLayout;
deckToolbarLayout->addStretch();
deckToolbarLayout->addWidget(deckToolBar);
deckToolbarLayout->addStretch();
QToolBar *deckToolBar = new QToolBar;
deckToolBar->setOrientation(Qt::Vertical);
deckToolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
deckToolBar->setIconSize(QSize(24, 24));
deckToolBar->addAction(aUpdatePrices);
QHBoxLayout *deckToolbarLayout = new QHBoxLayout;
deckToolbarLayout->addStretch();
deckToolbarLayout->addWidget(deckToolBar);
deckToolbarLayout->addStretch();
QVBoxLayout *rightFrame = new QVBoxLayout;
rightFrame->addLayout(grid);
rightFrame->addWidget(deckView, 10);
rightFrame->addLayout(deckToolbarLayout);
rightFrame->addLayout(deckToolbarLayout);
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addLayout(leftFrame, 10);
mainLayout->addLayout(middleFrame);
mainLayout->addLayout(rightFrame, 10);
mainLayout->addLayout(rightFrame);
setLayout(mainLayout);
aNewDeck = new QAction(QString(), this);
@ -216,34 +245,32 @@ TabDeckEditor::TabDeckEditor(TabSupervisor *_tabSupervisor, QWidget *parent)
dbMenu->addAction(aEditSets);
dbMenu->addAction(aEditTokens);
dbMenu->addSeparator();
dbMenu->addAction(aSearch);
dbMenu->addAction(aClearSearch);
dbMenu->addAction(aCardTextOnly);
addTabMenu(dbMenu);
aAddCard = new QAction(QString(), this);
aAddCard->setIcon(QIcon(":/resources/arrow_right_green.svg"));
connect(aAddCard, SIGNAL(triggered()), this, SLOT(actAddCard()));
aAddCardToSideboard = new QAction(QString(), this);
aAddCardToSideboard->setIcon(QIcon(":/resources/add_to_sideboard.svg"));
aAddCardToSideboard->setIcon(QIcon(":/resources/add_to_sideboard.svg"));
connect(aAddCardToSideboard, SIGNAL(triggered()), this, SLOT(actAddCardToSideboard()));
aRemoveCard = new QAction(QString(), this);
aRemoveCard->setIcon(QIcon(":/resources/remove_row.svg"));
aRemoveCard->setIcon(QIcon(":/resources/remove_row.svg"));
connect(aRemoveCard, SIGNAL(triggered()), this, SLOT(actRemoveCard()));
aIncrement = new QAction(QString(), this);
aIncrement->setIcon(QIcon(":/resources/increment.svg"));
aIncrement->setIcon(QIcon(":/resources/increment.svg"));
connect(aIncrement, SIGNAL(triggered()), this, SLOT(actIncrement()));
aDecrement = new QAction(QString(), this);
aDecrement->setIcon(QIcon(":/resources/decrement.svg"));
aDecrement->setIcon(QIcon(":/resources/decrement.svg"));
connect(aDecrement, SIGNAL(triggered()), this, SLOT(actDecrement()));
verticalToolBar->addAction(aAddCard);
verticalToolBar->addAction(aAddCardToSideboard);
verticalToolBar->addAction(aRemoveCard);
verticalToolBar->addAction(aIncrement);
verticalToolBar->addAction(aDecrement);
verticalToolBar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
dlgCardSearch = new DlgCardSearch(this);
deckEditToolBar->addAction(aAddCard);
deckEditToolBar->addAction(aAddCardToSideboard);
deckEditToolBar->addAction(aRemoveCard);
deckEditToolBar->addAction(aIncrement);
deckEditToolBar->addAction(aDecrement);
deckEditToolBar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
retranslateUi();
@ -257,7 +284,7 @@ TabDeckEditor::~TabDeckEditor()
void TabDeckEditor::retranslateUi()
{
aSearch->setText(tr("&Search..."));
aCardTextOnly->setText(tr("Show card text only"));
aClearSearch->setText(tr("&Clear search"));
searchLabel->setText(tr("&Search for:"));
@ -266,11 +293,11 @@ void TabDeckEditor::retranslateUi()
hashLabel1->setText(tr("Hash:"));
aUpdatePrices->setText(tr("&Update prices"));
aUpdatePrices->setShortcut(tr("Ctrl+U"));
aNewDeck->setText(tr("&New deck"));
aLoadDeck->setText(tr("&Load deck..."));
aSaveDeck->setText(tr("&Save deck"));
aUpdatePrices->setShortcut(tr("Ctrl+U"));
aNewDeck->setText(tr("&New deck"));
aLoadDeck->setText(tr("&Load deck..."));
aSaveDeck->setText(tr("&Save deck"));
aSaveDeckAs->setText(tr("Save deck &as..."));
aLoadDeckFromClipboard->setText(tr("Load deck from cl&ipboard..."));
aSaveDeckToClipboard->setText(tr("Save deck to clip&board"));
@ -280,9 +307,8 @@ void TabDeckEditor::retranslateUi()
aClose->setShortcut(tr("Ctrl+Q"));
aAddCard->setText(tr("Add card to &maindeck"));
aAddCard->setShortcuts(QList<QKeySequence>() << QKeySequence(tr("Return")) << QKeySequence(tr("Enter")));
aAddCardToSideboard->setText(tr("Add card to &sideboard"));
aAddCardToSideboard->setShortcuts(QList<QKeySequence>() << QKeySequence(tr("Ctrl+Return")) << QKeySequence(tr("Ctrl+Enter")));
aRemoveCard->setText(tr("&Remove row"));
aRemoveCard->setShortcut(tr("Del"));
aIncrement->setText(tr("&Increment number"));
@ -499,17 +525,6 @@ void TabDeckEditor::actEditTokens()
db->saveToFile(settingsCache->getTokenDatabasePath(), true);
}
void TabDeckEditor::actSearch()
{
if (dlgCardSearch->exec()) {
searchEdit->clear();
databaseDisplayModel->setCardName(dlgCardSearch->getCardName());
databaseDisplayModel->setCardText(dlgCardSearch->getCardText());
databaseDisplayModel->setCardTypes(dlgCardSearch->getCardTypes());
databaseDisplayModel->setCardColors(dlgCardSearch->getCardColors());
}
}
void TabDeckEditor::actClearSearch()
{
databaseDisplayModel->clearSearch();
@ -522,21 +537,29 @@ void TabDeckEditor::recursiveExpand(const QModelIndex &index)
deckView->expand(index);
}
void TabDeckEditor::addCardHelper(QString zoneName)
CardInfo *TabDeckEditor::currentCardInfo() const
{
const QModelIndex currentIndex = databaseView->selectionModel()->currentIndex();
if (!currentIndex.isValid())
return;
return NULL;
const QString cardName = currentIndex.sibling(currentIndex.row(), 0).data().toString();
CardInfo *info = db->getCard(cardName);
return db->getCard(cardName);
}
void TabDeckEditor::addCardHelper(QString zoneName)
{
const CardInfo *info;
info = currentCardInfo();
if(!info)
return;
if (info->getIsToken())
zoneName = "tokens";
QModelIndex newCardIndex = deckModel->addCard(cardName, zoneName);
QModelIndex newCardIndex = deckModel->addCard(info->getName(), zoneName);
recursiveExpand(newCardIndex);
deckView->setCurrentIndex(newCardIndex);
setModified(true);
}
@ -559,31 +582,57 @@ void TabDeckEditor::actRemoveCard()
setModified(true);
}
void TabDeckEditor::offsetCountAtIndex(const QModelIndex &idx, int offset)
{
if (!idx.isValid() || offset == 0)
return;
const QModelIndex numberIndex = idx.sibling(idx.row(), 0);
const int count = deckModel->data(numberIndex, Qt::EditRole).toInt();
const int new_count = count + offset;
deckView->setCurrentIndex(numberIndex);
if (new_count <= 0)
deckModel->removeRow(idx.row(), idx.parent());
else
deckModel->setData(numberIndex, new_count, Qt::EditRole);
setModified(true);
}
void TabDeckEditor::decrementCardHelper(QString zoneName)
{
const CardInfo *info;
QModelIndex idx;
info = currentCardInfo();
if(!info)
return;
if (info->getIsToken())
zoneName = "tokens";
idx = deckModel->findCard(info->getName(), zoneName);
offsetCountAtIndex(idx, -1);
}
void TabDeckEditor::actDecrementCard()
{
decrementCardHelper("main");
}
void TabDeckEditor::actDecrementCardFromSideboard()
{
decrementCardHelper("side");
}
void TabDeckEditor::actIncrement()
{
const QModelIndex &currentIndex = deckView->selectionModel()->currentIndex();
if (!currentIndex.isValid())
return;
const QModelIndex numberIndex = currentIndex.sibling(currentIndex.row(), 0);
const int count = deckModel->data(numberIndex, Qt::EditRole).toInt();
deckView->setCurrentIndex(numberIndex);
deckModel->setData(numberIndex, count + 1, Qt::EditRole);
setModified(true);
offsetCountAtIndex(currentIndex, 1);
}
void TabDeckEditor::actDecrement()
{
const QModelIndex &currentIndex = deckView->selectionModel()->currentIndex();
if (!currentIndex.isValid())
return;
const QModelIndex numberIndex = currentIndex.sibling(currentIndex.row(), 0);
const int count = deckModel->data(numberIndex, Qt::EditRole).toInt();
deckView->setCurrentIndex(numberIndex);
if (count == 1)
deckModel->removeRow(currentIndex.row(), currentIndex.parent());
else
deckModel->setData(numberIndex, count - 1, Qt::EditRole);
setModified(true);
offsetCountAtIndex(currentIndex, -1);
}
void TabDeckEditor::actUpdatePrices()
@ -622,3 +671,31 @@ void TabDeckEditor::setModified(bool _modified)
modified = _modified;
emit tabTextChanged(this, getTabText());
}
void TabDeckEditor::filterViewCustomContextMenu(const QPoint &point) {
QMenu menu;
QAction *action;
QModelIndex idx;
idx = filterView->indexAt(point);
if (!idx.isValid())
return;
action = menu.addAction(QString("delete"));
action->setData(point);
connect(&menu, SIGNAL(triggered(QAction *)),
this, SLOT(filterRemove(QAction *)));
menu.exec(filterView->mapToGlobal(point));
}
void TabDeckEditor::filterRemove(QAction *action) {
QPoint point;
QModelIndex idx;
point = action->data().toPoint();
idx = filterView->indexAt(point);
if (!idx.isValid())
return;
filterModel->removeRow(idx.row(), idx.parent());
}

View file

@ -4,18 +4,20 @@
#include "tab.h"
#include <QAbstractItemModel>
#include <QLineEdit>
#include "keysignals.h"
class CardDatabaseModel;
class CardDatabaseDisplayModel;
class DeckListModel;
class QTreeView;
class QTableView;
class CardInfoWidget;
class CardFrame;
class QTextEdit;
class DlgCardSearch;
class QLabel;
class DeckLoader;
class Response;
class FilterTreeModel;
class CardInfo;
class SearchLineEdit : public QLineEdit {
private:
@ -49,7 +51,6 @@ private slots:
void actEditSets();
void actEditTokens();
void actSearch();
void actClearSearch();
void actAddCard();
@ -57,12 +58,20 @@ private slots:
void actRemoveCard();
void actIncrement();
void actDecrement();
void actUpdatePrices();
void actDecrementCard();
void actDecrementCardFromSideboard();
void finishedUpdatingPrices();
void actUpdatePrices();
void finishedUpdatingPrices();
void saveDeckRemoteFinished(const Response &r);
void filterViewCustomContextMenu(const QPoint &point);
void filterRemove(QAction *action);
private:
CardInfo *currentCardInfo() const;
void addCardHelper(QString zoneName);
void offsetCountAtIndex(const QModelIndex &idx, int offset);
void decrementCardHelper(QString zoneName);
void recursiveExpand(const QModelIndex &index);
bool confirmClose();
@ -70,22 +79,27 @@ private:
CardDatabaseDisplayModel *databaseDisplayModel;
DeckListModel *deckModel;
QTreeView *databaseView;
QTreeView *deckView;
CardInfoWidget *cardInfo;
KeySignals deckViewKeySignals;
CardFrame *cardInfo;
QLabel *searchLabel;
SearchLineEdit *searchEdit;
KeySignals searchKeySignals;
QLabel *nameLabel;
QLineEdit *nameEdit;
QLabel *commentsLabel;
QTextEdit *commentsEdit;
QLabel *hashLabel1;
QLabel *hashLabel;
DlgCardSearch *dlgCardSearch;
FilterTreeModel *filterModel;
QTreeView *filterView;
QMenu *deckMenu, *dbMenu;
QAction *aNewDeck, *aLoadDeck, *aSaveDeck, *aSaveDeckAs, *aLoadDeckFromClipboard, *aSaveDeckToClipboard, *aPrintDeck, *aAnalyzeDeck, *aClose;
QAction *aEditSets, *aEditTokens, *aSearch, *aClearSearch;
QAction *aAddCard, *aAddCardToSideboard, *aRemoveCard, *aIncrement, *aDecrement, *aUpdatePrices;
QAction *aEditSets, *aEditTokens, *aClearSearch, *aCardTextOnly;
QAction *aAddCard, *aAddCardToSideboard, *aRemoveCard, *aIncrement, *aDecrement, *aUpdatePrices;
bool modified;
public:

View file

@ -532,7 +532,7 @@ void TabGame::retranslateUi()
gameMenu->setTitle(tr("&Game"));
if (aNextPhase) {
aNextPhase->setText(tr("Next &phase"));
aNextPhase->setShortcut(tr("Ctrl+Space"));
aNextPhase->setShortcuts(QList<QKeySequence>() << QKeySequence(tr("Ctrl+Space")) << QKeySequence(tr("Tab")));
}
if (aNextTurn) {
aNextTurn->setText(tr("Next &turn"));

View file

@ -4,6 +4,8 @@
#include "abstractclient.h"
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QPushButton>
#include <QLineEdit>
#include "pending_command.h"
#include "pb/session_commands.pb.h"
@ -21,34 +23,90 @@ TabUserLists::TabUserLists(TabSupervisor *_tabSupervisor, AbstractClient *_clien
ignoreList = new UserList(_tabSupervisor, client, UserList::IgnoreList);
userInfoBox = new UserInfoBox(client, false);
userInfoBox->updateInfo(userInfo);
connect(allUsersList, SIGNAL(openMessageDialog(const QString &, bool)), this, SIGNAL(openMessageDialog(const QString &, bool)));
connect(buddyList, SIGNAL(openMessageDialog(const QString &, bool)), this, SIGNAL(openMessageDialog(const QString &, bool)));
connect(ignoreList, SIGNAL(openMessageDialog(const QString &, bool)), this, SIGNAL(openMessageDialog(const QString &, bool)));
connect(client, SIGNAL(userJoinedEventReceived(const Event_UserJoined &)), this, SLOT(processUserJoinedEvent(const Event_UserJoined &)));
connect(client, SIGNAL(userLeftEventReceived(const Event_UserLeft &)), this, SLOT(processUserLeftEvent(const Event_UserLeft &)));
connect(client, SIGNAL(buddyListReceived(const QList<ServerInfo_User> &)), this, SLOT(buddyListReceived(const QList<ServerInfo_User> &)));
connect(client, SIGNAL(ignoreListReceived(const QList<ServerInfo_User> &)), this, SLOT(ignoreListReceived(const QList<ServerInfo_User> &)));
connect(client, SIGNAL(addToListEventReceived(const Event_AddToList &)), this, SLOT(processAddToListEvent(const Event_AddToList &)));
connect(client, SIGNAL(removeFromListEventReceived(const Event_RemoveFromList &)), this, SLOT(processRemoveFromListEvent(const Event_RemoveFromList &)));
PendingCommand *pend = client->prepareSessionCommand(Command_ListUsers());
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this, SLOT(processListUsersResponse(const Response &)));
client->sendCommand(pend);
QVBoxLayout *vbox = new QVBoxLayout;
vbox->addWidget(userInfoBox);
vbox->addWidget(allUsersList);
QHBoxLayout *addToBuddyList = new QHBoxLayout;
addBuddyEdit = new QLineEdit;
addBuddyEdit->setPlaceholderText(tr("Add to Buddy List"));
connect(addBuddyEdit, SIGNAL(returnPressed()), this, SLOT(addToBuddyList()));
QPushButton *addBuddyButton = new QPushButton("Add");
connect(addBuddyButton, SIGNAL(clicked()), this, SLOT(addToBuddyList()));
addToBuddyList->addWidget(addBuddyEdit);
addToBuddyList->addWidget(addBuddyButton);
QHBoxLayout *addToIgnoreList = new QHBoxLayout;
addIgnoreEdit = new QLineEdit;
addIgnoreEdit->setPlaceholderText(tr("Add to Ignore List"));
connect(addIgnoreEdit, SIGNAL(returnPressed()), this, SLOT(addToIgnoreList()));
QPushButton *addIgnoreButton = new QPushButton("Add");
connect(addIgnoreButton, SIGNAL(clicked()), this, SLOT(addToIgnoreList()));
addToIgnoreList->addWidget(addIgnoreEdit);
addToIgnoreList->addWidget(addIgnoreButton);
QVBoxLayout *buddyPanel = new QVBoxLayout;
buddyPanel->addWidget(buddyList);
buddyPanel->addLayout(addToBuddyList);
QVBoxLayout *ignorePanel = new QVBoxLayout;
ignorePanel->addWidget(ignoreList);
ignorePanel->addLayout(addToIgnoreList);
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(buddyList);
mainLayout->addWidget(ignoreList);
mainLayout->addLayout(buddyPanel);
mainLayout->addLayout(ignorePanel);
mainLayout->addLayout(vbox);
setLayout(mainLayout);
}
void TabUserLists::addToBuddyList()
{
QString userName = addBuddyEdit->text();
if (userName.length() < 1) return;
std::string listName = "buddy";
addToList(listName, userName);
addBuddyEdit->clear();
}
void TabUserLists::addToIgnoreList()
{
QString userName = addIgnoreEdit->text();
if (userName.length() < 1) return;
std::string listName = "ignore";
addToList(listName, userName);
addIgnoreEdit->clear();
}
void TabUserLists::addToList(const std::string &listName, const QString &userName)
{
Command_AddToList cmd;
cmd.set_list(listName);
cmd.set_user_name(userName.toStdString());
client->sendCommand(client->prepareSessionCommand(cmd));
}
void TabUserLists::retranslateUi()
{
allUsersList->retranslateUi();

View file

@ -3,6 +3,7 @@
#include "tab.h"
#include "pb/serverinfo_user.pb.h"
#include <QLineEdit>
class AbstractClient;
class UserList;
@ -30,12 +31,17 @@ private slots:
void ignoreListReceived(const QList<ServerInfo_User> &_ignoreList);
void processAddToListEvent(const Event_AddToList &event);
void processRemoveFromListEvent(const Event_RemoveFromList &event);
void addToIgnoreList();
void addToBuddyList();
private:
AbstractClient *client;
UserList *allUsersList;
UserList *buddyList;
UserList *ignoreList;
UserInfoBox *userInfoBox;
QLineEdit *addBuddyEdit;
QLineEdit *addIgnoreEdit;
void addToList(const std::string &listName, const QString &userName);
public:
TabUserLists(TabSupervisor *_tabSupervisor, AbstractClient *_client, const ServerInfo_User &userInfo, QWidget *parent = 0);
void retranslateUi();

View file

@ -1,7 +1,10 @@
#include <QPainter>
#include <QSet>
#include <QGraphicsScene>
#include <math.h>
#include <cmath>
#ifdef _WIN32
#include "round.h"
#endif /* _WIN32 */
#include "tablezone.h"
#include "player.h"
#include "settingscache.h"
@ -46,7 +49,7 @@ bool TableZone::isInverted() const
return ((player->getMirrored() && !settingsCache->getInvertVerticalCoordinate()) || (!player->getMirrored() && settingsCache->getInvertVerticalCoordinate()));
}
void TableZone::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/)
void TableZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
{
if (bgPixmap.isNull())
painter->fillRect(boundingRect(), QColor(0, 0, 100));

View file

@ -31,7 +31,7 @@ QRectF ZoneViewZone::boundingRect() const
return bRect;
}
void ZoneViewZone::paint(QPainter */*painter*/, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/)
void ZoneViewZone::paint(QPainter * /*painter*/, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
{
}

View file

@ -1,56 +1,38 @@
# CMakeLists for common directory
#
# provides the common library
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
add_subdirectory(pb)
SET(common_SOURCES
decklist.cpp
get_pb_extension.cpp
rng_abstract.cpp
rng_qt.cpp
rng_sfmt.cpp
server.cpp
server_abstractuserinterface.cpp
server_arrow.cpp
server_card.cpp
server_cardzone.cpp
server_counter.cpp
server_game.cpp
server_player.cpp
server_protocolhandler.cpp
server_remoteuserinterface.cpp
server_response_containers.cpp
server_room.cpp
serverinfo_user_container.cpp
sfmt/SFMT.c
)
SET(common_HEADERS
decklist.h
rng_abstract.h
rng_qt.h
rng_sfmt.h
server.h
server_arrowtarget.h
server_card.h
server_database_interface.h
server_game.h
server_player.h
server_protocolhandler.h
server_room.h
decklist.cpp
get_pb_extension.cpp
rng_abstract.cpp
rng_sfmt.cpp
server.cpp
server_abstractuserinterface.cpp
server_arrow.cpp
server_arrowtarget.h
server_card.cpp
server_cardzone.cpp
server_counter.cpp
server_game.cpp
server_database_interface.cpp
server_player.cpp
server_protocolhandler.cpp
server_remoteuserinterface.cpp
server_response_containers.cpp
server_room.cpp
serverinfo_user_container.cpp
sfmt/SFMT.c
)
FIND_PACKAGE(Qt4 REQUIRED)
FIND_PACKAGE(Protobuf REQUIRED)
QT4_WRAP_CPP(common_HEADERS_MOC ${common_HEADERS})
INCLUDE(${QT_USE_FILE})
INCLUDE_DIRECTORIES(pb)
INCLUDE_DIRECTORIES(sfmt)
INCLUDE_DIRECTORIES(${PROTOBUF_INCLUDE_DIR})
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
add_library(cockatrice_common ${common_SOURCES} ${common_HEADERS_MOC})
# Without this check, Linux will put -pthread out of order in link.txt and build will fail
if (UNIX)
target_link_libraries(cockatrice_common cockatrice_protocol pthread)
else (UNIX)
target_link_libraries(cockatrice_common cockatrice_protocol)
endif (UNIX)
add_library(cockatrice_common ${common_SOURCES} ${common_MOC_SRCS})
target_link_libraries(cockatrice_common cockatrice_protocol)

View file

@ -89,7 +89,7 @@ public:
virtual QString getName() const = 0;
virtual void setName(const QString &_name) = 0;
virtual float getPrice() const = 0;
virtual void setPrice(float _price) = 0;
virtual void setPrice(const float _price) = 0;
float getTotalPrice() const { return getNumber() * getPrice(); }
int height() const { return 0; }
bool compare(AbstractDecklistNode *other) const;

View file

@ -1,157 +1,163 @@
# CMakeLists for common directory
#
# provides the protobuf interfaces
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
SET(PROTO_FILES
admin_commands.proto
card_attributes.proto
color.proto
command_attach_card.proto
command_change_zone_properties.proto
command_concede.proto
command_create_arrow.proto
command_create_counter.proto
command_create_token.proto
command_deck_del_dir.proto
command_deck_del.proto
command_deck_download.proto
command_deck_list.proto
command_deck_new_dir.proto
command_deck_select.proto
command_deck_upload.proto
command_del_counter.proto
command_delete_arrow.proto
command_draw_cards.proto
command_dump_zone.proto
command_flip_card.proto
command_game_say.proto
command_inc_card_counter.proto
command_inc_counter.proto
command_kick_from_game.proto
command_leave_game.proto
command_move_card.proto
command_mulligan.proto
command_next_turn.proto
command_ready_start.proto
command_replay_delete_match.proto
command_replay_list.proto
command_replay_download.proto
command_replay_modify_match.proto
command_reveal_cards.proto
command_roll_die.proto
command_set_active_phase.proto
command_set_card_attr.proto
command_set_card_counter.proto
command_set_counter.proto
command_set_sideboard_plan.proto
command_set_sideboard_lock.proto
command_shuffle.proto
commands.proto
command_stop_dump_zone.proto
command_undo_draw.proto
context_concede.proto
context_connection_state_changed.proto
context_deck_select.proto
context_move_card.proto
context_mulligan.proto
context_ping_changed.proto
context_ready_start.proto
context_set_sideboard_lock.proto
context_undo_draw.proto
event_add_to_list.proto
event_attach_card.proto
event_change_zone_properties.proto
event_connection_closed.proto
event_create_arrow.proto
event_create_counter.proto
event_create_token.proto
event_del_counter.proto
event_delete_arrow.proto
event_destroy_card.proto
event_draw_cards.proto
event_dump_zone.proto
event_flip_card.proto
event_game_closed.proto
event_game_host_changed.proto
event_game_joined.proto
event_game_say.proto
event_game_state_changed.proto
event_join.proto
event_join_room.proto
event_kicked.proto
event_leave.proto
event_leave_room.proto
event_list_games.proto
event_list_rooms.proto
event_move_card.proto
event_player_properties_changed.proto
event_remove_from_list.proto
event_replay_added.proto
event_reveal_cards.proto
event_roll_die.proto
event_room_say.proto
event_server_complete_list.proto
event_server_identification.proto
event_server_message.proto
event_server_shutdown.proto
event_set_active_phase.proto
event_set_active_player.proto
event_set_card_attr.proto
event_set_card_counter.proto
event_set_counter.proto
event_shuffle.proto
event_stop_dump_zone.proto
event_user_joined.proto
event_user_left.proto
event_user_message.proto
game_commands.proto
game_event_container.proto
game_event_context.proto
game_event.proto
game_replay.proto
isl_message.proto
moderator_commands.proto
move_card_to_zone.proto
response_deck_download.proto
response_deck_list.proto
response_deck_upload.proto
response_dump_zone.proto
response_get_games_of_user.proto
response_get_user_info.proto
response_join_room.proto
response_list_users.proto
response_login.proto
response_replay_download.proto
response_replay_list.proto
response.proto
room_commands.proto
room_event.proto
serverinfo_arrow.proto
serverinfo_cardcounter.proto
serverinfo_card.proto
serverinfo_counter.proto
serverinfo_deckstorage.proto
serverinfo_game.proto
serverinfo_gametype.proto
serverinfo_playerping.proto
serverinfo_playerproperties.proto
serverinfo_player.proto
serverinfo_replay.proto
serverinfo_replay_match.proto
serverinfo_room.proto
serverinfo_user.proto
serverinfo_zone.proto
server_message.proto
session_commands.proto
session_event.proto
admin_commands.proto
card_attributes.proto
color.proto
command_attach_card.proto
command_change_zone_properties.proto
command_concede.proto
command_create_arrow.proto
command_create_counter.proto
command_create_token.proto
command_deck_del_dir.proto
command_deck_del.proto
command_deck_download.proto
command_deck_list.proto
command_deck_new_dir.proto
command_deck_select.proto
command_deck_upload.proto
command_del_counter.proto
command_delete_arrow.proto
command_draw_cards.proto
command_dump_zone.proto
command_flip_card.proto
command_game_say.proto
command_inc_card_counter.proto
command_inc_counter.proto
command_kick_from_game.proto
command_leave_game.proto
command_move_card.proto
command_mulligan.proto
command_next_turn.proto
command_ready_start.proto
command_replay_delete_match.proto
command_replay_list.proto
command_replay_download.proto
command_replay_modify_match.proto
command_reveal_cards.proto
command_roll_die.proto
command_set_active_phase.proto
command_set_card_attr.proto
command_set_card_counter.proto
command_set_counter.proto
command_set_sideboard_plan.proto
command_set_sideboard_lock.proto
command_shuffle.proto
commands.proto
command_stop_dump_zone.proto
command_undo_draw.proto
context_concede.proto
context_connection_state_changed.proto
context_deck_select.proto
context_move_card.proto
context_mulligan.proto
context_ping_changed.proto
context_ready_start.proto
context_set_sideboard_lock.proto
context_undo_draw.proto
event_add_to_list.proto
event_attach_card.proto
event_change_zone_properties.proto
event_connection_closed.proto
event_create_arrow.proto
event_create_counter.proto
event_create_token.proto
event_del_counter.proto
event_delete_arrow.proto
event_destroy_card.proto
event_draw_cards.proto
event_dump_zone.proto
event_flip_card.proto
event_game_closed.proto
event_game_host_changed.proto
event_game_joined.proto
event_game_say.proto
event_game_state_changed.proto
event_join.proto
event_join_room.proto
event_kicked.proto
event_leave.proto
event_leave_room.proto
event_list_games.proto
event_list_rooms.proto
event_move_card.proto
event_player_properties_changed.proto
event_remove_from_list.proto
event_replay_added.proto
event_reveal_cards.proto
event_roll_die.proto
event_room_say.proto
event_server_complete_list.proto
event_server_identification.proto
event_server_message.proto
event_server_shutdown.proto
event_set_active_phase.proto
event_set_active_player.proto
event_set_card_attr.proto
event_set_card_counter.proto
event_set_counter.proto
event_shuffle.proto
event_stop_dump_zone.proto
event_user_joined.proto
event_user_left.proto
event_user_message.proto
game_commands.proto
game_event_container.proto
game_event_context.proto
game_event.proto
game_replay.proto
isl_message.proto
moderator_commands.proto
move_card_to_zone.proto
response_deck_download.proto
response_deck_list.proto
response_deck_upload.proto
response_dump_zone.proto
response_get_games_of_user.proto
response_get_user_info.proto
response_join_room.proto
response_list_users.proto
response_login.proto
response_replay_download.proto
response_replay_list.proto
response.proto
room_commands.proto
room_event.proto
serverinfo_arrow.proto
serverinfo_cardcounter.proto
serverinfo_card.proto
serverinfo_counter.proto
serverinfo_deckstorage.proto
serverinfo_game.proto
serverinfo_gametype.proto
serverinfo_playerping.proto
serverinfo_playerproperties.proto
serverinfo_player.proto
serverinfo_replay.proto
serverinfo_replay_match.proto
serverinfo_room.proto
serverinfo_user.proto
serverinfo_zone.proto
server_message.proto
session_commands.proto
session_event.proto
)
find_package(Protobuf REQUIRED)
include_directories(${PROTOBUF_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${PROTO_FILES})
add_library(cockatrice_protocol ${PROTO_SRCS} ${PROTO_HDRS})
set(cockatrice_protocol_LIBS ${PROTOBUF_LIBRARIES})
if (WIN32)
set(cockatrice_protocol_LIBS ${cockatrice_protocol_LIBS} -lprotobuf)
endif (WIN32)
if (MSVC)
set(cockatrice_protocol_LIBS ${cockatrice_protocol_LIBS} -lprotobuf)
endif (MSVC)
if (UNIX)
set(cockatrice_protocol_LIBS ${cockatrice_protocol_LIBS} -lpthread)
endif (UNIX)
target_link_libraries(cockatrice_protocol ${cockatrice_protocol_LIBS})

View file

@ -7,9 +7,9 @@ QVector<int> RNG_Abstract::makeNumbersVector(int n, int min, int max)
const int bins = max - min + 1;
QVector<int> result(bins);
for (int i = 0; i < n; ++i) {
int number = getNumber(min, max);
int number = rand(min, max);
if ((number < min) || (number > max))
qDebug() << "getNumber(" << min << "," << max << ") returned " << number;
qDebug() << "rand(" << min << "," << max << ") returned " << number;
else
result[number - min]++;
}

View file

@ -8,7 +8,7 @@ class RNG_Abstract : public QObject {
Q_OBJECT
public:
RNG_Abstract(QObject *parent = 0) : QObject(parent) { }
virtual unsigned int getNumber(unsigned int min, unsigned int max) = 0;
virtual unsigned int rand(int min, int max) = 0;
QVector<int> makeNumbersVector(int n, int min, int max);
double testRandom(const QVector<int> &numbers) const;
};

View file

@ -1,16 +0,0 @@
#include "rng_qt.h"
#include <QDateTime>
#include <stdlib.h>
RNG_Qt::RNG_Qt(QObject *parent)
: RNG_Abstract(parent)
{
int seed = QDateTime::currentDateTime().toTime_t();
qsrand(seed);
}
unsigned int RNG_Qt::getNumber(unsigned int min, unsigned int max)
{
int r = qrand();
return min + (unsigned int) (((double) (max + 1 - min)) * r / (RAND_MAX + 1.0));
}

View file

@ -1,13 +0,0 @@
#ifndef RNG_QT_H
#define RNG_QT_H
#include "rng_abstract.h"
class RNG_Qt : public RNG_Abstract {
Q_OBJECT
public:
RNG_Qt(QObject *parent = 0);
unsigned int getNumber(unsigned int min, unsigned int max);
};
#endif

View file

@ -1,25 +1,136 @@
#include "rng_sfmt.h"
#include "sfmt/SFMT.h"
#include <QDateTime>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
#include <climits>
#include <stdexcept>
// This is from gcc sources, namely from fixincludes/inclhack.def
// On C++11 systems, <cstdint> could be included instead.
#ifndef UINT64_MAX
#define UINT64_MAX (~(uint64_t)0)
#endif
RNG_SFMT::RNG_SFMT(QObject *parent)
: RNG_Abstract(parent)
{
std::cerr << "Using SFMT random number generator." << std::endl;
int seed = QDateTime::currentDateTime().toTime_t();
init_gen_rand(seed);
for (int i = 0; i < 100000; ++i)
gen_rand64();
// initialize the random number generator with a 32bit integer seed (timestamp)
sfmt_init_gen_rand(&sfmt, QDateTime::currentDateTime().toTime_t());
}
unsigned int RNG_SFMT::getNumber(unsigned int min, unsigned int max)
{
mutex.lock();
uint64_t r = gen_rand64();
mutex.unlock();
return min + (unsigned int) (((double) (max + 1 - min)) * r / (18446744073709551616.0 + 1.0));
/**
* This method is the rand() equivalent which calls the cdf with proper bounds.
*
* It is possible to generate random numbers from [-min, +/-max] though the RNG uses
* unsigned numbers only, so this wrapper handles some special cases for min and max.
*
* It is only necessary that the upper bound is larger or equal to the lower bound - with the exception
* that someone wants something like rand() % -foo.
*/
unsigned int RNG_SFMT::rand(int min, int max) {
/* If min is negative, it would be possible to calculate
* cdf(0, max - min) + min
* There has been no use for negative random numbers with rand() though, so it's treated as error.
*/
if(min < 0) {
throw std::invalid_argument(
QString("Invalid bounds for RNG: Got min " +
QString::number(min) + " < 0!\n").toStdString());
// at this point, the method exits. No return value is needed, because
// basically the exception itself is returned.
}
// For complete fairness and equal timing, this should be a roll, but let's skip it anyway
if(min == max)
return max;
// This is actually not used in Cockatrice:
// Someone wants rand() % -foo, so we compute -rand(0, +foo)
// This is the only time where min > max is (sort of) legal.
// Not handling this will cause the application to crash.
if(min == 0 && max < 0) {
return -cdf(0, -max);
}
// No special cases are left, except !(min > max) which is caught in the cdf itself.
return cdf(min, max);
}
/**
* Much thought went into this, please read this comment before you modify the code.
* Let SFMT() be an alias for sfmt_genrand_uint64() aka SFMT's rand() function.
*
* SMFT() returns a uniformly distributed pseudorandom number from 0 to UINT64_MAX.
* As SFMT() operates on a limited integer range, it is a _discrete_ function.
*
* We want a random number from a given interval [min, max] though, so we need to
* implement the (discrete) cumulative distribution function SFMT(min, max), which
* returns a random number X from [min, max].
*
* This CDF is by formal definition:
* SFMT(X; min, max) = (floor(X) - min + 1) / (max - min + 1)
*
* To get out the random variable, solve for X:
* floor(X) = SFMT(X; min, max) * (max - min + 1) + min - 1
* So this is, what rand(min, max) should look like.
* Problem: SFMT(X; min, max) * (max - min + 1) could produce an integer overflow,
* so it is not safe.
*
* One solution is to divide the universe into buckets of equal size depending on the
* range [min, max] and assign X to the bucket that contains the number generated
* by SFMT(). This equals to modulo computation and is not satisfying:
* If the buckets don't divide the universe equally, because the bucket size is not
* a divisor of 2, there will be a range in the universe that is biased because one
* bucket is too small thus will be chosen less equally!
*
* This is solved by rejection sampling:
* As SFMT() is assumed to be unbiased, we are allowed to ignore those random numbers
* from SFMT() that would force us to have an unequal bucket and generate new random
* numbers until one number fits into one of the other buckets.
* This can be compared to an ideal six sided die that is rolled until only sides
* 1-5 show up, while 6 represents something that you don't want. So you basically roll
* a five sided die.
*
* Note: If you replace the SFMT RNG with some other rand() function in the future,
* then you _need_ to change the UINT64_MAX constant to the largest possible random
* number which can be created by the new rand() function. This value is often defined
* in a RAND_MAX constant.
* Otherwise you will probably skew the outcome of the rand() method or worsen the
* performance of the application.
*/
unsigned int RNG_SFMT::cdf(unsigned int min, unsigned int max)
{
// This all makes no sense if min > max, which should never happen.
if(min > max) {
throw std::invalid_argument(
QString("Invalid bounds for RNG: min > max! Values were: min = " +
QString::number(min) + ", max = " +
QString::number(max)).toStdString());
// at this point, the method exits. No return value is needed, because
// basically the exception itself is returned.
}
// First compute the diameter (aka size, length) of the [min, max] interval
const unsigned int diameter = max - min + 1;
// Compute how many buckets (each in size of the diameter) will fit into the
// universe.
// If the division has a remainder, the result is floored automatically.
const uint64_t buckets = UINT64_MAX / diameter;
// Compute the last valid random number. All numbers beyond have to be ignored.
// If there was no remainder in the previous step, limit is equal to UINT64_MAX.
const uint64_t limit = diameter * buckets;
uint64_t rand;
// To make the random number generation thread-safe, a mutex is created around
// the generation. Outside of the loop of course, to avoid lock/unlock overhead.
mutex.lock();
do {
rand = sfmt_genrand_uint64(&sfmt);
} while (rand >= limit);
mutex.unlock();
// Now determine the bucket containing the SFMT() random number and after adding
// the lower bound, a random number from [min, max] can be returned.
return (unsigned int) (rand / buckets + min);
}

View file

@ -1,16 +1,40 @@
#ifndef RNG_SFMT_H
#define RNG_SFMT_H
#include "rng_abstract.h"
#include <climits>
#include <QMutex>
#include "sfmt/SFMT.h"
#include "rng_abstract.h"
/**
* This class encapsulates a state of the art PRNG and can be used
* to return uniformly distributed integer random numbers from a range [min, max].
* Though technically possible, min must be >= 0 and max should always be > 0.
* If max < 0 and min == 0 it is assumed that rand() % -max is wanted and the result will
* be -rand(0, -max).
* This is the only exception to the rule that !(min > max) and is actually unused in
* Cockatrice.
*
* Technical details:
* The RNG uses the SIMD-oriented Fast Mersenne Twister code v1.4.1 from
* http://www.math.sci.hiroshima-u.ac.jp/~%20m-mat/MT/SFMT/index.html
* The SFMT RNG creates unsigned int 64bit pseudo random numbers.
*
* These are mapped to values from the interval [min, max] without bias by using Knuth's
* "Algorithm S (Selection sampling technique)" from "The Art of Computer Programming 3rd
* Edition Volume 2 / Seminumerical Algorithms".
*/
class RNG_SFMT : public RNG_Abstract {
Q_OBJECT
private:
QMutex mutex;
sfmt_t sfmt;
// The discrete cumulative distribution function for the RNG
unsigned int cdf(unsigned int min, unsigned int max);
public:
RNG_SFMT(QObject *parent = 0);
unsigned int getNumber(unsigned int min, unsigned int max);
unsigned int rand(int min, int max);
};
#endif

View file

@ -0,0 +1,2 @@
#include "server_arrowtarget.h"

View file

@ -26,7 +26,7 @@
#include "pb/command_move_card.pb.h"
Server_CardZone::Server_CardZone(Server_Player *_player, const QString &_name, bool _has_coords, ServerInfo_Zone::ZoneType _type)
: player(_player),
: player(_player),
name(_name),
has_coords(_has_coords),
type(_type),
@ -37,255 +37,257 @@ Server_CardZone::Server_CardZone(Server_Player *_player, const QString &_name, b
Server_CardZone::~Server_CardZone()
{
qDebug() << "Server_CardZone destructor:" << name;
clear();
qDebug() << "Server_CardZone destructor:" << name;
clear();
}
void Server_CardZone::shuffle()
{
QList<Server_Card *> temp;
for (int i = cards.size(); i; i--)
temp.append(cards.takeAt(rng->getNumber(0, i - 1)));
cards = temp;
playersWithWritePermission.clear();
// Size 0 or 1 decks are sorted
if (cards.size() < 2) return;
for (int i = cards.size() - 1; i > 0; i--){
int j = rng->rand(0, i);
cards.swap(j,i);
}
playersWithWritePermission.clear();
}
void Server_CardZone::removeCardFromCoordMap(Server_Card *card, int oldX, int oldY)
{
if (oldX < 0)
return;
const int baseX = (oldX / 3) * 3;
QMap<int, Server_Card *> &coordMap = coordinateMap[oldY];
if (coordMap.contains(baseX) && coordMap.contains(baseX + 1) && coordMap.contains(baseX + 2))
// If the removal of this card has opened up a previously full pile...
freePilesMap[oldY].insert(coordMap.value(baseX)->getName(), baseX);
coordMap.remove(oldX);
if (!(coordMap.contains(baseX) && coordMap.value(baseX)->getName() == card->getName()) && !(coordMap.contains(baseX + 1) && coordMap.value(baseX + 1)->getName() == card->getName()) && !(coordMap.contains(baseX + 2) && coordMap.value(baseX + 2)->getName() == card->getName()))
// If this card was the last one with this name...
freePilesMap[oldY].remove(card->getName(), baseX);
if (!coordMap.contains(baseX) && !coordMap.contains(baseX + 1) && !coordMap.contains(baseX + 2)) {
// If the removal of this card has freed a whole pile, i.e. it was the last card in it...
if (baseX < freeSpaceMap[oldY])
freeSpaceMap[oldY] = baseX;
}
if (oldX < 0)
return;
const int baseX = (oldX / 3) * 3;
QMap<int, Server_Card *> &coordMap = coordinateMap[oldY];
if (coordMap.contains(baseX) && coordMap.contains(baseX + 1) && coordMap.contains(baseX + 2))
// If the removal of this card has opened up a previously full pile...
freePilesMap[oldY].insert(coordMap.value(baseX)->getName(), baseX);
coordMap.remove(oldX);
if (!(coordMap.contains(baseX) && coordMap.value(baseX)->getName() == card->getName()) && !(coordMap.contains(baseX + 1) && coordMap.value(baseX + 1)->getName() == card->getName()) && !(coordMap.contains(baseX + 2) && coordMap.value(baseX + 2)->getName() == card->getName()))
// If this card was the last one with this name...
freePilesMap[oldY].remove(card->getName(), baseX);
if (!coordMap.contains(baseX) && !coordMap.contains(baseX + 1) && !coordMap.contains(baseX + 2)) {
// If the removal of this card has freed a whole pile, i.e. it was the last card in it...
if (baseX < freeSpaceMap[oldY])
freeSpaceMap[oldY] = baseX;
}
}
void Server_CardZone::insertCardIntoCoordMap(Server_Card *card, int x, int y)
{
if (x < 0)
return;
coordinateMap[y].insert(x, card);
if (!(x % 3)) {
if (!freePilesMap[y].contains(card->getName(), x) && card->getAttachedCards().isEmpty())
freePilesMap[y].insert(card->getName(), x);
if (freeSpaceMap[y] == x) {
int nextFreeX = x;
do {
nextFreeX += 3;
} while (coordinateMap[y].contains(nextFreeX) || coordinateMap[y].contains(nextFreeX + 1) || coordinateMap[y].contains(nextFreeX + 2));
freeSpaceMap[y] = nextFreeX;
}
} else if (!((x - 2) % 3)) {
const int baseX = (x / 3) * 3;
freePilesMap[y].remove(coordinateMap[y].value(baseX)->getName(), baseX);
}
if (x < 0)
return;
coordinateMap[y].insert(x, card);
if (!(x % 3)) {
if (!freePilesMap[y].contains(card->getName(), x) && card->getAttachedCards().isEmpty())
freePilesMap[y].insert(card->getName(), x);
if (freeSpaceMap[y] == x) {
int nextFreeX = x;
do {
nextFreeX += 3;
} while (coordinateMap[y].contains(nextFreeX) || coordinateMap[y].contains(nextFreeX + 1) || coordinateMap[y].contains(nextFreeX + 2));
freeSpaceMap[y] = nextFreeX;
}
} else if (!((x - 2) % 3)) {
const int baseX = (x / 3) * 3;
freePilesMap[y].remove(coordinateMap[y].value(baseX)->getName(), baseX);
}
}
int Server_CardZone::removeCard(Server_Card *card)
{
int index = cards.indexOf(card);
cards.removeAt(index);
if (has_coords)
removeCardFromCoordMap(card, card->getX(), card->getY());
card->setZone(0);
return index;
int index = cards.indexOf(card);
cards.removeAt(index);
if (has_coords)
removeCardFromCoordMap(card, card->getX(), card->getY());
card->setZone(0);
return index;
}
Server_Card *Server_CardZone::getCard(int id, int *position, bool remove)
{
if (type != ServerInfo_Zone::HiddenZone) {
for (int i = 0; i < cards.size(); ++i) {
Server_Card *tmp = cards[i];
if (tmp->getId() == id) {
if (position)
*position = i;
if (remove) {
cards.removeAt(i);
tmp->setZone(0);
}
return tmp;
}
}
return NULL;
} else {
if ((id >= cards.size()) || (id < 0))
return NULL;
Server_Card *tmp = cards[id];
if (position)
*position = id;
if (remove) {
cards.removeAt(id);
tmp->setZone(0);
}
return tmp;
}
if (type != ServerInfo_Zone::HiddenZone) {
for (int i = 0; i < cards.size(); ++i) {
Server_Card *tmp = cards[i];
if (tmp->getId() == id) {
if (position)
*position = i;
if (remove) {
cards.removeAt(i);
tmp->setZone(0);
}
return tmp;
}
}
return NULL;
} else {
if ((id >= cards.size()) || (id < 0))
return NULL;
Server_Card *tmp = cards[id];
if (position)
*position = id;
if (remove) {
cards.removeAt(id);
tmp->setZone(0);
}
return tmp;
}
}
int Server_CardZone::getFreeGridColumn(int x, int y, const QString &cardName) const
{
const QMap<int, Server_Card *> &coordMap = coordinateMap.value(y);
if (x == -1) {
if (freePilesMap[y].contains(cardName)) {
x = (freePilesMap[y].value(cardName) / 3) * 3;
if (!coordMap.contains(x))
return x;
else if (!coordMap.contains(x + 1))
return x + 1;
else
return x + 2;
}
} else if (x >= 0) {
int resultX = 0;
x = (x / 3) * 3;
if (!coordMap.contains(x))
resultX = x;
else if (!coordMap.value(x)->getAttachedCards().isEmpty()) {
resultX = x;
x = -1;
} else if (!coordMap.contains(x + 1))
resultX = x + 1;
else if (!coordMap.contains(x + 2))
resultX = x + 2;
else {
resultX = x;
x = -1;
}
if (x < 0)
while (coordMap.contains(resultX))
resultX += 3;
const QMap<int, Server_Card *> &coordMap = coordinateMap.value(y);
if (x == -1) {
if (freePilesMap[y].contains(cardName)) {
x = (freePilesMap[y].value(cardName) / 3) * 3;
if (!coordMap.contains(x))
return x;
else if (!coordMap.contains(x + 1))
return x + 1;
else
return x + 2;
}
} else if (x >= 0) {
int resultX = 0;
x = (x / 3) * 3;
if (!coordMap.contains(x))
resultX = x;
else if (!coordMap.value(x)->getAttachedCards().isEmpty()) {
resultX = x;
x = -1;
} else if (!coordMap.contains(x + 1))
resultX = x + 1;
else if (!coordMap.contains(x + 2))
resultX = x + 2;
else {
resultX = x;
x = -1;
}
if (x < 0)
while (coordMap.contains(resultX))
resultX += 3;
return resultX;
}
return freeSpaceMap[y];
return resultX;
}
return freeSpaceMap[y];
}
bool Server_CardZone::isColumnStacked(int x, int y) const
{
if (!has_coords)
return false;
return coordinateMap[y].contains((x / 3) * 3 + 1);
if (!has_coords)
return false;
return coordinateMap[y].contains((x / 3) * 3 + 1);
}
bool Server_CardZone::isColumnEmpty(int x, int y) const
{
if (!has_coords)
return true;
return !coordinateMap[y].contains((x / 3) * 3);
if (!has_coords)
return true;
return !coordinateMap[y].contains((x / 3) * 3);
}
void Server_CardZone::moveCardInRow(GameEventStorage &ges, Server_Card *card, int x, int y)
{
CardToMove *cardToMove = new CardToMove;
cardToMove->set_card_id(card->getId());
player->moveCard(ges, this, QList<const CardToMove *>() << cardToMove, this, x, y, false, false);
delete cardToMove;
CardToMove *cardToMove = new CardToMove;
cardToMove->set_card_id(card->getId());
player->moveCard(ges, this, QList<const CardToMove *>() << cardToMove, this, x, y, false, false);
delete cardToMove;
}
void Server_CardZone::fixFreeSpaces(GameEventStorage &ges)
{
if (!has_coords)
return;
QSet<QPair<int, int> > placesToLook;
for (int i = 0; i < cards.size(); ++i)
placesToLook.insert(QPair<int, int>((cards[i]->getX() / 3) * 3, cards[i]->getY()));
QSetIterator<QPair<int, int> > placeIterator(placesToLook);
while (placeIterator.hasNext()) {
const QPair<int, int> &foo = placeIterator.next();
int baseX = foo.first;
int y = foo.second;
if (!coordinateMap[y].contains(baseX)) {
if (coordinateMap[y].contains(baseX + 1))
moveCardInRow(ges, coordinateMap[y].value(baseX + 1), baseX, y);
else if (coordinateMap[y].contains(baseX + 2)) {
moveCardInRow(ges, coordinateMap[y].value(baseX + 2), baseX, y);
continue;
} else
continue;
}
if (!coordinateMap[y].contains(baseX + 1) && coordinateMap[y].contains(baseX + 2))
moveCardInRow(ges, coordinateMap[y].value(baseX + 2), baseX + 1, y);
}
if (!has_coords)
return;
QSet<QPair<int, int> > placesToLook;
for (int i = 0; i < cards.size(); ++i)
placesToLook.insert(QPair<int, int>((cards[i]->getX() / 3) * 3, cards[i]->getY()));
QSetIterator<QPair<int, int> > placeIterator(placesToLook);
while (placeIterator.hasNext()) {
const QPair<int, int> &foo = placeIterator.next();
int baseX = foo.first;
int y = foo.second;
if (!coordinateMap[y].contains(baseX)) {
if (coordinateMap[y].contains(baseX + 1))
moveCardInRow(ges, coordinateMap[y].value(baseX + 1), baseX, y);
else if (coordinateMap[y].contains(baseX + 2)) {
moveCardInRow(ges, coordinateMap[y].value(baseX + 2), baseX, y);
continue;
} else
continue;
}
if (!coordinateMap[y].contains(baseX + 1) && coordinateMap[y].contains(baseX + 2))
moveCardInRow(ges, coordinateMap[y].value(baseX + 2), baseX + 1, y);
}
}
void Server_CardZone::updateCardCoordinates(Server_Card *card, int oldX, int oldY)
{
if (!has_coords)
return;
if (oldX != -1)
removeCardFromCoordMap(card, oldX, oldY);
insertCardIntoCoordMap(card, card->getX(), card->getY());
if (!has_coords)
return;
if (oldX != -1)
removeCardFromCoordMap(card, oldX, oldY);
insertCardIntoCoordMap(card, card->getX(), card->getY());
}
void Server_CardZone::insertCard(Server_Card *card, int x, int y)
{
if (hasCoords()) {
card->setCoords(x, y);
cards.append(card);
insertCardIntoCoordMap(card, x, y);
} else {
card->setCoords(0, 0);
if (x == -1)
cards.append(card);
else
cards.insert(x, card);
}
card->setZone(this);
if (hasCoords()) {
card->setCoords(x, y);
cards.append(card);
insertCardIntoCoordMap(card, x, y);
} else {
card->setCoords(0, 0);
if (x == -1)
cards.append(card);
else
cards.insert(x, card);
}
card->setZone(this);
}
void Server_CardZone::clear()
{
for (int i = 0; i < cards.size(); i++)
delete cards.at(i);
cards.clear();
coordinateMap.clear();
freePilesMap.clear();
freeSpaceMap.clear();
playersWithWritePermission.clear();
for (int i = 0; i < cards.size(); i++)
delete cards.at(i);
cards.clear();
coordinateMap.clear();
freePilesMap.clear();
freeSpaceMap.clear();
playersWithWritePermission.clear();
}
void Server_CardZone::addWritePermission(int playerId)
{
playersWithWritePermission.insert(playerId);
playersWithWritePermission.insert(playerId);
}
void Server_CardZone::getInfo(ServerInfo_Zone *info, Server_Player *playerWhosAsking, bool omniscient)
{
info->set_name(name.toStdString());
info->set_type(type);
info->set_with_coords(has_coords);
info->set_card_count(cards.size());
info->set_always_reveal_top_card(alwaysRevealTopCard);
if (
(((playerWhosAsking == player) || omniscient) && (type != ServerInfo_Zone::HiddenZone))
|| ((playerWhosAsking != player) && (type == ServerInfo_Zone::PublicZone))
) {
QListIterator<Server_Card *> cardIterator(cards);
while (cardIterator.hasNext())
cardIterator.next()->getInfo(info->add_card_list());
}
info->set_name(name.toStdString());
info->set_type(type);
info->set_with_coords(has_coords);
info->set_card_count(cards.size());
info->set_always_reveal_top_card(alwaysRevealTopCard);
if (
(((playerWhosAsking == player) || omniscient) && (type != ServerInfo_Zone::HiddenZone))
|| ((playerWhosAsking != player) && (type == ServerInfo_Zone::PublicZone))
) {
QListIterator<Server_Card *> cardIterator(cards);
while (cardIterator.hasNext())
cardIterator.next()->getInfo(info->add_card_list());
}
}

View file

@ -0,0 +1,2 @@
#include "server_database_interface.h"

View file

@ -844,7 +844,7 @@ Response::ResponseCode Server_Player::cmdRollDie(const Command_RollDie &cmd, Res
Event_RollDie event;
event.set_sides(cmd.sides());
event.set_value(rng->getNumber(1, cmd.sides()));
event.set_value(rng->rand(1, cmd.sides()));
ges.enqueueGameEvent(event, playerId);
return Response::RespOk;
@ -1524,7 +1524,7 @@ Response::ResponseCode Server_Player::cmdRevealCards(const Command_RevealCards &
else if (cmd.card_id() == -2) {
if (zone->getCards().isEmpty())
return Response::RespContextError;
cardsToReveal.append(zone->getCards().at(rng->getNumber(0, zone->getCards().size() - 1)));
cardsToReveal.append(zone->getCards().at(rng->rand(0, zone->getCards().size() - 1)));
} else {
Server_Card *card = zone->getCard(cmd.card_id());
if (!card)

View file

@ -1,5 +1,8 @@
Copyright (c) 2006,2007 Mutsuo Saito, Makoto Matsumoto and Hiroshima
University. All rights reserved.
University.
Copyright (c) 2012 Mutsuo Saito, Makoto Matsumoto, Hiroshima University
and The University of Tokyo.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
@ -11,10 +14,10 @@ met:
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 the Hiroshima University nor the names of
its contributors may be used to endorse or promote products
derived from this software without specific prior written
permission.
* Neither the names of Hiroshima University, The University of
Tokyo 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

164
common/sfmt/SFMT-common.h Normal file
View file

@ -0,0 +1,164 @@
#pragma once
/**
* @file SFMT-common.h
*
* @brief SIMD oriented Fast Mersenne Twister(SFMT) pseudorandom
* number generator with jump function. This file includes common functions
* used in random number generation and jump.
*
* @author Mutsuo Saito (Hiroshima University)
* @author Makoto Matsumoto (The University of Tokyo)
*
* Copyright (C) 2006, 2007 Mutsuo Saito, Makoto Matsumoto and Hiroshima
* University.
* Copyright (C) 2012 Mutsuo Saito, Makoto Matsumoto, Hiroshima
* University and The University of Tokyo.
* All rights reserved.
*
* The 3-clause BSD License is applied to this software, see
* LICENSE.txt
*/
#ifndef SFMT_COMMON_H
#define SFMT_COMMON_H
#if defined(__cplusplus)
extern "C" {
#endif
#include "SFMT.h"
inline static void do_recursion(w128_t * r, w128_t * a, w128_t * b,
w128_t * c, w128_t * d);
inline static void rshift128(w128_t *out, w128_t const *in, int shift);
inline static void lshift128(w128_t *out, w128_t const *in, int shift);
/**
* This function simulates SIMD 128-bit right shift by the standard C.
* The 128-bit integer given in in is shifted by (shift * 8) bits.
* This function simulates the LITTLE ENDIAN SIMD.
* @param out the output of this function
* @param in the 128-bit data to be shifted
* @param shift the shift value
*/
#ifdef ONLY64
inline static void rshift128(w128_t *out, w128_t const *in, int shift) {
uint64_t th, tl, oh, ol;
th = ((uint64_t)in->u[2] << 32) | ((uint64_t)in->u[3]);
tl = ((uint64_t)in->u[0] << 32) | ((uint64_t)in->u[1]);
oh = th >> (shift * 8);
ol = tl >> (shift * 8);
ol |= th << (64 - shift * 8);
out->u[0] = (uint32_t)(ol >> 32);
out->u[1] = (uint32_t)ol;
out->u[2] = (uint32_t)(oh >> 32);
out->u[3] = (uint32_t)oh;
}
#else
inline static void rshift128(w128_t *out, w128_t const *in, int shift)
{
uint64_t th, tl, oh, ol;
th = ((uint64_t)in->u[3] << 32) | ((uint64_t)in->u[2]);
tl = ((uint64_t)in->u[1] << 32) | ((uint64_t)in->u[0]);
oh = th >> (shift * 8);
ol = tl >> (shift * 8);
ol |= th << (64 - shift * 8);
out->u[1] = (uint32_t)(ol >> 32);
out->u[0] = (uint32_t)ol;
out->u[3] = (uint32_t)(oh >> 32);
out->u[2] = (uint32_t)oh;
}
#endif
/**
* This function simulates SIMD 128-bit left shift by the standard C.
* The 128-bit integer given in in is shifted by (shift * 8) bits.
* This function simulates the LITTLE ENDIAN SIMD.
* @param out the output of this function
* @param in the 128-bit data to be shifted
* @param shift the shift value
*/
#ifdef ONLY64
inline static void lshift128(w128_t *out, w128_t const *in, int shift) {
uint64_t th, tl, oh, ol;
th = ((uint64_t)in->u[2] << 32) | ((uint64_t)in->u[3]);
tl = ((uint64_t)in->u[0] << 32) | ((uint64_t)in->u[1]);
oh = th << (shift * 8);
ol = tl << (shift * 8);
oh |= tl >> (64 - shift * 8);
out->u[0] = (uint32_t)(ol >> 32);
out->u[1] = (uint32_t)ol;
out->u[2] = (uint32_t)(oh >> 32);
out->u[3] = (uint32_t)oh;
}
#else
inline static void lshift128(w128_t *out, w128_t const *in, int shift)
{
uint64_t th, tl, oh, ol;
th = ((uint64_t)in->u[3] << 32) | ((uint64_t)in->u[2]);
tl = ((uint64_t)in->u[1] << 32) | ((uint64_t)in->u[0]);
oh = th << (shift * 8);
ol = tl << (shift * 8);
oh |= tl >> (64 - shift * 8);
out->u[1] = (uint32_t)(ol >> 32);
out->u[0] = (uint32_t)ol;
out->u[3] = (uint32_t)(oh >> 32);
out->u[2] = (uint32_t)oh;
}
#endif
/**
* This function represents the recursion formula.
* @param r output
* @param a a 128-bit part of the internal state array
* @param b a 128-bit part of the internal state array
* @param c a 128-bit part of the internal state array
* @param d a 128-bit part of the internal state array
*/
#ifdef ONLY64
inline static void do_recursion(w128_t *r, w128_t *a, w128_t *b, w128_t *c,
w128_t *d) {
w128_t x;
w128_t y;
lshift128(&x, a, SFMT_SL2);
rshift128(&y, c, SFMT_SR2);
r->u[0] = a->u[0] ^ x.u[0] ^ ((b->u[0] >> SFMT_SR1) & SFMT_MSK2) ^ y.u[0]
^ (d->u[0] << SFMT_SL1);
r->u[1] = a->u[1] ^ x.u[1] ^ ((b->u[1] >> SFMT_SR1) & SFMT_MSK1) ^ y.u[1]
^ (d->u[1] << SFMT_SL1);
r->u[2] = a->u[2] ^ x.u[2] ^ ((b->u[2] >> SFMT_SR1) & SFMT_MSK4) ^ y.u[2]
^ (d->u[2] << SFMT_SL1);
r->u[3] = a->u[3] ^ x.u[3] ^ ((b->u[3] >> SFMT_SR1) & SFMT_MSK3) ^ y.u[3]
^ (d->u[3] << SFMT_SL1);
}
#else
inline static void do_recursion(w128_t *r, w128_t *a, w128_t *b,
w128_t *c, w128_t *d)
{
w128_t x;
w128_t y;
lshift128(&x, a, SFMT_SL2);
rshift128(&y, c, SFMT_SR2);
r->u[0] = a->u[0] ^ x.u[0] ^ ((b->u[0] >> SFMT_SR1) & SFMT_MSK1)
^ y.u[0] ^ (d->u[0] << SFMT_SL1);
r->u[1] = a->u[1] ^ x.u[1] ^ ((b->u[1] >> SFMT_SR1) & SFMT_MSK2)
^ y.u[1] ^ (d->u[1] << SFMT_SL1);
r->u[2] = a->u[2] ^ x.u[2] ^ ((b->u[2] >> SFMT_SR1) & SFMT_MSK3)
^ y.u[2] ^ (d->u[2] << SFMT_SL1);
r->u[3] = a->u[3] ^ x.u[3] ^ ((b->u[3] >> SFMT_SR1) & SFMT_MSK4)
^ y.u[3] ^ (d->u[3] << SFMT_SL1);
}
#endif
#endif
#if defined(__cplusplus)
}
#endif

View file

@ -1,95 +1,96 @@
#pragma once
#ifndef SFMT_PARAMS_H
#define SFMT_PARAMS_H
#if !defined(MEXP)
#ifdef __GNUC__
#warning "MEXP is not defined. I assume MEXP is 19937."
#if !defined(SFMT_MEXP)
#if defined(__GNUC__) && !defined(__ICC)
#warning "SFMT_MEXP is not defined. I assume MEXP is 19937."
#endif
#define MEXP 19937
#define SFMT_MEXP 19937
#endif
/*-----------------
BASIC DEFINITIONS
-----------------*/
/** Mersenne Exponent. The period of the sequence
/** Mersenne Exponent. The period of the sequence
* is a multiple of 2^MEXP-1.
* #define MEXP 19937 */
* #define SFMT_MEXP 19937 */
/** SFMT generator has an internal state array of 128-bit integers,
* and N is its size. */
#define N (MEXP / 128 + 1)
#define SFMT_N (SFMT_MEXP / 128 + 1)
/** N32 is the size of internal state array when regarded as an array
* of 32-bit integers.*/
#define N32 (N * 4)
#define SFMT_N32 (SFMT_N * 4)
/** N64 is the size of internal state array when regarded as an array
* of 64-bit integers.*/
#define N64 (N * 2)
#define SFMT_N64 (SFMT_N * 2)
/*----------------------
the parameters of SFMT
following definitions are in paramsXXXX.h file.
----------------------*/
/** the pick up position of the array.
#define POS1 122
#define SFMT_POS1 122
*/
/** the parameter of shift left as four 32-bit registers.
#define SL1 18
#define SFMT_SL1 18
*/
/** the parameter of shift left as one 128-bit register.
* The 128-bit integer is shifted by (SL2 * 8) bits.
#define SL2 1
/** the parameter of shift left as one 128-bit register.
* The 128-bit integer is shifted by (SFMT_SL2 * 8) bits.
#define SFMT_SL2 1
*/
/** the parameter of shift right as four 32-bit registers.
#define SR1 11
#define SFMT_SR1 11
*/
/** the parameter of shift right as one 128-bit register.
* The 128-bit integer is shifted by (SL2 * 8) bits.
#define SR2 1
/** the parameter of shift right as one 128-bit register.
* The 128-bit integer is shifted by (SFMT_SL2 * 8) bits.
#define SFMT_SR21 1
*/
/** A bitmask, used in the recursion. These parameters are introduced
* to break symmetry of SIMD.
#define MSK1 0xdfffffefU
#define MSK2 0xddfecb7fU
#define MSK3 0xbffaffffU
#define MSK4 0xbffffff6U
#define SFMT_MSK1 0xdfffffefU
#define SFMT_MSK2 0xddfecb7fU
#define SFMT_MSK3 0xbffaffffU
#define SFMT_MSK4 0xbffffff6U
*/
/** These definitions are part of a 128-bit period certification vector.
#define PARITY1 0x00000001U
#define PARITY2 0x00000000U
#define PARITY3 0x00000000U
#define PARITY4 0xc98e126aU
#define SFMT_PARITY1 0x00000001U
#define SFMT_PARITY2 0x00000000U
#define SFMT_PARITY3 0x00000000U
#define SFMT_PARITY4 0xc98e126aU
*/
#if MEXP == 607
#if SFMT_MEXP == 607
#include "SFMT-params607.h"
#elif MEXP == 1279
#elif SFMT_MEXP == 1279
#include "SFMT-params1279.h"
#elif MEXP == 2281
#elif SFMT_MEXP == 2281
#include "SFMT-params2281.h"
#elif MEXP == 4253
#elif SFMT_MEXP == 4253
#include "SFMT-params4253.h"
#elif MEXP == 11213
#elif SFMT_MEXP == 11213
#include "SFMT-params11213.h"
#elif MEXP == 19937
#elif SFMT_MEXP == 19937
#include "SFMT-params19937.h"
#elif MEXP == 44497
#elif SFMT_MEXP == 44497
#include "SFMT-params44497.h"
#elif MEXP == 86243
#elif SFMT_MEXP == 86243
#include "SFMT-params86243.h"
#elif MEXP == 132049
#elif SFMT_MEXP == 132049
#include "SFMT-params132049.h"
#elif MEXP == 216091
#elif SFMT_MEXP == 216091
#include "SFMT-params216091.h"
#else
#ifdef __GNUC__
#error "MEXP is not valid."
#undef MEXP
#if defined(__GNUC__) && !defined(__ICC)
#error "SFMT_MEXP is not valid."
#undef SFMT_MEXP
#else
#undef MEXP
#undef SFMT_MEXP
#endif
#endif

View file

@ -1,46 +1,50 @@
#pragma once
#ifndef SFMT_PARAMS19937_H
#define SFMT_PARAMS19937_H
#define POS1 122
#define SL1 18
#define SL2 1
#define SR1 11
#define SR2 1
#define MSK1 0xdfffffefU
#define MSK2 0xddfecb7fU
#define MSK3 0xbffaffffU
#define MSK4 0xbffffff6U
#define PARITY1 0x00000001U
#define PARITY2 0x00000000U
#define PARITY3 0x00000000U
#define PARITY4 0x13c9e684U
#define SFMT_POS1 122
#define SFMT_SL1 18
#define SFMT_SL2 1
#define SFMT_SR1 11
#define SFMT_SR2 1
#define SFMT_MSK1 0xdfffffefU
#define SFMT_MSK2 0xddfecb7fU
#define SFMT_MSK3 0xbffaffffU
#define SFMT_MSK4 0xbffffff6U
#define SFMT_PARITY1 0x00000001U
#define SFMT_PARITY2 0x00000000U
#define SFMT_PARITY3 0x00000000U
#define SFMT_PARITY4 0x13c9e684U
/* PARAMETERS FOR ALTIVEC */
#if defined(__APPLE__) /* For OSX */
#define ALTI_SL1 (vector unsigned int)(SL1, SL1, SL1, SL1)
#define ALTI_SR1 (vector unsigned int)(SR1, SR1, SR1, SR1)
#define ALTI_MSK (vector unsigned int)(MSK1, MSK2, MSK3, MSK4)
#define ALTI_MSK64 \
(vector unsigned int)(MSK2, MSK1, MSK4, MSK3)
#define ALTI_SL2_PERM \
#define SFMT_ALTI_SL1 \
(vector unsigned int)(SFMT_SL1, SFMT_SL1, SFMT_SL1, SFMT_SL1)
#define SFMT_ALTI_SR1 \
(vector unsigned int)(SFMT_SR1, SFMT_SR1, SFMT_SR1, SFMT_SR1)
#define SFMT_ALTI_MSK \
(vector unsigned int)(SFMT_MSK1, SFMT_MSK2, SFMT_MSK3, SFMT_MSK4)
#define SFMT_ALTI_MSK64 \
(vector unsigned int)(SFMT_MSK2, SFMT_MSK1, SFMT_MSK4, SFMT_MSK3)
#define SFMT_ALTI_SL2_PERM \
(vector unsigned char)(1,2,3,23,5,6,7,0,9,10,11,4,13,14,15,8)
#define ALTI_SL2_PERM64 \
#define SFMT_ALTI_SL2_PERM64 \
(vector unsigned char)(1,2,3,4,5,6,7,31,9,10,11,12,13,14,15,0)
#define ALTI_SR2_PERM \
#define SFMT_ALTI_SR2_PERM \
(vector unsigned char)(7,0,1,2,11,4,5,6,15,8,9,10,17,12,13,14)
#define ALTI_SR2_PERM64 \
#define SFMT_ALTI_SR2_PERM64 \
(vector unsigned char)(15,0,1,2,3,4,5,6,17,8,9,10,11,12,13,14)
#else /* For OTHER OSs(Linux?) */
#define ALTI_SL1 {SL1, SL1, SL1, SL1}
#define ALTI_SR1 {SR1, SR1, SR1, SR1}
#define ALTI_MSK {MSK1, MSK2, MSK3, MSK4}
#define ALTI_MSK64 {MSK2, MSK1, MSK4, MSK3}
#define ALTI_SL2_PERM {1,2,3,23,5,6,7,0,9,10,11,4,13,14,15,8}
#define ALTI_SL2_PERM64 {1,2,3,4,5,6,7,31,9,10,11,12,13,14,15,0}
#define ALTI_SR2_PERM {7,0,1,2,11,4,5,6,15,8,9,10,17,12,13,14}
#define ALTI_SR2_PERM64 {15,0,1,2,3,4,5,6,17,8,9,10,11,12,13,14}
#define SFMT_ALTI_SL1 {SFMT_SL1, SFMT_SL1, SFMT_SL1, SFMT_SL1}
#define SFMT_ALTI_SR1 {SFMT_SR1, SFMT_SR1, SFMT_SR1, SFMT_SR1}
#define SFMT_ALTI_MSK {SFMT_MSK1, SFMT_MSK2, SFMT_MSK3, SFMT_MSK4}
#define SFMT_ALTI_MSK64 {SFMT_MSK2, SFMT_MSK1, SFMT_MSK4, SFMT_MSK3}
#define SFMT_ALTI_SL2_PERM {1,2,3,23,5,6,7,0,9,10,11,4,13,14,15,8}
#define SFMT_ALTI_SL2_PERM64 {1,2,3,4,5,6,7,31,9,10,11,12,13,14,15,0}
#define SFMT_ALTI_SR2_PERM {7,0,1,2,11,4,5,6,15,8,9,10,17,12,13,14}
#define SFMT_ALTI_SR2_PERM64 {15,0,1,2,3,4,5,6,17,8,9,10,11,12,13,14}
#endif /* For OSX */
#define IDSTR "SFMT-19937:122-18-1-11-1:dfffffef-ddfecb7f-bffaffff-bffffff6"
#define SFMT_IDSTR "SFMT-19937:122-18-1-11-1:dfffffef-ddfecb7f-bffaffff-bffffff6"
#endif /* SFMT_PARAMS19937_H */

View file

@ -1,19 +1,31 @@
/**
/**
* @file SFMT.c
* @brief SIMD oriented Fast Mersenne Twister(SFMT)
*
* @author Mutsuo Saito (Hiroshima University)
* @author Makoto Matsumoto (Hiroshima University)
*
* Copyright (C) 2006,2007 Mutsuo Saito, Makoto Matsumoto and Hiroshima
* University. All rights reserved.
* Copyright (C) 2006, 2007 Mutsuo Saito, Makoto Matsumoto and Hiroshima
* University.
* Copyright (C) 2012 Mutsuo Saito, Makoto Matsumoto, Hiroshima
* University and The University of Tokyo.
* Copyright (C) 2013 Mutsuo Saito, Makoto Matsumoto and Hiroshima
* University.
* All rights reserved.
*
* The new BSD License is applied to this software, see LICENSE.txt
* The 3-clause BSD License is applied to this software, see
* LICENSE.txt
*/
#if defined(__cplusplus)
extern "C" {
#endif
#include <string.h>
#include <assert.h>
#include "SFMT.h"
#include "SFMT-params.h"
#include "SFMT-common.h"
#if defined(__BIG_ENDIAN__) && !defined(__amd64) && !defined(BIG_ENDIAN64)
#define BIG_ENDIAN64 1
@ -27,74 +39,20 @@
#endif
#undef ONLY64
#endif
/*------------------------------------------------------
128-bit SIMD data type for Altivec, SSE2 or standard C
------------------------------------------------------*/
#if defined(HAVE_ALTIVEC)
#if !defined(__APPLE__)
#include <altivec.h>
#endif
/** 128-bit data structure */
union W128_T {
vector unsigned int s;
uint32_t u[4];
};
/** 128-bit data type */
typedef union W128_T w128_t;
#elif defined(HAVE_SSE2)
#include <emmintrin.h>
/** 128-bit data structure */
union W128_T {
__m128i si;
uint32_t u[4];
};
/** 128-bit data type */
typedef union W128_T w128_t;
#else
/** 128-bit data structure */
struct W128_T {
uint32_t u[4];
};
/** 128-bit data type */
typedef struct W128_T w128_t;
#endif
/*--------------------------------------
FILE GLOBAL VARIABLES
internal state, index counter and flag
--------------------------------------*/
/** the 128-bit internal state array */
static w128_t sfmt[N];
/** the 32bit integer pointer to the 128-bit internal state array */
static uint32_t *psfmt32 = &sfmt[0].u[0];
#if !defined(BIG_ENDIAN64) || defined(ONLY64)
/** the 64bit integer pointer to the 128-bit internal state array */
static uint64_t *psfmt64 = (uint64_t *)&sfmt[0].u[0];
#endif
/** index counter to the 32-bit internal state array */
static int idx;
/** a flag: it is 0 if and only if the internal state is not yet
* initialized. */
static int initialized = 0;
/** a parity check vector which certificate the period of 2^{MEXP} */
static uint32_t parity[4] = {PARITY1, PARITY2, PARITY3, PARITY4};
/**
* parameters used by sse2.
*/
static const w128_t sse2_param_mask = {{SFMT_MSK1, SFMT_MSK2,
SFMT_MSK3, SFMT_MSK4}};
/*----------------
STATIC FUNCTIONS
----------------*/
inline static int idxof(int i);
inline static void rshift128(w128_t *out, w128_t const *in, int shift);
inline static void lshift128(w128_t *out, w128_t const *in, int shift);
inline static void gen_rand_all(void);
inline static void gen_rand_array(w128_t *array, int size);
inline static void gen_rand_array(sfmt_t * sfmt, w128_t *array, int size);
inline static uint32_t func1(uint32_t x);
inline static uint32_t func2(uint32_t x);
static void period_certification(void);
static void period_certification(sfmt_t * sfmt);
#if defined(BIG_ENDIAN64) && !defined(ONLY64)
inline static void swap(w128_t *array, int size);
#endif
@ -102,11 +60,15 @@ inline static void swap(w128_t *array, int size);
#if defined(HAVE_ALTIVEC)
#include "SFMT-alti.h"
#elif defined(HAVE_SSE2)
#include "SFMT-sse2.h"
#if defined(_MSC_VER)
#include "SFMT-sse2-msc.h"
#else
#include "SFMT-sse2.h"
#endif
#endif
/**
* This function simulate a 64-bit index of LITTLE ENDIAN
* This function simulate a 64-bit index of LITTLE ENDIAN
* in BIG ENDIAN machine.
*/
#ifdef ONLY64
@ -118,190 +80,48 @@ inline static int idxof(int i) {
return i;
}
#endif
/**
* This function simulates SIMD 128-bit right shift by the standard C.
* The 128-bit integer given in in is shifted by (shift * 8) bits.
* This function simulates the LITTLE ENDIAN SIMD.
* @param out the output of this function
* @param in the 128-bit data to be shifted
* @param shift the shift value
*/
#ifdef ONLY64
inline static void rshift128(w128_t *out, w128_t const *in, int shift) {
uint64_t th, tl, oh, ol;
th = ((uint64_t)in->u[2] << 32) | ((uint64_t)in->u[3]);
tl = ((uint64_t)in->u[0] << 32) | ((uint64_t)in->u[1]);
oh = th >> (shift * 8);
ol = tl >> (shift * 8);
ol |= th << (64 - shift * 8);
out->u[0] = (uint32_t)(ol >> 32);
out->u[1] = (uint32_t)ol;
out->u[2] = (uint32_t)(oh >> 32);
out->u[3] = (uint32_t)oh;
}
#else
inline static void rshift128(w128_t *out, w128_t const *in, int shift) {
uint64_t th, tl, oh, ol;
th = ((uint64_t)in->u[3] << 32) | ((uint64_t)in->u[2]);
tl = ((uint64_t)in->u[1] << 32) | ((uint64_t)in->u[0]);
oh = th >> (shift * 8);
ol = tl >> (shift * 8);
ol |= th << (64 - shift * 8);
out->u[1] = (uint32_t)(ol >> 32);
out->u[0] = (uint32_t)ol;
out->u[3] = (uint32_t)(oh >> 32);
out->u[2] = (uint32_t)oh;
}
#endif
/**
* This function simulates SIMD 128-bit left shift by the standard C.
* The 128-bit integer given in in is shifted by (shift * 8) bits.
* This function simulates the LITTLE ENDIAN SIMD.
* @param out the output of this function
* @param in the 128-bit data to be shifted
* @param shift the shift value
*/
#ifdef ONLY64
inline static void lshift128(w128_t *out, w128_t const *in, int shift) {
uint64_t th, tl, oh, ol;
th = ((uint64_t)in->u[2] << 32) | ((uint64_t)in->u[3]);
tl = ((uint64_t)in->u[0] << 32) | ((uint64_t)in->u[1]);
oh = th << (shift * 8);
ol = tl << (shift * 8);
oh |= tl >> (64 - shift * 8);
out->u[0] = (uint32_t)(ol >> 32);
out->u[1] = (uint32_t)ol;
out->u[2] = (uint32_t)(oh >> 32);
out->u[3] = (uint32_t)oh;
}
#else
inline static void lshift128(w128_t *out, w128_t const *in, int shift) {
uint64_t th, tl, oh, ol;
th = ((uint64_t)in->u[3] << 32) | ((uint64_t)in->u[2]);
tl = ((uint64_t)in->u[1] << 32) | ((uint64_t)in->u[0]);
oh = th << (shift * 8);
ol = tl << (shift * 8);
oh |= tl >> (64 - shift * 8);
out->u[1] = (uint32_t)(ol >> 32);
out->u[0] = (uint32_t)ol;
out->u[3] = (uint32_t)(oh >> 32);
out->u[2] = (uint32_t)oh;
}
#endif
/**
* This function represents the recursion formula.
* @param r output
* @param a a 128-bit part of the internal state array
* @param b a 128-bit part of the internal state array
* @param c a 128-bit part of the internal state array
* @param d a 128-bit part of the internal state array
*/
#if (!defined(HAVE_ALTIVEC)) && (!defined(HAVE_SSE2))
#ifdef ONLY64
inline static void do_recursion(w128_t *r, w128_t *a, w128_t *b, w128_t *c,
w128_t *d) {
w128_t x;
w128_t y;
lshift128(&x, a, SL2);
rshift128(&y, c, SR2);
r->u[0] = a->u[0] ^ x.u[0] ^ ((b->u[0] >> SR1) & MSK2) ^ y.u[0]
^ (d->u[0] << SL1);
r->u[1] = a->u[1] ^ x.u[1] ^ ((b->u[1] >> SR1) & MSK1) ^ y.u[1]
^ (d->u[1] << SL1);
r->u[2] = a->u[2] ^ x.u[2] ^ ((b->u[2] >> SR1) & MSK4) ^ y.u[2]
^ (d->u[2] << SL1);
r->u[3] = a->u[3] ^ x.u[3] ^ ((b->u[3] >> SR1) & MSK3) ^ y.u[3]
^ (d->u[3] << SL1);
}
#else
inline static void do_recursion(w128_t *r, w128_t *a, w128_t *b, w128_t *c,
w128_t *d) {
w128_t x;
w128_t y;
lshift128(&x, a, SL2);
rshift128(&y, c, SR2);
r->u[0] = a->u[0] ^ x.u[0] ^ ((b->u[0] >> SR1) & MSK1) ^ y.u[0]
^ (d->u[0] << SL1);
r->u[1] = a->u[1] ^ x.u[1] ^ ((b->u[1] >> SR1) & MSK2) ^ y.u[1]
^ (d->u[1] << SL1);
r->u[2] = a->u[2] ^ x.u[2] ^ ((b->u[2] >> SR1) & MSK3) ^ y.u[2]
^ (d->u[2] << SL1);
r->u[3] = a->u[3] ^ x.u[3] ^ ((b->u[3] >> SR1) & MSK4) ^ y.u[3]
^ (d->u[3] << SL1);
}
#endif
#endif
#if (!defined(HAVE_ALTIVEC)) && (!defined(HAVE_SSE2))
/**
* This function fills the internal state array with pseudorandom
* integers.
*/
inline static void gen_rand_all(void) {
int i;
w128_t *r1, *r2;
r1 = &sfmt[N - 2];
r2 = &sfmt[N - 1];
for (i = 0; i < N - POS1; i++) {
do_recursion(&sfmt[i], &sfmt[i], &sfmt[i + POS1], r1, r2);
r1 = r2;
r2 = &sfmt[i];
}
for (; i < N; i++) {
do_recursion(&sfmt[i], &sfmt[i], &sfmt[i + POS1 - N], r1, r2);
r1 = r2;
r2 = &sfmt[i];
}
}
/**
* This function fills the user-specified array with pseudorandom
* integers.
*
* @param array an 128-bit array to be filled by pseudorandom numbers.
* @param sfmt SFMT internal state
* @param array an 128-bit array to be filled by pseudorandom numbers.
* @param size number of 128-bit pseudorandom numbers to be generated.
*/
inline static void gen_rand_array(w128_t *array, int size) {
inline static void gen_rand_array(sfmt_t * sfmt, w128_t *array, int size) {
int i, j;
w128_t *r1, *r2;
r1 = &sfmt[N - 2];
r2 = &sfmt[N - 1];
for (i = 0; i < N - POS1; i++) {
do_recursion(&array[i], &sfmt[i], &sfmt[i + POS1], r1, r2);
r1 = r2;
r2 = &array[i];
r1 = &sfmt->state[SFMT_N - 2];
r2 = &sfmt->state[SFMT_N - 1];
for (i = 0; i < SFMT_N - SFMT_POS1; i++) {
do_recursion(&array[i], &sfmt->state[i], &sfmt->state[i + SFMT_POS1], r1, r2);
r1 = r2;
r2 = &array[i];
}
for (; i < N; i++) {
do_recursion(&array[i], &sfmt[i], &array[i + POS1 - N], r1, r2);
r1 = r2;
r2 = &array[i];
for (; i < SFMT_N; i++) {
do_recursion(&array[i], &sfmt->state[i],
&array[i + SFMT_POS1 - SFMT_N], r1, r2);
r1 = r2;
r2 = &array[i];
}
for (; i < size - N; i++) {
do_recursion(&array[i], &array[i - N], &array[i + POS1 - N], r1, r2);
r1 = r2;
r2 = &array[i];
for (; i < size - SFMT_N; i++) {
do_recursion(&array[i], &array[i - SFMT_N],
&array[i + SFMT_POS1 - SFMT_N], r1, r2);
r1 = r2;
r2 = &array[i];
}
for (j = 0; j < 2 * N - size; j++) {
sfmt[j] = array[j + size - N];
for (j = 0; j < 2 * SFMT_N - size; j++) {
sfmt->state[j] = array[j + size - SFMT_N];
}
for (; i < size; i++, j++) {
do_recursion(&array[i], &array[i - N], &array[i + POS1 - N], r1, r2);
r1 = r2;
r2 = &array[i];
sfmt[j] = array[i];
do_recursion(&array[i], &array[i - SFMT_N],
&array[i + SFMT_POS1 - SFMT_N], r1, r2);
r1 = r2;
r2 = &array[i];
sfmt->state[j] = array[i];
}
}
#endif
@ -312,12 +132,12 @@ inline static void swap(w128_t *array, int size) {
uint32_t x, y;
for (i = 0; i < size; i++) {
x = array[i].u[0];
y = array[i].u[2];
array[i].u[0] = array[i].u[1];
array[i].u[2] = array[i].u[3];
array[i].u[1] = x;
array[i].u[3] = y;
x = array[i].u[0];
y = array[i].u[2];
array[i].u[0] = array[i].u[1];
array[i].u[2] = array[i].u[3];
array[i].u[1] = x;
array[i].u[3] = y;
}
}
#endif
@ -343,114 +163,101 @@ static uint32_t func2(uint32_t x) {
/**
* This function certificate the period of 2^{MEXP}
* @param sfmt SFMT internal state
*/
static void period_certification(void) {
static void period_certification(sfmt_t * sfmt) {
int inner = 0;
int i, j;
uint32_t work;
uint32_t *psfmt32 = &sfmt->state[0].u[0];
const uint32_t parity[4] = {SFMT_PARITY1, SFMT_PARITY2,
SFMT_PARITY3, SFMT_PARITY4};
for (i = 0; i < 4; i++)
inner ^= psfmt32[idxof(i)] & parity[i];
inner ^= psfmt32[idxof(i)] & parity[i];
for (i = 16; i > 0; i >>= 1)
inner ^= inner >> i;
inner ^= inner >> i;
inner &= 1;
/* check OK */
if (inner == 1) {
return;
return;
}
/* check NG, and modification */
for (i = 0; i < 4; i++) {
work = 1;
for (j = 0; j < 32; j++) {
if ((work & parity[i]) != 0) {
psfmt32[idxof(i)] ^= work;
return;
}
work = work << 1;
}
work = 1;
for (j = 0; j < 32; j++) {
if ((work & parity[i]) != 0) {
psfmt32[idxof(i)] ^= work;
return;
}
work = work << 1;
}
}
}
/*----------------
PUBLIC FUNCTIONS
----------------*/
#define UNUSED_VARIABLE(x) (void)(x)
/**
* This function returns the identification string.
* The string shows the word size, the Mersenne exponent,
* and all parameters of this generator.
* @param sfmt SFMT internal state
*/
const char *get_idstring(void) {
return IDSTR;
const char *sfmt_get_idstring(sfmt_t * sfmt) {
UNUSED_VARIABLE(sfmt);
return SFMT_IDSTR;
}
/**
* This function returns the minimum size of array used for \b
* fill_array32() function.
* @param sfmt SFMT internal state
* @return minimum size of array used for fill_array32() function.
*/
int get_min_array_size32(void) {
return N32;
int sfmt_get_min_array_size32(sfmt_t * sfmt) {
UNUSED_VARIABLE(sfmt);
return SFMT_N32;
}
/**
* This function returns the minimum size of array used for \b
* fill_array64() function.
* @param sfmt SFMT internal state
* @return minimum size of array used for fill_array64() function.
*/
int get_min_array_size64(void) {
return N64;
int sfmt_get_min_array_size64(sfmt_t * sfmt) {
UNUSED_VARIABLE(sfmt);
return SFMT_N64;
}
#ifndef ONLY64
#if !defined(HAVE_SSE2) && !defined(HAVE_ALTIVEC)
/**
* This function generates and returns 32-bit pseudorandom number.
* init_gen_rand or init_by_array must be called before this function.
* @return 32-bit pseudorandom number
* This function fills the internal state array with pseudorandom
* integers.
* @param sfmt SFMT internal state
*/
uint32_t gen_rand32(void) {
uint32_t r;
void sfmt_gen_rand_all(sfmt_t * sfmt) {
int i;
w128_t *r1, *r2;
assert(initialized);
if (idx >= N32) {
gen_rand_all();
idx = 0;
r1 = &sfmt->state[SFMT_N - 2];
r2 = &sfmt->state[SFMT_N - 1];
for (i = 0; i < SFMT_N - SFMT_POS1; i++) {
do_recursion(&sfmt->state[i], &sfmt->state[i],
&sfmt->state[i + SFMT_POS1], r1, r2);
r1 = r2;
r2 = &sfmt->state[i];
}
for (; i < SFMT_N; i++) {
do_recursion(&sfmt->state[i], &sfmt->state[i],
&sfmt->state[i + SFMT_POS1 - SFMT_N], r1, r2);
r1 = r2;
r2 = &sfmt->state[i];
}
r = psfmt32[idx++];
return r;
}
#endif
/**
* This function generates and returns 64-bit pseudorandom number.
* init_gen_rand or init_by_array must be called before this function.
* The function gen_rand64 should not be called after gen_rand32,
* unless an initialization is again executed.
* @return 64-bit pseudorandom number
*/
uint64_t gen_rand64(void) {
#if defined(BIG_ENDIAN64) && !defined(ONLY64)
uint32_t r1, r2;
#else
uint64_t r;
#endif
assert(initialized);
assert(idx % 2 == 0);
if (idx >= N32) {
gen_rand_all();
idx = 0;
}
#if defined(BIG_ENDIAN64) && !defined(ONLY64)
r1 = psfmt32[idx];
r2 = psfmt32[idx + 1];
idx += 2;
return ((uint64_t)r2 << 32) | r1;
#else
r = psfmt64[idx / 2];
idx += 2;
return r;
#endif
}
#ifndef ONLY64
/**
@ -464,6 +271,7 @@ uint64_t gen_rand64(void) {
* before the first call of this function. This function can not be
* used after calling gen_rand function, without initialization.
*
* @param sfmt SFMT internal state
* @param array an array where pseudorandom 32-bit integers are filled
* by this function. The pointer to the array must be \b "aligned"
* (namely, must be a multiple of 16) in the SIMD version, since it
@ -478,14 +286,13 @@ uint64_t gen_rand64(void) {
* memory. Mac OSX doesn't have these functions, but \b malloc of OSX
* returns the pointer to the aligned memory block.
*/
void fill_array32(uint32_t *array, int size) {
assert(initialized);
assert(idx == N32);
void sfmt_fill_array32(sfmt_t * sfmt, uint32_t *array, int size) {
assert(sfmt->idx == SFMT_N32);
assert(size % 4 == 0);
assert(size >= N32);
assert(size >= SFMT_N32);
gen_rand_array((w128_t *)array, size / 4);
idx = N32;
gen_rand_array(sfmt, (w128_t *)array, size / 4);
sfmt->idx = SFMT_N32;
}
#endif
@ -496,6 +303,7 @@ void fill_array32(uint32_t *array, int size) {
* multiple of two. The generation by this function is much faster
* than the following gen_rand function.
*
* @param sfmt SFMT internal state
* For initialization, init_gen_rand or init_by_array must be called
* before the first call of this function. This function can not be
* used after calling gen_rand function, without initialization.
@ -514,14 +322,13 @@ void fill_array32(uint32_t *array, int size) {
* memory. Mac OSX doesn't have these functions, but \b malloc of OSX
* returns the pointer to the aligned memory block.
*/
void fill_array64(uint64_t *array, int size) {
assert(initialized);
assert(idx == N32);
void sfmt_fill_array64(sfmt_t * sfmt, uint64_t *array, int size) {
assert(sfmt->idx == SFMT_N32);
assert(size % 2 == 0);
assert(size >= N64);
assert(size >= SFMT_N64);
gen_rand_array((w128_t *)array, size / 2);
idx = N32;
gen_rand_array(sfmt, (w128_t *)array, size / 2);
sfmt->idx = SFMT_N32;
#if defined(BIG_ENDIAN64) && !defined(ONLY64)
swap((w128_t *)array, size /2);
@ -532,54 +339,58 @@ void fill_array64(uint64_t *array, int size) {
* This function initializes the internal state array with a 32-bit
* integer seed.
*
* @param sfmt SFMT internal state
* @param seed a 32-bit integer used as the seed.
*/
void init_gen_rand(uint32_t seed) {
void sfmt_init_gen_rand(sfmt_t * sfmt, uint32_t seed) {
int i;
uint32_t *psfmt32 = &sfmt->state[0].u[0];
psfmt32[idxof(0)] = seed;
for (i = 1; i < N32; i++) {
psfmt32[idxof(i)] = 1812433253UL * (psfmt32[idxof(i - 1)]
^ (psfmt32[idxof(i - 1)] >> 30))
+ i;
for (i = 1; i < SFMT_N32; i++) {
psfmt32[idxof(i)] = 1812433253UL * (psfmt32[idxof(i - 1)]
^ (psfmt32[idxof(i - 1)] >> 30))
+ i;
}
idx = N32;
period_certification();
initialized = 1;
sfmt->idx = SFMT_N32;
period_certification(sfmt);
}
/**
* This function initializes the internal state array,
* with an array of 32-bit integers used as the seeds
* @param sfmt SFMT internal state
* @param init_key the array of 32-bit integers, used as a seed.
* @param key_length the length of init_key.
*/
void init_by_array(uint32_t *init_key, int key_length) {
void sfmt_init_by_array(sfmt_t * sfmt, uint32_t *init_key, int key_length) {
int i, j, count;
uint32_t r;
int lag;
int mid;
int size = N * 4;
int size = SFMT_N * 4;
uint32_t *psfmt32 = &sfmt->state[0].u[0];
if (size >= 623) {
lag = 11;
lag = 11;
} else if (size >= 68) {
lag = 7;
lag = 7;
} else if (size >= 39) {
lag = 5;
lag = 5;
} else {
lag = 3;
lag = 3;
}
mid = (size - lag) / 2;
memset(sfmt, 0x8b, sizeof(sfmt));
if (key_length + 1 > N32) {
count = key_length + 1;
memset(sfmt, 0x8b, sizeof(sfmt_t));
if (key_length + 1 > SFMT_N32) {
count = key_length + 1;
} else {
count = N32;
count = SFMT_N32;
}
r = func1(psfmt32[idxof(0)] ^ psfmt32[idxof(mid)]
^ psfmt32[idxof(N32 - 1)]);
r = func1(psfmt32[idxof(0)] ^ psfmt32[idxof(mid)]
^ psfmt32[idxof(SFMT_N32 - 1)]);
psfmt32[idxof(mid)] += r;
r += key_length;
psfmt32[idxof(mid + lag)] += r;
@ -587,34 +398,36 @@ void init_by_array(uint32_t *init_key, int key_length) {
count--;
for (i = 1, j = 0; (j < count) && (j < key_length); j++) {
r = func1(psfmt32[idxof(i)] ^ psfmt32[idxof((i + mid) % N32)]
^ psfmt32[idxof((i + N32 - 1) % N32)]);
psfmt32[idxof((i + mid) % N32)] += r;
r += init_key[j] + i;
psfmt32[idxof((i + mid + lag) % N32)] += r;
psfmt32[idxof(i)] = r;
i = (i + 1) % N32;
r = func1(psfmt32[idxof(i)] ^ psfmt32[idxof((i + mid) % SFMT_N32)]
^ psfmt32[idxof((i + SFMT_N32 - 1) % SFMT_N32)]);
psfmt32[idxof((i + mid) % SFMT_N32)] += r;
r += init_key[j] + i;
psfmt32[idxof((i + mid + lag) % SFMT_N32)] += r;
psfmt32[idxof(i)] = r;
i = (i + 1) % SFMT_N32;
}
for (; j < count; j++) {
r = func1(psfmt32[idxof(i)] ^ psfmt32[idxof((i + mid) % N32)]
^ psfmt32[idxof((i + N32 - 1) % N32)]);
psfmt32[idxof((i + mid) % N32)] += r;
r += i;
psfmt32[idxof((i + mid + lag) % N32)] += r;
psfmt32[idxof(i)] = r;
i = (i + 1) % N32;
r = func1(psfmt32[idxof(i)] ^ psfmt32[idxof((i + mid) % SFMT_N32)]
^ psfmt32[idxof((i + SFMT_N32 - 1) % SFMT_N32)]);
psfmt32[idxof((i + mid) % SFMT_N32)] += r;
r += i;
psfmt32[idxof((i + mid + lag) % SFMT_N32)] += r;
psfmt32[idxof(i)] = r;
i = (i + 1) % SFMT_N32;
}
for (j = 0; j < N32; j++) {
r = func2(psfmt32[idxof(i)] + psfmt32[idxof((i + mid) % N32)]
+ psfmt32[idxof((i + N32 - 1) % N32)]);
psfmt32[idxof((i + mid) % N32)] ^= r;
r -= i;
psfmt32[idxof((i + mid + lag) % N32)] ^= r;
psfmt32[idxof(i)] = r;
i = (i + 1) % N32;
for (j = 0; j < SFMT_N32; j++) {
r = func2(psfmt32[idxof(i)] + psfmt32[idxof((i + mid) % SFMT_N32)]
+ psfmt32[idxof((i + SFMT_N32 - 1) % SFMT_N32)]);
psfmt32[idxof((i + mid) % SFMT_N32)] ^= r;
r -= i;
psfmt32[idxof((i + mid + lag) % SFMT_N32)] ^= r;
psfmt32[idxof(i)] = r;
i = (i + 1) % SFMT_N32;
}
idx = N32;
period_certification();
initialized = 1;
sfmt->idx = SFMT_N32;
period_certification(sfmt);
}
#if defined(__cplusplus)
}
#endif

View file

@ -1,24 +1,28 @@
/**
* @file SFMT.h
#pragma once
/**
* @file SFMT.h
*
* @brief SIMD oriented Fast Mersenne Twister(SFMT) pseudorandom
* number generator
* number generator using C structure.
*
* @author Mutsuo Saito (Hiroshima University)
* @author Makoto Matsumoto (Hiroshima University)
* @author Makoto Matsumoto (The University of Tokyo)
*
* Copyright (C) 2006, 2007 Mutsuo Saito, Makoto Matsumoto and Hiroshima
* University. All rights reserved.
* University.
* Copyright (C) 2012 Mutsuo Saito, Makoto Matsumoto, Hiroshima
* University and The University of Tokyo.
* All rights reserved.
*
* The new BSD License is applied to this software.
* see LICENSE.txt
* The 3-clause BSD License is applied to this software, see
* LICENSE.txt
*
* @note We assume that your system has inttypes.h. If your system
* doesn't have inttypes.h, you have to typedef uint32_t and uint64_t,
* and you have to define PRIu64 and PRIx64 in this file as follows:
* @verbatim
typedef unsigned int uint32_t
typedef unsigned long long uint64_t
typedef unsigned long long uint64_t
#define PRIu64 "llu"
#define PRIx64 "llx"
@endverbatim
@ -28,14 +32,14 @@
* unsigned int and 64-bit unsigned int in hexadecimal format.
*/
#ifndef SFMT_H
#define SFMT_H
#ifdef __cplusplus
#ifndef SFMTST_H
#define SFMTST_H
#if defined(__cplusplus)
extern "C" {
#endif
#include <stdio.h>
#include <assert.h>
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
#include <inttypes.h>
@ -60,105 +64,232 @@ extern "C" {
#endif
#endif
#if defined(__GNUC__)
#define ALWAYSINLINE __attribute__((always_inline))
#else
#define ALWAYSINLINE
#endif
#include "SFMT-params.h"
#if defined(_MSC_VER)
#if _MSC_VER >= 1200
#define PRE_ALWAYS __forceinline
#else
#define PRE_ALWAYS inline
/*------------------------------------------
128-bit SIMD like data type for standard C
------------------------------------------*/
#if defined(HAVE_ALTIVEC)
#if !defined(__APPLE__)
#include <altivec.h>
#endif
/** 128-bit data structure */
union W128_T {
vector unsigned int s;
uint32_t u[4];
uint64_t u64[2];
};
#elif defined(HAVE_SSE2)
#include <emmintrin.h>
/** 128-bit data structure */
union W128_T {
uint32_t u[4];
uint64_t u64[2];
__m128i si;
};
#else
#define PRE_ALWAYS inline
/** 128-bit data structure */
union W128_T {
uint32_t u[4];
uint64_t u64[2];
};
#endif
uint32_t gen_rand32(void);
uint64_t gen_rand64(void);
void fill_array32(uint32_t *array, int size);
void fill_array64(uint64_t *array, int size);
void init_gen_rand(uint32_t seed);
void init_by_array(uint32_t *init_key, int key_length);
const char *get_idstring(void);
int get_min_array_size32(void);
int get_min_array_size64(void);
/** 128-bit data type */
typedef union W128_T w128_t;
/* These real versions are due to Isaku Wada */
/** generates a random number on [0,1]-real-interval */
inline static double to_real1(uint32_t v)
{
return v * (1.0/4294967295.0);
/* divided by 2^32-1 */
/**
* SFMT internal state
*/
struct SFMT_T {
/** the 128-bit internal state array */
w128_t state[SFMT_N];
/** index counter to the 32-bit internal state array */
int idx;
};
typedef struct SFMT_T sfmt_t;
void sfmt_fill_array32(sfmt_t * sfmt, uint32_t * array, int size);
void sfmt_fill_array64(sfmt_t * sfmt, uint64_t * array, int size);
void sfmt_init_gen_rand(sfmt_t * sfmt, uint32_t seed);
void sfmt_init_by_array(sfmt_t * sfmt, uint32_t * init_key, int key_length);
const char * sfmt_get_idstring(sfmt_t * sfmt);
int sfmt_get_min_array_size32(sfmt_t * sfmt);
int sfmt_get_min_array_size64(sfmt_t * sfmt);
void sfmt_gen_rand_all(sfmt_t * sfmt);
#ifndef ONLY64
/**
* This function generates and returns 32-bit pseudorandom number.
* init_gen_rand or init_by_array must be called before this function.
* @param sfmt SFMT internal state
* @return 32-bit pseudorandom number
*/
inline static uint32_t sfmt_genrand_uint32(sfmt_t * sfmt) {
uint32_t r;
uint32_t * psfmt32 = &sfmt->state[0].u[0];
if (sfmt->idx >= SFMT_N32) {
sfmt_gen_rand_all(sfmt);
sfmt->idx = 0;
}
r = psfmt32[sfmt->idx++];
return r;
}
#endif
/**
* This function generates and returns 64-bit pseudorandom number.
* init_gen_rand or init_by_array must be called before this function.
* The function gen_rand64 should not be called after gen_rand32,
* unless an initialization is again executed.
* @param sfmt SFMT internal state
* @return 64-bit pseudorandom number
*/
inline static uint64_t sfmt_genrand_uint64(sfmt_t * sfmt) {
#if defined(BIG_ENDIAN64) && !defined(ONLY64)
uint32_t * psfmt32 = &sfmt->state[0].u[0];
uint32_t r1, r2;
#else
uint64_t r;
#endif
uint64_t * psfmt64 = &sfmt->state[0].u64[0];
assert(sfmt->idx % 2 == 0);
if (sfmt->idx >= SFMT_N32) {
sfmt_gen_rand_all(sfmt);
sfmt->idx = 0;
}
#if defined(BIG_ENDIAN64) && !defined(ONLY64)
r1 = psfmt32[sfmt->idx];
r2 = psfmt32[sfmt->idx + 1];
sfmt->idx += 2;
return ((uint64_t)r2 << 32) | r1;
#else
r = psfmt64[sfmt->idx / 2];
sfmt->idx += 2;
return r;
#endif
}
/** generates a random number on [0,1]-real-interval */
inline static double genrand_real1(void)
/* =================================================
The following real versions are due to Isaku Wada
================================================= */
/**
* converts an unsigned 32-bit number to a double on [0,1]-real-interval.
* @param v 32-bit unsigned integer
* @return double on [0,1]-real-interval
*/
inline static double sfmt_to_real1(uint32_t v)
{
return to_real1(gen_rand32());
return v * (1.0/4294967295.0);
/* divided by 2^32-1 */
}
/** generates a random number on [0,1)-real-interval */
inline static double to_real2(uint32_t v)
/**
* generates a random number on [0,1]-real-interval
* @param sfmt SFMT internal state
* @return double on [0,1]-real-interval
*/
inline static double sfmt_genrand_real1(sfmt_t * sfmt)
{
return v * (1.0/4294967296.0);
return sfmt_to_real1(sfmt_genrand_uint32(sfmt));
}
/**
* converts an unsigned 32-bit integer to a double on [0,1)-real-interval.
* @param v 32-bit unsigned integer
* @return double on [0,1)-real-interval
*/
inline static double sfmt_to_real2(uint32_t v)
{
return v * (1.0/4294967296.0);
/* divided by 2^32 */
}
/** generates a random number on [0,1)-real-interval */
inline static double genrand_real2(void)
/**
* generates a random number on [0,1)-real-interval
* @param sfmt SFMT internal state
* @return double on [0,1)-real-interval
*/
inline static double sfmt_genrand_real2(sfmt_t * sfmt)
{
return to_real2(gen_rand32());
return sfmt_to_real2(sfmt_genrand_uint32(sfmt));
}
/** generates a random number on (0,1)-real-interval */
inline static double to_real3(uint32_t v)
/**
* converts an unsigned 32-bit integer to a double on (0,1)-real-interval.
* @param v 32-bit unsigned integer
* @return double on (0,1)-real-interval
*/
inline static double sfmt_to_real3(uint32_t v)
{
return (((double)v) + 0.5)*(1.0/4294967296.0);
return (((double)v) + 0.5)*(1.0/4294967296.0);
/* divided by 2^32 */
}
/** generates a random number on (0,1)-real-interval */
inline static double genrand_real3(void)
/**
* generates a random number on (0,1)-real-interval
* @param sfmt SFMT internal state
* @return double on (0,1)-real-interval
*/
inline static double sfmt_genrand_real3(sfmt_t * sfmt)
{
return to_real3(gen_rand32());
}
/** These real versions are due to Isaku Wada */
/** generates a random number on [0,1) with 53-bit resolution*/
inline static double to_res53(uint64_t v)
{
return v * (1.0/18446744073709551616.0L);
return sfmt_to_real3(sfmt_genrand_uint32(sfmt));
}
/** generates a random number on [0,1) with 53-bit resolution from two
* 32 bit integers */
inline static double to_res53_mix(uint32_t x, uint32_t y)
{
return to_res53(x | ((uint64_t)y << 32));
}
/** generates a random number on [0,1) with 53-bit resolution
/**
* converts an unsigned 32-bit integer to double on [0,1)
* with 53-bit resolution.
* @param v 32-bit unsigned integer
* @return double on [0,1)-real-interval with 53-bit resolution.
*/
inline static double genrand_res53(void)
{
return to_res53(gen_rand64());
}
inline static double sfmt_to_res53(uint64_t v)
{
return v * (1.0/18446744073709551616.0);
}
/** generates a random number on [0,1) with 53-bit resolution
using 32bit integer.
/**
* generates a random number on [0,1) with 53-bit resolution
* @param sfmt SFMT internal state
* @return double on [0,1) with 53-bit resolution
*/
inline static double genrand_res53_mix(void)
{
inline static double sfmt_genrand_res53(sfmt_t * sfmt)
{
return sfmt_to_res53(sfmt_genrand_uint64(sfmt));
}
/* =================================================
The following function are added by Saito.
================================================= */
/**
* generates a random number on [0,1) with 53-bit resolution from two
* 32 bit integers
*/
inline static double sfmt_to_res53_mix(uint32_t x, uint32_t y)
{
return sfmt_to_res53(x | ((uint64_t)y << 32));
}
/**
* generates a random number on [0,1) with 53-bit resolution
* using two 32bit integers.
* @param sfmt SFMT internal state
* @return double on [0,1) with 53-bit resolution
*/
inline static double sfmt_genrand_res53_mix(sfmt_t * sfmt)
{
uint32_t x, y;
x = gen_rand32();
y = gen_rand32();
return to_res53_mix(x, y);
}
#ifdef __cplusplus
x = sfmt_genrand_uint32(sfmt);
y = sfmt_genrand_uint32(sfmt);
return sfmt_to_res53_mix(x, y);
}
#if defined(__cplusplus)
}
#endif
#endif

View file

@ -1,333 +1,254 @@
<?xml version="1.0" encoding="UTF-8"?>
<cockatrice_setdatabase version="20130507">
<cockatrice_setdatabase version="20110126">
<picture_url>http://gatherer.wizards.com/Handlers/Image.ashx?multiverseid=!cardid!&amp;type=card</picture_url>
<set_url>http://gatherer.wizards.com/Pages/Search/Default.aspx?output=spoiler&amp;method=text&amp;set=[&quot;!longname!&quot;]&amp;special=true</set_url>
<set import="1">
<name>10E</name>
<longname>Tenth Edition</longname>
</set>
<set import="1">
<name>15ANN</name>
<longname>15th Anniversary</longname>
</set>
<set import="1">
<name>4E</name>
<longname>Fourth Edition</longname>
</set>
<set import="1">
<name>5DN</name>
<longname>Fifth Dawn</longname>
</set>
<set import="1">
<name>5E</name>
<longname>Fifth Edition</longname>
</set>
<set import="1">
<name>6E</name>
<longname>Classic Sixth Edition</longname>
</set>
<set import="1">
<name>7E</name>
<longname>Seventh Edition</longname>
</set>
<set import="1">
<name>8EB</name>
<longname>Eighth Edition Box Set</longname>
</set>
<set import="1">
<name>8E</name>
<longname>Eighth Edition</longname>
</set>
<set import="1">
<name>9EB</name>
<longname>Ninth Edition Box Set</longname>
</set>
<set import="1">
<name>9E</name>
<longname>Ninth Edition</longname>
</set>
<set import="1">
<name>AI</name>
<longname>Alliances</longname>
</set>
<set import="1">
<name>ALA</name>
<longname>Shards of Alara</longname>
</set>
<set import="1">
<name>AL</name>
<longname>Limited Edition Alpha</longname>
</set>
<set import="1">
<name>AN</name>
<longname>Arabian Nights</longname>
</set>
<set import="1">
<name>APAC</name>
<longname>Asia Pacific Land Program</longname>
</set>
<set import="1">
<name>AP</name>
<longname>Apocalypse</longname>
</set>
<set import="1">
<name>AQ</name>
<longname>Antiquities</longname>
</set>
<!-- <picture_url_hq>http://mtgimage.com/multiverseid/!cardid!.jpg</picture_url_hq> -->
<set_url>http://mtgjson.com/json/!name!.json</set_url>
<set import="1">
<name>ARB</name>
<longname>Alara Reborn</longname>
</set>
<set import="1">
<name>ALL</name>
<longname>Alliances</longname>
</set>
<set import="1">
<name>ATQ</name>
<longname>Antiquities</longname>
</set>
<set import="1">
<name>APC</name>
<longname>Apocalypse</longname>
</set>
<set import="1">
<name>ARN</name>
<longname>Arabian Nights</longname>
</set>
<set import="0">
<name>ARC</name>
<longname>Archenemy</longname>
</set>
<set import="1">
<name>ARENA</name>
<longname>Arena League</longname>
</set>
<set import="1">
<name>AT</name>
<longname>Anthologies</longname>
</set>
<set import="1">
<name>AVR</name>
<longname>Avacyn Restored</longname>
</set>
<set import="1">
<name>BD</name>
<longname>Beatdown Box Set</longname>
<set import="0">
<name>BRB</name>
<longname>Battle Royale Box Set</longname>
</set>
<set import="1">
<name>BE</name>
<longname>Limited Edition Beta</longname>
<set import="0">
<name>BTD</name>
<longname>Beatdown Box Set</longname>
</set>
<set import="1">
<name>BOK</name>
<longname>Betrayers of Kamigawa</longname>
</set>
<set import="1">
<name>BR</name>
<longname>Battle Royale Box Set</longname>
</set>
<set import="1">
<name>CED</name>
<longname>Collector's Edition</longname>
</set>
<set import="1">
<name>CEDI</name>
<longname>International Collectors' Edition</longname>
</set>
<set import="1">
<name>CFX</name>
<longname>Conflux</longname>
</set>
<set import="1">
<name>CH</name>
<longname>Chronicles</longname>
<name>BNG</name>
<longname>Born of the Gods</longname>
</set>
<set import="1">
<name>CHK</name>
<longname>Champions of Kamigawa</longname>
</set>
<set import="1">
<name>CMA</name>
<longname>Commander's Arsenal</longname>
<name>CHR</name>
<longname>Chronicles</longname>
</set>
<set import="1">
<name>CMD</name>
<longname>Commander</longname>
<name>6ED</name>
<longname>Classic Sixth Edition</longname>
</set>
<set import="1">
<name>CP</name>
<longname>Champs</longname>
</set>
<set import="1">
<name>CS</name>
<name>CSP</name>
<longname>Coldsnap</longname>
</set>
<set import="1">
<name>CSTD</name>
<longname>Coldsnap Theme Decks</longname>
<name>CON</name>
<longname>Conflux</longname>
</set>
<set import="0">
<name>CMA</name>
<longname>Commander's Arsenal</longname>
</set>
<set import="0">^M
<name>C13</name>^M
<longname>Commander 2013 Edition</longname>^M
</set>
<set import="1">
<name>DCILM</name>
<longname>Legend Membership</longname>
</set>
<set import="1">
<name>DDF</name>
<longname>Duel Decks: Elspeth vs. Tezzeret</longname>
</set>
<set import="1">
<name>DDG</name>
<longname>Duel Decks: Knights vs. Dragons</longname>
</set>
<set import="1">
<name>DDH</name>
<longname>Duel Decks: Ajani vs. Nicol Bolas</longname>
</set>
<set import="1">
<name>DDI</name>
<longname>Duel Decks: Venser vs. Koth</longname>
</set>
<set import="1">
<name>DDJ</name>
<longname>Duel Decks: Izzet vs. Golgari</longname>
</set>
<set import="1">
<name>DDK</name>
<longname>Duel Decks: Sorin vs. Tibalt</longname>
</set>
<set import="1">
<name>DGM</name>
<longname>Dragon's Maze</longname>
</set>
<set import="1">
<name>DI</name>
<longname>Dissension</longname>
<name>DST</name>
<longname>Darksteel</longname>
</set>
<set import="1">
<name>DKA</name>
<longname>Dark Ascension</longname>
</set>
<set import="1">
<name>DK</name>
<longname>The Dark</longname>
<name>DIS</name>
<longname>Dissension</longname>
</set>
<set import="1">
<name>DM</name>
<longname>Deckmasters</longname>
<name>DGM</name>
<longname>Dragon's Maze</longname>
</set>
<set import="1">
<name>DPA</name>
<longname>Duels of the Planeswalkers</longname>
<set import="0">
<name>DDH</name>
<longname>Duel Decks: Ajani vs. Nicol Bolas</longname>
</set>
<set import="1">
<name>DRC</name>
<longname>Dragon Con</longname>
</set>
<set import="1">
<name>DS</name>
<longname>Darksteel</longname>
</set>
<set import="1">
<name>DVD</name>
<set import="0">
<name>DDC</name>
<longname>Duel Decks: Divine vs. Demonic</longname>
</set>
<set import="0">
<name>DDF</name>
<longname>Duel Decks: Elspeth vs. Tezzeret</longname>
</set>
<set import="0">
<name>EVG</name>
<longname>Duel Decks: Elves vs. Goblins</longname>
</set>
<set import="0">
<name>DDD</name>
<longname>Duel Decks: Garruk vs. Liliana</longname>
</set>
<set import="0">
<name>DDL</name>
<longname>Duel Decks: Heroes vs. Monsters</longname>
</set>
<set import="0">
<name>DDJ</name>
<longname>Duel Decks: Izzet vs. Golgari</longname>
</set>
<set import="0">
<name>DD2</name>
<longname>Duel Decks: Jace vs. Chandra</longname>
</set>
<set import="0">
<name>DDM</name>
<longname>Duel Decks: Jace vs. Vraska</longname>
</set>
<set import="0">
<name>DDG</name>
<longname>Duel Decks: Knights vs. Dragons</longname>
</set>
<set import="0">
<name>DDE</name>
<longname>Duel Decks: Phyrexia vs. the Coalition</longname>
</set>
<set import="0">
<name>DDK</name>
<longname>Duel Decks: Sorin vs. Tibalt</longname>
</set>
<set import="0">
<name>DDI</name>
<longname>Duel Decks: Venser vs. Koth</longname>
</set>
<set import="1">
<name>EURO</name>
<longname>European Land Program</longname>
<name>8ED</name>
<longname>Eighth Edition</longname>
</set>
<set import="1">
<name>EVE</name>
<longname>Eventide</longname>
</set>
<set import="1">
<name>EVG</name>
<longname>Duel Decks: Elves vs. Goblins</longname>
</set>
<set import="1">
<name>EX</name>
<name>EXO</name>
<longname>Exodus</longname>
</set>
<set import="1">
<name>FE</name>
<name>FEM</name>
<longname>Fallen Empires</longname>
</set>
<set import="1">
<name>FNMP</name>
<longname>Friday Night Magic</longname>
<name>5DN</name>
<longname>Fifth Dawn</longname>
</set>
<set import="1">
<name>5ED</name>
<longname>Fifth Edition</longname>
</set>
<set import="1">
<name>4ED</name>
<longname>Fourth Edition</longname>
</set>
<set import="0">
<name>DRB</name>
<longname>From the Vault: Dragons</longname>
</set>
<set import="0">
<name>V09</name>
<longname>From the Vault: Exiled</longname>
</set>
<set import="0">
<name>V11</name>
<longname>From the Vault: Legends</longname>
</set>
<set import="0">
<name>V12</name>
<longname>From the Vault: Realms</longname>
</set>
<set import="0">
<name>V10</name>
<longname>From the Vault: Relics</longname>
</set>
<set import="0">
<name>V13</name>
<longname>From the Vault: Twenty</longname>
</set>
<set import="1">
<name>FUT</name>
<longname>Future Sight</longname>
</set>
<set import="1">
<name>FVD</name>
<longname>From the Vault: Dragons</longname>
</set>
<set import="1">
<name>FVE</name>
<longname>From the Vault: Exiled</longname>
</set>
<set import="1">
<name>FVL</name>
<longname>From the Vault: Legends</longname>
</set>
<set import="1">
<name>FVR</name>
<longname>From the Vault: Relics</longname>
</set>
<set import="1">
<name>GP</name>
<name>GPT</name>
<longname>Guildpact</longname>
</set>
<set import="1">
<name>GPX</name>
<longname>Grand Prix</longname>
</set>
<set import="1">
<name>GRC</name>
<longname>WPN/Gateway</longname>
</set>
<set import="1">
<name>GTC</name>
<longname>Gatecrash</longname>
</set>
<set import="1">
<name>GURU</name>
<longname>Guru</longname>
</set>
<set import="1">
<name>GVL</name>
<longname>Duel Decks: Garruk vs. Liliana</longname>
</set>
<set import="1">
<name>HHO</name>
<longname>Happy Holidays</longname>
</set>
<set import="1">
<name>HL</name>
<name>HML</name>
<longname>Homelands</longname>
</set>
<set import="1">
<name>IA</name>
<name>ICE</name>
<longname>Ice Age</longname>
</set>
<set import="1">
<name>IN</name>
<longname>Invasion</longname>
</set>
<set import="1">
<name>ISD</name>
<longname>Innistrad</longname>
</set>
<set import="1">
<name>ITP</name>
<longname>Introductory Two-Player Set</longname>
<name>INV</name>
<longname>Invasion</longname>
</set>
<set import="1">
<name>JR</name>
<longname>Judge Gift Program</longname>
<name>JOU</name>
<longname>Journey into Nyx</longname>
</set>
<set import="1">
<name>JU</name>
<name>JUD</name>
<longname>Judgment</longname>
</set>
<set import="1">
<name>JVC</name>
<longname>Duel Decks: Jace vs. Chandra</longname>
</set>
<set import="1">
<name>LE</name>
<longname>Legions</longname>
</set>
<set import="1">
<name>LG</name>
<name>LEG</name>
<longname>Legends</longname>
</set>
<set import="1">
<name>LW</name>
<name>LGN</name>
<longname>Legions</longname>
</set>
<set import="1">
<name>LEA</name>
<longname>Limited Edition Alpha</longname>
</set>
<set import="1">
<name>LEB</name>
<longname>Limited Edition Beta</longname>
</set>
<set import="1">
<name>LRW</name>
<longname>Lorwyn</longname>
</set>
<set import="1">
@ -347,63 +268,59 @@
<longname>Magic 2013</longname>
</set>
<set import="1">
<name>MBP</name>
<longname>Media Inserts</longname>
<name>M14</name>
<longname>Magic 2014 Core Set</longname>
</set>
<set import="0">
<name>CMD</name>
<longname>Magic: The Gathering-Commander</longname>
</set>
<set import="0">
<name>CNS</name>
<longname>Magic: The Gathering—Conspiracy</longname>
</set>
<set import="0">
<name>MED</name>
<longname>Masters Edition</longname>
</set>
<set import="0">
<name>ME2</name>
<longname>Masters Edition II</longname>
</set>
<set import="0">
<name>ME3</name>
<longname>Masters Edition III</longname>
</set>
<set import="0">
<name>ME4</name>
<longname>Masters Edition IV</longname>
</set>
<set import="1">
<name>MMQ</name>
<longname>Mercadian Masques</longname>
</set>
<set import="1">
<name>MIR</name>
<longname>Mirage</longname>
</set>
<set import="1">
<name>MRD</name>
<longname>Mirrodin</longname>
</set>
<set import="1">
<name>MBS</name>
<longname>Mirrodin Besieged</longname>
</set>
<set import="0">^M
<name>MMA</name>^M
<longname>Modern Masters</longname>^M
</set>^
<set import="1">
<name>ME2</name>
<longname>MTGO Masters Edition II</longname>
</set>
<set import="1">
<name>ME3</name>
<longname>MTGO Masters Edition III</longname>
</set>
<set import="1">
<name>ME4</name>
<longname>MTGO Masters Edition IV</longname>
</set>
<set import="1">
<name>MED</name>
<longname>MTGO Masters Edition</longname>
</set>
<set import="1">
<name>MGBC</name>
<longname>Multiverse Gift Box Cards</longname>
</set>
<set import="1">
<name>MGDC</name>
<longname>Magic Game Day Cards</longname>
</set>
<set import="1">
<name>MI</name>
<longname>Mirrodin</longname>
</set>
<set import="1">
<name>MLP</name>
<longname>Magic: The Gathering Launch Parties</longname>
</set>
<set import="1">
<name>MM</name>
<longname>Mercadian Masques</longname>
</set>
<set import="1">
<name>MPRP</name>
<longname>Magic Player Rewards</longname>
</set>
<set import="1">
<name>MR</name>
<longname>Mirage</longname>
</set>
<set import="1">
<name>MT</name>
<name>MOR</name>
<longname>Morningtide</longname>
</set>
<set import="1">
<name>NE</name>
<name>NMS</name>
<longname>Nemesis</longname>
</set>
<set import="1">
@ -411,104 +328,80 @@
<longname>New Phyrexia</longname>
</set>
<set import="1">
<name>OD</name>
<name>9ED</name>
<longname>Ninth Edition</longname>
</set>
<set import="1">
<name>ODY</name>
<longname>Odyssey</longname>
</set>
<set import="1">
<name>ON</name>
<name>ONS</name>
<longname>Onslaught</longname>
</set>
<set import="1">
<name>P3K</name>
<longname>Portal Three Kingdoms</longname>
<name>PLC</name>
<longname>Planar Chaos</longname>
</set>
<set import="1">
<set import="0">
<name>HOP</name>
<longname>Planechase</longname>
</set>
<set import="0">
<name>PC2</name>
<longname>Planechase 2012 Edition</longname>
</set>
<set import="1">
<name>PC</name>
<longname>Planar Chaos</longname>
<name>PLS</name>
<longname>Planeshift</longname>
</set>
<set import="1">
<name>PCH</name>
<longname>Planechase</longname>
</set>
<set import="1">
<name>PD2</name>
<longname>Premium Deck Series: Fire and Lightning</longname>
</set>
<set import="1">
<name>PD3</name>
<longname>Premium Deck Series: Graveborn</longname>
</set>
<set import="1">
<name>PDS</name>
<longname>Premium Deck Series: Slivers</longname>
<name>POR</name>
<longname>Portal</longname>
</set>
<set import="1">
<name>PO2</name>
<longname>Portal Second Age</longname>
</set>
<set import="1">
<name>PO</name>
<longname>Portal</longname>
<name>PTK</name>
<longname>Portal Three Kingdoms</longname>
</set>
<set import="0">
<name>PD2</name>
<longname>Premium Deck Series: Fire and Lightning</longname>
</set>
<set import="0">
<name>PD3</name>
<longname>Premium Deck Series: Graveborn</longname>
</set>
<set import="0">
<name>H09</name>
<longname>Premium Deck Series: Slivers</longname>
</set>
<set import="0">
<name>PPR</name>
<longname>Promo set for Gatherer</longname>
</set>
<set import="1">
<name>POT</name>
<longname>Portal Demogame</longname>
</set>
<set import="1">
<name>PR</name>
<name>PCY</name>
<longname>Prophecy</longname>
</set>
<set import="1">
<name>PRO</name>
<longname>Pro Tour</longname>
</set>
<set import="1">
<name>PS</name>
<longname>Planeshift</longname>
</set>
<set import="1">
<name>PTC</name>
<longname>Prerelease Events</longname>
</set>
<set import="1">
<name>PVC</name>
<longname>Duel Decks: Phyrexia vs. The Coalition</longname>
</set>
<set import="1">
<name>RAV</name>
<longname>Ravnica: City of Guilds</longname>
</set>
<set import="1">
<name>REP</name>
<longname>Release Events</longname>
</set>
<set import="1">
<name>ROE</name>
<longname>Rise of the Eldrazi</longname>
</set>
<set import="1">
<name>RTR</name>
<longname>Return to Ravnica</longname>
</set>
<set import="1">
<name>RV</name>
<name>3ED</name>
<longname>Revised Edition</longname>
</set>
<set import="1">
<name>SC</name>
<longname>Scourge</longname>
</set>
<set import="1">
<name>SH</name>
<longname>Stronghold</longname>
</set>
<set import="1">
<name>SHM</name>
<longname>Shadowmoor</longname>
<name>ROE</name>
<longname>Rise of the Eldrazi</longname>
</set>
<set import="1">
<name>SOK</name>
@ -519,97 +412,97 @@
<longname>Scars of Mirrodin</longname>
</set>
<set import="1">
<name>ST2K</name>
<longname>Starter 2000</longname>
<name>SCG</name>
<longname>Scourge</longname>
</set>
<set import="1">
<name>ST</name>
<name>7ED</name>
<longname>Seventh Edition</longname>
</set>
<set import="1">
<name>SHM</name>
<longname>Shadowmoor</longname>
</set>
<set import="1">
<name>ALA</name>
<longname>Shards of Alara</longname>
</set>
<set import="1">
<name>S99</name>
<longname>Starter 1999</longname>
</set>
<set import="1">
<name>SUM</name>
<longname>Summer of Magic</longname>
<name>S00</name>
<longname>Starter 2000</longname>
</set>
<set import="1">
<name>SUS</name>
<longname>Super Series</longname>
<name>STH</name>
<longname>Stronghold</longname>
</set>
<set import="1">
<name>THGT</name>
<longname>Two-Headed Giant Tournament</longname>
</set>
<set import="1">
<name>TP</name>
<name>TMP</name>
<longname>Tempest</longname>
</set>
<set import="1">
<name>TR</name>
<longname>Torment</longname>
<name>10E</name>
<longname>Tenth Edition</longname>
</set>
<set import="1">
<name>TS</name>
<name>DRK</name>
<longname>The Dark</longname>
</set>
<set import="1">
<name>THS</name>
<longname>Theros</longname>
</set>
<set import="1">
<name>TSP</name>
<longname>Time Spiral</longname>
</set>
<set import="1">
<name>TSTS</name>
<name>TSB</name>
<longname>Time Spiral "Timeshifted"</longname>
</set>
<set import="1">
<name>UD</name>
<longname>Urza's Destiny</longname>
<name>TOR</name>
<longname>Torment</longname>
</set>
<set import="1">
<name>UG</name>
<set import="0">
<name>UGL</name>
<longname>Unglued</longname>
</set>
<set import="1">
<name>UHAA</name>
<longname>Unhinged Alternate Foils</longname>
</set>
<set import="1">
<name>UH</name>
<set import="0">
<name>UNH</name>
<longname>Unhinged</longname>
</set>
<set import="1">
<name>UL</name>
<longname>Urza's Legacy</longname>
</set>
<set import="1">
<name>UN</name>
<name>2ED</name>
<longname>Unlimited Edition</longname>
</set>
<set import="1">
<name>UQC</name>
<longname>Celebration Cards</longname>
<name>UDS</name>
<longname>Urza's Destiny</longname>
</set>
<set import="1">
<name>US</name>
<name>ULG</name>
<longname>Urza's Legacy</longname>
</set>
<set import="1">
<name>USG</name>
<longname>Urza's Saga</longname>
</set>
<set import="1">
<name>V12</name>
<longname>From the Vault: Realms</longname>
<set import="0">
<name>VAN</name>
<longname>Vanguard</longname>
</set>
<set import="1">
<name>VI</name>
<name>VIS</name>
<longname>Visions</longname>
</set>
<set import="1">
<name>WL</name>
<name>WTH</name>
<longname>Weatherlight</longname>
</set>
<set import="1">
<name>WMCQ</name>
<longname>World Magic Cup Qualifiers</longname>
</set>
<set import="1">
<name>WOTC</name>
<longname>WotC Online Store</longname>
</set>
<set import="1">
<name>WRL</name>
<longname>Worlds</longname>
</set>
<set import="1">
<name>WWK</name>
<longname>Worldwake</longname>

View file

@ -213,12 +213,22 @@ FreeBSD 9.1 until the systems were updated.
FreeBSD
: `pkg_add -r qt4 qt4-linguist qt4-moc qt4-qmake qt4-rcc qt4-uic git cmake protobuf`
2. Download the sources from github via\
`cd git clone https://github.com/Daenyth/Cockatrice.git`
2. Download the sources from github via
`git clone https://github.com/Daenyth/Cockatrice.git`
3. To compile the sources, change into the newly created directory,
create a build directory and invoke cmake:\
`cd Cockatrice mkdir build cd build cmake .. make`\
create a build directory and invoke cmake:
i. `cd Cockatrice`
ii. `mkdir build`
iii. `cd build`
iv. `cmake ..`
v. `make`
If you have some issues with pthread\_ add pthread to the
“target\_link\_libraries” entry in the `CMakeFiles.txt` in
`Cockatrice/common`.
@ -229,7 +239,7 @@ FreeBSD 9.1 until the systems were updated.
5. Before you start Cockatrice for the first time, run `oracle -dlsets`
and download available cards, denn run `cockatrice`. The default
paths for decks, pics, cards and tokens are located in\
paths for decks, pics, cards and tokens are located in
`/home/<user>/.local/share/data/Cockatrice/Cockatrice`.
#### MacOS X
@ -244,10 +254,10 @@ Cockatrice is open source you are free to run your own. The compilation
works like already written above, but instead of invoking `cmake ..`,
you have to do it like this:
- If you want to build the server, use:\
- If you want to build the server, use:
`cmake -DWITH_SERVER=1 ..`
- If you want to build the server, but not the client, use:\
- If you want to build the server, but not the client, use:
`cmake -DWITH_SERVER=1 -DWITHOUT_CLIENT=1 ..`
There is more information on compiling and running Servatrice on CentOS
@ -368,13 +378,14 @@ has come out, you must re-run the Oracle and download set information.
except for “Instant” along with “Artifact” and “U”, the Deck editor
will only show you all Blue Instant and Artifact cards.
ll Letter & Card Type\
U & Blue\
W & White\
X & Colorless\
G & Green\
R & Red\
B & Black\
|Letter | Card Type |
|-------|-----------|
| U | Blue |
| W | White |
| X | Colorless |
| G | Green |
| R | Red |
| B | Black |
3. Card Data
: This section shows the Oracle text for the card that you currently
@ -736,7 +747,7 @@ players can not add or remove counters to or from your cards.
#### Pointing at Cards / Arrows
Pointing at cars is needed for resolving spells, or declaring attackers
Pointing at cards is needed for resolving spells, or declaring attackers
and blockers. All you need to do is right-click over a card and drag an
arrow over to what you are pointing at. Permanents, spells in the stack,
and even a players life total can be pointed at. You can point at your

Binary file not shown.

View file

@ -83,87 +83,115 @@ If someone runs his own server where you can register a user profile, read his d
\section{Downloading and Installing the Cockatrice Program}
Due to a legal dispute there are currently no official builds left, so currently you have to build your own binaries.
\subsection{Client compilation}
\subsection{Building the Client}
\subsubsection{Windows}
There should be two ways to compile Cockatrice: With Visual Studio 2010 and with MinGW.
As the Visual Studio method is more complicated and might not work, you should do it with MinGW.
The following howto has been tested with Windows 7 64Bit.
To build Cockatrice, we need the Cockatrice sourcecode, its dependencies and build tools of course.
Everything is freely available.
There should be two ways to compile Cockatrice:
With Microsoft Visual Studio 2010 (Visual C++ 2010) and with MinGW, a minimalist GNU environment for Windows.
We suggest to use Visual Studio because there is a severe problem with MinGW:
It doesn't offer a compatible version of its tools.
The Qt library needs a certain, old MinGW version\footnote{The officially needed version is MinGW 4.8.2, the last known working version was MinGW 20120426} which is unavailable on the internet because they use an online installer and don't offer old, stable releases.
Trying to build with the current version of MinGW will result in application crashes!
So MinGW and Qt force us to focus on Visual Studio and don't support MinGW.
Gladly, Microsoft offers Visual Studio Express free of charge, which is a limited but sufficient version of Visual Studio.
It only requires a free of charge registration after 30 days.
The following howto which uses Visual C++ 2010 Express has been tested with an up to date Windows 7 64Bit.
The resulting build is a 32bit binary, which runs on both 32bit and 64bit systems.
\paragraph{Prerequisites}
We need the Cockatrice sourcecode, it's dependencies and build tools. Everything is freely available:
Here is an introduction of all dependencies and tools needed for Cockatrice, followed by a list of downloadlinks in the same order.
\begin{enumerate}
\item MinGW is needed to compile everything, it ships the compiler and other tools for this task.
\item The Microsoft Windows SDK for Windows 7 and .NET Framework 4 provides tools and libraries to create Windows applications.
\item The Visual C++ 2010 SP 1 Compiler Update for Windows SDK 7.1 (KB2519277) is a necessary update for the SDK.
\item Microsoft Visual C++ 2010 Express is the actual development environment.
\item Microsoft Visual Studio 2010 Service Pack 1 (VS10sp1-KB983509) is an update for Visual Studio.
\item The Qt libraries 4.8.x for Windows (VS 2010) are the main dependency for Cockatrice.
\item protobuf 2.5.0 is another dependency for Cockatrice (it has no installer, you need to download the zip file with the sourcecode).
\item cmake version 2.8.12.x is needed to create Cockatrice's project files for Visual Studio. Version 3 has not been tested yet with Cockatrice.
\item git is needed to download the latest Cockatrice source code.
\item cmake is needed to create Cockatrice's project files for MinGW.
\item Qt 4.8 is a dependency for Cockatrice (download the MinGW version!)
\item protobuf 2.5 is another dependency for Cockatrice (download the zip file with the sourcecode).
\item Nullsoft Scriptable Install System (NSIS) which can be used to create an installer for your own Cockatrice version.
\item Nullsoft Scriptable Install System (NSIS 3.0b0) is a program to create the Windows installer for Cockatrice.
\end{enumerate}
All downloadlinks together:
\footnotesize{\begin{enumerate}
\item \url{http://sourceforge.net/projects/mingw/files/Installer/mingw-get-inst/mingw-get-inst-20120426/}
\item \url{http://www.microsoft.com/en-us/download/details.aspx?id=8279} % Win SDK
\item \url{http://www.microsoft.com/en-us/download/details.aspx?displaylang=en&id=4422} % SDK Update
\item \url{http://go.microsoft.com/?linkid=9709949} % MSVC
\item \url{http://www.microsoft.com/en-us/download/details.aspx?id=23691} % MSVC SP1
\item \url{http://download.qt-project.org/official_releases/qt/4.8/4.8.6/qt-opensource-windows-x86-vs2010-4.8.6.exe}
\item \url{http://www.cmake.org/files/v2.8/cmake-2.8.12.2-win32-x86.exe}
\item \url{http://git-scm.com/download/win}
\item \url{http://www.cmake.org/files/v2.8/cmake-2.8.10.2-win32-x86.exe}
\item \url{http://download.qt-project.org/official_releases/qt/4.8/4.8.4/qt-win-opensource-4.8.4-mingw.exe}
\item \url{http://protobuf.googlecode.com/files/protobuf-2.5.0.zip}
\item \url{http://nsis.sourceforge.net/Download}
\end{enumerate}}
\paragraph{Installation of the Prerequisites}
Problems will occur if you don't install the first four steps (all the Microsoft SDK and Visual Studio packages) in the exact same order as printed here!
\begin{enumerate}
\item Download MinGW (mingw-get-inst), git, cmake, protobuf 2.5 sources zip and Qt 4.8.4 MinGW (see links above).
\item Make a standard installation for git, cmake and NSIS.
\item Install MinGW:
\begin{enumerate}
\item Select default values everywhere, except: Also check the C++ Compiler, check the MSYS Basis System and MinGW Developer Toolkit.
\item Append \shellcmd{C:\textbackslash MinGW\textbackslash bin} to your PATH variable (google how to do it for your Windows version, if you don't know it).
This is very important and overseen many times! You can keep the PATH configuration dialog open for the next step.
\end{enumerate}
\item Install Qt, select default values everywhere, ignore the message regarding win32.h and append \shellcmd{C:\textbackslash Qt\textbackslash 4.8.4\textbackslash bin} to your PATH variable like you did for MinGW.
\item Unpack protobuf-2.5.0.zip in \shellcmd{C:\textbackslash MinGW\textbackslash msys\textbackslash 1.0\textbackslash home\textbackslash YOURLOGIN}
\begin{enumerate}
\item Open MinGW Shell, type the following commands exactly:
\item \shellcmd{cd protobuf-2.5.0/protobuf-2.5.0}
\item \shellcmd{./configure --prefix=`cd /mingw; pwd -W`} (these apostrophs are backticks and do not forget the dot at the beginning!)
\item \shellcmd{make; make install} (this builds and installs protobuf, which needs some time)
\item Close MinGW Shell
\end{enumerate}
\item Install Microsoft Windows SDK for Windows 7 and .NET Framework 4.
\item Apply the Visual C++ 2010 SP 1 Compiler Update for Windows SDK 7.1
\item Install Visual C++ 2010 Express (Start the web installer, you may disable Silverlight)
\item Apply Visual C++ 2010 Express Service Pack 1
\item Install Qt4 VS 2010 edition.
\item Install NSIS.
\item Install cmake. Choose to add CMake to the System path.
\item Install git. Choose Run Git from Windows Command Prompt.
\end{enumerate}
Your system is now able to compile Cockatrice. You do not have to repeat the process so far ever again.
As protobuf does neither provide an installer nor the libraries needed for Cockatrice, you have to build those with Visual Studio from the protobuf sources.
The Cockatrice installer will search for the protobuf libraries within the Cockatrice sources, so before unpacking and building protobuf, you need to download the Cockatrice sources first:
\begin{enumerate}
\item Right click into a folder, select Git Gui, then Clone Existing Directory,
\item enter Source Location \url{https://github.com/Daenyth/Cockatrice}
\item enter target directory (from now on called Cockatrice), click clone and wait until the sources have been downloaded,
\item close Git Gui.
\end{enumerate}
Now we prepare protobuf:
\begin{enumerate}
\item Create a \shellcmd{build} directory inside the Cockatrice directory.
\item Copy the protobuf-2.5.0.zip into the build directory.
\item Rightclick the zip, choose Extract all. This uses the Windows included zip unpacker to extract the archive.
\end{enumerate}
To be clear: you will (and must) have a Cockatrice/build/protobuf-2.5.0/protobuf-2.5.0 directory hierarchy after that!
Now the protobuf dependencies for Cockatrice will be built:
\begin{enumerate}
\item Start Visual C++ 2010 Express and from the File menu Open Project/Solution, move to the Cockatrice/build/protobuf-2.5.0/protobuf-2.5.0/vsprojects directory and choose protobuf.sln.
\item Let you guide through the Conversion Wizard, you don't need to create a backup.
\item After the conversion is finished, open the projects (uncheck ``Ask me for every project in this solution'' and click OK).
\item You don't need to look at the conversion report.
\item Select Release or Debug in the toolbar. Release optimizes the code for size and speed, while Debug creates larger, slower binaries, used for development. You need to use the same setting for Cockatrice later! We suggest to use Release.
\item Rightclick on libprotobuf, choose Build. Note that the output should say: Build started: Project libprotobuf, Configuration: Release Win32
\item Then rightclick on protoc, choose Build. This will build libprotoc and the protoc executable, also as Release Win32.
\item After the build succeeded, close Visual C++.
\end{enumerate}
The Cockatrice/build/protobuf-2.5.0/protobuf-2.5.0/vsprojects/Release directory now contains libprotobuf.dll, libprotobuf.lib and protoc.exe which are needed for Cockatrice.
\paragraph{Cockatrice Compilation}
Now everything is ready to compile Cockatrice.
\begin{enumerate}
\item Checkout Cockatrice:
\begin{enumerate}
\item Start Git Bash and type the following command exactly:
\item \shellcmd{git clone https://github.com/Daenyth/Cockatrice}
\item Close Git Bash
\end{enumerate}
\item Start CMake (cmake-gui) and do the following:
\begin{enumerate}
\item Where is the source code: Point to the Cockatrice directory
\item Where to build the binaries: Point to the Cockatrice/build directory (it doesn't matter if it exists; if it doesn't, cmake will ask later if it shall create this directory)
\item Check Advanced
\item Click Configure, choose MinGW, leave the rest default
\item An error will occur, set the following:
\begin{itemize}
\item Set PROTOBUF\_INCLUDE\_DIR to C:/MinGW/include/google/protobuf
\item Set PROTOBUF\_LIBRARY to C:/MinGW/lib/libprotobuf.dll.a
\item Set PROTOBUF\_LITE\_LIBRARY to C:/MinGW/lib/libprotobuf-lite.dll.a
\item Set PROTOBUF\_PROTOC\_EXECUTABLE to C:/MinGW/bin/protoc.exe
\item Set PROTOBUF\_PROTOC\_LIBRARY to C:/MinGW/lib/libprotoc.dll.a
\end{itemize}
\item Click Configure again, then Generate
\item Close CMake
\end{enumerate}
\item Start cmd.exe (the Windows Command Prompt) and type the following commands:
\begin{enumerate}
\item \shellcmd{cd Cockatrice/build} (this changes to the build directory)
\item \shellcmd{make} (this builds everything and might need some time)
\end{enumerate}
\item Start CMake GUI, locate the Cockatrice directory and locate the Cockatrice/build directory.
Then click Configure and choose Visual Studio 10.
An error will occur during the Configure process because CMake does not know the location of the protobuf library.
\item To satisfy CMake, check Advanced, enter ``protobuf'' in the Search field,
\begin{enumerate}
\item Set PROTOBUF\_INCLUDE\_DIR to Cockatrice/build/protobuf-2.5.0/protobuf-2.5.0/src/
\item Set PROTOBUF\_LIBRARY to Cockatrice/build/protobuf-2.5.0/protobuf-2.5.0/vsprojects/Release/libprotobuf.lib
\item Set PROTOBUF\_PROTOC\_EXECUTABLE to Cockatrice/build/protobuf-2.5.0/protobuf-2.5.0/vsprojects/Release/protoc.exe
\item Set PROTOBUF\_PROTOC\_LIBRARY to Cockatrice/build/protobuf-2.5.0/protobuf-2.5.0/vsprojects/Release/libprotoc.lib % TODO: Is this needed? I don't think so; but it doesn't hurt either.
\item Click Configure again.
\end{enumerate}
\item Click Generate, then close CMake GUI. The project files have been generated.
\item Start Visual C++ 2010 Express and from the File menu select Open Project/Solution, point to the Cockatrice/build directory and choose Cockatrice.sln.
\item Select Release or Debug in the toolbar exactly as you did for protobuf. We suggest Release.
\item Rightclick on ALL\_BUILD, choose Build.
\end{enumerate}
Cockatrice has now been downloaded and built for the first time. You do not have to repeat the process so far ever again.
\paragraph{Updating your Cockatrice build}
If you just compiled Cockatrice for the first time, you skip this step obviously.
@ -174,17 +202,19 @@ But if you want to update Cockatrice after the source code changed on github, do
\item \shellcmd{git pull origin master}
\item \shellcmd{Close Git Bash}
\end{enumerate}
\item Start cmd.exe, change to Cockatrice/build, type make like you did previously.
\item Start Visual C++ 2010 Express and build the Cockatrice sources again.
\end{enumerate}
Cockatrice has now been updated and built. You may repeat this process every time when the source code changed.
\paragraph{Cockatrice installation}
To install Cockatrice, you have to create an installer with NSIS now.
Change to the directory \shellcmd{nsis} in the Cockatrice root directory, right click the cockatrice.nsi file and select \shellcmd{Compile NSIS Script}.
Change to the directory \shellcmd{nsis} in the Cockatrice directory, right click the cockatrice.nsi file and select \shellcmd{Compile NSIS Script}.
The NSIS program then creates a file called cockatrice\_win32\_YYYYmmdd\_git-xxxxxxx.exe. This is the complete, redistributable installer for your Cockatrice build.
Now install Cockatrice by executing the installer.
Note: if you installed MinGW or Qt in other than the default paths, you have to fix the paths in the cockatrice.nsi file (also if some libraries change); you can edit this file with a text editor.
Note: if you installed Qt in other than the default path, you have to fix the paths in the cockatrice.nsi file; you can edit this file with a text editor.
We will remove this static NSIS file in the future and let CMake create the NSIS file on the fly.
\paragraph{Create a card database}
Start the oracle.exe (the installer does this automatically) and let it generate a current cards.xml file:
@ -194,7 +224,7 @@ Start the oracle.exe (the installer does this automatically) and let it generate
\end{enumerate}
Congratulations, you may now use Cockatrice!
\subsubsection{Linux and BSD}
\subsubsection{Linux, BSD, OS X}
The following procedures have been tested with Debian Wheezy, Fedora 18, XUbuntu 13.10, FreeBSD 9.1 and 10.0.
If you use Gentoo with KDE you have the needed prerequisites and may continue with downloading the source.
If you use Bodhi or Arch Linux (AUR) or another distribution that includes Cockatrice, you might install Cockatrice from the default packages -- though the package might be old,
@ -204,11 +234,12 @@ Before you install new software, you should update your system. The following in
\begin{enumerate}
\item You need to install the build tools and dependencies. This varies between the Linux distributions.
\begin{description}
\item[Debian, Ubuntu and spin-offs] \shellcmd{sudo apt-get install build-essential git libqt4-dev qtmobility-dev libprotobuf-dev protobuf-compiler cmake} (see note below regarding pthread)
\item[Debian, Ubuntu and spin-offs] \shellcmd{sudo apt-get install build-essential git libqt4-dev qtmobility-dev libprotobuf-dev protobuf-compiler cmake}
\item[Fedora] \shellcmd{sudo yum groupinstall "Development Tools"\\
yum install qt-devel qt-mobility-devel protobuf-devel protobuf-compiler cmake}
\item[FreeBSD 9] \shellcmd{pkg\_add -r qt4 qt4-linguist qt4-moc qt4-qmake qt4-rcc qt4-uic git cmake protobuf}
\item[FreeBSD 10] \shellcmd{pkg install qt4 qt4-linguist qt4-moc qt4-qmake qt4-rcc qt4-uic git cmake protobuf}
\item[OS X] \shellcmd{brew install qt cmake protobuf}
\end{description}
\item Download the sources from github via \\ \shellcmd{cd\\ git clone https://github.com/Daenyth/Cockatrice.git}
\item To compile the sources, change into the newly created directory, create a build directory and invoke cmake:\\
@ -217,19 +248,13 @@ mkdir build \\
cd build \\
cmake ..\\
make}\\
\begin{framed}
If you have linking errors with pthread\_* add 'pthread' to the ``target\_link\_libraries'' entry in the \shellcmd{CMakeFiles.txt} in \shellcmd{Cockatrice/common}, e.g. for Xubuntu, then continue the make process.
\end{framed}
\item You may install the program into the directory \shellcmd{/usr/local} by typing \shellcmd{sudo make install} but you should also be able to start
cockatrice and the oracle from the build directory.
\item Before you start Cockatrice for the first time, run \shellcmd{oracle -dlsets} and download available cards, then run \shellcmd{cockatrice}.
The default paths for decks, pics, cards and tokens are located in \\ \shellcmd{/home/<user>/.local/share/data/Cockatrice/Cockatrice}.
\end{enumerate}
\subsubsection{MacOS X}
TODO, please contribute this section! See Linux section, then use the \shellcmd{prepareMacRelease.sh} script from Cockatrice.
\subsection{Server compilation}
\subsection{Building the Server}
You don't need your own server if you plan to play only. But as Cockatrice is open source you are free to run your own.
The compilation works like already written above, but instead of invoking \shellcmd{cmake ..}, you have to do it like this:
\begin{itemize}
@ -487,7 +512,7 @@ Sometimes Counters are needed to be placed on cards that the counters on the sid
(One of each counter)
\subsubsection{Pointing at Cards / Arrows}
Pointing at cars is needed for resolving spells, or declaring attackers and blockers. All you need to do is right-click over a card and drag an arrow over to what you are pointing at. Permanents, spells in the stack, and even a players life total can be pointed at. You can point at your opponents cards and life total, and they can point at yours. When your arrows are no loner needed, press Ctrl-R to remove them from the screen.
Pointing at cards is needed for resolving spells, or declaring attackers and blockers. All you need to do is right-click over a card and drag an arrow over to what you are pointing at. Permanents, spells in the stack, and even a players life total can be pointed at. You can point at your opponents cards and life total, and they can point at yours. When your arrows are no loner needed, press Ctrl-R to remove them from the screen.
\begin{center}
\includegraphics[scale=0.5]{pics/fetch98fd} \\

View file

@ -9,6 +9,9 @@ OutFile "cockatrice_win32_${TIMESTAMP}_git-${VERSION}.exe"
SetCompressor /SOLID lzma
InstallDir "$PROGRAMFILES\Cockatrice"
; set the Qt install dir here (and make sure you use the latest 4.8 version for packaging)
!define QTDIR "C:\Qt\4.8.6"
!define MUI_ABORTWARNING
!define MUI_WELCOMEFINISHPAGE_BITMAP "leftimage.bmp"
!define MUI_UNWELCOMEFINISHPAGE_BITMAP "leftimage.bmp"
@ -34,35 +37,33 @@ InstallDir "$PROGRAMFILES\Cockatrice"
!insertmacro MUI_LANGUAGE "English"
Section "Application" SecApplication
SetShellVarContext all
SetOutPath "$INSTDIR"
File ..\build\cockatrice\cockatrice.exe
File ..\build\oracle\oracle.exe
File ..\build\cockatrice\Release\cockatrice.exe
File ..\build\oracle\Release\oracle.exe
File ..\doc\usermanual\Usermanual.pdf
File C:\MinGW\bin\libstdc++-6.dll
File C:\MinGW\bin\libgcc_s_dw2-1.dll
File C:\MinGW\bin\mingwm10.dll
File C:\MinGW\bin\libprotobuf-8.dll
File C:\Qt\4.8.4\bin\QtCore4.dll
File C:\Qt\4.8.4\bin\QtGui4.dll
File C:\Qt\4.8.4\bin\QtNetwork4.dll
File C:\Qt\4.8.4\bin\QtSvg4.dll
File C:\Qt\4.8.4\bin\QtXml4.dll
File C:\Qt\4.8.4\bin\QtMultimedia4.dll
File ..\build\protobuf-2.5.0\protobuf-2.5.0\vsprojects\Release\libprotobuf.lib
File "${QTDIR}\bin\QtCore4.dll"
File "${QTDIR}\bin\QtGui4.dll"
File "${QTDIR}\bin\QtNetwork4.dll"
File "${QTDIR}\bin\QtSvg4.dll"
File "${QTDIR}\bin\QtXml4.dll"
File "${QTDIR}\bin\QtMultimedia4.dll"
SetOutPath "$INSTDIR\zonebg"
File /r ..\zonebg\*.*
SetOutPath "$INSTDIR\plugins"
SetOutPath "$INSTDIR\plugins\codecs"
File C:\Qt\4.8.4\plugins\codecs\qcncodecs4.dll
File C:\Qt\4.8.4\plugins\codecs\qjpcodecs4.dll
File C:\Qt\4.8.4\plugins\codecs\qkrcodecs4.dll
File C:\Qt\4.8.4\plugins\codecs\qtwcodecs4.dll
File "${QTDIR}\plugins\codecs\qcncodecs4.dll"
File "${QTDIR}\plugins\codecs\qjpcodecs4.dll"
File "${QTDIR}\plugins\codecs\qkrcodecs4.dll"
File "${QTDIR}\plugins\codecs\qtwcodecs4.dll"
SetOutPath "$INSTDIR\plugins\iconengines"
File C:\Qt\4.8.4\plugins\iconengines\qsvgicon4.dll
File "${QTDIR}\plugins\iconengines\qsvgicon4.dll"
SetOutPath "$INSTDIR\plugins\imageformats"
File C:\Qt\4.8.4\plugins\imageformats\qjpeg4.dll
File C:\Qt\4.8.4\plugins\imageformats\qsvg4.dll
File "${QTDIR}\plugins\imageformats\qjpeg4.dll"
File "${QTDIR}\plugins\imageformats\qsvg4.dll"
SetOutPath "$INSTDIR\sounds"
File /r ..\sounds\*.*
@ -70,9 +71,9 @@ Section "Application" SecApplication
SetOutPath "$INSTDIR\translations"
File /r ..\build\cockatrice\*.qm
WriteUninstaller "$INSTDIR\uninstall.exe"
${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
IntFmt $0 "0x%08X" $0
WriteUninstaller "$INSTDIR\uninstall.exe"
${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
IntFmt $0 "0x%08X" $0
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cockatrice" "DisplayName" "Cockatrice"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cockatrice" "UninstallString" "$\"$INSTDIR\uninstall.exe$\""
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cockatrice" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S"
@ -96,38 +97,36 @@ Section "Start menu item" SecStartMenu
SectionEnd
Section Uninstall
RMDir /r "$INSTDIR\zonebg"
RMDir /r "$INSTDIR\plugins"
RMDir /r "$INSTDIR\sounds"
SetShellVarContext all
RMDir /r "$INSTDIR\zonebg"
RMDir /r "$INSTDIR\plugins"
RMDir /r "$INSTDIR\sounds"
RMDir /r "$INSTDIR\translations"
Delete "$INSTDIR\uninstall.exe"
Delete "$INSTDIR\cockatrice.exe"
Delete "$INSTDIR\oracle.exe"
Delete "$INSTDIR\Usermanual.pdf"
Delete "$INSTDIR\libstdc++-6.dll"
Delete "$INSTDIR\libprotobuf-8.dll"
Delete "$INSTDIR\libgcc_s_dw2-1.dll"
Delete "$INSTDIR\mingwm10.dll"
Delete "$INSTDIR\QtCore4.dll"
Delete "$INSTDIR\QtGui4.dll"
Delete "$INSTDIR\QtNetwork4.dll"
Delete "$INSTDIR\QtSvg4.dll"
Delete "$INSTDIR\QtXml4.dll"
Delete "$INSTDIR\uninstall.exe"
Delete "$INSTDIR\cockatrice.exe"
Delete "$INSTDIR\oracle.exe"
Delete "$INSTDIR\Usermanual.pdf"
Delete "$INSTDIR\libprotobuf.lib"
Delete "$INSTDIR\QtCore4.dll"
Delete "$INSTDIR\QtGui4.dll"
Delete "$INSTDIR\QtNetwork4.dll"
Delete "$INSTDIR\QtSvg4.dll"
Delete "$INSTDIR\QtXml4.dll"
Delete "$INSTDIR\QtMultimedia4.dll"
RMDir "$INSTDIR"
RMDir "$INSTDIR"
RMDir /r "$SMPROGRAMS\Cockatrice"
DeleteRegKey HKCU "Software\Cockatrice"
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cockatrice"
DeleteRegKey HKCU "Software\Cockatrice"
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cockatrice"
SectionEnd
LangString DESC_SecApplication ${LANG_ENGLISH} "Cockatrice program files"
LangString DESC_SecUpdateConfig ${LANG_ENGLISH} "Update the paths in the application settings according to the installation paths."
LangString DESC_SecStartMenu ${LANG_ENGLISH} "Create start menu items for Cockatrice and Oracle."
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
!insertmacro MUI_DESCRIPTION_TEXT ${SecApplication} $(DESC_SecApplication)
!insertmacro MUI_DESCRIPTION_TEXT ${SecUpdateConfig} $(DESC_SecUpdateConfig)
!insertmacro MUI_DESCRIPTION_TEXT ${SecStartMenu} $(DESC_SecStartMenu)
!insertmacro MUI_DESCRIPTION_TEXT ${SecApplication} $(DESC_SecApplication)
!insertmacro MUI_DESCRIPTION_TEXT ${SecUpdateConfig} $(DESC_SecUpdateConfig)
!insertmacro MUI_DESCRIPTION_TEXT ${SecStartMenu} $(DESC_SecStartMenu)
!insertmacro MUI_FUNCTION_DESCRIPTION_END

View file

@ -1,32 +1,77 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
# CMakeLists for oracle directory
#
# provides the oracle binary
PROJECT(oracle)
# paths
set(DESKTOPDIR share/applications CACHE STRING "path to .desktop files")
SET(oracle_SOURCES src/main.cpp src/oracleimporter.cpp src/window_main.cpp ../cockatrice/src/carddatabase.cpp ../cockatrice/src/settingscache.cpp)
SET(oracle_HEADERS src/oracleimporter.h src/window_main.h ../cockatrice/src/carddatabase.h ../cockatrice/src/settingscache.h)
SET(oracle_SOURCES
src/main.cpp
src/oraclewizard.cpp
src/oracleimporter.cpp
../cockatrice/src/carddatabase.cpp
../cockatrice/src/settingscache.cpp
../cockatrice/src/qt-json/json.cpp
)
SET(QT_USE_QTNETWORK TRUE)
SET(QT_USE_QTXML TRUE)
SET(QT_USE_QTSVG TRUE)
FIND_PACKAGE(Qt4 REQUIRED)
set(CMAKE_BUILD_TYPE Release)
set(CMAKE_CXX_FLAGS_RELEASE "-s -O2")
QT4_WRAP_CPP(oracle_HEADERS_MOC ${oracle_HEADERS})
# Include directories
INCLUDE(${QT_USE_FILE})
INCLUDE_DIRECTORIES(../cockatrice/src)
ADD_EXECUTABLE(oracle WIN32 MACOSX_BUNDLE ${oracle_SOURCES} ${oracle_HEADERS_MOC})
TARGET_LINK_LIBRARIES(oracle ${QT_LIBRARIES})
# Build oracle binary and link it
ADD_EXECUTABLE(oracle WIN32 MACOSX_BUNDLE ${oracle_SOURCES} ${oracle_MOC_SRCS})
TARGET_LINK_LIBRARIES(oracle ${QT_QTMAIN_LIBRARY} ${QT_LIBRARIES})
if(MSVC)
set_target_properties(oracle PROPERTIES LINK_FLAGS "/SUBSYSTEM:WINDOWS")
endif(MSVC)
if(UNIX)
if(APPLE)
INSTALL(TARGETS oracle BUNDLE DESTINATION ./)
else()
# Assume linux
INSTALL(TARGETS oracle RUNTIME DESTINATION bin/)
endif()
elseif(WIN32)
INSTALL(TARGETS oracle RUNTIME DESTINATION ./)
endif()
IF (NOT APPLE)
INSTALL(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/oracle DESTINATION bin)
ELSE (APPLE)
INSTALL(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/oracle.app DESTINATION bin)
ENDIF (NOT APPLE)
IF (NOT WIN32 AND NOT APPLE)
INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/oracle.desktop DESTINATION ${DESKTOPDIR})
INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/oracle.desktop DESTINATION ${DESKTOPDIR})
ENDIF (NOT WIN32 AND NOT APPLE)
if(APPLE)
set(plugin_dest_dir ./oracle.app/Contents/Plugins)
set(qtconf_dest_dir ./oracle.app/Contents/Resources)
# note: no codecs in qt5
# note: phonon_backend => mediaservice
# note: needs platform on osx
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
install(DIRECTORY "${QT_PLUGINS_DIR}/" DESTINATION ${plugin_dest_dir} COMPONENT Runtime
FILES_MATCHING REGEX "(codecs|iconengines|imageformats|mediaservice|phonon_backend|platforms)/.*_debug\\.dylib")
else()
install(DIRECTORY "${QT_PLUGINS_DIR}/" DESTINATION ${plugin_dest_dir} COMPONENT Runtime
FILES_MATCHING REGEX "(codecs|iconengines|imageformats|mediaservice|phonon_backend|platforms)/[^_]*\\.dylib")
endif()
install(CODE "
file(WRITE \"${qtconf_dest_dir}/qt.conf\" \"[Paths]
Plugins = Plugins\")
" COMPONENT Runtime)
install(CODE "
file(GLOB_RECURSE QTPLUGINS
\"${plugin_dest_dir}/*.dylib\")
include(BundleUtilities)
fixup_bundle(\"\${CMAKE_INSTALL_PREFIX}/oracle.app\" \"\${QTPLUGINS}\" \"${QT_LIBRARY_DIR}\")
" COMPONENT Runtime)
endif()

View file

@ -1,6 +1,6 @@
#include <QApplication>
#include <QTextCodec>
#include "window_main.h"
#include "oraclewizard.h"
#include "settingscache.h"
SettingsCache *settingsCache;
@ -12,13 +12,14 @@ int main(int argc, char *argv[])
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
QCoreApplication::setOrganizationName("Cockatrice");
QCoreApplication::setOrganizationDomain("cockatrice.de");
QCoreApplication::setOrganizationDomain("cockatrice");
// this can't be changed, as it influences the default savepath for cards.xml
QCoreApplication::setApplicationName("Cockatrice");
settingsCache = new SettingsCache;
WindowMain wnd;
wnd.show();
OracleWizard wizard;
wizard.show();
return app.exec();
}

View file

@ -1,325 +1,242 @@
#include "oracleimporter.h"
#include <QtGui>
#include <QtNetwork>
#include <QXmlStreamReader>
#include <QDomDocument>
#include <QDebug>
#include "qt-json/json.h"
OracleImporter::OracleImporter(const QString &_dataDir, QObject *parent)
: CardDatabase(parent), dataDir(_dataDir), setIndex(-1)
: CardDatabase(parent), dataDir(_dataDir)
{
buffer = new QBuffer(this);
http = new QHttp(this);
connect(http, SIGNAL(requestFinished(int, bool)), this, SLOT(httpRequestFinished(int, bool)));
connect(http, SIGNAL(responseHeaderReceived(const QHttpResponseHeader &)), this, SLOT(readResponseHeader(const QHttpResponseHeader &)));
connect(http, SIGNAL(dataReadProgress(int, int)), this, SIGNAL(dataReadProgress(int, int)));
}
bool OracleImporter::readSetsFromFile(const QString &fileName)
{
QFile setsFile(fileName);
if (!setsFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
QMessageBox::critical(0, tr("Error"), tr("Cannot open file '%1'.").arg(fileName));
return false;
}
QXmlStreamReader xml(&setsFile);
return readSetsFromXml(xml);
}
bool OracleImporter::readSetsFromByteArray(const QByteArray &data)
{
QXmlStreamReader xml(data);
return readSetsFromXml(xml);
}
QList<SetToDownload> newSetList;
bool ok;
setsMap = QtJson::Json::parse(QString(data), ok).toMap();
if (!ok) {
qDebug() << "error: QtJson::Json::parse()";
return 0;
}
QListIterator<QVariant> it(setsMap.values());
QVariantMap map;
bool OracleImporter::readSetsFromXml(QXmlStreamReader &xml)
{
QList<SetToDownload> newSetList;
QString edition;
QString editionLong;
QString editionURL;
while (!xml.atEnd()) {
if (xml.readNext() == QXmlStreamReader::EndElement)
break;
if (xml.name() == "set") {
bool import = xml.attributes().value("import").toString().toInt();
while (!xml.atEnd()) {
if (xml.readNext() == QXmlStreamReader::EndElement)
break;
if (xml.name() == "name")
edition = xml.readElementText();
else if (xml.name() == "longname")
editionLong = xml.readElementText();
else if (xml.name() == "url")
editionURL = xml.readElementText();
}
newSetList.append(SetToDownload(edition, editionLong, editionURL, import));
edition = editionLong = editionURL = QString();
} else if (xml.name() == "picture_url")
pictureUrl = xml.readElementText();
else if (xml.name() == "picture_url_hq")
pictureUrlHq = xml.readElementText();
else if (xml.name() == "picture_url_st")
pictureUrlSt = xml.readElementText();
else if (xml.name() == "set_url")
setUrl = xml.readElementText();
}
if (newSetList.isEmpty())
return false;
allSets = newSetList;
return true;
QString edition;
QString editionLong;
QVariant editionCards;
bool import;
while (it.hasNext()) {
map = it.next().toMap();
edition = map.value("code").toString();
editionLong = map.value("name").toString();
editionCards = map.value("cards");
// core and expansion sets are marked to be imported by default
import = (0 == QString::compare(map.value("type").toString(), QString("core"), Qt::CaseInsensitive) ||
0 == QString::compare(map.value("type").toString(), QString("expansion"), Qt::CaseInsensitive));
newSetList.append(SetToDownload(edition, editionLong, editionCards, import));
}
qSort(newSetList);
if (newSetList.isEmpty())
return false;
allSets = newSetList;
return true;
}
CardInfo *OracleImporter::addCard(const QString &setName,
QString cardName,
bool isToken,
int cardId,
const QString &cardCost,
const QString &cardType,
const QString &cardPT,
int cardLoyalty,
const QStringList &cardText)
QString cardName,
bool isToken,
int cardId,
QString &cardCost,
const QString &cardType,
const QString &cardPT,
int cardLoyalty,
const QStringList &cardText)
{
QString fullCardText = cardText.join("\n");
bool splitCard = false;
if (cardName.contains('(')) {
cardName.remove(QRegExp(" \\(.*\\)"));
splitCard = true;
}
// Workaround for card name weirdness
if (cardName.contains("XX"))
cardName.remove("XX");
cardName = cardName.replace("Æ", "AE");
cardName = cardName.replace("", "'");
QString fullCardText = cardText.join("\n");
bool splitCard = false;
if (cardName.contains('(')) {
cardName.remove(QRegExp(" \\(.*\\)"));
splitCard = true;
}
// Workaround for card name weirdness
if (cardName.contains("XX"))
cardName.remove("XX");
cardName = cardName.replace("Æ", "AE");
cardName = cardName.replace("", "'");
CardInfo *card;
if (cardHash.contains(cardName)) {
card = cardHash.value(cardName);
if (splitCard && !card->getText().contains(fullCardText))
card->setText(card->getText() + "\n---\n" + fullCardText);
} else {
bool mArtifact = false;
if (cardType.endsWith("Artifact"))
for (int i = 0; i < cardText.size(); ++i)
if (cardText[i].contains("{T}") && cardText[i].contains("to your mana pool"))
mArtifact = true;
QStringList colors;
QStringList allColors = QStringList() << "W" << "U" << "B" << "R" << "G";
for (int i = 0; i < allColors.size(); i++)
if (cardCost.contains(allColors[i]))
colors << allColors[i];
if (cardText.contains(cardName + " is white."))
colors << "W";
if (cardText.contains(cardName + " is blue."))
colors << "U";
if (cardText.contains(cardName + " is black."))
colors << "B";
if (cardText.contains(cardName + " is red."))
colors << "R";
if (cardText.contains(cardName + " is green."))
colors << "G";
bool cipt = (cardText.contains(cardName + " enters the battlefield tapped."));
card = new CardInfo(this, cardName, isToken, cardCost, cardType, cardPT, fullCardText, colors, cardLoyalty, cipt);
int tableRow = 1;
QString mainCardType = card->getMainCardType();
if ((mainCardType == "Land") || mArtifact)
tableRow = 0;
else if ((mainCardType == "Sorcery") || (mainCardType == "Instant"))
tableRow = 3;
else if (mainCardType == "Creature")
tableRow = 2;
card->setTableRow(tableRow);
cardHash.insert(cardName, card);
}
card->setPicURL(setName, getPictureUrl(pictureUrl, cardId, cardName, setName));
card->setPicURLHq(setName, getPictureUrl(pictureUrlHq, cardId, cardName, setName));
card->setPicURLSt(setName, getPictureUrl(pictureUrlSt, cardId, cardName, setName));
return card;
// Remove {} around mana costs
cardCost.remove(QChar('{'));
cardCost.remove(QChar('}'));
CardInfo *card;
if (cardHash.contains(cardName)) {
card = cardHash.value(cardName);
if (splitCard && !card->getText().contains(fullCardText))
card->setText(card->getText() + "\n---\n" + fullCardText);
} else {
bool mArtifact = false;
if (cardType.endsWith("Artifact"))
for (int i = 0; i < cardText.size(); ++i)
if (cardText[i].contains("{T}") && cardText[i].contains("to your mana pool"))
mArtifact = true;
QStringList colors;
QStringList allColors = QStringList() << "W" << "U" << "B" << "R" << "G";
for (int i = 0; i < allColors.size(); i++)
if (cardCost.contains(allColors[i]))
colors << allColors[i];
if (cardText.contains(cardName + " is white."))
colors << "W";
if (cardText.contains(cardName + " is blue."))
colors << "U";
if (cardText.contains(cardName + " is black."))
colors << "B";
if (cardText.contains(cardName + " is red."))
colors << "R";
if (cardText.contains(cardName + " is green."))
colors << "G";
bool cipt = (cardText.contains(cardName + " enters the battlefield tapped."));
card = new CardInfo(this, cardName, isToken, cardCost, cardType, cardPT, fullCardText, colors, cardLoyalty, cipt);
int tableRow = 1;
QString mainCardType = card->getMainCardType();
if ((mainCardType == "Land") || mArtifact)
tableRow = 0;
else if ((mainCardType == "Sorcery") || (mainCardType == "Instant"))
tableRow = 3;
else if (mainCardType == "Creature")
tableRow = 2;
card->setTableRow(tableRow);
cardHash.insert(cardName, card);
}
card->setMuId(setName, cardId);
return card;
}
int OracleImporter::importTextSpoiler(CardSet *set, const QByteArray &data)
int OracleImporter::importTextSpoiler(CardSet *set, const QVariant &data)
{
int cards = 0;
QString bufferContents(data);
// Workaround for ampersand bug in text spoilers
int index = -1;
while ((index = bufferContents.indexOf('&', index + 1)) != -1) {
int semicolonIndex = bufferContents.indexOf(';', index);
if (semicolonIndex > 5) {
bufferContents.insert(index + 1, "amp;");
index += 4;
}
}
QDomDocument doc;
QString errorMsg;
int errorLine, errorColumn;
if (!doc.setContent(bufferContents, &errorMsg, &errorLine, &errorColumn))
qDebug() << "error:" << errorMsg << "line:" << errorLine << "column:" << errorColumn;
int cards = 0;
QListIterator<QVariant> it(data.toList());
QVariantMap map;
QString cardName;
QString cardCost;
QString cardType;
QString cardPT;
QString cardText;
int cardId;
int cardLoyalty;
QMap<int, QVariantMap> splitCards;
QDomNodeList divs = doc.elementsByTagName("div");
for (int i = 0; i < divs.size(); ++i) {
QDomElement div = divs.at(i).toElement();
QDomNode divClass = div.attributes().namedItem("class");
if (divClass.nodeValue() == "textspoiler") {
QString cardName, cardCost, cardType, cardPT, cardText;
int cardId = 0;
int cardLoyalty = 0;
QDomNodeList trs = div.elementsByTagName("tr");
for (int j = 0; j < trs.size(); ++j) {
QDomElement tr = trs.at(j).toElement();
QDomNodeList tds = tr.elementsByTagName("td");
if (tds.size() != 2) {
QStringList cardTextSplit = cardText.split("\n");
for (int i = 0; i < cardTextSplit.size(); ++i)
cardTextSplit[i] = cardTextSplit[i].trimmed();
CardInfo *card = addCard(set->getShortName(), cardName, false, cardId, cardCost, cardType, cardPT, cardLoyalty, cardTextSplit);
if (!set->contains(card)) {
card->addToSet(set);
cards++;
}
cardName = cardCost = cardType = cardPT = cardText = QString();
} else {
QString v1 = tds.at(0).toElement().text().simplified();
QString v2 = tds.at(1).toElement().text().replace(trUtf8(""), "-");
if (v1 == "Name") {
QDomElement a = tds.at(1).toElement().elementsByTagName("a").at(0).toElement();
QString href = a.attributes().namedItem("href").nodeValue();
cardId = href.mid(href.indexOf("multiverseid=") + 13).toInt();
cardName = v2.simplified();
} else if (v1 == "Cost:")
cardCost = v2.simplified();
else if (v1 == "Type:")
cardType = v2.simplified();
else if (v1 == "Pow/Tgh:")
cardPT = v2.simplified().remove('(').remove(')');
else if (v1 == "Rules Text:")
cardText = v2.trimmed();
else if (v1 == "Loyalty:")
cardLoyalty = v2.trimmed().remove('(').remove(')').toInt();
}
}
break;
}
}
return cards;
while (it.hasNext()) {
map = it.next().toMap();
if(0 == QString::compare(map.value("layout").toString(), QString("split"), Qt::CaseInsensitive))
{
// Split card handling
cardId = map.contains("multiverseid") ? map.value("multiverseid").toInt() : 0;
if(splitCards.contains(cardId))
{
// merge two split cards
QVariantMap tmpMap = splitCards.take(cardId);
QVariantMap * card1 = 0, * card2 = 0;
// same cardid
cardId = map.contains("multiverseid") ? map.value("multiverseid").toInt() : 0;
// this is currently an integer; can't accept 2 values
cardLoyalty = 0;
// determine which subcard is the first one in the split
QStringList names=map.contains("names") ? map.value("names").toStringList() : QStringList("");
if(names.count()>0 &&
map.contains("name") &&
0 == QString::compare(map.value("name").toString(), names.at(0)))
{
// map is the left part of the split card, tmpMap is right part
card1 = &map;
card2 = &tmpMap;
} else {
//tmpMap is the left part of the split card, map is right part
card1 = &tmpMap;
card2 = &map;
}
// add first card's data
cardName = card1->contains("name") ? card1->value("name").toString() : QString("");
cardCost = card1->contains("manaCost") ? card1->value("manaCost").toString() : QString("");
cardType = card1->contains("type") ? card1->value("type").toString() : QString("");
cardPT = card1->contains("power") || card1->contains("toughness") ? card1->value("power").toString() + QString('/') + card1->value("toughness").toString() : QString("");
cardText = card1->contains("text") ? card1->value("text").toString() : QString("");
// add second card's data
cardName += card2->contains("name") ? QString(" // ") + card2->value("name").toString() : QString("");
cardCost += card2->contains("manaCost") ? QString(" // ") + card2->value("manaCost").toString() : QString("");
cardType += card2->contains("type") ? QString(" // ") + card2->value("type").toString() : QString("");
cardPT += card2->contains("power") || card2->contains("toughness") ? QString(" // ") + card2->value("power").toString() + QString('/') + card2->value("toughness").toString() : QString("");
cardText += card2->contains("text") ? QString("\n\n---\n\n") + card2->value("text").toString() : QString("");
} else {
// first card od a pair; enqueue for later merging
splitCards.insert(cardId, map);
continue;
}
} else {
// normal cards handling
cardName = map.contains("name") ? map.value("name").toString() : QString("");
cardCost = map.contains("manaCost") ? map.value("manaCost").toString() : QString("");
cardType = map.contains("type") ? map.value("type").toString() : QString("");
cardPT = map.contains("power") || map.contains("toughness") ? map.value("power").toString() + QString('/') + map.value("toughness").toString() : QString("");
cardText = map.contains("text") ? map.value("text").toString() : QString("");
cardId = map.contains("multiverseid") ? map.value("multiverseid").toInt() : 0;
cardLoyalty = map.contains("loyalty") ? map.value("loyalty").toInt() : 0;
}
CardInfo *card = addCard(set->getShortName(), cardName, false, cardId, cardCost, cardType, cardPT, cardLoyalty, cardText.split("\n"));
if (!set->contains(card)) {
card->addToSet(set);
cards++;
}
}
return cards;
}
QString OracleImporter::getPictureUrl(QString url, int cardId, QString name, const QString &setName) const
int OracleImporter::startImport()
{
if ((name == "Island") || (name == "Swamp") || (name == "Mountain") || (name == "Plains") || (name == "Forest"))
name.append("1");
return url.replace("!cardid!", QString::number(cardId)).replace("!set!", setName).replace("!name!", name
.replace("ö", "o")
// .remove('\'')
.remove(" // ")
// .remove(',')
// .remove(':')
// .remove('.')
.remove(QRegExp("\\(.*\\)"))
.simplified()
// .replace(' ', '_')
// .replace('-', '_')
);
}
int OracleImporter::startDownload()
{
clear();
setsToDownload.clear();
for (int i = 0; i < allSets.size(); ++i)
if (allSets[i].getImport())
setsToDownload.append(allSets[i]);
if (setsToDownload.isEmpty())
return 0;
setIndex = 0;
emit setIndexChanged(0, 0, setsToDownload[0].getLongName());
downloadNextFile();
return setsToDownload.size();
}
void OracleImporter::downloadNextFile()
{
QString urlString = setsToDownload[setIndex].getUrl();
if (urlString.isEmpty())
urlString = setUrl;
urlString = urlString.replace("!longname!", setsToDownload[setIndex].getLongName());
if (urlString.startsWith("http://")) {
QUrl url(urlString);
http->setHost(url.host(), QHttp::ConnectionModeHttp, url.port() == -1 ? 0 : url.port());
QString path = QUrl::toPercentEncoding(urlString.mid(url.host().size() + 7).replace(' ', '+'), "?!$&'()*+,;=:@/");
buffer->close();
buffer->setData(QByteArray());
buffer->open(QIODevice::ReadWrite | QIODevice::Text);
reqId = http->get(path, buffer);
} else {
QFile file(dataDir + "/" + urlString);
file.open(QIODevice::ReadOnly | QIODevice::Text);
buffer->close();
buffer->setData(file.readAll());
buffer->open(QIODevice::ReadWrite | QIODevice::Text);
reqId = 0;
httpRequestFinished(reqId, false);
}
}
void OracleImporter::httpRequestFinished(int requestId, bool error)
{
if (error) {
QMessageBox::information(0, tr("HTTP"), tr("Error."));
return;
}
if (requestId != reqId)
return;
CardSet *set = new CardSet(setsToDownload[setIndex].getShortName(), setsToDownload[setIndex].getLongName());
if (!setHash.contains(set->getShortName()))
setHash.insert(set->getShortName(), set);
buffer->seek(0);
buffer->close();
int cards = importTextSpoiler(set, buffer->data());
if (cards > 0)
++setIndex;
if (setIndex == setsToDownload.size()) {
emit setIndexChanged(cards, setIndex, QString());
setIndex = -1;
} else {
downloadNextFile();
emit setIndexChanged(cards, setIndex, setsToDownload[setIndex].getLongName());
}
}
void OracleImporter::readResponseHeader(const QHttpResponseHeader &responseHeader)
{
switch (responseHeader.statusCode()) {
case 200:
case 301:
case 302:
case 303:
case 307:
break;
default:
QMessageBox::information(0, tr("HTTP"), tr("Download failed: %1.").arg(responseHeader.reasonPhrase()));
http->abort();
deleteLater();
}
clear();
int setCards = 0, setIndex= 0;
QListIterator<SetToDownload> it(allSets);
const SetToDownload * curSet;
while (it.hasNext())
{
curSet = & it.next();
if(!curSet->getImport())
continue;
CardSet *set = new CardSet(curSet->getShortName(), curSet->getLongName());
if (!setHash.contains(set->getShortName()))
setHash.insert(set->getShortName(), set);
int setCards = importTextSpoiler(set, curSet->getCards());
++setIndex;
emit setIndexChanged(setCards, setIndex, curSet->getLongName());
}
emit setIndexChanged(setCards, setIndex, QString());
// total number of sets
return setIndex;
}

View file

@ -1,53 +1,42 @@
#ifndef ORACLEIMPORTER_H
#define ORACLEIMPORTER_H
#include <carddatabase.h>
#include <QHttp>
#include <QMap>
class QBuffer;
class QXmlStreamReader;
#include <carddatabase.h>
class SetToDownload {
private:
QString shortName, longName, url;
QString shortName, longName;
bool import;
QVariant cards;
public:
const QString &getShortName() const { return shortName; }
const QString &getLongName() const { return longName; }
const QString &getUrl() const { return url; }
const QVariant &getCards() const { return cards; }
bool getImport() const { return import; }
void setImport(bool _import) { import = _import; }
SetToDownload(const QString &_shortName, const QString &_longName, const QString &_url, bool _import)
: shortName(_shortName), longName(_longName), url(_url), import(_import) { }
SetToDownload(const QString &_shortName, const QString &_longName, const QVariant &_cards, bool _import)
: shortName(_shortName), longName(_longName), cards(_cards), import(_import) { }
bool operator<(const SetToDownload &set) const { return longName.compare(set.longName, Qt::CaseInsensitive) < 0; }
};
class OracleImporter : public CardDatabase {
Q_OBJECT
private:
QList<SetToDownload> allSets, setsToDownload;
QString pictureUrl, pictureUrlHq, pictureUrlSt, setUrl;
QList<SetToDownload> allSets;
QVariantMap setsMap;
QString dataDir;
int setIndex;
int reqId;
QBuffer *buffer;
QHttp *http;
QString getPictureUrl(QString url, int cardId, QString name, const QString &setName) const;
void downloadNextFile();
bool readSetsFromXml(QXmlStreamReader &xml);
CardInfo *addCard(const QString &setName, QString cardName, bool isToken, int cardId, const QString &cardCost, const QString &cardType, const QString &cardPT, int cardLoyalty, const QStringList &cardText);
private slots:
void httpRequestFinished(int requestId, bool error);
void readResponseHeader(const QHttpResponseHeader &responseHeader);
CardInfo *addCard(const QString &setName, QString cardName, bool isToken, int cardId, QString &cardCost, const QString &cardType, const QString &cardPT, int cardLoyalty, const QStringList &cardText);
signals:
void setIndexChanged(int cardsImported, int setIndex, const QString &nextSetName);
void setIndexChanged(int cardsImported, int setIndex, const QString &setName);
void dataReadProgress(int bytesRead, int totalBytes);
public:
OracleImporter(const QString &_dataDir, QObject *parent = 0);
bool readSetsFromByteArray(const QByteArray &data);
bool readSetsFromFile(const QString &fileName);
int startDownload();
int importTextSpoiler(CardSet *set, const QByteArray &data);
int startImport();
int importTextSpoiler(CardSet *set, const QVariant &data);
QList<SetToDownload> &getSets() { return allSets; }
const QString &getDataDir() const { return dataDir; }
};

398
oracle/src/oraclewizard.cpp Normal file
View file

@ -0,0 +1,398 @@
#include <QtGui>
#include <QGridLayout>
#include <QDesktopServices>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include "oraclewizard.h"
#include "oracleimporter.h"
#define ALLSETS_URL "http://mtgjson.com/json/AllSets.json"
OracleWizard::OracleWizard(QWidget *parent)
: QWizard(parent)
{
settings = new QSettings(this);
importer = new OracleImporter(QDesktopServices::storageLocation(QDesktopServices::DataLocation), this);
addPage(new IntroPage);
addPage(new LoadSetsPage);
addPage(new ChooseSetsPage);
addPage(new SaveSetsPage);
setWindowTitle(tr("Oracle Importer"));
QWizard::setButtonText(QWizard::FinishButton, tr("Save"));
}
void OracleWizard::accept()
{
QDialog::accept();
}
void OracleWizard::enableButtons()
{
button(QWizard::NextButton)->setDisabled(false);
button(QWizard::BackButton)->setDisabled(false);
}
void OracleWizard::disableButtons()
{
button(QWizard::NextButton)->setDisabled(true);
button(QWizard::BackButton)->setDisabled(true);
}
IntroPage::IntroPage(QWidget *parent)
: OracleWizardPage(parent)
{
setTitle(tr("Introduction"));
label = new QLabel(tr("This wizard will import the list of sets and cards "
"that will be used by Cockatrice. You will need to "
"specify an url or a filename that will be used as a "
"source, and then choose the wanted sets from the list "
"of the available ones."),
this);
label->setWordWrap(true);
QVBoxLayout *layout = new QVBoxLayout(this);
layout->addWidget(label);
setLayout(layout);
}
LoadSetsPage::LoadSetsPage(QWidget *parent)
: OracleWizardPage(parent), nam(0)
{
setTitle(tr("Source selection"));
setSubTitle(tr("Please specify a source for the list of sets and cards. "
"You can specify an url address that will be download or "
"use an existing file from your computer."));
urlRadioButton = new QRadioButton(tr("Download url:"), this);
fileRadioButton = new QRadioButton(tr("Local file:"), this);
urlLineEdit = new QLineEdit(this);
fileLineEdit = new QLineEdit(this);
progressLabel = new QLabel(this);
progressBar = new QProgressBar(this);
urlRadioButton->setChecked(true);
fileButton = new QPushButton(tr("Choose file..."), this);
connect(fileButton, SIGNAL(clicked()), this, SLOT(actLoadSetsFile()));
QGridLayout *layout = new QGridLayout(this);
layout->addWidget(urlRadioButton, 0, 0);
layout->addWidget(urlLineEdit, 0, 1);
layout->addWidget(fileRadioButton, 1, 0);
layout->addWidget(fileLineEdit, 1, 1);
layout->addWidget(fileButton, 2, 1, Qt::AlignRight);
layout->addWidget(progressLabel, 3, 0);
layout->addWidget(progressBar, 3, 1);
connect(&watcher, SIGNAL(finished()), this, SLOT(importFinished()));
setLayout(layout);
}
void LoadSetsPage::initializePage()
{
urlLineEdit->setText(wizard()->settings->value("allsetsurl", ALLSETS_URL).toString());
progressLabel->hide();
progressBar->hide();
}
void LoadSetsPage::actLoadSetsFile()
{
QFileDialog dialog(this, tr("Load sets file"));
dialog.setFileMode(QFileDialog::ExistingFile);
dialog.setNameFilter("Sets JSON file (*.json)");
if(!fileLineEdit->text().isEmpty() && QFile::exists(fileLineEdit->text()))
dialog.selectFile(fileLineEdit->text());
if (!dialog.exec())
return;
fileLineEdit->setText(dialog.selectedFiles().at(0));
}
bool LoadSetsPage::validatePage()
{
// once the import is finished, we call next(); skip validation
if(wizard()->importer->getSets().count() > 0)
return true;
// else, try to import sets
if(urlRadioButton->isChecked())
{
QUrl url = QUrl::fromUserInput(urlLineEdit->text());
if(!url.isValid())
{
QMessageBox::critical(this, tr("Error"), tr("The provided url is not valid."));
return false;
}
progressLabel->setText(tr("Downloading (0MB)"));
// show an infinite progressbar
progressBar->setMaximum(0);
progressBar->setMinimum(0);
progressBar->setValue(0);
progressLabel->show();
progressBar->show();
wizard()->disableButtons();
setEnabled(false);
if(!nam)
nam = new QNetworkAccessManager(this);
QNetworkReply *reply = nam->get(QNetworkRequest(url));
connect(reply, SIGNAL(finished()), this, SLOT(actDownloadFinishedSetsFile()));
connect(reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(actDownloadProgressSetsFile(qint64, qint64)));
} else if(fileRadioButton->isChecked()) {
QFile setsFile(fileLineEdit->text());
if(!setsFile.exists())
{
QMessageBox::critical(this, tr("Error"), tr("Please choose a file."));
return false;
}
if (!setsFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
QMessageBox::critical(0, tr("Error"), tr("Cannot open file '%1'.").arg(fileLineEdit->text()));
return false;
}
wizard()->disableButtons();
setEnabled(false);
readSetsFromByteArray(setsFile.readAll());
}
return false;
}
void LoadSetsPage::actDownloadProgressSetsFile(qint64 received, qint64 total)
{
if(total > 0 && progressBar->maximum()==0)
{
progressBar->setMaximum(total);
progressBar->setValue(received);
}
progressLabel->setText(tr("Downloading (%1MB)").arg((int) received / 1048576));
}
void LoadSetsPage::actDownloadFinishedSetsFile()
{
progressLabel->hide();
progressBar->hide();
// check for a reply
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
QNetworkReply::NetworkError errorCode = reply->error();
if (errorCode != QNetworkReply::NoError) {
QMessageBox::critical(this, tr("Error"), tr("Network error: %1.").arg(reply->errorString()));
wizard()->enableButtons();
setEnabled(true);
reply->deleteLater();
return;
}
// save allsets.json url, but only if the user customized it and download was successfull
if(urlLineEdit->text() != QString(ALLSETS_URL))
wizard()->settings->setValue("allsetsurl", urlLineEdit->text());
else
wizard()->settings->remove("allsetsurl");
readSetsFromByteArray(reply->readAll());
reply->deleteLater();
}
void LoadSetsPage::readSetsFromByteArray(QByteArray data)
{
// show an infinite progressbar
progressBar->setMaximum(0);
progressBar->setMinimum(0);
progressBar->setValue(0);
progressLabel->setText(tr("Parsing file"));
progressLabel->show();
progressBar->show();
// Start the computation.
future = QtConcurrent::run(wizard()->importer, &OracleImporter::readSetsFromByteArray, data);
watcher.setFuture(future);
}
void LoadSetsPage::importFinished()
{
wizard()->enableButtons();
setEnabled(true);
progressLabel->hide();
progressBar->hide();
if(watcher.future().result())
{
wizard()->next();
} else {
QMessageBox::critical(this, tr("Error"), tr("The file was retrieved successfully, but it does not contain any sets data."));
}
}
ChooseSetsPage::ChooseSetsPage(QWidget *parent)
: OracleWizardPage(parent)
{
setTitle(tr("Sets selection"));
setSubTitle(tr("The following sets has been found in the source file. "
"Please mark the sets that will be imported."));
checkBoxLayout = new QVBoxLayout;
QWidget *checkboxFrame = new QWidget(this);
checkboxFrame->setLayout(checkBoxLayout);
QScrollArea *checkboxArea = new QScrollArea(this);
checkboxArea->setWidget(checkboxFrame);
checkboxArea->setWidgetResizable(true);
checkAllButton = new QPushButton(tr("&Check all"));
connect(checkAllButton, SIGNAL(clicked()), this, SLOT(actCheckAll()));
uncheckAllButton = new QPushButton(tr("&Uncheck all"));
connect(uncheckAllButton, SIGNAL(clicked()), this, SLOT(actUncheckAll()));
QGridLayout *layout = new QGridLayout(this);
layout->addWidget(checkboxArea, 0, 0, 1, 2);
layout->addWidget(checkAllButton, 1, 0);
layout->addWidget(uncheckAllButton, 1, 1);
setLayout(layout);
}
void ChooseSetsPage::initializePage()
{
// populate checkbox list
for (int i = 0; i < checkBoxList.size(); ++i)
delete checkBoxList[i];
checkBoxList.clear();
QList<SetToDownload> &sets = wizard()->importer->getSets();
for (int i = 0; i < sets.size(); ++i) {
QCheckBox *checkBox = new QCheckBox(sets[i].getLongName());
checkBox->setChecked(sets[i].getImport());
connect(checkBox, SIGNAL(stateChanged(int)), this, SLOT(checkBoxChanged(int)));
checkBoxLayout->addWidget(checkBox);
checkBoxList << checkBox;
}
}
void ChooseSetsPage::checkBoxChanged(int state)
{
QCheckBox *checkBox = qobject_cast<QCheckBox *>(sender());
QList<SetToDownload> &sets = wizard()->importer->getSets();
for (int i = 0; i < sets.size(); ++i)
if (sets[i].getLongName() == checkBox->text()) {
sets[i].setImport(state);
break;
}
}
void ChooseSetsPage::actCheckAll()
{
for (int i = 0; i < checkBoxList.size(); ++i)
checkBoxList[i]->setChecked(true);
}
void ChooseSetsPage::actUncheckAll()
{
for (int i = 0; i < checkBoxList.size(); ++i)
checkBoxList[i]->setChecked(false);
}
bool ChooseSetsPage::validatePage()
{
for (int i = 0; i < checkBoxList.size(); ++i)
{
if(checkBoxList[i]->isChecked())
return true;
}
QMessageBox::critical(this, tr("Error"), tr("Please mark at least one set."));
return false;
}
SaveSetsPage::SaveSetsPage(QWidget *parent)
: OracleWizardPage(parent)
{
setTitle(tr("Sets imported"));
setSubTitle(tr("The following sets has been imported. "
"Press \"Save\" to save the imported cards to the Cockatrice database."));
defaultPathCheckBox = new QCheckBox(this);
defaultPathCheckBox->setText(tr("Save to the default path (recommended)"));
defaultPathCheckBox->setChecked(true);
messageLog = new QTextEdit(this);
messageLog->setReadOnly(true);
QGridLayout *layout = new QGridLayout(this);
layout->addWidget(defaultPathCheckBox, 0, 0);
layout->addWidget(messageLog, 1, 0);
setLayout(layout);
}
void SaveSetsPage::cleanupPage()
{
disconnect(wizard()->importer, SIGNAL(setIndexChanged(int, int, const QString &)), 0, 0);
}
void SaveSetsPage::initializePage()
{
messageLog->clear();
connect(wizard()->importer, SIGNAL(setIndexChanged(int, int, const QString &)), this, SLOT(updateTotalProgress(int, int, const QString &)));
if (!wizard()->importer->startImport())
QMessageBox::critical(this, tr("Error"), tr("No set has been imported."));
}
void SaveSetsPage::updateTotalProgress(int cardsImported, int setIndex, const QString &setName)
{
if (setName.isEmpty()) {
messageLog->append("<b>" + tr("Import finished: %1 cards.").arg(wizard()->importer->getCardList().size()) + "</b>");
} else {
messageLog->append(tr("%1: %2 cards imported").arg(setName).arg(cardsImported));
}
messageLog->verticalScrollBar()->setValue(messageLog->verticalScrollBar()->maximum());
}
bool SaveSetsPage::validatePage()
{
bool ok = false;
const QString dataDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
QDir dir(dataDir);
if (!dir.exists())
dir.mkpath(dataDir);
QString savePath = dataDir + "/cards.xml";
do {
QString fileName;
if (savePath.isEmpty() || !defaultPathCheckBox->isChecked())
fileName = QFileDialog::getSaveFileName(this, tr("Save card database"), dataDir + "/cards.xml", tr("XML card database (*.xml)"));
else {
fileName = savePath;
savePath.clear();
}
if (fileName.isEmpty()) {
return false;
}
if (wizard()->importer->saveToFile(fileName))
ok = true;
else
QMessageBox::critical(this, tr("Error"), tr("The file could not be saved to the desired location."));
} while (!ok);
return true;
}

114
oracle/src/oraclewizard.h Normal file
View file

@ -0,0 +1,114 @@
#ifndef ORACLEWIZARD_H
#define ORACLEWIZARD_H
#include <QWizard>
#include <QFutureWatcher>
#include <QFuture>
class QCheckBox;
class QGroupBox;
class QLabel;
class QLineEdit;
class QRadioButton;
class QProgressBar;
class QNetworkAccessManager;
class QTextEdit;
class QVBoxLayout;
class OracleImporter;
class QSettings;
class OracleWizard : public QWizard
{
Q_OBJECT
public:
OracleWizard(QWidget *parent = 0);
void accept();
void enableButtons();
void disableButtons();
public:
OracleImporter *importer;
QSettings * settings;
};
class OracleWizardPage : public QWizardPage
{
Q_OBJECT
public:
OracleWizardPage(QWidget *parent = 0): QWizardPage(parent) {};
protected:
inline OracleWizard *wizard() { return (OracleWizard*) QWizardPage::wizard(); };
};
class IntroPage : public OracleWizardPage
{
Q_OBJECT
public:
IntroPage(QWidget *parent = 0);
private:
QLabel *label;
};
class LoadSetsPage : public OracleWizardPage
{
Q_OBJECT
public:
LoadSetsPage(QWidget *parent = 0);
protected:
void initializePage();
bool validatePage();
void readSetsFromByteArray(QByteArray data);
private:
QRadioButton *urlRadioButton;
QRadioButton *fileRadioButton;
QLineEdit *urlLineEdit;
QLineEdit *fileLineEdit;
QPushButton *fileButton;
QLabel *progressLabel;
QProgressBar * progressBar;
QNetworkAccessManager *nam;
QFutureWatcher<bool> watcher;
QFuture<bool> future;
private slots:
void actLoadSetsFile();
void actDownloadProgressSetsFile(qint64 received, qint64 total);
void actDownloadFinishedSetsFile();
void importFinished();
};
class ChooseSetsPage : public OracleWizardPage
{
Q_OBJECT
public:
ChooseSetsPage(QWidget *parent = 0);
protected:
void initializePage();
bool validatePage();
private:
QPushButton *checkAllButton, *uncheckAllButton;
QVBoxLayout *checkBoxLayout;
QList<QCheckBox *> checkBoxList;
private slots:
void actCheckAll();
void actUncheckAll();
void checkBoxChanged(int state);
};
class SaveSetsPage : public OracleWizardPage
{
Q_OBJECT
public:
SaveSetsPage(QWidget *parent = 0);
private:
QTextEdit *messageLog;
QCheckBox * defaultPathCheckBox;
protected:
void initializePage();
void cleanupPage();
bool validatePage();
private slots:
void updateTotalProgress(int cardsImported, int setIndex, const QString &setName);
};
#endif

View file

@ -1,248 +0,0 @@
#include <QApplication>
#include <QMenu>
#include <QMenuBar>
#include <QStatusBar>
#include <QLineEdit>
#include <QFileDialog>
#include <QMessageBox>
#include <QScrollArea>
#include <QTextEdit>
#include <QInputDialog>
#include <QLabel>
#include <QPushButton>
#include <QCheckBox>
#include <QProgressBar>
#include <QVBoxLayout>
#include <QDesktopServices>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include "window_main.h"
#include "oracleimporter.h"
const QString WindowMain::defaultSetsUrl = QString("http://www.woogerworks.com/files/sets.xml");
WindowMain::WindowMain(QWidget *parent)
: QMainWindow(parent)
{
importer = new OracleImporter(QDesktopServices::storageLocation(QDesktopServices::DataLocation), this);
nam = new QNetworkAccessManager(this);
checkBoxLayout = new QVBoxLayout;
QWidget *checkboxFrame = new QWidget;
checkboxFrame->setLayout(checkBoxLayout);
QScrollArea *checkboxArea = new QScrollArea;
checkboxArea->setWidget(checkboxFrame);
checkboxArea->setWidgetResizable(true);
checkAllButton = new QPushButton(tr("&Check all"));
connect(checkAllButton, SIGNAL(clicked()), this, SLOT(actCheckAll()));
uncheckAllButton = new QPushButton(tr("&Uncheck all"));
connect(uncheckAllButton, SIGNAL(clicked()), this, SLOT(actUncheckAll()));
QHBoxLayout *checkAllButtonLayout = new QHBoxLayout;
checkAllButtonLayout->addWidget(checkAllButton);
checkAllButtonLayout->addWidget(uncheckAllButton);
startButton = new QPushButton(tr("&Start download"));
connect(startButton, SIGNAL(clicked()), this, SLOT(actStart()));
QVBoxLayout *settingsLayout = new QVBoxLayout;
settingsLayout->addWidget(checkboxArea);
settingsLayout->addLayout(checkAllButtonLayout);
settingsLayout->addWidget(startButton);
totalLabel = new QLabel(tr("Total progress:"));
totalProgressBar = new QProgressBar;
nextSetLabel1 = new QLabel(tr("Current file:"));
nextSetLabel2 = new QLabel;
fileLabel = new QLabel(tr("Progress:"));
fileProgressBar = new QProgressBar;
messageLog = new QTextEdit;
messageLog->setReadOnly(true);
QGridLayout *grid = new QGridLayout;
grid->addWidget(totalLabel, 0, 0);
grid->addWidget(totalProgressBar, 0, 1);
grid->addWidget(nextSetLabel1, 1, 0);
grid->addWidget(nextSetLabel2, 1, 1);
grid->addWidget(fileLabel, 2, 0);
grid->addWidget(fileProgressBar, 2, 1);
grid->addWidget(messageLog, 3, 0, 1, 2);
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addLayout(settingsLayout, 6);
mainLayout->addSpacing(10);
mainLayout->addLayout(grid, 10);
QWidget *centralWidget = new QWidget;
centralWidget->setLayout(mainLayout);
setCentralWidget(centralWidget);
connect(importer, SIGNAL(setIndexChanged(int, int, const QString &)), this, SLOT(updateTotalProgress(int, int, const QString &)));
connect(importer, SIGNAL(dataReadProgress(int, int)), this, SLOT(updateFileProgress(int, int)));
aLoadSetsFile = new QAction(tr("Load sets information from &file..."), this);
connect(aLoadSetsFile, SIGNAL(triggered()), this, SLOT(actLoadSetsFile()));
aDownloadSetsFile = new QAction(tr("&Download sets information..."), this);
connect(aDownloadSetsFile, SIGNAL(triggered()), this, SLOT(actDownloadSetsFile()));
aExit = new QAction(tr("E&xit"), this);
connect(aExit, SIGNAL(triggered()), this, SLOT(close()));
fileMenu = menuBar()->addMenu(tr("&File"));
fileMenu->addAction(aLoadSetsFile);
fileMenu->addAction(aDownloadSetsFile);
fileMenu->addSeparator();
fileMenu->addAction(aExit);
setWindowTitle(tr("Oracle importer"));
setMinimumSize(750, 500);
QStringList args = qApp->arguments();
if (args.contains("-dlsets"))
downloadSetsFile(defaultSetsUrl);
statusLabel = new QLabel;
statusBar()->addWidget(statusLabel);
statusLabel->setText(tr("Sets data not loaded."));
}
void WindowMain::updateSetList()
{
for (int i = 0; i < checkBoxList.size(); ++i)
delete checkBoxList[i];
checkBoxList.clear();
QList<SetToDownload> &sets = importer->getSets();
for (int i = 0; i < sets.size(); ++i) {
QCheckBox *checkBox = new QCheckBox(sets[i].getLongName());
checkBox->setChecked(sets[i].getImport());
connect(checkBox, SIGNAL(stateChanged(int)), this, SLOT(checkBoxChanged(int)));
checkBoxLayout->addWidget(checkBox);
checkBoxList << checkBox;
}
statusLabel->setText(tr("Ready."));
}
void WindowMain::actLoadSetsFile()
{
QFileDialog dialog(this, tr("Load sets file"));
dialog.setFileMode(QFileDialog::ExistingFile);
dialog.setNameFilter("Sets XML file (*.xml)");
if (!dialog.exec())
return;
QString fileName = dialog.selectedFiles().at(0);
if (importer->readSetsFromFile(fileName))
updateSetList();
else
QMessageBox::critical(this, tr("Error"), tr("This file does not contain any sets data."));
}
void WindowMain::actDownloadSetsFile()
{
QString url = QInputDialog::getText(this, tr("Load sets from URL"), tr("Please enter the URL of the sets file:"), QLineEdit::Normal, defaultSetsUrl);
if (!url.isEmpty())
downloadSetsFile(url);
}
void WindowMain::downloadSetsFile(const QString &url)
{
QNetworkReply *reply = nam->get(QNetworkRequest(url));
connect(reply, SIGNAL(finished()), this, SLOT(setsDownloadFinished()));
}
void WindowMain::setsDownloadFinished()
{
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
QNetworkReply::NetworkError errorCode = reply->error();
if (errorCode == QNetworkReply::NoError) {
if (importer->readSetsFromByteArray(reply->readAll()))
updateSetList();
else
QMessageBox::critical(this, tr("Error"), tr("The file was retrieved successfully, but it does not contain any sets data."));
} else
QMessageBox::critical(this, tr("Error"), tr("Network error: %1.").arg(reply->errorString()));
reply->deleteLater();
}
void WindowMain::updateTotalProgress(int cardsImported, int setIndex, const QString &nextSetName)
{
if (setIndex != 0)
messageLog->append(QString("%1: %2 cards imported").arg(nextSetLabel2->text()).arg(cardsImported));
totalProgressBar->setValue(setIndex);
if (nextSetName.isEmpty()) {
QMessageBox::information(this, tr("Oracle importer"), tr("Import finished: %1 cards.").arg(importer->getCardList().size()));
bool ok = false;
const QString dataDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
QDir dir(dataDir);
if (!dir.exists())
dir.mkpath(dataDir);
QString savePath = dataDir + "/cards.xml";
do {
QString fileName;
if (savePath.isEmpty())
fileName = QFileDialog::getSaveFileName(this, tr("Save card database"), dataDir + "/cards.xml", tr("XML card database (*.xml)"));
else {
fileName = savePath;
savePath.clear();
}
if (fileName.isEmpty()) {
qApp->quit();
return;
}
if (importer->saveToFile(fileName))
ok = true;
else
QMessageBox::critical(this, tr("Error"), tr("The file could not be saved to the desired location."));
} while (!ok);
qApp->quit();
} else {
nextSetLabel2->setText(nextSetName);
}
}
void WindowMain::updateFileProgress(int bytesRead, int totalBytes)
{
fileProgressBar->setMaximum(totalBytes);
fileProgressBar->setValue(bytesRead);
}
void WindowMain::actCheckAll()
{
for (int i = 0; i < checkBoxList.size(); ++i)
checkBoxList[i]->setChecked(true);
}
void WindowMain::actUncheckAll()
{
for (int i = 0; i < checkBoxList.size(); ++i)
checkBoxList[i]->setChecked(false);
}
void WindowMain::actStart()
{
int setsCount = importer->startDownload();
if (!setsCount) {
QMessageBox::critical(this, tr("Error"), tr("No sets to download selected."));
return;
}
for (int i = 0; i < checkBoxList.size(); ++i)
checkBoxList[i]->setEnabled(false);
startButton->setEnabled(false);
totalProgressBar->setMaximum(setsCount);
statusLabel->setText(tr("Downloading card data..."));
}
void WindowMain::checkBoxChanged(int state)
{
QCheckBox *checkBox = qobject_cast<QCheckBox *>(sender());
QList<SetToDownload> &sets = importer->getSets();
for (int i = 0; i < sets.size(); ++i)
if (sets[i].getLongName() == checkBox->text()) {
sets[i].setImport(state);
break;
}
}

View file

@ -1,52 +0,0 @@
#ifndef WINDOW_MAIN_H
#define WINDOW_MAIN_H
#include <QMainWindow>
#include <QList>
class OracleImporter;
class QLabel;
class QProgressBar;
class QTextEdit;
class QPushButton;
class QCheckBox;
class QVBoxLayout;
class QMenu;
class QAction;
class QNetworkAccessManager;
class WindowMain : public QMainWindow {
Q_OBJECT
private:
static const QString defaultSetsUrl;
OracleImporter *importer;
QNetworkAccessManager *nam;
QMenu *fileMenu;
QAction *aLoadSetsFile, *aDownloadSetsFile, *aExit;
QPushButton *checkAllButton, *uncheckAllButton, *startButton;
QLabel *totalLabel, *fileLabel, *nextSetLabel1, *nextSetLabel2;
QProgressBar *totalProgressBar, *fileProgressBar;
QTextEdit *messageLog;
QVBoxLayout *checkBoxLayout;
QList<QCheckBox *> checkBoxList;
QLabel *statusLabel;
void downloadSetsFile(const QString &url);
private slots:
void updateTotalProgress(int cardsImported, int setIndex, const QString &nextSetName);
void updateFileProgress(int bytesRead, int totalBytes);
void updateSetList();
void actCheckAll();
void actUncheckAll();
void actStart();
void actLoadSetsFile();
void actDownloadSetsFile();
void setsDownloadFinished();
void checkBoxChanged(int state);
public:
WindowMain(QWidget *parent = 0);
};
#endif

View file

@ -1,44 +1,30 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
SET(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR})
# CMakeLists for servatrice directory
#
# provides the servatrice binary
PROJECT(servatrice)
# cmake modules
include(GNUInstallDirs)
# cmake module for libgcrypt is included in current directory
SET(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR})
FIND_PACKAGE(Libgcrypt REQUIRED)
SET(servatrice_SOURCES
src/main.cpp
src/passwordhasher.cpp
src/servatrice.cpp
src/servatrice_connection_pool.cpp
src/servatrice_database_interface.cpp
src/server_logger.cpp
src/serversocketinterface.cpp
src/isl_interface.cpp
${CMAKE_CURRENT_BINARY_DIR}/version_string.cpp
)
SET(servatrice_HEADERS
src/servatrice.h
src/servatrice_connection_pool.h
src/servatrice_database_interface.h
src/server_logger.h
src/serversocketinterface.h
src/isl_interface.h
src/main.cpp
src/passwordhasher.cpp
src/servatrice.cpp
src/servatrice_connection_pool.cpp
src/servatrice_database_interface.cpp
src/server_logger.cpp
src/serversocketinterface.cpp
src/isl_interface.cpp
${CMAKE_CURRENT_BINARY_DIR}/version_string.cpp
)
SET(QT_DONTUSE_QTGUI)
SET(QT_USE_QTNETWORK TRUE)
SET(QT_USE_QTSQL TRUE)
FIND_PACKAGE(Qt4 REQUIRED)
FIND_PACKAGE(Protobuf REQUIRED)
FIND_PACKAGE(Libgcrypt REQUIRED)
FIND_PACKAGE(Threads)
#set(CMAKE_BUILD_TYPE Release)
set(CMAKE_CXX_FLAGS_DEBUG "-ggdb -O2")
set(CMAKE_CXX_FLAGS_RELEASE "-O2")
QT4_WRAP_CPP(servatrice_HEADERS_MOC ${servatrice_HEADERS})
# Include directories
INCLUDE(${QT_USE_FILE})
INCLUDE_DIRECTORIES(../common)
INCLUDE_DIRECTORIES(${LIBGCRYPT_INCLUDE_DIR})
@ -46,14 +32,53 @@ INCLUDE_DIRECTORIES(${PROTOBUF_INCLUDE_DIR})
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/../common)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
ADD_EXECUTABLE(servatrice ${servatrice_SOURCES} ${servatrice_HEADERS_MOC})
# Build servatrice binary and link it
ADD_EXECUTABLE(servatrice MACOSX_BUNDLE ${servatrice_SOURCES} ${servatrice_MOC_SRCS})
TARGET_LINK_LIBRARIES(servatrice cockatrice_common ${QT_LIBRARIES} ${LIBGCRYPT_LIBRARY} ${CMAKE_THREAD_LIBS_INIT})
#add_custom_target(versionheader ALL DEPENDS version_header)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/version_string.h ${CMAKE_CURRENT_BINARY_DIR}/version_string.cpp
COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR} -P ${CMAKE_CURRENT_SOURCE_DIR}/../common/getversion.cmake
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/version_string.h ${CMAKE_CURRENT_BINARY_DIR}/version_string.cpp
COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR} -P ${CMAKE_CURRENT_SOURCE_DIR}/../common/getversion.cmake
)
# install rules
INSTALL(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/servatrice DESTINATION ${CMAKE_INSTALL_BINDIR})
if(UNIX)
if(APPLE)
INSTALL(TARGETS servatrice BUNDLE DESTINATION ./)
else()
# Assume linux
INSTALL(TARGETS servatrice RUNTIME DESTINATION bin/)
endif()
elseif(WIN32)
INSTALL(TARGETS servatrice RUNTIME DESTINATION ./)
endif()
if(APPLE)
set(plugin_dest_dir ./servatrice.app/Contents/Plugins)
set(qtconf_dest_dir ./servatrice.app/Contents/Resources)
# note: no codecs in qt5
# note: phonon_backend => mediaservice
# note: needs platform on osx
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
install(DIRECTORY "${QT_PLUGINS_DIR}/" DESTINATION ${plugin_dest_dir} COMPONENT Runtime
FILES_MATCHING REGEX "(codecs|iconengines|imageformats|mediaservice|phonon_backend|platforms)/.*_debug\\.dylib")
else()
install(DIRECTORY "${QT_PLUGINS_DIR}/" DESTINATION ${plugin_dest_dir} COMPONENT Runtime
FILES_MATCHING REGEX "(codecs|iconengines|imageformats|mediaservice|phonon_backend|platforms)/[^_]*\\.dylib")
endif()
install(CODE "
file(WRITE \"${qtconf_dest_dir}/qt.conf\" \"[Paths]
Plugins = Plugins\")
" COMPONENT Runtime)
install(CODE "
file(GLOB_RECURSE QTPLUGINS
\"${plugin_dest_dir}/*.dylib\")
include(BundleUtilities)
fixup_bundle(\"\${CMAKE_INSTALL_PREFIX}/servatrice.app\" \"\${QTPLUGINS}\" \"${QT_LIBRARY_DIR}\")
" COMPONENT Runtime)
endif()

16
sounds/CMakeLists.txt Normal file
View file

@ -0,0 +1,16 @@
# CMakeLists for sounds/ directory
#
# Installs default sound files
FILE(GLOB sounds "${CMAKE_CURRENT_SOURCE_DIR}/*.raw")
if(UNIX)
if(APPLE)
INSTALL(FILES ${sounds} DESTINATION sounds/)
else()
# Assume linux
INSTALL(FILES ${sounds} DESTINATION share/cockatrice/sounds/)
endif()
elseif(WIN32)
INSTALL(FILES ${sounds} DESTINATION sounds/)
endif()

16
zonebg/CMakeLists.txt Normal file
View file

@ -0,0 +1,16 @@
# CMakeLists for zonebg/ directory
#
# Installs default "zone background" files
FILE(GLOB zonebg "${CMAKE_CURRENT_SOURCE_DIR}/*.*")
if(UNIX)
if(APPLE)
INSTALL(FILES ${zonebg} DESTINATION zonebg/)
else()
# Assume linux
INSTALL(FILES ${zonebg} DESTINATION share/cockatrice/zonebg/)
endif()
elseif(WIN32)
INSTALL(FILES ${zonebg} DESTINATION zonebg/)
endif()