pax_global_header00006660000000000000000000000064145537341550014526gustar00rootroot0000000000000052 comment=73b7de74a5769095acb96eb6c6333ffe161452f2 nextpnr-nextpnr-0.7/000077500000000000000000000000001455373415500145665ustar00rootroot00000000000000nextpnr-nextpnr-0.7/.clang-format000066400000000000000000000047541455373415500171530ustar00rootroot00000000000000--- Language: Cpp # BasedOnStyle: LLVM AccessModifierOffset: -2 AlignAfterOpenBracket: Align AlignConsecutiveAssignments: false AlignConsecutiveDeclarations: false AlignEscapedNewlinesLeft: false AlignOperands: true AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: true AllowShortBlocksOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: All AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: false AlwaysBreakTemplateDeclarations: false BinPackArguments: true BinPackParameters: true BraceWrapping: AfterClass: true AfterControlStatement: false AfterEnum: true AfterFunction: true AfterNamespace: false AfterObjCDeclaration: false AfterStruct: true AfterUnion: true BeforeCatch: false BeforeElse: false IndentBraces: false BreakBeforeBinaryOperators: None BreakBeforeBraces: Custom BreakBeforeTernaryOperators: true BreakConstructorInitializersBeforeComma: false ColumnLimit: 120 CommentPragmas: '^ IWYU pragma:' ConstructorInitializerAllOnOneLineOrOnePerLine: false ConstructorInitializerIndentWidth: 8 ContinuationIndentWidth: 8 Cpp11BracedListStyle: true DerivePointerAlignment: false DisableFormat: false ExperimentalAutoDetectBinPacking: false ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] IncludeCategories: - Regex: '<.*>' Priority: 1 - Regex: '.*' Priority: 2 IndentCaseLabels: false IndentWidth: 4 IndentWrappedFunctionNames: false KeepEmptyLinesAtTheStartOfBlocks: true MacroBlockBegin: '' MacroBlockEnd: '' MaxEmptyLinesToKeep: 1 NamespaceIndentation: None ObjCBlockIndentWidth: 4 ObjCSpaceAfterProperty: false ObjCSpaceBeforeProtocolList: true PenaltyBreakBeforeFirstCallParameter: 19 PenaltyBreakComment: 300 PenaltyBreakFirstLessLess: 120 PenaltyBreakString: 1000 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 60 PointerAlignment: Right ReflowComments: true SortIncludes: true SpaceAfterCStyleCast: false SpaceBeforeAssignmentOperators: true SpaceBeforeParens: ControlStatements SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 1 SpacesInAngles: false SpacesInContainerLiterals: true SpacesInCStyleCastParentheses: false SpacesInParentheses: false SpacesInSquareBrackets: false Standard: Cpp11 TabWidth: 8 UseTab: Never ... nextpnr-nextpnr-0.7/.github/000077500000000000000000000000001455373415500161265ustar00rootroot00000000000000nextpnr-nextpnr-0.7/.github/ci/000077500000000000000000000000001455373415500165215ustar00rootroot00000000000000nextpnr-nextpnr-0.7/.github/ci/build_common.sh000066400000000000000000000030741455373415500215300ustar00rootroot00000000000000#!/bin/bash # Install latest Yosys function build_yosys { PREFIX=`pwd`/.yosys YOSYS_PATH=${DEPS_PATH}/yosys mkdir -p ${YOSYS_PATH} git clone --recursive https://github.com/YosysHQ/yosys ${YOSYS_PATH} pushd ${YOSYS_PATH} git reset --hard ${YOSYS_REVISION} make -j`nproc` PREFIX=$PREFIX make install PREFIX=$PREFIX popd } function build_icestorm { PREFIX=`pwd`/.icestorm ICESTORM_PATH=${DEPS_PATH}/icestorm mkdir -p ${ICESTORM_PATH} git clone --recursive https://github.com/YosysHQ/icestorm ${ICESTORM_PATH} pushd ${ICESTORM_PATH} git reset --hard ${ICESTORM_REVISION} make -j`nproc` PREFIX=${PREFIX} make install PREFIX=${PREFIX} popd } function build_trellis { PREFIX=`pwd`/.trellis TRELLIS_PATH=${DEPS_PATH}/prjtrellis mkdir -p ${TRELLIS_PATH} git clone --recursive https://github.com/YosysHQ/prjtrellis ${TRELLIS_PATH} pushd ${TRELLIS_PATH} git reset --hard ${TRELLIS_REVISION} mkdir -p libtrellis/build pushd libtrellis/build cmake -DCMAKE_INSTALL_PREFIX=${PREFIX} .. make -j`nproc` make install popd popd } function build_prjoxide { PREFIX=`pwd`/.prjoxide PRJOXIDE_PATH=${DEPS_PATH}/prjoxide curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y ;\ mkdir -p ${PRJOXIDE_PATH} git clone --recursive https://github.com/gatecat/prjoxide ${PRJOXIDE_PATH} pushd ${PRJOXIDE_PATH} git reset --hard ${PRJOXIDE_REVISION} cd libprjoxide PATH=$PATH:$HOME/.cargo/bin cargo install --root $PREFIX --path prjoxide popd } nextpnr-nextpnr-0.7/.github/ci/build_ecp5.sh000066400000000000000000000010671455373415500210740ustar00rootroot00000000000000#!/bin/bash function get_dependencies { : } function build_nextpnr { mkdir build pushd build cmake .. -DARCH=ecp5 -DTRELLIS_INSTALL_PREFIX=${GITHUB_WORKSPACE}/.trellis -DWERROR=on -DBUILD_GUI=on -DUSE_IPO=off make nextpnr-ecp5 -j`nproc` popd } function run_tests { export PATH=${GITHUB_WORKSPACE}/.trellis/bin:${GITHUB_WORKSPACE}/.yosys/bin:$PATH make -j $(nproc) -C tests/ecp5/regressions NPNR=$(pwd)/build/nextpnr-ecp5 } function run_archcheck { pushd build ./nextpnr-ecp5 --um5g-25k --package CABGA381 --test popd } nextpnr-nextpnr-0.7/.github/ci/build_generic.sh000066400000000000000000000007231455373415500216520ustar00rootroot00000000000000#!/bin/bash function get_dependencies { : } function build_nextpnr { mkdir build pushd build cmake .. -DARCH=generic -DWERROR=on make nextpnr-generic -j`nproc` popd } function run_tests { export PATH=${GITHUB_WORKSPACE}/.yosys/bin:$PATH ( export NPNR=$(pwd)/build/nextpnr-generic && cd tests/generic/flow && ./run.sh ) } function run_archcheck { pushd build # TODO # ./nextpnr-generic --uarch example --test popd } nextpnr-nextpnr-0.7/.github/ci/build_gowin.sh000066400000000000000000000006141455373415500213600ustar00rootroot00000000000000#!/bin/bash function get_dependencies { pip3 install apycula==${APYCULA_REVISION} } function build_nextpnr { mkdir build pushd build cmake .. -DARCH=gowin -DWERROR=on -DBUILD_GUI=on -DUSE_IPO=off make nextpnr-gowin -j`nproc` popd } function run_tests { : } function run_archcheck { pushd build ./nextpnr-gowin --device GW1N-UV4LQ144C6/I5 --test popd } nextpnr-nextpnr-0.7/.github/ci/build_himbaechel.sh000066400000000000000000000012121455373415500223110ustar00rootroot00000000000000#!/bin/bash function get_dependencies { : } function build_nextpnr { mkdir build pushd build cmake .. -DARCH=himbaechel make nextpnr-himbaechel bbasm -j`nproc` # We'd ideally use pypy3 for speed (as works locally), but the version # our CI Ubuntu provides doesn't like some of the typing stuff python3 ../himbaechel/uarch/example/example_arch_gen.py ./example.bba mkdir -p share/himbaechel/example ./bba/bbasm --l ./example.bba share/himbaechel/example/example.bin popd } function run_tests { : } function run_archcheck { pushd build ./nextpnr-himbaechel --device EXAMPLE --test popd } nextpnr-nextpnr-0.7/.github/ci/build_ice40.sh000066400000000000000000000014061455373415500211410ustar00rootroot00000000000000#!/bin/bash function get_dependencies { : } function build_nextpnr { mkdir build pushd build cmake .. -DARCH=ice40 -DICESTORM_INSTALL_PREFIX=${GITHUB_WORKSPACE}/.icestorm -DWERROR=on -DBUILD_TESTS=on -DBUILD_GUI=on make nextpnr-ice40 nextpnr-ice40-test -j`nproc` popd } function run_tests { export PATH=${GITHUB_WORKSPACE}/.yosys/bin:${GITHUB_WORKSPACE}/.icestorm/bin:$PATH (cd build && ./nextpnr-ice40-test) (export NEXTPNR=$(pwd)/build/nextpnr-ice40 && cd ice40/smoketest/attosoc && ./smoketest.sh) make -j $(nproc) -C tests/ice40/regressions NPNR=$(pwd)/build/nextpnr-ice40 } function run_archcheck { pushd build ./nextpnr-ice40 --hx8k --package ct256 --test ./nextpnr-ice40 --up5k --package sg48 --test popd } nextpnr-nextpnr-0.7/.github/ci/build_interchange.sh000077500000000000000000000035651455373415500225370ustar00rootroot00000000000000#!/bin/bash # Install capnproto libraries function build_capnp { curl -O https://capnproto.org/capnproto-c++-0.8.0.tar.gz tar zxf capnproto-c++-0.8.0.tar.gz pushd capnproto-c++-0.8.0 ./configure make -j`nproc` check sudo make install popd git clone https://github.com/capnproto/capnproto-java.git pushd capnproto-java make -j`nproc` sudo make install popd } # Install latest Yosys function build_yosys { DESTDIR=`pwd`/.yosys pushd yosys make -j`nproc` sudo make install DESTDIR=$DESTDIR popd } function get_dependencies { # Install python-fpga-interchange libraries git clone -b ${PYTHON_INTERCHANGE_TAG} https://github.com/SymbiFlow/python-fpga-interchange.git ${PYTHON_INTERCHANGE_PATH} pushd ${PYTHON_INTERCHANGE_PATH} git submodule update --init --recursive python3 -m pip install -r requirements.txt popd if [ ${DEVICE} == "LIFCL-17" ] || [ ${DEVICE} == "LIFCL-40" ]; then # Install prjoxide curl --proto '=https' -sSf https://sh.rustup.rs | sh -s -- -y git clone --recursive https://github.com/gatecat/prjoxide.git pushd prjoxide/libprjoxide # TODO: use a tag instead of a commit, like python-fpga-interchange git reset --hard ${PRJOXIDE_REVISION} PATH=$PATH:$HOME/.cargo/bin cargo install --path prjoxide --all-features popd else # Install RapidWright git clone https://github.com/Xilinx/RapidWright.git ${RAPIDWRIGHT_PATH} pushd ${RAPIDWRIGHT_PATH} ./gradlew updateJars --no-watch-fs make compile popd fi } function build_nextpnr { build_capnp mkdir build pushd build cmake .. -DARCH=fpga_interchange -DRAPIDWRIGHT_PATH=${RAPIDWRIGHT_PATH} -DPYTHON_INTERCHANGE_PATH=${PYTHON_INTERCHANGE_PATH} -DWERROR=on make nextpnr-fpga_interchange -j`nproc` popd } nextpnr-nextpnr-0.7/.github/ci/build_machxo2.sh000066400000000000000000000007201455373415500215740ustar00rootroot00000000000000#!/bin/bash function get_dependencies { : } function build_nextpnr { mkdir build pushd build cmake .. -DARCH=machxo2 -DTRELLIS_INSTALL_PREFIX=${GITHUB_WORKSPACE}/.trellis -DWERROR=on -DUSE_IPO=off make nextpnr-machxo2 -j`nproc` popd } function run_tests { : } function run_archcheck { pushd build ./nextpnr-machxo2 --device LCMXO2-1200HC-4SG32C --test ./nextpnr-machxo2 --device LCMXO3LF-6900C-6BG256C --test popd } nextpnr-nextpnr-0.7/.github/ci/build_mistral.sh000066400000000000000000000011171455373415500217070ustar00rootroot00000000000000#!/bin/bash export MISTRAL_PATH=${DEPS_PATH}/mistral function get_dependencies { # Fetch mistral mkdir -p ${MISTRAL_PATH} git clone --recursive https://github.com/Ravenslofty/mistral.git ${MISTRAL_PATH} pushd ${MISTRAL_PATH} git reset --hard ${MISTRAL_REVISION} popd } function build_nextpnr { mkdir build pushd build cmake .. -DARCH=mistral -DMISTRAL_ROOT=${MISTRAL_PATH} make nextpnr-mistral -j`nproc` popd } function run_tests { : } function run_archcheck { pushd build ./nextpnr-mistral --device 5CEBA2F17A7 --test popd } nextpnr-nextpnr-0.7/.github/ci/build_nexus.sh000066400000000000000000000005601455373415500213770ustar00rootroot00000000000000#!/bin/bash function get_dependencies { : } function build_nextpnr { mkdir build pushd build cmake .. -DARCH=nexus -DOXIDE_INSTALL_PREFIX=${GITHUB_WORKSPACE}/.prjoxide make nextpnr-nexus -j`nproc` popd } function run_tests { : } function run_archcheck { pushd build ./nextpnr-nexus --device LIFCL-40-9BG400CES --test popd } nextpnr-nextpnr-0.7/.github/workflows/000077500000000000000000000000001455373415500201635ustar00rootroot00000000000000nextpnr-nextpnr-0.7/.github/workflows/arch_ci.yml000066400000000000000000000056341455373415500223060ustar00rootroot00000000000000# CI for everything other than the sui generis FPGA interchange arrangements name: Arch CI tests on: [push, pull_request] jobs: Build-nextpnr: strategy: fail-fast: false matrix: arch: [mistral, ice40, ecp5, generic, nexus, machxo2, gowin, himbaechel] runs-on: ubuntu-latest env: DEPS_PATH: ${{ github.workspace }}/deps YOSYS_REVISION: bd7ee79486d4e8788f36de8c25a3fb2df451d682 ICESTORM_REVISION: 9f66f9ce16941c6417813cb87653c735a78b53ae TRELLIS_REVISION: 36c615d1740473cc3574464c7f0bed44da20e5b6 PRJOXIDE_REVISION: c3fb1526cf4a2165e15b74f4a994d153c7695fe4 MISTRAL_REVISION: ebfc0dd2cc7d6d2159b641a397c88554840e93c9 APYCULA_REVISION: 0.8.2a1 steps: - uses: actions/checkout@v3 with: submodules: recursive - uses: actions/setup-python@v4 with: python-version: '3.10' - name: Install run: | sudo apt-get update sudo apt-get install git make cmake libboost-all-dev python3-dev pypy3 libeigen3-dev tcl-dev lzma-dev libftdi-dev clang bison flex swig qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools iverilog - name: Cache yosys installation uses: actions/cache@v3 id: cache-yosys with: path: .yosys key: cache-yosys-${{ env.YOSYS_REVISION }}-r3 - name: Build yosys run: | source ./.github/ci/build_common.sh build_yosys if: steps.cache-yosys.outputs.cache-hit != 'true' - name: Cache icestorm installation uses: actions/cache@v3 id: cache-icestorm with: path: .icestorm key: cache-icestorm-${{ env.ICESTORM_REVISION }}-r3 if: matrix.arch == 'ice40' - name: Build icestorm run: | source ./.github/ci/build_common.sh build_icestorm if: matrix.arch == 'ice40' && steps.cache-icestorm.outputs.cache-hit != 'true' - name: Cache trellis installation uses: actions/cache@v3 id: cache-trellis with: path: .trellis key: cache-trellis-${{ env.TRELLIS_REVISION }}-r3 if: matrix.arch == 'ecp5' || matrix.arch == 'machxo2' - name: Build trellis run: | source ./.github/ci/build_common.sh build_trellis if: (matrix.arch == 'ecp5' || matrix.arch == 'machxo2') && steps.cache-trellis.outputs.cache-hit != 'true' - name: Cache prjoxide installation uses: actions/cache@v3 id: cache-prjoxide with: path: .prjoxide key: cache-prjoxide-${{ env.PRJOXIDE_REVISION }}-r3 if: matrix.arch == 'nexus' - name: Build prjoxide run: | source ./.github/ci/build_common.sh build_prjoxide if: matrix.arch == 'nexus' && steps.cache-prjoxide.outputs.cache-hit != 'true' - name: Execute build nextpnr run: | source ./.github/ci/build_${{ matrix.arch }}.sh get_dependencies build_nextpnr run_tests run_archcheck nextpnr-nextpnr-0.7/.github/workflows/interchange_ci.yml.disable000066400000000000000000000071201455373415500252520ustar00rootroot00000000000000name: FPGA interchange CI tests on: [push, pull_request] jobs: Build-yosys: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 with: submodules: recursive - uses: actions/setup-python@v2 - name: Install run: | sudo apt-get update sudo apt-get install git make cmake libboost-all-dev python3-dev libeigen3-dev tcl-dev clang bison flex swig locales libtinfo-dev - name: ccache uses: hendrikmuhs/ccache-action@v1 - name: Get yosys run: | git clone https://github.com/YosysHQ/yosys.git cd yosys echo "YOSYS_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV - name: Cache yosys installation uses: actions/cache@v2 id: cache-yosys with: path: .yosys key: cache-yosys-${{ env.YOSYS_SHA }} - name: Build yosys run: | export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" source ./.github/ci/build_interchange.sh build_yosys if: steps.cache-yosys.outputs.cache-hit != 'true' Build-nextpnr: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 with: submodules: recursive - uses: actions/setup-python@v2 - name: Install run: | sudo apt-get update sudo apt-get install git make cmake libboost-all-dev python3-dev libeigen3-dev tcl-dev clang bison flex swig - name: ccache uses: hendrikmuhs/ccache-action@v1 - name: Execute build nextpnr run: | export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" source ./.github/ci/build_interchange.sh build_nextpnr Run-Tests: runs-on: ubuntu-latest needs: [Build-yosys, Build-nextpnr] strategy: # Don't terminate jobs when one fails. This is important when # debugging CI failures. fail-fast: false matrix: device: [xc7a35t, xc7a100t, xc7a200t, xc7z010, LIFCL-17, LIFCL-40] steps: - uses: actions/checkout@v2 with: submodules: recursive - uses: actions/setup-python@v2 - name: Install run: | sudo apt-get update sudo apt-get install git make cmake libboost-all-dev python3-dev libeigen3-dev tcl-dev clang bison flex swig - name: ccache uses: hendrikmuhs/ccache-action@v1 - name: Get yosys run: | git clone https://github.com/YosysHQ/yosys.git cd yosys echo "YOSYS_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV - name: Cache yosys installation uses: actions/cache@v2 id: cache-yosys with: path: .yosys key: cache-yosys-${{ env.YOSYS_SHA }} - name: Build yosys run: | export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" source ./.github/ci/build_interchange.sh build_yosys if: steps.cache-yosys.outputs.cache-hit != 'true' - name: Execute build interchange script env: RAPIDWRIGHT_PATH: ${{ github.workspace }}/RapidWright PYTHON_INTERCHANGE_PATH: ${{ github.workspace }}/python-fpga-interchange PYTHON_INTERCHANGE_TAG: v0.0.20 PRJOXIDE_REVISION: 318331f8b30c2e2a31cc41d51f104b671e180a8a DEVICE: ${{ matrix.device }} run: | export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" source ./.github/ci/build_interchange.sh build_nextpnr && get_dependencies - name: Run tests env: DEVICE: ${{ matrix.device }} run: | export PATH="$GITHUB_WORKSPACE/.yosys/usr/local/bin:$PATH" which yosys cd build make all-$DEVICE-tests -j`nproc` nextpnr-nextpnr-0.7/.gitignore000066400000000000000000000010671455373415500165620ustar00rootroot00000000000000/generated/ /objs/ /nextpnr-generic* /nextpnr-ice40* /nextpnr-ecp5* /nextpnr-nexus* /nextpnr-fpga_interchange* /nextpnr-gowin* /nextpnr-machxo2* /nextpnr-himbaechel* .cache cmake-build-*/ Makefile cmake_install.cmake compile_commands.json CMakeFiles CMakeScripts CTestfile.cmake CMakeCache.txt *.so *.dll *.a *.cbp *.depends .*.swp a.out *.json *.dot *.il /generic/examples/blinky.png build/ *.asc *.bin /Testing/* CTestTestfile.cmake install_manifest.txt /bba/bbasm /bba-export.cmake /ImportExecutables.cmake *-coverage/ *-coverage.info *.netlist *.phys *.dcp *.bit nextpnr-nextpnr-0.7/.gitmodules000066400000000000000000000007241455373415500167460ustar00rootroot00000000000000[submodule "tests"] path = tests url = https://github.com/YosysHQ/nextpnr-tests [submodule "fpga-interchange-schema"] path = 3rdparty/fpga-interchange-schema url = https://github.com/SymbiFlow/fpga-interchange-schema.git [submodule "himbaechel/uarch/xilinx/meta"] path = himbaechel/uarch/xilinx/meta url = https://github.com/gatecat/nextpnr-xilinx-meta [submodule "3rdparty/corrosion"] path = 3rdparty/corrosion url = https://github.com/corrosion-rs/corrosion nextpnr-nextpnr-0.7/3rdparty/000077500000000000000000000000001455373415500163365ustar00rootroot00000000000000nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/000077500000000000000000000000001455373415500220335ustar00rootroot00000000000000nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/.gitignore000066400000000000000000000004361455373415500240260ustar00rootroot00000000000000# Compiled Object files *.slo *.lo *.o *.obj # Precompiled Headers *.gch *.pch # Compiled Dynamic libraries *.so *.dylib *.dll # Fortran module files *.mod # Compiled Static libraries *.lai *.la *.a *.lib # Executables *.exe *.out *.app # Ignores 'build' in any sub folder build/ nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/CMakeLists.txt000066400000000000000000000004441455373415500245750ustar00rootroot00000000000000CMAKE_MINIMUM_REQUIRED(VERSION 3.13) PROJECT(QtPropertyBrowser) ##################### Look for required libraries ###################### # Add QT dependencies FIND_PACKAGE(Qt5Widgets REQUIRED) ######################### Add Primary Targets ########################## ADD_SUBDIRECTORY(src) nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/README.md000066400000000000000000000017301455373415500233130ustar00rootroot00000000000000# Qt Solutions Component: Property Browser A property browser framework enabling the user to edit a set of properties. The framework provides a browser widget that displays the given properties with labels and corresponding editing widgets (e.g. line edits or comboboxes). The various types of editing widgets are provided by the framework's editor factories: For each property type, the framework provides a property manager (e.g. QtIntPropertyManager and QtStringPropertyManager) which can be associated with the preferred editor factory (e.g.QtSpinBoxFactory and QtLineEditFactory). The framework also provides a variant based property type with corresponding variant manager and factory. Finally, the framework provides three ready-made implementations of the browser widget: QtTreePropertyBrowser, QtButtonPropertyBrowser and QtGroupBoxPropertyBrowser. Original source code is archived at https://qt.gitorious.org/qt-solutions/qt-solutions This fork adds CMake and Qt5 supportnextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/cmake/000077500000000000000000000000001455373415500231135ustar00rootroot00000000000000nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/cmake/CommonCMakeUtils.cmake000066400000000000000000000021661455373415500272740ustar00rootroot00000000000000# extract filename components of all items in src_list in dst_list # example usage: extract_filename_components(ALL_LIBS_BASENAME ALL_LIBS NAME_WE) macro(extract_filename_components dst_list src_list component) set(list_var "${${src_list}}") #message(STATUS "list_var: ${list_var}") #message(STATUS "component: ${component}") foreach(item ${list_var}) get_filename_component(BASENAME ${item} ${component}) list( APPEND ${dst_list} ${BASENAME}) endforeach() #message(STATUS "dst_list: ${${dst_list}}") endmacro() # extract target properties of all items in src_list in dst_list # example usage: extract_target_properties(QT_INCLUDES Qt5::Core INTERFACE_INCLUDE_DIR) macro(extract_target_properties target_props target_list property) set(list_var "${${target_list}}") # message(STATUS "list_var: ${list_var}") #message(STATUS "property: ${property}") foreach(item ${list_var}) get_target_property(value ${item} ${property}) list( APPEND ${target_props} ${value}) endforeach() #message(STATUS "target_props: ${${target_props}}") list(REMOVE_DUPLICATES ${target_props}) endmacro()nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/cmake/CompileSettings.cmake000066400000000000000000000046671455373415500272430ustar00rootroot00000000000000######################### COMPILE SETTINGS ################################ IF(NOT CMAKE_BUILD_TYPE) SET(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." FORCE) ENDIF(NOT CMAKE_BUILD_TYPE) MESSAGE(STATUS "===============================================================") MESSAGE(STATUS "============ Configuring CompileSettings =====================") IF(CMAKE_COMPILER_IS_GNUCC) SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") SET (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -march=native -funroll-loops -ffast-math") SET (CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -march=native -funroll-loops") OPTION (USE_PEDANTIC_FLAGS "Use Pedantic Flags in GCC" ON) IF(USE_PEDANTIC_FLAGS) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic -Wno-long-long -Wno-variadic-macros") SET(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -pedantic -Wno-long-long -Wno-variadic-macros") ENDIF() OPTION (USE_DEBUG_SYMBOLS "Use Debug Symbols" OFF) IF(USE_DEBUG_SYMBOLS) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g") SET(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -g") ENDIF() ENDIF(CMAKE_COMPILER_IS_GNUCC) IF(NOT MSVC) OPTION (USE_CPP_11 "Use C++11 Compiler" ON) IF(USE_CPP_11) INCLUDE(CheckCXXCompilerFlag) CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11) CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X) IF(COMPILER_SUPPORTS_CXX11) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") ELSEIF(COMPILER_SUPPORTS_CXX0X) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") ELSE() SET(USE_CPP_11 OFF) MESSAGE(STATUS "Compiler ${CMAKE_CXX_COMPILER} has no C++11 support.") ENDIF() ENDIF() ENDIF() IF(CMAKE_BUILD_TYPE MATCHES Debug) SET(CMAKE_BUILD_TYPE_FLAGS ${CMAKE_CXX_FLAGS_DEBUG}) ELSEIF(CMAKE_BUILD_TYPE MATCHES RelWithDebInfo) SET(CMAKE_BUILD_TYPE_FLAGS ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}) ELSEIF(CMAKE_BUILD_TYPE MATCHES Release) SET(CMAKE_BUILD_TYPE_FLAGS ${CMAKE_CXX_FLAGS_RELEASE}) ENDIF() OPTION (USE_OpenMP "Use OpenMP" ON) IF(USE_OpenMP) FIND_PACKAGE(OpenMP) IF(OPENMP_FOUND) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") ENDIF() ENDIF() MESSAGE(STATUS "===============================================================")nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/cmake/InstallProjectConfig.cmake000066400000000000000000000010011455373415500301700ustar00rootroot00000000000000###################### InstallProjectConfig ########################### include(CMakePackageConfigHelpers) configure_package_config_file( ${CMAKE_SOURCE_DIR}/cmake/${PROJECT_NAME}Config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake INSTALL_DESTINATION ${INSTALL_CMAKE_DIR} ) install(EXPORT ${PROJECT_NAME}Targets DESTINATION ${INSTALL_CMAKE_DIR} ) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake DESTINATION ${INSTALL_CMAKE_DIR} COMPONENT Devel )nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/cmake/InstallSettings.cmake000066400000000000000000000023241455373415500272450ustar00rootroot00000000000000###################### Installation Settings ########################### # Set a local folder for default installation when CMAKE_INSTALL_PREFIX is NOT specified IF(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) IF(WIN32) SET(DEFAULT_INSTALL_PATH "$ENV{HOMEDRIVE}/${PROJECT_NAME}" ) ELSE() SET(DEFAULT_INSTALL_PATH "$ENV{HOME}/local") ENDIF() SET(CMAKE_INSTALL_PREFIX "${DEFAULT_INSTALL_PATH}" CACHE PATH "${PROJECT_NAME} install prefix" FORCE) ENDIF(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) # Offer the user the choice of overriding the installation directories SET(INSTALL_LIB_DIR lib CACHE PATH "Install dir for libraries") SET(INSTALL_BIN_DIR bin CACHE PATH "Install dir for executables") SET(INSTALL_INCLUDE_DIR include/${PROJECT_NAME} CACHE PATH "Install dir for headers") IF(WIN32 AND NOT CYGWIN) SET(DEF_INSTALL_CMAKE_DIR CMake) ELSE() SET(DEF_INSTALL_CMAKE_DIR lib/cmake/${PROJECT_NAME}) ENDIF() SET(INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Install dir for CMake files") # Make relative paths absolute (needed later on) FOREACH(p LIB BIN INCLUDE CMAKE) SET(var INSTALL_${p}_DIR) IF(NOT IS_ABSOLUTE "${${var}}") SET(${var} "${CMAKE_INSTALL_PREFIX}/${${var}}") ENDIF() ENDFOREACH() nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/cmake/QtPropertyBrowserConfig.cmake.in000066400000000000000000000020101455373415500313360ustar00rootroot00000000000000# Config file for the QtPropertyBrowser package # This adds QtPropertyBrowser IMPORTED target # # Usage example: # # find_package(QtPropertyBrowser) # add_executable(foo foo.cpp) # target_link_libraries(foo QtPropertyBrowser) # # Additionaly you can use the following varaibles: # # QtPropertyBrowser_FOUND - standard CMake Package found indicator # QtPropertyBrowser_INCLUDE_DIR - include directories for QtPropertyBrowser alone # QtPropertyBrowser_INCLUDE_DIRS - include directories for QtPropertyBrowser with all dpendencies # QtPropertyBrowser_DEFINITIONS - Definitions needed to build with QtPropertyBrowser # QtPropertyBrowser_LIBRARIES - Libraries needed to build with QtPropertyBrowser include(CMakeFindDependencyMacro) find_dependency(Qt5Widgets) # Our library dependencies (contains definitions for IMPORTED targets) if(NOT TARGET QtPropertyBrowser) include("${CMAKE_CURRENT_LIST_DIR}/QtPropertyBrowserTargets.cmake") endif() # @PACKAGE_INIT@ # check_required_components(QtPropertyBrowser) nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/cmake/cmake_uninstall.cmake000066400000000000000000000021161455373415500272660ustar00rootroot00000000000000################ CMake Uninstall Template ####################### # CMake Template file for uninstallation of files # mentioned in 'install_manifest.txt' # # Used by uinstall target ################################################################# MESSAGE(STATUS "======================================================") MESSAGE(STATUS "================ Uninstalling ======================") SET(MANIFEST "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt") IF(NOT EXISTS ${MANIFEST}) MESSAGE(FATAL_ERROR "Cannot find install manifest: '${MANIFEST}'") ENDIF() FILE(STRINGS ${MANIFEST} files) FOREACH(file ${files}) IF(EXISTS ${file}) MESSAGE(STATUS "Removing file: '${file}'") EXECUTE_PROCESS( COMMAND ${CMAKE_COMMAND} -E remove ${file} OUTPUT_VARIABLE rm_out RESULT_VARIABLE rm_retval ) IF(NOT "${rm_retval}" STREQUAL 0) MESSAGE(FATAL_ERROR "Failed to remove file: '${file}'.") ENDIF() ELSE() MESSAGE(STATUS "File '${file}' does not exist.") ENDIF() ENDFOREACH(file) nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/doc/000077500000000000000000000000001455373415500226005ustar00rootroot00000000000000nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/doc/images/000077500000000000000000000000001455373415500240455ustar00rootroot00000000000000nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/doc/images/canvas_typed.png000066400000000000000000000377701455373415500272510ustar00rootroot00000000000000PNG  IHDR]$F pHYs u :[[tIME 2g?IDATx{de}OܪMVŘԖI j 2B(^Ipo`lvݠيSA5M 20wn0\ J{9osNs_&=={||Oj>71cL4(c1& 1 {{5c1iαoQqvc1Ƙ4g_~څ'^c1ԟ^^qթ[f t1c9οiyX֑[|ΡMW]]_r/9kc1ͯ_q7-7pݎ`ָv ӫ^{魷zm][[sw9s׽5cu^|孯r - f 7|l{ϭ[>|ӟ޸M'7_u.{oeՍ1cbfۑ[xz.<v΋7W^y_~ܹ_}]c1&9_y{MnGna0k\7/:o˹瞻iӦW/}󅷿c _֗cf^r_t9 }]7f[x '\|/htp>:1lw YW||9;_tڦW;Sֽ^o^KNظiÇ[rEc Lo9o{9p7<(}NxW&\~ᤋ~/ɟ55o7'uqo`K텷05.Ke?N 4Փ>uӥgkcLGf`wqﺥ/9oŘل/t𝡍aK^~qo@ Öqa0k\x'vϺ~cٯr9o*ƘHoeeFU ?Zwi >Ν)gW1}f[x  m|ͪ k9JuŸr2> f _G׽?o9g}^x>RycLg;^p5~gٖY~cZC>t2r!)uy W S~OJ>ߙpk>n$0 ̘)[l_ -|k?aK^PV ßa0k\̆-B~YwgqƍOpچT~-cLgpyy/8zar| }|3ǻ7Xyˡ.e{.hvU78zOo {v۰qm*a_c}6W5p[{~ghc׼gN?p9lwt.<{~}ӏ=3?ϧޗם|NpƏ}1.Թ_c}^~moY>xu=u o!k>?aK^Np7x%\[[y>׿no_z饗]v͛7ck mz7ss+mٞ Wo w`k~{-ŸYa)W~٧SdU[L[5fLmsE;[86-ni]xGU-[=|ro 7pu׽;*1s~q_pV. ? 9m7upp!ܟn\xf{6n[FZǜ3dw2ut1sο8lu;r YMY?\yՙshGϺ[?_>Ͻ=oc#:/ 5O?sm__K6n/:\pLC> ݓ즲< ;d$3SCPc;g^ fۑ[xdޅߴ<4x'O㕯ߍ~(>~>68n7cLOU}ko:a^rg6a)hv9|ԫ&\[ q-CM؞]璿\;~Sghc`v캃: nt죣ofۑ[^ٽ34g}ۧ]l ?4[.>LJiWGcN|k;>CU`_/4pݎ`ָ5cz:g/ϗN  ;^1c_nyݦp 1ft'ppݎ`ָcLO}_Z>vwŰϼE?6.-Cۍ1&?&pNB6k\cLj\/WXcb5.|3c1ic1Ƙ.]>ړ$IJ __v$I %Ią$IBI$q$IP$I\(I$.$IJ$i.\Z[.H$)*NJ$%EB$IzqydI]X %I %I %IRsa$%/:tމ$IR.$IJ$ %Ią$IBI$q$IP$I\(I$.$IJ$ m$IJ᭒$u/-I-nٲO%IFJ5,\°S&\.m(Gb*u]w@ e8zd8̅PzOVNK |΅ vBIhv0߿0Rz[lזJS0lr`53Jt;>ȏ*gܹse9k[lזJ詂~+ 윿̅Pp=V9][-.|GW !>TC;gq$4T'\xG*gz:ҖPΨc0rc{BIhNC~] m 3zҖhPΨ裏Gs t.ptuP. ~]7ޅ%'39r$|ɕ ; _BIhNp{z:l=L\(E>5BNouȅGG϶p$4T'\{@Biԅ9TC.<\JBCu…;v.F]`iC.3JK]ݕÅyT{!`d;sit܅wܹrP*a*`g.- 0pPR4tš(B %I1W\\(q$ PBIRe/9GPąOz}ą]cR9\(q$ PBIrą$.B %I\ȅJp.]wP o-[·Cra yJąӻ0]fɰ T.< 5+DI\8s?{CV&%.+QЅ{47̅.At( wV&BGG B!J.w~]h(pal(DCI\ԅVf 6.Mt( pCɻhQhQp".״2y:> \3 Ѱ=#B T>LCh3\ȅPHlD8pyj7nC=Y̬ur7. reBI`.kr&آ7`.ݣpar(LP(-R]=TɻwB4Å\f\x]M+w\ }AJaߟG]YBG Ba4L(!V\;M+w\spN"lŅwܹô2y:> \ȅסԗB>ȏ*g&.mZ v.B(pڮp. ~/V&{< ]x !J]m۶jm9? \ȅP(a8xzhBB..r! P;r Ņ\ȅ ER4"B.r!B&B.Bq!BaC2˟H\kJ l .ƅwb%raB.L(͜a]8+:yNuPQwi P"~ ǭ#n.^rku*7z` ;+].ThR"g f Dǒ{ |GB.LԅD(̈́}a]X7N<%Iم5;B.T\hPz҅ `sua_G^sB.DC(0Zq xɊr!&B(Um|2oF#¼ :xtم+)24WwJ o qa4; }DB4@ 5s 0EZ&Lhh Ņ\6i\ȅDȅ\ȅB. p.\>{.9,\ȅB4B"BL]\ȅB4L q;.\Ʃ.B! .ޅvA$Bi\ȅDȅ\ȅB4Bq P\- -r!r0i ⓂB.Lʅ8ȅB.BأO0a.̟9%naJ6 ݥi"]8z)PPȅ\)c. g(~GqJ rḅمqKnRwaؙ A"Bq!rp@l^ȅ P\((܅kK\h Ņj \XADȅ\ȅBY&LŅ/7+zʘ 'uᒤոPP¡}!NBH.ą~pB#[ B.BqZF0}*y3: P\ʼn 1r! J݅8 .BqP\81 yShg虧]vaB.LvDž8 | g%ҧ.r!raw\H\#[ݞ]}VkiDrP\8_!v.NkcPXr4F{ B \䍓\!zΊjCC.TPpa.@ȅ=]/t%.[\ ERp8܅_cB. g B8v܅+)2,Dq .\ -.I-.*9⠸ .TD\`P\ȅB%BO Ņ\I07.ƅ8(.ral(  BuمKVi] z P}vᣕ3 H.ąAau\ zą\ud#. C"B 8hp! ;Mցh B 0:C(ŅB.Lt0 B!.l&}ʸ濏,m۶m-*lA<w܅Cdے='=7[q&:ƶ|H1R][QaDjUraO >. ra<:L!_.עq2O,-M +op^ <\زgD(Լi8=P}qEtg*+X5e38?W~7pa9g dz˅1,BsJ xw-li^X!@Y'[sIg5:[0QA"TL.|I]X@pa]XgeJdG?̅}aM Z&Bq<\XQqaš.,yeIWlI_i:x eP\8'>RԤ/,GFSLj>#9{!oLn "0iBP\/T/ g@ݹYS@$B%BK)PѸ˅:u B,*1>R9\ȅI\=Y r! eԖ ˜\(.Դ@t4tᒤոӅ'PŅvCzA$BNp0\Bq!r # P\' ӡ%.B.[oFeY r! 9Ep 9 rj:ICA0Qּ:$B"څ  |PEa3b$Bqa4.,_3KʅPȅIpݎ%.Ʌ7Q<,.B:A"FB |Y\ g2J\ؗJq!ra*" #q:\JƅG*'瑹pt1B!A"FQ < +ߤ  ! vA0b&q!&iq\<P\ȅ\(.LBP {Hp! eDpI\ȅB(%=г J\ȅPؗO&BKjхKVB˄3! ;R8] a;$B Ņ\-J\(.B.l>YO.[ P\ȅ\2C"P\ȅ\tP;$.GuaA(?2dɅ]Ga$VZ p6^8C:.¾.|r"pa9 &]`ƅe.Ž +uH1FI4\XɊ O@D(qa4:Xqš(B." C J\~':\@(C?\9qw W.?(® PΊG-?W΅\Z. y'ޠOm P\ȅ mן88-EBq!&$B( &B4P\ȅPP8ąB.L~Lr >pIj\h.m'+N:\(ԅo- " ׿?dNx  s9ȅ]+>nf2ٷOhȅP 4PB3 3I_gy߽Co~a.F8\Bi>.|r Ug:¡\h PB.]x}:$!.B.B ;'>=e`#=}<(B!rąra Wc.;vՙ]H\ȅR_\x}UN .,at 0?32!rą}|y",’0sa^IхPȅ\(qa/ G7΅@ ǭ n '--B!rąpa!+ #~zqVr#O  %.ž\੏:ЅCS8nz2!rąz}J)&|!O a$Pȅ\(qɺpoaP.$B.B SvP/p3G0Pȅ\(q!r]8VP/ oV.1rą\;~ˁG_63޿0|/ȅk-1B!rą\ #d&z€•Jp ]xrtᒤµѥʅ\(qa H.¡}fBs!J\ȅ\pGB.B SR!r 9tr ].&(B. PsB tavNh}0EézPJȅP(.0J&M~pLڅD(.0b\B$&*Z&J\X߅V `cTӅe]B 'uΝ;ÍŅC҅Ҹ9v4L…P(.udŸ0H\X6Eľ""B"J1p"&’&ʕN.L΅ ŅR(Ot\8 B&۳.,yK/L˅P(.0NATDžP(.cudʉ.d2. ~Ћ %.ޝwx\ȅ Ņх}d.T_]B ŅP(.p.輓%IB"J\Xƒ>X9Sw KKBjӅ ŅɅw S.߿ ŅՅ__ զ P\(q!  Ņ.;Åj;J\N͠Yi p踕ɡġywэ_s! %.y'a˿O}TA.@ 5XG~w{Uy.Ņa˿5 KVzR/n|-3fw8 ?Ћp!j.xąuE5va 1z;X/,?htabuv\cqą:$ly'޵ 기uNd-_5 ;B(J\8 >P93<$lyI y>^JKRGG\غ 9䱢q 럷;a!&(X<ú\\ą ) W_(U vHօ5_7O7Q7_#sǒąv4_κpw[hF,]ąy}$q ;N5JÅyrfxމp5Z&$. w"..BIn պ  \I^pIjsqȒąy'vA$B 8$.y'4 ,$.y'4 $. i 5K,I\ȅB.BIBF'R~4Lu_I9ʉ༓ݹ߻d,.JR]wʉsBS᧙Xr|F7 '`+@EI:0w9ko=Ņ`@EI {wI Kv`r p"aQf~wRwRp{D<'Ur|<̅ Ea4"4{+ǿwz {g+^XNPp(DñX,ta^_ȅ hrp@E E!F !,*nyLt]ػNAB.L!/* .Zy'KV ”i8Κ7Бj otpr%8Gn }i^Ѕ 8XưѬ.ﻷr|}/-.raPXICXFW84ȅ\ȅͅAaZos@6!/za>\8y'P\ȅq ($l.,ߧٱra \Ht(.,wa-ZTmX5oNr!ra(DCq.|.,^ zy䉎Հ#{rio(h]'x–:.W9dC5]X0Nt\.&B.paN–Njȅ1B.MQ g5y'%'& ]8@aʅѺpN4LFB4TO]{`5 _Vyމ+I Io ™0_\+ P\8/ Ņmo.b! t Ņ́@whh(. w".]X~wqO..ySB. P\ȅ\N P\؊ $ƅ ?\(4l3y' "q}&rP\`?ģ̅BuPypN<\(.T4Lqp.B1 զS;b\Xؖo.h\ȅ\(.T@L@qa}"yIF 4c7ݷ$@t| :҅׊υP>pza4L꼓!ፂplBZb %.lمE!ra/,tau {A瑹 %.ą@!C;a.,3rąsDH02srNB.B cpbPp҅N ϽB.B  aqaӭw2.Qppą\ȅpƧtQDžFţ ar! %4B4L WNpPH\. Ѱ_@y#SwpPB.Bޅ}< ŅB!j..%IuԅǮzt&B.t!]Ѕ^Lx\(4L.);.T/]8v8z G!raNh ?Vrz07B.y'4 GP\ȅo\tم^_ȅJepe.Ba4& Mä\8r'5h5p\X =,4\<  J̅;wﯜ;ȅ z}А J.ND !ra]دNJ`TlVV .а(ŻYot܅;dK0T6yd.B B..0c1V;\ȅvT\ȅ\NJ%.JɅ\8;B.BIuB. ;dj$_aSÅ:ra7]wk-JB.90$%4.BIh\ȅB.ą\ȅta;B %q!r\دNABIh\8瑳%Iq$.__[XBI\ȅ\( %EXm.ܱk_Lyމ_ %q!PRT4raNtމo^ %Cø*6sJ\()9FH %.ą\ȅ{+y'JBÛS8\̅;PRB4L`ra:DBI0ȅ\JC.B %!rN$.DDȅ;P 8DBI\8z}ąvo#qa.{B J\ȅ%.tމą)r%.BH\Ht(q!}9.0uą\B!J\ȅ\(q!ҡąprw"q!ą\8օ; PB.tމą\ȅrJ\h(q!rąPr!J\h(q!rą\ȅr!J\h(q!rą\ȅr!J\ȅ\(q!rąP&»v,WJ\ȅ\(q!rą\ȅR.pązB4 . P~pOpą\ȅFB. PPB.BIB % %.B.$. PPB.BIB % %.DC($. PPB.BI؅S9\(q!B$.B %q!J\ȅ\( PB4BIpwpą\ȅ %.DC(ą\(q!B$.B  %q!J\ȅ\( PB4BI\ȅ!JB.Prąh %.DC(ą\(q!$=;]9\(q! $.B %q!J\(IB.PR*~.U9\(qQȅB %p!J\()urPBIhB %! %.$.J\(Ih(.Pj %.\ȅ\(q$4DC.B %q!rap.P PBIh(.B %q %.h wVJ\( Ņ\(q$4rą %.ą\ȅ\(q$4DC.B % %.$.B.PА PBIB.B % %.$4J\A[/#.B.B Jh sgpąIsB!rąI\ wTJ\h(!rąPr!J\Ht(!rąPr!J\h(q!rą\ȅr!J\h(q!rąPr!J\h(!rą\ȅr!J\ϮqP\ȅB.\(4UgPB.B %.B.А P~#4aBPB.B( %.LƅӰǐ B ra41BqP´\ ýB %.B.А PNp4J\ȅ\(qa]0Jhȅ\(qaG]8o+. [waMrąwh2J3b۶mZ3J\oΜB ݻïp\(qa]8+ J\&Ba_i\(qa]n %4{ %.L݅5Xy B p6Å=r!Jhr!*zą\ȅjezą\ȅʲ^(q!&B($r!JhY/ PBCX/ PBeY/ PBCX/ PBeY/ Sq! UB %4ѬJ\ȅ\(qVVJ\wvsPB>fPB.Bg.D9ePB.B4tXB  %4ʊB H\(.Te %.T]t4sac(4L'*PhʬJ\D]#0|hcž1яD 'P`ŸPҤUpǮCχ(ڳX/Ldp_{B.~C4]6D 'P.z;Y9 wc.za"녓 ?Jta3 w޵X/Ldp_Bg.NB͝1¸߯Er!><ًɜ.% g+ PjӅ TǷ4{>@%I=|K^Isq$IP$Ii>b1cҜ. gg1cfqA IENDB`nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/doc/images/canvas_variant.png000066400000000000000000000356751455373415500275720ustar00rootroot00000000000000PNG  IHDR]$F pHYs u :[[tIME 3t?;\IDATx}de}?MqlbI dDp@yQ( Ip "bACLKufOٳ_M 2ü1>WU޺r}ҩ]uVuǧ6 ˽0c1iBλnۛQc1csvc1Ƙ4v~=mc1&YsW_rq7n3c1k+w­ZlVpMی1cL@vNƲ7+\x^};y_reoW+9WaW0co~{οcބ۶dYo7緽{{77+u{o}^?j1{znے=f |z=on;uE'\O+􋯾7c1wb m^ Ov_uUW\q\~ҧ>қ_c1&9#_{睻MmKЛ.|gןsYvgqE7gW>{Fc☥{}cV] dW -ñ N^}\tSưez…o̎as',w'Пu{5ވcL4sµuݯ6\dW=bN+cLsG/7ᶅ{+^?++ +ᘋo> ?.-a{z…kQO: _{Y'39}+cfNxu= 'Uυ>ڰ7֘k~џ7ᶅ{םw˫rx.->ެpi1zVիWy̛~s>_-71tk:fKEo oR-o[)} аw=,_1+s~?]om ?nƷ/a~'~WZކa˰ϡ7+\?1z}ǎ=nW}Yg]p\қc:4=[>Ko{o-ٻYIw>toW•9\!d=Sw{! [jY/?buB@c:7'~&ܶp:a;>ݾaK^q ( +ϡ7+\[w5"<3/?N;SO=5'+oeX3G6}w 㮼;ð'[9NmaC٧]3|˙ʿ}EٿadKG{ӹY{_]om ?nư%l经}Ÿ?za ^r.}C8 h= 3WT} };1[s}Som K'{gocWC~}q>\oeЛ.<; n~>ԓ?l˛~/O|Ӛdl?sۇӕyI*G(Я1L5Gn~Uwd~իBS>ү;P Z2hc:4oܵ'?vO%^ᶅ{;^x?'l +Kogޖp9l Л.<o\./|~nkG=;}U욣 7?Oz=+YaˉW}+;#6aq1S6޻/g?}ĉ'lfp7m [%]xm߹kÆ _s>3m?[nƏ^_ׅ77teN/ 6v÷p9\XR0c;tB|^u=Ww aWqXj|-Ƙiznے=f ޾7g}ngy6~/}_]w1+O}X'l$69w{;i~k>=^LJ Ov*_$nKӷ}m(>UBc:7_ znے=f ϻcoϝz~(3璫?[1wq0{p9{MsǬ>]=/ yo{m[=?p!=yzCw1-o_7-CoV/2$>gʱBo»aco{xMɄ[-,OL~ Wc2g|Wznے=f ǻ1sMyGr/NPdy}Ɲppۖ7+\]Ӊ9rWVB+8JƘ9LƲq'ܪU{f y.c1pd1cIsc1Ƭt7>b}WBIhV$.t-=Qgta1s3zŅPp'f*.-лN2JBC…Ϧ0Sqߩ wJ~{>f~ %Z{,}( J.id\^h^®r%q]~/}q|;\^h^DHprid.t40*$.{5LޅFƆB4ąu]idVi^DH w9` f.h( rɻh^˜Q[˲q(6ϗT\sBy|&V}bjkہq/p!B40ɎŇ?Aa.l'VxFFB4B4pY$?˒远_Dek۬tᾶͰSxǽI{ SA!VA!J\}O ޶>4ɻ{>v$wM{ B!!J\DmǞO~.:ޤoE9y6 T \ip!B!J\ n= >(8wRx9Lޅ|^x5.L  ua‡+nn~{Ɗ;̶p>waSCwFwM{  P{q.P1荅ۇ]3Ϭtb;g/eid.t4 B4;vyl7J: M \ eB)6nf f.B(T3a#.|ɻh^B.RW ]SϕT\/?|42y: \ȅP(um]~/F& m !J]iӦjM9 \ȅP(a88^Mbǿś>3Kw_8B.xRG0ef(\wgT&8 P"q ta [DT.+ٷ}.¨DR4"B.©p뎽Yx\ȅP(`{Eȅ\ȅSq[wfaeqa4fR ]wa Nip>.7CU^tc.;Y(Q.B˄¶EN ^Sw[^mCa޻y ^a̅*Å\r\8lqp{va{TyGG.\)pa4B)evÅKC-ٸ*\ p!vTE] Ѹqw _J8% pܸ -Jp&OsL]Gsm)&ߵ5EC( a ٕ'Dh¾S8l<̅Ps~aޅOzt±YZ,8LӖ9XghJߩ !&Gî(DC )msa/ 0-Z&B4@ȅ\ȅ PKC(B.$B.B.LӅ0U 0E. NW.LʅboWTf_|}qa4. =NS!&pg44Sra@H\3 -r!Z *.\ƩCs!Z .< "qFHC(B.$B.B.r!zʘ Ņ2!r! b'((¤\\(.BB q!&yoS3 G,PP(.1˅SBB aB!Z TR.]}ު,Uvޭ+r! ŅSpJ.ƗBnj{apBq:B Pqp%orFHn.l3F[s! Ņ]xN +.k { K?[.BuUPȅuB. .qG|d. -ra\8֙"α~Ø\8⠕^qڈB B"Bq,]w.Nu+s9H\(.B.5 !r! pprpB.B.1:8s[Dȅ\ȅBY&L…/7̿˅2.\ ;^w.@ȅСn  q. P\QͅK+J.cυ;!B.B.j~"Z/yʘ ŅBq!FgJ P\((A"ٹ0^.Aq cCaoP\XŅf.HZ 'ua'c.lpPҙЅtA$B頰:B.wB.ZucDžuatH\hP]wc..Bqai8-rBq!r B" 0s܀\8)}dAnڴicQa{*mL݅mq]y=<0C"Yj Ö/*l CmP\8 G5S#0&>4v.LH 5X +jvU;,t2¾5zT\X3)hZ"j4Pj@;"qXb.'q\!j9D–.PDžM1֢]mL&ypaZ:$BD\lQVȅqaRzzʟ3HtX eP\8 >SԜ]8L\8 +1Tyh~# |@(. * _~j3HƺB#W?ȓ'TLuGƬC( [ Օk{K :Ք.BEI(O{\XZsa@BY Tb.|t Ņt@(.B.|"B)>SÅ1P\Ipi*$BIqa Oӡ, gBH6ąFao<, B.Bq!6F"$Bq!r0N;CM"BK\ȅ\(.'eP\ȅ\(.@t%.l &ȩ/dqąP\i^.;0]! A"Fµzua](tE8ݎ%.Ʌ7L̅9 0502(Vڗ,ra"(e"+녥Ką 0~j.%Cɺ9(\;A"F¥!Q, c4^_ȅPؼ "tą0 1ND9HB.Bqa"ltHR]cJ P\ g'BKB.Ba'莞PB.&®| t87:\R.\Z&ι.AhC\ J\(.B(|thPBq!ra}zrąB.D -ąB.B(Ú"!q<Dž}<2\ < ąspeq!v^%Uvᓥ G@gpplpc?l raE:$BI\8 bōpa\1&ąS`km ǽ,.l) C _wX[.:s Y >Y:qw ]GKPHpZ<*<}xy.B5,BKB5uڍ3(S$.ra*.6pg,qH\(.„DBD   "B4P\ȅЏ\8]rE.HZ -vޅZ?zJuCO q!&©s %.raTKP {4PBq!FDѻp>Ål\Dp! g+B(B.P\ȅ %.l9 iv@=…P(.0N^NDž}G …mAr*I#Uƒ . Pa4y䱰 G<,.B.B #\/0ѯ/^\B #wa!K S}…\8?zp!J\ȅusPpN"B.B [SLJ7F?R\B ta?! D; PB.BЅk}TTƺ2r!J\ȅ\pBM˅;B. P-uzKPȅ\(q!r:RtQB.:ƒ3 $-7. nV.B G.AhCs]/δ\c.B UP8Pȅ\(q!r¥sJ 9X"B.wr\ȅr!*uzX\(qa. h85U*^Q  ŅFBܤ^v! %.؅+gJɅDž ŅVw>E6Utau+fBPq]m۶5ssZy p! zZsM g>. e; æVYD´\HB)&Eä^_8e t seBq% 0Ѕ#V].'i0-BP;}fFQBP \<ВK'Nɸp<A/. ;wIq!Z&J\8C#sB(J\ȅ\(.BqąSvX,HZyP.ܷҙ/,8mIZ&J\8#uމ aBP™ =`PMŅr P\(q<^_X.T.ܱP–wn}\ٌeaT;&gGܤLq?n쎛 P\(qa; [}\p$_~һhMrx0rx.$Bqąx}aoE…a+RS7_`Ox0c.Bԅ.|.4D!&Jdžb֙pSƓ B %.y'a?ᕅ-U\X@./}5a-#XxB.B(J\8 >V:S<$ly\X3.|ށs.$BLCqNr3EUwaUpV?d*O+s.BI]XOUхjrINpSUWsD%睌p% ;PSt<;5KP(I\؞tڅ]1k]B"$. >XLDž -Jͅ;ra}B$qa;]XB. \INpAr3qȒąy'tA$B 8$.y'4 ,$.y'4 $. i 5M,I\ȅB.BIBLF9iכ?av N\臯$q]hDpI2 ?J#Dž\(IwQ&MpB!J/L P.BIr!kՄշ % S}a{'Gq.BIRB.ܳqI.~~ r$ ;މSS¾' $ r$ ]T;J P\(IZ/y'\(.$qL\حNABIą]pPą3qa.HZ % SwL8m % S? Ņąp#3y'0\(.$\Ι : Ņą1 P\(IŽ0;tػ\?apoy.$u H2^༓>p%BIRZe.ܽ .qI4Å\(IR%NpauY Pą\NM7r!JRtabsǃ02V&r$)Qx}a{'\ȅ\(I(x.Q %I\y')v\(IR%B.JTq__ȅ\(.$Ez/y'\(.R^.I N4p.,'I _|a'a#g?J\ȅ\9Q\R.l #~4pa9\(q!ra.|TMp_8DJх0GFB4:DJ… 0FB4TQ8 w"Fh ! PB.B(DCq!J)p4L1 w"¹0r w"Y0FB4Tj.tމ gDÔP% Pu}ΐ?,0V $\8-zL P\8 w"qa} z(P©y'D0ɅBy>} \(q P %.Tih(.B S\(4½ 9\(. w"q:FC(DCq,\ 1sܸPh8z}ąS;b\X؆[1Ѹ %.T@L@qau":DB DLJ kpy'J\ '!ICH\(qaT.. ѐ PB ;Y ӡ!J\(qa .0(s{Ky'J\Rh{Ą.tމą&B4OBH\(q!4.B %.l҅G!ơrąB!{{х{Jy'J\"6B4+dB:DB P4 w"q 8]xkgkŅ\(.B)N(<.&u rN]8v8x G!rNT\Xa0?dͅ\ _n84ȅB.}b .B)¾p a;Q8krą㹰B# B.™0s{Jy'Rr.\*:;A\ȅ-wN\(aQȅwOo%r:DB B.6 %.R?a.B.. 6yr!ޅKy'J?=.ֺy'JB.BH\( PBIh PBI\ȅ\ %q!rN$. w"q$.B.B %q!r!J\( .ܺ}w8DBI\ȅ\8ԅ;PR4ra :DBI0ʅ\JJR.B %q!rapqމą'sN$. 9\XÅ;PR*:L0ra=z}ąajǐ PBIh\ %!rN$.8ȅK;P NŅ^_(qaH\ ڶtP¤9r:D9rN$.$B: > %.Lh(q!z}ąPr!J\Ht(qa.\,H\h(q!uN$.B4 w"q!rą\B!J\ȅ\(q!ą\ȅB!J\ȅ\(q!rą\ȅB!J\ȅ\(q!rą\ȅr!J\ȅ\(q!ąɹpB %.B. PJ҅.RQrer!J\-,. PBhQȅr!JJ\ȅ\(I\(q!r$qą\ȅąr!JJ\ȅ\(I\(q!r$qąhąr!JJ\ȅ\(IcpC;K %.DC(ą\(q!r$.B %q!J\P()5(. Prąh %.DC(ą\(q!B$.B %q!J\P( PB4BI\ȅ!JB. Prąh %.C"]Å"JB.qPrą$.B %Ҫ:\ÅJ\(.P4rąR! %.h(.PPBIBqąB % ѐ PBIhȅ\ȅJBC4B.Pr!pB % %.B.P PBIhp[pąP\ȅJBCq!J\( ѐ PBI\ȅ\ȅJBC4B.PА PBIB.B % %.$.B.PА PBIBCqąaq|ą\ȅ\(qaD Ssn+.0iTB4B.0iҡА vB  %4B. PB.B %4B. PBC.B  %.B. PBC.B  %.B. PBC.B  %4B. PB.B uwm6m@! Ņ\(qa(q{/_ǕА P¨Pȅ]B. .n-..l BC. %.7\8! P\ *. pА P\6\(4J\ȅ\ȅBqą\ȅ\(4J\ȅ\ȅ ѐ . [B'#k4tX2 K.r!J\ȅ\ȅB.B Ph(. B P\(.0RMB.r!J\ȅ\B؅?x År!Jhȅ\(qaW\*0rPC\pą\ȅr!J\ȅ\(!rąraKhȅBCqą\ȅP(.J\ aˏ! Ņ&icȅBqąiϊ %4B. PBC.B [90PB.B ¹ѰYA\ȅԅayB ѰqVD!J\yΈٞP ۴iʅ+sąvi-Jhv~݄ rąwtطC.덅ҸP¶6 %4z %.L݅Xz B p:Åv=r!Jh%r!zD ePB.B dPB.B(J\ȅ  ŅB %4J\ȅ\(J\ȅ\(qJ\ȅ\(J\ȅ\(qJ\ȅ B %4J\ȅ\(qJ\usPB.fPB.Bc.DePB.B{4tXfB  %4ҒB H\(.Ti %.Ṱl01B D\(4Ti %.T. ]5ҡ0J\D]8X0J\Q[/S`P\T %.T., zą(<0٬J\]8xNI!w".L**E:&BC fPBq:B  P\¬J\\ 5̅6mXp5 %. Ohȅ %4( 2B Ņ'ztPBqfսm tO|`~B ŅŽ {7 / %.j._ntхh8-ڳ?B ŅB.߅;Y(*P.P\(.D]uB yr!FB4܅Q:\(qaU-ֺ P.|mÅBahȅ\ pBU. DC.B.Dq]X\(q!rВamڴic•P6_ҒBq!vzpPB. ̅\ȅ5\^_XqPB. =f05\r! gG ͅO>\pą\ȅyspr r.|gJ %.B.6IcJ\ȅ\(.l!‡ PT0\(q!r](DYpϾGCao{. ;B(vp(Dépמ01 J\ȅ\(.l +pm År! ۋB4 nU:\(q!r(DépC;J %.B.ra.|mÅr! ێB4܅|U %. %.l 4amڴ)pe. P\va+s԰ f߷կ,);v6ʷ=rƍ ]}T컽╍1LV}~ԣ!J 7y1&ɾ)~T>JtO=W: |D9D.&P\(u҅?L߄NQߖG;d;eX/Ldp_>Jta/?j^"G0D? Y/W@ {ba?X/Ldp_կυR']gߣ,m&CC&^/Xﲉo&^8ɯa7 Ï 6l\vJ\k(sD9]6D PspXQJN{}mPعk1&^zḿJܻ|\(iJ\u }[?c~&^8_ NpC;Jgdw7 Y/W@sI>Pزur ֻl녉+P 7pPxpvcLc0qT>JsavX?*^X/~T?/ q^L$p)?yO)pj &]oJ'y%M߅O[I^I3q$IP$Ii[ c1Ƙ4'h gc1Ƙ_ֆ,IENDB`nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/doc/images/decoration.png000066400000000000000000000147341455373415500267130ustar00rootroot00000000000000PNG  IHDR>s pHYs:duhtIME  01S* {IDATx]X6F&jh4&&zck7714E( b 5GD `bT(XQQ, F_g}ݜ9̞=ٝz,I)MuDCOݡaq$$$|Z/HBn{ޟ&96#0%c9x>u-c{fZEyan[1Ую$$%$mg0jш]v,sֳ), %}x>u[(-{ .` A6ЫюyR{ِ]qiA;,;bwq KfI37O݆3N?'O}w̙n#}u l8הm<-]|\xG]#I޽_1^|3x 'LZB``$l1sxIԝuN6 [xߞ˻ eI҇pzAݸ|ˌC2laLM (,cRⱻvwԩIU]7u?}}UiQٽ(~>ȽǙ9OIƕlC|Jxc̭Yn㠩<脝ד3r 3BSr92D߫1ᄨ$ ܝMfc<(VmTf_xüQ``P_<1"(dc&F4FSh]aHjݦu:ڳ_%Fe[їm?hc? < !7x ]`-wﶷ_uCkYNO*>VTI歓S0d{%?L7"(dcVI5nnȨ6k߻->k^ꌷ) ifB\5dȐB u5)Æ ߨ7T4@(r^{ݻŠTj0 Ͽx_:ͬ^rҚ9D)+:zU6~BEG7eL%AtA% i1jeˋD]Cm=ptN{uѳ| ,}DHz99+)gj73I=d­y%--=`iCW~RZmZi*uo˥1aKeµiO]` l2/+mxJG.kY־Ȩ+w_G.n;uС7]+9ՙ㽑uq^&VW$f F|J?޽ZR3^v+q^ԎFNc'n,+!aF\ٽ`P&3(,fcV:r%R@[Y78˦r;uvhkѾS#+vn;ݼys5}Ms9zcu #65|c?^ܞ 崈\S0w־\SVBoEEwfA7I6C膺:Iov% AtA%ܵlxw´ly}EVpqFsKۜ|өv9-_7ԭsdg222D3,wk׮efe=qݼ{q!fJدu$d[tRRRN|?ѭm( YyQl wT1עoNk!!Q``Pɦe)2_VXMa¬I5SCws03S"~ev}[:ƙ%;bw),%}&"!Q8)ڣfcm#0k$l1uI4&KX]?zU`dj,%}"EBB!ɧn)( x?@ &H]۝Ae`U.]]y렏|2YuQ4===eYSS)M.vxB2bccu)єfP1AR >"hBASA݇-CH]:hJ3e3-U?)͠nP*TкukDxiBj̙ӳgOJd] ݔ.K\zuȑ7&ꉺUzg ؄YD]S>xΝ;eʔiӦըQ^cYf&/WZ7xq70y{ꕐ 5[JĻZ+WXD+k%nv0v؟~IA$1c qiDGlٲmڴtM ̦n` \&mmŋ.\hժbC,Ùw?pܹx;;;5k7Ko^mJHD<[pdׯ_wY|gqoܸ&F8.QHԾZMV+_<8111WGei&/v1>r~CX Ylɓ'᷑vpp U۵R7YS8pYzĉ2n݂JM=5J.͋x-*ʼ+fEݻw_`zCLmJHfX0mTV-<hOm6R{)V`6u\wS4.+/&,̙3mFFFǾuV UxMvpB n5˛'@ћ7o4D\ԾZMT1Ѯ];0xq/faaLQ+6х8x!kRJjۦM*VB&j ?s<mƕoҥKUƨGux/5jF *JM{lFuw ZԽ;h 3=Y!u {eKWCMiuZt5tДfPAR $hBASJ]%hhAF]jJ}4Iԥ8O͞4ŋEMS.A}^_>hPDbͽ_  Wű\rXӧO|X#L*U1YT`hٲrAӘ%JARi^dz!ٰa4 ɓ]䊨K|ӧE"00>:ԩSL_F0`"!{lagggpϘ>33*W믿2%~ARaW/|~M,֭[ŊX\yPZP5G]!kWC-ฤXMGx] q J#Vf2#`>xy(B 8az鱆Nadر## zzzJ=b_|Vx7]t({JU+i&D`)W.X!4x.ׯ_6#b?cy4Kc4B4^FψҠ K׬YD  >46yLRJ]"OݺuI G&3DEE5k֌1Sjzƪf.wqdo ,Bgeeq42/bzEFsAT)~w,ЦeUE)W^ V, qsM2>p.c!.N8uQ@֕a4.`CRzjL`Eܖ-fjx]\\%|R2a2`ҁ%ݡCT 6zh.lp9el*oxc9."LSbpۥKne+/`0  /TҡjC'D J5F @׸w ݰ/b`ɉ觥.֬f?ńqb6SAJ8m7f;،4[aSG<7g0 +E$G Sy.^`ڹUUrRω_~ڵ,J_L5kExᴉ~Zz]y]Q@^@%%uu.D@ &Qc9ˣﺭBqdc5r7`Kuo[Z*)Ty"!&6u(-{JU?ZlCcQ ?"vb`VAn,`l988` ?QU,LSXC6#O/\@YLtt4V;͙3)h pR7nDkԐ~дiȧdY&V7|%<ƽ,}'-UYTc{2$Jq𫲇Tu{X]v k!-PUXJ̍%K;qۍDJ8Ѓw𐕥neaaax*s%h*<.VwJdw4ũr:B ɳЀ";P+Ⱦgo=zR3RQgϞ ފnYو"J̍Uhodp^*qCVd(PQ(YBfEVЕ &K]De4 Dqz]u^b.t.r^Wx :CuTo Kdx)E*H]Rtd'5Ѳ-nQe+J`ٴ%T)z,u˛a^愴'ÞLƓ  ǺXWFа @U乘r<^Ǻr`[zuY˃)E*H]Ʃ/Ô_F`:#Sn[@Y(W|E?O!Ʃk'/:Ir뺮̳%ɚc||Sx1wAr3;aV:XN ؗsyhUwϛaƴ3caF(tuh˖-ȵLQ0\F2ü(EzL:B- O{ w?SMnDDJ\5N]O2dQldhV}/fY)0fL;8^J̍ԥD]#d2W\ƴbDL W\xy4hٸ13+VrٗC<|A/%>>ėǏ/܇Ǻ',tD]ZaKy+cN%uB]|/B(JXP4I4|5&T *h".Wzqٙ}{gg]-BȆOg".k".k`2EEVfo1a# OYMdڌj<0>[ICszƣVp4KMWGTϧ-E6SlSi!aszXq}G+Op yyPWX[ /j ! }rt,SRR"4Sw===.ǥw_6Sm23kBikO=텥/4*{xMmBƺ^Cu_Ct,H,@)z`, jhhhA 55 fog6ϳ޲Qef"4~U\[Q\&6j ܗ9Oj0EBD%p D B=}|Vkz^Pسg!!DnD%Fݗ@nu(3!Z(SLo}yC]-'"#=-iwdxI!cxKFYٛW ON/ !ep&fP'DJ +!UJ_; EbT9LjjAoʬk"7O*E,9l=Y<+%q2ۋ 3BX" Ap45* pLrgafREsLLw˓~xм3&OLk5l6ok>;XƯrf=zhNNNBB >q;"^} =ߵ;dW5!?i2046.-!z :R"R/hyji[Gg$7OIcukn8b='~B _V D5&LLz`_,!_{v BY6G96+zol!---3BȭwSXZ^-wY:ʚŕ'3'{y}PP(044ݥ( Z !/_|l.Ƿڄ{2!VVVί˿6juy~LyE5&TTT؍BUu? H$p8j8MZ---TG$ ٽ4='0pt<)3!^'ΟNY/ s\=oR+9Dl)4PQ[WX]D,v5Gϼ" *f:6FjU48.[ g*z _ Lu5 ieeezUs@֊ӓݥɒPSSSn*K3l"K0<)+Y6?CjKlKoRzy_29Td<5m㊱ n1y:HshsF\a( ?R2az|ծ~Ӂwi)QszX@7Q"bqAQANNNccctuu-(*r1Fn?IE=ysEy*Y2T_cF]c"Q]}cv.VW= ͌;o蘝K@ЬMMMB͌;"}3B>}oy:4 g|ň#d111 c}ѣǒ%Kjjjhy|^__`kkۯ_ݻwΝ6lx7tuuǎk.;v7ߔʨpqq)--A>}JJJXN߿^d9Er a &uUV9888883vշo_[[+V0--U#<ͪ}}%K<}T><;;3ssBBHvv !W^}׭RRR?T\эS'L|E5L1-`֭s1558qDsFFT{,ooׯ?Yȫg?6gh_4[f[S`&[6@'r݃ "$%%eeeeggFGG8g߿DD OHH())w޵kw}J:MKKtR^^ʕ+p333f;vMOO>|x\fffZZ}lRt.RZZm6WWW+((Ϗgݸqw-,,ܼysfYP[[{ȑC*_Է~>_|YGGҥKk׮;ߝ;w?TFR]6yde_*BnL['X111aaaBP lذ!!!yC(jYz<he{ cayT_7oބL***T{k˗/;88}'kkk;^pٙ3bNҲHSSmll_ pǏlr޹sG[[;887ޘ>}tÇ<+:eΑ#G&&&G pB޽ !SLyT˔)S߿rhl3"4Y ŋVW^=}#GfΜ9p͛7o„  :tH$*..E#FpE$$<h,O&Vh}" onhPbӧ+VCAA'!D,D"CcfddDEEݽ{~DŽ;::m'''E/++̘s% BɄΝ~:(EDѹ( &իHd04,Vd*S uuu))).\Pk׮uÇZ[[~BǷm۶}v==D//$+s#IR\niiܶQrLe:EڼysMMٳgȫg? ,&;%)@kT qvv>tPPPPuu5ǻw^IIIiiiyyyYYp%Kܿ,??_,3h^^͕{o{%x_uԨQ:5E(XYYI>v"N[|h%+AOOoVO[T===Ç2tȐ!۷/=ʰaN>k׮6=䍤dTĘ1cִZZZuuut[f*):ȫg?DkhndGӲhXJU@%IJ"@E{xx|~~~+W|P(|!p]]^~~~PP7<<燅<(((66ڵk ׮]۸qd : ::e}&E(:E-'""9}fWxx8ϧ3gl֡MMMdfUB]]ݱcǘ%;ܹsܸqzkΝŋ?zA$DfJQ&o$:ayXn]BB™3g^zO?5m|v][[[PP,m2mc͝;޽{sȷNYyhVGӲh9@WE]RչTQe…Ǐ 3f̴ilmm?>ݻwoTTԩSnj#cii9hР1cƌ;Vn!!!k׮ݵkW\=g\HkkaÆ >ΎY2z1c <1,J:00ޒ+={أ8a2y۷SʟСC?sM[iȑ#/^ذaCJVwTty<|pԩ111ݻwxMkK&% t]@#sWs@Et¸ *{Ns]R+Nawl,L\]Y*++ISm[Λ,j:tg,tR KoҲ&@ѵ{Nf7%")ǶwHW_۷Y: %PEPQo"պJei ]P_˟O{Y.H'M9mCr:W(CTTɓ'[t|˞:V[]@Pt|@T7j]4mzk M ઔDyiik[>ZbU 0ttPG޽A8FWR{? `^p[.{ټy0 H''{fzWOUUIR@:}q型)KX|@7 Z[[~޽[nMө;>k4a nByٳsrr|Ie˖eee={4\u*BJ_$r==SDynt %%%ݻvZzz:{Ղާ3v|-_lWg>読uss ~W..., Y\uȟ\竊,ԁ/u r=*](j!xƑ#<2ij=4IFFoggrmmmKKKixQQCU,.a>xQc><~xZZڸq^{/*_H)_ q[]n,tCŒȩ̌Og(d…K,~YYY~~X,f`rss6"r*SH%WxЅXhZH't%uuu:::zzzAAAL9sBCC_xKƳK+**2T2ePt.R,I|ƲE-oxx8&l[睢Xd޽QQQSN3f ڷo_OO!C0a"r*SH%WE"럖Y>cYn2<hXff@:pPCuHn,?`@jV':@:p貖+m:@:pPO?Vs\~=''-...PPj6ݖBdeuuбh˟ dddU;!Mzj@@___u=zw: VVVyyy΄\:/+5Q600p͚5Fb\Ku=蛗Эu4Fkh}=U" D@ 6H`7 !/~QCCly}}}%W[r'OBÇ,Y~t>(9sBCC_x˰08tPh|>,ZM<:t@8:7iӦegg糩q7l=pBh .36l""" ۷!C1뒃3 6)_eeeee>tP???\eΜ97n`3߸qcΜ96|fbb"nbbʷkP޿+Ͽqi _O!Ww^qqqzzԩS%ˢ|g67oɓO.[ٳgC u :Dm0l[?MLL;`.+kkkkkkh;wݻ7[|y]]  <ϯZ6[Z#&&&&&&t%ٙw!M]]ŋݻW2ξ} ̙ӣG+++oobbbb"zf>>G-,,4ŋ9s}3g/^H:99.H@&-Vp#F/}||]e,B?˗s8O>/wޭ!HaRݓ} u@ PG⒒?HIIZn}ë(tժUq[cwU:WL,N!Ջ +-<ҥKΖٟ)grϞ=Gӕ,GGÇ9sF[[{РAzŋ-ڸqMLLjIKKVOO1A^<u@ PJo*SRRp9qqq'f{`{{{GDD޽[,{{{3{C7|||hElҳgϜCfkjjͼ}9{l` ,33SjN@ PN kP?>dnnN dAzzzaՖ-[㉩}k-[1s=YE__'''7y't1ut)˟ijj&$$x}rՀj7Nh*ܞ5@Z)PZ8~~~+W|P(|%KK|~XX̙3ӧ[v't^uaQyUАDd3'M4i$&O2ªU@{ݻw/K= qNyT׈B˟WWWRv6@ t z r&@3駟6U)s;s۾]: ֵ~zNNŅլ: &71;\-ywyO'N%/FRE=Y@ .ow'gV2ݻ !*51t˕R* !třu ''g@ P> TmBgWGscoo|rVPue\o4 uhgDX,nVd ȗ߽{wK.U݁t+hsu`tw0@ghOĝի[JJ CBillӧO=,YRSS#EHHAׯZ!((^*>3/"##]\\[QQRZZӧOII Tn :0p8f779#wu@ ]U 6 ?Vؾ1ߝ;w$wݻΝKIJJJKKՍʭt۶mo\\\AAAfffFFF~~~||blٲiiiYYYϞ=3331cƱcÇ[ZZe@n@p * ?:@Xldp^gSKz-|>>99Y6­[N>D9q͛mmmkۇgϞݼyubb3g#55511l̈́˗Bŋg͚V ԡ"uhϩb&P S1 u@ H&i1JKK۷t~A /%7QQ笆c*U\o-Ǐ߶m$]655UWWRPP@}"Џ,$_ʽ|իEEELLǹs|||_N_B) @hL@GC,f6G6mÇ !g[lykFyի;@[o?~ښfTUU5k֬nk֬ib9#7|nݺ?v}tg:_Y@ZI}}}HHȹs!މ~r {-,,,))~ȤrIII;w,,,0`}\]]ӌ~4P~++&LgSٳ'j 66655U([n޼y7o޴{b\$IH(--1cFpp1c!iii8}tcccBBɓ've``@Om͚5ϟ722 ͓9Gg|Y viBիW$-z??[уx+W*yt++XjUqqqqq{iAAATTڰaͽ{rF ļz*==֭[MޮuyP ,S333$*eg>$OKKtR^^utOo3{lGDD(SfΦnMeOCACCÆ bqRRҝ;w$ %%%YYY׮]# G{~>`7 !/~QCCۓ`__ߑ#G2!~~~+W|P(|!Y('""燅(9gΜ/^|2,,: ::w -ZJ@G?rȮ]퍍l"9k׮ez-}}}+W0񓓓y|СCƍsrrD'O100i&gϞr2kK=WD?]LL%w:u*88XR2AAAcƌ6mG}gimm=lذÇٱ ۷!CѣGEyFJE~IhP(ۿKHH۷?իpvv.**R@ ۡ~bXΈr̙x}}ݻwO6vMC$RLExH|fInnnN7YIu] [fS$fd2iҤ[ԤҐqIJٓn;881HrowώLfXzի- !ɲy̆͛eogϞE¹uVFFH;>bCC+G7nܰW2s__۷O8իW̮O)gOz*:VuҥKsrrBAaP[[Kb WZ5o<%4wܠ >OueΜ9ߧoxCHw2(?țܬSSS%ttt󃂂T} *M-G4$==w!,Xɓ$ӧOGFF_Kŋr#Cuvv} ЭT8vaܹBY;600׿% ǎ[nф |M]cǎ4hP^lllbbb7+9!$00b>ۻwoTTԩSr*=UϦVf ظ8X0rș3g:;;XߧI֮]knn>bĈPS^^^RR燪@!vca=Ge2pw}W /FB=͝Q_ˮ u@ H`_'o2h#GxbÆ -!%%e/_WSNU2rccsZySGP ]"_f ԩS˖-CUHrMɯ PRp7I7:?mE (MtgQ&./{O5+tvu䠝Dkb .uϦO7uh55|ZIO3m?qOv;."Phg:@ e(22~b+h4cUqT7khBۏSV]YsQe=qUMbbG=چyΛ7o!!!Vumڊ?M z_:b© :Veeim}5"rI̓g% u盿jXMj[{c0KB***9yf߉vrrիWlllͻhr=RGKU\oSSSIAmmv @ TZرc峣իWJF]\\TZم#e88/|SN  !B e MJDǿ]OSSS SY|vɓ'x<7%%yX,?',XξMsǞZ%s^(IVV֐!C R>}zRx6Qu@ * I9vqqU@gaVWp!{:ѫL,oBb_zǿ07ʭvժUϟ722ZredddUU!qƍǏ>>۶m#ڵKGG'99ѣGڇ0a !4gz\##={ݾ}‚"铑aii7˗O/6lؐnݷoἽi?߿?Jj4 :Š  >ƿ-jǟ\}!#NįT/aQ`V?|Z:F򏋋X,^|9m۶۷oOk׮ݰaCRR!$66޽{bxɒ%7nLHHI=zt̙%K,\ÇgΜ _eXUUeddDm~~bڵ|Ihh(!$--mĈjkB777Ç<?|=9K!Co-NNY|?(7lؐ’ZCgee5O um\$܈SR)L^딿h%$3W˞gb!DSK"gΜٲe-[?D[[[CC3---o_0k̚5~{RgDIHH077+V8vXCCX,gϞ>Vo^ ٷħVSxC?w,9:Ǩ&:_Y@ @@8E"QCf~>FS;::m'''&bXGGGr=CY˟mg666^vSg_>744U YKShnr//Ǐ| q$DKz9X[[mfbccᅲWTTTVV2k[[[\kkk%(CvVZo߾7otA޽{߹sy$߿?{rw4hP3߿? 00099=RGGZ;*۷V[lllA_|G7ׯ_~6mRׅ6m:|2.u8s}<%3Va``oY]]|*/U+V[njoΜ9YnѢEO>9r$!??>{rE={veC 3lݺ522uLHH:s挢rssGH$jYºFFF˖-۸q#}ollܲe˩S{;vBׯ__BNi&]]]Bݫu}ikkٳgܸq2fƍ(**255~9!D  2$==zh+e˖1?0[[,O~!væ͚5kժUG&:tɓʡ@ʰyv3lmـ@V+WTΞ=[Ȼw&‘2g~XhaC컺EZ8ZZZYØV6jK130058pBHvvvJJ pV^zj&''K~.N˙n+p͚5k֬cʞr,Y~#GݸqƍL(~hhe˚$G惡n7utV?11"##C,Kw޽zqDDD\\ڼysaa?LܲeKtt4Mܹsyݾ}111? țwܹzyDDi_>lذ67l߿/9ѣm77G'g?dȐ)VrX,=|psshi_xu: n" mu3`0$Y|y}}L (_ |V8z;+o0`!/]Gϊ^FN㽲  6xyy՝PYYyA:ңyy9SMg"+g}֚@󏉉 ϟ;w 7noiS>=zS_~%u\0c ƶYfOpp0n: e#Mb mmoZk[^|ij SS&17yA 0ѣ"7tvvnn@ F }Z|dUG !\=i}˿VrMu !/_?/t,3:::*eȑ555^xx kjj&&&P;jh?]?**J2dTb-lB Ǐ4s|GGGXRR$|0n3vcc#{0ݿ+oo~Yf 5߮#Is|]ȍ/e2579{キu֚Ԗmـ?ЦjVp䞯}߬~[VTV&{363hjjŋ/^ܞ$V$`~"yKJaee_mfbmm/^0yyyVVVJPQ>|֭[#GSۖJޯ_w{׏=9K^{:|?e9@6UWW)mb166nnL!DSSӜkPi\ymKO;PS˿IMUVVVZZ|LYp5k>}* =zĬ5}Ғ 6L>]*NJR < >>^E3ۗ/_fnٲؼyYhe';wwiqrʵkf͚p@[sN`ۨnɕ{՝ٚ|coob#+wO}VgeV.ˠjut{du 6?@9oQQQ~ BHXXGE2e2Fglٲw}Z˗#9f3fLpp0zyyycǎ%̟?_?ʕ+-Kΰcǎ0Zlyfi.~~~G ;vE1 $'Jm;pԨQ[lqqqQ2{zZ$y(iQjrs;<=zh꽬Y9@ˍ77n߿Í5U:mʪ>$$ܹsooD:&$$ݻ:rIII;w,,,0`}\]]irKק BOO+3"$$dϞ= M Ʀ u͛7͛tY\@0p߷R_I(--1cFpp1c!iii8}tcccBBɓ'vx]f獌HPn%ww;vzp)eƮ@__ )|ݺu Z]O>̙3mk6_ш"RRRZMN: e,^x&8秥OKZ5tJIkD@҉lu3`̘\\\AAAffX,g_LKKtʼ9q/ž<--ҥK\.wϞ=+WɷEg޺u#GAbbbDDġC,sii]]]<)l4CCD333f;v魜X.uއb8::zŊ}X,ްañcbqRRҝ;w{𘘘DBHBBBIIIVVH$Zbi?$G8#F)zvݝV8Xu߬QMBgmmĉCBBDlll4557mԶof?U5jTXX.ٳ7nHJJJKK311 ޶mUz);K*ȶQ+Ӎ+*ٳg/\@^%&&N27m$i3ܺuK$500ѝ?3Ӌލ, F莥 R~Wvvvp^^^V־xbkV}/&yX 8|H$7nH$:yӧi9n8ZgϞ?u||w}1bkkkLn%#Fj~x:&177:ucdǏO<ĉ-!$::7`,EV lNdۨm1|>ɉnKҷ+U%_vmjj*J%95 !BPn222޽[SSCir"7t,eIqtt8w%j{"]wҤIoWRXX8n8"(SOtfj<"Ip@0@;=˪s(C@@ɓ8'|B$ <==%٭&턮gt"F .3*//ٙ>uo֭=zhArY.\7a*ɥ:Tq </77Wj5k88855feE ۷k]]k.BŋZebZ[[ՋZ mKc)rMP1OTMMMUs'u@ Y8999sFGG͍<ʕ+t̿ȵ҉lu3`ХODDĞ={bqXXK`__ߑ#G,9ѲC?<E!&TF*OժE!XEEv$*E*UV Eъʢ HH~o&!%aG^3w93O2gνVڵKڧ:uZdddSv~OmPRR2aXccgϞ߿!rʈ={x<O*Luup924ץK/^,֭[қ G$۠D.ضm ~GQT$oСCz#ȑoC6߄.i4Zppiw.'N8WZ`p_;v9sFBx<oo V!Nߋ+**"Gr͚5l6 1cǵkz%/ %V"yN'IslZKKk666o+V044ܼyex#!!!ƍ2e).LOO˗/M6mFFF}a,J7|Umo񼼼lmm׬Y3zm۶}嗸I``Ό3Ҿwޕ gVCNԪT @O!KbJ"t4e6 JJJϟ?///ߺu+/_^S/^\O?_%Օ͛7/^HTPRRڽ{wii{l"N +&:\pUQQq۷oBo~@zbJvWIMMxzWoCb?۠Coc\}ݻw-[t)ߑҾ7{_zE d;;wĝ;wL&2f#:HCT@W߆l WP(A%%%|Yt6ۿpB B: r)*r@]M'@ga/GGӧOpWZcb5""bժUp &/3lHW'FnÕ6q :\߾}'O^v_y}=xV:|M@PH{f?yVV= knn~& 0οoڴ=!!A]%ѣGcbbȱt:ې́q?vvv#a***[ennO~[ww'OΝ;W[[M.kkk<}FB߆l aHQ̿S[iEݫ7<PObe%ky|:z̘12{yxx= vDSS^Ԕ<@ ߆l@]8y-/LZ&)唪*]0C4{;(JALfXX(ߥKzضOabcc̙#/7FSS^~&x@@6+r!ogYm[ir.T~oz˚Ƅ\Ttĉ3'wP .2>H$իn_SÇ777}r!KKK&޽kii  P@ޅ#57 CC?7E|\xc :'Ş*yf'v)Ŀ޼yseeew 7z{M1_%bhÇ<;v`X\\\h4Ūwuuـ?Ȼp}Ԝk,y[x8Ϫ[>j3^cR9͇'ɓOiR=lP ߿LJwUPP|ٳg555cbb[:oXccѣG-,,w}W[[{e"p"xa߾}gϞUWWOKKZtiNN'B?j}KGKN:/y/_!媪*ëF_iӦH###kkkA`0_^nBh=8q"JIJJ211)++o:ZzuXXXzz:#:G (JA`֬Y?Evv6α$I1G IDAT 6dgg%@[Td|Q Jxy HA7 mfjjCt:}DuօGFF?|{ifٲeqqq </&&fٲe]v%$$FDDC INNƓ&$%%hA!tӧVXfǏ+O4ISSs۶mW^u4L{Җ3:@ HQ B]Io'RE7۷o4bU% ^w-cu7˺v&uZÄ zzzVVV3&%%!N8Bٳg ...555ƍ G-Y߿#7>>~ҥ<ۛ7ܹF%vvvݮ۷o.DEE%=====vO*cv:[O2EmIyy3 kzQcdcAT? \8w\WW׮۽~D]]}̙ fs +躶6V~QzbU{$2[<ݡۙrÛB >q>}`pK.]Tٳg'?[nݺu¨YD'Ae &sn?o"yLsu%;W岉vZr K 'Ooٝqv?{!d@ GAu5]NJ?j) US؎K"##>}RRRݻee;w&qqq7n@=b;BC}ȆEF땖~fV8Q_s6,>HOYYYn?/x`ܓX,WWW333}}}/dy<^pp0B Seb"Y|9=ztҥ񆆆 $66KHrrrq͛7̙sE)UQQQff&.͍>|^bbӧ%ȑ#x;99x4 <9|333.{}}}555/P(]]]QZkkk!/̠A(ښ3&9gy즙ijj]'2' "KՋ/^۵kEll,dh:@ l C771cUVVرOLZ233 =zׯ>|Xx}rGyyy:t:t f6l|bq1Ԙ 2/ȈBňիWgΜ!z{5jT}}6؜={|2?~wpp>x𠳳3.a700׷嵵#G&&&7_@MTsǎT={رSvv۷ Faa'P:@ @h0xfwO7ʲӛ7o,<.K#tttTTTΝ"Z[.<`[ȁ!᳐G9rDnUd@_333kkӧOVVVG_~ݥ}1Bpƍ6mzׯE >/WTTon߾=sL>qx%zzzL&իWl6b啕x)7`!6- $ ȄӧO[[[ãH3<&9m4}}<{{֖NjfT*Ԕ$-'l:4$$$22299Y1(Z]]=11(> /lII <7}.5g%a0_61LK. ۶mUQQIHH%T*'))ĤoDKKT8UsHHHZZz|||PWWMMMHgB<26,r<3 ]43BhȐ!GUL&N߿w? -- !T[[J$r<`"fKx":t(BR~ud@b .***n߾}uRت !@RTSRQQIMMœ؉/˗/W^-/^qO?e///cpݻwލ l[1Q8?W1>ܾ}[^'uu>'* Ћd6/ZhѢEt4`[A$((($''w))`= kJ uE _v1x"SyAAANxrlL{{;^9#CCC^ a+oͳp R,yyy.}]]@ź:b+.'#a***[ennOKG5@u`555Ԇ555 /m_ bB,K E9p<%ϟz rN4fwzK$瞴%-R}"2uZSpe_hkkwHK.ڒǞx3gΔҥYxے[nI:\v@@|uAʅ!s)ggglmmussSWWONNƅxlfffӦM{A_G9rT1u@ `Z+ޓX,WWW333}}}/drpXȩp?1bfffcƌ|2mT*m.^8vXSSSuuu#^/cW^-((x͊+6m/O>h>m̘1EEE;v8t.7o\^p< ׯ/[n͙3!t ,ooo9~xSSӒ%Kݫ&ܪ-***''yyyfee EGq\[[ۖ5##C.nli#AAAAYY/c} T^fMXXؽ{G9lذofGG- pgECCiСkjjŀVVVfnnN~<::bݽ{yxxoi޽`0qξu ŋ %--իk&%%>|-111<<<33#S'OOR S򔔔b1tАdV ?f0ꉉDYtd֭[BR!?oC*rrr֮]+a{"W1>6lٳϟ?~@@ݰajG}hiid2񟙘@<B2 ]vA8ҞW_{ll,OpΝ'O8))):::!ooo"#7o x8vX\\ŋ[ZZ.\/&٧N244DEFFΙ3G1999?B(>>(,00_ ޯgkk+jkk$cǎd9cu6l}ݻw)eeex<___\[[ӧb7:...4-77ㅇEB1x ɃͬYdh lC6* 6dggKLBQqž:333۪3!JR \7FGGCmjj211N騋| pe_KJtKo ˟t9]2I<LKKݻwߢjVVǏkjjߺ4n<&1!!Aq@x :TPd&Ecxxx}}}]]]hhW^sRZZJ(++VUUo644ٳgҤI")Jy9y 1ˌ@+gg琐o߆v2Z[[}Qxx'NMW#,X@8t:xg=66tԩ1>={+ 7o޼l2BBBƍggg7el%aƌև :$lGvW[^tOCHQy L^>J"_@u uuukJ,0ȟDEE%55555U|*.5G*J`ТE-Z$\.O۷o߾}VJJJĜEG?B~pss%YYY˵pzWt}hFCCk׮xjxƞwu}_z_9rIPwB,"*<|Vi[ob@/#YYY\.*V___???". kkkSDDDLL KIIw^^^ޓ'Ow܉߸qu@}]Q nݒ)ZZZsOڒwFP+ WUUvo&^6{씔uu?s޽}̂GxUV>|H&=_[|~ ޴미QbbW_}7 7sɓ'Ϟ=+yJJ E;99Yo޼TUUí$9 555[[NOA!xzz.YWIINNNK`jkk񏹥 6/77ܹscbbr IDAT^ڥ.czzzjkk 5j4L)..2eےr)]g@ ;:@ ?FT*uQQQǏojjZd޽{P\\\zz:noo'OPOpB;v`0.##CLfEEEΝSUUE͝;wܹ' {cbbn%~Kl vȑxz8οZkjjBo96zo߾ū޽uwwOII)..f0***D[pwJK-'O_YY)(&pDn"n%<$˨())!+>}:1Tz#0}8>|8^QQ!/BJ&%%7]m.ƍ7mѣׯ_WUUu܆#FTTTz{{8p3gį3.Ioo>\d2_zU]]fY,Q^YY=OfyO"ϿOu@,_|xѥKfggjhhDFF/De򓓓hddMD6n޼9gUUUMMp=#;ŋ}7B$1SCC!Cx{{?x@zICC/kjj^ڞ{ɀq@NpBCCT_zm#JKKՖeeeUUժ*???isHHHuu۷oCCCqԩS"##{I~z6l믿JJJ\?}cdʕuuu4 u1_GA?QM!tAD.]奠p!>>gΜ)t;;;ϕߪYfN5kְl ___600044tƌ׮]3L"wɬ/&`fffmm}ieee++ѣGcwˆ'hnn_q/bСMMMiŠGE:"+"͓%L&?K/F o޼9vTqЏ#<(QQQIMM3ƉiB֥?M,1ebAII)>>^x0˗/W^iN=gY/^K~'wV[[[[[[Ed!*())޽{ݸp˖-]%yY{̢8 V7֮],,,,,,bcc>@Sg۶mKOO&|||?p{l&ƚN::t#7[Hdɖ-[fϞ=qDKKy湻Kp3P(Gy'wA{{{ll֭[Nlii5jԤI=zzȑ .|J__8uThh#΀$… /_9E۷?x𠶶6??\d@@˗/;[Bb**܊E]pfWUURvtDf i^G]FBrr2n !!=?{?X__O2!\ѥw2D5SSS߿ʕ*++GGG THLL| ɼv͛77ݸq fyPӧ'OVVVO>ߝF[V9?$Qĉ?#oF $8wٳgKv߉Mɸ={z|A]]/Dc1u@@̽TWW'0u]]U61s&)\nmm=c > ss, <477K>=m^^^fؕoϿ;/f$\6ᅫfQ9r$^&0ĨKiL<[̯!BD˜?nۅ7Wp~̵yyyJEEErYezSrΟ?">|/L/^ű>>  ߫W xDRG[X,ŋ{r>s܂&$VA(_ZV=sիW5kɒ%BBB:mڴy͘1CIIInݺhѢg/wqq;wy>u;u@@'OaaaUUIUUUaas7֋1s771cUVVرR~OмyU< d%N(**tTaȐ!۷oB,;;[>U?????۬@t:ܲR&-qwwOz*:xਨǏ755-Yd޽jjj! ftڢrrr8NPPB edd$b䧨ܹssΝ;8 {cbbn%>JGG­Db0/^P(iii>>>W^7Sb #'Ra?䗤x2jήypwP p*&G2dHVVV~j.utt/_{Z=ztҥ٧N244V̙CxCNN?ldd":ܼy/[YYñc/^Ҳp莆#N/tttB"vτ w777777uP1Zt¡CΞ=bX.Q 555x>~L&NǏBSc``MIIquu% o;5 >ѬHL~YD5WVVVG˗q1B`Tƍ⋡C655H+===:.Qy\IiT @np%''gڵV޻w/7\˥a,Հo ]r۶m*** J$%%}"kii;V9$$$--M]]=>>ﶥEYYYUUj׮]Mrrr񱶶njj:pIQD'=_ȖCd|D@^ Wo߾}vjv@@KbR||<<J"}E-ZH#7[Hv%Ҫ:?&++ ~ @zn6ٜ.$w"yLt@rAWCp3f̰rpzBtv  R}󗼲|T9@6 t t#= nH~w&)aekk>]T? \8w\WWWIm$ɫϜ93!!AhC/"`J~(6 ? HfI~v:@ pUÕ1?d2$?fYXXXUU?3EUUUaaaf]ﭡa|xHtx=޳__(** {ZWJ-8?I}rPB脅u_v 4{n?.zswwp8@R5vXM6}oP(}ٰa;> B#h4Yzz:.\~c]]$V___???ssbkGsjH6<:S(.r7nk׮999qܶ6 Whnn4447n\jj*Lf($$|֭71W[6&=z>ܽrLP"#Gq-9Ùa2Wsss߾}W߽{R\\`0JKKUTT"##&we08j(fOHHx1(..~%.\vGYYYii%!99FGGXw2̪ ؠjժ,5??_Ư)K"##>}RRRݻee;w&qqq7nܐ5SG6B~}ۿ9oAAA wرyfwXkoohnjjZb 6,"""99x{{:u !w^UUUDܶcǎq877q=~xذaxQIIå}%I-ڱcBW\~׎NԩSM=zhLLB(66N) ϗ ?Ћz8 3˳ҥKuuuO:ehh3g+~999?Bu͛xAUU5<\PPc2EEEZZZ>>>!!![}}w}G(-<~Kl6.9r$^ƙz8οrkjjz5fΝނ$ ^zUSScbbrA 7olee5zh_|#***mܸ1::/:thSSZA>|xee%6BLdE &&&3gTQQ/< Ҹ$33ãe߾}ROO#M==QFKz#?gٝZKr\.Op^)ӧ^:}ts l:y$w_z5y4H__wv._<~xuVBh̘1`XDM5^~TNsx޽T*ttl6!$p9FSS^~f'@8l۶m߾}޸J<|BT;0==}ǎnnnFFF>>>gΜ醩4-88xڴi+WI(lsPPЬYNOII VTTDEEEEGG^^^5kְl ___600044tƌ׮]y_oc~>/$ =z'.οcg/o8NIIIYʝ"___ggjnܸ˗o޼%~&CBBڙY$W^mhhpuuݺu{/1n:???4tu*2ŅFXpbsW˩@i%3Ї\p8)*n߾˗/~@@˗/BbAII)>>[nŅEEEuuuT*U?" B***UUUUUUD} m@|r2Y ^\O?_%͛/^$*())޽޽{[lgbcV[[[SY wv_gƏO@9rȑ#-??ՖΖnk֬(7&B(222((h<N偁۶m;w/]bbb ڳgOPPŋ;:[jjj^xݲe˳g&N{>iu@@ HW]]  ݻ%O1.\pBbҥK".dڵk׮yEEE]oKUU©шĂw}LSUU~z6( Jϟ3^vtYYYAAA$iu@@ H 2hР$aÆ9BٳgϨQ,,,Ο?gϞѣG[XXC 46@n<jGhh/.\p=Mwu!RRR FiiJdd ŋ+++,Y ?~`0_|IT{.ڒyڇh4i(l ΀ }$@=j}}}tʐ!CX,V]]qjjp;w~H,Hc$D,fŗtu2vBlm@TdPPPPVV&P=ߪ&&&.YD QQQAX,Oq\8^133( ^̀OL6ɓ+Wxyy{T*5))p/_lhhU3FQQQann.Nw޽ANoIzì~րcǎ;600gffN6`'bK|D''B\!kiiiffuV"GԧO|}}G5iҤ/$5٫/"G?}ӧO\.o_z-QBR}||?p>f߼yŋ Ħ{]rիWD oRRR785ikkڵkB(55W\y𡲲rtt4d2 #@ S,Ya##;w~N8ϟo+V044ܼye$>>~~~1fffO>}YCC"yw 0h f͚eff@l_)!mooOR g(oYYYfffϯ===4&==H|ɓ'9_ P(ɶt:=???99ΎNӯd  e\۰aŽ9TMϟ3#O\nDDħ~*&ۗ/_ov DǕ+W?Q/\ݻoucbbƎѣ -[w 0h|||ݻh"6,'999ׯ_G%%%UTTGEE%&&XTTty o߾BP||ݻweeeEEEx-›Μ9_xzz޾}̙3Qimm CBBWklllzzzCCCss3 Z[[dOJJJNNnhhxI&Xb _TTp\\\8 f4ٳy͛7teռwǏpssKKK̅(>>w&s\]n>lϞ==== L&â:uԸ8///eB%Oh n___8 s/?P1D"FKKk޽{ #IvQٳDٳgϞ1bD@@@@@`RSS|???Q:@P\\,I!1_kkk'$$=0mvI 45|DG&:lmm%y۹&&$Xn.P}!֯_O841",I'agop[Uf ʰ@e?BhƍAAA{6W[npvv&bcmm]]]_K?޷o^\\\||`A>Ќ>C_ѣ3/SSӺ:Upmmxłk.Ⱥuvttt,22RP IG$}?Ua W:04vZ++;v:tܭ[g0sqww/> %88rqq6mQ]@3+V`2l6;$$dŊb v (;8֮'|bժU{wwwKKKrr)Sh{1ùw\ٳg/^ h3:::fdd}PtPF` e˖W.XG̭!4bĈ-[TVV655]|yҥhPCC#..555`_~ $#a``'O? ̦O>c +++&)&`ڀ#n1c,]tΜ9nܸ1&&fܸq?b1Qm|$ûxȑsrB fMMk|!H/ZhѢEġ #>?P0L=tr>^~bBG}6l1YYY K}d/pBUN_.vx K@+֭[ _锿F ?a`: @/C`___UV"́1D"A#rׯu(Qu.,,/B1;Pa"* WWvae00A&TWWh4h4h7P:垞;v쨭!"kkk\=U-P52g̙zPNQsQfM!+` ӧ!@)jjkk>>>zzz!ٳ^"ĸbOOOHHȱc8NDD֭[\?ð{!TPPrܹps#ɼqXJi2Np8Iү]6''G d ^Gwjĉmmmŋ'N󋍍----//ollU()))//p8!%ԡ;n߾]^^z5ZBBW_}߄mۖu.l6֭[:af` c Z>TWW~EB Aedd,[$333??̘1S߿gٻwb;VXX8vX ]Lwygʔ)B%77ҥKT:Fפ/_$JhC  D P7iddDtY >@a5/꓏[~7==='===~ԩSG5rH &"=J,Nޯ;BpӕҼpsihhayVqvv&ԋ0XrZVʿac_QMQ|9;;~LRkkk9Noo!PǏIlݺu۶m{!*#\TjMM Um0Qy1@EK[ٶm޽{mۆc|||UWWs8իW hddt}u?y򤭭‘ӏEe7o'\V^`0lvSSQIƍ7nP!Q 2x`!=^Ë)P?ԹY%TV+Ŭd8;;ihh^CBB͛CWWeD"GGGAqoO:Ύ0vܹ{#G9299yb%::tܸqSLY`,bSN" kZm\Bd:m@*P!Q"(CCA,M^e)*U"o#""TU3g177C*z&M*--;GpD}0e[[۱cǠ sFFF---0=zҥK B(;;?666˳DEEE͝;P1115|y86RVNj(IK^fϞ]VVo޼%N͙3K|\lPPB=zthh(\>K7 y}OOO1^^^?p83+>&?{ŋt.MMMmmz@ V߻[ZZL"W/GGnj >##C~c)j/A| Cxxxpeee[[[ee%>㚚b*ElvEEIg?` IDATnhh?y$H5Q%z&Th~ oXF5}`)y xdܹNx.`` `xF vyƍ5k`_XXhgg7vXı͕W\|2>^B{}չIPɽ3f̐1@9?++/++ d?+ hhhPp䔔\|ի`jXB B.T1\ɓ@?//oʕ|)833x1e&%%YZZGGG>vd5vJggg7otww?A-]4&&FKK !daas΃666>}¢olATv XCCCٳf}0O>|GGGWVVZYYYYY߽{_ݳg_ʦ&bx2K__!N&n!YYYa򸸸k׮q/2>>>** u͂Om޸qC|v)ԩSqp`` +'A0#""...3g466Kinn^WW0UL&MTZZ`PYY٤Ib;v Z %jgϞݵkill?@|c^aCPZZzԩD٥oR{Wre|ܹs߰Wdl6wg/ۆIgxx8z\~=\/p^KØa5/S0=RdBްlb۸q㚛4x"`9ǎ]J:;;7޵p z`` ` *F+))2!** /W$}AAFv`̙Yf뻹 & ݺu)Sd_~YXX`oӦM=8q"oܸlAWҏjSSzCF]]o޼ٴiSLL JDAoݺgUVV«Ɂ:::/Whzzzuuu8l``~Ky--t|HL L/pHD >,G!Hp˪'`` 0hx =_?W0 XrcJܥ|bQT3 chEEŐi?O>0aW?P<0*Xل~SBs( @9`_|Y/yTp%KWi~guAqqquu5LhhBJJJt:4r풤/((.p{g̙/pBUN_.vx Kxe4ׯ%4-- !_9%''BdeeI`ȑߢ%/8~66Rurr={64L999Gk׮Q Hȷ4m`0@"\ `T$QQ[[`Jh. 1P:_bdd?_<r@+U <|UWZuaIJ Hb| P(G ollL|ell<@IF5===\R[[Y[[{OO(q>\\\|Ν۷o_t)33] *( 4RAh{SSSLMMa?(WoJJ odjjFhhի;;;$)%%zԨQx D"D'00ԔB$%%ɼqwMR---cbb= Z N-&H?K0BQ"ٱoĉ;v+_xqĉ۷oƖ߿g))))//711bFĎ;n߾]^^-Ʃrtt3fTUUVurUaELNr˗/K0/IJWrMuu5F<=FQrccc 222-[fbb?fP||ԩS mw^,lpر±c"FMeBGG>vw 0@Jz{{w}774]]]B⿫k˖-?#L޼ysTT)o7&MSbr B(&&&22 oo)V%.NNN P_0}ZZB?/ҏjKu{/00D"ON:5 bɯq;:: Bd2] "ਨD111mmm\.ߟS(}]Sd"axQ''ٳgCS:pzzz$Ivڜ5QGii)$ w߅vn+G5E}agg윛;IPT*իxTsPǏ[rjI&.X!TVV6i$  Qsrr,--BQQQsSgΜsXbccy]c&%%=!ϗk@InxNH)̆| p{({"@9dl۶_Vjj*׿o> f422>N_nff~TT.wٳxzz9s2̍7½;:m` ` , b N]455Y[[0`ُp8LN,h722jkkSݧ`ٯՙիWQA9;;q8bYHHD?ٳI&1LQѱ}SrHWxӦM=8q"Q7:@)177pi}}-B^u) aʶcǎA xE.~:Bh̙b h=AvfApW1"44͛77o\b'loo'"FJJJKK `^Qa !HCnuRcs=Az˗/ kiiinnսŋÇT<9b={d_@p8%^,.ޯl82TtT A"&L d2ɓ'd??B)0TC \Ca|_666*pB3g$v !]onRrYL0VG[ n$lPJfP-:@E3bĈ-[lٲETC:t!ãG -8 k(<9EFUA Adr$iӦM0{KNb =WG~|k0HWWڤ;tjblw_Z@X !!!!===nnn N,W東L@,ZV@...s]|yff@&_<οэ-5;a$Yw$B[||rco 7:P!:@;;;O>L&A(lol.Wh{{{*+OlkiiIxrpp033?~UUBbS(ٻwR111Ĥ@V+jn8Y&& f5Ӈn=~uI cv=kWY^wJ^@wUIeU[.eccckk=Pԁ8chh(Uh j`` "aFwLX,W"ਨ(5)111mmm\.ߟS(}bUU#Ϙ1w"2TJ ˗PTX=<7nQ]=ܮBeB Bu}]F9rd UZeRۣG^vƍ\.wڵ999 .a5̔?HTTTL6 Θ93ŋeXX(RX,*baGQ999yyyx˨s)3g盘 bccy%%%=!/}}}&*cZ#aրl%VW (iwwy򪻗!" #_lAhC.\d2TmۼB7qܹ3;;?޿oSRRX,ĉ:4ydPOOOdddnn. q cX/^U;RRR455SSS߿ d >)C qĉpܓ˧ۗ-[uVХK8pԩ Z:BO>uz#zO4n^AzMMM8L0X#ttt8ΠՑBL&.CV7n@9;; +O{F):v tvz^W|cMޫi#.^)!!+B@vvkBm""" tүJPRSS7o\TTsK$.--߱1755ݿ֭wӧCCCKJJg ѐRcݻ;/Kc??K.q܈A(QM`h&z`{SՕSVZ/\bjjZ__gZˣ&M*--]`BlҤIpː S;vLCLVؿ[h}旜=#/_QOѧjެE#Gi2O>mll;v}Dr;vilwѳfڻw/_Tܹsssϝ;gee""qѣCBBtuuWZyf"oFö 7aĉ}}} ,?~@KRya`_$FaU˒\W@@Ǐ9ν{],_<,,d[ÇTOOp3&~zey-]d?A__ߛޑ-f/qȰ6k]'Կqɹtܹs~~ Gٳ[~p֬YFFFǏg|B nhh7nO#͉C1q\MMM0v(>(zzz7Qpq-;;СC?WcuAJJJt:4L|rAAFvA"&Lȗd2ɓ'd??B۴iӣG&N7n"[})֖/JZ]@TS4Ez6XrШ=P[ӧL|ݽaÆDbrůEmm4.L0͛/&LLs͛7wuu߿%C+++KKKycB(¢A~k׮!& O%`` 9xtNN4ё|2F×@(rep"fĈ[lٲe::::tBÇ [2@HDi|2Q rxaBHTX “cM#FPIKXM|L~ yyy!!!|X VZuU|~K 0TeX,o흝ON&ࢫ'^$l6߷l6Vy/*e{zZ4/.*溦7삖/;.M˾׍1\;lٲ6}GO^\.DڲeKeeeSS˗,Y›7w8jԨǏMo’d= | ߷XO"vY[[[[[%82??ɒ%8'%)Pa_n߾ѣG?cEEW j*Pjj[ n߾k.\O?=x`ѢE[nő_{ JJJ>}J$yfAApԩSq| 9NOOOttΝ;Z0lY~'O222ڀT466񍍍CS9eTYd;ŭn|C%=k~ϖpw>j1vw( f&x)--=uT* ,K7KNNƑyyyeǎ.=T1eʔ~o?@KO %GI+OҳX,*b9l1}_'tXR4 ZO8[wlZedE5v[dɗ1333)))99Y[[;&&fż644;v oYЀw>?pSSӸqVKީL&#;U,^xϞ=^:yJMu reG=}T0Rxb1~k"PtuuG PQ^ bS0cB6o޼ٴiSLL iDcffVWW7~xiWnž*++nua @ٔ?Xʏ2,W7%3rYyᄪyAOOO__߳l˗/#nݺs}___ j*&b^x.4±4aolllhh+yrWZnݺ۷o߽{w%J:@@z'12Tr1==]h|y-ZaÆ:WȩSN:I$Gcc#N'v;wb眢vtӳn޼yk,yٻwoHHv7sΝ;w8qb@%JX(4fW)(+++..Iɭ$n"pppݙ\eQE-1bD@@@@@YC ]v9$Kob’C""##V}rY"<{ٳg5G`` ` W IDATB:VrEGG'++K4 _a޽{_1J2v gχ hG]~=4 =*MX?8& PN}]H)#np1QMP+:GBS2A}6%A6?H5@ـ0J0ByRQQ:@=v 󯩩IʩdZXH`̙3Q_~e…ϫ\~]N qEe2xh4d `)_~eHQ"0 `LZT$i@jɋ&X]` vQh@=zFA;*vcSLtrrBy¢QCC!TRR]YYI"Ŀ@$iӦM 0Q`IM7@x/_zDZ)//ommy&>Yz5Rʙ{...s]|yff7ܾXxz UB|iӦM6 j(Ōj~3gLJJ5jyU'''WRRx-}||dr`` .%OB>ٳg'O>zl';;{T*! FBꫯħIMMFz [occ3~ . ~w//W"Ο?ooo?n8l6֭[zo]kaaaqqq[[<$GUU#Ϙ1 ]  j>" p$iF~QGk֬裏nܸqs"?f.]255EtQeXr?|1cƌ;=<|8a&߽{ɓ'UV%''oڴ䢢չȘbs(Q&kꨝoի׮]}vm{q FVV??~HKK0B/MT(rTT ZZ/,۟PV0$JOdXd677쐐+Vɓ'~b!qy󦯯Gzyy<~ܻwO퍻455 ?{ŋ!!!De~~Ǔ%<˗477 WQ/q@K"G5@:0~\%HCxxg̘aeeE|kkkWWW.^(:@@ ìaFl޼KVss . tuvtttah|?b2$gW__|I0jSG3 {{Qu҈(7` OdhTTT@C0Pu0 ` AAAӧOG}駼~ysss?x㷦ޞ/Drwwohh0aB``$?a++8>88822Ņf~?2d2ɓ'd??~LZUԩȰB{;ɊJ|Ti:pxV0 `  0Nf^lٲec@Quüh" f^~H0ciCb<پX u,x]%a%;`pw?HTzT¢'~U20,n++*:󷰰7f dQ/jΝt:N)u _~ON&a6m/珜6^ %99֖N'''~ 'ꫯ Fww7(((5k17::ޞJz{{V'OƛPխYf̘1+V`8YOOOxx8FIOO+|ĉx Q+ `ff6*kiiI҄NCUE40l4TeG,srrJJJ._\TTt\wX oo|8aG||ݻw***FMjMMM8L[ysjjFcݵkJ?w_ƳgܹdΝ_%&&RT??۷o˶q:;;p`` `jjZWWõ8ܻjX4Xd۷冄XO<9--߿-44HqƠ [[۾>gkk꯿ȑ#tWWv}}=oo>==xoiidɒ^ 7\|yXX\b{S&*ь0)..f'E\\\@ GQMQcffORE%055??SaCoݺJ: DUF&ÃOO yhnn`0~Gvښ{{{`!`0H${CCÄ % 6XYY...\.7((7Źs>}~d2ɓ'd??B\5QF f- ɓ'?3 KJ%ɘXn]```LLرc=zr)))\.W_=?~rqqqWDŽZ }慆RSS 'sEEEġ7,[lٲe|GeQomzhѢE^^^8ۏ7ٍ7ėL:tKVS#R@ݨ#Ufzzz$c@ G6'Ht:`%޾}7m$ĕ__?SJ7fuuuC]!888$$'""M_jFFZA,QfW+[q_Pf1#FmB$ٿB999B$ @$)22222 X {{{ggW^-^8,,Laʦ===! %2+a_0̶ŋ``'Odddވ!O4I0f z M.ra~gg=3ógמf^Y볺WXc"wwwB֭[/^XTT⒐M駟7mDihhmxZZZUUUIIZ^|yzzzZZUTTJ۷;vZ)i.CGtvtV *!!W2~rg߱=;\߇̙3N\Vp%Emm-o2X&M2W̙ܹs&gEA̴ea(?|05޲BCCudddPRPPPXXKIMM}ꩧo߾/bС̾OzÇ{xxB6mϳ֭[!+W%[ KbsG :R! C0<$l// 0vݢMOO_paJJ^ߓD@PSSf@aw0Kf֭[2Қ[_ygYd?GjjjN{nWUU Q#h\.p] yĈB~BX,V*s>gϯٽ"[:CBZM~6|J !W@f}۷o*S֦"ҭ(Pf[|u=#\"gz 8`=@ lC%s g***r߮]hbnn?l0gg第>{=v>+Wf̘!]\\XGh,"+a7PɃ`KeN5@xВ aϝ;7uT'''@94Xr^P0-E9T2 .@>T*Ս7^{=fIoX?0Gd2Y^^^9=W_}%xUռ}*++]ZZikkń:6hh_~Iobbb"""r̙aÆu-[̙3G"477K$STWg1üX*ìo{l mъb2)ޛ7on|-U#|v]g}Nw kccc)f]&z yqhp<\bc/Ydչj7\d M ^vmCCC||fLFz̫}v9##c޽M$۷ok4͝b+Py5B%À1)0-c~a~:ںppp6mZok^{mbfcAMzzL&9raEvu!D2yӧϟpBGGٳ&_~ԩgvppZp!S[NNNf͚6m߳a^@ *{#66wtݵ:t|0n8xER9rϲe߿Ouuu%''d2: J5bOowttƏ9mڴWP=yo'*ޥ qOG_8L`SR#GZƬX/|mook.6p?~cll,xu2eFw|cgBx ߙr<Wx `} }5k> +s΀G^|{Ŋ=))))**rww'lݺŋEEE... ل~qӦMކUUU˗]EEE~T*ݾ}{\\ܱcxhke$xY%H\ɥ~vp]>3gΜ:uJ fff򶣐fj†ˁ,#`\&0)w5-A?|0ٲBCCudddPRPPPXXKIMM}ꩧo߾/bСX8ptM6=uV_vʕd'D>/>R!BBdwPPn̬nQl [ .LIIUxzzjfa3?/23;K Q/>>^ DDDTWW3f͚54=!!aƍaaajzݺu4qʕ3fhmmՊ󗜜nݺ &P8))2~8RD(5.Q֭ۼy  ŋ׮]f8q̙3[[[͛f3u,BÖŋ{1$23ĉF, @ cggc!$..n0̪UVZUmffVl5kְ]EhuxnowZTA4ŸB% ua-_|Rpb.9CBB!3s)-44Dgo"`uc>{켼mml ?stQ·33gμRd؈bXVkKR]  Z\-6zEEUXP1Eĥ9_טhQTƒ ] Y/^4XoooZu֛1.=zN<,,`7EPSрj EKLA666Z)}]7[9ў7,ң-(eҴ MOik0w36uo#r7oZ޼y*LUL7sLTcǏ%42a„Og„ {qrrڰaCQQR <<<4~TT{iiiym[K/bZ7n'g%ڌ5{3g޽:uW_}uƍs^SVVnV׭#]UB%b C$d~1]Ξ={ĉlڴ Ou@ .XeLX}CCC}}c/^L)..~g*J}}}8VUU6dwwѣG+ ԰OFAٔFcbL寗WiiioFݛ䔜|a^XX+Hz+СCiiiC xw<+Vr)=|dMWg5#P ! %!o ?zUnt!C}XsH@0wqqMM 5:k֬O?O? H$^ziٲe׮]sSƦn׳^^^/_ a}Qi~,}ϮXWW(URD" ϿZÇX]]]=s̡C>裵l9B`3>-"JX,=>{j-!" Cl3A#F)#4oqJ05+<@-摫+mkt:ԟ.ܹ{ȸqmVUU91&&&..TT^~}ٲe^}2is[(Z|vDBaaeXb2}Ν;t===+***++t.S<<<4OԌ7.==}ʔ)nԙ) t!^tpp4W4.++c?޾}[{`D_mrww2cƌV:۟cǎ76lSL=$''믿  ?eʔ__^{m޼y^}ukWWW??͈>6 !}YpaJJJ]]]mmmJJJ_z5k֔)ʟ {?1))޽{4Q"ܺuK ']``֏@ D666t !"!1Ė!B;88IzrJU^^MII׵h"<}`G+myxx`?W+a\r%m0w .(/İ Ǐ/**R(W\Yl0̪U._\SSsz ~t;3߸M߀Ќ5Hќf^3׭[<}t.YW\9iҤ#F>s4}͚5#G1cO<}7~i\{xxL4i>>>ܗ2.B>t8jDhtϟGb]NNNNNb ׊=0L\\\\\V9iiiZ5Eٽ{V!Z2 MD!BD d4%%7plllll,:@ ;w<}kjErss-r&*92qW'$$$333::!t)=???$$İNU5,VO?{mmݬ!#z>#666K@ JJJhZ0až={6lPTTT*>RQRٳ۶meWCظqZ!(Z3ϟ/..hp___ϱ|}=shh(n!`Dv嘙l,0_/?!<<]]]lV,ð`8;;:ua:y򤫫k``ɓ7oޜյiӦ;wr)m֭/^,**rqqIHHHMMζ z*|zE^&|ٟ%sfffbbbcccpp0(|[þ5B 2`>' @`gg'40A  |jEΞ=K'%%?ciԧz-'''R-fv֭[i ~ƍ.]>9VUUE_R53NNN---4VpssE^f^^^ kunw̰C8AX^Db}P:1fOjuxxD"!KiiifrqqiiiaKƦޞR__Ϧ{yy9r3gBJJJ-2uFccgGtrHbX@oרlZ]Xi$&y[v?9%e½I&- ~ԨQӧO/H.mhMAI&Ҿ9s'f9w8(tRhJiooDwywt7nܶmV\ب95&&&..n~~~7oܲeݻ-NNN>pZNJJzW,2JeWWG]bղ_+ AY/YZkAY}eJRwKSSV }e˓MD"JxQ[N*%&&;Md> 6 ]"˻%cҥt?}xCh˶իW4eiiR~:;GƂnBHsrW~ר&%͉@埔I;鱮]kDY=TVV('6Q6c6y}sӧO_vMV/Z(77RPV|,|||M@KZ)\w̷椴b~G O3ܢol!dܽa6rEcUmJ#b[lYUwtђ++ !QOxu<(8lcK.-Z_~avdtvv^jձcǺf̘{zzj5Rsss[ZZ"""vڥ qzz!$##cƍMD@'TTT&}U_ˈo:1 L8D`֍&V MMMhN+ն?W#hcK#ه\ʻqsOc𐑞qwKdO~nv(~][m -ww}!}p rqq9qxqT:~y555555cǎ7nqq r]BB?WWBFo"Y hT00ZМA hlg]Ccbbv=sLBݻuⴴ4~Æ #deeD!sislu!!!r7l-c}}g!Lb1bMf7G1S(-:pu0fZ#?mu1̥ߎW23~!NTM~yQ-PxJ>mپgJ;C ת_|J#߻O[[[Ս78QmLMxx{ZZZ[o999͚5kڴiڵСCdӧOgׯ_?uٳg;88DEE-\O2eرӦMo+TjrM͔nW~+ݪm+,c3-ZM /^3&$LMH_˟(˽m]l0 sVʘ7o޼y؏o[Wtp!66-*11aB dggggg7& x؜ڴA [kzLeeoeeV: cxKpIcmVϟr]Djs/8 > ˤz}`億f466~cW0n|PXfNt1o>8wMMM\>}zԨQgϞ>=33 ~ a #f)7Kl/KC=!?h/}Ypg߾95jϞ=1?up74KS*^/rJvq!:::??ʄ{66!🻇ɾ]X+g;w?L2PYEEE̓V k766v5a?i$<Q̓Bf!#`a8q`e`Bc&:;;![] ۶N4}S˃Ɖb]mmmZ 2죏>zQۀ'|G2 bp[aaalm~%`zZ[[5[[[`Fmd2-x.C(M;}ob? 7ŅNM aaa\ڋ@@8=EZOc$ѩn[-}9o9D`.a x.'c'߻wϰmۃzM޸:x@:p4sww'DHHHCCaVKoyM@ @pJS(}j#7.B  2u`->]~GB?nol~7vW`0Hi9 GҬ|MMaI>3`P-G}ڰmEoGrBBB233 A^KEE FoƟ| z G {i@kIIIpppII7zd׮]d%%g}}_~٣@ :dp/=;~RTJכ~3w7u MLFuu+u@%O G @ %XXX,yaA `IylI#IENDB`nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/doc/images/extension.png000066400000000000000000000076321455373415500265770ustar00rootroot00000000000000PNG  IHDR#$B pHYs u :[[tIME 5, 9IDATxs3*QA07 I /dnPCL$ !BTZ[ƨ:U@oMbmo8}˹gww\v=s6g'wwʹi( 4UwȚ6owa8{6S;aIZZ {ljikT!v°GLޠ]+#TgP-˖׭ W{P@qroK˗_Q뇚r=RAui]C?Yɓ5&ozf5o.LvFy^sCAg\TPBZ!S6W>;_5-k>&7'tfHfI~vykkjJ|{6n(9i/:3z2ܲR_XXXG 8n}`5 ^6Ʌ# o~?oJGrRWuԛwk1:Ƥ3S6:KjSY;/$ƪyЗzFB 5kUu+:3r+ܝ^ynOkvӄj)Bqn!=7lHel2uigŪUf&mcfhzaߖ?sfV'rɳ5AP\9ye~2#j-+-ShT)}>ߜd<2ƾϜa7 " LңїԉU93r+QK= .$M„'`q ?K+-ShTas.ߚ+)..Hee+VC=tL}/{utJ |TRkR 5``Jwjee&B44[}ydn=1g\n)Bq 3:ѫ>!m #&j|.g'efdcY3IJer[ZSYsB-G% qֲ&!*P YNleejn_?@YOX1g\n"js5AP\„_K}dvW9)b7#Fkߗ;'`gOMM*5 oG& cMO,waȳVK(Φ+k Oߣf| wUn_?@9NUg\n{3*WH+}iezeҊp]҂_v^ζJdodϢϩ2ՙ{r>'Bzsy62jIjj4lVn~,{ ZO{*6hoN⚖˭@Dm?ZG)Bq {NC2E(έ:Aݱ|EUzKl0kuG]]]}}} [(׳fHHUvslEw$i&4ҬRzDMt\.YsN^:kބJ)iIѫYGQv^kUJCvuuuvvnTu7sTVi[<3ݨ2qڭdW-PycM_7!OH\v+7(SwfH!{}csKJZumsG9|𦧷uӷ:mYV13/3)rh5ITmYe!'ss}){l5`)L:4ln8yQF)޿e_eCGy-'OŝR&ȳ2*-oUӲڒ(QK ("XdѪҞ^JqMcM_ݣ}Mo;3z*ƛvNC)Bqe̶GؠHMUMI_&^vS o;3zҖ8 qOOo5,H!U4 ޱ2횲#vdO {aƍXMF;ȶv+)d:`,,iSĆ] )dÃ%mjذ ]% K&mP0 TҾ47KFíJ͒pkafIh5Hoy4_iA|#Qi7 WE0 4A 44=iF7(.2cT94[5_-:N$ײ} p4'=|XJ;Q%ͨxK_Ou!?OA4f(m=OçfIP8? Cvs4i@4i@4i @4i @4A @4A @4A @H A @H A AH%رc" (A-q̜A-4i i A A AH A#5Za8&&H#0 GD+͙ksd^IENDB`nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/doc/images/object_controller.png000066400000000000000000001153521455373415500302730ustar00rootroot00000000000000PNG  IHDR<|dw pHYs:duhtIME 0yR IDATxwXWVXviK/R*6DUw&jL~)j(v4( Q@.m]Yvv?pg{3wp}ܗxw *xW*@ ޽xillg=CR-,,̴dSyV7n`2d2JBBBP{B b˝drp82O۔+mYj_I<ۻPĉ)= :6߶*ձZWWW@P\\ K__M,m6.h={fbb'H^TTЧO:.{NOOrd2l„ oDFFbv䶻gA<OOOnT*{Vl&mmme3ս |XRR"Wr1˗>z̙3ϗ>gg瀀<aXq srrX,}:KOO/,,H$?Wj …(F-Z;Y$FDDDRMNrss?~LPJJJjkk+** -E(VҾ444tBb˵x񢵵5-((={=ZMU]SOOO5/j)^HB+$b1hdi?XO+#gS.Ҕ˗3gz꥘޾C566,M Bv@bbAV\ ׯ_PVVm6F;&7meeeÇǏwhY\HJJrwwϱ;͛7>|8vUVz{{c)zzz$++KzXEEŸq0;|>˝INNFFF_ҥK;\DFFb1r(ͤ7ٲe͛@ |5jjX_5HT1Dų8CCCLO }tRhh(̚5 K۷L***233E"QEEt:]-**233crlD"{|kįx5###y)ήTZRlnn-8+W̕Q(M'+..611p84MI,b\dܜ/Fmmmϼk@n!tҳA3H 'ŋڔ ZGʹ*ˊUmSSSzz:D ӻrJuu5044FƠAqƵdff5 \]]?TRRMxNW:snTݰܧOTH:`05{{fl >}tȑO>%C&:dN?~-gff:TB,D 8wiiiLb)7775 k˖-x0X6&^/5ޯX,DrOUU4M"K1wJmb="HD56eK*f۞:uj\\ʠ>Q02??}Сa̘1wl6[```0a„3gΔ$FO˖-0`@^^իW DbEE4Ǫy葟tTnX*((hkkqD277h~mLL̀rrr\JZTTT^^ohh'0{{WDPVVw>'}v%%%Q(//XUt!F?ܹs +++cX'OVsFqdddt՜H$b)>h46PEss8&<OiN]jlv&aaaX={aaa0m4,E}ҩ˗/Y,3֏|R__f:88Ȏlmm###/]ٳV}}}'''lebb2m4l)RϾ}|ի[,U|Ir'N6Ν;$ٳg?**CŲ (ù*9״|>2΢F zȫԝJJ#sj r}yzxx> )_:y ">8+ȤЪAP_~vz&0dj}@ c܍ 12"յb)lNQnmDZo΀G`Dϫ8=k|85y< .`Հi' o<>x~R\9~Cݢ%s+j cCh1md˶ID@W=K] ;C4<O<>oC=DA<_ |_|t‰_ U_ 5T*ǴfMͨFg Fs{[yzn-\4zP_S CR3GxEFC l̨$&GxnVΟ''[+I\G*#t&P|E'!>f^U@B>/$Vv08Np!d6:O#I?\[оb%+FY6~H}ۏ@&y<'?×vRovԍ)dɵZ$/ x,EM.?ޭcq7Z5&z^+OACYyyW㽚|>o2i,g{*]r]yZ6w 0L)&Āl!%Ϛ1lHk2KڄVFy+jhb+w"4q^F,wH7q |}^ѫ%BF^TKCR%oaHºv5`/$VЋ!<ɥP6Q:ή.wH,o~/qhOfwQnFұ1 "YPבf㕻fҠedJ6]Fup?S2ܗ.QMzY#ƺnP%J&/-w紕>kLyzjgg~=zT5UUޟyРAvvvBJOg]+65ÛcctBEIdix8AZY[wUNΠO+kkᅴbիG;hޠ?#G$D"o/^,ݵgϞڇ>x˗{wիW &Mk5}fffBBBVVLޱcGW-)99}ٳgWƦ.\ƪ\\tiǎfffݸYGu8ݺu+Nנ 毿⛛|ba|9hlLNJ%m_|AsGкoFBp/'u‰`ݻwD[ʦ;::qttlhh2556( 6|lر Hb1놑)Sڵŋ666t:=///))iϞ=j\0 i h\:Cu ++ͺش<xzɒ%MWS/pؤ[ԝOK(DՏ|Fpbȑ#e-,,*~[XXh5D"577K---ҪkkkkjjaNn۶- n:tPQRtp-TU;Ҳ%\ohwFa!H$ZuD" p߿0n ٲeKcccCCæMBBB //~Ԭ[N>o޼RP=)))p麱*6mրJx1SÇ8D=|XuKH$P/_H5Ne8._Scس |'\_ZXX 6/+-(( -UV 6l̙+V ɓ'F<""'$$>}SYYY]SNy{{{bcchKd_Drڵ!Chi```DDɓ'/_eeeɓiiiv]S۱bUsٿ֮K͆m`HLd۷dzYpLhAAAJ_NNNKj׏=BP(ci^^^pp0B100NKKӠŋ{{{S(==#GVWWcO>8qĉuM<T}}iwڵpBWWNkBҊ+++l|m\.Ν;2:()N|~JJJ޽?0UDӁxyWltRUUu ȥ߾}{̙q:eʔGN`E_~=((H"_|>_)FI tS]nڴfffrK4Ͳ:={Ν;pBm; ۽{^@@JxI~/[ d2~dܾ ŋЃE6--mԨQ?tMk׮͛7O:`mn8---7oHc)Ej)JN549r۷?0_UUUIT}Y+W`РV;Tݻ_-ZH1bp8eD8s洚mʪ^xb qi-e0b֭[4h͛7[[[[ZZn޼j5N[!> oׯ2i IDAT)۷oFk=Ξ=gfϞz:rH{{SDDfUcbcc ǜ9kjjڿ?٠UT*aXMim;ynyG$@E P"-񮂄w$솜?N@sZ@A5$ɔ)Se>k:7FOgϞ]UUʒH$ÇJ::+fffIh4ݱct_Rccc,( J*&L{lnYJ ٛa ZZPr/h}^_~{]ǏkCKmBn<L2eɒ% Çq1/\d J(RﶥiA?>g_III혘;woSS֭[===֭[l {ж7|u7yy`6Zx:TT)wԩ0zZUZPz }ق0o47Cs3̝ ZO {iDu:X122ٵk.Ç+[@ Jo߾+պ\ޱcǾ}t,9\wNkbu ;VԲeBaYYٚ5k>-="""77W(lܸ1 @7#UU\D9sBaqq tNvڦ&&nݺ`QBBҦ7L&0w/ܑŢEPY \.\[l!Je˖999޽[Ke2eJXXB8p`cc.g\:&$$dΜ9 eԨQցEۻٵ:fׯ_=u [[{){:|}8&҈BNyH# @ՠE P"-4wjgƺi iD!4E (h]@Q# ̙2`ӧOk0t$MMMtW_}rU&Uoݺ5a bff駟2 8ժ}ʳ/In?UJj#df¤I@tQKcQş}٧~}uysQ%?deeݹs~ӁS*62k644K?UZ :t4Wޏq\v9@ `X x(՝4{o6&&&((BΝ;mlllmmu'z&yɓT}tבbbbbhh}&Uܭ[a ppț4RRR ŋY,ʞ=dl{”&>>_u,oyEs% g@+) jkT5 (4-[&T\\|Ν w#h4ګ۳akk{O>_th|w:pnIq6Ӌh]J$\.?u /^@e%@TvVFMMMoߞڦhmd{ӧ={w:l:Z:5b+@!6t0ɢRA03SS8p(4. {zz^[;--My{{{و5&Ǖ_֔] ^@ĸtշkK] iDmڴdXm۶}G:>lƍ5556lԁׯ4hΜ9.lUYfYc̙YY Bq1,X:⊌k LX(ĥW̝;=Va]ĥKzyyy{{5j…:p*]N+**Tz IZKuԝJ=; 9sBQ4ťE`o`g--E!.j)za@F񮂂@A@ P"Ļ ҈B Fr8@<1-X*jDYs١\L0JR &issYT֭[5T PiUKS-Jpݺ&ff R=7nѠt:̞ ]ҘF?kDDk[\ƅ ,YaaaUUU~~~gցӨ(*ZYYWRRr%Q%@U .UN(?] R=P[ Я_W+ L&sرϟ 'ɓ;fccӡ.p85/..ήC;]ZStJPLtm4u{P"'áӅ;w;6oޜm= 㱃ty=QRn޼љ W\L?oaXL&믿zT%l6|tQ|UטFeCxjK)Cl޼u#8iҤ☘ L+ &@cFKΩ.xAѣt-y햖&1($ ͮBuȍ7ё.ɂ ͛}ի5^ՊzBk֬T Vi)@߿ll6ZS*zA333SS\~]g%ժSKp)*647-xy+h\KQ F ]?<|#-`d2.//'ɵÇq;;O_ꌩ:HNFCCC?%%EizTOOrzzz(9sFbg'Q}A%'NH5Q #_j;1Q8՘FǡCX,6J\kv-W9sdee  AFFF]d[.88XNA\jQKbӢEPY \.\[TiA}l55P] 6@Gqŏ?#G^^^gZӐ9sP(QFyzz>|XN-Zdoongg?z'Sݻgkkkkk{=MJpEGCExyV̡C .jbZP jA-] 0jtQ|;|4za9E;G|-@E (hw@ (q4"K7?u)HN*}ab$$$P( h)_~%N(,,{nii)LvwwijONN HnnnFFF)D"駟uSk+[SSsƍ2}} & 2m۶MA~z Xy3ghRGU{#""|~BBӧ/^x<'O\|nʋ.-~6-`VVVEENL&s߾}lbBBۍMMMwqi@pB2Lтut EOOoȑպ),É+oǏ۷/D211qaR(s^^z t?x@NPB{,yu֙&''۷Oo{ݿѢE=Gvgώ3ܜf߽{Qg#UGӧnjcii|ʕk]/J:5N8uСǎ[OVI8p@v򊍍e0rCy>}t}}=F0a=2oV ` QfeGo&he{݈w:^)1ׯ%:]&LAKjf-@E (hw@(׈R7@c洨wbqKT ĻPE ;>;GV ]iP"zDR'aՈ-=4mFV8dUU!Mqܴs*3ia3= aUъ >CMa <\]Iݶᖿ*(%4+mmdUUZж^ Z3oGCc㭒K?LG $ncNW{9]![ҷΎ]]AIAQCC@е[oW@BH2׆YFV]m#e=3 k-6C@cϮ}i>>ѿ~b:x :1Rw'Nx`zr+)ˎB@$OR&w'G d>J>e&O j5Dʎ7`-6mIVK@$Qiڙl/^) }'qj$X49L=H$|JvEb~*!J ~too_r%Gߪ4 y )H?f΀_,2]= ~ l΅[xADኡz|۟ hkK7rwܹ B#ˊ)}_5PTѓC000 Z11Id x<^(7K,TP݉ Bf$HUI$UT}qk"gs;qa9 ͼⵞV%1UȒ mpN̕H@ζF$`2Evs[2v8֘?4¥5ބ ͂vLaVr$pT!K\XDuhYI.}ib8xDpB ROYbu}QY"FdH$*%5&f\f'G9rX;AqgCQ[-$VOkIzB6D"f;R\#Gv;c @/j dT;eZ ^68D.Jf_u/=3;_j|v d81ЂL7ެi*=K{1o=@~6C Ŝ>Q} Ox@n)"Kiz|}S}Ᏼ/|'q׎r&c޽ێSN?!<<< wa/9FFFj56JEKH`ee&WJO0!;ՔZbH$7M^ 3'AʬoW!ɐ`_jVMH)ff' !kyDźSqcWMUt$!ǑMnUj%*l'4r1ZX/&M#ʒ_9- cS\Tfǁ낁+_… ^lvBxPrVz@V3g-.s IDAT=[fyۻ71;|a'JscgU);ta%( ZեAJ$@b|,lXz60gllQk?)hnVeVM'y<J~ujVm3Ua)Y`k0p3/+NR:$hԅؔi6qn?AqoS=S6î;qm\~Hbx իG$q4Q'v>*; wR+FOT᩸vH h4l'5Ԧ#VϛtHpZTLUuvZS:#[|(>FɥC3T2!%tGO,YUWW^OM?@t|dggc^L!J+xU=oo6_Ib1dR4Y+m#jyǝk. eML -me~'cL{n {ڸN oB1y>*ѱbu$E(>NKSLgVͺvUiQ&*>55pP԰y`܂Vp3gJV]O"0 SST:ƙ9ZɪBvx,KPCНDɪKP"-D5ovG5@n/n#r-@E (h-@A@E (h >(h 8{%|77o6lߍ7dw>bOEn%;Æ KKKöy<#LKKH$w4aU5EW[n 6ԩSɌAN0`@54RGM"hVJjjU[^^w??ZbŖ-[***Ξ={]Z,w.ٙ1cٳg파 &y̙3f⦦&f'b=m;55uٲe;v쨫KNN~]ӓ'OD"DzF U{=7n8|p2HiJKKKIIa2d߾}Ϟ=KII)))!ɛ6m9sfTTTiiiii_~)HZ[[;L鲴͞=;,,ҥKҜܹs֭[+Vҷo^__C |mVSSQ^^}v5#W9ji0hqd9J8qbɒ%lq~$W$(R 4hPnn.XZZ2 4hӧ=<<=zl|SSSDWWj|3cv8zǏƍ|ɳgϖ,Y)1U|||O'''(-- 9TC\\\hhl쟲s簜?FGG|^LLLaaa5 /..;x{{bcm_|_~~:L:5222$$3U^^ U8I7n@QQe=/7\]]0((@/UkYhllRieWP`IccvQSSOn߾ŋz鱍ѣGK}`llm Bl`c۽zQB'ܹ333ƆN$&&޽[.c1 ilggיti^qVPjkkev{ظ\ٷggUWW ɓM6eddHk[zGUrԩp,!O6U55)P(ĶmGGGeTU:͡R4.[9jipѾ; QoBBrСCChѢ秧WWW(YZZ>y򤲲ZCrl\ޡ# SSS__m۶H$-[ :fqdaaQQQmWTTt hjN;lذ7ovieebaD"Xxq^^ɬR FBB²eˌ-ZXWWXYYIJ˨tZZZolһd i/_{gϞ(]vݾ}㕖JD"L&Hgҍ蒒>+5(*3$$dӦM cƍI6mZJJX,ONN6mZM2e [l FFF=_=걪ֳzm۶%&&x( nV*.. .NDI$^yy9t-;ӥ;wn̙LfϞ}y53s/._|2*ӿ+ӧOWrő;#Y7l:s;v 2Doݹs[xx8[Uޱc[XXذaa+V suu]jɓcttСCǍ MБ'b6q;Znvرc B$dٲe'O{#Ǫ;t͛O>b]6 `ԩ666/OGnڴnʔ)~qժUG611Qعsʦ̙3'66VMο+33}9K۸q dkka$W9j{ty!j…L&S%KXCYqqg}v} ?N.]RZbb!Jս|ƍSL1c-[֮]+v܉Қ#1B&{lggS _rvv;v,裏֮]@=F(h[>J^`hE|XAۻwEz]:K` HEPP5ĂɫD( H][?w}weY=<vVB7|'[3n(w UUհRѣ{2BٸqަM]bffヂ3R*cjj~zZ9[apmmm&&& Zoo)t$=&aiiiooT8G":::...3T'^@pFZ_BhA#/^ϯ=zâ""7WTTHII޽=[2 ù>}DɱWSS|`_]GG˗ׯ_ۊ ;w S/ w/~FYhUTTTTTlll^xqq,|rbb޽{O-))ICCC]]}Ϟ=.]鉉W^7[={`\~K˗'ׯtRUUǏ;99IKK+((ܹ޽{< -^@i3 sZfZ[[ 1 #W:aFFFp d28&>oN2%##cժUg8 ZlYpp/r06.**y̍K/ x\=8YeCCCð x9y-ؕ <޸qchhӥ>UXSCCC{{?SRRؘ`xzz:;;+))}Ȉ1%$$( | ZAi{_r]刈+Wh/_j އ}}}UTTrrr?w}YǘÃSSS=YFFv˖-b++Cuww766pN D9Ms;vd˗/gg̘յ|p\H$ZXXlݺ_MW_uuuqupp;OY)))h4&ðCEFF_^GGgÆ ,ykiimܸ133s^@􋃃ùsx%Tŋljj`9s@ ܹsmmm/_0L݁bw,X޾]YYUUU:gfHNcn#:;;4Y1H /^XHn8</..1*xw=%곽"M$iHhEMK&97`&!մzV>BimlllllP ƨ;>9}│hNˣɓ'C|ΚGV(v4-vk!EVxɓJJJ\߳ oa9˙3grI%O`ZXXXXX$$$OnnnnnnH~Fv uuunݚ6mKqqH$r:￳}'LǏ?D2eʿ M+ښ6;;{Μ9 F%$$XYYK pciiiaawGemqxo<,aVWWijjj`` q~ő=99,YYY@tҎ;x|DDŋAM6{!!!HӊݰaCXXXeeիWaeeeHIIűa߾}o޼~`Vٳ%???;;Ç dɒdN?RPP8cnnnaaqҥDiWr̩SrssϟoggwM8rvvѱf=BSS4e)-4%`iMLLx1'vVgdJIIg scc;>(((-[l޼iZմ555UWW#C{!HD"1)) C:::v„ H]Jмi-ZU[[kff 7n(&&J",,,BBBXRq_2 `Oð tuu۔Sp{{{lx9` C]]}ڴi/_+Lw z꠮8LUkpΛ7o]vmmmٳ?v؎;9añc>M;c rҴKl/̙3?nmm=i6ZZZ3r݆iPfTh5-" 9-@XӢoi~\p8PQ__/6O?pBy#ӧOwbnQ#E9is4ciH~VLLlR111III]]]777^GTK˩ ɉlAA98=モЈ7#ܾ}{jjj?`}"M+v@W# `|NNN5!3gΰ~ҥK1 ;qÇ_zURRrSNo޼:s {Z]߲eKssׯq8;ҴC״> DJJ?݉[xww/|;vPRR/(**bcVCLx˗㪪˗+((HKK/ZD" FRwء!++xI ҢSN{.1c8`0wutt 0'''^.iiig@[[+++SRR=(RQִ$ݻw ?DKHH{t{ÇWX3ѣGxٲe7onjjjjjܺu+T '111??D"IKKÝ#LDDĆ NW@SSSyyY0 +--NF 4Iɜ0555))) $ђ;w̘1iZ״--- X\\]677{b¾>xu5oCCÒpL$ִϞ=6mJe9{̙UVqh4pL` x{{xyy3c/2$$ZҴ¨iZ̨b&--|sZMM QTg5d2 ٳ9ihhr)vs3ׯ__d 8f{EEEp֦ciiɼ9-@\\gϞewŋ̐c0BTP(ล|._]]]tzGG mm횚* RɓI&]𿯯ݻ/qgee_$" IDATկ\M$Ӳ`3ŋk֬r CAz,Z699t:@ 9r$&&ڣP(RRR555~~~02!aX@@۷oTjii)0̃g E}#<*O>sZ~o3caҴ1,1ici1igaӛTɢIxOƍׯ߾}\h VVVFFFo˗//^G/_0IVVס:x`QQQVVVIIT\\:'N`8\UU5m4Ɂ&iӲ%#M+sP99UVuww㊊ x8::(**n߾(=kk'>}ԩSs111T|55N.dqqq ׯ_鷉IZZڀυwΚ5KRRlcbbϞ9&&=&& 40jZNYPVV0LJJzyMLLxqkk+_~  p8d;;;X[[s2O#wEEwHHw>6ӊΜ@sZi״ip#  jm~m\Mu* P QvӧO>2D<ꘛh#;HbG E }i3kY*Ø7ɰ.굗>>RZO_'.WPm$#y/sڹ>+N9Lljaf-K3&jb&>NlbNE81sy/ ue$?5/_xԔ=n76CM6cƌ?qƄ ` qF}}}}}M6Q(|)kkk ٳg| ?~a>ZZZ...$ԔL&?~433kjj,i{dLDQպkvk)Rc1 sye`h%!Q{Km9pXjqǙr3um>>r*:O4ѓ+#Q:(4Km8%^r}>;}y ,r_[e1 7olkzf>^Sfgh s 4QY$Y*1aׯ?x ϟT999wuuŋ7m|,,,"##q8ʕ+jjjcf,x\Qi9.?"u|JWP ;t]=4yO ?#+`QԺRLGg+fw` -CtR 4νgsaZ^ȗ &*xHjG食ydRq 0 Yuy5HgQ]vڵkZZZFFFPC^r%>>^UUUMM-))0Urr2F@ '$$|rssgΜ)%%%//cǎl:믿~N_~Օ.ʰ4,Lfiy8IM;,sZևshIհA}G*x.I8p=ST]HE Rg"ek]I}HSh|ܷ̄5Me:{h 1 S8faaЀp [di$ ԋN{{{'&&Rd>8600hnni4JMMMzzzYyElllqq10+)&&F222V\ѣ8/H$---x|vlLnCyZGSWOI#z]WGԸ?|,@[gk7{E10 {Mv0zW_1qC{E^YЍaXqCV) Zۮ6c ajt/ޢg޹sjhhԀ]5550-{&ijj2LJׯ/?|`nno߮7uTIII~6@`9ş Ob|]iqbbb8OW>XbarˬUq!4iq}tF/$q6\C{.$xN״ѕ'f+n~y<ڗ]v92,m4'f*>_{8aU`wvjzofggXbEtttss3Lo}~wa80#--]WWp998ʧS|!OˣOjZO[Iw_VdϮƲZԍtN6vG\nUGvV6S9_%p:}MOU"tOXxZyic7f/1PkxE OzڤfcNq"##;Kn۶ 2e{@bbbutt233arȩS!>^cܒI*j瞑EQvSspQI^|r#h۷oJnF܌H|{,/5kՈZlLfϜ9s)4iqK[XAH111c)sԴB?a̦[GIpll*"O<177G10`'OPSeeelRMeׁSxx t؁ݾ>}0jZc#P#d1Dcdx)...**EZ ^hG̗Nև#A?t?d~$£icK,7ӹ$䞭H^-e? ;HiEckZ.۷o߻w1w={v5kHCO> ~%6QҴ#i{zz6mdlllmm}QP'NeV7o1 ^n݉'=yڵka9s;88k#GL48$$4-!!(00lfM ӧ'M%9KV{߻wvaaaVVVCCs={ZZZ󳳳>|222::>:bNaÆʫW['OܻwMMM{e9{))8!o` @^^^iii|o_z  ]_jjj,cbbTUYeddũihhBEEeٲeΝ?%K%d2YWWw%PWWr ikk+((DFF^~]5-aG57=[`lGH7ҴkZNijjsQI)aТK|OH3gQ3g#f̜:u*77wvvv7odϙ9[v;@D"YWWWGGںYȅN2{)// p!_ n"i״3;z4`Κuu:CCC;;k׮Y[[!4ysνzj߾}۷ogϙ9[ 744466D 7 سgςǏgϞr;%$$6m"iӮXbݭ---_reTTTKKKsssTT󩠠cǎ' (//4=BTTTss3ŅuBCCTjYYY1ӳyZZZR(&M$v4ھ}{XXc=~xxxxxBPPPvv6?y$f~I+fnnێX>>(44͛7'M$%%eddMhMMM999.T"jhh8p>p8IIIA4͞=ǙVVV>~%//㓓ˋTSSvvv[ R(u2NetEGii׮]<&&&H$iii"ĔTUU̞Y2ٵkWcccEEEyyyMM pp{ÇWXà r7o<`nQQQd2yOҀumjkk)..~{*NetE1i1)| k[n1xe444,))D"QKK zzzeee,X~蔗7oหKBB9ҥK/_|%K𒛮nEE8.++ | ,TA]]ݷo߂㊊ ُ#C[[+++SRR=(R -[N!yyy˖-SWWƍ~A\\RฯE8ッ[nܹsXЅB 6moElُ#@~~9-!s2eJff&L>~8u]SSCRi4Z.}9E0---8 a ,N7o/ikk3XyߟUSS/܏hNիWV`|}}߾}KRKKK=<>^AA}GP||||||( /cNc6NQ(OOOYYYMMM{><~Y.] ~PԤ$IIIƜs3 ,plxŋ}VYYjfзLjOlڴH$X5" '?^IIBH">L"޿L H"HӎڧOPwӧOFkrr0hZd@saZ>| hN+NjPg@iHӎYM+q >>>|۷x<ӛ cD455500hnn:4-!!(00{xccckkkXW*,,ܲeM7ǯ_~.L5谴lmmZZZ0 NJJw\x<СC7oyϧM&--͜<((ڵkΝ{վ}hro6::9**o9,,eԩ%0 UVVŸ===޽۶m۠Jnݺj*ZVV _qsʕQQQt/?Ó'O>~zafCij&tt-[p\||+K>!!!{zpj>fFHh\=;vhhhL>}ƌ/^ g^=Tr ,X&&&V1cƠJqӧ/Y{jjjsurrz{zzٳgӦM+))IKKHS4x|/Xӧ/_Bv6VZk>>55UԅV Q/q gϞ%/҈(`!Jt: MBhs%!B#E/矨)1'NA@ iiZiA)!XPk#ֱ/0C޽{73 <<<~7 JOO]yy+W=M[TTdff`hMMM999.< $$$YLL >A___hh 4R]]b EEEp*zHJJQK.sp:~۷o׮]&f8ĒTUUx_mݻWKKK^^Zo޼9i$)))##'N M[[[%%%8bcc_PP@"7PTĔTUUm˖-ۼysSSSSSen9<򌊊"555EEE\/}tt4+G/-YѣGIx葷7[n?АST ð+W,Y$--mӦM ׅD"{.!!~ Huuu 0ƒ ݻk׮y?.v<>|^:55`@"coSOOE444؝;RNyM l|X5tO \\\<T*UBB^`2 77GrO/^`)^ccqGG/.1 kiia0===0s ~ZAOLLd0}}}?~P(>|looommmii!$@ '&& ^B @kk+ۯ7{ qqqqqqƁ e)..~[Ϛ5K^^o $0Sy8,`=K Jh!aӦM৺:DgI$|d%%S2 {{/_*))d.UR5]v[qΝ< mcc-[L]]]__?##C$vX`?@EEe…/~kjjT*F;uimmmvwFt:>yϰpS[[HK2z <WgΜó7nܘ9njuuuGGm۶͝;ðs熆:99s\xynٶml$IBBBc``wn$ͧLI&?-]9-GSNy{{__߷oRRN`ºu6nX__޾yfHPdeekjj p#$$L&755^/NLMMG QUU 3HwN@=LMMyXvô#hswy|\Bci}9/Z)S>}Cx}~~>/0>-?B+*ֱ?DXg^֮]{9>YcD =Sqckk+MN 뗪Z}p<)^nطo_yyt=k##MSVV~Y-B+B6===77]Nf͚Eh8{ݻw|} '{ 0DM vʲ[=M;|w{> |ݳg>f.i{+_xqɒ%;_~>}LKK ?>ִJJJ9G?࠯?W^ '$$XYYvww:OOOSSSf [[[CcH\'N311Yn=yڵkΞ3gCzz:R:rȤICBBz{{b0sAfI&A韋mˮO^iZ:,PK!A^v|ѢEhJJJ@5k|}}KKKKKKͣA={ZZZ󳳳>|3aYYY ^^^ 3##ˋ6l zj{ɽ{?|b@^z%yfZZByͽ1/᥎h-1QִڲAAA%%% qqq gNN߿322444oN`aʲeΝ;%KS̫L&߿qqqyNi1 ;z277[!l+.RPrG4-,@͈D5xb&&&x<nhjj200dž3~0yp̙>*zB:u*77wvvvЬ!3W'ENŀp8.t:=00XofL:~Vr 7nf 񉉉;w҇ƏՁjkk̇CCC;; IIIkkk&O TqvvvHH_)))h~w],Z˫,55=Œ3Ν70ʼq֭ys Gc9Ĝ߿u֔MM͍7¹+M9}ncn֖E_2}***ec0/;4b($<[[cǎ Ă#5o9-}W<5_B@ E нe !XPk !Buldx$Aʅ (RYYYCX#âit:ڮ.aiQŋ/^piAgg'ܠ)_XZ___'ODB;sZh\P]0~%Sqq1 O86D3Q`/0$?M 6Za3v $ȑ#pW0w֮]SSScddkjjrss!>67XB'M+pFSӊIIIA5U]]b EEE F Դ n:yyy< ٳzY___zzz"''[. ?3s& ߆X` .#zxxʂ٘Ѵ}O;ʫw}a{{+|||@e6o |{[ZZnݺVII ,c^TTT[[[MMMqq`8{VP{ڵ&22{Q!ǎ. //J]pwtt\p!((h] Xs3\$&&H$iiif򟭦y ðfp%!!KCC`>|^:55YtuusKV\\蔗7op/*sK*((xb666SIII899900p~Y<?~Ǐ?~P(,f( 8uq^sj7CCÒpL$+ cX=#dNQSSK,ٳnmmmiiu떇s>D"NgfdbbMMMᰖSQ]5*2wغuѣGTf<ą(ECC8gn ;wA({ZNu߾} .p߿TTT.\`0/^̜DKKr0 }Kx]iӦ?^JJ/lXP(OKK `?~XOO-A)4]L‡'m۷o7@433srrM L@Eb:"===7o644444 wܙ9sٳgA J577BB@#!ܯCpG ={VWWkjj233 @ ޽kIIɘ GS E|CYYעx555uu+Wp99F{okkkGEEeff"M@Xhڸ-L600ĠSN=x`޼y'O£sjkkx+++ydA|ԩYYY}]9cQ[[kllaXMM pta-p̓h" 455oܸ욌!M@߿[]]yfMbŊf2b PVV g$0}1%?fR_|bb`y엉3+ԇ,̌,4 "ͭ32>{E4އ ˯NԦ+Qefdϛ?6:&Ǜ?|"=\n$FFfF /0"`ddf cfbb`dx՛o yAP ,,eebWaá,QܬLL>5Lll10 m00wTVxOÚ bGB8GtUմXplII ׶R/@2 Y{ ]d9#ule+}N6XfJ"խJ13002³ @K"ŭzo?1000@{ lϿ`?ï2"ecgd H.fFfɆ}Ͽߌ"٭윌 y02000Ac<\po/."?;#ߛ!hgddd\<|\300<|?j"-U L9D8E i[ZP?z5fF6? o"b')~?3311g/ ֯cz߿>pvfL~g'""٭Qd'i `Ϳ'?HۅǞy?200 %)h1.7?."ͭ 32yVfFfGyO/:?LL [,?/?^}|:`luX-tN X"_CkǶ>w:7WlSofFcOv{OD7톚)*$@d"7$1CRgɉi[!.f&v_#ɧ{='JXXc`agպ]R\̅?ӧ_ᄏvѦ_2"g|fە(m )\!&&&F{ ba~>qci.O?l-"s܅Ǐ<Ϟn%hm)tN6P߿0H~̌,|ןhmF>1:19_/رcc7k䱞]ۯ咒SaB[?|}kf~?ɍkF/>9*qpQ( @##ïe1| QXn_ #ơp7B]X?F[a'K+ q/̌,,L L 7tDʡz /#300VnC")"/?110qp￿l_GVWNOU_UIPSCؐ?\e``=_R(2r-d?ÿ_?+78$$ +:xBVFn^?cbdd@yĂf```aba㔆L)J sI2Ҥ!#3 > ^y^~o (?+33d:.cfL(H*sJ`Mg222ڥž15,l l"<-- !{ȑQ[[$50lbD uu5766._|„ /x!vpp`X6mDSZYYz E"ƍY,ѣG%W_}o` ttt$ 77'$⣲TQQQnnnccc```tt4.[,"")..(ΝT!޴iӏ?n:l9܎=plEiD;%!^;vl׮]k׮x"˗ .W@LL BY`Ass֭[ mٲeڴiƛ6mq/СCx_݆WG:pɌ/j8Bt8p<}~1Џ|38}te@o/@7@7tnBG^cǏ,jnh<==5Y7;vP<^CP::Uk>>>GGG6-U)rJ609yUJ݀nBL(ʗSCOOtKG o`.|Det]t:]Z:S'66#&&C 2k([?57;fYv)S߿ظk׮zLV"fS䨣zzzoVvv6s%FӰFۗ/V5oJhH ;KFT*155UfF|vݺu Teddteb׾} N߷o_VVA@m۶MCtB5HJ\.N*b:0 4kkk#bPNrylBl6G)\ҼHLLT@d2_bw566b#%#mlɨGPvjҥ?H$"bLMMİܾd ~X,nhh ݈P>Chh={߿OR}||qxTTT@@@{{;$%… ҥKSRR4mbW`Mo4ܿPqND$={V 0oi3)M 1=#?x|_uF,3{---De1o0&Ñs[@'O9Q@qϒ,(nݻw5V1III*,?QX9X5Ptn n- 7SNt݀R]nl- "^LΪU2335]7Fp?PU`S`oh4ZFFt$??_Mtgg琐YC^w=xoݿݾ};F377%WLMMءAEdffJ?{KKK 2''>@:ugΜbءL9}Br>tsE}U'''bWcc'L`iixb룏>*.. .][,--wun}YZZLʕ+obeebٓ. ʱ#G4C7aaaƧ/"""]˖-srrC}g;wN {%?KKKIN/{/5ݴiC\._={6Bz̙8>cƌj3\|zǎ@/4iĉsrrBL&sʔ)Įrwwwqq9}too9s+ٳg$'fgeeaٳgܽ{2󎮮.B˗FFF8nll,DL"ȱC/E4ZnݻbGYYYbbbee%n)~e```jjW.\ ep8aiK9s vSعA|! cccW^e2΃rЏù\%h}9s{{{~mիjjjZ[[8qƍTD_|ۛ20̪*>/ڰ'zA 7nkYY.//wuu>ݻ_3cY>8b\ݻsLJ755=֏?8$$F8OINc5$~^nrtt$~Vp8O>6ϧP(Dd 8\?uر &|߿?>>^[[[[[{޽ c II˗~?TLL X,VxxyNsrrׯuqqquu N۷ocS~5h~[ϟW !m=\bŋ෥;,bh z | 8t|b7~[oKb$ܼySٌ6mi^u_tn  d~#̜9s֬YGN`̝;w]L^^B3Exl0SH"&t`<|#{{"H$,S u Q"lDfbCoߟa`fj5 ,gu+oZhsiEIW 'Կ72͛}]xxBRRɓ+OeGn(rtv]5bYYXm򦃶U>zKS. z)+}1\1z!(~'^^^+V(,,qʀj;aÆGkKJJJKKKJJl6y\u{)0o#5_-?7}DZ_A>>;;loo7nfGqI7RWQ[[QN=iQT-,'.\1Ξ`*!m=N/ ˖-5kֶmxGPϟ#/_f{xxA''~HEm4SRo LgZE] JDcHtH,23No۶m͛7'&&2La0YYYrǎꫯ.]} SRRlD"ٽ{ʕ+B( EIhhmۦNoرc*~7NS,ϴ(Zm-W-15i4O  'O$?Ù3g?㸸-[ $^^^ n֬YG #gdi>P++@#N81w\sssl& W4PNYgν?;^sAAɓ'+++TgBB Bhʔ) 2ʆޓ'O;waÆ ΎܑN!y~R%&4CܮI @ne܅<0044?< @>@| Rp8Cϗ.SGqDXG26(( _'|SS`?uTqqqMM̓ Ϝ9C9CE]tI,#~G*z]X,tҢEӉH$ڸq#rttM^7贴4www_]]=v{7n8q~322RRRX,֞={㣷_ Collllmm B˗/Ǻq㆝ĉ ݻWUUݾ}֭[8[rss|M]]]Mxr͘1P8A/Yo;wnYYY~~>1ZdLo6''g}Xb1<~&&&7|(00PXllM[o񨨨4u֦&w_?44W~B* 6bIOO(BfGDDD"UʋDgϒ$~F U(/5ǓF}M`񖖖~1AI`͘ՍLɓ'AxNP/$ 7ʺA{{w:::jbU߯uzcM7͆dc``}MM_^0@7Cm)oKрm9Q~[@u~[fm[R7~}[jH,T ~[#7 D"QV)) m nzzzNjee+I8p[n)ttokus:==${wܑ%oЙk XXXPTGGTb~[C7WlvVVB%%%͞=[<… W\\{v횴rK~Ƣ:&&:tPF&2p8x _srmll6t-hkk={N7`2ׯ_F!t:i_ B$jMHHHttGbqmmmXXLEڵK >O8\< !!!Am nbbb|}},Xb͛'S ..KWWj8s324 . 600wrr/qo.((b '-ڱcΝ;!& oSN>}]ک5l&,,L ҉dһ9 _ ~[ Џ~q%A7Y- m"~K tn n F6J4 \ @;ntn 4>IENDB`nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/doc/images/qtgroupboxpropertybrowser.png000066400000000000000000000132731455373415500322040ustar00rootroot00000000000000PNG  IHDRagF pHYs:duhtIME 4}<ZIDATxkPWODQ,C$xAܤUKPED bL^%: 2Ue* AaF!ZQKy7eI}ڜ=nys[@C@Ch 7+ j0h t*ʻ{r m޼!{P~ /SRR@C=!:T>|~4 hǏhT.^A!#qׯOOOG 0 %%%""433;z(Uk ڦ{zzUUUrPbŊ#F >|ɒ%!?~<ڴiL&Sloop޽{e2ƍY,NMM:M/2qD, P?|@;>l0@Et!!5]rE(GEEe˖EDDԸܹS\\z>tx<\(H*++oݺuM>*F;z˧O⍨)+++**H$$u4]C#Ԛ!:sP[[ۨQCӳ/++;v,BvѢEՊ-gvv BH,_!WW\Sveq4i! dѣk֬!tӧOL6 |H X@! \KKK>|cb:zh*8H4k,"%ŊSoذBѣG8ͩBMmUV^pS P7^|iggTVVJ$TD+ݧaaaN""8~͛q'?6iI.4DvssAq\]111;vXtҁQQQ/^O>p8<(((&&F"·7mt޽0(9SSSD"і-[n˔R"tȑ#k׮upppǧ500PU \.F׻DGG۲eզM]u&''ˎww"N0N[SSA84qD>OxVhH S-cz [[[sss6&233͛V__@ ,Ғogg`0ߟm N*={6??4Y yFQ,`s՜`! SNH$fff!\nooddduO0jJR@ݣ4-':hggdX,]B;P1>v1F^%---ZeoߖdR499pgr˘^!$$r硡AAA!\F :֭[P^^nnnM###̙[ [ !!!/88x߾}0>Dyl0H|4PDDLk>1ءVjT̗rccA̹8@744m083"HA/{j!< tSwY4PC&֐SII x<#N?ubIAAa;ظ`L0!44ѣGT;8k,%O۶m666111M?z9hڠLŧnP477744ܸqcƌ-/==]ܯ!tǏ eFM6)=d-={2e .ܽ{wvtt\vuJKKvYYݫMk8 z{}.?xΝ;J #2Ģ˗VVVVWWkU644߿֭$'Dݱ]#~d7odoqժU;wD_S)((h>>>D.T^:=vȑ#F|7}9xΝ;Վݽ{7''{ԞkF˸\O@@ _pw377ߟx~zWWW777??u)m۶XCK_~ݜחQA?~3g>S-Bc{p*r  ={+HN !>^ ۃ   AS)- ׯ_'[4SD\ l@Ch ! !44ՐH$Zfϟ\V/qjhڵƍ+// 'N0kR4ooggWWW7h r:ܬ;;;o<C'Nej˗#}xƦ̦y9::׫y|>bYZZx-SYXc Nq[>}=B`6 0?@+UJ{Q,d<o鸎{^^$2"k˺Ppp۷e2T*MNNPܻe˖ B@HgXf :Xn]BBByy7ѷdeeeeemٲH\.F wqq󡌌 ` ͙&1\Ы}{ !44@Cp @Chtؼuqiдi@Cmmm355!ٽwwF_r@ XTjR !СC[ZZTkT,2JzCз78DD_4yw!T`0v1 E1c2oE]jGE_ZXX~wx)7n۶N?DM}=aq((((;;oWVVTVVgΜ BgO?ɓ'!!!Տ?.,,hӽga\zCFX>93-$j*W >h}#}Lg>hA Ͱ4ٹgggg{{{;p޾a Mc4PRRREEEQQQMMyhӷAvv6Bx<___%S_t ;%&&^zUQzBS쬪rb899ZoiH)0Dx T[Xp8J/^+J%I\\\'ԣcZHHǏrCCC 6A3, q\pB qqqC qww>}Oc14baa?rA&ZMMMPPPEE.'4im߾}ǎvR8>D dsӧO4iUll,|=ԖZ/!kB14440Lb[q<Pͩ FCJhSwY4PC]M!AÀ$#A@ !44҄S^ 苌 QPW!@>!4`p)p]IENDB`nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/doc/images/qtpropertybrowser-duplicate.png000066400000000000000000000031241455373415500323600ustar00rootroot00000000000000PNG  IHDR38 pHYs u :[[tIME-uAtEXtCommentCreated with The GIMPd%n~PLTEwwwxxx! bKGDH3IDATx  jmWku[\hzҋ=ih…@_PW;NkF/ j^Nwpx*w9or2D;_dw  ܲ p Bph377 "lnǓ b "Wlu4ڧmvcSc (ۡg"l$-w Se(KWH @ lj jC  |A !x/'@4Epx J8|@G߈ 7@(E0 zP,\ hE=v@%t p_zC[AG/;MVHA8k 2ƂQlAat8 g+5I.f`;{EA1j4lF(Ef&3KߝbK/hFQ?j}mqt=" kU ;`.trM k֍#AAh=$1G0:x-CiUbK^hl^c*@(b.+EA<Ԣݧ9ׁ #hDGH-}:mH-} LAP4RGjirrg6H`]CE^)GP@@Ou](EOBa4Bl本S$ ϶SG1!+ ,^jTA4Cqb8vm~(>i B 7{EA1tT"P`SUe%"[-r3X)2(@:Dsi~Iu#K;7/#Q?[6B0>eU/"`OYF?iI5vfvcC:S^GP@@Ou](E s>3Y`ʍ>wץI[&5;Bj#t`JH]O6\%5p]@GT[YPUT"P SE~"PNkƃv'\AIENDB`nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/doc/images/qtpropertybrowser.png000066400000000000000000000227151455373415500304170ustar00rootroot00000000000000PNG  IHDRY7%IDATx ٿ$jTvQAD>5@peSx$OQ] , 3 B@RtWOtWt:oߪv߷~dIi2/ }LdB_&2ЗɄL&eu?Y*WPp7w}}zDp`wdقs~cO/ aQv)),: =a#FoNi)pA~yxf&їn=-%>{<<ވy{}Fuu/vw#;꾡+(sveUOv;Mwԭ[7-#<(SCc/KA*U }C.ٻ 'OQA(<" <>ʔaz0">ݎ~W앸Fѹ;-cO~ͷz픗\{-ͷP6Ͼ5k5kv?f[ 7բ#P0v+S g^^MۢG0OL7NRCg.z=f<5a}(}{xͪ}C@9y_]<|5Ok}vfm߾yy{~tx{CfZjpspͭ}1s61Lկ vW0gWffϜ5VZ S^xy-eK+$-oq7&~M͋Jߜ`3,)' =w=G2#|_@lzcVgceZʮ30jلY,<sÇ mݥ/I'ut08GM A-Nn.n9}W7jD}/5ӗg[2u;}={1/ЅЏǜK?k0)07~&N?{1= g2yg<;̀_:/O`ct>d^>P#lkqzʂ͇9uf9~rWA\̃6=9ώFa@o.Bf@ }?d^:`~$>hq>~$[qo;B_^n˅/B_+ 1WJ2YXL/El|f_L }/B_'8apϞ=Z#-R2eʞspL/+-nP xDY[nAwEpW\iq6mʻtM˗/&==Kk׮.2r 57nuv7RM0իRÇǐ08qk _rWO;vطo]v >lff&5wy;rHZ?%5<СCsrr֮]SOG}kz=0|ӆ#̙3Ϛ5 )Bg -gA\ h:sԠ+KP(MexHɚ6b_K }߹s'رlG3<}v t/SL^z{7̰q)%֡CF -21 YYY N:у Ò.]<+V ֳ%Ljժ/޲e * BgcA[ʆרQ?5k,7oܶm[]4h0j(j#A?/|Ȑ!dzw矛a`Ki4?%~-55 ЏwE'G]] ~QWB_ }/JPUF|1/ɇ#.O2YiZ`k_UO^&,˻뮻XֲeK2X,bE Lb!5|i3z:u4oޜ,mXjrA?+pd'~"N43f Ѡӯ_CM>1]niӻw#G5ZSJJJhYQ:y }p.]zĉy]xB?g52& ܎ӧMyǎ_s5$O olC&h8sV.cNcرw֍+} DFDb%M6} /2&hDȏ1'o>cRnjcJz"CqtO?>i۶m#A5 ؾHܹW>FMӧOx3ș={6B >Dî޽ǰ3MԖJ#|dZ{-##E~ڗ 'O=S[&Lj7n 72Ha>4_z%\RvK}@nAA6(cU͈Izlolɒ%dO7tBGK]'XQeыa_|gQ6mZ4͑FT^&$9E&^4 xoԸ KQY,]0},*D>r6m2 ^ m/}xwKGzǜvڑGx޽{(BGEGk*ѧJ<7}U38p _.eܦO)dCb7Þ^B?ғ>dժU{뭷B:,:]S1}f+W^zu4h"HL9ClFv h,k׮[\C<\i^B?ғ>dCƍǖG8)}|ruD_ԙyl ]"z0Q[/Ŧ6lȍqVZ%;li}on\2.B_ }/(x 1B_JKt/WB_ }(zR8h Ilذԗ#Y-e,7g-' VOc,"|o[X͖h2(Bg RB> I4XhQ!C2a„x볲LΊ-e,>}2-SQnC7|6<..H]=٧LjI0jl[jU{'tiЏ1Aӊ$\?nkϹEs޳5 _ZB_˄З }/B_}.W,QcRoi\] }/B_'2ܒ[κ!+rD?Dܮ{K } oqʔ)^{Q~.{fϞ}8j }u}/b2{KB?%l(++Vw, 07Ů.B?aL_,~WPlBOL]] }EY$( f rJKWZzh~ }/O *'5dB5lДY2|ΨYٚ_9EfLO!T9٥%4iNaڴip崴M:RP}WOv{=f zԩ3S B싱^#]]];ژK~З/7+ HIϚ5K.V}vdeeu=իWΎp+E_>n۶mpn0ͭVYП8q"y)EwF<7n\ݺujZ_/pu_OB{ʕ5j4c /eB_˄З B?+ՅJP%JbW*--=+'ՅB_ }/~D?@; t9Xx`ޣt|/RmDQ#,O(XF}KG?"&r3]=8iҤǏoXw W~h@׿5ںǎcQ>Q۷of ~?ըoFӺub@THA:IFO:+cǎ%1[n$؅ dM=@%NhjX(I:p>}.3-\(^ٳE?`,nՓ@e}>z{|/Rm@? }z|} Ϗ?tr}7d5,`th~jRvE_F hG} MtN-4WHA:IF9+ r x֭[(;Fj47Sb駟v \r|eo~3!I:zSƲx%3 ~_er|/RmN>S[L7nc{TYEP  }З,WB_ }8gB_ }EYNPJVZz }/O&Svf ~ SP$yu !,~O$zXl)f;WA^zhFpJlɑB?7e)((}FN&cWAQ DM6UW]%~/_E$˚憇.NAfh tW2V'}/B_&L }2'{p%(.AҕhiB_ }/B?яOE B[ʢ{^ qzX\lSJf[`;RP#E)n~LQ󸕂b)(ԩS [ʢLV&JA1y9 }2EhʼnRPky= 4͊QǕs=Ǘ!4WQ?ǕqߜhVOd_ZB_/eB_/eB_VQ_IqF}B+-=~,Q_-WO]䰼tJA?<E.V*Tt+pԇw$'aÆ$45nx̘1v#rq6mo&V#[*k&'ԤB|*Z]D8TRe=X'NP7oN$O-^25{)W|}V Ϝ9lZ }Q{,!ɯEg YrLGydС999d6AԈ(m~Μ9֬YP2r,Y\۷sQAs;t2W gO<ĺu vȡg=`7Yo\N ,DK976bĈ5jЯQ4W7j\233Gնm[2(CU.Rw=u X VZKwbGcN>iӦ1?>EtԩG ctҥϊ+-K?/RP4-Z0 HwbGN>S[&L:;&rh_A oC733:C @?q"EALs!/[k>͕bŎˀ]_+k!WB_Q_ }E}/(W;2 B_wdPɀGM!) 1="ZZdُ)U7FYgD]~y&b&MPO8F!2kך6m>KA1r>Ɏ>9Y,@z!Kyʬv\,daI+7Y݉!Y5/ਫ';d6>{…͚5З_~i߱cGpII /Q_~>}:_Зb;Ɏ#G`{֩Sg޽PoOJ 5N>Eto@ & =ֹsgB;K374ȵQ V9Znką~jժF1?ѿ̐/֧Oú]Aw9{,sqfժUPa ^hիWF dI7}G_ w pE?#+ՅO@Sӳ]] D?eg }胵B?Ƚ eW,[떕(K{t'y_l }t0Ww xC?FB?ЏzYVٱM(IFjʊ#G?F}/#GZl~OEn?/Zn,WP`0.3ryRwA_&K`2/ }LdB_&2З*RIENDB`nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/doc/images/qttreepropertybrowser.png000066400000000000000000000161221455373415500312720ustar00rootroot00000000000000PNG  IHDRM"U pHYs:duhtIME 0w\IDATxy\G{kfHʪkэF%Mh!Fb(Y]W 5nb4 1 ^cTGvVax롦z8:@/@@@e+:&QOZ'Bp8999TCQI~wO8X넜Eq83izE!ɝd777UuiooG:r$˒^?)I2uhZG3@:xZ777 Zr`jj뛜e}k=---33s߾}2F5sLDF<~DžC G:˗/7(//|rHHZ S^x7&ݾ}hnjj?󛚚j)))nnn 22ĥRiBBB~AxxD"?-Jr\.յTkiiׯH${2I6225kuRSSÅBaHH=i.>T[E^SSsssjkkiNLL-//_f SҥK.]~P(\nYYYw544\rib1EQbX,[XXL6mϞ=ZffMO:MӳfdѣGf w^qqҥKeZLMek+77wΝL|ڵdȑ#III<oذ!##~z>֯_a߿MMM?d޼ykiiiɓAAA=Hj{%8q+W̖-[v9 ,:u)ekk˔E"3tqq! ɉɨJMGi4lذGN6ŋIII=###'Mpv}Qsrr )bHT[܇Queb|]]])*++^vѱ@ 8uT>}ϦϏqtt544;;;:4##Օ鰰1cp܆755ݛצ&؛˖-DLxHDӦM#񰰰蒒֛7o~ Okaaq]fs&&&WcBTTSSSHw_ps˖-111L\Yn1^/] 6>>>?d>K~o@@cDDĉ6**7xHeeiۛ 6Dlْ4uT???yǏ_ĕVǵa#o߾t>/:h޽˖-ߤuuuG( &988ĉaaa0^)O•=ڽ{#Gcat6&-*օBaJ$k[dhZGuhtE"D"Av:SSS$˒F>>>?΃$wAh}رcǎE:W"ɝMII {k]Z:slg] FY[] /A{gä3ر$^ZZ:ess޽{O09dÆ 4<<ӧ2'lkk511 e<}t̙vvv:NNN?,cgϞSL={6 N4i\hS?++륥+W9[RRRNNN^^^UUђ%KH|Ŋ"ܹs:*׮]˓J*(PJ=~I\&&,K$HAI$2Úg޾}Af:saa!) B:M)%{W\Q1 esf 0ܻw/%%mllHĄ遮^GR߿d)WUU%srIR=ukc^Yŏg [М*+y^,j1/Dd1Cyд;mLITzi{&3`F66ׯװQuM5yS"Hkd: XVҮVor:?~/;čR/jd+h37ny-)))H Cj^+~u(+ oq}Wv[p?8Paq zh0 4 e5k5b11|37JE>½uώ' v\ÊG-Eq h0 `< %ux};^}L 8zClJjI\򴭯!SOG0q6/4ַ4֟/pֵJ ),,J  DN^x. ~[6q9[ݗἚ!6u6/{w56u?`ʘ:ujHHȭ[Appڵkajjjx<{oMM s~ïPOϭIϭay53k3kNj B4:EQUUU*.#z6YDB&<:ݶ_'wf1Ōn<Є[j̟Ҵ ߿?na|0/IC,[*kX_yI+! PJ.ucIի9Щ(:Bs8]v#? ڕu 7Mi_/#ig;Ecu_ߵkƍ;]>}믿3KQ&ɓ'N(jΝEEE.\ kP `{ȱډZǏGEE1i*))䓥KJM6LL HN:"YI=*-޳g:EQfff \.'O0 cuwNԿ^{M۷C뉛)1bݻnݪQ~>uT'9Z[ڽҒ\segg3/r_p8oe LϞ=[[[6o޼|핕۶m[jՊ+T(KKKbN2kO,f?p啕˖-c(9Έ#ȋĉnnn$>rȌ RoE0kך1mmmIII~ӯMs?3KKKKK%K3Fy1I^X-oߴC yȱڄ)jtSȽݮ?VK}쐻… ίjTTTM&R<<<<<<֭[ǼJ,9vEY\fbܹsܮ^Z\\o> hGcǎs޼y3;;<""ڵ˗/>>|m248˗/_.J[[[W^/ꫯ:::1b˖-j?Q{I&yxxDFF*IOOONN(k֬733[|ɓ'!_͹~UԔ<:q//ݻwϞ=Fׯc[nڵ+33s~6h>%%ŋK;v1c888ˋjtRxxΝ;G̓2[EË́ 8{瘴7ph=^ K.b---s]n=S-''ÇB"քǏ'iii bL:fΝ۶m{_'xϘ1ʕ+O>ۺu'{ŋ{Ç3>(&&T*޾}{޼yб&a>Ŏ~UUUBpHEŋuuu}Qaa͛DDDܺuK*EGGO4IOر7======66̟?VUUyxxDGGCjYjEQ_Ƚ{LMM?9>(3lڴ)..,‘]wN eb>?y丸8 ?G`)s : 5H$|S#th@@D^9!/]py$t6ߴd/GKҤ_wqqqss#j)6dzS^ygggv+VDs1fplX};;;4*cp]R&u3QUSStx mP_qssc2̗T_)x~\d?ё㏁25B!ꙿ666`bb"J9{wN"Yl_Req1a0F'7bĈ>lE=:&&ߟԴg^yG:t(!\f8롡ΝF~iBCCE"Quu y3gx{{|IU.4 'O4-;Œmmm0>"[7 I2_R~ 5}sa)~M_)u7ߐ8_:uzsIu~$emMѮGIeWa~Qg͚uӧ#eiO?+55|󍏏رc?`iۨ֎nذA,?ʕ+]/^ܹ3~E1 eAF{|lرc666<O{699822P6Z6}u"wͣ^iuu#)3)kShh7:3!j}O|H)sZAN2eʕuuu jOhaaq=nvzc.Ydfffs=Λ7oܸqD .Oum%|7vCPf%T9v tٲebz&L@S9^www???sss6^ׄ3gΜ9M_uXov) o @@@@@@@ZZZZZZZZZZ::::::::::uuuuuuuuuuhhhhhhhhh@Hx7݋ݑ8q-fN}}={wvvvqq1wwwZuuzEǭ *IENDB`nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/doc/images/simple.png000066400000000000000000000225141455373415500260500ustar00rootroot00000000000000PNG  IHDR\ pHYs u :[[tIME 4-c$IDATx{՝ǩJ%*&CS[5Ѩ<p@`E|#` D4(b &q$XL_[&Z\3IօwO7lŒI&M8qlOIN?fFub(<QCh%ZjN<-\" B_7Y+Ay)R(JDa #/<)|yLAL}8vP|ߦ$O-N;_ߏ3eP#[OeŊ8KIlÇN? _О2pQ@,Fd8Xjb]i wy海Ouq'.}aܕGDEio Ok7._;~cqEo]GNl(l5JlHl4@D̤_v/%Vx-\~;u:(x^h鳯񹓗ұ>C=tݿ.| ep7hᯟzݡ(ҰW{<{Ʋ"ˋ`}gDYH 5A![ӮoθOI?ƞd%5hszߌbtD`Q~/bKۂT/ 8jR(VDˋQ.U[+||Wv:RCuP`/n'OKQzY?'V?pϺ귳Xבj9?%p 8mT4H=W'GXKH 5Aa֏{q <'Nu +i&8ɴk9UC:(X;w8'F?(irfd3Ƹ (qݎwB~( B( B( B( B( BO(tvvv <BAl@ S'k(͐,x}~7<֭ e[[~Yt{"ڳO`AAb/W(p>|&D~uA4 }[~9 Z'Ѻ(lߎr O@aۻ. o`\'ƛj]z_C (lx+!CDJ Bm/@k{lyȇ  Mۜ򐐚QA0.TԮkQad C}ܤCt̏/Can >n #H_JW0=d~L}q lԺ(l1& K +H-a(8{&WzG0DPX)-Lz.VHWta(i[Q3?v PzGuw3/fy}xp}@>L ~Y2|eR=nx;DQ="wh4"S@@) P@d (e CBLay+qV^LPQ"S@@) P@d :N,x^ $S 9\x=tVx@Pu(įҹіD"RܤB<Ԥ(7qHPi(~ )L(T Ҿ@4]s#i*I)|sDP-~ d @2 d Ef PQb4gќP@<D"S@@)!(;P>s={,embڗެvuê9cW\LALXJ-鑳8 pPPlwGoRmP(y j/ ,N2Š EDWVbqyldYs L(h 2ÄzfBF^APOݻ^qP^ON .TXV(4"S{25:SHSu_@顠X+ ̫%Sh8vTPH{= i;UG|T S( ;eJFpuaG6hv4*n%fa#+Z{dյ\%Sp{ +3,{mK9~xW)C.]kS2C"S@@)  hΈ[9#x LD"S"0*'7|z"LBPU;4J~<鵙P SnB53d@P S >22@L(H*$M$SKP L( @P S ())0$BEќ"FsF@ LDfT7/PvPxg_ tױ(T_?P (P (T oMCb!Tg2p+*J@P@@P@YGB!~'I\o^5Q2|=$r oGA!~i۵B e ttdIs%ՠغrM ՜f @ۇݰPT/vI] Mh| 5P(98((fixS&Τu-*B61B^־Ba޽ %J2Bg!eCA<&)((Z dX8չ:SHƹC.B %n젠͟K 8 @u()է<RuδhT>d{K=7H2 (x=)0 SU-p%;ZFA%`&y}7 Sʃ w (Pp Pñ9dVT( P!(l{m @(  @(4$0"H hyHty)@!7(HkiYȡoi ,oLBE%v(PPw!BU`d (܁BnP&B߻p B{ –m; r\P (P (T ojplUh86pDZfV%`oj 0P @[AgI,CP(NFAa@,X *\Bo]U>Bo[7[P@ HCANA/ "";(۷/Lȴ` Pr0i90g T5" "9BAk`ymr@ars(hg)G@LPxoPL!/hD4P /٣Ss)|L$M wS@ sA CasZܠ SSٵ]*\bxףػ@ :%/ M> wPK@+JAa@kP (T  $M3Bo ;I ܊B6P@@RPئ5P@@ZPN*Z  (T =i FI#{o 8* |{& 4P^6՗2A!6m1`(l(dա!BRH߾PL )3v`i+]_7 (lݪ5Ph6<0f\Ju_vIߡ}H ByOܖ [ r\ P (B١ݳEkP( PñukT(0~bVP@@P@е_kP bIME)nHG]zV l+7wvἎE6(i%Dmdt!igr{y7fj,P(pY ~L>0&PK y"FKꍃBlon(}2e:}UlVWHss(4"SP[ f;&l(8 {.(ɘ)h/0钮D>AAk&KЄ- }Z dj6` (H/wCMB}."Pp ejNBkxj5KBlv  ;eJyǛ+Ѥ1co%,RuJNv[<)c(O4jV!C7Q%\BsS&( ]  (BWkP( Pñ9dVT@T{ (BuУ5P@@(#mW&Hw3;f^r@( ҋZƚנ]@(PDy%/ 6h 4FHU"~ E#o(o(Re PP_BA˩F) Aa@(Hc D|3sB|a>P h/1)]@/+PX~@JA[kP (Pp Pñ9dVTkuk P (P (0lNzKM6-Dv #5Ns.Bh\EPLGI+ ύf3KB&6Ay@a@!⧾6/Ց^,vջe5tHvPp=Y_ؓ"$-d`qO }@( rTP0[l w#2v D, BIz ~FuYw4jͫQ[k6h 4\ɁP @(d P@@(P ( fV(  (   ^o``i$2'is6#:&Am2Y_.\ @A+gdBb{'Bu 餀Q_q%!ZMgOB `HC`X@A}aO -(cBS,PHMЧPM00  CA= ;B:˧hLJ4]} I[1I)'S ()P S S@@LL!*Jf (9)p`*Jd ( 2 L0s z+V͜I) d d P4<9U]XRln:m02`&7 22PHۛC$HVd d @(i=P S )z ~FOn*7>$S OP S ()) @@3Cb!T1p+b4g}@@OڶmmEC=ܸ>cP &L8#>O̜9"S( 2,xyᔥ&(g>k퓟dooa7Sm4&i%S eHgl(~=(+U]S__ߧ>o~Ň_y DLy W^yꫯ^jU|aq!f?( P@d ( 2gCw+ԏo{DxP9eHCRzqKZ@28{M7i|@ЌC'.ԁ1Gf9r ^Ȑ¯> kf +IK?\* BV($t{V_@PnB>ܡDEƞ>4O(7|Wk#qPPT u~S8paRU GP۲Z. 9Q-ěGP8r"ʅ~a(g * ]Z*뻵 (T l( P!(7qX%Dh*<[QQ2t@# 凂O! @80@ S(A`nHFPpn<2]-MrCG(87B lFSeA{ B6B\ŌPۇR>$-)}i C*L!餯 O MBx` OLPP\ +LJ. BmЄ f Ppn<2)ѨmaB80ɒPpn< P@BN#>PiC"i/E/6pu!O$6C`N) 2'=BeP@P@P@P@P@P@Pv q-P0ƸY݁ߧG IENDB`nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/000077500000000000000000000000001455373415500236515ustar00rootroot00000000000000nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/CMakeLists.txt000066400000000000000000000005701455373415500264130ustar00rootroot00000000000000 INCLUDE_DIRECTORIES( ${${PROJECT_NAME}_SOURCE_DIR}/src ) # setting a common place to put all executable files SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) ADD_SUBDIRECTORY(canvas_typed) ADD_SUBDIRECTORY(canvas_variant) ADD_SUBDIRECTORY(decoration) ADD_SUBDIRECTORY(demo) ADD_SUBDIRECTORY(extension) ADD_SUBDIRECTORY(object_controller) ADD_SUBDIRECTORY(simple) nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/canvas_typed/000077500000000000000000000000001455373415500263315ustar00rootroot00000000000000nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/canvas_typed/CMakeLists.txt000066400000000000000000000006361455373415500310760ustar00rootroot00000000000000# Tell CMake to run moc when necessary: set(CMAKE_AUTOMOC ON) # As moc files are generated in the binary dir, tell CMake # to always look for includes there: set(CMAKE_INCLUDE_CURRENT_DIR ON) SET(example_name canvas_typed) SET(KIT_SRCS main.cpp mainwindow.cpp mainwindow.h qtcanvas.cpp qtcanvas.h ) ADD_EXECUTABLE(${example_name} ${KIT_SRCS}) TARGET_LINK_LIBRARIES(${example_name} ${PROJECT_NAME}) nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/canvas_typed/canvas_typed.qdoc000066400000000000000000000100541455373415500316610ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ /*! \page qtpropertybrowser-example-canvas_typed.html \title Type Based Canvas Example This example demonstrates how to use different QtAbstractPropertyManager subclasses for different property types. Using this approach, the developer interfaces with a type-safe API (since each manager has its own property-type specific API). \image canvas_typed.png The example presents a canvas filled up with items of different types, and a tree property browser which displays the currently selected item's properties. All item types has a few common properties like "Position X", "Position Y" or "Position Z", but each type also adds its own type-specific properties (e.g. the text items provide "Text" and "Font" properties, and the line items provide a "Vector" property). The source files can be found in examples/canvas_typed directory of the package. \section1 Third party copyright notice The canvas class used in this example contains third party code with the following copyright notice: \legalese \code Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of Digital not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. \endcode \endlegalese */ nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/canvas_typed/main.cpp000066400000000000000000000041731455373415500277660ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #include #include "mainwindow.h" int main(int argc, char **argv) { QApplication app(argc, argv); MainWindow mw; mw.show(); return app.exec(); } nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/canvas_typed/mainwindow.cpp000066400000000000000000000430621455373415500312160ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #include "mainwindow.h" #include "qtpropertymanager.h" #include "qteditorfactory.h" #include "qttreepropertybrowser.h" #include #include #include #include #include #include void CanvasView::contentsMousePressEvent(QMouseEvent* event) { handleMouseClickEvent(event); } void CanvasView::contentsMouseDoubleClickEvent(QMouseEvent* event) { handleMouseClickEvent(event); } void CanvasView::handleMouseClickEvent(QMouseEvent* event) { QPoint p = inverseWorldMatrix().map(event->pos()); QtCanvasItemList l = canvas()->collisions(p); moving = 0; if (!l.isEmpty()) moving = l.first(); moving_start = p; emit itemClicked(moving); } void CanvasView::contentsMouseMoveEvent(QMouseEvent* event) { if (moving) { QPoint p = inverseWorldMatrix().map(event->pos()); moving->moveBy(p.x() - moving_start.x(), p.y() - moving_start.y()); moving_start = p; canvas()->update(); emit itemMoved(moving); } } MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { QMenu *editMenu = menuBar()->addMenu(tr("Edit")); QMenu *newObjectMenu = editMenu->addMenu(tr("New Object")); QAction *newRectangleAction = new QAction(tr("Rectangle"), this); connect(newRectangleAction, SIGNAL(triggered(bool)), this, SLOT(newRectangle())); newObjectMenu->addAction(newRectangleAction); QAction *newLineAction = new QAction(tr("Line"), this); connect(newLineAction, SIGNAL(triggered(bool)), this, SLOT(newLine())); newObjectMenu->addAction(newLineAction); QAction *newEllipseAction = new QAction(tr("Ellipse"), this); connect(newEllipseAction, SIGNAL(triggered(bool)), this, SLOT(newEllipse())); newObjectMenu->addAction(newEllipseAction); QAction *newTextAction = new QAction(tr("Text"), this); connect(newTextAction, SIGNAL(triggered(bool)), this, SLOT(newText())); newObjectMenu->addAction(newTextAction); deleteAction = new QAction(tr("Delete Object"), this); connect(deleteAction, SIGNAL(triggered(bool)), this, SLOT(deleteObject())); editMenu->addAction(deleteAction); QAction *clearAction = new QAction(tr("Clear All"), this); connect(clearAction, SIGNAL(triggered(bool)), this, SLOT(clearAll())); editMenu->addAction(clearAction); QAction *fillAction = new QAction(tr("Fill View"), this); connect(fillAction, SIGNAL(triggered(bool)), this, SLOT(fillView())); editMenu->addAction(fillAction); doubleManager = new QtDoublePropertyManager(this); stringManager = new QtStringPropertyManager(this); colorManager = new QtColorPropertyManager(this); fontManager = new QtFontPropertyManager(this); pointManager = new QtPointPropertyManager(this); sizeManager = new QtSizePropertyManager(this); connect(doubleManager, SIGNAL(valueChanged(QtProperty *, double)), this, SLOT(valueChanged(QtProperty *, double))); connect(stringManager, SIGNAL(valueChanged(QtProperty *, const QString &)), this, SLOT(valueChanged(QtProperty *, const QString &))); connect(colorManager, SIGNAL(valueChanged(QtProperty *, const QColor &)), this, SLOT(valueChanged(QtProperty *, const QColor &))); connect(fontManager, SIGNAL(valueChanged(QtProperty *, const QFont &)), this, SLOT(valueChanged(QtProperty *, const QFont &))); connect(pointManager, SIGNAL(valueChanged(QtProperty *, const QPoint &)), this, SLOT(valueChanged(QtProperty *, const QPoint &))); connect(sizeManager, SIGNAL(valueChanged(QtProperty *, const QSize &)), this, SLOT(valueChanged(QtProperty *, const QSize &))); QtDoubleSpinBoxFactory *doubleSpinBoxFactory = new QtDoubleSpinBoxFactory(this); QtCheckBoxFactory *checkBoxFactory = new QtCheckBoxFactory(this); QtSpinBoxFactory *spinBoxFactory = new QtSpinBoxFactory(this); QtLineEditFactory *lineEditFactory = new QtLineEditFactory(this); QtEnumEditorFactory *comboBoxFactory = new QtEnumEditorFactory(this); canvas = new QtCanvas(800, 600); canvasView = new CanvasView(canvas, this); setCentralWidget(canvasView); QDockWidget *dock = new QDockWidget(this); addDockWidget(Qt::RightDockWidgetArea, dock); propertyEditor = new QtTreePropertyBrowser(dock); propertyEditor->setFactoryForManager(doubleManager, doubleSpinBoxFactory); propertyEditor->setFactoryForManager(stringManager, lineEditFactory); propertyEditor->setFactoryForManager(colorManager->subIntPropertyManager(), spinBoxFactory); propertyEditor->setFactoryForManager(fontManager->subIntPropertyManager(), spinBoxFactory); propertyEditor->setFactoryForManager(fontManager->subBoolPropertyManager(), checkBoxFactory); propertyEditor->setFactoryForManager(fontManager->subEnumPropertyManager(), comboBoxFactory); propertyEditor->setFactoryForManager(pointManager->subIntPropertyManager(), spinBoxFactory); propertyEditor->setFactoryForManager(sizeManager->subIntPropertyManager(), spinBoxFactory); dock->setWidget(propertyEditor); currentItem = 0; connect(canvasView, SIGNAL(itemClicked(QtCanvasItem *)), this, SLOT(itemClicked(QtCanvasItem *))); connect(canvasView, SIGNAL(itemMoved(QtCanvasItem *)), this, SLOT(itemMoved(QtCanvasItem *))); fillView(); itemClicked(0); } void MainWindow::newRectangle() { QtCanvasItem *item = addRectangle(); canvas->update(); itemClicked(item); } void MainWindow::newEllipse() { QtCanvasItem *item = addEllipse(); canvas->update(); itemClicked(item); } void MainWindow::newLine() { QtCanvasItem *item = addLine(); canvas->update(); itemClicked(item); } void MainWindow::newText() { QtCanvasItem *item = addText(); canvas->update(); itemClicked(item); } void MainWindow::deleteObject() { if (!currentItem) return; delete currentItem; itemClicked(0); canvas->update(); } void MainWindow::clearAll() { QtCanvasItemList list = canvas->allItems(); qDeleteAll(list); itemClicked(0); canvas->update(); } void MainWindow::fillView() { for (int i = 0; i < 10; i++) { addRectangle(); addEllipse(); addLine(); addText(); } canvas->update(); } QtCanvasItem *MainWindow::addRectangle() { QtCanvasPolygonalItem *item = new QtCanvasRectangle(rand() % canvas->width(), rand() % canvas->height(), 50, 50, canvas); int z = rand() % 256; item->setBrush(QColor(rand() % 32 * 8, rand() % 32 * 8, rand() % 32 * 8)); item->setPen(QPen(QColor(rand() % 32*8, rand() % 32*8, rand() % 32*8), 4)); item->setZ(z); item->show(); return item; } QtCanvasItem *MainWindow::addEllipse() { QtCanvasPolygonalItem *item = new QtCanvasEllipse(50, 50, canvas); item->setBrush(QColor(rand() % 32 * 8, rand() % 32 * 8, rand() % 32 * 8)); item->move(rand() % canvas->width(), rand() % canvas->height()); item->setZ(rand() % 256); item->show(); return item; } QtCanvasItem *MainWindow::addLine() { QtCanvasLine *item = new QtCanvasLine(canvas); item->setPoints(0, 0, rand() % canvas->width() - canvas->width() / 2, rand() % canvas->height() - canvas->height() / 2); item->move(rand() % canvas->width(), rand() % canvas->height()); item->setPen(QPen(QColor(rand() % 32*8, rand() % 32*8, rand() % 32*8), 6)); item->setZ(rand() % 256); item->show(); return item; } QtCanvasItem *MainWindow::addText() { QtCanvasText *item = new QtCanvasText(canvas); item->setText(tr("Text")); item->setColor(QColor(rand() % 32*8, rand() % 32*8, rand() % 32*8)); item->move(rand() % canvas->width(), rand() % canvas->height()); item->setZ(rand() % 256); item->show(); return item; } void MainWindow::itemMoved(QtCanvasItem *item) { if (item != currentItem) return; doubleManager->setValue(idToProperty[QLatin1String("xpos")], item->x()); doubleManager->setValue(idToProperty[QLatin1String("ypos")], item->y()); doubleManager->setValue(idToProperty[QLatin1String("zpos")], item->z()); } void MainWindow::updateExpandState() { QList list = propertyEditor->topLevelItems(); QListIterator it(list); while (it.hasNext()) { QtBrowserItem *item = it.next(); QtProperty *prop = item->property(); idToExpanded[propertyToId[prop]] = propertyEditor->isExpanded(item); } } void MainWindow::itemClicked(QtCanvasItem *item) { updateExpandState(); QMap::ConstIterator itProp = propertyToId.constBegin(); while (itProp != propertyToId.constEnd()) { delete itProp.key(); itProp++; } propertyToId.clear(); idToProperty.clear(); currentItem = item; if (!currentItem) { deleteAction->setEnabled(false); return; } deleteAction->setEnabled(true); QtProperty *property; property = doubleManager->addProperty(tr("Position X")); doubleManager->setRange(property, 0, canvas->width()); doubleManager->setValue(property, item->x()); addProperty(property, QLatin1String("xpos")); property = doubleManager->addProperty(tr("Position Y")); doubleManager->setRange(property, 0, canvas->height()); doubleManager->setValue(property, item->y()); addProperty(property, QLatin1String("ypos")); property = doubleManager->addProperty(tr("Position Z")); doubleManager->setRange(property, 0, 256); doubleManager->setValue(property, item->z()); addProperty(property, QLatin1String("zpos")); if (item->rtti() == QtCanvasItem::Rtti_Rectangle) { QtCanvasRectangle *i = (QtCanvasRectangle *)item; property = colorManager->addProperty(tr("Brush Color")); colorManager->setValue(property, i->brush().color()); addProperty(property, QLatin1String("brush")); property = colorManager->addProperty(tr("Pen Color")); colorManager->setValue(property, i->pen().color()); addProperty(property, QLatin1String("pen")); property = sizeManager->addProperty(tr("Size")); sizeManager->setValue(property, i->size()); addProperty(property, QLatin1String("size")); } else if (item->rtti() == QtCanvasItem::Rtti_Line) { QtCanvasLine *i = (QtCanvasLine *)item; property = colorManager->addProperty(tr("Pen Color")); colorManager->setValue(property, i->pen().color()); addProperty(property, QLatin1String("pen")); property = pointManager->addProperty(tr("Vector")); pointManager->setValue(property, i->endPoint()); addProperty(property, QLatin1String("endpoint")); } else if (item->rtti() == QtCanvasItem::Rtti_Ellipse) { QtCanvasEllipse *i = (QtCanvasEllipse *)item; property = colorManager->addProperty(tr("Brush Color")); colorManager->setValue(property, i->brush().color()); addProperty(property, QLatin1String("brush")); property = sizeManager->addProperty(tr("Size")); sizeManager->setValue(property, QSize(i->width(), i->height())); sizeManager->setRange(property, QSize(0, 0), QSize(1000, 1000)); addProperty(property, QLatin1String("size")); } else if (item->rtti() == QtCanvasItem::Rtti_Text) { QtCanvasText *i = (QtCanvasText *)item; property = colorManager->addProperty(tr("Color")); colorManager->setValue(property, i->color()); addProperty(property, QLatin1String("color")); property = stringManager->addProperty(tr("Text")); stringManager->setValue(property, i->text()); addProperty(property, QLatin1String("text")); property = fontManager->addProperty(tr("Font")); fontManager->setValue(property, i->font()); addProperty(property, QLatin1String("font")); } } void MainWindow::addProperty(QtProperty *property, const QString &id) { propertyToId[property] = id; idToProperty[id] = property; QtBrowserItem *item = propertyEditor->addProperty(property); if (idToExpanded.contains(id)) propertyEditor->setExpanded(item, idToExpanded[id]); } void MainWindow::valueChanged(QtProperty *property, double value) { if (!propertyToId.contains(property)) return; if (!currentItem) return; QString id = propertyToId[property]; if (id == QLatin1String("xpos")) { currentItem->setX(value); } else if (id == QLatin1String("ypos")) { currentItem->setY(value); } else if (id == QLatin1String("zpos")) { currentItem->setZ(value); } canvas->update(); } void MainWindow::valueChanged(QtProperty *property, const QString &value) { if (!propertyToId.contains(property)) return; if (!currentItem) return; QString id = propertyToId[property]; if (id == QLatin1String("text")) { if (currentItem->rtti() == QtCanvasItem::Rtti_Text) { QtCanvasText *i = (QtCanvasText *)currentItem; i->setText(value); } } canvas->update(); } void MainWindow::valueChanged(QtProperty *property, const QColor &value) { if (!propertyToId.contains(property)) return; if (!currentItem) return; QString id = propertyToId[property]; if (id == QLatin1String("color")) { if (currentItem->rtti() == QtCanvasItem::Rtti_Text) { QtCanvasText *i = (QtCanvasText *)currentItem; i->setColor(value); } } else if (id == QLatin1String("brush")) { if (currentItem->rtti() == QtCanvasItem::Rtti_Rectangle || currentItem->rtti() == QtCanvasItem::Rtti_Ellipse) { QtCanvasPolygonalItem *i = (QtCanvasPolygonalItem *)currentItem; QBrush b = i->brush(); b.setColor(value); i->setBrush(b); } } else if (id == QLatin1String("pen")) { if (currentItem->rtti() == QtCanvasItem::Rtti_Rectangle || currentItem->rtti() == QtCanvasItem::Rtti_Line) { QtCanvasPolygonalItem *i = (QtCanvasPolygonalItem *)currentItem; QPen p = i->pen(); p.setColor(value); i->setPen(p); } } canvas->update(); } void MainWindow::valueChanged(QtProperty *property, const QFont &value) { if (!propertyToId.contains(property)) return; if (!currentItem) return; QString id = propertyToId[property]; if (id == QLatin1String("font")) { if (currentItem->rtti() == QtCanvasItem::Rtti_Text) { QtCanvasText *i = (QtCanvasText *)currentItem; i->setFont(value); } } canvas->update(); } void MainWindow::valueChanged(QtProperty *property, const QPoint &value) { if (!propertyToId.contains(property)) return; if (!currentItem) return; QString id = propertyToId[property]; if (currentItem->rtti() == QtCanvasItem::Rtti_Line) { QtCanvasLine *i = (QtCanvasLine *)currentItem; if (id == QLatin1String("endpoint")) { i->setPoints(i->startPoint().x(), i->startPoint().y(), value.x(), value.y()); } } canvas->update(); } void MainWindow::valueChanged(QtProperty *property, const QSize &value) { if (!propertyToId.contains(property)) return; if (!currentItem) return; QString id = propertyToId[property]; if (id == QLatin1String("size")) { if (currentItem->rtti() == QtCanvasItem::Rtti_Rectangle) { QtCanvasRectangle *i = (QtCanvasRectangle *)currentItem; i->setSize(value.width(), value.height()); } else if (currentItem->rtti() == QtCanvasItem::Rtti_Ellipse) { QtCanvasEllipse *i = (QtCanvasEllipse *)currentItem; i->setSize(value.width(), value.height()); } } canvas->update(); } nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/canvas_typed/mainwindow.h000066400000000000000000000103261455373415500306600ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include "qtcanvas.h" class QtProperty; class CanvasView : public QtCanvasView { Q_OBJECT public: CanvasView(QWidget *parent = 0) : QtCanvasView(parent), moving(0) { } CanvasView(QtCanvas *canvas, QWidget *parent = 0) : QtCanvasView(canvas, parent), moving(0) { } signals: void itemClicked(QtCanvasItem *item); void itemMoved(QtCanvasItem *item); protected: void contentsMousePressEvent(QMouseEvent *event); void contentsMouseDoubleClickEvent(QMouseEvent *event); void contentsMouseMoveEvent(QMouseEvent* event); private: void handleMouseClickEvent(QMouseEvent *event); QPoint moving_start; QtCanvasItem *moving; }; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = 0); private slots: void newRectangle(); void newEllipse(); void newLine(); void newText(); void deleteObject(); void clearAll(); void fillView(); void itemClicked(QtCanvasItem *item); void itemMoved(QtCanvasItem *item); void valueChanged(QtProperty *property, double value); void valueChanged(QtProperty *property, const QString &value); void valueChanged(QtProperty *property, const QColor &value); void valueChanged(QtProperty *property, const QFont &value); void valueChanged(QtProperty *property, const QPoint &value); void valueChanged(QtProperty *property, const QSize &value); private: QtCanvasItem *addRectangle(); QtCanvasItem *addEllipse(); QtCanvasItem *addLine(); QtCanvasItem *addText(); void addProperty(QtProperty *property, const QString &id); void updateExpandState(); QAction *deleteAction; class QtDoublePropertyManager *doubleManager; class QtStringPropertyManager *stringManager; class QtColorPropertyManager *colorManager; class QtFontPropertyManager *fontManager; class QtPointPropertyManager *pointManager; class QtSizePropertyManager *sizeManager; class QtTreePropertyBrowser *propertyEditor; CanvasView *canvasView; QtCanvas *canvas; QtCanvasItem *currentItem; QMap propertyToId; QMap idToProperty; QMap idToExpanded; }; #endif nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/canvas_typed/qtcanvas.cpp000066400000000000000000005021201455373415500306550ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #include "qtcanvas.h" #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Qt; class QtCanvasData { public: QtCanvasData() { } QList viewList; QSet itemDict; QSet animDict; }; class QtCanvasViewData { public: QtCanvasViewData() {} QMatrix xform; QMatrix ixform; bool highQuality; }; // clusterizer class QtCanvasClusterizer { public: QtCanvasClusterizer(int maxclusters); ~QtCanvasClusterizer(); void add(int x, int y); // 1x1 rectangle (point) void add(int x, int y, int w, int h); void add(const QRect& rect); void clear(); int clusters() const { return count; } const QRect& operator[](int i) const; private: QRect* cluster; int count; const int maxcl; }; static void include(QRect& r, const QRect& rect) { if (rect.left() < r.left()) { r.setLeft(rect.left()); } if (rect.right()>r.right()) { r.setRight(rect.right()); } if (rect.top() < r.top()) { r.setTop(rect.top()); } if (rect.bottom()>r.bottom()) { r.setBottom(rect.bottom()); } } /* A QtCanvasClusterizer groups rectangles (QRects) into non-overlapping rectangles by a merging heuristic. */ QtCanvasClusterizer::QtCanvasClusterizer(int maxclusters) : cluster(new QRect[maxclusters]), count(0), maxcl(maxclusters) { } QtCanvasClusterizer::~QtCanvasClusterizer() { delete [] cluster; } void QtCanvasClusterizer::clear() { count = 0; } void QtCanvasClusterizer::add(int x, int y) { add(QRect(x, y, 1, 1)); } void QtCanvasClusterizer::add(int x, int y, int w, int h) { add(QRect(x, y, w, h)); } void QtCanvasClusterizer::add(const QRect& rect) { QRect biggerrect(rect.x()-1, rect.y()-1, rect.width()+2, rect.height()+2); //assert(rect.width()>0 && rect.height()>0); int cursor; for (cursor = 0; cursor < count; cursor++) { if (cluster[cursor].contains(rect)) { // Wholly contained already. return; } } int lowestcost = 9999999; int cheapest = -1; cursor = 0; while(cursor < count) { if (cluster[cursor].intersects(biggerrect)) { QRect larger = cluster[cursor]; include(larger, rect); int cost = larger.width()*larger.height() - cluster[cursor].width()*cluster[cursor].height(); if (cost < lowestcost) { bool bad = false; for (int c = 0; c < count && !bad; c++) { bad = cluster[c].intersects(larger) && c!= cursor; } if (!bad) { cheapest = cursor; lowestcost = cost; } } } cursor++; } if (cheapest>= 0) { include(cluster[cheapest], rect); return; } if (count < maxcl) { cluster[count++] = rect; return; } // Do cheapest of: // add to closest cluster // do cheapest cluster merge, add to new cluster lowestcost = 9999999; cheapest = -1; cursor = 0; while(cursor < count) { QRect larger = cluster[cursor]; include(larger, rect); int cost = larger.width()*larger.height() - cluster[cursor].width()*cluster[cursor].height(); if (cost < lowestcost) { bool bad = false; for (int c = 0; c < count && !bad; c++) { bad = cluster[c].intersects(larger) && c!= cursor; } if (!bad) { cheapest = cursor; lowestcost = cost; } } cursor++; } // ### // could make an heuristic guess as to whether we need to bother // looking for a cheap merge. int cheapestmerge1 = -1; int cheapestmerge2 = -1; int merge1 = 0; while(merge1 < count) { int merge2 = 0; while(merge2 < count) { if(merge1!= merge2) { QRect larger = cluster[merge1]; include(larger, cluster[merge2]); int cost = larger.width()*larger.height() - cluster[merge1].width()*cluster[merge1].height() - cluster[merge2].width()*cluster[merge2].height(); if (cost < lowestcost) { bool bad = false; for (int c = 0; c < count && !bad; c++) { bad = cluster[c].intersects(larger) && c!= cursor; } if (!bad) { cheapestmerge1 = merge1; cheapestmerge2 = merge2; lowestcost = cost; } } } merge2++; } merge1++; } if (cheapestmerge1>= 0) { include(cluster[cheapestmerge1], cluster[cheapestmerge2]); cluster[cheapestmerge2] = cluster[count--]; } else { // if (!cheapest) debugRectangles(rect); include(cluster[cheapest], rect); } // NB: clusters do not intersect (or intersection will // overwrite). This is a result of the above algorithm, // given the assumption that (x, y) are ordered topleft // to bottomright. // ### // // add explicit x/y ordering to that comment, move it to the top // and rephrase it as pre-/post-conditions. } const QRect& QtCanvasClusterizer::operator[](int i) const { return cluster[i]; } // end of clusterizer class QtCanvasItemLess { public: inline bool operator()(const QtCanvasItem *i1, const QtCanvasItem *i2) const { if (i1->z() == i2->z()) return i1 > i2; return (i1->z() > i2->z()); } }; class QtCanvasChunk { public: QtCanvasChunk() : changed(true) { } // Other code assumes lists are not deleted. Assignment is also // done on ChunkRecs. So don't add that sort of thing here. void sort() { qSort(m_list.begin(), m_list.end(), QtCanvasItemLess()); } const QtCanvasItemList &list() const { return m_list; } void add(QtCanvasItem* item) { m_list.prepend(item); changed = true; } void remove(QtCanvasItem* item) { m_list.removeAll(item); changed = true; } void change() { changed = true; } bool hasChanged() const { return changed; } bool takeChange() { bool y = changed; changed = false; return y; } private: QtCanvasItemList m_list; bool changed; }; static int gcd(int a, int b) { int r; while ((r = a%b)) { a = b; b = r; } return b; } static int scm(int a, int b) { int g = gcd(a, b); return a/g*b; } /* \class QtCanvas qtcanvas.h \brief The QtCanvas class provides a 2D area that can contain QtCanvasItem objects. The QtCanvas class manages its 2D graphic area and all the canvas items the area contains. The canvas has no visual appearance of its own. Instead, it is displayed on screen using a QtCanvasView. Multiple QtCanvasView widgets may be associated with a canvas to provide multiple views of the same canvas. The canvas is optimized for large numbers of items, particularly where only a small percentage of the items change at any one time. If the entire display changes very frequently, you should consider using your own custom QtScrollView subclass. Qt provides a rich set of canvas item classes, e.g. QtCanvasEllipse, QtCanvasLine, QtCanvasPolygon, QtCanvasPolygonalItem, QtCanvasRectangle, QtCanvasSpline, QtCanvasSprite and QtCanvasText. You can subclass to create your own canvas items; QtCanvasPolygonalItem is the most common base class used for this purpose. Items appear on the canvas after their \link QtCanvasItem::show() show()\endlink function has been called (or \link QtCanvasItem::setVisible() setVisible(true)\endlink), and \e after update() has been called. The canvas only shows items that are \link QtCanvasItem::setVisible() visible\endlink, and then only if \l update() is called. (By default the canvas is white and so are canvas items, so if nothing appears try changing colors.) If you created the canvas without passing a width and height to the constructor you must also call resize(). Although a canvas may appear to be similar to a widget with child widgets, there are several notable differences: \list \i Canvas items are usually much faster to manipulate and redraw than child widgets, with the speed advantage becoming especially great when there are \e many canvas items and non-rectangular items. In most situations canvas items are also a lot more memory efficient than child widgets. \i It's easy to detect overlapping items (collision detection). \i The canvas can be larger than a widget. A million-by-million canvas is perfectly possible. At such a size a widget might be very inefficient, and some window systems might not support it at all, whereas QtCanvas scales well. Even with a billion pixels and a million items, finding a particular canvas item, detecting collisions, etc., is still fast (though the memory consumption may be prohibitive at such extremes). \i Two or more QtCanvasView objects can view the same canvas. \i An arbitrary transformation matrix can be set on each QtCanvasView which makes it easy to zoom, rotate or shear the viewed canvas. \i Widgets provide a lot more functionality, such as input (QKeyEvent, QMouseEvent etc.) and layout management (QGridLayout etc.). \endlist A canvas consists of a background, a number of canvas items organized by x, y and z coordinates, and a foreground. A canvas item's z coordinate can be treated as a layer number -- canvas items with a higher z coordinate appear in front of canvas items with a lower z coordinate. The background is white by default, but can be set to a different color using setBackgroundColor(), or to a repeated pixmap using setBackgroundPixmap() or to a mosaic of smaller pixmaps using setTiles(). Individual tiles can be set with setTile(). There are corresponding get functions, e.g. backgroundColor() and backgroundPixmap(). Note that QtCanvas does not inherit from QWidget, even though it has some functions which provide the same functionality as those in QWidget. One of these is setBackgroundPixmap(); some others are resize(), size(), width() and height(). \l QtCanvasView is the widget used to display a canvas on the screen. Canvas items are added to a canvas by constructing them and passing the canvas to the canvas item's constructor. An item can be moved to a different canvas using QtCanvasItem::setCanvas(). Canvas items are movable (and in the case of QtCanvasSprites, animated) objects that inherit QtCanvasItem. Each canvas item has a position on the canvas (x, y coordinates) and a height (z coordinate), all of which are held as floating-point numbers. Moving canvas items also have x and y velocities. It's possible for a canvas item to be outside the canvas (for example QtCanvasItem::x() is greater than width()). When a canvas item is off the canvas, onCanvas() returns false and the canvas disregards the item. (Canvas items off the canvas do not slow down any of the common operations on the canvas.) Canvas items can be moved with QtCanvasItem::move(). The advance() function moves all QtCanvasItem::animated() canvas items and setAdvancePeriod() makes QtCanvas move them automatically on a periodic basis. In the context of the QtCanvas classes, to `animate' a canvas item is to set it in motion, i.e. using QtCanvasItem::setVelocity(). Animation of a canvas item itself, i.e. items which change over time, is enabled by calling QtCanvasSprite::setFrameAnimation(), or more generally by subclassing and reimplementing QtCanvasItem::advance(). To detect collisions use one of the QtCanvasItem::collisions() functions. The changed parts of the canvas are redrawn (if they are visible in a canvas view) whenever update() is called. You can either call update() manually after having changed the contents of the canvas, or force periodic updates using setUpdatePeriod(). If you have moving objects on the canvas, you must call advance() every time the objects should move one step further. Periodic calls to advance() can be forced using setAdvancePeriod(). The advance() function will call QtCanvasItem::advance() on every item that is \link QtCanvasItem::animated() animated\endlink and trigger an update of the affected areas afterwards. (A canvas item that is `animated' is simply a canvas item that is in motion.) QtCanvas organizes its canvas items into \e chunks; these are areas on the canvas that are used to speed up most operations. Many operations start by eliminating most chunks (i.e. those which haven't changed) and then process only the canvas items that are in the few interesting (i.e. changed) chunks. A valid chunk, validChunk(), is one which is on the canvas. The chunk size is a key factor to QtCanvas's speed: if there are too many chunks, the speed benefit of grouping canvas items into chunks is reduced. If the chunks are too large, it takes too long to process each one. The QtCanvas constructor tries to pick a suitable size, but you can call retune() to change it at any time. The chunkSize() function returns the current chunk size. The canvas items always make sure they're in the right chunks; all you need to make sure of is that the canvas uses the right chunk size. A good rule of thumb is that the size should be a bit smaller than the average canvas item size. If you have moving objects, the chunk size should be a bit smaller than the average size of the moving items. The foreground is normally nothing, but if you reimplement drawForeground(), you can draw things in front of all the canvas items. Areas can be set as changed with setChanged() and set unchanged with setUnchanged(). The entire canvas can be set as changed with setAllChanged(). A list of all the items on the canvas is returned by allItems(). An area can be copied (painted) to a QPainter with drawArea(). If the canvas is resized it emits the resized() signal. The examples/canvas application and the 2D graphics page of the examples/demo application demonstrate many of QtCanvas's facilities. \sa QtCanvasView QtCanvasItem */ void QtCanvas::init(int w, int h, int chunksze, int mxclusters) { d = new QtCanvasData; awidth = w; aheight = h; chunksize = chunksze; maxclusters = mxclusters; chwidth = (w+chunksize-1)/chunksize; chheight = (h+chunksize-1)/chunksize; chunks = new QtCanvasChunk[chwidth*chheight]; update_timer = 0; bgcolor = white; grid = 0; htiles = 0; vtiles = 0; debug_redraw_areas = false; } /* Create a QtCanvas with no size. \a parent is passed to the QObject superclass. \warning You \e must call resize() at some time after creation to be able to use the canvas. */ QtCanvas::QtCanvas(QObject* parent) : QObject(parent) { init(0, 0); } /* Constructs a QtCanvas that is \a w pixels wide and \a h pixels high. */ QtCanvas::QtCanvas(int w, int h) { init(w, h); } /* Constructs a QtCanvas which will be composed of \a h tiles horizontally and \a v tiles vertically. Each tile will be an image \a tilewidth by \a tileheight pixels taken from pixmap \a p. The pixmap \a p is a list of tiles, arranged left to right, (and in the case of pixmaps that have multiple rows of tiles, top to bottom), with tile 0 in the top-left corner, tile 1 next to the right, and so on, e.g. \table \row \i 0 \i 1 \i 2 \i 3 \row \i 4 \i 5 \i 6 \i 7 \endtable The QtCanvas is initially sized to show exactly the given number of tiles horizontally and vertically. If it is resized to be larger, the entire matrix of tiles will be repeated as often as necessary to cover the area. If it is smaller, tiles to the right and bottom will not be visible. \sa setTiles() */ QtCanvas::QtCanvas(QPixmap p, int h, int v, int tilewidth, int tileheight) { init(h*tilewidth, v*tileheight, scm(tilewidth, tileheight)); setTiles(p, h, v, tilewidth, tileheight); } /* Destroys the canvas and all the canvas's canvas items. */ QtCanvas::~QtCanvas() { for (int i = 0; i < d->viewList.size(); ++i) d->viewList[i]->viewing = 0; QtCanvasItemList all = allItems(); for (QtCanvasItemList::Iterator it = all.begin(); it!= all.end(); ++it) delete *it; delete [] chunks; delete [] grid; delete d; } /* \internal Returns the chunk at a chunk position \a i, \a j. */ QtCanvasChunk& QtCanvas::chunk(int i, int j) const { return chunks[i+chwidth*j]; } /* \internal Returns the chunk at a pixel position \a x, \a y. */ QtCanvasChunk& QtCanvas::chunkContaining(int x, int y) const { return chunk(x/chunksize, y/chunksize); } /* Returns a list of all the items in the canvas. */ QtCanvasItemList QtCanvas::allItems() { return d->itemDict.toList(); } /* Changes the size of the canvas to have a width of \a w and a height of \a h. This is a slow operation. */ void QtCanvas::resize(int w, int h) { if (awidth == w && aheight == h) return; QList hidden; for (QSet::const_iterator it = d->itemDict.begin(); it != d->itemDict.end(); ++it) { if ((*it)->isVisible()) { (*it)->hide(); hidden.append(*it); } } int nchwidth = (w+chunksize-1)/chunksize; int nchheight = (h+chunksize-1)/chunksize; QtCanvasChunk* newchunks = new QtCanvasChunk[nchwidth*nchheight]; // Commit the new values. // awidth = w; aheight = h; chwidth = nchwidth; chheight = nchheight; delete [] chunks; chunks = newchunks; for (int i = 0; i < hidden.size(); ++i) hidden.at(i)->show(); setAllChanged(); emit resized(); } /* \fn void QtCanvas::resized() This signal is emitted whenever the canvas is resized. Each QtCanvasView connects to this signal to keep the scrollview's size correct. */ /* Change the efficiency tuning parameters to \a mxclusters clusters, each of size \a chunksze. This is a slow operation if there are many objects on the canvas. The canvas is divided into chunks which are rectangular areas \a chunksze wide by \a chunksze high. Use a chunk size which is about the average size of the canvas items. If you choose a chunk size which is too small it will increase the amount of calculation required when drawing since each change will affect many chunks. If you choose a chunk size which is too large the amount of drawing required will increase because for each change, a lot of drawing will be required since there will be many (unchanged) canvas items which are in the same chunk as the changed canvas items. Internally, a canvas uses a low-resolution "chunk matrix" to keep track of all the items in the canvas. A 64x64 chunk matrix is the default for a 1024x1024 pixel canvas, where each chunk collects canvas items in a 16x16 pixel square. This default is also affected by setTiles(). You can tune this default using this function. For example if you have a very large canvas and want to trade off speed for memory then you might set the chunk size to 32 or 64. The \a mxclusters argument is the number of rectangular groups of chunks that will be separately drawn. If the canvas has a large number of small, dispersed items, this should be about that number. Our testing suggests that a large number of clusters is almost always best. */ void QtCanvas::retune(int chunksze, int mxclusters) { maxclusters = mxclusters; if (chunksize!= chunksze) { QList hidden; for (QSet::const_iterator it = d->itemDict.begin(); it != d->itemDict.end(); ++it) { if ((*it)->isVisible()) { (*it)->hide(); hidden.append(*it); } } chunksize = chunksze; int nchwidth = (awidth+chunksize-1)/chunksize; int nchheight = (aheight+chunksize-1)/chunksize; QtCanvasChunk* newchunks = new QtCanvasChunk[nchwidth*nchheight]; // Commit the new values. // chwidth = nchwidth; chheight = nchheight; delete [] chunks; chunks = newchunks; for (int i = 0; i < hidden.size(); ++i) hidden.at(i)->show(); } } /* \fn int QtCanvas::width() const Returns the width of the canvas, in pixels. */ /* \fn int QtCanvas::height() const Returns the height of the canvas, in pixels. */ /* \fn QSize QtCanvas::size() const Returns the size of the canvas, in pixels. */ /* \fn QRect QtCanvas::rect() const Returns a rectangle the size of the canvas. */ /* \fn bool QtCanvas::onCanvas(int x, int y) const Returns true if the pixel position (\a x, \a y) is on the canvas; otherwise returns false. \sa validChunk() */ /* \fn bool QtCanvas::onCanvas(const QPoint& p) const \overload Returns true if the pixel position \a p is on the canvas; otherwise returns false. \sa validChunk() */ /* \fn bool QtCanvas::validChunk(int x, int y) const Returns true if the chunk position (\a x, \a y) is on the canvas; otherwise returns false. \sa onCanvas() */ /* \fn bool QtCanvas::validChunk(const QPoint& p) const \overload Returns true if the chunk position \a p is on the canvas; otherwise returns false. \sa onCanvas() */ /* \fn int QtCanvas::chunkSize() const Returns the chunk size of the canvas. \sa retune() */ /* \fn bool QtCanvas::sameChunk(int x1, int y1, int x2, int y2) const \internal Tells if the points (\a x1, \a y1) and (\a x2, \a y2) are within the same chunk. */ /* \internal This method adds an the item \a item to the list of QtCanvasItem objects in the QtCanvas. The QtCanvasItem class calls this. */ void QtCanvas::addItem(QtCanvasItem* item) { d->itemDict.insert(item); } /* \internal This method adds the item \a item to the list of QtCanvasItem objects to be moved. The QtCanvasItem class calls this. */ void QtCanvas::addAnimation(QtCanvasItem* item) { d->animDict.insert(item); } /* \internal This method adds the item \a item to the list of QtCanvasItem objects which are no longer to be moved. The QtCanvasItem class calls this. */ void QtCanvas::removeAnimation(QtCanvasItem* item) { d->animDict.remove(item); } /* \internal This method removes the item \a item from the list of QtCanvasItem objects in this QtCanvas. The QtCanvasItem class calls this. */ void QtCanvas::removeItem(QtCanvasItem* item) { d->itemDict.remove(item); } /* \internal This method adds the view \a view to the list of QtCanvasView objects viewing this QtCanvas. The QtCanvasView class calls this. */ void QtCanvas::addView(QtCanvasView* view) { d->viewList.append(view); if (htiles>1 || vtiles>1 || pm.isNull()) { QPalette::ColorRole role = view->widget()->backgroundRole(); QPalette viewPalette = view->widget()->palette(); viewPalette.setColor(role, backgroundColor()); view->widget()->setPalette(viewPalette); } } /* \internal This method removes the view \a view from the list of QtCanvasView objects viewing this QtCanvas. The QtCanvasView class calls this. */ void QtCanvas::removeView(QtCanvasView* view) { d->viewList.removeAll(view); } /* Sets the canvas to call advance() every \a ms milliseconds. Any previous setting by setAdvancePeriod() or setUpdatePeriod() is overridden. If \a ms is less than 0 advancing will be stopped. */ void QtCanvas::setAdvancePeriod(int ms) { if (ms < 0) { if (update_timer) update_timer->stop(); } else { if (update_timer) delete update_timer; update_timer = new QTimer(this); connect(update_timer, SIGNAL(timeout()), this, SLOT(advance())); update_timer->start(ms); } } /* Sets the canvas to call update() every \a ms milliseconds. Any previous setting by setAdvancePeriod() or setUpdatePeriod() is overridden. If \a ms is less than 0 automatic updating will be stopped. */ void QtCanvas::setUpdatePeriod(int ms) { if (ms < 0) { if (update_timer) update_timer->stop(); } else { if (update_timer) delete update_timer; update_timer = new QTimer(this); connect(update_timer, SIGNAL(timeout()), this, SLOT(update())); update_timer->start(ms); } } /* Moves all QtCanvasItem::animated() canvas items on the canvas and refreshes all changes to all views of the canvas. (An `animated' item is an item that is in motion; see setVelocity().) The advance takes place in two phases. In phase 0, the QtCanvasItem::advance() function of each QtCanvasItem::animated() canvas item is called with paramater 0. Then all these canvas items are called again, with parameter 1. In phase 0, the canvas items should not change position, merely examine other items on the canvas for which special processing is required, such as collisions between items. In phase 1, all canvas items should change positions, ignoring any other items on the canvas. This two-phase approach allows for considerations of "fairness", although no QtCanvasItem subclasses supplied with Qt do anything interesting in phase 0. The canvas can be configured to call this function periodically with setAdvancePeriod(). \sa update() */ void QtCanvas::advance() { QSetIterator it = d->animDict; while (it.hasNext()) { QtCanvasItem *i = it.next(); if (i) i->advance(0); } // we expect the dict contains the exact same items as in the // first pass. it.toFront(); while (it.hasNext()) { QtCanvasItem* i = it.next(); if (i) i->advance(1); } update(); } // Don't call this unless you know what you're doing. // p is in the content's co-ordinate example. /* \internal */ void QtCanvas::drawViewArea(QtCanvasView* view, QPainter* p, const QRect& vr, bool) { QMatrix wm = view->worldMatrix(); QMatrix iwm = wm.inverted(); // ivr = covers all chunks in vr QRect ivr = iwm.mapRect(vr); p->setMatrix(wm); drawCanvasArea(ivr, p, false); } /* Repaints changed areas in all views of the canvas. \sa advance() */ void QtCanvas::update() { QRect r = changeBounds(); for (int i = 0; i < d->viewList.size(); ++i) { QtCanvasView* view = d->viewList.at(i); if (!r.isEmpty()) { QRect tr = view->worldMatrix().mapRect(r); view->widget()->update(tr); } } setUnchanged(r); } /* Marks the whole canvas as changed. All views of the canvas will be entirely redrawn when update() is called next. */ void QtCanvas::setAllChanged() { setChanged(QRect(0, 0, width(), height())); } /* Marks \a area as changed. This \a area will be redrawn in all views that are showing it when update() is called next. */ void QtCanvas::setChanged(const QRect& area) { QRect thearea = area.intersected(QRect(0, 0, width(), height())); int mx = (thearea.x()+thearea.width()+chunksize)/chunksize; int my = (thearea.y()+thearea.height()+chunksize)/chunksize; if (mx>chwidth) mx = chwidth; if (my>chheight) my = chheight; int x = thearea.x()/chunksize; while(x < mx) { int y = thearea.y()/chunksize; while(y < my) { chunk(x, y).change(); y++; } x++; } } /* Marks \a area as \e unchanged. The area will \e not be redrawn in the views for the next update(), unless it is marked or changed again before the next call to update(). */ void QtCanvas::setUnchanged(const QRect& area) { QRect thearea = area.intersected(QRect(0, 0, width(), height())); int mx = (thearea.x()+thearea.width()+chunksize)/chunksize; int my = (thearea.y()+thearea.height()+chunksize)/chunksize; if (mx>chwidth) mx = chwidth; if (my>chheight) my = chheight; int x = thearea.x()/chunksize; while(x < mx) { int y = thearea.y()/chunksize; while(y < my) { chunk(x, y).takeChange(); y++; } x++; } } /* \internal */ QRect QtCanvas::changeBounds() { QRect area = QRect(0, 0, width(), height()); int mx = (area.x()+area.width()+chunksize)/chunksize; int my = (area.y()+area.height()+chunksize)/chunksize; if (mx > chwidth) mx = chwidth; if (my > chheight) my = chheight; QRect result; int x = area.x()/chunksize; while(x < mx) { int y = area.y()/chunksize; while(y < my) { QtCanvasChunk& ch = chunk(x, y); if (ch.hasChanged()) result |= QRect(x*chunksize, y*chunksize, chunksize + 1, chunksize + 1); y++; } x++; } return result; } /* Paints all canvas items that are in the area \a clip to \a painter, using double-buffering if \a dbuf is true. e.g. to print the canvas to a printer: \code QPrinter pr; if (pr.setup()) { QPainter p(&pr); canvas.drawArea(canvas.rect(), &p); } \endcode */ void QtCanvas::drawArea(const QRect& clip, QPainter* painter, bool dbuf) { if (painter) drawCanvasArea(clip, painter, dbuf); } #include /* \internal */ void QtCanvas::drawCanvasArea(const QRect& inarea, QPainter* p, bool /*double_buffer*/) { QRect area = inarea.intersected(QRect(0, 0, width(), height())); if (!p) return; // Nothing to do. int lx = area.x()/chunksize; int ly = area.y()/chunksize; int mx = area.right()/chunksize; int my = area.bottom()/chunksize; if (mx>= chwidth) mx = chwidth-1; if (my>= chheight) my = chheight-1; QtCanvasItemList allvisible; // Stores the region within area that need to be drawn. It is relative // to area.topLeft() (so as to keep within bounds of 16-bit XRegions) QRegion rgn; for (int x = lx; x <= mx; x++) { for (int y = ly; y <= my; y++) { // Only reset change if all views updating, and // wholy within area. (conservative: ignore entire boundary) // // Disable this to help debugging. // if (!p) { if (chunk(x, y).takeChange()) { // ### should at least make bands rgn |= QRegion(x*chunksize-area.x(), y*chunksize-area.y(), chunksize, chunksize); allvisible += chunk(x, y).list(); } } else { allvisible += chunk(x, y).list(); } } } qSort(allvisible.begin(), allvisible.end(), QtCanvasItemLess()); drawBackground(*p, area); if (!allvisible.isEmpty()) { QtCanvasItem* prev = 0; for (int i = allvisible.size() - 1; i >= 0; --i) { QtCanvasItem *g = allvisible[i]; if (g != prev) { g->draw(*p); prev = g; } } } drawForeground(*p, area); } /* \internal This method to informs the QtCanvas that a given chunk is `dirty' and needs to be redrawn in the next Update. (\a x, \a y) is a chunk location. The sprite classes call this. Any new derived class of QtCanvasItem must do so too. SetChangedChunkContaining can be used instead. */ void QtCanvas::setChangedChunk(int x, int y) { if (validChunk(x, y)) { QtCanvasChunk& ch = chunk(x, y); ch.change(); } } /* \internal This method to informs the QtCanvas that the chunk containing a given pixel is `dirty' and needs to be redrawn in the next Update. (\a x, \a y) is a pixel location. The item classes call this. Any new derived class of QtCanvasItem must do so too. SetChangedChunk can be used instead. */ void QtCanvas::setChangedChunkContaining(int x, int y) { if (x>= 0 && x < width() && y>= 0 && y < height()) { QtCanvasChunk& chunk = chunkContaining(x, y); chunk.change(); } } /* \internal This method adds the QtCanvasItem \a g to the list of those which need to be drawn if the given chunk at location (\a x, \a y) is redrawn. Like SetChangedChunk and SetChangedChunkContaining, this method marks the chunk as `dirty'. */ void QtCanvas::addItemToChunk(QtCanvasItem* g, int x, int y) { if (validChunk(x, y)) { chunk(x, y).add(g); } } /* \internal This method removes the QtCanvasItem \a g from the list of those which need to be drawn if the given chunk at location (\a x, \a y) is redrawn. Like SetChangedChunk and SetChangedChunkContaining, this method marks the chunk as `dirty'. */ void QtCanvas::removeItemFromChunk(QtCanvasItem* g, int x, int y) { if (validChunk(x, y)) { chunk(x, y).remove(g); } } /* \internal This method adds the QtCanvasItem \a g to the list of those which need to be drawn if the chunk containing the given pixel (\a x, \a y) is redrawn. Like SetChangedChunk and SetChangedChunkContaining, this method marks the chunk as `dirty'. */ void QtCanvas::addItemToChunkContaining(QtCanvasItem* g, int x, int y) { if (x>= 0 && x < width() && y>= 0 && y < height()) { chunkContaining(x, y).add(g); } } /* \internal This method removes the QtCanvasItem \a g from the list of those which need to be drawn if the chunk containing the given pixel (\a x, \a y) is redrawn. Like SetChangedChunk and SetChangedChunkContaining, this method marks the chunk as `dirty'. */ void QtCanvas::removeItemFromChunkContaining(QtCanvasItem* g, int x, int y) { if (x>= 0 && x < width() && y>= 0 && y < height()) { chunkContaining(x, y).remove(g); } } /* Returns the color set by setBackgroundColor(). By default, this is white. This function is not a reimplementation of QWidget::backgroundColor() (QtCanvas is not a subclass of QWidget), but all QtCanvasViews that are viewing the canvas will set their backgrounds to this color. \sa setBackgroundColor(), backgroundPixmap() */ QColor QtCanvas::backgroundColor() const { return bgcolor; } /* Sets the solid background to be the color \a c. \sa backgroundColor(), setBackgroundPixmap(), setTiles() */ void QtCanvas::setBackgroundColor(const QColor& c) { if (bgcolor != c) { bgcolor = c; for (int i = 0; i < d->viewList.size(); ++i) { QtCanvasView *view = d->viewList.at(i); QPalette::ColorRole role = view->widget()->backgroundRole(); QPalette viewPalette = view->widget()->palette(); viewPalette.setColor(role, bgcolor); view->widget()->setPalette(viewPalette); } setAllChanged(); } } /* Returns the pixmap set by setBackgroundPixmap(). By default, this is a null pixmap. \sa setBackgroundPixmap(), backgroundColor() */ QPixmap QtCanvas::backgroundPixmap() const { return pm; } /* Sets the solid background to be the pixmap \a p repeated as necessary to cover the entire canvas. \sa backgroundPixmap(), setBackgroundColor(), setTiles() */ void QtCanvas::setBackgroundPixmap(const QPixmap& p) { setTiles(p, 1, 1, p.width(), p.height()); for (int i = 0; i < d->viewList.size(); ++i) { QtCanvasView* view = d->viewList.at(i); view->widget()->update(); } } /* This virtual function is called for all updates of the canvas. It renders any background graphics using the painter \a painter, in the area \a clip. If the canvas has a background pixmap or a tiled background, that graphic is used, otherwise the canvas is cleared using the background color. If the graphics for an area change, you must explicitly call setChanged(const QRect&) for the result to be visible when update() is next called. \sa setBackgroundColor(), setBackgroundPixmap(), setTiles() */ void QtCanvas::drawBackground(QPainter& painter, const QRect& clip) { if (pm.isNull()) { painter.fillRect(clip, bgcolor); } else if (!grid) { for (int x = clip.x()/pm.width(); x < (clip.x()+clip.width()+pm.width()-1)/pm.width(); x++) { for (int y = clip.y()/pm.height(); y < (clip.y()+clip.height()+pm.height()-1)/pm.height(); y++) { painter.drawPixmap(x*pm.width(), y*pm.height(), pm); } } } else { const int x1 = clip.left()/tilew; int x2 = clip.right()/tilew; const int y1 = clip.top()/tileh; int y2 = clip.bottom()/tileh; const int roww = pm.width()/tilew; for (int j = y1; j <= y2; j++) { int jj = j%tilesVertically(); for (int i = x1; i <= x2; i++) { int t = tile(i%tilesHorizontally(), jj); int tx = t % roww; int ty = t / roww; painter.drawPixmap(i*tilew, j*tileh, pm, tx*tilew, ty*tileh, tilew, tileh); } } } } /* This virtual function is called for all updates of the canvas. It renders any foreground graphics using the painter \a painter, in the area \a clip. If the graphics for an area change, you must explicitly call setChanged(const QRect&) for the result to be visible when update() is next called. The default is to draw nothing. */ void QtCanvas::drawForeground(QPainter& painter, const QRect& clip) { if (debug_redraw_areas) { painter.setPen(red); painter.setBrush(NoBrush); painter.drawRect(clip); } } /* Sets the QtCanvas to be composed of \a h tiles horizontally and \a v tiles vertically. Each tile will be an image \a tilewidth by \a tileheight pixels from pixmap \a p. The pixmap \a p is a list of tiles, arranged left to right, (and in the case of pixmaps that have multiple rows of tiles, top to bottom), with tile 0 in the top-left corner, tile 1 next to the right, and so on, e.g. \table \row \i 0 \i 1 \i 2 \i 3 \row \i 4 \i 5 \i 6 \i 7 \endtable If the canvas is larger than the matrix of tiles, the entire matrix is repeated as necessary to cover the whole canvas. If it is smaller, tiles to the right and bottom are not visible. The width and height of \a p must be a multiple of \a tilewidth and \a tileheight. If they are not the function will do nothing. If you want to unset any tiling set, then just pass in a null pixmap and 0 for \a h, \a v, \a tilewidth, and \a tileheight. */ void QtCanvas::setTiles(QPixmap p, int h, int v, int tilewidth, int tileheight) { if (!p.isNull() && (!tilewidth || !tileheight || p.width() % tilewidth != 0 || p.height() % tileheight != 0)) return; htiles = h; vtiles = v; delete[] grid; pm = p; if (h && v && !p.isNull()) { grid = new ushort[h*v]; memset(grid, 0, h*v*sizeof(ushort)); tilew = tilewidth; tileh = tileheight; } else { grid = 0; } if (h + v > 10) { int s = scm(tilewidth, tileheight); retune(s < 128 ? s : qMax(tilewidth, tileheight)); } setAllChanged(); } /* \fn int QtCanvas::tile(int x, int y) const Returns the tile at position (\a x, \a y). Initially, all tiles are 0. The parameters must be within range, i.e. 0 \< \a x \< tilesHorizontally() and 0 \< \a y \< tilesVertically(). \sa setTile() */ /* \fn int QtCanvas::tilesHorizontally() const Returns the number of tiles horizontally. */ /* \fn int QtCanvas::tilesVertically() const Returns the number of tiles vertically. */ /* \fn int QtCanvas::tileWidth() const Returns the width of each tile. */ /* \fn int QtCanvas::tileHeight() const Returns the height of each tile. */ /* Sets the tile at (\a x, \a y) to use tile number \a tilenum, which is an index into the tile pixmaps. The canvas will update appropriately when update() is next called. The images are taken from the pixmap set by setTiles() and are arranged left to right, (and in the case of pixmaps that have multiple rows of tiles, top to bottom), with tile 0 in the top-left corner, tile 1 next to the right, and so on, e.g. \table \row \i 0 \i 1 \i 2 \i 3 \row \i 4 \i 5 \i 6 \i 7 \endtable \sa tile() setTiles() */ void QtCanvas::setTile(int x, int y, int tilenum) { ushort& t = grid[x+y*htiles]; if (t != tilenum) { t = tilenum; if (tilew == tileh && tilew == chunksize) setChangedChunk(x, y); // common case else setChanged(QRect(x*tilew, y*tileh, tilew, tileh)); } } // lesser-used data in canvas item, plus room for extension. // Be careful adding to this - check all usages. class QtCanvasItemExtra { QtCanvasItemExtra() : vx(0.0), vy(0.0) { } double vx, vy; friend class QtCanvasItem; }; /* \class QtCanvasItem qtcanvas.h \brief The QtCanvasItem class provides an abstract graphic object on a QtCanvas. A variety of QtCanvasItem subclasses provide immediately usable behaviour. This class is a pure abstract superclass providing the behaviour that is shared among all the concrete canvas item classes. QtCanvasItem is not intended for direct subclassing. It is much easier to subclass one of its subclasses, e.g. QtCanvasPolygonalItem (the commonest base class), QtCanvasRectangle, QtCanvasSprite, QtCanvasEllipse or QtCanvasText. Canvas items are added to a canvas by constructing them and passing the canvas to the canvas item's constructor. An item can be moved to a different canvas using setCanvas(). Items appear on the canvas after their \link show() show()\endlink function has been called (or \link setVisible() setVisible(true)\endlink), and \e after update() has been called. The canvas only shows items that are \link setVisible() visible\endlink, and then only if \l update() is called. If you created the canvas without passing a width and height to the constructor you'll also need to call \link QtCanvas::resize() resize()\endlink. Since the canvas background defaults to white and canvas items default to white, you may need to change colors to see your items. A QtCanvasItem object can be moved in the x(), y() and z() dimensions using functions such as move(), moveBy(), setX(), setY() and setZ(). A canvas item can be set in motion, `animated', using setAnimated() and given a velocity in the x and y directions with setXVelocity() and setYVelocity() -- the same effect can be achieved by calling setVelocity(). Use the collidesWith() function to see if the canvas item will collide on the \e next advance(1) and use collisions() to see what collisions have occurred. Use QtCanvasSprite or your own subclass of QtCanvasSprite to create canvas items which are animated, i.e. which change over time. The size of a canvas item is given by boundingRect(). Use boundingRectAdvanced() to see what the size of the canvas item will be \e after the next advance(1) call. The rtti() function is used for identifying subclasses of QtCanvasItem. The canvas() function returns a pointer to the canvas which contains the canvas item. QtCanvasItem provides the show() and isVisible() functions like those in QWidget. QtCanvasItem also provides the setEnabled(), setActive() and setSelected() functions; these functions set the relevant boolean and cause a repaint but the boolean values they set are not used in QtCanvasItem itself. You can make use of these booleans in your subclasses. By default, canvas items have no velocity, no size, and are not in motion. The subclasses provided in Qt do not change these defaults except where noted. */ /* \enum QtCanvasItem::RttiValues This enum is used to name the different types of canvas item. \value Rtti_Item Canvas item abstract base class \value Rtti_Ellipse \value Rtti_Line \value Rtti_Polygon \value Rtti_PolygonalItem \value Rtti_Rectangle \value Rtti_Spline \value Rtti_Sprite \value Rtti_Text */ /* \fn void QtCanvasItem::update() Call this function to repaint the canvas's changed chunks. */ /* Constructs a QtCanvasItem on canvas \a canvas. \sa setCanvas() */ QtCanvasItem::QtCanvasItem(QtCanvas* canvas) : cnv(canvas), myx(0), myy(0), myz(0) { ani = 0; vis = 0; val = 0; sel = 0; ena = 0; act = 0; ext = 0; if (cnv) cnv->addItem(this); } /* Destroys the QtCanvasItem and removes it from its canvas. */ QtCanvasItem::~QtCanvasItem() { if (cnv) { cnv->removeItem(this); cnv->removeAnimation(this); } delete ext; } QtCanvasItemExtra& QtCanvasItem::extra() { if (!ext) ext = new QtCanvasItemExtra; return *ext; } /* \fn double QtCanvasItem::x() const Returns the horizontal position of the canvas item. Note that subclasses often have an origin other than the top-left corner. */ /* \fn double QtCanvasItem::y() const Returns the vertical position of the canvas item. Note that subclasses often have an origin other than the top-left corner. */ /* \fn double QtCanvasItem::z() const Returns the z index of the canvas item, which is used for visual order: higher-z items obscure (are in front of) lower-z items. */ /* \fn void QtCanvasItem::setX(double x) Moves the canvas item so that its x-position is \a x. \sa x(), move() */ /* \fn void QtCanvasItem::setY(double y) Moves the canvas item so that its y-position is \a y. \sa y(), move() */ /* \fn void QtCanvasItem::setZ(double z) Sets the z index of the canvas item to \a z. Higher-z items obscure (are in front of) lower-z items. \sa z(), move() */ /* Moves the canvas item relative to its current position by (\a dx, \a dy). */ void QtCanvasItem::moveBy(double dx, double dy) { if (dx || dy) { removeFromChunks(); myx += dx; myy += dy; addToChunks(); } } /* Moves the canvas item to the absolute position (\a x, \a y). */ void QtCanvasItem::move(double x, double y) { moveBy(x-myx, y-myy); } /* Returns true if the canvas item is in motion; otherwise returns false. \sa setVelocity(), setAnimated() */ bool QtCanvasItem::animated() const { return (bool)ani; } /* Sets the canvas item to be in motion if \a y is true, or not if \a y is false. The speed and direction of the motion is set with setVelocity(), or with setXVelocity() and setYVelocity(). \sa advance(), QtCanvas::advance() */ void QtCanvasItem::setAnimated(bool y) { if (y != (bool)ani) { ani = (uint)y; if (y) { cnv->addAnimation(this); } else { cnv->removeAnimation(this); } } } /* \fn void QtCanvasItem::setXVelocity(double vx) Sets the horizontal component of the canvas item's velocity to \a vx. \sa setYVelocity() setVelocity() */ /* \fn void QtCanvasItem::setYVelocity(double vy) Sets the vertical component of the canvas item's velocity to \a vy. \sa setXVelocity() setVelocity() */ /* Sets the canvas item to be in motion, moving by \a vx and \a vy pixels in the horizontal and vertical directions respectively. \sa advance() setXVelocity() setYVelocity() */ void QtCanvasItem::setVelocity(double vx, double vy) { if (ext || vx!= 0.0 || vy!= 0.0) { if (!ani) setAnimated(true); extra().vx = vx; extra().vy = vy; } } /* Returns the horizontal velocity component of the canvas item. */ double QtCanvasItem::xVelocity() const { return ext ? ext->vx : 0; } /* Returns the vertical velocity component of the canvas item. */ double QtCanvasItem::yVelocity() const { return ext ? ext->vy : 0; } /* The default implementation moves the canvas item, if it is animated(), by the preset velocity if \a phase is 1, and does nothing if \a phase is 0. Note that if you reimplement this function, the reimplementation must not change the canvas in any way, for example it must not add or remove items. \sa QtCanvas::advance() setVelocity() */ void QtCanvasItem::advance(int phase) { if (ext && phase == 1) moveBy(ext->vx, ext->vy); } /* \fn void QtCanvasItem::draw(QPainter& painter) This abstract virtual function draws the canvas item using \a painter. */ /* Sets the QtCanvas upon which the canvas item is to be drawn to \a c. \sa canvas() */ void QtCanvasItem::setCanvas(QtCanvas* c) { bool v = isVisible(); setVisible(false); if (cnv) { if (ext) cnv->removeAnimation(this); cnv->removeItem(this); } cnv = c; if (cnv) { cnv->addItem(this); if (ext) cnv->addAnimation(this); } setVisible(v); } /* \fn QtCanvas* QtCanvasItem::canvas() const Returns the canvas containing the canvas item. */ /* Shorthand for setVisible(true). */ void QtCanvasItem::show() { setVisible(true); } /* Shorthand for setVisible(false). */ void QtCanvasItem::hide() { setVisible(false); } /* Makes the canvas item visible if \a yes is true, or invisible if \a yes is false. The change takes effect when QtCanvas::update() is next called. */ void QtCanvasItem::setVisible(bool yes) { if ((bool)vis!= yes) { if (yes) { vis = (uint)yes; addToChunks(); } else { removeFromChunks(); vis = (uint)yes; } } } /* \obsolete \fn bool QtCanvasItem::visible() const Use isVisible() instead. */ /* \fn bool QtCanvasItem::isVisible() const Returns true if the canvas item is visible; otherwise returns false. Note that in this context true does \e not mean that the canvas item is currently in a view, merely that if a view is showing the area where the canvas item is positioned, and the item is not obscured by items with higher z values, and the view is not obscured by overlaying windows, it would be visible. \sa setVisible(), z() */ /* \obsolete \fn bool QtCanvasItem::selected() const Use isSelected() instead. */ /* \fn bool QtCanvasItem::isSelected() const Returns true if the canvas item is selected; otherwise returns false. */ /* Sets the selected flag of the item to \a yes. If this changes the item's selected state the item will be redrawn when QtCanvas::update() is next called. The QtCanvas, QtCanvasItem and the Qt-supplied QtCanvasItem subclasses do not make use of this value. The setSelected() function is supplied because many applications need it, but it is up to you how you use the isSelected() value. */ void QtCanvasItem::setSelected(bool yes) { if ((bool)sel!= yes) { sel = (uint)yes; changeChunks(); } } /* \obsolete \fn bool QtCanvasItem::enabled() const Use isEnabled() instead. */ /* \fn bool QtCanvasItem::isEnabled() const Returns true if the QtCanvasItem is enabled; otherwise returns false. */ /* Sets the enabled flag of the item to \a yes. If this changes the item's enabled state the item will be redrawn when QtCanvas::update() is next called. The QtCanvas, QtCanvasItem and the Qt-supplied QtCanvasItem subclasses do not make use of this value. The setEnabled() function is supplied because many applications need it, but it is up to you how you use the isEnabled() value. */ void QtCanvasItem::setEnabled(bool yes) { if (ena!= (uint)yes) { ena = (uint)yes; changeChunks(); } } /* \obsolete \fn bool QtCanvasItem::active() const Use isActive() instead. */ /* \fn bool QtCanvasItem::isActive() const Returns true if the QtCanvasItem is active; otherwise returns false. */ /* Sets the active flag of the item to \a yes. If this changes the item's active state the item will be redrawn when QtCanvas::update() is next called. The QtCanvas, QtCanvasItem and the Qt-supplied QtCanvasItem subclasses do not make use of this value. The setActive() function is supplied because many applications need it, but it is up to you how you use the isActive() value. */ void QtCanvasItem::setActive(bool yes) { if (act!= (uint)yes) { act = (uint)yes; changeChunks(); } } bool qt_testCollision(const QtCanvasSprite* s1, const QtCanvasSprite* s2) { const QImage* s2image = s2->imageAdvanced()->collision_mask; QRect s2area = s2->boundingRectAdvanced(); QRect cyourarea(s2area.x(), s2area.y(), s2area.width(), s2area.height()); QImage* s1image = s1->imageAdvanced()->collision_mask; QRect s1area = s1->boundingRectAdvanced(); QRect ourarea = s1area.intersected(cyourarea); if (ourarea.isEmpty()) return false; int x2 = ourarea.x()-cyourarea.x(); int y2 = ourarea.y()-cyourarea.y(); int x1 = ourarea.x()-s1area.x(); int y1 = ourarea.y()-s1area.y(); int w = ourarea.width(); int h = ourarea.height(); if (!s2image) { if (!s1image) return w>0 && h>0; // swap everything around int t; t = x1; x1 = x2; x2 = t; t = y1; x1 = y2; y2 = t; s2image = s1image; s1image = 0; } // s2image != 0 // A non-linear search may be more efficient. // Perhaps spiralling out from the center, or a simpler // vertical expansion from the centreline. // We assume that sprite masks don't have // different bit orders. // // Q_ASSERT(s1image->bitOrder() == s2image->bitOrder()); if (s1image) { if (s1image->format() == QImage::Format_MonoLSB) { for (int j = 0; j < h; j++) { uchar* ml = s1image->scanLine(y1+j); const uchar* yl = s2image->scanLine(y2+j); for (int i = 0; i < w; i++) { if (*(yl + ((x2+i) >> 3)) & (1 << ((x2+i) & 7)) && *(ml + ((x1+i) >> 3)) & (1 << ((x1+i) & 7))) { return true; } } } } else { for (int j = 0; j < h; j++) { uchar* ml = s1image->scanLine(y1+j); const uchar* yl = s2image->scanLine(y2+j); for (int i = 0; i < w; i++) { if (*(yl + ((x2+i) >> 3)) & (1 << (7-((x2+i) & 7))) && *(ml + ((x1+i) >> 3)) & (1 << (7-((x1+i) & 7)))) { return true; } } } } } else { if (s2image->format() == QImage::Format_MonoLSB) { for (int j = 0; j < h; j++) { const uchar* yl = s2image->scanLine(y2+j); for (int i = 0; i < w; i++) { if (*(yl + ((x2+i) >> 3)) & (1 << ((x2+i) & 7))) { return true; } } } } else { for (int j = 0; j< h; j++) { const uchar* yl = s2image->scanLine(y2+j); for (int i = 0; i < w; i++) { if (*(yl + ((x2+i) >> 3)) & (1 << (7-((x2+i) & 7)))) { return true; } } } } } return false; } static bool collision_double_dispatch(const QtCanvasSprite* s1, const QtCanvasPolygonalItem* p1, const QtCanvasRectangle* r1, const QtCanvasEllipse* e1, const QtCanvasText* t1, const QtCanvasSprite* s2, const QtCanvasPolygonalItem* p2, const QtCanvasRectangle* r2, const QtCanvasEllipse* e2, const QtCanvasText* t2) { const QtCanvasItem* i1 = s1 ? (const QtCanvasItem*)s1 : p1 ? (const QtCanvasItem*)p1 : r1 ? (const QtCanvasItem*)r1 : e1 ? (const QtCanvasItem*)e1 : (const QtCanvasItem*)t1; const QtCanvasItem* i2 = s2 ? (const QtCanvasItem*)s2 : p2 ? (const QtCanvasItem*)p2 : r2 ? (const QtCanvasItem*)r2 : e2 ? (const QtCanvasItem*)e2 : (const QtCanvasItem*)t2; if (s1 && s2) { // a return qt_testCollision(s1, s2); } else if ((r1 || t1 || s1) && (r2 || t2 || s2)) { // b QRect rc1 = i1->boundingRectAdvanced(); QRect rc2 = i2->boundingRectAdvanced(); return rc1.intersects(rc2); } else if (e1 && e2 && e1->angleLength()>= 360*16 && e2->angleLength()>= 360*16 && e1->width() == e1->height() && e2->width() == e2->height()) { // c double xd = (e1->x()+e1->xVelocity())-(e2->x()+e1->xVelocity()); double yd = (e1->y()+e1->yVelocity())-(e2->y()+e1->yVelocity()); double rd = (e1->width()+e2->width())/2; return xd*xd+yd*yd <= rd*rd; } else if (p1 && (p2 || s2 || t2)) { // d QPolygon pa1 = p1->areaPointsAdvanced(); QPolygon pa2 = p2 ? p2->areaPointsAdvanced() : QPolygon(i2->boundingRectAdvanced()); bool col = !(QRegion(pa1) & QRegion(pa2, Qt::WindingFill)).isEmpty(); return col; } else { return collision_double_dispatch(s2, p2, r2, e2, t2, s1, p1, r1, e1, t1); } } /* \fn bool QtCanvasItem::collidesWith(const QtCanvasItem* other) const Returns true if the canvas item will collide with the \a other item \e after they have moved by their current velocities; otherwise returns false. \sa collisions() */ /* \class QtCanvasSprite qtcanvas.h \brief The QtCanvasSprite class provides an animated canvas item on a QtCanvas. A canvas sprite is an object which can contain any number of images (referred to as frames), only one of which is current, i.e. displayed, at any one time. The images can be passed in the constructor or set or changed later with setSequence(). If you subclass QtCanvasSprite you can change the frame that is displayed periodically, e.g. whenever QtCanvasItem::advance(1) is called to create the effect of animation. The current frame can be set with setFrame() or with move(). The number of frames available is given by frameCount(). The bounding rectangle of the current frame is returned by boundingRect(). The current frame's image can be retrieved with image(); use imageAdvanced() to retrieve the image for the frame that will be shown after advance(1) is called. Use the image() overload passing it an integer index to retrieve a particular image from the list of frames. Use width() and height() to retrieve the dimensions of the current frame. Use leftEdge() and rightEdge() to retrieve the current frame's left-hand and right-hand x-coordinates respectively. Use bottomEdge() and topEdge() to retrieve the current frame's bottom and top y-coordinates respectively. These functions have an overload which will accept an integer frame number to retrieve the coordinates of a particular frame. QtCanvasSprite draws very quickly, at the expense of memory. The current frame's image can be drawn on a painter with draw(). Like any other canvas item, canvas sprites can be moved with move() which sets the x and y coordinates and the frame number, as well as with QtCanvasItem::move() and QtCanvasItem::moveBy(), or by setting coordinates with QtCanvasItem::setX(), QtCanvasItem::setY() and QtCanvasItem::setZ(). */ /* \reimp */ bool QtCanvasSprite::collidesWith(const QtCanvasItem* i) const { return i->collidesWith(this, 0, 0, 0, 0); } /* Returns true if the canvas item collides with any of the given items; otherwise returns false. The parameters, \a s, \a p, \a r, \a e and \a t, are all the same object, this is just a type resolution trick. */ bool QtCanvasSprite::collidesWith(const QtCanvasSprite* s, const QtCanvasPolygonalItem* p, const QtCanvasRectangle* r, const QtCanvasEllipse* e, const QtCanvasText* t) const { return collision_double_dispatch(s, p, r, e, t, this, 0, 0, 0, 0); } /* \reimp */ bool QtCanvasPolygonalItem::collidesWith(const QtCanvasItem* i) const { return i->collidesWith(0, this, 0, 0, 0); } bool QtCanvasPolygonalItem::collidesWith(const QtCanvasSprite* s, const QtCanvasPolygonalItem* p, const QtCanvasRectangle* r, const QtCanvasEllipse* e, const QtCanvasText* t) const { return collision_double_dispatch(s, p, r, e, t, 0, this, 0, 0, 0); } /* \reimp */ bool QtCanvasRectangle::collidesWith(const QtCanvasItem* i) const { return i->collidesWith(0, this, this, 0, 0); } bool QtCanvasRectangle::collidesWith(const QtCanvasSprite* s, const QtCanvasPolygonalItem* p, const QtCanvasRectangle* r, const QtCanvasEllipse* e, const QtCanvasText* t) const { return collision_double_dispatch(s, p, r, e, t, 0, this, this, 0, 0); } /* \reimp */ bool QtCanvasEllipse::collidesWith(const QtCanvasItem* i) const { return i->collidesWith(0,this, 0, this, 0); } bool QtCanvasEllipse::collidesWith(const QtCanvasSprite* s, const QtCanvasPolygonalItem* p, const QtCanvasRectangle* r, const QtCanvasEllipse* e, const QtCanvasText* t) const { return collision_double_dispatch(s, p, r, e, t, 0, this, 0, this, 0); } /* \reimp */ bool QtCanvasText::collidesWith(const QtCanvasItem* i) const { return i->collidesWith(0, 0, 0, 0, this); } bool QtCanvasText::collidesWith(const QtCanvasSprite* s, const QtCanvasPolygonalItem* p, const QtCanvasRectangle* r, const QtCanvasEllipse* e, const QtCanvasText* t) const { return collision_double_dispatch(s, p, r, e, t, 0, 0, 0, 0, this); } /* Returns the list of canvas items that this canvas item has collided with. A collision is generally defined as occurring when the pixels of one item draw on the pixels of another item, but not all subclasses are so precise. Also, since pixel-wise collision detection can be slow, this function works in either exact or inexact mode, according to the \a exact parameter. If \a exact is true, the canvas items returned have been accurately tested for collision with the canvas item. If \a exact is false, the canvas items returned are \e near the canvas item. You can test the canvas items returned using collidesWith() if any are interesting collision candidates. By using this approach, you can ignore some canvas items for which collisions are not relevant. The returned list is a list of QtCanvasItems, but often you will need to cast the items to their subclass types. The safe way to do this is to use rtti() before casting. This provides some of the functionality of the standard C++ dynamic cast operation even on compilers where dynamic casts are not available. Note that a canvas item may be `on' a canvas, e.g. it was created with the canvas as parameter, even though its coordinates place it beyond the edge of the canvas's area. Collision detection only works for canvas items which are wholly or partly within the canvas's area. Note that if items have a velocity (see \l setVelocity()), then collision testing is done based on where the item \e will be when it moves, not its current location. For example, a "ball" item doesn't need to actually embed into a "wall" item before a collision is detected. For items without velocity, plain intersection is used. */ QtCanvasItemList QtCanvasItem::collisions(bool exact) const { return canvas()->collisions(chunks(), this, exact); } /* Returns a list of canvas items that collide with the point \a p. The list is ordered by z coordinates, from highest z coordinate (front-most item) to lowest z coordinate (rear-most item). */ QtCanvasItemList QtCanvas::collisions(const QPoint& p) const { return collisions(QRect(p, QSize(1, 1))); } /* \overload Returns a list of items which collide with the rectangle \a r. The list is ordered by z coordinates, from highest z coordinate (front-most item) to lowest z coordinate (rear-most item). */ QtCanvasItemList QtCanvas::collisions(const QRect& r) const { QtCanvasRectangle i(r, (QtCanvas*)this); i.setPen(NoPen); i.show(); // doesn't actually show, since we destroy it QtCanvasItemList l = i.collisions(true); qSort(l.begin(), l.end(), QtCanvasItemLess()); return l; } /* \overload Returns a list of canvas items which intersect with the chunks listed in \a chunklist, excluding \a item. If \a exact is true, only those which actually \link QtCanvasItem::collidesWith() collide with\endlink \a item are returned; otherwise canvas items are included just for being in the chunks. This is a utility function mainly used to implement the simpler QtCanvasItem::collisions() function. */ QtCanvasItemList QtCanvas::collisions(const QPolygon& chunklist, const QtCanvasItem* item, bool exact) const { QSet seen; QtCanvasItemList result; for (int i = 0; i <(int)chunklist.count(); i++) { int x = chunklist[i].x(); int y = chunklist[i].y(); if (validChunk(x, y)) { const QtCanvasItemList &l = chunk(x, y).list(); for (int i = 0; i < l.size(); ++i) { QtCanvasItem *g = l.at(i); if (g != item) { if (!seen.contains(g)) { seen.insert(g); if (!exact || item->collidesWith(g)) result.append(g); } } } } } return result; } /* \internal Adds the item to all the chunks it covers. */ void QtCanvasItem::addToChunks() { if (isVisible() && canvas()) { QPolygon pa = chunks(); for (int i = 0; i < (int)pa.count(); i++) canvas()->addItemToChunk(this, pa[i].x(), pa[i].y()); val = (uint)true; } } /* \internal Removes the item from all the chunks it covers. */ void QtCanvasItem::removeFromChunks() { if (isVisible() && canvas()) { QPolygon pa = chunks(); for (int i = 0; i < (int)pa.count(); i++) canvas()->removeItemFromChunk(this, pa[i].x(), pa[i].y()); } } /* \internal Sets all the chunks covered by the item to be refreshed with QtCanvas::update() is next called. */ void QtCanvasItem::changeChunks() { if (isVisible() && canvas()) { if (!val) addToChunks(); QPolygon pa = chunks(); for (int i = 0; i < (int)pa.count(); i++) canvas()->setChangedChunk(pa[i].x(), pa[i].y()); } } /* \fn QRect QtCanvasItem::boundingRect() const Returns the bounding rectangle in pixels that the canvas item covers. \sa boundingRectAdvanced() */ /* Returns the bounding rectangle of pixels that the canvas item \e will cover after advance(1) is called. \sa boundingRect() */ QRect QtCanvasItem::boundingRectAdvanced() const { int dx = int(x()+xVelocity())-int(x()); int dy = int(y()+yVelocity())-int(y()); QRect r = boundingRect(); r.translate(dx, dy); return r; } /* \class QtCanvasPixmap qtcanvas.h \brief The QtCanvasPixmap class provides pixmaps for QtCanvasSprites. If you want to show a single pixmap on a QtCanvas use a QtCanvasSprite with just one pixmap. When pixmaps are inserted into a QtCanvasPixmapArray they are held as QtCanvasPixmaps. \l{QtCanvasSprite}s are used to show pixmaps on \l{QtCanvas}es and hold their pixmaps in a QtCanvasPixmapArray. If you retrieve a frame (pixmap) from a QtCanvasSprite it will be returned as a QtCanvasPixmap. The pixmap is a QPixmap and can only be set in the constructor. There are three different constructors, one taking a QPixmap, one a QImage and one a file name that refers to a file in any supported file format (see QImageReader). QtCanvasPixmap can have a hotspot which is defined in terms of an (x, y) offset. When you create a QtCanvasPixmap from a PNG file or from a QImage that has a QImage::offset(), the offset() is initialized appropriately, otherwise the constructor leaves it at (0, 0). You can set it later using setOffset(). When the QtCanvasPixmap is used in a QtCanvasSprite, the offset position is the point at QtCanvasItem::x() and QtCanvasItem::y(), not the top-left corner of the pixmap. Note that for QtCanvasPixmap objects created by a QtCanvasSprite, the position of each QtCanvasPixmap object is set so that the hotspot stays in the same position. \sa QtCanvasPixmapArray QtCanvasItem QtCanvasSprite */ /* Constructs a QtCanvasPixmap that uses the image stored in \a datafilename. */ QtCanvasPixmap::QtCanvasPixmap(const QString& datafilename) { QImage image(datafilename); init(image); } /* Constructs a QtCanvasPixmap from the image \a image. */ QtCanvasPixmap::QtCanvasPixmap(const QImage& image) { init(image); } /* Constructs a QtCanvasPixmap from the pixmap \a pm using the offset \a offset. */ QtCanvasPixmap::QtCanvasPixmap(const QPixmap& pm, const QPoint& offset) { init(pm, offset.x(), offset.y()); } void QtCanvasPixmap::init(const QImage& image) { this->QPixmap::operator = (QPixmap::fromImage(image)); hotx = image.offset().x(); hoty = image.offset().y(); #ifndef QT_NO_IMAGE_DITHER_TO_1 if(image.hasAlphaChannel()) { QImage i = image.createAlphaMask(); collision_mask = new QImage(i); } else #endif collision_mask = 0; } void QtCanvasPixmap::init(const QPixmap& pixmap, int hx, int hy) { (QPixmap&)*this = pixmap; hotx = hx; hoty = hy; if(pixmap.hasAlphaChannel()) { QImage i = mask().toImage(); collision_mask = new QImage(i); } else collision_mask = 0; } /* Destroys the pixmap. */ QtCanvasPixmap::~QtCanvasPixmap() { delete collision_mask; } /* \fn int QtCanvasPixmap::offsetX() const Returns the x-offset of the pixmap's hotspot. \sa setOffset() */ /* \fn int QtCanvasPixmap::offsetY() const Returns the y-offset of the pixmap's hotspot. \sa setOffset() */ /* \fn void QtCanvasPixmap::setOffset(int x, int y) Sets the offset of the pixmap's hotspot to (\a x, \a y). \warning Do not call this function if any QtCanvasSprites are currently showing this pixmap. */ /* \class QtCanvasPixmapArray qtcanvas.h \brief The QtCanvasPixmapArray class provides an array of QtCanvasPixmaps. This class is used by QtCanvasSprite to hold an array of pixmaps. It is used to implement animated sprites, i.e. images that change over time, with each pixmap in the array holding one frame. Depending on the constructor you use you can load multiple pixmaps into the array either from a directory (specifying a wildcard pattern for the files), or from a list of QPixmaps. You can also read in a set of pixmaps after construction using readPixmaps(). Individual pixmaps can be set with setImage() and retrieved with image(). The number of pixmaps in the array is returned by count(). QtCanvasSprite uses an image's mask for collision detection. You can change this by reading in a separate set of image masks using readCollisionMasks(). */ /* Constructs an invalid array (i.e. isValid() will return false). You must call readPixmaps() before being able to use this QtCanvasPixmapArray. */ QtCanvasPixmapArray::QtCanvasPixmapArray() : framecount(0), img(0) { } /* Constructs a QtCanvasPixmapArray from files. The \a fc parameter sets the number of frames to be loaded for this image. If \a fc is not 0, \a datafilenamepattern should contain "%1", e.g. "foo%1.png". The actual filenames are formed by replacing the %1 with four-digit integers from 0 to (fc - 1), e.g. foo0000.png, foo0001.png, foo0002.png, etc. If \a fc is 0, \a datafilenamepattern is asssumed to be a filename, and the image contained in this file will be loaded as the first (and only) frame. If \a datafilenamepattern does not exist, is not readable, isn't an image, or some other error occurs, the array ends up empty and isValid() returns false. */ QtCanvasPixmapArray::QtCanvasPixmapArray(const QString& datafilenamepattern, int fc) : framecount(0), img(0) { readPixmaps(datafilenamepattern, fc); } /* \obsolete Use QtCanvasPixmapArray::QtCanvasPixmapArray(QtValueList, QPolygon) instead. Constructs a QtCanvasPixmapArray from the list of QPixmaps \a list. The \a hotspots list has to be of the same size as \a list. */ QtCanvasPixmapArray::QtCanvasPixmapArray(const QList &list, const QPolygon &hotspots) : framecount(list.count()), img(new QtCanvasPixmap*[list.count()]) { if (list.count() != hotspots.count()) { qWarning("QtCanvasPixmapArray: lists have different lengths"); reset(); img = 0; } else { for (int i = 0; i < framecount; i++) img[i] = new QtCanvasPixmap(list.at(i), hotspots.at(i)); } } /* Destroys the pixmap array and all the pixmaps it contains. */ QtCanvasPixmapArray::~QtCanvasPixmapArray() { reset(); } void QtCanvasPixmapArray::reset() { for (int i = 0; i < framecount; i++) delete img[i]; delete [] img; img = 0; framecount = 0; } /* Reads one or more pixmaps into the pixmap array. If \a fc is not 0, \a filenamepattern should contain "%1", e.g. "foo%1.png". The actual filenames are formed by replacing the %1 with four-digit integers from 0 to (fc - 1), e.g. foo0000.png, foo0001.png, foo0002.png, etc. If \a fc is 0, \a filenamepattern is asssumed to be a filename, and the image contained in this file will be loaded as the first (and only) frame. If \a filenamepattern does not exist, is not readable, isn't an image, or some other error occurs, this function will return false, and isValid() will return false; otherwise this function will return true. \sa isValid() */ bool QtCanvasPixmapArray::readPixmaps(const QString& filenamepattern, int fc) { return readPixmaps(filenamepattern, fc, false); } /* Reads new collision masks for the array. By default, QtCanvasSprite uses the image mask of a sprite to detect collisions. Use this function to set your own collision image masks. If count() is 1 \a filename must specify a real filename to read the mask from. If count() is greater than 1, the \a filename must contain a "%1" that will get replaced by the number of the mask to be loaded, just like QtCanvasPixmapArray::readPixmaps(). All collision masks must be 1-bit images or this function call will fail. If the file isn't readable, contains the wrong number of images, or there is some other error, this function will return false, and the array will be flagged as invalid; otherwise this function returns true. \sa isValid() */ bool QtCanvasPixmapArray::readCollisionMasks(const QString& filename) { return readPixmaps(filename, framecount, true); } bool QtCanvasPixmapArray::readPixmaps(const QString& datafilenamepattern, int fc, bool maskonly) { if (!maskonly) { reset(); framecount = fc; if (!framecount) framecount = 1; img = new QtCanvasPixmap*[framecount]; } if (!img) return false; bool ok = true; bool arg = fc > 1; if (!arg) framecount = 1; for (int i = 0; i < framecount; i++) { QString r; r.sprintf("%04d", i); if (maskonly) { if (!img[i]->collision_mask) img[i]->collision_mask = new QImage(); img[i]->collision_mask->load( arg ? datafilenamepattern.arg(r) : datafilenamepattern); ok = ok && !img[i]->collision_mask->isNull() && img[i]->collision_mask->depth() == 1; } else { img[i] = new QtCanvasPixmap( arg ? datafilenamepattern.arg(r) : datafilenamepattern); ok = ok && !img[i]->isNull(); } } if (!ok) { reset(); } return ok; } /* \obsolete Use isValid() instead. This returns false if the array is valid, and true if it is not. */ bool QtCanvasPixmapArray::operator!() { return img == 0; } /* Returns true if the pixmap array is valid; otherwise returns false. */ bool QtCanvasPixmapArray::isValid() const { return (img != 0); } /* \fn QtCanvasPixmap* QtCanvasPixmapArray::image(int i) const Returns pixmap \a i in the array, if \a i is non-negative and less than than count(), and returns an unspecified value otherwise. */ // ### wouldn't it be better to put empty QtCanvasPixmaps in there instead of // initializing the additional elements in the array to 0? Lars /* Replaces the pixmap at index \a i with pixmap \a p. The array takes ownership of \a p and will delete \a p when the array itself is deleted. If \a i is beyond the end of the array the array is extended to at least i+1 elements, with elements count() to i-1 being initialized to 0. */ void QtCanvasPixmapArray::setImage(int i, QtCanvasPixmap* p) { if (i >= framecount) { QtCanvasPixmap** newimg = new QtCanvasPixmap*[i+1]; memcpy(newimg, img, sizeof(QtCanvasPixmap *)*framecount); memset(newimg + framecount, 0, sizeof(QtCanvasPixmap *)*(i+1 - framecount)); framecount = i+1; delete [] img; img = newimg; } delete img[i]; img[i] = p; } /* \fn uint QtCanvasPixmapArray::count() const Returns the number of pixmaps in the array. */ /* Returns the x-coordinate of the current left edge of the sprite. (This may change as the sprite animates since different frames may have different left edges.) \sa rightEdge() bottomEdge() topEdge() */ int QtCanvasSprite::leftEdge() const { return int(x()) - image()->hotx; } /* \overload Returns what the x-coordinate of the left edge of the sprite would be if the sprite (actually its hotspot) were moved to x-position \a nx. \sa rightEdge() bottomEdge() topEdge() */ int QtCanvasSprite::leftEdge(int nx) const { return nx - image()->hotx; } /* Returns the y-coordinate of the top edge of the sprite. (This may change as the sprite animates since different frames may have different top edges.) \sa leftEdge() rightEdge() bottomEdge() */ int QtCanvasSprite::topEdge() const { return int(y()) - image()->hoty; } /* \overload Returns what the y-coordinate of the top edge of the sprite would be if the sprite (actually its hotspot) were moved to y-position \a ny. \sa leftEdge() rightEdge() bottomEdge() */ int QtCanvasSprite::topEdge(int ny) const { return ny - image()->hoty; } /* Returns the x-coordinate of the current right edge of the sprite. (This may change as the sprite animates since different frames may have different right edges.) \sa leftEdge() bottomEdge() topEdge() */ int QtCanvasSprite::rightEdge() const { return leftEdge() + image()->width()-1; } /* \overload Returns what the x-coordinate of the right edge of the sprite would be if the sprite (actually its hotspot) were moved to x-position \a nx. \sa leftEdge() bottomEdge() topEdge() */ int QtCanvasSprite::rightEdge(int nx) const { return leftEdge(nx) + image()->width()-1; } /* Returns the y-coordinate of the current bottom edge of the sprite. (This may change as the sprite animates since different frames may have different bottom edges.) \sa leftEdge() rightEdge() topEdge() */ int QtCanvasSprite::bottomEdge() const { return topEdge() + image()->height()-1; } /* \overload Returns what the y-coordinate of the top edge of the sprite would be if the sprite (actually its hotspot) were moved to y-position \a ny. \sa leftEdge() rightEdge() topEdge() */ int QtCanvasSprite::bottomEdge(int ny) const { return topEdge(ny) + image()->height()-1; } /* \fn QtCanvasPixmap* QtCanvasSprite::image() const Returns the current frame's image. \sa frame(), setFrame() */ /* \fn QtCanvasPixmap* QtCanvasSprite::image(int f) const \overload Returns the image for frame \a f. Does not do any bounds checking on \a f. */ /* Returns the image the sprite \e will have after advance(1) is called. By default this is the same as image(). */ QtCanvasPixmap* QtCanvasSprite::imageAdvanced() const { return image(); } /* Returns the bounding rectangle for the image in the sprite's current frame. This assumes that the images are tightly cropped (i.e. do not have transparent pixels all along a side). */ QRect QtCanvasSprite::boundingRect() const { return QRect(leftEdge(), topEdge(), width(), height()); } /* \internal Returns the chunks covered by the item. */ QPolygon QtCanvasItem::chunks() const { QPolygon r; int n = 0; QRect br = boundingRect(); if (isVisible() && canvas()) { int chunksize = canvas()->chunkSize(); br &= QRect(0, 0, canvas()->width(), canvas()->height()); if (br.isValid()) { r.resize((br.width()/chunksize+2)*(br.height()/chunksize+2)); for (int j = br.top()/chunksize; j <= br.bottom()/chunksize; j++) { for (int i = br.left()/chunksize; i <= br.right()/chunksize; i++) { r[n++] = QPoint(i, j); } } } } r.resize(n); return r; } /* \internal Add the sprite to the chunks in its QtCanvas which it overlaps. */ void QtCanvasSprite::addToChunks() { if (isVisible() && canvas()) { int chunksize = canvas()->chunkSize(); for (int j = topEdge()/chunksize; j <= bottomEdge()/chunksize; j++) { for (int i = leftEdge()/chunksize; i <= rightEdge()/chunksize; i++) { canvas()->addItemToChunk(this, i, j); } } } } /* \internal Remove the sprite from the chunks in its QtCanvas which it overlaps. \sa addToChunks() */ void QtCanvasSprite::removeFromChunks() { if (isVisible() && canvas()) { int chunksize = canvas()->chunkSize(); for (int j = topEdge()/chunksize; j <= bottomEdge()/chunksize; j++) { for (int i = leftEdge()/chunksize; i <= rightEdge()/chunksize; i++) { canvas()->removeItemFromChunk(this, i, j); } } } } /* The width of the sprite for the current frame's image. \sa frame() */ //### mark: Why don't we have width(int) and height(int) to be //consistent with leftEdge() and leftEdge(int)? int QtCanvasSprite::width() const { return image()->width(); } /* The height of the sprite for the current frame's image. \sa frame() */ int QtCanvasSprite::height() const { return image()->height(); } /* Draws the current frame's image at the sprite's current position on painter \a painter. */ void QtCanvasSprite::draw(QPainter& painter) { painter.drawPixmap(leftEdge(), topEdge(), *image()); } /* \class QtCanvasView qtcanvas.h \brief The QtCanvasView class provides an on-screen view of a QtCanvas. A QtCanvasView is widget which provides a view of a QtCanvas. If you want users to be able to interact with a canvas view, subclass QtCanvasView. You might then reimplement QtScrollView::contentsMousePressEvent(). For example: \code void MyCanvasView::contentsMousePressEvent(QMouseEvent* e) { QtCanvasItemList l = canvas()->collisions(e->pos()); for (QtCanvasItemList::Iterator it = l.begin(); it!= l.end(); ++it) { if ((*it)->rtti() == QtCanvasRectangle::RTTI) qDebug("A QtCanvasRectangle lies somewhere at this point"); } } \endcode The canvas view shows canvas canvas(); this can be changed using setCanvas(). A transformation matrix can be used to transform the view of the canvas in various ways, for example, zooming in or out or rotating. For example: \code QMatrix wm; wm.scale(2, 2); // Zooms in by 2 times wm.rotate(90); // Rotates 90 degrees counter clockwise // around the origin. wm.translate(0, -canvas->height()); // moves the canvas down so what was visible // before is still visible. myCanvasView->setWorldMatrix(wm); \endcode Use setWorldMatrix() to set the canvas view's world matrix: you must ensure that the world matrix is invertible. The current world matrix is retrievable with worldMatrix(), and its inversion is retrievable with inverseWorldMatrix(). Example: The following code finds the part of the canvas that is visible in this view, i.e. the bounding rectangle of the view in canvas coordinates. \code QRect rc = QRect(myCanvasView->contentsX(), myCanvasView->contentsY(), myCanvasView->visibleWidth(), myCanvasView->visibleHeight()); QRect canvasRect = myCanvasView->inverseWorldMatrix().mapRect(rc); \endcode \sa QMatrix QPainter::setWorldMatrix() */ class QtCanvasWidget : public QWidget { public: QtCanvasWidget(QtCanvasView *view) : QWidget(view) { m_view = view; } protected: void paintEvent(QPaintEvent *e); void mousePressEvent(QMouseEvent *e) { m_view->contentsMousePressEvent(e); } void mouseMoveEvent(QMouseEvent *e) { m_view->contentsMouseMoveEvent(e); } void mouseReleaseEvent(QMouseEvent *e) { m_view->contentsMouseReleaseEvent(e); } void mouseDoubleClickEvent(QMouseEvent *e) { m_view->contentsMouseDoubleClickEvent(e); } void dragEnterEvent(QDragEnterEvent *e) { m_view->contentsDragEnterEvent(e); } void dragMoveEvent(QDragMoveEvent *e) { m_view->contentsDragMoveEvent(e); } void dragLeaveEvent(QDragLeaveEvent *e) { m_view->contentsDragLeaveEvent(e); } void dropEvent(QDropEvent *e) { m_view->contentsDropEvent(e); } void wheelEvent(QWheelEvent *e) { m_view->contentsWheelEvent(e); } void contextMenuEvent(QContextMenuEvent *e) { m_view->contentsContextMenuEvent(e); } QtCanvasView *m_view; }; void QtCanvasWidget::paintEvent(QPaintEvent *e) { QPainter p(this); if (m_view->d->highQuality) { p.setRenderHint(QPainter::Antialiasing); p.setRenderHint(QPainter::SmoothPixmapTransform); } m_view->drawContents(&p, e->rect().x(), e->rect().y(), e->rect().width(), e->rect().height()); } /* Constructs a QtCanvasView with parent \a parent. The canvas view is not associated with a canvas, so you must to call setCanvas() to view a canvas. */ QtCanvasView::QtCanvasView(QWidget* parent) : QScrollArea(parent) { d = new QtCanvasViewData; setWidget(new QtCanvasWidget(this)); d->highQuality = false; viewing = 0; setCanvas(0); } /* \overload Constructs a QtCanvasView which views canvas \a canvas, with parent \a parent. */ QtCanvasView::QtCanvasView(QtCanvas* canvas, QWidget* parent) : QScrollArea(parent) { d = new QtCanvasViewData; d->highQuality = false; setWidget(new QtCanvasWidget(this)); viewing = 0; setCanvas(canvas); } /* Destroys the canvas view. The associated canvas is \e not deleted. */ QtCanvasView::~QtCanvasView() { delete d; d = 0; setCanvas(0); } /* \property QtCanvasView::highQualityRendering \brief whether high quality rendering is turned on If high quality rendering is turned on, the canvas view will paint itself using the QPainter::Antialiasing and QPainter::SmoothPixmapTransform rendering flags. Enabling these flag will usually improve the visual appearance on the screen at the cost of rendering speed. */ bool QtCanvasView::highQualityRendering() const { return d->highQuality; } void QtCanvasView::setHighQualityRendering(bool enable) { d->highQuality = enable; widget()->update(); } void QtCanvasView::contentsMousePressEvent(QMouseEvent *e) { e->ignore(); } void QtCanvasView::contentsMouseReleaseEvent(QMouseEvent *e) { e->ignore(); } void QtCanvasView::contentsMouseDoubleClickEvent(QMouseEvent *e) { e->ignore(); } void QtCanvasView::contentsMouseMoveEvent(QMouseEvent *e) { e->ignore(); } void QtCanvasView::contentsDragEnterEvent(QDragEnterEvent *) { } void QtCanvasView::contentsDragMoveEvent(QDragMoveEvent *) { } void QtCanvasView::contentsDragLeaveEvent(QDragLeaveEvent *) { } void QtCanvasView::contentsDropEvent(QDropEvent *) { } void QtCanvasView::contentsWheelEvent(QWheelEvent *e) { e->ignore(); } void QtCanvasView::contentsContextMenuEvent(QContextMenuEvent *e) { e->ignore(); } /* \fn QtCanvas* QtCanvasView::canvas() const Returns a pointer to the canvas which the QtCanvasView is currently showing. */ /* Sets the canvas that the QtCanvasView is showing to the canvas \a canvas. */ void QtCanvasView::setCanvas(QtCanvas* canvas) { if (viewing == canvas) return; if (viewing) { disconnect(viewing); viewing->removeView(this); } viewing = canvas; if (viewing) { connect(viewing, SIGNAL(resized()), this, SLOT(updateContentsSize())); viewing->addView(this); } if (d) // called by d'tor updateContentsSize(); update(); } /* Returns a reference to the canvas view's current transformation matrix. \sa setWorldMatrix() inverseWorldMatrix() */ const QMatrix &QtCanvasView::worldMatrix() const { return d->xform; } /* Returns a reference to the inverse of the canvas view's current transformation matrix. \sa setWorldMatrix() worldMatrix() */ const QMatrix &QtCanvasView::inverseWorldMatrix() const { return d->ixform; } /* Sets the transformation matrix of the QtCanvasView to \a wm. The matrix must be invertible (i.e. if you create a world matrix that zooms out by 2 times, then the inverse of this matrix is one that will zoom in by 2 times). When you use this, you should note that the performance of the QtCanvasView will decrease considerably. Returns false if \a wm is not invertable; otherwise returns true. \sa worldMatrix() inverseWorldMatrix() QMatrix::isInvertible() */ bool QtCanvasView::setWorldMatrix(const QMatrix & wm) { bool ok = wm.isInvertible(); if (ok) { d->xform = wm; d->ixform = wm.inverted(); updateContentsSize(); widget()->update(); } return ok; } void QtCanvasView::updateContentsSize() { if (viewing) { QRect br; br = d->xform.mapRect(QRect(0, 0, viewing->width(), viewing->height())); widget()->resize(br.size()); } else { widget()->resize(size()); } } /* Repaints part of the QtCanvas that the canvas view is showing starting at \a cx by \a cy, with a width of \a cw and a height of \a ch using the painter \a p. */ void QtCanvasView::drawContents(QPainter *p, int cx, int cy, int cw, int ch) { if (!viewing) return; QPainterPath clipPath; clipPath.addRect(viewing->rect()); p->setClipPath(d->xform.map(clipPath), Qt::IntersectClip); viewing->drawViewArea(this, p, QRect(cx, cy, cw, ch), false); } /* Suggests a size sufficient to view the entire canvas. */ QSize QtCanvasView::sizeHint() const { if (!canvas()) return QScrollArea::sizeHint(); // should maybe take transformations into account return (canvas()->size() + 2 * QSize(frameWidth(), frameWidth())) .boundedTo(3 * QApplication::desktop()->size() / 4); } /* \class QtCanvasPolygonalItem qtcanvas.h \brief The QtCanvasPolygonalItem class provides a polygonal canvas item on a QtCanvas. The mostly rectangular classes, such as QtCanvasSprite and QtCanvasText, use the object's bounding rectangle for movement, repainting and collision calculations. For most other items, the bounding rectangle can be far too large -- a diagonal line being the worst case, and there are many other cases which are also bad. QtCanvasPolygonalItem provides polygon-based bounding rectangle handling, etc., which is much faster for non-rectangular items. Derived classes should try to define as small an area as possible to maximize efficiency, but the polygon must \e definitely be contained completely within the polygonal area. Calculating the exact requirements is usually difficult, but if you allow a small overestimate it can be easy and quick, while still getting almost all of QtCanvasPolygonalItem's speed. Note that all subclasses \e must call hide() in their destructor since hide() needs to be able to access areaPoints(). Normally, QtCanvasPolygonalItem uses the odd-even algorithm for determining whether an object intersects this object. You can change this to the winding algorithm using setWinding(). The bounding rectangle is available using boundingRect(). The points bounding the polygonal item are retrieved with areaPoints(). Use areaPointsAdvanced() to retrieve the bounding points the polygonal item \e will have after QtCanvasItem::advance(1) has been called. If the shape of the polygonal item is about to change while the item is visible, call invalidate() before updating with a different result from \l areaPoints(). By default, QtCanvasPolygonalItem objects have a black pen and no brush (the default QPen and QBrush constructors). You can change this with setPen() and setBrush(), but note that some QtCanvasPolygonalItem subclasses only use the brush, ignoring the pen setting. The polygonal item can be drawn on a painter with draw(). Subclasses must reimplement drawShape() to draw themselves. Like any other canvas item polygonal items can be moved with QtCanvasItem::move() and QtCanvasItem::moveBy(), or by setting coordinates with QtCanvasItem::setX(), QtCanvasItem::setY() and QtCanvasItem::setZ(). */ /* Since most polygonal items don't have a pen, the default is NoPen and a black brush. */ static const QPen& defaultPolygonPen() { static QPen* dp = 0; if (!dp) dp = new QPen; return *dp; } static const QBrush& defaultPolygonBrush() { static QBrush* db = 0; if (!db) db = new QBrush; return *db; } /* Constructs a QtCanvasPolygonalItem on the canvas \a canvas. */ QtCanvasPolygonalItem::QtCanvasPolygonalItem(QtCanvas* canvas) : QtCanvasItem(canvas), br(defaultPolygonBrush()), pn(defaultPolygonPen()) { wind = 0; } /* Note that all subclasses \e must call hide() in their destructor since hide() needs to be able to access areaPoints(). */ QtCanvasPolygonalItem::~QtCanvasPolygonalItem() { } /* Returns true if the polygonal item uses the winding algorithm to determine the "inside" of the polygon. Returns false if it uses the odd-even algorithm. The default is to use the odd-even algorithm. \sa setWinding() */ bool QtCanvasPolygonalItem::winding() const { return wind; } /* If \a enable is true, the polygonal item will use the winding algorithm to determine the "inside" of the polygon; otherwise the odd-even algorithm will be used. The default is to use the odd-even algorithm. \sa winding() */ void QtCanvasPolygonalItem::setWinding(bool enable) { wind = enable; } /* Invalidates all information about the area covered by the canvas item. The item will be updated automatically on the next call that changes the item's status, for example, move() or update(). Call this function if you are going to change the shape of the item (as returned by areaPoints()) while the item is visible. */ void QtCanvasPolygonalItem::invalidate() { val = (uint)false; removeFromChunks(); } /* \fn QtCanvasPolygonalItem::isValid() const Returns true if the polygonal item's area information has not been invalidated; otherwise returns false. \sa invalidate() */ /* Returns the points the polygonal item \e will have after QtCanvasItem::advance(1) is called, i.e. what the points are when advanced by the current xVelocity() and yVelocity(). */ QPolygon QtCanvasPolygonalItem::areaPointsAdvanced() const { int dx = int(x()+xVelocity())-int(x()); int dy = int(y()+yVelocity())-int(y()); QPolygon r = areaPoints(); r.detach(); // Explicit sharing is stupid. if (dx || dy) r.translate(dx, dy); return r; } //#define QCANVAS_POLYGONS_DEBUG #ifdef QCANVAS_POLYGONS_DEBUG static QWidget* dbg_wid = 0; static QPainter* dbg_ptr = 0; #endif class QPolygonalProcessor { public: QPolygonalProcessor(QtCanvas* c, const QPolygon& pa) : canvas(c) { QRect pixelbounds = pa.boundingRect(); int cs = canvas->chunkSize(); QRect canvasbounds = pixelbounds.intersected(canvas->rect()); bounds.setLeft(canvasbounds.left()/cs); bounds.setRight(canvasbounds.right()/cs); bounds.setTop(canvasbounds.top()/cs); bounds.setBottom(canvasbounds.bottom()/cs); bitmap = QImage(bounds.width(), bounds.height(), QImage::Format_MonoLSB); pnt = 0; bitmap.fill(0); #ifdef QCANVAS_POLYGONS_DEBUG dbg_start(); #endif } inline void add(int x, int y) { if (pnt >= (int)result.size()) { result.resize(pnt*2+10); } result[pnt++] = QPoint(x+bounds.x(), y+bounds.y()); #ifdef QCANVAS_POLYGONS_DEBUG if (dbg_ptr) { int cs = canvas->chunkSize(); QRect r(x*cs+bounds.x()*cs, y*cs+bounds.y()*cs, cs-1, cs-1); dbg_ptr->setPen(Qt::blue); dbg_ptr->drawRect(r); } #endif } inline void addBits(int x1, int x2, uchar newbits, int xo, int yo) { for (int i = x1; i <= x2; i++) if (newbits & (1 <resize(800, 600); dbg_wid->show(); dbg_ptr = new QPainter(dbg_wid); dbg_ptr->setBrush(Qt::NoBrush); } dbg_ptr->fillRect(dbg_wid->rect(), Qt::white); } #endif void doSpans(int n, QPoint* pt, int* w) { int cs = canvas->chunkSize(); for (int j = 0; j < n; j++) { int y = pt[j].y()/cs-bounds.y(); if (y >= bitmap.height() || y < 0) continue; uchar* l = bitmap.scanLine(y); int x = pt[j].x(); int x1 = x/cs-bounds.x(); if (x1 > bounds.width()) continue; x1 = qMax(0,x1); int x2 = (x+w[j])/cs-bounds.x(); if (x2 < 0) continue; x2 = qMin(bounds.width(), x2); int x1q = x1/8; int x1r = x1%8; int x2q = x2/8; int x2r = x2%8; #ifdef QCANVAS_POLYGONS_DEBUG if (dbg_ptr) dbg_ptr->setPen(Qt::yellow); #endif if (x1q == x2q) { uchar newbits = (~l[x1q]) & (((2 <<(x2r-x1r))-1) <setPen(Qt::darkGreen); #endif addBits(x1r, x2r, newbits, x1q*8, y); l[x1q] |= newbits; } } else { #ifdef QCANVAS_POLYGONS_DEBUG if (dbg_ptr) dbg_ptr->setPen(Qt::blue); #endif uchar newbits1 = (~l[x1q]) & (0xff <setPen(Qt::green); #endif addBits(x1r, 7, newbits1, x1q*8, y); l[x1q] |= newbits1; } for (int i = x1q+1; i < x2q; i++) { if (l[i] != 0xff) { addBits(0, 7, ~l[i], i*8, y); l[i] = 0xff; } } uchar newbits2 = (~l[x2q]) & (0xff>>(7-x2r)); if (newbits2) { #ifdef QCANVAS_POLYGONS_DEBUG if (dbg_ptr) dbg_ptr->setPen(Qt::red); #endif addBits(0, x2r, newbits2, x2q*8, y); l[x2q] |= newbits2; } } #ifdef QCANVAS_POLYGONS_DEBUG if (dbg_ptr) { dbg_ptr->drawLine(pt[j], pt[j]+QPoint(w[j], 0)); } #endif } result.resize(pnt); } int pnt; QPolygon result; QtCanvas* canvas; QRect bounds; QImage bitmap; }; QPolygon QtCanvasPolygonalItem::chunks() const { QPolygon pa = areaPoints(); if (!pa.size()) { pa.detach(); // Explicit sharing is stupid. return pa; } QPolygonalProcessor processor(canvas(), pa); scanPolygon(pa, wind, processor); return processor.result; } /* Simply calls QtCanvasItem::chunks(). */ QPolygon QtCanvasRectangle::chunks() const { // No need to do a polygon scan! return QtCanvasItem::chunks(); } /* Returns the bounding rectangle of the polygonal item, based on areaPoints(). */ QRect QtCanvasPolygonalItem::boundingRect() const { return areaPoints().boundingRect(); } /* Reimplemented from QtCanvasItem, this draws the polygonal item by setting the pen and brush for the item on the painter \a p and calling drawShape(). */ void QtCanvasPolygonalItem::draw(QPainter & p) { p.setPen(pn); p.setBrush(br); drawShape(p); } /* \fn void QtCanvasPolygonalItem::drawShape(QPainter & p) Subclasses must reimplement this function to draw their shape. The pen and brush of \a p are already set to pen() and brush() prior to calling this function. \sa draw() */ /* \fn QPen QtCanvasPolygonalItem::pen() const Returns the QPen used to draw the outline of the item, if any. \sa setPen() */ /* \fn QBrush QtCanvasPolygonalItem::brush() const Returns the QBrush used to fill the item, if filled. \sa setBrush() */ /* Sets the QPen used when drawing the item to the pen \a p. Note that many QtCanvasPolygonalItems do not use the pen value. \sa setBrush(), pen(), drawShape() */ void QtCanvasPolygonalItem::setPen(QPen p) { if (pn != p) { removeFromChunks(); pn = p; addToChunks(); } } /* Sets the QBrush used when drawing the polygonal item to the brush \a b. \sa setPen(), brush(), drawShape() */ void QtCanvasPolygonalItem::setBrush(QBrush b) { if (br != b) { br = b; changeChunks(); } } /* \class QtCanvasPolygon qtcanvas.h \brief The QtCanvasPolygon class provides a polygon on a QtCanvas. Paints a polygon with a QBrush. The polygon's points can be set in the constructor or set or changed later using setPoints(). Use points() to retrieve the points, or areaPoints() to retrieve the points relative to the canvas's origin. The polygon can be drawn on a painter with drawShape(). Like any other canvas item polygons can be moved with QtCanvasItem::move() and QtCanvasItem::moveBy(), or by setting coordinates with QtCanvasItem::setX(), QtCanvasItem::setY() and QtCanvasItem::setZ(). Note: QtCanvasPolygon does not use the pen. */ /* Constructs a point-less polygon on the canvas \a canvas. You should call setPoints() before using it further. */ QtCanvasPolygon::QtCanvasPolygon(QtCanvas* canvas) : QtCanvasPolygonalItem(canvas) { } /* Destroys the polygon. */ QtCanvasPolygon::~QtCanvasPolygon() { hide(); } /* Draws the polygon using the painter \a p. Note that QtCanvasPolygon does not support an outline (the pen is always NoPen). */ void QtCanvasPolygon::drawShape(QPainter & p) { // ### why can't we draw outlines? We could use drawPolyline for it. Lars // ### see other message. Warwick p.setPen(NoPen); // since QRegion(QPolygon) excludes outline :-()-: p.drawPolygon(poly); } /* Sets the points of the polygon to be \a pa. These points will have their x and y coordinates automatically translated by x(), y() as the polygon is moved. */ void QtCanvasPolygon::setPoints(QPolygon pa) { removeFromChunks(); poly = pa; poly.detach(); // Explicit sharing is stupid. poly.translate((int)x(), (int)y()); addToChunks(); } /* \reimp */ void QtCanvasPolygon::moveBy(double dx, double dy) { // Note: does NOT call QtCanvasPolygonalItem::moveBy(), since that // only does half this work. // int idx = int(x()+dx)-int(x()); int idy = int(y()+dy)-int(y()); if (idx || idy) { removeFromChunks(); poly.translate(idx, idy); } myx+= dx; myy+= dy; if (idx || idy) { addToChunks(); } } /* \class QtCanvasSpline qtcanvas.h \brief The QtCanvasSpline class provides multi-bezier splines on a QtCanvas. A QtCanvasSpline is a sequence of 4-point bezier curves joined together to make a curved shape. You set the control points of the spline with setControlPoints(). If the bezier is closed(), then the first control point will be re-used as the last control point. Therefore, a closed bezier must have a multiple of 3 control points and an open bezier must have one extra point. The beziers are not necessarily joined "smoothly". To ensure this, set control points appropriately (general reference texts about beziers will explain this in detail). Like any other canvas item splines can be moved with QtCanvasItem::move() and QtCanvasItem::moveBy(), or by setting coordinates with QtCanvasItem::setX(), QtCanvasItem::setY() and QtCanvasItem::setZ(). */ /* Create a spline with no control points on the canvas \a canvas. \sa setControlPoints() */ QtCanvasSpline::QtCanvasSpline(QtCanvas* canvas) : QtCanvasPolygon(canvas), cl(true) { } /* Destroy the spline. */ QtCanvasSpline::~QtCanvasSpline() { } /* Set the spline control points to \a ctrl. If \a close is true, then the first point in \a ctrl will be re-used as the last point, and the number of control points must be a multiple of 3. If \a close is false, one additional control point is required, and the number of control points must be one of (4, 7, 10, 13, ...). If the number of control points doesn't meet the above conditions, the number of points will be truncated to the largest number of points that do meet the requirement. */ void QtCanvasSpline::setControlPoints(QPolygon ctrl, bool close) { if ((int)ctrl.count() % 3 != (close ? 0 : 1)) { qWarning("QtCanvasSpline::setControlPoints(): Number of points doesn't fit."); int numCurves = (ctrl.count() - (close ? 0 : 1))/ 3; ctrl.resize(numCurves*3 + (close ? 0 : 1)); } cl = close; bez = ctrl; recalcPoly(); } /* Returns the current set of control points. \sa setControlPoints(), closed() */ QPolygon QtCanvasSpline::controlPoints() const { return bez; } /* Returns true if the control points are a closed set; otherwise returns false. */ bool QtCanvasSpline::closed() const { return cl; } void QtCanvasSpline::recalcPoly() { if (bez.count() == 0) return; QPainterPath path; path.moveTo(bez[0]); for (int i = 1; i < (int)bez.count()-1; i+= 3) { path.cubicTo(bez[i], bez[i+1], cl ? bez[(i+2)%bez.size()] : bez[i+2]); } QPolygon p = path.toFillPolygon().toPolygon(); QtCanvasPolygon::setPoints(p); } /* \fn QPolygon QtCanvasPolygonalItem::areaPoints() const This function must be reimplemented by subclasses. It \e must return the points bounding (i.e. outside and not touching) the shape or drawing errors will occur. */ /* \fn QPolygon QtCanvasPolygon::points() const Returns the vertices of the polygon, not translated by the position. \sa setPoints(), areaPoints() */ QPolygon QtCanvasPolygon::points() const { QPolygon pa = areaPoints(); pa.translate(int(-x()), int(-y())); return pa; } /* Returns the vertices of the polygon translated by the polygon's current x(), y() position, i.e. relative to the canvas's origin. \sa setPoints(), points() */ QPolygon QtCanvasPolygon::areaPoints() const { return poly; } /* \class QtCanvasLine qtcanvas.h \brief The QtCanvasLine class provides a line on a QtCanvas. The line inherits functionality from QtCanvasPolygonalItem, for example the setPen() function. The start and end points of the line are set with setPoints(). Like any other canvas item lines can be moved with QtCanvasItem::move() and QtCanvasItem::moveBy(), or by setting coordinates with QtCanvasItem::setX(), QtCanvasItem::setY() and QtCanvasItem::setZ(). */ /* Constructs a line from (0, 0) to (0, 0) on \a canvas. \sa setPoints() */ QtCanvasLine::QtCanvasLine(QtCanvas* canvas) : QtCanvasPolygonalItem(canvas) { x1 = y1 = x2 = y2 = 0; } /* Destroys the line. */ QtCanvasLine::~QtCanvasLine() { hide(); } /* \reimp */ void QtCanvasLine::setPen(QPen p) { QtCanvasPolygonalItem::setPen(p); } /* \fn QPoint QtCanvasLine::startPoint () const Returns the start point of the line. \sa setPoints(), endPoint() */ /* \fn QPoint QtCanvasLine::endPoint () const Returns the end point of the line. \sa setPoints(), startPoint() */ /* Sets the line's start point to (\a xa, \a ya) and its end point to (\a xb, \a yb). */ void QtCanvasLine::setPoints(int xa, int ya, int xb, int yb) { if (x1 != xa || x2 != xb || y1 != ya || y2 != yb) { removeFromChunks(); x1 = xa; y1 = ya; x2 = xb; y2 = yb; addToChunks(); } } /* \reimp */ void QtCanvasLine::drawShape(QPainter &p) { p.drawLine((int)(x()+x1), (int)(y()+y1), (int)(x()+x2), (int)(y()+y2)); } /* \reimp Note that the area defined by the line is somewhat thicker than the line that is actually drawn. */ QPolygon QtCanvasLine::areaPoints() const { QPolygon p(4); int xi = int(x()); int yi = int(y()); int pw = pen().width(); int dx = qAbs(x1-x2); int dy = qAbs(y1-y2); pw = pw*4/3+2; // approx pw*sqrt(2) int px = x1 < x2 ? -pw : pw ; int py = y1 < y2 ? -pw : pw ; if (dx && dy && (dx > dy ? (dx*2/dy <= 2) : (dy*2/dx <= 2))) { // steep if (px == py) { p[0] = QPoint(x1+xi, y1+yi+py); p[1] = QPoint(x2+xi-px, y2+yi); p[2] = QPoint(x2+xi, y2+yi-py); p[3] = QPoint(x1+xi+px, y1+yi); } else { p[0] = QPoint(x1+xi+px, y1+yi); p[1] = QPoint(x2+xi, y2+yi-py); p[2] = QPoint(x2+xi-px, y2+yi); p[3] = QPoint(x1+xi, y1+yi+py); } } else if (dx > dy) { // horizontal p[0] = QPoint(x1+xi+px, y1+yi+py); p[1] = QPoint(x2+xi-px, y2+yi+py); p[2] = QPoint(x2+xi-px, y2+yi-py); p[3] = QPoint(x1+xi+px, y1+yi-py); } else { // vertical p[0] = QPoint(x1+xi+px, y1+yi+py); p[1] = QPoint(x2+xi+px, y2+yi-py); p[2] = QPoint(x2+xi-px, y2+yi-py); p[3] = QPoint(x1+xi-px, y1+yi+py); } return p; } /* \reimp */ void QtCanvasLine::moveBy(double dx, double dy) { QtCanvasPolygonalItem::moveBy(dx, dy); } /* \class QtCanvasRectangle qtcanvas.h \brief The QtCanvasRectangle class provides a rectangle on a QtCanvas. This item paints a single rectangle which may have any pen() and brush(), but may not be tilted/rotated. For rotated rectangles, use QtCanvasPolygon. The rectangle's size and initial position can be set in the constructor. The size can be set or changed later using setSize(). Use height() and width() to retrieve the rectangle's dimensions. The rectangle can be drawn on a painter with drawShape(). Like any other canvas item rectangles can be moved with QtCanvasItem::move() and QtCanvasItem::moveBy(), or by setting coordinates with QtCanvasItem::setX(), QtCanvasItem::setY() and QtCanvasItem::setZ(). */ /* Constructs a rectangle at position (0,0) with both width and height set to 32 pixels on \a canvas. */ QtCanvasRectangle::QtCanvasRectangle(QtCanvas* canvas) : QtCanvasPolygonalItem(canvas), w(32), h(32) { } /* Constructs a rectangle positioned and sized by \a r on \a canvas. */ QtCanvasRectangle::QtCanvasRectangle(const QRect& r, QtCanvas* canvas) : QtCanvasPolygonalItem(canvas), w(r.width()), h(r.height()) { move(r.x(), r.y()); } /* Constructs a rectangle at position (\a x, \a y) and size \a width by \a height, on \a canvas. */ QtCanvasRectangle::QtCanvasRectangle(int x, int y, int width, int height, QtCanvas* canvas) : QtCanvasPolygonalItem(canvas), w(width), h(height) { move(x, y); } /* Destroys the rectangle. */ QtCanvasRectangle::~QtCanvasRectangle() { hide(); } /* Returns the width of the rectangle. */ int QtCanvasRectangle::width() const { return w; } /* Returns the height of the rectangle. */ int QtCanvasRectangle::height() const { return h; } /* Sets the \a width and \a height of the rectangle. */ void QtCanvasRectangle::setSize(int width, int height) { if (w != width || h != height) { removeFromChunks(); w = width; h = height; addToChunks(); } } /* \fn QSize QtCanvasRectangle::size() const Returns the width() and height() of the rectangle. \sa rect(), setSize() */ /* \fn QRect QtCanvasRectangle::rect() const Returns the integer-converted x(), y() position and size() of the rectangle as a QRect. */ /* \reimp */ QPolygon QtCanvasRectangle::areaPoints() const { QPolygon pa(4); int pw = (pen().width()+1)/2; if (pw < 1) pw = 1; if (pen() == NoPen) pw = 0; pa[0] = QPoint((int)x()-pw, (int)y()-pw); pa[1] = pa[0] + QPoint(w+pw*2, 0); pa[2] = pa[1] + QPoint(0, h+pw*2); pa[3] = pa[0] + QPoint(0, h+pw*2); return pa; } /* Draws the rectangle on painter \a p. */ void QtCanvasRectangle::drawShape(QPainter & p) { p.drawRect((int)x(), (int)y(), w, h); } /* \class QtCanvasEllipse qtcanvas.h \brief The QtCanvasEllipse class provides an ellipse or ellipse segment on a QtCanvas. A canvas item that paints an ellipse or ellipse segment with a QBrush. The ellipse's height, width, start angle and angle length can be set at construction time. The size can be changed at runtime with setSize(), and the angles can be changed (if you're displaying an ellipse segment rather than a whole ellipse) with setAngles(). Note that angles are specified in 16ths of a degree. \target anglediagram \img qcanvasellipse.png Ellipse If a start angle and length angle are set then an ellipse segment will be drawn. The start angle is the angle that goes from zero in a counter-clockwise direction (shown in green in the diagram). The length angle is the angle from the start angle in a counter-clockwise direction (shown in blue in the diagram). The blue segment is the segment of the ellipse that would be drawn. If no start angle and length angle are specified the entire ellipse is drawn. The ellipse can be drawn on a painter with drawShape(). Like any other canvas item ellipses can be moved with move() and moveBy(), or by setting coordinates with setX(), setY() and setZ(). Note: QtCanvasEllipse does not use the pen. */ /* Constructs a 32x32 ellipse, centered at (0, 0) on \a canvas. */ QtCanvasEllipse::QtCanvasEllipse(QtCanvas* canvas) : QtCanvasPolygonalItem(canvas), w(32), h(32), a1(0), a2(360*16) { } /* Constructs a \a width by \a height pixel ellipse, centered at (0, 0) on \a canvas. */ QtCanvasEllipse::QtCanvasEllipse(int width, int height, QtCanvas* canvas) : QtCanvasPolygonalItem(canvas), w(width), h(height), a1(0), a2(360*16) { } // ### add a constructor taking degrees in float. 1/16 degrees is stupid. Lars // ### it's how QPainter does it, so QtCanvas does too for consistency. If it's // ### a good idea, it should be added to QPainter, not just to QtCanvas. Warwick /* Constructs a \a width by \a height pixel ellipse, centered at (0, 0) on \a canvas. Only a segment of the ellipse is drawn, starting at angle \a startangle, and extending for angle \a angle (the angle length). Note that angles are specified in sixteenths of a degree. */ QtCanvasEllipse::QtCanvasEllipse(int width, int height, int startangle, int angle, QtCanvas* canvas) : QtCanvasPolygonalItem(canvas), w(width), h(height), a1(startangle), a2(angle) { } /* Destroys the ellipse. */ QtCanvasEllipse::~QtCanvasEllipse() { hide(); } /* Returns the width of the ellipse. */ int QtCanvasEllipse::width() const { return w; } /* Returns the height of the ellipse. */ int QtCanvasEllipse::height() const { return h; } /* Sets the \a width and \a height of the ellipse. */ void QtCanvasEllipse::setSize(int width, int height) { if (w != width || h != height) { removeFromChunks(); w = width; h = height; addToChunks(); } } /* \fn int QtCanvasEllipse::angleStart() const Returns the start angle in 16ths of a degree. Initially this will be 0. \sa setAngles(), angleLength() */ /* \fn int QtCanvasEllipse::angleLength() const Returns the length angle (the extent of the ellipse segment) in 16ths of a degree. Initially this will be 360 * 16 (a complete ellipse). \sa setAngles(), angleStart() */ /* Sets the angles for the ellipse. The start angle is \a start and the extent of the segment is \a length (the angle length) from the \a start. The angles are specified in 16ths of a degree. By default the ellipse will start at 0 and have an angle length of 360 * 16 (a complete ellipse). \sa angleStart(), angleLength() */ void QtCanvasEllipse::setAngles(int start, int length) { if (a1 != start || a2 != length) { removeFromChunks(); a1 = start; a2 = length; addToChunks(); } } /* \reimp */ QPolygon QtCanvasEllipse::areaPoints() const { QPainterPath path; path.arcTo(QRectF(x()-w/2.0+0.5-1, y()-h/2.0+0.5-1, w+3, h+3), a1/16., a2/16.); return path.toFillPolygon().toPolygon(); } /* Draws the ellipse, centered at x(), y() using the painter \a p. Note that QtCanvasEllipse does not support an outline (the pen is always NoPen). */ void QtCanvasEllipse::drawShape(QPainter & p) { p.setPen(NoPen); // since QRegion(QPolygon) excludes outline :-()-: if (!a1 && a2 == 360*16) { p.drawEllipse(int(x()-w/2.0+0.5), int(y()-h/2.0+0.5), w, h); } else { p.drawPie(int(x()-w/2.0+0.5), int(y()-h/2.0+0.5), w, h, a1, a2); } } /* \class QtCanvasText \brief The QtCanvasText class provides a text object on a QtCanvas. A canvas text item has text with font, color and alignment attributes. The text and font can be set in the constructor or set or changed later with setText() and setFont(). The color is set with setColor() and the alignment with setTextFlags(). The text item's bounding rectangle is retrieved with boundingRect(). The text can be drawn on a painter with draw(). Like any other canvas item text items can be moved with QtCanvasItem::move() and QtCanvasItem::moveBy(), or by setting coordinates with QtCanvasItem::setX(), QtCanvasItem::setY() and QtCanvasItem::setZ(). */ /* Constructs a QtCanvasText with the text "\", on \a canvas. */ QtCanvasText::QtCanvasText(QtCanvas* canvas) : QtCanvasItem(canvas), txt(""), flags(0) { setRect(); } // ### add textflags to the constructor? Lars /* Constructs a QtCanvasText with the text \a t, on canvas \a canvas. */ QtCanvasText::QtCanvasText(const QString& t, QtCanvas* canvas) : QtCanvasItem(canvas), txt(t), flags(0) { setRect(); } // ### see above /* Constructs a QtCanvasText with the text \a t and font \a f, on the canvas \a canvas. */ QtCanvasText::QtCanvasText(const QString& t, QFont f, QtCanvas* canvas) : QtCanvasItem(canvas), txt(t), flags(0), fnt(f) { setRect(); } /* Destroys the canvas text item. */ QtCanvasText::~QtCanvasText() { removeFromChunks(); } /* Returns the bounding rectangle of the text. */ QRect QtCanvasText::boundingRect() const { return brect; } void QtCanvasText::setRect() { brect = QFontMetrics(fnt).boundingRect(int(x()), int(y()), 0, 0, flags, txt); } /* \fn int QtCanvasText::textFlags() const Returns the currently set alignment flags. \sa setTextFlags() Qt::AlignmentFlag Qt::TextFlag */ /* Sets the alignment flags to \a f. These are a bitwise OR of the flags available to QPainter::drawText() -- see the \l{Qt::AlignmentFlag}s and \l{Qt::TextFlag}s. \sa setFont() setColor() */ void QtCanvasText::setTextFlags(int f) { if (flags != f) { removeFromChunks(); flags = f; setRect(); addToChunks(); } } /* Returns the text item's text. \sa setText() */ QString QtCanvasText::text() const { return txt; } /* Sets the text item's text to \a t. The text may contain newlines. \sa text(), setFont(), setColor() setTextFlags() */ void QtCanvasText::setText(const QString& t) { if (txt != t) { removeFromChunks(); txt = t; setRect(); addToChunks(); } } /* Returns the font in which the text is drawn. \sa setFont() */ QFont QtCanvasText::font() const { return fnt; } /* Sets the font in which the text is drawn to font \a f. \sa font() */ void QtCanvasText::setFont(const QFont& f) { if (f != fnt) { removeFromChunks(); fnt = f; setRect(); addToChunks(); } } /* Returns the color of the text. \sa setColor() */ QColor QtCanvasText::color() const { return col; } /* Sets the color of the text to the color \a c. \sa color(), setFont() */ void QtCanvasText::setColor(const QColor& c) { col = c; changeChunks(); } /* \reimp */ void QtCanvasText::moveBy(double dx, double dy) { int idx = int(x()+dx)-int(x()); int idy = int(y()+dy)-int(y()); if (idx || idy) { removeFromChunks(); } myx+= dx; myy+= dy; if (idx || idy) { brect.translate(idx, idy); addToChunks(); } } /* Draws the text using the painter \a painter. */ void QtCanvasText::draw(QPainter& painter) { painter.setFont(fnt); painter.setPen(col); painter.drawText(painter.fontMetrics().boundingRect(int(x()), int(y()), 0, 0, flags, txt), flags, txt); } /* \reimp */ void QtCanvasText::changeChunks() { if (isVisible() && canvas()) { int chunksize = canvas()->chunkSize(); for (int j = brect.top()/chunksize; j <= brect.bottom()/chunksize; j++) { for (int i = brect.left()/chunksize; i <= brect.right()/chunksize; i++) { canvas()->setChangedChunk(i, j); } } } } /* Adds the text item to the appropriate chunks. */ void QtCanvasText::addToChunks() { if (isVisible() && canvas()) { int chunksize = canvas()->chunkSize(); for (int j = brect.top()/chunksize; j <= brect.bottom()/chunksize; j++) { for (int i = brect.left()/chunksize; i <= brect.right()/chunksize; i++) { canvas()->addItemToChunk(this, i, j); } } } } /* Removes the text item from the appropriate chunks. */ void QtCanvasText::removeFromChunks() { if (isVisible() && canvas()) { int chunksize = canvas()->chunkSize(); for (int j = brect.top()/chunksize; j <= brect.bottom()/chunksize; j++) { for (int i = brect.left()/chunksize; i <= brect.right()/chunksize; i++) { canvas()->removeItemFromChunk(this, i, j); } } } } /* Returns 0 (QtCanvasItem::Rtti_Item). Make your derived classes return their own values for rtti(), so that you can distinguish between objects returned by QtCanvas::at(). You should use values greater than 1000 to allow for extensions to this class. Overuse of this functionality can damage its extensibility. For example, once you have identified a base class of a QtCanvasItem found by QtCanvas::at(), cast it to that type and call meaningful methods rather than acting upon the object based on its rtti value. For example: \code QtCanvasItem* item; // Find an item, e.g. with QtCanvasItem::collisions(). ... if (item->rtti() == MySprite::RTTI) { MySprite* s = (MySprite*)item; if (s->isDamagable()) s->loseHitPoints(1000); if (s->isHot()) myself->loseHitPoints(1000); ... } \endcode */ int QtCanvasItem::rtti() const { return RTTI; } int QtCanvasItem::RTTI = Rtti_Item; /* Returns 1 (QtCanvasItem::Rtti_Sprite). \sa QtCanvasItem::rtti() */ int QtCanvasSprite::rtti() const { return RTTI; } int QtCanvasSprite::RTTI = Rtti_Sprite; /* Returns 2 (QtCanvasItem::Rtti_PolygonalItem). \sa QtCanvasItem::rtti() */ int QtCanvasPolygonalItem::rtti() const { return RTTI; } int QtCanvasPolygonalItem::RTTI = Rtti_PolygonalItem; /* Returns 3 (QtCanvasItem::Rtti_Text). \sa QtCanvasItem::rtti() */ int QtCanvasText::rtti() const { return RTTI; } int QtCanvasText::RTTI = Rtti_Text; /* Returns 4 (QtCanvasItem::Rtti_Polygon). \sa QtCanvasItem::rtti() */ int QtCanvasPolygon::rtti() const { return RTTI; } int QtCanvasPolygon::RTTI = Rtti_Polygon; /* Returns 5 (QtCanvasItem::Rtti_Rectangle). \sa QtCanvasItem::rtti() */ int QtCanvasRectangle::rtti() const { return RTTI; } int QtCanvasRectangle::RTTI = Rtti_Rectangle; /* Returns 6 (QtCanvasItem::Rtti_Ellipse). \sa QtCanvasItem::rtti() */ int QtCanvasEllipse::rtti() const { return RTTI; } int QtCanvasEllipse::RTTI = Rtti_Ellipse; /* Returns 7 (QtCanvasItem::Rtti_Line). \sa QtCanvasItem::rtti() */ int QtCanvasLine::rtti() const { return RTTI; } int QtCanvasLine::RTTI = Rtti_Line; /* Returns 8 (QtCanvasItem::Rtti_Spline). \sa QtCanvasItem::rtti() */ int QtCanvasSpline::rtti() const { return RTTI; } int QtCanvasSpline::RTTI = Rtti_Spline; /* Constructs a QtCanvasSprite which uses images from the QtCanvasPixmapArray \a a. The sprite in initially positioned at (0, 0) on \a canvas, using frame 0. */ QtCanvasSprite::QtCanvasSprite(QtCanvasPixmapArray* a, QtCanvas* canvas) : QtCanvasItem(canvas), frm(0), anim_val(0), anim_state(0), anim_type(0), images(a) { } /* Set the array of images used for displaying the sprite to the QtCanvasPixmapArray \a a. If the current frame() is larger than the number of images in \a a, the current frame will be reset to 0. */ void QtCanvasSprite::setSequence(QtCanvasPixmapArray* a) { bool isvisible = isVisible(); if (isvisible && images) hide(); images = a; if (frm >= (int)images->count()) frm = 0; if (isvisible) show(); } /* \internal Marks any chunks the sprite touches as changed. */ void QtCanvasSprite::changeChunks() { if (isVisible() && canvas()) { int chunksize = canvas()->chunkSize(); for (int j = topEdge()/chunksize; j <= bottomEdge()/chunksize; j++) { for (int i = leftEdge()/chunksize; i <= rightEdge()/chunksize; i++) { canvas()->setChangedChunk(i, j); } } } } /* Destroys the sprite and removes it from the canvas. Does \e not delete the images. */ QtCanvasSprite::~QtCanvasSprite() { removeFromChunks(); } /* Sets the animation frame used for displaying the sprite to \a f, an index into the QtCanvasSprite's QtCanvasPixmapArray. The call will be ignored if \a f is larger than frameCount() or smaller than 0. \sa frame() move() */ void QtCanvasSprite::setFrame(int f) { move(x(), y(), f); } /* \enum QtCanvasSprite::FrameAnimationType This enum is used to identify the different types of frame animation offered by QtCanvasSprite. \value Cycle at each advance the frame number will be incremented by 1 (modulo the frame count). \value Oscillate at each advance the frame number will be incremented by 1 up to the frame count then decremented to by 1 to 0, repeating this sequence forever. */ /* Sets the animation characteristics for the sprite. For \a type == \c Cycle, the frames will increase by \a step at each advance, modulo the frameCount(). For \a type == \c Oscillate, the frames will increase by \a step at each advance, up to the frameCount(), then decrease by \a step back to 0, repeating forever. The \a state parameter is for internal use. */ void QtCanvasSprite::setFrameAnimation(FrameAnimationType type, int step, int state) { anim_val = step; anim_type = type; anim_state = state; setAnimated(true); } /* Extends the default QtCanvasItem implementation to provide the functionality of setFrameAnimation(). The \a phase is 0 or 1: see QtCanvasItem::advance() for details. \sa QtCanvasItem::advance() setVelocity() */ void QtCanvasSprite::advance(int phase) { if (phase == 1) { int nf = frame(); if (anim_type == Oscillate) { if (anim_state) nf += anim_val; else nf -= anim_val; if (nf < 0) { nf = abs(anim_val); anim_state = !anim_state; } else if (nf >= frameCount()) { nf = frameCount()-1-abs(anim_val); anim_state = !anim_state; } } else { nf = (nf + anim_val + frameCount()) % frameCount(); } move(x()+xVelocity(), y()+yVelocity(), nf); } } /* \fn int QtCanvasSprite::frame() const Returns the index of the current animation frame in the QtCanvasSprite's QtCanvasPixmapArray. \sa setFrame(), move() */ /* \fn int QtCanvasSprite::frameCount() const Returns the number of frames in the QtCanvasSprite's QtCanvasPixmapArray. */ /* Moves the sprite to (\a x, \a y). */ void QtCanvasSprite::move(double x, double y) { QtCanvasItem::move(x, y); } /* \fn void QtCanvasSprite::move(double nx, double ny, int nf) Moves the sprite to (\a nx, \a ny) and sets the current frame to \a nf. \a nf will be ignored if it is larger than frameCount() or smaller than 0. */ void QtCanvasSprite::move(double nx, double ny, int nf) { if (isVisible() && canvas()) { hide(); QtCanvasItem::move(nx, ny); if (nf >= 0 && nf < frameCount()) frm = nf; show(); } else { QtCanvasItem::move(nx, ny); if (nf >= 0 && nf < frameCount()) frm = nf; } } class QPoint; class QtPolygonScanner { public: virtual ~QtPolygonScanner() {} void scan(const QPolygon& pa, bool winding, int index = 0, int npoints = -1); void scan(const QPolygon& pa, bool winding, int index, int npoints, bool stitchable); enum Edge { Left = 1, Right = 2, Top = 4, Bottom = 8 }; void scan(const QPolygon& pa, bool winding, int index, int npoints, Edge edges); virtual void processSpans(int n, QPoint* point, int* width) = 0; }; // Based on Xserver code miFillGeneralPoly... /* * * Written by Brian Kelleher; Oct. 1985 * * Routine to fill a polygon. Two fill rules are * supported: frWINDING and frEVENODD. * * See fillpoly.h for a complete description of the algorithm. */ /* * These are the data structures needed to scan * convert regions. Two different scan conversion * methods are available -- the even-odd method, and * the winding number method. * The even-odd rule states that a point is inside * the polygon if a ray drawn from that point in any * direction will pass through an odd number of * path segments. * By the winding number rule, a point is decided * to be inside the polygon if a ray drawn from that * point in any direction passes through a different * number of clockwise and counterclockwise path * segments. * * These data structures are adapted somewhat from * the algorithm in (Foley/Van Dam) for scan converting * polygons. * The basic algorithm is to start at the top (smallest y) * of the polygon, stepping down to the bottom of * the polygon by incrementing the y coordinate. We * keep a list of edges which the current scanline crosses, * sorted by x. This list is called the Active Edge Table (AET) * As we change the y-coordinate, we update each entry in * in the active edge table to reflect the edges new xcoord. * This list must be sorted at each scanline in case * two edges intersect. * We also keep a data structure known as the Edge Table (ET), * which keeps track of all the edges which the current * scanline has not yet reached. The ET is basically a * list of ScanLineList structures containing a list of * edges which are entered at a given scanline. There is one * ScanLineList per scanline at which an edge is entered. * When we enter a new edge, we move it from the ET to the AET. * * From the AET, we can implement the even-odd rule as in * (Foley/Van Dam). * The winding number rule is a little trickier. We also * keep the EdgeTableEntries in the AET linked by the * nextWETE (winding EdgeTableEntry) link. This allows * the edges to be linked just as before for updating * purposes, but only uses the edges linked by the nextWETE * link as edges representing spans of the polygon to * drawn (as with the even-odd rule). */ /* $XConsortium: miscanfill.h, v 1.5 94/04/17 20:27:50 dpw Exp $ */ /* Copyright (c) 1987 X Consortium Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of the X Consortium shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the X Consortium. */ /* * scanfill.h * * Written by Brian Kelleher; Jan 1985 * * This file contains a few macros to help track * the edge of a filled object. The object is assumed * to be filled in scanline order, and thus the * algorithm used is an extension of Bresenham's line * drawing algorithm which assumes that y is always the * major axis. * Since these pieces of code are the same for any filled shape, * it is more convenient to gather the library in one * place, but since these pieces of code are also in * the inner loops of output primitives, procedure call * overhead is out of the question. * See the author for a derivation if needed. */ /* * In scan converting polygons, we want to choose those pixels * which are inside the polygon. Thus, we add .5 to the starting * x coordinate for both left and right edges. Now we choose the * first pixel which is inside the pgon for the left edge and the * first pixel which is outside the pgon for the right edge. * Draw the left pixel, but not the right. * * How to add .5 to the starting x coordinate: * If the edge is moving to the right, then subtract dy from the * error term from the general form of the algorithm. * If the edge is moving to the left, then add dy to the error term. * * The reason for the difference between edges moving to the left * and edges moving to the right is simple: If an edge is moving * to the right, then we want the algorithm to flip immediately. * If it is moving to the left, then we don't want it to flip until * we traverse an entire pixel. */ #define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \ int dx; /* local storage */ \ \ /* \ * if the edge is horizontal, then it is ignored \ * and assumed not to be processed. Otherwise, do this stuff. \ */ \ if ((dy) != 0) { \ xStart = (x1); \ dx = (x2) - xStart; \ if (dx < 0) { \ m = dx / (dy); \ m1 = m - 1; \ incr1 = -2 * dx + 2 * (dy) * m1; \ incr2 = -2 * dx + 2 * (dy) * m; \ d = 2 * m * (dy) - 2 * dx - 2 * (dy); \ } else { \ m = dx / (dy); \ m1 = m + 1; \ incr1 = 2 * dx - 2 * (dy) * m1; \ incr2 = 2 * dx - 2 * (dy) * m; \ d = -2 * m * (dy) + 2 * dx; \ } \ } \ } #define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \ if (m1 > 0) { \ if (d > 0) { \ minval += m1; \ d += incr1; \ } \ else { \ minval += m; \ d += incr2; \ } \ } else {\ if (d >= 0) { \ minval += m1; \ d += incr1; \ } \ else { \ minval += m; \ d += incr2; \ } \ } \ } /* * This structure contains all of the information needed * to run the bresenham algorithm. * The variables may be hardcoded into the declarations * instead of using this structure to make use of * register declarations. */ typedef struct { int minor; /* minor axis */ int d; /* decision variable */ int m, m1; /* slope and slope+1 */ int incr1, incr2; /* error increments */ } BRESINFO; #define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \ BRESINITPGON(dmaj, min1, min2, bres.minor, bres.d, \ bres.m, bres.m1, bres.incr1, bres.incr2) #define BRESINCRPGONSTRUCT(bres) \ BRESINCRPGON(bres.d, bres.minor, bres.m, bres.m1, bres.incr1, bres.incr2) typedef struct _EdgeTableEntry { int ymax; /* ycoord at which we exit this edge. */ BRESINFO bres; /* Bresenham info to run the edge */ struct _EdgeTableEntry *next; /* next in the list */ struct _EdgeTableEntry *back; /* for insertion sort */ struct _EdgeTableEntry *nextWETE; /* for winding num rule */ int ClockWise; /* flag for winding number rule */ } EdgeTableEntry; typedef struct _ScanLineList{ int scanline; /* the scanline represented */ EdgeTableEntry *edgelist; /* header node */ struct _ScanLineList *next; /* next in the list */ } ScanLineList; typedef struct { int ymax; /* ymax for the polygon */ int ymin; /* ymin for the polygon */ ScanLineList scanlines; /* header node */ } EdgeTable; /* * Here is a struct to help with storage allocation * so we can allocate a big chunk at a time, and then take * pieces from this heap when we need to. */ #define SLLSPERBLOCK 25 typedef struct _ScanLineListBlock { ScanLineList SLLs[SLLSPERBLOCK]; struct _ScanLineListBlock *next; } ScanLineListBlock; /* * number of points to buffer before sending them off * to scanlines() : Must be an even number */ #define NUMPTSTOBUFFER 200 /* * * a few macros for the inner loops of the fill code where * performance considerations don't allow a procedure call. * * Evaluate the given edge at the given scanline. * If the edge has expired, then we leave it and fix up * the active edge table; otherwise, we increment the * x value to be ready for the next scanline. * The winding number rule is in effect, so we must notify * the caller when the edge has been removed so he * can reorder the Winding Active Edge Table. */ #define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \ if (pAET->ymax == y) { /* leaving this edge */ \ pPrevAET->next = pAET->next; \ pAET = pPrevAET->next; \ fixWAET = 1; \ if (pAET) \ pAET->back = pPrevAET; \ } \ else { \ BRESINCRPGONSTRUCT(pAET->bres); \ pPrevAET = pAET; \ pAET = pAET->next; \ } \ } /* * Evaluate the given edge at the given scanline. * If the edge has expired, then we leave it and fix up * the active edge table; otherwise, we increment the * x value to be ready for the next scanline. * The even-odd rule is in effect. */ #define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \ if (pAET->ymax == y) { /* leaving this edge */ \ pPrevAET->next = pAET->next; \ pAET = pPrevAET->next; \ if (pAET) \ pAET->back = pPrevAET; \ } \ else { \ BRESINCRPGONSTRUCT(pAET->bres) \ pPrevAET = pAET; \ pAET = pAET->next; \ } \ } /*********************************************************** Copyright (c) 1987 X Consortium Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of the X Consortium shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the X Consortium. Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of Digital not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************/ #define MAXINT 0x7fffffff #define MININT -MAXINT /* * fillUtils.c * * Written by Brian Kelleher; Oct. 1985 * * This module contains all of the utility functions * needed to scan convert a polygon. * */ /* * InsertEdgeInET * * Insert the given edge into the edge table. * First we must find the correct bucket in the * Edge table, then find the right slot in the * bucket. Finally, we can insert it. * */ static bool miInsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE, int scanline, ScanLineListBlock **SLLBlock, int *iSLLBlock) { register EdgeTableEntry *start, *prev; register ScanLineList *pSLL, *pPrevSLL; ScanLineListBlock *tmpSLLBlock; /* * find the right bucket to put the edge into */ pPrevSLL = &ET->scanlines; pSLL = pPrevSLL->next; while (pSLL && (pSLL->scanline < scanline)) { pPrevSLL = pSLL; pSLL = pSLL->next; } /* * reassign pSLL (pointer to ScanLineList) if necessary */ if ((!pSLL) || (pSLL->scanline > scanline)) { if (*iSLLBlock > SLLSPERBLOCK-1) { tmpSLLBlock = (ScanLineListBlock *)malloc(sizeof(ScanLineListBlock)); if (!tmpSLLBlock) return false; (*SLLBlock)->next = tmpSLLBlock; tmpSLLBlock->next = 0; *SLLBlock = tmpSLLBlock; *iSLLBlock = 0; } pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]); pSLL->next = pPrevSLL->next; pSLL->edgelist = 0; pPrevSLL->next = pSLL; } pSLL->scanline = scanline; /* * now insert the edge in the right bucket */ prev = 0; start = pSLL->edgelist; while (start && (start->bres.minor < ETE->bres.minor)) { prev = start; start = start->next; } ETE->next = start; if (prev) prev->next = ETE; else pSLL->edgelist = ETE; return true; } /* * CreateEdgeTable * * This routine creates the edge table for * scan converting polygons. * The Edge Table (ET) looks like: * * EdgeTable * -------- * | ymax | ScanLineLists * |scanline|-->------------>-------------->... * -------- |scanline| |scanline| * |edgelist| |edgelist| * --------- --------- * | | * | | * V V * list of ETEs list of ETEs * * where ETE is an EdgeTableEntry data structure, * and there is one ScanLineList per scanline at * which an edge is initially entered. * */ typedef struct { #if defined(Q_OS_MAC) int y, x; #else int x, y; #endif } DDXPointRec, *DDXPointPtr; /* * Clean up our act. */ static void miFreeStorage(ScanLineListBlock *pSLLBlock) { register ScanLineListBlock *tmpSLLBlock; while (pSLLBlock) { tmpSLLBlock = pSLLBlock->next; free(pSLLBlock); pSLLBlock = tmpSLLBlock; } } static bool miCreateETandAET(int count, DDXPointPtr pts, EdgeTable *ET, EdgeTableEntry *AET, EdgeTableEntry *pETEs, ScanLineListBlock *pSLLBlock) { register DDXPointPtr top, bottom; register DDXPointPtr PrevPt, CurrPt; int iSLLBlock = 0; int dy; if (count < 2) return true; /* * initialize the Active Edge Table */ AET->next = 0; AET->back = 0; AET->nextWETE = 0; AET->bres.minor = MININT; /* * initialize the Edge Table. */ ET->scanlines.next = 0; ET->ymax = MININT; ET->ymin = MAXINT; pSLLBlock->next = 0; PrevPt = &pts[count-1]; /* * for each vertex in the array of points. * In this loop we are dealing with two vertices at * a time -- these make up one edge of the polygon. */ while (count--) { CurrPt = pts++; /* * find out which point is above and which is below. */ if (PrevPt->y > CurrPt->y) { bottom = PrevPt, top = CurrPt; pETEs->ClockWise = 0; } else { bottom = CurrPt, top = PrevPt; pETEs->ClockWise = 1; } /* * don't add horizontal edges to the Edge table. */ if (bottom->y != top->y) { pETEs->ymax = bottom->y-1; /* -1 so we don't get last scanline */ /* * initialize integer edge algorithm */ dy = bottom->y - top->y; BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres) if (!miInsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, &iSLLBlock)) { miFreeStorage(pSLLBlock->next); return false; } ET->ymax = qMax(ET->ymax, PrevPt->y); ET->ymin = qMin(ET->ymin, PrevPt->y); pETEs++; } PrevPt = CurrPt; } return true; } /* * loadAET * * This routine moves EdgeTableEntries from the * EdgeTable into the Active Edge Table, * leaving them sorted by smaller x coordinate. * */ static void miloadAET(EdgeTableEntry *AET, EdgeTableEntry *ETEs) { register EdgeTableEntry *pPrevAET; register EdgeTableEntry *tmp; pPrevAET = AET; AET = AET->next; while (ETEs) { while (AET && (AET->bres.minor < ETEs->bres.minor)) { pPrevAET = AET; AET = AET->next; } tmp = ETEs->next; ETEs->next = AET; if (AET) AET->back = ETEs; ETEs->back = pPrevAET; pPrevAET->next = ETEs; pPrevAET = ETEs; ETEs = tmp; } } /* * computeWAET * * This routine links the AET by the * nextWETE (winding EdgeTableEntry) link for * use by the winding number rule. The final * Active Edge Table (AET) might look something * like: * * AET * ---------- --------- --------- * |ymax | |ymax | |ymax | * | ... | |... | |... | * |next |->|next |->|next |->... * |nextWETE| |nextWETE| |nextWETE| * --------- --------- ^-------- * | | | * V-------------------> V---> ... * */ static void micomputeWAET(EdgeTableEntry *AET) { register EdgeTableEntry *pWETE; register int inside = 1; register int isInside = 0; AET->nextWETE = 0; pWETE = AET; AET = AET->next; while (AET) { if (AET->ClockWise) isInside++; else isInside--; if ((!inside && !isInside) || (inside && isInside)) { pWETE->nextWETE = AET; pWETE = AET; inside = !inside; } AET = AET->next; } pWETE->nextWETE = 0; } /* * InsertionSort * * Just a simple insertion sort using * pointers and back pointers to sort the Active * Edge Table. * */ static int miInsertionSort(EdgeTableEntry *AET) { register EdgeTableEntry *pETEchase; register EdgeTableEntry *pETEinsert; register EdgeTableEntry *pETEchaseBackTMP; register int changed = 0; AET = AET->next; while (AET) { pETEinsert = AET; pETEchase = AET; while (pETEchase->back->bres.minor > AET->bres.minor) pETEchase = pETEchase->back; AET = AET->next; if (pETEchase != pETEinsert) { pETEchaseBackTMP = pETEchase->back; pETEinsert->back->next = AET; if (AET) AET->back = pETEinsert->back; pETEinsert->next = pETEchase; pETEchase->back->next = pETEinsert; pETEchase->back = pETEinsert; pETEinsert->back = pETEchaseBackTMP; changed = 1; } } return changed; } /* \overload */ void QtPolygonScanner::scan(const QPolygon& pa, bool winding, int index, int npoints) { scan(pa, winding, index, npoints, true); } /* \overload If \a stitchable is false, the right and bottom edges of the polygon are included. This causes adjacent polygons to overlap. */ void QtPolygonScanner::scan(const QPolygon& pa, bool winding, int index, int npoints, bool stitchable) { scan(pa, winding, index, npoints, stitchable ? Edge(Left+Top) : Edge(Left+Right+Top+Bottom)); } /* Calls processSpans() for all scanlines of the polygon defined by \a npoints starting at \a index in \a pa. If \a winding is true, the Winding algorithm rather than the Odd-Even rule is used. The \a edges is any bitwise combination of: \list \i QtPolygonScanner::Left \i QtPolygonScanner::Right \i QtPolygonScanner::Top \i QtPolygonScanner::Bottom \endlist \a edges determines which edges are included. \warning The edges feature does not work properly. */ void QtPolygonScanner::scan(const QPolygon& pa, bool winding, int index, int npoints, Edge edges) { DDXPointPtr ptsIn = (DDXPointPtr)pa.data(); ptsIn += index; register EdgeTableEntry *pAET; /* the Active Edge Table */ register int y; /* the current scanline */ register int nPts = 0; /* number of pts in buffer */ register EdgeTableEntry *pWETE; /* Winding Edge Table */ register ScanLineList *pSLL; /* Current ScanLineList */ register DDXPointPtr ptsOut; /* ptr to output buffers */ int *width; DDXPointRec FirstPoint[NUMPTSTOBUFFER]; /* the output buffers */ int FirstWidth[NUMPTSTOBUFFER]; EdgeTableEntry *pPrevAET; /* previous AET entry */ EdgeTable ET; /* Edge Table header node */ EdgeTableEntry AET; /* Active ET header node */ EdgeTableEntry *pETEs; /* Edge Table Entries buff */ ScanLineListBlock SLLBlock; /* header for ScanLineList */ int fixWAET = 0; int edge_l = (edges & Left) ? 1 : 0; int edge_r = (edges & Right) ? 1 : 0; int edge_t = 1; //#### (edges & Top) ? 1 : 0; int edge_b = (edges & Bottom) ? 1 : 0; if (npoints == -1) npoints = pa.size(); if (npoints < 3) return; if(!(pETEs = (EdgeTableEntry *) malloc(sizeof(EdgeTableEntry) * npoints))) return; ptsOut = FirstPoint; width = FirstWidth; if (!miCreateETandAET(npoints, ptsIn, &ET, &AET, pETEs, &SLLBlock)) { free(pETEs); return; } pSLL = ET.scanlines.next; if (!winding) { /* * for each scanline */ for (y = ET.ymin+1-edge_t; y < ET.ymax+edge_b; y++) { /* * Add a new edge to the active edge table when we * get to the next edge. */ if (pSLL && y == pSLL->scanline) { miloadAET(&AET, pSLL->edgelist); pSLL = pSLL->next; } pPrevAET = &AET; pAET = AET.next; /* * for each active edge */ while (pAET) { ptsOut->x = pAET->bres.minor + 1 - edge_l; ptsOut++->y = y; *width++ = pAET->next->bres.minor - pAET->bres.minor - 1 + edge_l + edge_r; nPts++; /* * send out the buffer when its full */ if (nPts == NUMPTSTOBUFFER) { processSpans(nPts, (QPoint*)FirstPoint, FirstWidth); ptsOut = FirstPoint; width = FirstWidth; nPts = 0; } EVALUATEEDGEEVENODD(pAET, pPrevAET, y) EVALUATEEDGEEVENODD(pAET, pPrevAET, y) } miInsertionSort(&AET); } } else /* default to WindingNumber */ { /* * for each scanline */ for (y = ET.ymin+1-edge_t; y < ET.ymax+edge_b; y++) { /* * Add a new edge to the active edge table when we * get to the next edge. */ if (pSLL && y == pSLL->scanline) { miloadAET(&AET, pSLL->edgelist); micomputeWAET(&AET); pSLL = pSLL->next; } pPrevAET = &AET; pAET = AET.next; pWETE = pAET; /* * for each active edge */ while (pAET) { /* * if the next edge in the active edge table is * also the next edge in the winding active edge * table. */ if (pWETE == pAET) { ptsOut->x = pAET->bres.minor + 1 - edge_l; ptsOut++->y = y; *width++ = pAET->nextWETE->bres.minor - pAET->bres.minor - 1 + edge_l + edge_r; nPts++; /* * send out the buffer */ if (nPts == NUMPTSTOBUFFER) { processSpans(nPts, (QPoint*)FirstPoint, FirstWidth); ptsOut = FirstPoint; width = FirstWidth; nPts = 0; } pWETE = pWETE->nextWETE; while (pWETE != pAET) { EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) } pWETE = pWETE->nextWETE; } EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) } /* * reevaluate the Winding active edge table if we * just had to resort it or if we just exited an edge. */ if (miInsertionSort(&AET) || fixWAET) { micomputeWAET(&AET); fixWAET = 0; } } } /* * Get any spans that we missed by buffering */ processSpans(nPts, (QPoint*)FirstPoint, FirstWidth); free(pETEs); miFreeStorage(SLLBlock.next); } /***** END OF X11-based CODE *****/ class QtCanvasPolygonScanner : public QtPolygonScanner { QPolygonalProcessor& processor; public: QtCanvasPolygonScanner(QPolygonalProcessor& p) : processor(p) { } void processSpans(int n, QPoint* point, int* width) { processor.doSpans(n, point, width); } }; void QtCanvasPolygonalItem::scanPolygon(const QPolygon& pa, int winding, QPolygonalProcessor& process) const { QtCanvasPolygonScanner scanner(process); scanner.scan(pa, winding); } nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/canvas_typed/qtcanvas.h000066400000000000000000000466201455373415500303320ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #ifndef QTCANVAS_H #define QTCANVAS_H #include #include #include #include #include class QtCanvasSprite; class QtCanvasPolygonalItem; class QtCanvasRectangle; class QtCanvasPolygon; class QtCanvasEllipse; class QtCanvasText; class QtCanvasLine; class QtCanvasChunk; class QtCanvas; class QtCanvasItem; class QtCanvasView; class QtCanvasPixmap; typedef QList QtCanvasItemList; class QtCanvasItemExtra; class QtCanvasItem { public: QtCanvasItem(QtCanvas* canvas); virtual ~QtCanvasItem(); double x() const { return myx; } double y() const { return myy; } double z() const { return myz; } // (depth) virtual void moveBy(double dx, double dy); void move(double x, double y); void setX(double a) { move(a,y()); } void setY(double a) { move(x(),a); } void setZ(double a) { myz=a; changeChunks(); } bool animated() const; virtual void setAnimated(bool y); virtual void setVelocity(double vx, double vy); void setXVelocity(double vx) { setVelocity(vx,yVelocity()); } void setYVelocity(double vy) { setVelocity(xVelocity(),vy); } double xVelocity() const; double yVelocity() const; virtual void advance(int stage); virtual bool collidesWith(const QtCanvasItem*) const=0; QtCanvasItemList collisions(bool exact /* NO DEFAULT */) const; virtual void setCanvas(QtCanvas*); virtual void draw(QPainter&)=0; void show(); void hide(); virtual void setVisible(bool yes); bool isVisible() const { return (bool)vis; } virtual void setSelected(bool yes); bool isSelected() const { return (bool)sel; } virtual void setEnabled(bool yes); bool isEnabled() const { return (bool)ena; } virtual void setActive(bool yes); bool isActive() const { return (bool)act; } bool visible() const { return (bool)vis; } bool selected() const { return (bool)sel; } bool enabled() const { return (bool)ena; } bool active() const { return (bool)act; } enum RttiValues { Rtti_Item = 0, Rtti_Sprite = 1, Rtti_PolygonalItem = 2, Rtti_Text = 3, Rtti_Polygon = 4, Rtti_Rectangle = 5, Rtti_Ellipse = 6, Rtti_Line = 7, Rtti_Spline = 8 }; virtual int rtti() const; static int RTTI; virtual QRect boundingRect() const=0; virtual QRect boundingRectAdvanced() const; QtCanvas* canvas() const { return cnv; } protected: void update() { changeChunks(); } private: // For friendly subclasses... friend class QtCanvasPolygonalItem; friend class QtCanvasSprite; friend class QtCanvasRectangle; friend class QtCanvasPolygon; friend class QtCanvasEllipse; friend class QtCanvasText; friend class QtCanvasLine; virtual QPolygon chunks() const; virtual void addToChunks(); virtual void removeFromChunks(); virtual void changeChunks(); virtual bool collidesWith(const QtCanvasSprite*, const QtCanvasPolygonalItem*, const QtCanvasRectangle*, const QtCanvasEllipse*, const QtCanvasText*) const = 0; // End of friend stuff QtCanvas* cnv; static QtCanvas* current_canvas; double myx,myy,myz; QtCanvasItemExtra *ext; QtCanvasItemExtra& extra(); uint ani:1; uint vis:1; uint val:1; uint sel:1; uint ena:1; uint act:1; }; class QtCanvasData; class QtCanvas : public QObject { Q_OBJECT public: QtCanvas(QObject* parent = 0); QtCanvas(int w, int h); QtCanvas(QPixmap p, int h, int v, int tilewidth, int tileheight); virtual ~QtCanvas(); virtual void setTiles(QPixmap tiles, int h, int v, int tilewidth, int tileheight); virtual void setBackgroundPixmap(const QPixmap& p); QPixmap backgroundPixmap() const; virtual void setBackgroundColor(const QColor& c); QColor backgroundColor() const; virtual void setTile(int x, int y, int tilenum); int tile(int x, int y) const { return grid[x+y*htiles]; } int tilesHorizontally() const { return htiles; } int tilesVertically() const { return vtiles; } int tileWidth() const { return tilew; } int tileHeight() const { return tileh; } virtual void resize(int width, int height); int width() const { return awidth; } int height() const { return aheight; } QSize size() const { return QSize(awidth,aheight); } QRect rect() const { return QRect(0, 0, awidth, aheight); } bool onCanvas(int x, int y) const { return x>=0 && y>=0 && x=0 && y>=0 && x &pixmaps, const QPolygon &hotspots = QPolygon()); ~QtCanvasPixmapArray(); #ifndef QT_NO_IMAGEIO bool readPixmaps(const QString& datafilenamepattern, int framecount=0); bool readCollisionMasks(const QString& filenamepattern); #endif // deprecated bool operator!(); // Failure check. bool isValid() const; QtCanvasPixmap* image(int i) const { return img ? img[i] : 0; } void setImage(int i, QtCanvasPixmap* p); uint count() const { return (uint)framecount; } private: Q_DISABLE_COPY(QtCanvasPixmapArray) #ifndef QT_NO_IMAGEIO bool readPixmaps(const QString& datafilenamepattern, int framecount, bool maskonly); #endif void reset(); int framecount; QtCanvasPixmap** img; }; class QtCanvasSprite : public QtCanvasItem { public: QtCanvasSprite(QtCanvasPixmapArray* array, QtCanvas* canvas); void setSequence(QtCanvasPixmapArray* seq); virtual ~QtCanvasSprite(); void move(double x, double y); virtual void move(double x, double y, int frame); void setFrame(int); enum FrameAnimationType { Cycle, Oscillate }; virtual void setFrameAnimation(FrameAnimationType=Cycle, int step=1, int state=0); int frame() const { return frm; } int frameCount() const { return images->count(); } int rtti() const; static int RTTI; bool collidesWith(const QtCanvasItem*) const; QRect boundingRect() const; // is there a reason for these to be protected? Lars //protected: int width() const; int height() const; int leftEdge() const; int topEdge() const; int rightEdge() const; int bottomEdge() const; int leftEdge(int nx) const; int topEdge(int ny) const; int rightEdge(int nx) const; int bottomEdge(int ny) const; QtCanvasPixmap* image() const { return images->image(frm); } virtual QtCanvasPixmap* imageAdvanced() const; QtCanvasPixmap* image(int f) const { return images->image(f); } virtual void advance(int stage); public: void draw(QPainter& painter); private: Q_DISABLE_COPY(QtCanvasSprite) void addToChunks(); void removeFromChunks(); void changeChunks(); int frm; ushort anim_val; uint anim_state:2; uint anim_type:14; bool collidesWith(const QtCanvasSprite*, const QtCanvasPolygonalItem*, const QtCanvasRectangle*, const QtCanvasEllipse*, const QtCanvasText*) const; friend bool qt_testCollision(const QtCanvasSprite* s1, const QtCanvasSprite* s2); QtCanvasPixmapArray* images; }; class QPolygonalProcessor; class QtCanvasPolygonalItem : public QtCanvasItem { public: QtCanvasPolygonalItem(QtCanvas* canvas); virtual ~QtCanvasPolygonalItem(); bool collidesWith(const QtCanvasItem*) const; virtual void setPen(QPen p); virtual void setBrush(QBrush b); QPen pen() const { return pn; } QBrush brush() const { return br; } virtual QPolygon areaPoints() const=0; virtual QPolygon areaPointsAdvanced() const; QRect boundingRect() const; int rtti() const; static int RTTI; protected: void draw(QPainter &); virtual void drawShape(QPainter &) = 0; bool winding() const; void setWinding(bool); void invalidate(); bool isValid() const { return (bool)val; } private: void scanPolygon(const QPolygon& pa, int winding, QPolygonalProcessor& process) const; QPolygon chunks() const; bool collidesWith(const QtCanvasSprite*, const QtCanvasPolygonalItem*, const QtCanvasRectangle*, const QtCanvasEllipse*, const QtCanvasText*) const; QBrush br; QPen pn; uint wind:1; }; class QtCanvasRectangle : public QtCanvasPolygonalItem { public: QtCanvasRectangle(QtCanvas* canvas); QtCanvasRectangle(const QRect&, QtCanvas* canvas); QtCanvasRectangle(int x, int y, int width, int height, QtCanvas* canvas); ~QtCanvasRectangle(); int width() const; int height() const; void setSize(int w, int h); QSize size() const { return QSize(w,h); } QPolygon areaPoints() const; QRect rect() const { return QRect(int(x()),int(y()),w,h); } bool collidesWith(const QtCanvasItem*) const; int rtti() const; static int RTTI; protected: void drawShape(QPainter &); QPolygon chunks() const; private: bool collidesWith( const QtCanvasSprite*, const QtCanvasPolygonalItem*, const QtCanvasRectangle*, const QtCanvasEllipse*, const QtCanvasText*) const; int w, h; }; class QtCanvasPolygon : public QtCanvasPolygonalItem { public: QtCanvasPolygon(QtCanvas* canvas); ~QtCanvasPolygon(); void setPoints(QPolygon); QPolygon points() const; void moveBy(double dx, double dy); QPolygon areaPoints() const; int rtti() const; static int RTTI; protected: void drawShape(QPainter &); QPolygon poly; }; class QtCanvasSpline : public QtCanvasPolygon { public: QtCanvasSpline(QtCanvas* canvas); ~QtCanvasSpline(); void setControlPoints(QPolygon, bool closed=true); QPolygon controlPoints() const; bool closed() const; int rtti() const; static int RTTI; private: void recalcPoly(); QPolygon bez; bool cl; }; class QtCanvasLine : public QtCanvasPolygonalItem { public: QtCanvasLine(QtCanvas* canvas); ~QtCanvasLine(); void setPoints(int x1, int y1, int x2, int y2); QPoint startPoint() const { return QPoint(x1,y1); } QPoint endPoint() const { return QPoint(x2,y2); } int rtti() const; static int RTTI; void setPen(QPen p); void moveBy(double dx, double dy); protected: void drawShape(QPainter &); QPolygon areaPoints() const; private: int x1,y1,x2,y2; }; class QtCanvasEllipse : public QtCanvasPolygonalItem { public: QtCanvasEllipse(QtCanvas* canvas); QtCanvasEllipse(int width, int height, QtCanvas* canvas); QtCanvasEllipse(int width, int height, int startangle, int angle, QtCanvas* canvas); ~QtCanvasEllipse(); int width() const; int height() const; void setSize(int w, int h); void setAngles(int start, int length); int angleStart() const { return a1; } int angleLength() const { return a2; } QPolygon areaPoints() const; bool collidesWith(const QtCanvasItem*) const; int rtti() const; static int RTTI; protected: void drawShape(QPainter &); private: bool collidesWith(const QtCanvasSprite*, const QtCanvasPolygonalItem*, const QtCanvasRectangle*, const QtCanvasEllipse*, const QtCanvasText*) const; int w, h; int a1, a2; }; class QtCanvasTextExtra; class QtCanvasText : public QtCanvasItem { public: QtCanvasText(QtCanvas* canvas); QtCanvasText(const QString&, QtCanvas* canvas); QtCanvasText(const QString&, QFont, QtCanvas* canvas); virtual ~QtCanvasText(); void setText(const QString&); void setFont(const QFont&); void setColor(const QColor&); QString text() const; QFont font() const; QColor color() const; void moveBy(double dx, double dy); int textFlags() const { return flags; } void setTextFlags(int); QRect boundingRect() const; bool collidesWith(const QtCanvasItem*) const; int rtti() const; static int RTTI; protected: virtual void draw(QPainter&); private: Q_DISABLE_COPY(QtCanvasText) void addToChunks(); void removeFromChunks(); void changeChunks(); void setRect(); QRect brect; QString txt; int flags; QFont fnt; QColor col; QtCanvasTextExtra* extra; bool collidesWith(const QtCanvasSprite*, const QtCanvasPolygonalItem*, const QtCanvasRectangle*, const QtCanvasEllipse*, const QtCanvasText*) const; }; #endif // QTCANVAS_H nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/canvas_variant/000077500000000000000000000000001455373415500266505ustar00rootroot00000000000000nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/canvas_variant/CMakeLists.txt000066400000000000000000000006401455373415500314100ustar00rootroot00000000000000# Tell CMake to run moc when necessary: set(CMAKE_AUTOMOC ON) # As moc files are generated in the binary dir, tell CMake # to always look for includes there: set(CMAKE_INCLUDE_CURRENT_DIR ON) SET(example_name canvas_variant) SET(KIT_SRCS main.cpp mainwindow.cpp mainwindow.h qtcanvas.cpp qtcanvas.h ) ADD_EXECUTABLE(${example_name} ${KIT_SRCS}) TARGET_LINK_LIBRARIES(${example_name} ${PROJECT_NAME}) nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/canvas_variant/canvas_variant.qdoc000066400000000000000000000100661455373415500325220ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ /*! \page qtpropertybrowser-example-canvas_variant.html \title Variant Based Canvas Example This example demonstrates how to use the QtVariantPropertyManager convenience class for all property types. In this approach only one instance of the property manager class is used, and the developer interfaces with a dynamic API based on QVariant. \image canvas_variant.png The example presents a canvas filled up with items of different types, and a tree property browser which displays the currently selected item's properties. All item types has a few common properties like "Position X", "Position Y" or "Position Z", but each type also adds its own type-specific properties (e.g. the text items provide "Text" and "Font" properties, and the line items provide a "Vector" property). The source files can be found in examples/canvas_variant directory of the package. \section1 Third party copyright notice The canvas class used in this example contains third party code with the following copyright notice: \legalese \code Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of Digital not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. \endcode \endlegalese */ nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/canvas_variant/main.cpp000066400000000000000000000041731455373415500303050ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #include #include "mainwindow.h" int main(int argc, char **argv) { QApplication app(argc, argv); MainWindow mw; mw.show(); return app.exec(); } nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/canvas_variant/mainwindow.cpp000066400000000000000000000356371455373415500315460ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #include "mainwindow.h" #include "qtvariantproperty.h" #include "qttreepropertybrowser.h" #include #include #include #include #include #include void CanvasView::contentsMousePressEvent(QMouseEvent* event) { handleMouseClickEvent(event); } void CanvasView::contentsMouseDoubleClickEvent(QMouseEvent* event) { handleMouseClickEvent(event); } void CanvasView::handleMouseClickEvent(QMouseEvent* event) { QPoint p = inverseWorldMatrix().map(event->pos()); QtCanvasItemList l = canvas()->collisions(p); moving = 0; if (!l.isEmpty()) moving = l.first(); moving_start = p; emit itemClicked(moving); } void CanvasView::contentsMouseMoveEvent(QMouseEvent* event) { if (moving) { QPoint p = inverseWorldMatrix().map(event->pos()); moving->moveBy(p.x() - moving_start.x(), p.y() - moving_start.y()); moving_start = p; canvas()->update(); emit itemMoved(moving); } } MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { QMenu *editMenu = menuBar()->addMenu(tr("Edit")); QMenu *newObjectMenu = editMenu->addMenu(tr("New Object")); QAction *newRectangleAction = new QAction(tr("Rectangle"), this); connect(newRectangleAction, SIGNAL(triggered(bool)), this, SLOT(newRectangle())); newObjectMenu->addAction(newRectangleAction); QAction *newLineAction = new QAction(tr("Line"), this); connect(newLineAction, SIGNAL(triggered(bool)), this, SLOT(newLine())); newObjectMenu->addAction(newLineAction); QAction *newEllipseAction = new QAction(tr("Ellipse"), this); connect(newEllipseAction, SIGNAL(triggered(bool)), this, SLOT(newEllipse())); newObjectMenu->addAction(newEllipseAction); QAction *newTextAction = new QAction(tr("Text"), this); connect(newTextAction, SIGNAL(triggered(bool)), this, SLOT(newText())); newObjectMenu->addAction(newTextAction); deleteAction = new QAction(tr("Delete Object"), this); connect(deleteAction, SIGNAL(triggered(bool)), this, SLOT(deleteObject())); editMenu->addAction(deleteAction); QAction *clearAction = new QAction(tr("Clear All"), this); connect(clearAction, SIGNAL(triggered(bool)), this, SLOT(clearAll())); editMenu->addAction(clearAction); QAction *fillAction = new QAction(tr("Fill View"), this); connect(fillAction, SIGNAL(triggered(bool)), this, SLOT(fillView())); editMenu->addAction(fillAction); variantManager = new QtVariantPropertyManager(this); connect(variantManager, SIGNAL(valueChanged(QtProperty *, const QVariant &)), this, SLOT(valueChanged(QtProperty *, const QVariant &))); QtVariantEditorFactory *variantFactory = new QtVariantEditorFactory(this); canvas = new QtCanvas(800, 600); canvasView = new CanvasView(canvas, this); setCentralWidget(canvasView); QDockWidget *dock = new QDockWidget(this); addDockWidget(Qt::RightDockWidgetArea, dock); propertyEditor = new QtTreePropertyBrowser(dock); propertyEditor->setFactoryForManager(variantManager, variantFactory); dock->setWidget(propertyEditor); currentItem = 0; connect(canvasView, SIGNAL(itemClicked(QtCanvasItem *)), this, SLOT(itemClicked(QtCanvasItem *))); connect(canvasView, SIGNAL(itemMoved(QtCanvasItem *)), this, SLOT(itemMoved(QtCanvasItem *))); fillView(); itemClicked(0); } void MainWindow::newRectangle() { QtCanvasItem *item = addRectangle(); canvas->update(); itemClicked(item); } void MainWindow::newEllipse() { QtCanvasItem *item = addEllipse(); canvas->update(); itemClicked(item); } void MainWindow::newLine() { QtCanvasItem *item = addLine(); canvas->update(); itemClicked(item); } void MainWindow::newText() { QtCanvasItem *item = addText(); canvas->update(); itemClicked(item); } void MainWindow::deleteObject() { if (!currentItem) return; delete currentItem; itemClicked(0); canvas->update(); } void MainWindow::clearAll() { QtCanvasItemList list = canvas->allItems(); qDeleteAll(list); itemClicked(0); canvas->update(); } void MainWindow::fillView() { for (int i = 0; i < 10; i++) { addRectangle(); addEllipse(); addLine(); addText(); } canvas->update(); } QtCanvasItem *MainWindow::addRectangle() { QtCanvasPolygonalItem *item = new QtCanvasRectangle(rand() % canvas->width(), rand() % canvas->height(), 50, 50, canvas); int z = rand() % 256; item->setBrush(QColor(rand() % 32 * 8, rand() % 32 * 8, rand() % 32 * 8)); item->setPen(QPen(QColor(rand() % 32*8, rand() % 32*8, rand() % 32*8), 4)); item->setZ(z); item->show(); return item; } QtCanvasItem *MainWindow::addEllipse() { QtCanvasPolygonalItem *item = new QtCanvasEllipse(50, 50, canvas); item->setBrush(QColor(rand() % 32 * 8, rand() % 32 * 8, rand() % 32 * 8)); item->move(rand() % canvas->width(), rand() % canvas->height()); item->setZ(rand() % 256); item->show(); return item; } QtCanvasItem *MainWindow::addLine() { QtCanvasLine *item = new QtCanvasLine(canvas); item->setPoints(0, 0, rand() % canvas->width() - canvas->width() / 2, rand() % canvas->height() - canvas->height() / 2); item->move(rand() % canvas->width(), rand() % canvas->height()); item->setPen(QPen(QColor(rand() % 32*8, rand() % 32*8, rand() % 32*8), 6)); item->setZ(rand() % 256); item->show(); return item; } QtCanvasItem *MainWindow::addText() { QtCanvasText *item = new QtCanvasText(canvas); item->setText(tr("Text")); item->setColor(QColor(rand() % 32*8, rand() % 32*8, rand() % 32*8)); item->move(rand() % canvas->width(), rand() % canvas->height()); item->setZ(rand() % 256); item->show(); return item; } void MainWindow::itemMoved(QtCanvasItem *item) { if (item != currentItem) return; variantManager->setValue(idToProperty[QLatin1String("xpos")], item->x()); variantManager->setValue(idToProperty[QLatin1String("ypos")], item->y()); variantManager->setValue(idToProperty[QLatin1String("zpos")], item->z()); } void MainWindow::updateExpandState() { QList list = propertyEditor->topLevelItems(); QListIterator it(list); while (it.hasNext()) { QtBrowserItem *item = it.next(); QtProperty *prop = item->property(); idToExpanded[propertyToId[prop]] = propertyEditor->isExpanded(item); } } void MainWindow::itemClicked(QtCanvasItem *item) { updateExpandState(); QMap::ConstIterator itProp = propertyToId.constBegin(); while (itProp != propertyToId.constEnd()) { delete itProp.key(); itProp++; } propertyToId.clear(); idToProperty.clear(); currentItem = item; if (!currentItem) { deleteAction->setEnabled(false); return; } deleteAction->setEnabled(true); QtVariantProperty *property; property = variantManager->addProperty(QVariant::Double, tr("Position X")); property->setAttribute(QLatin1String("minimum"), 0); property->setAttribute(QLatin1String("maximum"), canvas->width()); property->setValue(item->x()); addProperty(property, QLatin1String("xpos")); property = variantManager->addProperty(QVariant::Double, tr("Position Y")); property->setAttribute(QLatin1String("minimum"), 0); property->setAttribute(QLatin1String("maximum"), canvas->height()); property->setValue(item->y()); addProperty(property, QLatin1String("ypos")); property = variantManager->addProperty(QVariant::Double, tr("Position Z")); property->setAttribute(QLatin1String("minimum"), 0); property->setAttribute(QLatin1String("maximum"), 256); property->setValue(item->z()); addProperty(property, QLatin1String("zpos")); if (item->rtti() == QtCanvasItem::Rtti_Rectangle) { QtCanvasRectangle *i = (QtCanvasRectangle *)item; property = variantManager->addProperty(QVariant::Color, tr("Brush Color")); property->setValue(i->brush().color()); addProperty(property, QLatin1String("brush")); property = variantManager->addProperty(QVariant::Color, tr("Pen Color")); property->setValue(i->pen().color()); addProperty(property, QLatin1String("pen")); property = variantManager->addProperty(QVariant::Size, tr("Size")); property->setValue(i->size()); addProperty(property, QLatin1String("size")); } else if (item->rtti() == QtCanvasItem::Rtti_Line) { QtCanvasLine *i = (QtCanvasLine *)item; property = variantManager->addProperty(QVariant::Color, tr("Pen Color")); property->setValue(i->pen().color()); addProperty(property, QLatin1String("pen")); property = variantManager->addProperty(QVariant::Point, tr("Vector")); property->setValue(i->endPoint()); addProperty(property, QLatin1String("endpoint")); } else if (item->rtti() == QtCanvasItem::Rtti_Ellipse) { QtCanvasEllipse *i = (QtCanvasEllipse *)item; property = variantManager->addProperty(QVariant::Color, tr("Brush Color")); property->setValue(i->brush().color()); addProperty(property, QLatin1String("brush")); property = variantManager->addProperty(QVariant::Size, tr("Size")); property->setValue(QSize(i->width(), i->height())); addProperty(property, QLatin1String("size")); } else if (item->rtti() == QtCanvasItem::Rtti_Text) { QtCanvasText *i = (QtCanvasText *)item; property = variantManager->addProperty(QVariant::Color, tr("Color")); property->setValue(i->color()); addProperty(property, QLatin1String("color")); property = variantManager->addProperty(QVariant::String, tr("Text")); property->setValue(i->text()); addProperty(property, QLatin1String("text")); property = variantManager->addProperty(QVariant::Font, tr("Font")); property->setValue(i->font()); addProperty(property, QLatin1String("font")); } } void MainWindow::addProperty(QtVariantProperty *property, const QString &id) { propertyToId[property] = id; idToProperty[id] = property; QtBrowserItem *item = propertyEditor->addProperty(property); if (idToExpanded.contains(id)) propertyEditor->setExpanded(item, idToExpanded[id]); } void MainWindow::valueChanged(QtProperty *property, const QVariant &value) { if (!propertyToId.contains(property)) return; if (!currentItem) return; QString id = propertyToId[property]; if (id == QLatin1String("xpos")) { currentItem->setX(value.toDouble()); } else if (id == QLatin1String("ypos")) { currentItem->setY(value.toDouble()); } else if (id == QLatin1String("zpos")) { currentItem->setZ(value.toDouble()); } else if (id == QLatin1String("text")) { if (currentItem->rtti() == QtCanvasItem::Rtti_Text) { QtCanvasText *i = (QtCanvasText *)currentItem; i->setText(value.value()); } } else if (id == QLatin1String("color")) { if (currentItem->rtti() == QtCanvasItem::Rtti_Text) { QtCanvasText *i = (QtCanvasText *)currentItem; i->setColor(value.value()); } } else if (id == QLatin1String("brush")) { if (currentItem->rtti() == QtCanvasItem::Rtti_Rectangle || currentItem->rtti() == QtCanvasItem::Rtti_Ellipse) { QtCanvasPolygonalItem *i = (QtCanvasPolygonalItem *)currentItem; QBrush b = i->brush(); b.setColor(value.value()); i->setBrush(b); } } else if (id == QLatin1String("pen")) { if (currentItem->rtti() == QtCanvasItem::Rtti_Rectangle || currentItem->rtti() == QtCanvasItem::Rtti_Line) { QtCanvasPolygonalItem *i = (QtCanvasPolygonalItem *)currentItem; QPen p = i->pen(); p.setColor(value.value()); i->setPen(p); } } else if (id == QLatin1String("font")) { if (currentItem->rtti() == QtCanvasItem::Rtti_Text) { QtCanvasText *i = (QtCanvasText *)currentItem; i->setFont(value.value()); } } else if (id == QLatin1String("endpoint")) { if (currentItem->rtti() == QtCanvasItem::Rtti_Line) { QtCanvasLine *i = (QtCanvasLine *)currentItem; QPoint p = value.value(); i->setPoints(i->startPoint().x(), i->startPoint().y(), p.x(), p.y()); } } else if (id == QLatin1String("size")) { if (currentItem->rtti() == QtCanvasItem::Rtti_Rectangle) { QtCanvasRectangle *i = (QtCanvasRectangle *)currentItem; QSize s = value.value(); i->setSize(s.width(), s.height()); } else if (currentItem->rtti() == QtCanvasItem::Rtti_Ellipse) { QtCanvasEllipse *i = (QtCanvasEllipse *)currentItem; QSize s = value.value(); i->setSize(s.width(), s.height()); } } canvas->update(); } nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/canvas_variant/mainwindow.h000066400000000000000000000073511455373415500312030ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include "qtcanvas.h" class QtVariantProperty; class QtProperty; class QtBrowserIndex; class CanvasView : public QtCanvasView { Q_OBJECT public: CanvasView(QWidget *parent = 0) : QtCanvasView(parent), moving(0) { } CanvasView(QtCanvas *canvas, QWidget *parent = 0) : QtCanvasView(canvas, parent), moving(0) { } signals: void itemClicked(QtCanvasItem *item); void itemMoved(QtCanvasItem *item); protected: void contentsMousePressEvent(QMouseEvent *event); void contentsMouseDoubleClickEvent(QMouseEvent *event); void contentsMouseMoveEvent(QMouseEvent* event); private: void handleMouseClickEvent(QMouseEvent *event); QPoint moving_start; QtCanvasItem *moving; }; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = 0); private slots: void newRectangle(); void newEllipse(); void newLine(); void newText(); void deleteObject(); void clearAll(); void fillView(); void itemClicked(QtCanvasItem *item); void itemMoved(QtCanvasItem *item); void valueChanged(QtProperty *property, const QVariant &value); private: QtCanvasItem *addRectangle(); QtCanvasItem *addEllipse(); QtCanvasItem *addLine(); QtCanvasItem *addText(); void addProperty(QtVariantProperty *property, const QString &id); void updateExpandState(); QAction *deleteAction; class QtVariantPropertyManager *variantManager; class QtTreePropertyBrowser *propertyEditor; CanvasView *canvasView; QtCanvas *canvas; QtCanvasItem *currentItem; QMap propertyToId; QMap idToProperty; QMap idToExpanded; }; #endif nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/canvas_variant/qtcanvas.cpp000066400000000000000000005021201455373415500311740ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #include "qtcanvas.h" #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Qt; class QtCanvasData { public: QtCanvasData() { } QList viewList; QSet itemDict; QSet animDict; }; class QtCanvasViewData { public: QtCanvasViewData() {} QMatrix xform; QMatrix ixform; bool highQuality; }; // clusterizer class QtCanvasClusterizer { public: QtCanvasClusterizer(int maxclusters); ~QtCanvasClusterizer(); void add(int x, int y); // 1x1 rectangle (point) void add(int x, int y, int w, int h); void add(const QRect& rect); void clear(); int clusters() const { return count; } const QRect& operator[](int i) const; private: QRect* cluster; int count; const int maxcl; }; static void include(QRect& r, const QRect& rect) { if (rect.left() < r.left()) { r.setLeft(rect.left()); } if (rect.right()>r.right()) { r.setRight(rect.right()); } if (rect.top() < r.top()) { r.setTop(rect.top()); } if (rect.bottom()>r.bottom()) { r.setBottom(rect.bottom()); } } /* A QtCanvasClusterizer groups rectangles (QRects) into non-overlapping rectangles by a merging heuristic. */ QtCanvasClusterizer::QtCanvasClusterizer(int maxclusters) : cluster(new QRect[maxclusters]), count(0), maxcl(maxclusters) { } QtCanvasClusterizer::~QtCanvasClusterizer() { delete [] cluster; } void QtCanvasClusterizer::clear() { count = 0; } void QtCanvasClusterizer::add(int x, int y) { add(QRect(x, y, 1, 1)); } void QtCanvasClusterizer::add(int x, int y, int w, int h) { add(QRect(x, y, w, h)); } void QtCanvasClusterizer::add(const QRect& rect) { QRect biggerrect(rect.x()-1, rect.y()-1, rect.width()+2, rect.height()+2); //assert(rect.width()>0 && rect.height()>0); int cursor; for (cursor = 0; cursor < count; cursor++) { if (cluster[cursor].contains(rect)) { // Wholly contained already. return; } } int lowestcost = 9999999; int cheapest = -1; cursor = 0; while(cursor < count) { if (cluster[cursor].intersects(biggerrect)) { QRect larger = cluster[cursor]; include(larger, rect); int cost = larger.width()*larger.height() - cluster[cursor].width()*cluster[cursor].height(); if (cost < lowestcost) { bool bad = false; for (int c = 0; c < count && !bad; c++) { bad = cluster[c].intersects(larger) && c!= cursor; } if (!bad) { cheapest = cursor; lowestcost = cost; } } } cursor++; } if (cheapest>= 0) { include(cluster[cheapest], rect); return; } if (count < maxcl) { cluster[count++] = rect; return; } // Do cheapest of: // add to closest cluster // do cheapest cluster merge, add to new cluster lowestcost = 9999999; cheapest = -1; cursor = 0; while(cursor < count) { QRect larger = cluster[cursor]; include(larger, rect); int cost = larger.width()*larger.height() - cluster[cursor].width()*cluster[cursor].height(); if (cost < lowestcost) { bool bad = false; for (int c = 0; c < count && !bad; c++) { bad = cluster[c].intersects(larger) && c!= cursor; } if (!bad) { cheapest = cursor; lowestcost = cost; } } cursor++; } // ### // could make an heuristic guess as to whether we need to bother // looking for a cheap merge. int cheapestmerge1 = -1; int cheapestmerge2 = -1; int merge1 = 0; while(merge1 < count) { int merge2 = 0; while(merge2 < count) { if(merge1!= merge2) { QRect larger = cluster[merge1]; include(larger, cluster[merge2]); int cost = larger.width()*larger.height() - cluster[merge1].width()*cluster[merge1].height() - cluster[merge2].width()*cluster[merge2].height(); if (cost < lowestcost) { bool bad = false; for (int c = 0; c < count && !bad; c++) { bad = cluster[c].intersects(larger) && c!= cursor; } if (!bad) { cheapestmerge1 = merge1; cheapestmerge2 = merge2; lowestcost = cost; } } } merge2++; } merge1++; } if (cheapestmerge1>= 0) { include(cluster[cheapestmerge1], cluster[cheapestmerge2]); cluster[cheapestmerge2] = cluster[count--]; } else { // if (!cheapest) debugRectangles(rect); include(cluster[cheapest], rect); } // NB: clusters do not intersect (or intersection will // overwrite). This is a result of the above algorithm, // given the assumption that (x, y) are ordered topleft // to bottomright. // ### // // add explicit x/y ordering to that comment, move it to the top // and rephrase it as pre-/post-conditions. } const QRect& QtCanvasClusterizer::operator[](int i) const { return cluster[i]; } // end of clusterizer class QtCanvasItemLess { public: inline bool operator()(const QtCanvasItem *i1, const QtCanvasItem *i2) const { if (i1->z() == i2->z()) return i1 > i2; return (i1->z() > i2->z()); } }; class QtCanvasChunk { public: QtCanvasChunk() : changed(true) { } // Other code assumes lists are not deleted. Assignment is also // done on ChunkRecs. So don't add that sort of thing here. void sort() { qSort(m_list.begin(), m_list.end(), QtCanvasItemLess()); } const QtCanvasItemList &list() const { return m_list; } void add(QtCanvasItem* item) { m_list.prepend(item); changed = true; } void remove(QtCanvasItem* item) { m_list.removeAll(item); changed = true; } void change() { changed = true; } bool hasChanged() const { return changed; } bool takeChange() { bool y = changed; changed = false; return y; } private: QtCanvasItemList m_list; bool changed; }; static int gcd(int a, int b) { int r; while ((r = a%b)) { a = b; b = r; } return b; } static int scm(int a, int b) { int g = gcd(a, b); return a/g*b; } /* \class QtCanvas qtcanvas.h \brief The QtCanvas class provides a 2D area that can contain QtCanvasItem objects. The QtCanvas class manages its 2D graphic area and all the canvas items the area contains. The canvas has no visual appearance of its own. Instead, it is displayed on screen using a QtCanvasView. Multiple QtCanvasView widgets may be associated with a canvas to provide multiple views of the same canvas. The canvas is optimized for large numbers of items, particularly where only a small percentage of the items change at any one time. If the entire display changes very frequently, you should consider using your own custom QtScrollView subclass. Qt provides a rich set of canvas item classes, e.g. QtCanvasEllipse, QtCanvasLine, QtCanvasPolygon, QtCanvasPolygonalItem, QtCanvasRectangle, QtCanvasSpline, QtCanvasSprite and QtCanvasText. You can subclass to create your own canvas items; QtCanvasPolygonalItem is the most common base class used for this purpose. Items appear on the canvas after their \link QtCanvasItem::show() show()\endlink function has been called (or \link QtCanvasItem::setVisible() setVisible(true)\endlink), and \e after update() has been called. The canvas only shows items that are \link QtCanvasItem::setVisible() visible\endlink, and then only if \l update() is called. (By default the canvas is white and so are canvas items, so if nothing appears try changing colors.) If you created the canvas without passing a width and height to the constructor you must also call resize(). Although a canvas may appear to be similar to a widget with child widgets, there are several notable differences: \list \i Canvas items are usually much faster to manipulate and redraw than child widgets, with the speed advantage becoming especially great when there are \e many canvas items and non-rectangular items. In most situations canvas items are also a lot more memory efficient than child widgets. \i It's easy to detect overlapping items (collision detection). \i The canvas can be larger than a widget. A million-by-million canvas is perfectly possible. At such a size a widget might be very inefficient, and some window systems might not support it at all, whereas QtCanvas scales well. Even with a billion pixels and a million items, finding a particular canvas item, detecting collisions, etc., is still fast (though the memory consumption may be prohibitive at such extremes). \i Two or more QtCanvasView objects can view the same canvas. \i An arbitrary transformation matrix can be set on each QtCanvasView which makes it easy to zoom, rotate or shear the viewed canvas. \i Widgets provide a lot more functionality, such as input (QKeyEvent, QMouseEvent etc.) and layout management (QGridLayout etc.). \endlist A canvas consists of a background, a number of canvas items organized by x, y and z coordinates, and a foreground. A canvas item's z coordinate can be treated as a layer number -- canvas items with a higher z coordinate appear in front of canvas items with a lower z coordinate. The background is white by default, but can be set to a different color using setBackgroundColor(), or to a repeated pixmap using setBackgroundPixmap() or to a mosaic of smaller pixmaps using setTiles(). Individual tiles can be set with setTile(). There are corresponding get functions, e.g. backgroundColor() and backgroundPixmap(). Note that QtCanvas does not inherit from QWidget, even though it has some functions which provide the same functionality as those in QWidget. One of these is setBackgroundPixmap(); some others are resize(), size(), width() and height(). \l QtCanvasView is the widget used to display a canvas on the screen. Canvas items are added to a canvas by constructing them and passing the canvas to the canvas item's constructor. An item can be moved to a different canvas using QtCanvasItem::setCanvas(). Canvas items are movable (and in the case of QtCanvasSprites, animated) objects that inherit QtCanvasItem. Each canvas item has a position on the canvas (x, y coordinates) and a height (z coordinate), all of which are held as floating-point numbers. Moving canvas items also have x and y velocities. It's possible for a canvas item to be outside the canvas (for example QtCanvasItem::x() is greater than width()). When a canvas item is off the canvas, onCanvas() returns false and the canvas disregards the item. (Canvas items off the canvas do not slow down any of the common operations on the canvas.) Canvas items can be moved with QtCanvasItem::move(). The advance() function moves all QtCanvasItem::animated() canvas items and setAdvancePeriod() makes QtCanvas move them automatically on a periodic basis. In the context of the QtCanvas classes, to `animate' a canvas item is to set it in motion, i.e. using QtCanvasItem::setVelocity(). Animation of a canvas item itself, i.e. items which change over time, is enabled by calling QtCanvasSprite::setFrameAnimation(), or more generally by subclassing and reimplementing QtCanvasItem::advance(). To detect collisions use one of the QtCanvasItem::collisions() functions. The changed parts of the canvas are redrawn (if they are visible in a canvas view) whenever update() is called. You can either call update() manually after having changed the contents of the canvas, or force periodic updates using setUpdatePeriod(). If you have moving objects on the canvas, you must call advance() every time the objects should move one step further. Periodic calls to advance() can be forced using setAdvancePeriod(). The advance() function will call QtCanvasItem::advance() on every item that is \link QtCanvasItem::animated() animated\endlink and trigger an update of the affected areas afterwards. (A canvas item that is `animated' is simply a canvas item that is in motion.) QtCanvas organizes its canvas items into \e chunks; these are areas on the canvas that are used to speed up most operations. Many operations start by eliminating most chunks (i.e. those which haven't changed) and then process only the canvas items that are in the few interesting (i.e. changed) chunks. A valid chunk, validChunk(), is one which is on the canvas. The chunk size is a key factor to QtCanvas's speed: if there are too many chunks, the speed benefit of grouping canvas items into chunks is reduced. If the chunks are too large, it takes too long to process each one. The QtCanvas constructor tries to pick a suitable size, but you can call retune() to change it at any time. The chunkSize() function returns the current chunk size. The canvas items always make sure they're in the right chunks; all you need to make sure of is that the canvas uses the right chunk size. A good rule of thumb is that the size should be a bit smaller than the average canvas item size. If you have moving objects, the chunk size should be a bit smaller than the average size of the moving items. The foreground is normally nothing, but if you reimplement drawForeground(), you can draw things in front of all the canvas items. Areas can be set as changed with setChanged() and set unchanged with setUnchanged(). The entire canvas can be set as changed with setAllChanged(). A list of all the items on the canvas is returned by allItems(). An area can be copied (painted) to a QPainter with drawArea(). If the canvas is resized it emits the resized() signal. The examples/canvas application and the 2D graphics page of the examples/demo application demonstrate many of QtCanvas's facilities. \sa QtCanvasView QtCanvasItem */ void QtCanvas::init(int w, int h, int chunksze, int mxclusters) { d = new QtCanvasData; awidth = w; aheight = h; chunksize = chunksze; maxclusters = mxclusters; chwidth = (w+chunksize-1)/chunksize; chheight = (h+chunksize-1)/chunksize; chunks = new QtCanvasChunk[chwidth*chheight]; update_timer = 0; bgcolor = white; grid = 0; htiles = 0; vtiles = 0; debug_redraw_areas = false; } /* Create a QtCanvas with no size. \a parent is passed to the QObject superclass. \warning You \e must call resize() at some time after creation to be able to use the canvas. */ QtCanvas::QtCanvas(QObject* parent) : QObject(parent) { init(0, 0); } /* Constructs a QtCanvas that is \a w pixels wide and \a h pixels high. */ QtCanvas::QtCanvas(int w, int h) { init(w, h); } /* Constructs a QtCanvas which will be composed of \a h tiles horizontally and \a v tiles vertically. Each tile will be an image \a tilewidth by \a tileheight pixels taken from pixmap \a p. The pixmap \a p is a list of tiles, arranged left to right, (and in the case of pixmaps that have multiple rows of tiles, top to bottom), with tile 0 in the top-left corner, tile 1 next to the right, and so on, e.g. \table \row \i 0 \i 1 \i 2 \i 3 \row \i 4 \i 5 \i 6 \i 7 \endtable The QtCanvas is initially sized to show exactly the given number of tiles horizontally and vertically. If it is resized to be larger, the entire matrix of tiles will be repeated as often as necessary to cover the area. If it is smaller, tiles to the right and bottom will not be visible. \sa setTiles() */ QtCanvas::QtCanvas(QPixmap p, int h, int v, int tilewidth, int tileheight) { init(h*tilewidth, v*tileheight, scm(tilewidth, tileheight)); setTiles(p, h, v, tilewidth, tileheight); } /* Destroys the canvas and all the canvas's canvas items. */ QtCanvas::~QtCanvas() { for (int i = 0; i < d->viewList.size(); ++i) d->viewList[i]->viewing = 0; QtCanvasItemList all = allItems(); for (QtCanvasItemList::Iterator it = all.begin(); it!= all.end(); ++it) delete *it; delete [] chunks; delete [] grid; delete d; } /* \internal Returns the chunk at a chunk position \a i, \a j. */ QtCanvasChunk& QtCanvas::chunk(int i, int j) const { return chunks[i+chwidth*j]; } /* \internal Returns the chunk at a pixel position \a x, \a y. */ QtCanvasChunk& QtCanvas::chunkContaining(int x, int y) const { return chunk(x/chunksize, y/chunksize); } /* Returns a list of all the items in the canvas. */ QtCanvasItemList QtCanvas::allItems() { return d->itemDict.toList(); } /* Changes the size of the canvas to have a width of \a w and a height of \a h. This is a slow operation. */ void QtCanvas::resize(int w, int h) { if (awidth == w && aheight == h) return; QList hidden; for (QSet::const_iterator it = d->itemDict.begin(); it != d->itemDict.end(); ++it) { if ((*it)->isVisible()) { (*it)->hide(); hidden.append(*it); } } int nchwidth = (w+chunksize-1)/chunksize; int nchheight = (h+chunksize-1)/chunksize; QtCanvasChunk* newchunks = new QtCanvasChunk[nchwidth*nchheight]; // Commit the new values. // awidth = w; aheight = h; chwidth = nchwidth; chheight = nchheight; delete [] chunks; chunks = newchunks; for (int i = 0; i < hidden.size(); ++i) hidden.at(i)->show(); setAllChanged(); emit resized(); } /* \fn void QtCanvas::resized() This signal is emitted whenever the canvas is resized. Each QtCanvasView connects to this signal to keep the scrollview's size correct. */ /* Change the efficiency tuning parameters to \a mxclusters clusters, each of size \a chunksze. This is a slow operation if there are many objects on the canvas. The canvas is divided into chunks which are rectangular areas \a chunksze wide by \a chunksze high. Use a chunk size which is about the average size of the canvas items. If you choose a chunk size which is too small it will increase the amount of calculation required when drawing since each change will affect many chunks. If you choose a chunk size which is too large the amount of drawing required will increase because for each change, a lot of drawing will be required since there will be many (unchanged) canvas items which are in the same chunk as the changed canvas items. Internally, a canvas uses a low-resolution "chunk matrix" to keep track of all the items in the canvas. A 64x64 chunk matrix is the default for a 1024x1024 pixel canvas, where each chunk collects canvas items in a 16x16 pixel square. This default is also affected by setTiles(). You can tune this default using this function. For example if you have a very large canvas and want to trade off speed for memory then you might set the chunk size to 32 or 64. The \a mxclusters argument is the number of rectangular groups of chunks that will be separately drawn. If the canvas has a large number of small, dispersed items, this should be about that number. Our testing suggests that a large number of clusters is almost always best. */ void QtCanvas::retune(int chunksze, int mxclusters) { maxclusters = mxclusters; if (chunksize!= chunksze) { QList hidden; for (QSet::const_iterator it = d->itemDict.begin(); it != d->itemDict.end(); ++it) { if ((*it)->isVisible()) { (*it)->hide(); hidden.append(*it); } } chunksize = chunksze; int nchwidth = (awidth+chunksize-1)/chunksize; int nchheight = (aheight+chunksize-1)/chunksize; QtCanvasChunk* newchunks = new QtCanvasChunk[nchwidth*nchheight]; // Commit the new values. // chwidth = nchwidth; chheight = nchheight; delete [] chunks; chunks = newchunks; for (int i = 0; i < hidden.size(); ++i) hidden.at(i)->show(); } } /* \fn int QtCanvas::width() const Returns the width of the canvas, in pixels. */ /* \fn int QtCanvas::height() const Returns the height of the canvas, in pixels. */ /* \fn QSize QtCanvas::size() const Returns the size of the canvas, in pixels. */ /* \fn QRect QtCanvas::rect() const Returns a rectangle the size of the canvas. */ /* \fn bool QtCanvas::onCanvas(int x, int y) const Returns true if the pixel position (\a x, \a y) is on the canvas; otherwise returns false. \sa validChunk() */ /* \fn bool QtCanvas::onCanvas(const QPoint& p) const \overload Returns true if the pixel position \a p is on the canvas; otherwise returns false. \sa validChunk() */ /* \fn bool QtCanvas::validChunk(int x, int y) const Returns true if the chunk position (\a x, \a y) is on the canvas; otherwise returns false. \sa onCanvas() */ /* \fn bool QtCanvas::validChunk(const QPoint& p) const \overload Returns true if the chunk position \a p is on the canvas; otherwise returns false. \sa onCanvas() */ /* \fn int QtCanvas::chunkSize() const Returns the chunk size of the canvas. \sa retune() */ /* \fn bool QtCanvas::sameChunk(int x1, int y1, int x2, int y2) const \internal Tells if the points (\a x1, \a y1) and (\a x2, \a y2) are within the same chunk. */ /* \internal This method adds an the item \a item to the list of QtCanvasItem objects in the QtCanvas. The QtCanvasItem class calls this. */ void QtCanvas::addItem(QtCanvasItem* item) { d->itemDict.insert(item); } /* \internal This method adds the item \a item to the list of QtCanvasItem objects to be moved. The QtCanvasItem class calls this. */ void QtCanvas::addAnimation(QtCanvasItem* item) { d->animDict.insert(item); } /* \internal This method adds the item \a item to the list of QtCanvasItem objects which are no longer to be moved. The QtCanvasItem class calls this. */ void QtCanvas::removeAnimation(QtCanvasItem* item) { d->animDict.remove(item); } /* \internal This method removes the item \a item from the list of QtCanvasItem objects in this QtCanvas. The QtCanvasItem class calls this. */ void QtCanvas::removeItem(QtCanvasItem* item) { d->itemDict.remove(item); } /* \internal This method adds the view \a view to the list of QtCanvasView objects viewing this QtCanvas. The QtCanvasView class calls this. */ void QtCanvas::addView(QtCanvasView* view) { d->viewList.append(view); if (htiles>1 || vtiles>1 || pm.isNull()) { QPalette::ColorRole role = view->widget()->backgroundRole(); QPalette viewPalette = view->widget()->palette(); viewPalette.setColor(role, backgroundColor()); view->widget()->setPalette(viewPalette); } } /* \internal This method removes the view \a view from the list of QtCanvasView objects viewing this QtCanvas. The QtCanvasView class calls this. */ void QtCanvas::removeView(QtCanvasView* view) { d->viewList.removeAll(view); } /* Sets the canvas to call advance() every \a ms milliseconds. Any previous setting by setAdvancePeriod() or setUpdatePeriod() is overridden. If \a ms is less than 0 advancing will be stopped. */ void QtCanvas::setAdvancePeriod(int ms) { if (ms < 0) { if (update_timer) update_timer->stop(); } else { if (update_timer) delete update_timer; update_timer = new QTimer(this); connect(update_timer, SIGNAL(timeout()), this, SLOT(advance())); update_timer->start(ms); } } /* Sets the canvas to call update() every \a ms milliseconds. Any previous setting by setAdvancePeriod() or setUpdatePeriod() is overridden. If \a ms is less than 0 automatic updating will be stopped. */ void QtCanvas::setUpdatePeriod(int ms) { if (ms < 0) { if (update_timer) update_timer->stop(); } else { if (update_timer) delete update_timer; update_timer = new QTimer(this); connect(update_timer, SIGNAL(timeout()), this, SLOT(update())); update_timer->start(ms); } } /* Moves all QtCanvasItem::animated() canvas items on the canvas and refreshes all changes to all views of the canvas. (An `animated' item is an item that is in motion; see setVelocity().) The advance takes place in two phases. In phase 0, the QtCanvasItem::advance() function of each QtCanvasItem::animated() canvas item is called with paramater 0. Then all these canvas items are called again, with parameter 1. In phase 0, the canvas items should not change position, merely examine other items on the canvas for which special processing is required, such as collisions between items. In phase 1, all canvas items should change positions, ignoring any other items on the canvas. This two-phase approach allows for considerations of "fairness", although no QtCanvasItem subclasses supplied with Qt do anything interesting in phase 0. The canvas can be configured to call this function periodically with setAdvancePeriod(). \sa update() */ void QtCanvas::advance() { QSetIterator it = d->animDict; while (it.hasNext()) { QtCanvasItem *i = it.next(); if (i) i->advance(0); } // we expect the dict contains the exact same items as in the // first pass. it.toFront(); while (it.hasNext()) { QtCanvasItem* i = it.next(); if (i) i->advance(1); } update(); } // Don't call this unless you know what you're doing. // p is in the content's co-ordinate example. /* \internal */ void QtCanvas::drawViewArea(QtCanvasView* view, QPainter* p, const QRect& vr, bool) { QMatrix wm = view->worldMatrix(); QMatrix iwm = wm.inverted(); // ivr = covers all chunks in vr QRect ivr = iwm.mapRect(vr); p->setMatrix(wm); drawCanvasArea(ivr, p, false); } /* Repaints changed areas in all views of the canvas. \sa advance() */ void QtCanvas::update() { QRect r = changeBounds(); for (int i = 0; i < d->viewList.size(); ++i) { QtCanvasView* view = d->viewList.at(i); if (!r.isEmpty()) { QRect tr = view->worldMatrix().mapRect(r); view->widget()->update(tr); } } setUnchanged(r); } /* Marks the whole canvas as changed. All views of the canvas will be entirely redrawn when update() is called next. */ void QtCanvas::setAllChanged() { setChanged(QRect(0, 0, width(), height())); } /* Marks \a area as changed. This \a area will be redrawn in all views that are showing it when update() is called next. */ void QtCanvas::setChanged(const QRect& area) { QRect thearea = area.intersected(QRect(0, 0, width(), height())); int mx = (thearea.x()+thearea.width()+chunksize)/chunksize; int my = (thearea.y()+thearea.height()+chunksize)/chunksize; if (mx>chwidth) mx = chwidth; if (my>chheight) my = chheight; int x = thearea.x()/chunksize; while(x < mx) { int y = thearea.y()/chunksize; while(y < my) { chunk(x, y).change(); y++; } x++; } } /* Marks \a area as \e unchanged. The area will \e not be redrawn in the views for the next update(), unless it is marked or changed again before the next call to update(). */ void QtCanvas::setUnchanged(const QRect& area) { QRect thearea = area.intersected(QRect(0, 0, width(), height())); int mx = (thearea.x()+thearea.width()+chunksize)/chunksize; int my = (thearea.y()+thearea.height()+chunksize)/chunksize; if (mx>chwidth) mx = chwidth; if (my>chheight) my = chheight; int x = thearea.x()/chunksize; while(x < mx) { int y = thearea.y()/chunksize; while(y < my) { chunk(x, y).takeChange(); y++; } x++; } } /* \internal */ QRect QtCanvas::changeBounds() { QRect area = QRect(0, 0, width(), height()); int mx = (area.x()+area.width()+chunksize)/chunksize; int my = (area.y()+area.height()+chunksize)/chunksize; if (mx > chwidth) mx = chwidth; if (my > chheight) my = chheight; QRect result; int x = area.x()/chunksize; while(x < mx) { int y = area.y()/chunksize; while(y < my) { QtCanvasChunk& ch = chunk(x, y); if (ch.hasChanged()) result |= QRect(x*chunksize, y*chunksize, chunksize + 1, chunksize + 1); y++; } x++; } return result; } /* Paints all canvas items that are in the area \a clip to \a painter, using double-buffering if \a dbuf is true. e.g. to print the canvas to a printer: \code QPrinter pr; if (pr.setup()) { QPainter p(&pr); canvas.drawArea(canvas.rect(), &p); } \endcode */ void QtCanvas::drawArea(const QRect& clip, QPainter* painter, bool dbuf) { if (painter) drawCanvasArea(clip, painter, dbuf); } #include /* \internal */ void QtCanvas::drawCanvasArea(const QRect& inarea, QPainter* p, bool /*double_buffer*/) { QRect area = inarea.intersected(QRect(0, 0, width(), height())); if (!p) return; // Nothing to do. int lx = area.x()/chunksize; int ly = area.y()/chunksize; int mx = area.right()/chunksize; int my = area.bottom()/chunksize; if (mx>= chwidth) mx = chwidth-1; if (my>= chheight) my = chheight-1; QtCanvasItemList allvisible; // Stores the region within area that need to be drawn. It is relative // to area.topLeft() (so as to keep within bounds of 16-bit XRegions) QRegion rgn; for (int x = lx; x <= mx; x++) { for (int y = ly; y <= my; y++) { // Only reset change if all views updating, and // wholy within area. (conservative: ignore entire boundary) // // Disable this to help debugging. // if (!p) { if (chunk(x, y).takeChange()) { // ### should at least make bands rgn |= QRegion(x*chunksize-area.x(), y*chunksize-area.y(), chunksize, chunksize); allvisible += chunk(x, y).list(); } } else { allvisible += chunk(x, y).list(); } } } qSort(allvisible.begin(), allvisible.end(), QtCanvasItemLess()); drawBackground(*p, area); if (!allvisible.isEmpty()) { QtCanvasItem* prev = 0; for (int i = allvisible.size() - 1; i >= 0; --i) { QtCanvasItem *g = allvisible[i]; if (g != prev) { g->draw(*p); prev = g; } } } drawForeground(*p, area); } /* \internal This method to informs the QtCanvas that a given chunk is `dirty' and needs to be redrawn in the next Update. (\a x, \a y) is a chunk location. The sprite classes call this. Any new derived class of QtCanvasItem must do so too. SetChangedChunkContaining can be used instead. */ void QtCanvas::setChangedChunk(int x, int y) { if (validChunk(x, y)) { QtCanvasChunk& ch = chunk(x, y); ch.change(); } } /* \internal This method to informs the QtCanvas that the chunk containing a given pixel is `dirty' and needs to be redrawn in the next Update. (\a x, \a y) is a pixel location. The item classes call this. Any new derived class of QtCanvasItem must do so too. SetChangedChunk can be used instead. */ void QtCanvas::setChangedChunkContaining(int x, int y) { if (x>= 0 && x < width() && y>= 0 && y < height()) { QtCanvasChunk& chunk = chunkContaining(x, y); chunk.change(); } } /* \internal This method adds the QtCanvasItem \a g to the list of those which need to be drawn if the given chunk at location (\a x, \a y) is redrawn. Like SetChangedChunk and SetChangedChunkContaining, this method marks the chunk as `dirty'. */ void QtCanvas::addItemToChunk(QtCanvasItem* g, int x, int y) { if (validChunk(x, y)) { chunk(x, y).add(g); } } /* \internal This method removes the QtCanvasItem \a g from the list of those which need to be drawn if the given chunk at location (\a x, \a y) is redrawn. Like SetChangedChunk and SetChangedChunkContaining, this method marks the chunk as `dirty'. */ void QtCanvas::removeItemFromChunk(QtCanvasItem* g, int x, int y) { if (validChunk(x, y)) { chunk(x, y).remove(g); } } /* \internal This method adds the QtCanvasItem \a g to the list of those which need to be drawn if the chunk containing the given pixel (\a x, \a y) is redrawn. Like SetChangedChunk and SetChangedChunkContaining, this method marks the chunk as `dirty'. */ void QtCanvas::addItemToChunkContaining(QtCanvasItem* g, int x, int y) { if (x>= 0 && x < width() && y>= 0 && y < height()) { chunkContaining(x, y).add(g); } } /* \internal This method removes the QtCanvasItem \a g from the list of those which need to be drawn if the chunk containing the given pixel (\a x, \a y) is redrawn. Like SetChangedChunk and SetChangedChunkContaining, this method marks the chunk as `dirty'. */ void QtCanvas::removeItemFromChunkContaining(QtCanvasItem* g, int x, int y) { if (x>= 0 && x < width() && y>= 0 && y < height()) { chunkContaining(x, y).remove(g); } } /* Returns the color set by setBackgroundColor(). By default, this is white. This function is not a reimplementation of QWidget::backgroundColor() (QtCanvas is not a subclass of QWidget), but all QtCanvasViews that are viewing the canvas will set their backgrounds to this color. \sa setBackgroundColor(), backgroundPixmap() */ QColor QtCanvas::backgroundColor() const { return bgcolor; } /* Sets the solid background to be the color \a c. \sa backgroundColor(), setBackgroundPixmap(), setTiles() */ void QtCanvas::setBackgroundColor(const QColor& c) { if (bgcolor != c) { bgcolor = c; for (int i = 0; i < d->viewList.size(); ++i) { QtCanvasView *view = d->viewList.at(i); QPalette::ColorRole role = view->widget()->backgroundRole(); QPalette viewPalette = view->widget()->palette(); viewPalette.setColor(role, bgcolor); view->widget()->setPalette(viewPalette); } setAllChanged(); } } /* Returns the pixmap set by setBackgroundPixmap(). By default, this is a null pixmap. \sa setBackgroundPixmap(), backgroundColor() */ QPixmap QtCanvas::backgroundPixmap() const { return pm; } /* Sets the solid background to be the pixmap \a p repeated as necessary to cover the entire canvas. \sa backgroundPixmap(), setBackgroundColor(), setTiles() */ void QtCanvas::setBackgroundPixmap(const QPixmap& p) { setTiles(p, 1, 1, p.width(), p.height()); for (int i = 0; i < d->viewList.size(); ++i) { QtCanvasView* view = d->viewList.at(i); view->widget()->update(); } } /* This virtual function is called for all updates of the canvas. It renders any background graphics using the painter \a painter, in the area \a clip. If the canvas has a background pixmap or a tiled background, that graphic is used, otherwise the canvas is cleared using the background color. If the graphics for an area change, you must explicitly call setChanged(const QRect&) for the result to be visible when update() is next called. \sa setBackgroundColor(), setBackgroundPixmap(), setTiles() */ void QtCanvas::drawBackground(QPainter& painter, const QRect& clip) { if (pm.isNull()) { painter.fillRect(clip, bgcolor); } else if (!grid) { for (int x = clip.x()/pm.width(); x < (clip.x()+clip.width()+pm.width()-1)/pm.width(); x++) { for (int y = clip.y()/pm.height(); y < (clip.y()+clip.height()+pm.height()-1)/pm.height(); y++) { painter.drawPixmap(x*pm.width(), y*pm.height(), pm); } } } else { const int x1 = clip.left()/tilew; int x2 = clip.right()/tilew; const int y1 = clip.top()/tileh; int y2 = clip.bottom()/tileh; const int roww = pm.width()/tilew; for (int j = y1; j <= y2; j++) { int jj = j%tilesVertically(); for (int i = x1; i <= x2; i++) { int t = tile(i%tilesHorizontally(), jj); int tx = t % roww; int ty = t / roww; painter.drawPixmap(i*tilew, j*tileh, pm, tx*tilew, ty*tileh, tilew, tileh); } } } } /* This virtual function is called for all updates of the canvas. It renders any foreground graphics using the painter \a painter, in the area \a clip. If the graphics for an area change, you must explicitly call setChanged(const QRect&) for the result to be visible when update() is next called. The default is to draw nothing. */ void QtCanvas::drawForeground(QPainter& painter, const QRect& clip) { if (debug_redraw_areas) { painter.setPen(red); painter.setBrush(NoBrush); painter.drawRect(clip); } } /* Sets the QtCanvas to be composed of \a h tiles horizontally and \a v tiles vertically. Each tile will be an image \a tilewidth by \a tileheight pixels from pixmap \a p. The pixmap \a p is a list of tiles, arranged left to right, (and in the case of pixmaps that have multiple rows of tiles, top to bottom), with tile 0 in the top-left corner, tile 1 next to the right, and so on, e.g. \table \row \i 0 \i 1 \i 2 \i 3 \row \i 4 \i 5 \i 6 \i 7 \endtable If the canvas is larger than the matrix of tiles, the entire matrix is repeated as necessary to cover the whole canvas. If it is smaller, tiles to the right and bottom are not visible. The width and height of \a p must be a multiple of \a tilewidth and \a tileheight. If they are not the function will do nothing. If you want to unset any tiling set, then just pass in a null pixmap and 0 for \a h, \a v, \a tilewidth, and \a tileheight. */ void QtCanvas::setTiles(QPixmap p, int h, int v, int tilewidth, int tileheight) { if (!p.isNull() && (!tilewidth || !tileheight || p.width() % tilewidth != 0 || p.height() % tileheight != 0)) return; htiles = h; vtiles = v; delete[] grid; pm = p; if (h && v && !p.isNull()) { grid = new ushort[h*v]; memset(grid, 0, h*v*sizeof(ushort)); tilew = tilewidth; tileh = tileheight; } else { grid = 0; } if (h + v > 10) { int s = scm(tilewidth, tileheight); retune(s < 128 ? s : qMax(tilewidth, tileheight)); } setAllChanged(); } /* \fn int QtCanvas::tile(int x, int y) const Returns the tile at position (\a x, \a y). Initially, all tiles are 0. The parameters must be within range, i.e. 0 \< \a x \< tilesHorizontally() and 0 \< \a y \< tilesVertically(). \sa setTile() */ /* \fn int QtCanvas::tilesHorizontally() const Returns the number of tiles horizontally. */ /* \fn int QtCanvas::tilesVertically() const Returns the number of tiles vertically. */ /* \fn int QtCanvas::tileWidth() const Returns the width of each tile. */ /* \fn int QtCanvas::tileHeight() const Returns the height of each tile. */ /* Sets the tile at (\a x, \a y) to use tile number \a tilenum, which is an index into the tile pixmaps. The canvas will update appropriately when update() is next called. The images are taken from the pixmap set by setTiles() and are arranged left to right, (and in the case of pixmaps that have multiple rows of tiles, top to bottom), with tile 0 in the top-left corner, tile 1 next to the right, and so on, e.g. \table \row \i 0 \i 1 \i 2 \i 3 \row \i 4 \i 5 \i 6 \i 7 \endtable \sa tile() setTiles() */ void QtCanvas::setTile(int x, int y, int tilenum) { ushort& t = grid[x+y*htiles]; if (t != tilenum) { t = tilenum; if (tilew == tileh && tilew == chunksize) setChangedChunk(x, y); // common case else setChanged(QRect(x*tilew, y*tileh, tilew, tileh)); } } // lesser-used data in canvas item, plus room for extension. // Be careful adding to this - check all usages. class QtCanvasItemExtra { QtCanvasItemExtra() : vx(0.0), vy(0.0) { } double vx, vy; friend class QtCanvasItem; }; /* \class QtCanvasItem qtcanvas.h \brief The QtCanvasItem class provides an abstract graphic object on a QtCanvas. A variety of QtCanvasItem subclasses provide immediately usable behaviour. This class is a pure abstract superclass providing the behaviour that is shared among all the concrete canvas item classes. QtCanvasItem is not intended for direct subclassing. It is much easier to subclass one of its subclasses, e.g. QtCanvasPolygonalItem (the commonest base class), QtCanvasRectangle, QtCanvasSprite, QtCanvasEllipse or QtCanvasText. Canvas items are added to a canvas by constructing them and passing the canvas to the canvas item's constructor. An item can be moved to a different canvas using setCanvas(). Items appear on the canvas after their \link show() show()\endlink function has been called (or \link setVisible() setVisible(true)\endlink), and \e after update() has been called. The canvas only shows items that are \link setVisible() visible\endlink, and then only if \l update() is called. If you created the canvas without passing a width and height to the constructor you'll also need to call \link QtCanvas::resize() resize()\endlink. Since the canvas background defaults to white and canvas items default to white, you may need to change colors to see your items. A QtCanvasItem object can be moved in the x(), y() and z() dimensions using functions such as move(), moveBy(), setX(), setY() and setZ(). A canvas item can be set in motion, `animated', using setAnimated() and given a velocity in the x and y directions with setXVelocity() and setYVelocity() -- the same effect can be achieved by calling setVelocity(). Use the collidesWith() function to see if the canvas item will collide on the \e next advance(1) and use collisions() to see what collisions have occurred. Use QtCanvasSprite or your own subclass of QtCanvasSprite to create canvas items which are animated, i.e. which change over time. The size of a canvas item is given by boundingRect(). Use boundingRectAdvanced() to see what the size of the canvas item will be \e after the next advance(1) call. The rtti() function is used for identifying subclasses of QtCanvasItem. The canvas() function returns a pointer to the canvas which contains the canvas item. QtCanvasItem provides the show() and isVisible() functions like those in QWidget. QtCanvasItem also provides the setEnabled(), setActive() and setSelected() functions; these functions set the relevant boolean and cause a repaint but the boolean values they set are not used in QtCanvasItem itself. You can make use of these booleans in your subclasses. By default, canvas items have no velocity, no size, and are not in motion. The subclasses provided in Qt do not change these defaults except where noted. */ /* \enum QtCanvasItem::RttiValues This enum is used to name the different types of canvas item. \value Rtti_Item Canvas item abstract base class \value Rtti_Ellipse \value Rtti_Line \value Rtti_Polygon \value Rtti_PolygonalItem \value Rtti_Rectangle \value Rtti_Spline \value Rtti_Sprite \value Rtti_Text */ /* \fn void QtCanvasItem::update() Call this function to repaint the canvas's changed chunks. */ /* Constructs a QtCanvasItem on canvas \a canvas. \sa setCanvas() */ QtCanvasItem::QtCanvasItem(QtCanvas* canvas) : cnv(canvas), myx(0), myy(0), myz(0) { ani = 0; vis = 0; val = 0; sel = 0; ena = 0; act = 0; ext = 0; if (cnv) cnv->addItem(this); } /* Destroys the QtCanvasItem and removes it from its canvas. */ QtCanvasItem::~QtCanvasItem() { if (cnv) { cnv->removeItem(this); cnv->removeAnimation(this); } delete ext; } QtCanvasItemExtra& QtCanvasItem::extra() { if (!ext) ext = new QtCanvasItemExtra; return *ext; } /* \fn double QtCanvasItem::x() const Returns the horizontal position of the canvas item. Note that subclasses often have an origin other than the top-left corner. */ /* \fn double QtCanvasItem::y() const Returns the vertical position of the canvas item. Note that subclasses often have an origin other than the top-left corner. */ /* \fn double QtCanvasItem::z() const Returns the z index of the canvas item, which is used for visual order: higher-z items obscure (are in front of) lower-z items. */ /* \fn void QtCanvasItem::setX(double x) Moves the canvas item so that its x-position is \a x. \sa x(), move() */ /* \fn void QtCanvasItem::setY(double y) Moves the canvas item so that its y-position is \a y. \sa y(), move() */ /* \fn void QtCanvasItem::setZ(double z) Sets the z index of the canvas item to \a z. Higher-z items obscure (are in front of) lower-z items. \sa z(), move() */ /* Moves the canvas item relative to its current position by (\a dx, \a dy). */ void QtCanvasItem::moveBy(double dx, double dy) { if (dx || dy) { removeFromChunks(); myx += dx; myy += dy; addToChunks(); } } /* Moves the canvas item to the absolute position (\a x, \a y). */ void QtCanvasItem::move(double x, double y) { moveBy(x-myx, y-myy); } /* Returns true if the canvas item is in motion; otherwise returns false. \sa setVelocity(), setAnimated() */ bool QtCanvasItem::animated() const { return (bool)ani; } /* Sets the canvas item to be in motion if \a y is true, or not if \a y is false. The speed and direction of the motion is set with setVelocity(), or with setXVelocity() and setYVelocity(). \sa advance(), QtCanvas::advance() */ void QtCanvasItem::setAnimated(bool y) { if (y != (bool)ani) { ani = (uint)y; if (y) { cnv->addAnimation(this); } else { cnv->removeAnimation(this); } } } /* \fn void QtCanvasItem::setXVelocity(double vx) Sets the horizontal component of the canvas item's velocity to \a vx. \sa setYVelocity() setVelocity() */ /* \fn void QtCanvasItem::setYVelocity(double vy) Sets the vertical component of the canvas item's velocity to \a vy. \sa setXVelocity() setVelocity() */ /* Sets the canvas item to be in motion, moving by \a vx and \a vy pixels in the horizontal and vertical directions respectively. \sa advance() setXVelocity() setYVelocity() */ void QtCanvasItem::setVelocity(double vx, double vy) { if (ext || vx!= 0.0 || vy!= 0.0) { if (!ani) setAnimated(true); extra().vx = vx; extra().vy = vy; } } /* Returns the horizontal velocity component of the canvas item. */ double QtCanvasItem::xVelocity() const { return ext ? ext->vx : 0; } /* Returns the vertical velocity component of the canvas item. */ double QtCanvasItem::yVelocity() const { return ext ? ext->vy : 0; } /* The default implementation moves the canvas item, if it is animated(), by the preset velocity if \a phase is 1, and does nothing if \a phase is 0. Note that if you reimplement this function, the reimplementation must not change the canvas in any way, for example it must not add or remove items. \sa QtCanvas::advance() setVelocity() */ void QtCanvasItem::advance(int phase) { if (ext && phase == 1) moveBy(ext->vx, ext->vy); } /* \fn void QtCanvasItem::draw(QPainter& painter) This abstract virtual function draws the canvas item using \a painter. */ /* Sets the QtCanvas upon which the canvas item is to be drawn to \a c. \sa canvas() */ void QtCanvasItem::setCanvas(QtCanvas* c) { bool v = isVisible(); setVisible(false); if (cnv) { if (ext) cnv->removeAnimation(this); cnv->removeItem(this); } cnv = c; if (cnv) { cnv->addItem(this); if (ext) cnv->addAnimation(this); } setVisible(v); } /* \fn QtCanvas* QtCanvasItem::canvas() const Returns the canvas containing the canvas item. */ /* Shorthand for setVisible(true). */ void QtCanvasItem::show() { setVisible(true); } /* Shorthand for setVisible(false). */ void QtCanvasItem::hide() { setVisible(false); } /* Makes the canvas item visible if \a yes is true, or invisible if \a yes is false. The change takes effect when QtCanvas::update() is next called. */ void QtCanvasItem::setVisible(bool yes) { if ((bool)vis!= yes) { if (yes) { vis = (uint)yes; addToChunks(); } else { removeFromChunks(); vis = (uint)yes; } } } /* \obsolete \fn bool QtCanvasItem::visible() const Use isVisible() instead. */ /* \fn bool QtCanvasItem::isVisible() const Returns true if the canvas item is visible; otherwise returns false. Note that in this context true does \e not mean that the canvas item is currently in a view, merely that if a view is showing the area where the canvas item is positioned, and the item is not obscured by items with higher z values, and the view is not obscured by overlaying windows, it would be visible. \sa setVisible(), z() */ /* \obsolete \fn bool QtCanvasItem::selected() const Use isSelected() instead. */ /* \fn bool QtCanvasItem::isSelected() const Returns true if the canvas item is selected; otherwise returns false. */ /* Sets the selected flag of the item to \a yes. If this changes the item's selected state the item will be redrawn when QtCanvas::update() is next called. The QtCanvas, QtCanvasItem and the Qt-supplied QtCanvasItem subclasses do not make use of this value. The setSelected() function is supplied because many applications need it, but it is up to you how you use the isSelected() value. */ void QtCanvasItem::setSelected(bool yes) { if ((bool)sel!= yes) { sel = (uint)yes; changeChunks(); } } /* \obsolete \fn bool QtCanvasItem::enabled() const Use isEnabled() instead. */ /* \fn bool QtCanvasItem::isEnabled() const Returns true if the QtCanvasItem is enabled; otherwise returns false. */ /* Sets the enabled flag of the item to \a yes. If this changes the item's enabled state the item will be redrawn when QtCanvas::update() is next called. The QtCanvas, QtCanvasItem and the Qt-supplied QtCanvasItem subclasses do not make use of this value. The setEnabled() function is supplied because many applications need it, but it is up to you how you use the isEnabled() value. */ void QtCanvasItem::setEnabled(bool yes) { if (ena!= (uint)yes) { ena = (uint)yes; changeChunks(); } } /* \obsolete \fn bool QtCanvasItem::active() const Use isActive() instead. */ /* \fn bool QtCanvasItem::isActive() const Returns true if the QtCanvasItem is active; otherwise returns false. */ /* Sets the active flag of the item to \a yes. If this changes the item's active state the item will be redrawn when QtCanvas::update() is next called. The QtCanvas, QtCanvasItem and the Qt-supplied QtCanvasItem subclasses do not make use of this value. The setActive() function is supplied because many applications need it, but it is up to you how you use the isActive() value. */ void QtCanvasItem::setActive(bool yes) { if (act!= (uint)yes) { act = (uint)yes; changeChunks(); } } bool qt_testCollision(const QtCanvasSprite* s1, const QtCanvasSprite* s2) { const QImage* s2image = s2->imageAdvanced()->collision_mask; QRect s2area = s2->boundingRectAdvanced(); QRect cyourarea(s2area.x(), s2area.y(), s2area.width(), s2area.height()); QImage* s1image = s1->imageAdvanced()->collision_mask; QRect s1area = s1->boundingRectAdvanced(); QRect ourarea = s1area.intersected(cyourarea); if (ourarea.isEmpty()) return false; int x2 = ourarea.x()-cyourarea.x(); int y2 = ourarea.y()-cyourarea.y(); int x1 = ourarea.x()-s1area.x(); int y1 = ourarea.y()-s1area.y(); int w = ourarea.width(); int h = ourarea.height(); if (!s2image) { if (!s1image) return w>0 && h>0; // swap everything around int t; t = x1; x1 = x2; x2 = t; t = y1; x1 = y2; y2 = t; s2image = s1image; s1image = 0; } // s2image != 0 // A non-linear search may be more efficient. // Perhaps spiralling out from the center, or a simpler // vertical expansion from the centreline. // We assume that sprite masks don't have // different bit orders. // // Q_ASSERT(s1image->bitOrder() == s2image->bitOrder()); if (s1image) { if (s1image->format() == QImage::Format_MonoLSB) { for (int j = 0; j < h; j++) { uchar* ml = s1image->scanLine(y1+j); const uchar* yl = s2image->scanLine(y2+j); for (int i = 0; i < w; i++) { if (*(yl + ((x2+i) >> 3)) & (1 << ((x2+i) & 7)) && *(ml + ((x1+i) >> 3)) & (1 << ((x1+i) & 7))) { return true; } } } } else { for (int j = 0; j < h; j++) { uchar* ml = s1image->scanLine(y1+j); const uchar* yl = s2image->scanLine(y2+j); for (int i = 0; i < w; i++) { if (*(yl + ((x2+i) >> 3)) & (1 << (7-((x2+i) & 7))) && *(ml + ((x1+i) >> 3)) & (1 << (7-((x1+i) & 7)))) { return true; } } } } } else { if (s2image->format() == QImage::Format_MonoLSB) { for (int j = 0; j < h; j++) { const uchar* yl = s2image->scanLine(y2+j); for (int i = 0; i < w; i++) { if (*(yl + ((x2+i) >> 3)) & (1 << ((x2+i) & 7))) { return true; } } } } else { for (int j = 0; j< h; j++) { const uchar* yl = s2image->scanLine(y2+j); for (int i = 0; i < w; i++) { if (*(yl + ((x2+i) >> 3)) & (1 << (7-((x2+i) & 7)))) { return true; } } } } } return false; } static bool collision_double_dispatch(const QtCanvasSprite* s1, const QtCanvasPolygonalItem* p1, const QtCanvasRectangle* r1, const QtCanvasEllipse* e1, const QtCanvasText* t1, const QtCanvasSprite* s2, const QtCanvasPolygonalItem* p2, const QtCanvasRectangle* r2, const QtCanvasEllipse* e2, const QtCanvasText* t2) { const QtCanvasItem* i1 = s1 ? (const QtCanvasItem*)s1 : p1 ? (const QtCanvasItem*)p1 : r1 ? (const QtCanvasItem*)r1 : e1 ? (const QtCanvasItem*)e1 : (const QtCanvasItem*)t1; const QtCanvasItem* i2 = s2 ? (const QtCanvasItem*)s2 : p2 ? (const QtCanvasItem*)p2 : r2 ? (const QtCanvasItem*)r2 : e2 ? (const QtCanvasItem*)e2 : (const QtCanvasItem*)t2; if (s1 && s2) { // a return qt_testCollision(s1, s2); } else if ((r1 || t1 || s1) && (r2 || t2 || s2)) { // b QRect rc1 = i1->boundingRectAdvanced(); QRect rc2 = i2->boundingRectAdvanced(); return rc1.intersects(rc2); } else if (e1 && e2 && e1->angleLength()>= 360*16 && e2->angleLength()>= 360*16 && e1->width() == e1->height() && e2->width() == e2->height()) { // c double xd = (e1->x()+e1->xVelocity())-(e2->x()+e1->xVelocity()); double yd = (e1->y()+e1->yVelocity())-(e2->y()+e1->yVelocity()); double rd = (e1->width()+e2->width())/2; return xd*xd+yd*yd <= rd*rd; } else if (p1 && (p2 || s2 || t2)) { // d QPolygon pa1 = p1->areaPointsAdvanced(); QPolygon pa2 = p2 ? p2->areaPointsAdvanced() : QPolygon(i2->boundingRectAdvanced()); bool col = !(QRegion(pa1) & QRegion(pa2, Qt::WindingFill)).isEmpty(); return col; } else { return collision_double_dispatch(s2, p2, r2, e2, t2, s1, p1, r1, e1, t1); } } /* \fn bool QtCanvasItem::collidesWith(const QtCanvasItem* other) const Returns true if the canvas item will collide with the \a other item \e after they have moved by their current velocities; otherwise returns false. \sa collisions() */ /* \class QtCanvasSprite qtcanvas.h \brief The QtCanvasSprite class provides an animated canvas item on a QtCanvas. A canvas sprite is an object which can contain any number of images (referred to as frames), only one of which is current, i.e. displayed, at any one time. The images can be passed in the constructor or set or changed later with setSequence(). If you subclass QtCanvasSprite you can change the frame that is displayed periodically, e.g. whenever QtCanvasItem::advance(1) is called to create the effect of animation. The current frame can be set with setFrame() or with move(). The number of frames available is given by frameCount(). The bounding rectangle of the current frame is returned by boundingRect(). The current frame's image can be retrieved with image(); use imageAdvanced() to retrieve the image for the frame that will be shown after advance(1) is called. Use the image() overload passing it an integer index to retrieve a particular image from the list of frames. Use width() and height() to retrieve the dimensions of the current frame. Use leftEdge() and rightEdge() to retrieve the current frame's left-hand and right-hand x-coordinates respectively. Use bottomEdge() and topEdge() to retrieve the current frame's bottom and top y-coordinates respectively. These functions have an overload which will accept an integer frame number to retrieve the coordinates of a particular frame. QtCanvasSprite draws very quickly, at the expense of memory. The current frame's image can be drawn on a painter with draw(). Like any other canvas item, canvas sprites can be moved with move() which sets the x and y coordinates and the frame number, as well as with QtCanvasItem::move() and QtCanvasItem::moveBy(), or by setting coordinates with QtCanvasItem::setX(), QtCanvasItem::setY() and QtCanvasItem::setZ(). */ /* \reimp */ bool QtCanvasSprite::collidesWith(const QtCanvasItem* i) const { return i->collidesWith(this, 0, 0, 0, 0); } /* Returns true if the canvas item collides with any of the given items; otherwise returns false. The parameters, \a s, \a p, \a r, \a e and \a t, are all the same object, this is just a type resolution trick. */ bool QtCanvasSprite::collidesWith(const QtCanvasSprite* s, const QtCanvasPolygonalItem* p, const QtCanvasRectangle* r, const QtCanvasEllipse* e, const QtCanvasText* t) const { return collision_double_dispatch(s, p, r, e, t, this, 0, 0, 0, 0); } /* \reimp */ bool QtCanvasPolygonalItem::collidesWith(const QtCanvasItem* i) const { return i->collidesWith(0, this, 0, 0, 0); } bool QtCanvasPolygonalItem::collidesWith(const QtCanvasSprite* s, const QtCanvasPolygonalItem* p, const QtCanvasRectangle* r, const QtCanvasEllipse* e, const QtCanvasText* t) const { return collision_double_dispatch(s, p, r, e, t, 0, this, 0, 0, 0); } /* \reimp */ bool QtCanvasRectangle::collidesWith(const QtCanvasItem* i) const { return i->collidesWith(0, this, this, 0, 0); } bool QtCanvasRectangle::collidesWith(const QtCanvasSprite* s, const QtCanvasPolygonalItem* p, const QtCanvasRectangle* r, const QtCanvasEllipse* e, const QtCanvasText* t) const { return collision_double_dispatch(s, p, r, e, t, 0, this, this, 0, 0); } /* \reimp */ bool QtCanvasEllipse::collidesWith(const QtCanvasItem* i) const { return i->collidesWith(0,this, 0, this, 0); } bool QtCanvasEllipse::collidesWith(const QtCanvasSprite* s, const QtCanvasPolygonalItem* p, const QtCanvasRectangle* r, const QtCanvasEllipse* e, const QtCanvasText* t) const { return collision_double_dispatch(s, p, r, e, t, 0, this, 0, this, 0); } /* \reimp */ bool QtCanvasText::collidesWith(const QtCanvasItem* i) const { return i->collidesWith(0, 0, 0, 0, this); } bool QtCanvasText::collidesWith(const QtCanvasSprite* s, const QtCanvasPolygonalItem* p, const QtCanvasRectangle* r, const QtCanvasEllipse* e, const QtCanvasText* t) const { return collision_double_dispatch(s, p, r, e, t, 0, 0, 0, 0, this); } /* Returns the list of canvas items that this canvas item has collided with. A collision is generally defined as occurring when the pixels of one item draw on the pixels of another item, but not all subclasses are so precise. Also, since pixel-wise collision detection can be slow, this function works in either exact or inexact mode, according to the \a exact parameter. If \a exact is true, the canvas items returned have been accurately tested for collision with the canvas item. If \a exact is false, the canvas items returned are \e near the canvas item. You can test the canvas items returned using collidesWith() if any are interesting collision candidates. By using this approach, you can ignore some canvas items for which collisions are not relevant. The returned list is a list of QtCanvasItems, but often you will need to cast the items to their subclass types. The safe way to do this is to use rtti() before casting. This provides some of the functionality of the standard C++ dynamic cast operation even on compilers where dynamic casts are not available. Note that a canvas item may be `on' a canvas, e.g. it was created with the canvas as parameter, even though its coordinates place it beyond the edge of the canvas's area. Collision detection only works for canvas items which are wholly or partly within the canvas's area. Note that if items have a velocity (see \l setVelocity()), then collision testing is done based on where the item \e will be when it moves, not its current location. For example, a "ball" item doesn't need to actually embed into a "wall" item before a collision is detected. For items without velocity, plain intersection is used. */ QtCanvasItemList QtCanvasItem::collisions(bool exact) const { return canvas()->collisions(chunks(), this, exact); } /* Returns a list of canvas items that collide with the point \a p. The list is ordered by z coordinates, from highest z coordinate (front-most item) to lowest z coordinate (rear-most item). */ QtCanvasItemList QtCanvas::collisions(const QPoint& p) const { return collisions(QRect(p, QSize(1, 1))); } /* \overload Returns a list of items which collide with the rectangle \a r. The list is ordered by z coordinates, from highest z coordinate (front-most item) to lowest z coordinate (rear-most item). */ QtCanvasItemList QtCanvas::collisions(const QRect& r) const { QtCanvasRectangle i(r, (QtCanvas*)this); i.setPen(NoPen); i.show(); // doesn't actually show, since we destroy it QtCanvasItemList l = i.collisions(true); qSort(l.begin(), l.end(), QtCanvasItemLess()); return l; } /* \overload Returns a list of canvas items which intersect with the chunks listed in \a chunklist, excluding \a item. If \a exact is true, only those which actually \link QtCanvasItem::collidesWith() collide with\endlink \a item are returned; otherwise canvas items are included just for being in the chunks. This is a utility function mainly used to implement the simpler QtCanvasItem::collisions() function. */ QtCanvasItemList QtCanvas::collisions(const QPolygon& chunklist, const QtCanvasItem* item, bool exact) const { QSet seen; QtCanvasItemList result; for (int i = 0; i <(int)chunklist.count(); i++) { int x = chunklist[i].x(); int y = chunklist[i].y(); if (validChunk(x, y)) { const QtCanvasItemList &l = chunk(x, y).list(); for (int i = 0; i < l.size(); ++i) { QtCanvasItem *g = l.at(i); if (g != item) { if (!seen.contains(g)) { seen.insert(g); if (!exact || item->collidesWith(g)) result.append(g); } } } } } return result; } /* \internal Adds the item to all the chunks it covers. */ void QtCanvasItem::addToChunks() { if (isVisible() && canvas()) { QPolygon pa = chunks(); for (int i = 0; i < (int)pa.count(); i++) canvas()->addItemToChunk(this, pa[i].x(), pa[i].y()); val = (uint)true; } } /* \internal Removes the item from all the chunks it covers. */ void QtCanvasItem::removeFromChunks() { if (isVisible() && canvas()) { QPolygon pa = chunks(); for (int i = 0; i < (int)pa.count(); i++) canvas()->removeItemFromChunk(this, pa[i].x(), pa[i].y()); } } /* \internal Sets all the chunks covered by the item to be refreshed with QtCanvas::update() is next called. */ void QtCanvasItem::changeChunks() { if (isVisible() && canvas()) { if (!val) addToChunks(); QPolygon pa = chunks(); for (int i = 0; i < (int)pa.count(); i++) canvas()->setChangedChunk(pa[i].x(), pa[i].y()); } } /* \fn QRect QtCanvasItem::boundingRect() const Returns the bounding rectangle in pixels that the canvas item covers. \sa boundingRectAdvanced() */ /* Returns the bounding rectangle of pixels that the canvas item \e will cover after advance(1) is called. \sa boundingRect() */ QRect QtCanvasItem::boundingRectAdvanced() const { int dx = int(x()+xVelocity())-int(x()); int dy = int(y()+yVelocity())-int(y()); QRect r = boundingRect(); r.translate(dx, dy); return r; } /* \class QtCanvasPixmap qtcanvas.h \brief The QtCanvasPixmap class provides pixmaps for QtCanvasSprites. If you want to show a single pixmap on a QtCanvas use a QtCanvasSprite with just one pixmap. When pixmaps are inserted into a QtCanvasPixmapArray they are held as QtCanvasPixmaps. \l{QtCanvasSprite}s are used to show pixmaps on \l{QtCanvas}es and hold their pixmaps in a QtCanvasPixmapArray. If you retrieve a frame (pixmap) from a QtCanvasSprite it will be returned as a QtCanvasPixmap. The pixmap is a QPixmap and can only be set in the constructor. There are three different constructors, one taking a QPixmap, one a QImage and one a file name that refers to a file in any supported file format (see QImageReader). QtCanvasPixmap can have a hotspot which is defined in terms of an (x, y) offset. When you create a QtCanvasPixmap from a PNG file or from a QImage that has a QImage::offset(), the offset() is initialized appropriately, otherwise the constructor leaves it at (0, 0). You can set it later using setOffset(). When the QtCanvasPixmap is used in a QtCanvasSprite, the offset position is the point at QtCanvasItem::x() and QtCanvasItem::y(), not the top-left corner of the pixmap. Note that for QtCanvasPixmap objects created by a QtCanvasSprite, the position of each QtCanvasPixmap object is set so that the hotspot stays in the same position. \sa QtCanvasPixmapArray QtCanvasItem QtCanvasSprite */ /* Constructs a QtCanvasPixmap that uses the image stored in \a datafilename. */ QtCanvasPixmap::QtCanvasPixmap(const QString& datafilename) { QImage image(datafilename); init(image); } /* Constructs a QtCanvasPixmap from the image \a image. */ QtCanvasPixmap::QtCanvasPixmap(const QImage& image) { init(image); } /* Constructs a QtCanvasPixmap from the pixmap \a pm using the offset \a offset. */ QtCanvasPixmap::QtCanvasPixmap(const QPixmap& pm, const QPoint& offset) { init(pm, offset.x(), offset.y()); } void QtCanvasPixmap::init(const QImage& image) { this->QPixmap::operator = (QPixmap::fromImage(image)); hotx = image.offset().x(); hoty = image.offset().y(); #ifndef QT_NO_IMAGE_DITHER_TO_1 if(image.hasAlphaChannel()) { QImage i = image.createAlphaMask(); collision_mask = new QImage(i); } else #endif collision_mask = 0; } void QtCanvasPixmap::init(const QPixmap& pixmap, int hx, int hy) { (QPixmap&)*this = pixmap; hotx = hx; hoty = hy; if(pixmap.hasAlphaChannel()) { QImage i = mask().toImage(); collision_mask = new QImage(i); } else collision_mask = 0; } /* Destroys the pixmap. */ QtCanvasPixmap::~QtCanvasPixmap() { delete collision_mask; } /* \fn int QtCanvasPixmap::offsetX() const Returns the x-offset of the pixmap's hotspot. \sa setOffset() */ /* \fn int QtCanvasPixmap::offsetY() const Returns the y-offset of the pixmap's hotspot. \sa setOffset() */ /* \fn void QtCanvasPixmap::setOffset(int x, int y) Sets the offset of the pixmap's hotspot to (\a x, \a y). \warning Do not call this function if any QtCanvasSprites are currently showing this pixmap. */ /* \class QtCanvasPixmapArray qtcanvas.h \brief The QtCanvasPixmapArray class provides an array of QtCanvasPixmaps. This class is used by QtCanvasSprite to hold an array of pixmaps. It is used to implement animated sprites, i.e. images that change over time, with each pixmap in the array holding one frame. Depending on the constructor you use you can load multiple pixmaps into the array either from a directory (specifying a wildcard pattern for the files), or from a list of QPixmaps. You can also read in a set of pixmaps after construction using readPixmaps(). Individual pixmaps can be set with setImage() and retrieved with image(). The number of pixmaps in the array is returned by count(). QtCanvasSprite uses an image's mask for collision detection. You can change this by reading in a separate set of image masks using readCollisionMasks(). */ /* Constructs an invalid array (i.e. isValid() will return false). You must call readPixmaps() before being able to use this QtCanvasPixmapArray. */ QtCanvasPixmapArray::QtCanvasPixmapArray() : framecount(0), img(0) { } /* Constructs a QtCanvasPixmapArray from files. The \a fc parameter sets the number of frames to be loaded for this image. If \a fc is not 0, \a datafilenamepattern should contain "%1", e.g. "foo%1.png". The actual filenames are formed by replacing the %1 with four-digit integers from 0 to (fc - 1), e.g. foo0000.png, foo0001.png, foo0002.png, etc. If \a fc is 0, \a datafilenamepattern is asssumed to be a filename, and the image contained in this file will be loaded as the first (and only) frame. If \a datafilenamepattern does not exist, is not readable, isn't an image, or some other error occurs, the array ends up empty and isValid() returns false. */ QtCanvasPixmapArray::QtCanvasPixmapArray(const QString& datafilenamepattern, int fc) : framecount(0), img(0) { readPixmaps(datafilenamepattern, fc); } /* \obsolete Use QtCanvasPixmapArray::QtCanvasPixmapArray(QtValueList, QPolygon) instead. Constructs a QtCanvasPixmapArray from the list of QPixmaps \a list. The \a hotspots list has to be of the same size as \a list. */ QtCanvasPixmapArray::QtCanvasPixmapArray(const QList &list, const QPolygon &hotspots) : framecount(list.count()), img(new QtCanvasPixmap*[list.count()]) { if (list.count() != hotspots.count()) { qWarning("QtCanvasPixmapArray: lists have different lengths"); reset(); img = 0; } else { for (int i = 0; i < framecount; i++) img[i] = new QtCanvasPixmap(list.at(i), hotspots.at(i)); } } /* Destroys the pixmap array and all the pixmaps it contains. */ QtCanvasPixmapArray::~QtCanvasPixmapArray() { reset(); } void QtCanvasPixmapArray::reset() { for (int i = 0; i < framecount; i++) delete img[i]; delete [] img; img = 0; framecount = 0; } /* Reads one or more pixmaps into the pixmap array. If \a fc is not 0, \a filenamepattern should contain "%1", e.g. "foo%1.png". The actual filenames are formed by replacing the %1 with four-digit integers from 0 to (fc - 1), e.g. foo0000.png, foo0001.png, foo0002.png, etc. If \a fc is 0, \a filenamepattern is asssumed to be a filename, and the image contained in this file will be loaded as the first (and only) frame. If \a filenamepattern does not exist, is not readable, isn't an image, or some other error occurs, this function will return false, and isValid() will return false; otherwise this function will return true. \sa isValid() */ bool QtCanvasPixmapArray::readPixmaps(const QString& filenamepattern, int fc) { return readPixmaps(filenamepattern, fc, false); } /* Reads new collision masks for the array. By default, QtCanvasSprite uses the image mask of a sprite to detect collisions. Use this function to set your own collision image masks. If count() is 1 \a filename must specify a real filename to read the mask from. If count() is greater than 1, the \a filename must contain a "%1" that will get replaced by the number of the mask to be loaded, just like QtCanvasPixmapArray::readPixmaps(). All collision masks must be 1-bit images or this function call will fail. If the file isn't readable, contains the wrong number of images, or there is some other error, this function will return false, and the array will be flagged as invalid; otherwise this function returns true. \sa isValid() */ bool QtCanvasPixmapArray::readCollisionMasks(const QString& filename) { return readPixmaps(filename, framecount, true); } bool QtCanvasPixmapArray::readPixmaps(const QString& datafilenamepattern, int fc, bool maskonly) { if (!maskonly) { reset(); framecount = fc; if (!framecount) framecount = 1; img = new QtCanvasPixmap*[framecount]; } if (!img) return false; bool ok = true; bool arg = fc > 1; if (!arg) framecount = 1; for (int i = 0; i < framecount; i++) { QString r; r.sprintf("%04d", i); if (maskonly) { if (!img[i]->collision_mask) img[i]->collision_mask = new QImage(); img[i]->collision_mask->load( arg ? datafilenamepattern.arg(r) : datafilenamepattern); ok = ok && !img[i]->collision_mask->isNull() && img[i]->collision_mask->depth() == 1; } else { img[i] = new QtCanvasPixmap( arg ? datafilenamepattern.arg(r) : datafilenamepattern); ok = ok && !img[i]->isNull(); } } if (!ok) { reset(); } return ok; } /* \obsolete Use isValid() instead. This returns false if the array is valid, and true if it is not. */ bool QtCanvasPixmapArray::operator!() { return img == 0; } /* Returns true if the pixmap array is valid; otherwise returns false. */ bool QtCanvasPixmapArray::isValid() const { return (img != 0); } /* \fn QtCanvasPixmap* QtCanvasPixmapArray::image(int i) const Returns pixmap \a i in the array, if \a i is non-negative and less than than count(), and returns an unspecified value otherwise. */ // ### wouldn't it be better to put empty QtCanvasPixmaps in there instead of // initializing the additional elements in the array to 0? Lars /* Replaces the pixmap at index \a i with pixmap \a p. The array takes ownership of \a p and will delete \a p when the array itself is deleted. If \a i is beyond the end of the array the array is extended to at least i+1 elements, with elements count() to i-1 being initialized to 0. */ void QtCanvasPixmapArray::setImage(int i, QtCanvasPixmap* p) { if (i >= framecount) { QtCanvasPixmap** newimg = new QtCanvasPixmap*[i+1]; memcpy(newimg, img, sizeof(QtCanvasPixmap *)*framecount); memset(newimg + framecount, 0, sizeof(QtCanvasPixmap *)*(i+1 - framecount)); framecount = i+1; delete [] img; img = newimg; } delete img[i]; img[i] = p; } /* \fn uint QtCanvasPixmapArray::count() const Returns the number of pixmaps in the array. */ /* Returns the x-coordinate of the current left edge of the sprite. (This may change as the sprite animates since different frames may have different left edges.) \sa rightEdge() bottomEdge() topEdge() */ int QtCanvasSprite::leftEdge() const { return int(x()) - image()->hotx; } /* \overload Returns what the x-coordinate of the left edge of the sprite would be if the sprite (actually its hotspot) were moved to x-position \a nx. \sa rightEdge() bottomEdge() topEdge() */ int QtCanvasSprite::leftEdge(int nx) const { return nx - image()->hotx; } /* Returns the y-coordinate of the top edge of the sprite. (This may change as the sprite animates since different frames may have different top edges.) \sa leftEdge() rightEdge() bottomEdge() */ int QtCanvasSprite::topEdge() const { return int(y()) - image()->hoty; } /* \overload Returns what the y-coordinate of the top edge of the sprite would be if the sprite (actually its hotspot) were moved to y-position \a ny. \sa leftEdge() rightEdge() bottomEdge() */ int QtCanvasSprite::topEdge(int ny) const { return ny - image()->hoty; } /* Returns the x-coordinate of the current right edge of the sprite. (This may change as the sprite animates since different frames may have different right edges.) \sa leftEdge() bottomEdge() topEdge() */ int QtCanvasSprite::rightEdge() const { return leftEdge() + image()->width()-1; } /* \overload Returns what the x-coordinate of the right edge of the sprite would be if the sprite (actually its hotspot) were moved to x-position \a nx. \sa leftEdge() bottomEdge() topEdge() */ int QtCanvasSprite::rightEdge(int nx) const { return leftEdge(nx) + image()->width()-1; } /* Returns the y-coordinate of the current bottom edge of the sprite. (This may change as the sprite animates since different frames may have different bottom edges.) \sa leftEdge() rightEdge() topEdge() */ int QtCanvasSprite::bottomEdge() const { return topEdge() + image()->height()-1; } /* \overload Returns what the y-coordinate of the top edge of the sprite would be if the sprite (actually its hotspot) were moved to y-position \a ny. \sa leftEdge() rightEdge() topEdge() */ int QtCanvasSprite::bottomEdge(int ny) const { return topEdge(ny) + image()->height()-1; } /* \fn QtCanvasPixmap* QtCanvasSprite::image() const Returns the current frame's image. \sa frame(), setFrame() */ /* \fn QtCanvasPixmap* QtCanvasSprite::image(int f) const \overload Returns the image for frame \a f. Does not do any bounds checking on \a f. */ /* Returns the image the sprite \e will have after advance(1) is called. By default this is the same as image(). */ QtCanvasPixmap* QtCanvasSprite::imageAdvanced() const { return image(); } /* Returns the bounding rectangle for the image in the sprite's current frame. This assumes that the images are tightly cropped (i.e. do not have transparent pixels all along a side). */ QRect QtCanvasSprite::boundingRect() const { return QRect(leftEdge(), topEdge(), width(), height()); } /* \internal Returns the chunks covered by the item. */ QPolygon QtCanvasItem::chunks() const { QPolygon r; int n = 0; QRect br = boundingRect(); if (isVisible() && canvas()) { int chunksize = canvas()->chunkSize(); br &= QRect(0, 0, canvas()->width(), canvas()->height()); if (br.isValid()) { r.resize((br.width()/chunksize+2)*(br.height()/chunksize+2)); for (int j = br.top()/chunksize; j <= br.bottom()/chunksize; j++) { for (int i = br.left()/chunksize; i <= br.right()/chunksize; i++) { r[n++] = QPoint(i, j); } } } } r.resize(n); return r; } /* \internal Add the sprite to the chunks in its QtCanvas which it overlaps. */ void QtCanvasSprite::addToChunks() { if (isVisible() && canvas()) { int chunksize = canvas()->chunkSize(); for (int j = topEdge()/chunksize; j <= bottomEdge()/chunksize; j++) { for (int i = leftEdge()/chunksize; i <= rightEdge()/chunksize; i++) { canvas()->addItemToChunk(this, i, j); } } } } /* \internal Remove the sprite from the chunks in its QtCanvas which it overlaps. \sa addToChunks() */ void QtCanvasSprite::removeFromChunks() { if (isVisible() && canvas()) { int chunksize = canvas()->chunkSize(); for (int j = topEdge()/chunksize; j <= bottomEdge()/chunksize; j++) { for (int i = leftEdge()/chunksize; i <= rightEdge()/chunksize; i++) { canvas()->removeItemFromChunk(this, i, j); } } } } /* The width of the sprite for the current frame's image. \sa frame() */ //### mark: Why don't we have width(int) and height(int) to be //consistent with leftEdge() and leftEdge(int)? int QtCanvasSprite::width() const { return image()->width(); } /* The height of the sprite for the current frame's image. \sa frame() */ int QtCanvasSprite::height() const { return image()->height(); } /* Draws the current frame's image at the sprite's current position on painter \a painter. */ void QtCanvasSprite::draw(QPainter& painter) { painter.drawPixmap(leftEdge(), topEdge(), *image()); } /* \class QtCanvasView qtcanvas.h \brief The QtCanvasView class provides an on-screen view of a QtCanvas. A QtCanvasView is widget which provides a view of a QtCanvas. If you want users to be able to interact with a canvas view, subclass QtCanvasView. You might then reimplement QtScrollView::contentsMousePressEvent(). For example: \code void MyCanvasView::contentsMousePressEvent(QMouseEvent* e) { QtCanvasItemList l = canvas()->collisions(e->pos()); for (QtCanvasItemList::Iterator it = l.begin(); it!= l.end(); ++it) { if ((*it)->rtti() == QtCanvasRectangle::RTTI) qDebug("A QtCanvasRectangle lies somewhere at this point"); } } \endcode The canvas view shows canvas canvas(); this can be changed using setCanvas(). A transformation matrix can be used to transform the view of the canvas in various ways, for example, zooming in or out or rotating. For example: \code QMatrix wm; wm.scale(2, 2); // Zooms in by 2 times wm.rotate(90); // Rotates 90 degrees counter clockwise // around the origin. wm.translate(0, -canvas->height()); // moves the canvas down so what was visible // before is still visible. myCanvasView->setWorldMatrix(wm); \endcode Use setWorldMatrix() to set the canvas view's world matrix: you must ensure that the world matrix is invertible. The current world matrix is retrievable with worldMatrix(), and its inversion is retrievable with inverseWorldMatrix(). Example: The following code finds the part of the canvas that is visible in this view, i.e. the bounding rectangle of the view in canvas coordinates. \code QRect rc = QRect(myCanvasView->contentsX(), myCanvasView->contentsY(), myCanvasView->visibleWidth(), myCanvasView->visibleHeight()); QRect canvasRect = myCanvasView->inverseWorldMatrix().mapRect(rc); \endcode \sa QMatrix QPainter::setWorldMatrix() */ class QtCanvasWidget : public QWidget { public: QtCanvasWidget(QtCanvasView *view) : QWidget(view) { m_view = view; } protected: void paintEvent(QPaintEvent *e); void mousePressEvent(QMouseEvent *e) { m_view->contentsMousePressEvent(e); } void mouseMoveEvent(QMouseEvent *e) { m_view->contentsMouseMoveEvent(e); } void mouseReleaseEvent(QMouseEvent *e) { m_view->contentsMouseReleaseEvent(e); } void mouseDoubleClickEvent(QMouseEvent *e) { m_view->contentsMouseDoubleClickEvent(e); } void dragEnterEvent(QDragEnterEvent *e) { m_view->contentsDragEnterEvent(e); } void dragMoveEvent(QDragMoveEvent *e) { m_view->contentsDragMoveEvent(e); } void dragLeaveEvent(QDragLeaveEvent *e) { m_view->contentsDragLeaveEvent(e); } void dropEvent(QDropEvent *e) { m_view->contentsDropEvent(e); } void wheelEvent(QWheelEvent *e) { m_view->contentsWheelEvent(e); } void contextMenuEvent(QContextMenuEvent *e) { m_view->contentsContextMenuEvent(e); } QtCanvasView *m_view; }; void QtCanvasWidget::paintEvent(QPaintEvent *e) { QPainter p(this); if (m_view->d->highQuality) { p.setRenderHint(QPainter::Antialiasing); p.setRenderHint(QPainter::SmoothPixmapTransform); } m_view->drawContents(&p, e->rect().x(), e->rect().y(), e->rect().width(), e->rect().height()); } /* Constructs a QtCanvasView with parent \a parent. The canvas view is not associated with a canvas, so you must to call setCanvas() to view a canvas. */ QtCanvasView::QtCanvasView(QWidget* parent) : QScrollArea(parent) { d = new QtCanvasViewData; setWidget(new QtCanvasWidget(this)); d->highQuality = false; viewing = 0; setCanvas(0); } /* \overload Constructs a QtCanvasView which views canvas \a canvas, with parent \a parent. */ QtCanvasView::QtCanvasView(QtCanvas* canvas, QWidget* parent) : QScrollArea(parent) { d = new QtCanvasViewData; d->highQuality = false; setWidget(new QtCanvasWidget(this)); viewing = 0; setCanvas(canvas); } /* Destroys the canvas view. The associated canvas is \e not deleted. */ QtCanvasView::~QtCanvasView() { delete d; d = 0; setCanvas(0); } /* \property QtCanvasView::highQualityRendering \brief whether high quality rendering is turned on If high quality rendering is turned on, the canvas view will paint itself using the QPainter::Antialiasing and QPainter::SmoothPixmapTransform rendering flags. Enabling these flag will usually improve the visual appearance on the screen at the cost of rendering speed. */ bool QtCanvasView::highQualityRendering() const { return d->highQuality; } void QtCanvasView::setHighQualityRendering(bool enable) { d->highQuality = enable; widget()->update(); } void QtCanvasView::contentsMousePressEvent(QMouseEvent *e) { e->ignore(); } void QtCanvasView::contentsMouseReleaseEvent(QMouseEvent *e) { e->ignore(); } void QtCanvasView::contentsMouseDoubleClickEvent(QMouseEvent *e) { e->ignore(); } void QtCanvasView::contentsMouseMoveEvent(QMouseEvent *e) { e->ignore(); } void QtCanvasView::contentsDragEnterEvent(QDragEnterEvent *) { } void QtCanvasView::contentsDragMoveEvent(QDragMoveEvent *) { } void QtCanvasView::contentsDragLeaveEvent(QDragLeaveEvent *) { } void QtCanvasView::contentsDropEvent(QDropEvent *) { } void QtCanvasView::contentsWheelEvent(QWheelEvent *e) { e->ignore(); } void QtCanvasView::contentsContextMenuEvent(QContextMenuEvent *e) { e->ignore(); } /* \fn QtCanvas* QtCanvasView::canvas() const Returns a pointer to the canvas which the QtCanvasView is currently showing. */ /* Sets the canvas that the QtCanvasView is showing to the canvas \a canvas. */ void QtCanvasView::setCanvas(QtCanvas* canvas) { if (viewing == canvas) return; if (viewing) { disconnect(viewing); viewing->removeView(this); } viewing = canvas; if (viewing) { connect(viewing, SIGNAL(resized()), this, SLOT(updateContentsSize())); viewing->addView(this); } if (d) // called by d'tor updateContentsSize(); update(); } /* Returns a reference to the canvas view's current transformation matrix. \sa setWorldMatrix() inverseWorldMatrix() */ const QMatrix &QtCanvasView::worldMatrix() const { return d->xform; } /* Returns a reference to the inverse of the canvas view's current transformation matrix. \sa setWorldMatrix() worldMatrix() */ const QMatrix &QtCanvasView::inverseWorldMatrix() const { return d->ixform; } /* Sets the transformation matrix of the QtCanvasView to \a wm. The matrix must be invertible (i.e. if you create a world matrix that zooms out by 2 times, then the inverse of this matrix is one that will zoom in by 2 times). When you use this, you should note that the performance of the QtCanvasView will decrease considerably. Returns false if \a wm is not invertable; otherwise returns true. \sa worldMatrix() inverseWorldMatrix() QMatrix::isInvertible() */ bool QtCanvasView::setWorldMatrix(const QMatrix & wm) { bool ok = wm.isInvertible(); if (ok) { d->xform = wm; d->ixform = wm.inverted(); updateContentsSize(); widget()->update(); } return ok; } void QtCanvasView::updateContentsSize() { if (viewing) { QRect br; br = d->xform.mapRect(QRect(0, 0, viewing->width(), viewing->height())); widget()->resize(br.size()); } else { widget()->resize(size()); } } /* Repaints part of the QtCanvas that the canvas view is showing starting at \a cx by \a cy, with a width of \a cw and a height of \a ch using the painter \a p. */ void QtCanvasView::drawContents(QPainter *p, int cx, int cy, int cw, int ch) { if (!viewing) return; QPainterPath clipPath; clipPath.addRect(viewing->rect()); p->setClipPath(d->xform.map(clipPath), Qt::IntersectClip); viewing->drawViewArea(this, p, QRect(cx, cy, cw, ch), false); } /* Suggests a size sufficient to view the entire canvas. */ QSize QtCanvasView::sizeHint() const { if (!canvas()) return QScrollArea::sizeHint(); // should maybe take transformations into account return (canvas()->size() + 2 * QSize(frameWidth(), frameWidth())) .boundedTo(3 * QApplication::desktop()->size() / 4); } /* \class QtCanvasPolygonalItem qtcanvas.h \brief The QtCanvasPolygonalItem class provides a polygonal canvas item on a QtCanvas. The mostly rectangular classes, such as QtCanvasSprite and QtCanvasText, use the object's bounding rectangle for movement, repainting and collision calculations. For most other items, the bounding rectangle can be far too large -- a diagonal line being the worst case, and there are many other cases which are also bad. QtCanvasPolygonalItem provides polygon-based bounding rectangle handling, etc., which is much faster for non-rectangular items. Derived classes should try to define as small an area as possible to maximize efficiency, but the polygon must \e definitely be contained completely within the polygonal area. Calculating the exact requirements is usually difficult, but if you allow a small overestimate it can be easy and quick, while still getting almost all of QtCanvasPolygonalItem's speed. Note that all subclasses \e must call hide() in their destructor since hide() needs to be able to access areaPoints(). Normally, QtCanvasPolygonalItem uses the odd-even algorithm for determining whether an object intersects this object. You can change this to the winding algorithm using setWinding(). The bounding rectangle is available using boundingRect(). The points bounding the polygonal item are retrieved with areaPoints(). Use areaPointsAdvanced() to retrieve the bounding points the polygonal item \e will have after QtCanvasItem::advance(1) has been called. If the shape of the polygonal item is about to change while the item is visible, call invalidate() before updating with a different result from \l areaPoints(). By default, QtCanvasPolygonalItem objects have a black pen and no brush (the default QPen and QBrush constructors). You can change this with setPen() and setBrush(), but note that some QtCanvasPolygonalItem subclasses only use the brush, ignoring the pen setting. The polygonal item can be drawn on a painter with draw(). Subclasses must reimplement drawShape() to draw themselves. Like any other canvas item polygonal items can be moved with QtCanvasItem::move() and QtCanvasItem::moveBy(), or by setting coordinates with QtCanvasItem::setX(), QtCanvasItem::setY() and QtCanvasItem::setZ(). */ /* Since most polygonal items don't have a pen, the default is NoPen and a black brush. */ static const QPen& defaultPolygonPen() { static QPen* dp = 0; if (!dp) dp = new QPen; return *dp; } static const QBrush& defaultPolygonBrush() { static QBrush* db = 0; if (!db) db = new QBrush; return *db; } /* Constructs a QtCanvasPolygonalItem on the canvas \a canvas. */ QtCanvasPolygonalItem::QtCanvasPolygonalItem(QtCanvas* canvas) : QtCanvasItem(canvas), br(defaultPolygonBrush()), pn(defaultPolygonPen()) { wind = 0; } /* Note that all subclasses \e must call hide() in their destructor since hide() needs to be able to access areaPoints(). */ QtCanvasPolygonalItem::~QtCanvasPolygonalItem() { } /* Returns true if the polygonal item uses the winding algorithm to determine the "inside" of the polygon. Returns false if it uses the odd-even algorithm. The default is to use the odd-even algorithm. \sa setWinding() */ bool QtCanvasPolygonalItem::winding() const { return wind; } /* If \a enable is true, the polygonal item will use the winding algorithm to determine the "inside" of the polygon; otherwise the odd-even algorithm will be used. The default is to use the odd-even algorithm. \sa winding() */ void QtCanvasPolygonalItem::setWinding(bool enable) { wind = enable; } /* Invalidates all information about the area covered by the canvas item. The item will be updated automatically on the next call that changes the item's status, for example, move() or update(). Call this function if you are going to change the shape of the item (as returned by areaPoints()) while the item is visible. */ void QtCanvasPolygonalItem::invalidate() { val = (uint)false; removeFromChunks(); } /* \fn QtCanvasPolygonalItem::isValid() const Returns true if the polygonal item's area information has not been invalidated; otherwise returns false. \sa invalidate() */ /* Returns the points the polygonal item \e will have after QtCanvasItem::advance(1) is called, i.e. what the points are when advanced by the current xVelocity() and yVelocity(). */ QPolygon QtCanvasPolygonalItem::areaPointsAdvanced() const { int dx = int(x()+xVelocity())-int(x()); int dy = int(y()+yVelocity())-int(y()); QPolygon r = areaPoints(); r.detach(); // Explicit sharing is stupid. if (dx || dy) r.translate(dx, dy); return r; } //#define QCANVAS_POLYGONS_DEBUG #ifdef QCANVAS_POLYGONS_DEBUG static QWidget* dbg_wid = 0; static QPainter* dbg_ptr = 0; #endif class QPolygonalProcessor { public: QPolygonalProcessor(QtCanvas* c, const QPolygon& pa) : canvas(c) { QRect pixelbounds = pa.boundingRect(); int cs = canvas->chunkSize(); QRect canvasbounds = pixelbounds.intersected(canvas->rect()); bounds.setLeft(canvasbounds.left()/cs); bounds.setRight(canvasbounds.right()/cs); bounds.setTop(canvasbounds.top()/cs); bounds.setBottom(canvasbounds.bottom()/cs); bitmap = QImage(bounds.width(), bounds.height(), QImage::Format_MonoLSB); pnt = 0; bitmap.fill(0); #ifdef QCANVAS_POLYGONS_DEBUG dbg_start(); #endif } inline void add(int x, int y) { if (pnt >= (int)result.size()) { result.resize(pnt*2+10); } result[pnt++] = QPoint(x+bounds.x(), y+bounds.y()); #ifdef QCANVAS_POLYGONS_DEBUG if (dbg_ptr) { int cs = canvas->chunkSize(); QRect r(x*cs+bounds.x()*cs, y*cs+bounds.y()*cs, cs-1, cs-1); dbg_ptr->setPen(Qt::blue); dbg_ptr->drawRect(r); } #endif } inline void addBits(int x1, int x2, uchar newbits, int xo, int yo) { for (int i = x1; i <= x2; i++) if (newbits & (1 <resize(800, 600); dbg_wid->show(); dbg_ptr = new QPainter(dbg_wid); dbg_ptr->setBrush(Qt::NoBrush); } dbg_ptr->fillRect(dbg_wid->rect(), Qt::white); } #endif void doSpans(int n, QPoint* pt, int* w) { int cs = canvas->chunkSize(); for (int j = 0; j < n; j++) { int y = pt[j].y()/cs-bounds.y(); if (y >= bitmap.height() || y < 0) continue; uchar* l = bitmap.scanLine(y); int x = pt[j].x(); int x1 = x/cs-bounds.x(); if (x1 > bounds.width()) continue; x1 = qMax(0,x1); int x2 = (x+w[j])/cs-bounds.x(); if (x2 < 0) continue; x2 = qMin(bounds.width(), x2); int x1q = x1/8; int x1r = x1%8; int x2q = x2/8; int x2r = x2%8; #ifdef QCANVAS_POLYGONS_DEBUG if (dbg_ptr) dbg_ptr->setPen(Qt::yellow); #endif if (x1q == x2q) { uchar newbits = (~l[x1q]) & (((2 <<(x2r-x1r))-1) <setPen(Qt::darkGreen); #endif addBits(x1r, x2r, newbits, x1q*8, y); l[x1q] |= newbits; } } else { #ifdef QCANVAS_POLYGONS_DEBUG if (dbg_ptr) dbg_ptr->setPen(Qt::blue); #endif uchar newbits1 = (~l[x1q]) & (0xff <setPen(Qt::green); #endif addBits(x1r, 7, newbits1, x1q*8, y); l[x1q] |= newbits1; } for (int i = x1q+1; i < x2q; i++) { if (l[i] != 0xff) { addBits(0, 7, ~l[i], i*8, y); l[i] = 0xff; } } uchar newbits2 = (~l[x2q]) & (0xff>>(7-x2r)); if (newbits2) { #ifdef QCANVAS_POLYGONS_DEBUG if (dbg_ptr) dbg_ptr->setPen(Qt::red); #endif addBits(0, x2r, newbits2, x2q*8, y); l[x2q] |= newbits2; } } #ifdef QCANVAS_POLYGONS_DEBUG if (dbg_ptr) { dbg_ptr->drawLine(pt[j], pt[j]+QPoint(w[j], 0)); } #endif } result.resize(pnt); } int pnt; QPolygon result; QtCanvas* canvas; QRect bounds; QImage bitmap; }; QPolygon QtCanvasPolygonalItem::chunks() const { QPolygon pa = areaPoints(); if (!pa.size()) { pa.detach(); // Explicit sharing is stupid. return pa; } QPolygonalProcessor processor(canvas(), pa); scanPolygon(pa, wind, processor); return processor.result; } /* Simply calls QtCanvasItem::chunks(). */ QPolygon QtCanvasRectangle::chunks() const { // No need to do a polygon scan! return QtCanvasItem::chunks(); } /* Returns the bounding rectangle of the polygonal item, based on areaPoints(). */ QRect QtCanvasPolygonalItem::boundingRect() const { return areaPoints().boundingRect(); } /* Reimplemented from QtCanvasItem, this draws the polygonal item by setting the pen and brush for the item on the painter \a p and calling drawShape(). */ void QtCanvasPolygonalItem::draw(QPainter & p) { p.setPen(pn); p.setBrush(br); drawShape(p); } /* \fn void QtCanvasPolygonalItem::drawShape(QPainter & p) Subclasses must reimplement this function to draw their shape. The pen and brush of \a p are already set to pen() and brush() prior to calling this function. \sa draw() */ /* \fn QPen QtCanvasPolygonalItem::pen() const Returns the QPen used to draw the outline of the item, if any. \sa setPen() */ /* \fn QBrush QtCanvasPolygonalItem::brush() const Returns the QBrush used to fill the item, if filled. \sa setBrush() */ /* Sets the QPen used when drawing the item to the pen \a p. Note that many QtCanvasPolygonalItems do not use the pen value. \sa setBrush(), pen(), drawShape() */ void QtCanvasPolygonalItem::setPen(QPen p) { if (pn != p) { removeFromChunks(); pn = p; addToChunks(); } } /* Sets the QBrush used when drawing the polygonal item to the brush \a b. \sa setPen(), brush(), drawShape() */ void QtCanvasPolygonalItem::setBrush(QBrush b) { if (br != b) { br = b; changeChunks(); } } /* \class QtCanvasPolygon qtcanvas.h \brief The QtCanvasPolygon class provides a polygon on a QtCanvas. Paints a polygon with a QBrush. The polygon's points can be set in the constructor or set or changed later using setPoints(). Use points() to retrieve the points, or areaPoints() to retrieve the points relative to the canvas's origin. The polygon can be drawn on a painter with drawShape(). Like any other canvas item polygons can be moved with QtCanvasItem::move() and QtCanvasItem::moveBy(), or by setting coordinates with QtCanvasItem::setX(), QtCanvasItem::setY() and QtCanvasItem::setZ(). Note: QtCanvasPolygon does not use the pen. */ /* Constructs a point-less polygon on the canvas \a canvas. You should call setPoints() before using it further. */ QtCanvasPolygon::QtCanvasPolygon(QtCanvas* canvas) : QtCanvasPolygonalItem(canvas) { } /* Destroys the polygon. */ QtCanvasPolygon::~QtCanvasPolygon() { hide(); } /* Draws the polygon using the painter \a p. Note that QtCanvasPolygon does not support an outline (the pen is always NoPen). */ void QtCanvasPolygon::drawShape(QPainter & p) { // ### why can't we draw outlines? We could use drawPolyline for it. Lars // ### see other message. Warwick p.setPen(NoPen); // since QRegion(QPolygon) excludes outline :-()-: p.drawPolygon(poly); } /* Sets the points of the polygon to be \a pa. These points will have their x and y coordinates automatically translated by x(), y() as the polygon is moved. */ void QtCanvasPolygon::setPoints(QPolygon pa) { removeFromChunks(); poly = pa; poly.detach(); // Explicit sharing is stupid. poly.translate((int)x(), (int)y()); addToChunks(); } /* \reimp */ void QtCanvasPolygon::moveBy(double dx, double dy) { // Note: does NOT call QtCanvasPolygonalItem::moveBy(), since that // only does half this work. // int idx = int(x()+dx)-int(x()); int idy = int(y()+dy)-int(y()); if (idx || idy) { removeFromChunks(); poly.translate(idx, idy); } myx+= dx; myy+= dy; if (idx || idy) { addToChunks(); } } /* \class QtCanvasSpline qtcanvas.h \brief The QtCanvasSpline class provides multi-bezier splines on a QtCanvas. A QtCanvasSpline is a sequence of 4-point bezier curves joined together to make a curved shape. You set the control points of the spline with setControlPoints(). If the bezier is closed(), then the first control point will be re-used as the last control point. Therefore, a closed bezier must have a multiple of 3 control points and an open bezier must have one extra point. The beziers are not necessarily joined "smoothly". To ensure this, set control points appropriately (general reference texts about beziers will explain this in detail). Like any other canvas item splines can be moved with QtCanvasItem::move() and QtCanvasItem::moveBy(), or by setting coordinates with QtCanvasItem::setX(), QtCanvasItem::setY() and QtCanvasItem::setZ(). */ /* Create a spline with no control points on the canvas \a canvas. \sa setControlPoints() */ QtCanvasSpline::QtCanvasSpline(QtCanvas* canvas) : QtCanvasPolygon(canvas), cl(true) { } /* Destroy the spline. */ QtCanvasSpline::~QtCanvasSpline() { } /* Set the spline control points to \a ctrl. If \a close is true, then the first point in \a ctrl will be re-used as the last point, and the number of control points must be a multiple of 3. If \a close is false, one additional control point is required, and the number of control points must be one of (4, 7, 10, 13, ...). If the number of control points doesn't meet the above conditions, the number of points will be truncated to the largest number of points that do meet the requirement. */ void QtCanvasSpline::setControlPoints(QPolygon ctrl, bool close) { if ((int)ctrl.count() % 3 != (close ? 0 : 1)) { qWarning("QtCanvasSpline::setControlPoints(): Number of points doesn't fit."); int numCurves = (ctrl.count() - (close ? 0 : 1))/ 3; ctrl.resize(numCurves*3 + (close ? 0 : 1)); } cl = close; bez = ctrl; recalcPoly(); } /* Returns the current set of control points. \sa setControlPoints(), closed() */ QPolygon QtCanvasSpline::controlPoints() const { return bez; } /* Returns true if the control points are a closed set; otherwise returns false. */ bool QtCanvasSpline::closed() const { return cl; } void QtCanvasSpline::recalcPoly() { if (bez.count() == 0) return; QPainterPath path; path.moveTo(bez[0]); for (int i = 1; i < (int)bez.count()-1; i+= 3) { path.cubicTo(bez[i], bez[i+1], cl ? bez[(i+2)%bez.size()] : bez[i+2]); } QPolygon p = path.toFillPolygon().toPolygon(); QtCanvasPolygon::setPoints(p); } /* \fn QPolygon QtCanvasPolygonalItem::areaPoints() const This function must be reimplemented by subclasses. It \e must return the points bounding (i.e. outside and not touching) the shape or drawing errors will occur. */ /* \fn QPolygon QtCanvasPolygon::points() const Returns the vertices of the polygon, not translated by the position. \sa setPoints(), areaPoints() */ QPolygon QtCanvasPolygon::points() const { QPolygon pa = areaPoints(); pa.translate(int(-x()), int(-y())); return pa; } /* Returns the vertices of the polygon translated by the polygon's current x(), y() position, i.e. relative to the canvas's origin. \sa setPoints(), points() */ QPolygon QtCanvasPolygon::areaPoints() const { return poly; } /* \class QtCanvasLine qtcanvas.h \brief The QtCanvasLine class provides a line on a QtCanvas. The line inherits functionality from QtCanvasPolygonalItem, for example the setPen() function. The start and end points of the line are set with setPoints(). Like any other canvas item lines can be moved with QtCanvasItem::move() and QtCanvasItem::moveBy(), or by setting coordinates with QtCanvasItem::setX(), QtCanvasItem::setY() and QtCanvasItem::setZ(). */ /* Constructs a line from (0, 0) to (0, 0) on \a canvas. \sa setPoints() */ QtCanvasLine::QtCanvasLine(QtCanvas* canvas) : QtCanvasPolygonalItem(canvas) { x1 = y1 = x2 = y2 = 0; } /* Destroys the line. */ QtCanvasLine::~QtCanvasLine() { hide(); } /* \reimp */ void QtCanvasLine::setPen(QPen p) { QtCanvasPolygonalItem::setPen(p); } /* \fn QPoint QtCanvasLine::startPoint () const Returns the start point of the line. \sa setPoints(), endPoint() */ /* \fn QPoint QtCanvasLine::endPoint () const Returns the end point of the line. \sa setPoints(), startPoint() */ /* Sets the line's start point to (\a xa, \a ya) and its end point to (\a xb, \a yb). */ void QtCanvasLine::setPoints(int xa, int ya, int xb, int yb) { if (x1 != xa || x2 != xb || y1 != ya || y2 != yb) { removeFromChunks(); x1 = xa; y1 = ya; x2 = xb; y2 = yb; addToChunks(); } } /* \reimp */ void QtCanvasLine::drawShape(QPainter &p) { p.drawLine((int)(x()+x1), (int)(y()+y1), (int)(x()+x2), (int)(y()+y2)); } /* \reimp Note that the area defined by the line is somewhat thicker than the line that is actually drawn. */ QPolygon QtCanvasLine::areaPoints() const { QPolygon p(4); int xi = int(x()); int yi = int(y()); int pw = pen().width(); int dx = qAbs(x1-x2); int dy = qAbs(y1-y2); pw = pw*4/3+2; // approx pw*sqrt(2) int px = x1 < x2 ? -pw : pw ; int py = y1 < y2 ? -pw : pw ; if (dx && dy && (dx > dy ? (dx*2/dy <= 2) : (dy*2/dx <= 2))) { // steep if (px == py) { p[0] = QPoint(x1+xi, y1+yi+py); p[1] = QPoint(x2+xi-px, y2+yi); p[2] = QPoint(x2+xi, y2+yi-py); p[3] = QPoint(x1+xi+px, y1+yi); } else { p[0] = QPoint(x1+xi+px, y1+yi); p[1] = QPoint(x2+xi, y2+yi-py); p[2] = QPoint(x2+xi-px, y2+yi); p[3] = QPoint(x1+xi, y1+yi+py); } } else if (dx > dy) { // horizontal p[0] = QPoint(x1+xi+px, y1+yi+py); p[1] = QPoint(x2+xi-px, y2+yi+py); p[2] = QPoint(x2+xi-px, y2+yi-py); p[3] = QPoint(x1+xi+px, y1+yi-py); } else { // vertical p[0] = QPoint(x1+xi+px, y1+yi+py); p[1] = QPoint(x2+xi+px, y2+yi-py); p[2] = QPoint(x2+xi-px, y2+yi-py); p[3] = QPoint(x1+xi-px, y1+yi+py); } return p; } /* \reimp */ void QtCanvasLine::moveBy(double dx, double dy) { QtCanvasPolygonalItem::moveBy(dx, dy); } /* \class QtCanvasRectangle qtcanvas.h \brief The QtCanvasRectangle class provides a rectangle on a QtCanvas. This item paints a single rectangle which may have any pen() and brush(), but may not be tilted/rotated. For rotated rectangles, use QtCanvasPolygon. The rectangle's size and initial position can be set in the constructor. The size can be set or changed later using setSize(). Use height() and width() to retrieve the rectangle's dimensions. The rectangle can be drawn on a painter with drawShape(). Like any other canvas item rectangles can be moved with QtCanvasItem::move() and QtCanvasItem::moveBy(), or by setting coordinates with QtCanvasItem::setX(), QtCanvasItem::setY() and QtCanvasItem::setZ(). */ /* Constructs a rectangle at position (0,0) with both width and height set to 32 pixels on \a canvas. */ QtCanvasRectangle::QtCanvasRectangle(QtCanvas* canvas) : QtCanvasPolygonalItem(canvas), w(32), h(32) { } /* Constructs a rectangle positioned and sized by \a r on \a canvas. */ QtCanvasRectangle::QtCanvasRectangle(const QRect& r, QtCanvas* canvas) : QtCanvasPolygonalItem(canvas), w(r.width()), h(r.height()) { move(r.x(), r.y()); } /* Constructs a rectangle at position (\a x, \a y) and size \a width by \a height, on \a canvas. */ QtCanvasRectangle::QtCanvasRectangle(int x, int y, int width, int height, QtCanvas* canvas) : QtCanvasPolygonalItem(canvas), w(width), h(height) { move(x, y); } /* Destroys the rectangle. */ QtCanvasRectangle::~QtCanvasRectangle() { hide(); } /* Returns the width of the rectangle. */ int QtCanvasRectangle::width() const { return w; } /* Returns the height of the rectangle. */ int QtCanvasRectangle::height() const { return h; } /* Sets the \a width and \a height of the rectangle. */ void QtCanvasRectangle::setSize(int width, int height) { if (w != width || h != height) { removeFromChunks(); w = width; h = height; addToChunks(); } } /* \fn QSize QtCanvasRectangle::size() const Returns the width() and height() of the rectangle. \sa rect(), setSize() */ /* \fn QRect QtCanvasRectangle::rect() const Returns the integer-converted x(), y() position and size() of the rectangle as a QRect. */ /* \reimp */ QPolygon QtCanvasRectangle::areaPoints() const { QPolygon pa(4); int pw = (pen().width()+1)/2; if (pw < 1) pw = 1; if (pen() == NoPen) pw = 0; pa[0] = QPoint((int)x()-pw, (int)y()-pw); pa[1] = pa[0] + QPoint(w+pw*2, 0); pa[2] = pa[1] + QPoint(0, h+pw*2); pa[3] = pa[0] + QPoint(0, h+pw*2); return pa; } /* Draws the rectangle on painter \a p. */ void QtCanvasRectangle::drawShape(QPainter & p) { p.drawRect((int)x(), (int)y(), w, h); } /* \class QtCanvasEllipse qtcanvas.h \brief The QtCanvasEllipse class provides an ellipse or ellipse segment on a QtCanvas. A canvas item that paints an ellipse or ellipse segment with a QBrush. The ellipse's height, width, start angle and angle length can be set at construction time. The size can be changed at runtime with setSize(), and the angles can be changed (if you're displaying an ellipse segment rather than a whole ellipse) with setAngles(). Note that angles are specified in 16ths of a degree. \target anglediagram \img qcanvasellipse.png Ellipse If a start angle and length angle are set then an ellipse segment will be drawn. The start angle is the angle that goes from zero in a counter-clockwise direction (shown in green in the diagram). The length angle is the angle from the start angle in a counter-clockwise direction (shown in blue in the diagram). The blue segment is the segment of the ellipse that would be drawn. If no start angle and length angle are specified the entire ellipse is drawn. The ellipse can be drawn on a painter with drawShape(). Like any other canvas item ellipses can be moved with move() and moveBy(), or by setting coordinates with setX(), setY() and setZ(). Note: QtCanvasEllipse does not use the pen. */ /* Constructs a 32x32 ellipse, centered at (0, 0) on \a canvas. */ QtCanvasEllipse::QtCanvasEllipse(QtCanvas* canvas) : QtCanvasPolygonalItem(canvas), w(32), h(32), a1(0), a2(360*16) { } /* Constructs a \a width by \a height pixel ellipse, centered at (0, 0) on \a canvas. */ QtCanvasEllipse::QtCanvasEllipse(int width, int height, QtCanvas* canvas) : QtCanvasPolygonalItem(canvas), w(width), h(height), a1(0), a2(360*16) { } // ### add a constructor taking degrees in float. 1/16 degrees is stupid. Lars // ### it's how QPainter does it, so QtCanvas does too for consistency. If it's // ### a good idea, it should be added to QPainter, not just to QtCanvas. Warwick /* Constructs a \a width by \a height pixel ellipse, centered at (0, 0) on \a canvas. Only a segment of the ellipse is drawn, starting at angle \a startangle, and extending for angle \a angle (the angle length). Note that angles are specified in sixteenths of a degree. */ QtCanvasEllipse::QtCanvasEllipse(int width, int height, int startangle, int angle, QtCanvas* canvas) : QtCanvasPolygonalItem(canvas), w(width), h(height), a1(startangle), a2(angle) { } /* Destroys the ellipse. */ QtCanvasEllipse::~QtCanvasEllipse() { hide(); } /* Returns the width of the ellipse. */ int QtCanvasEllipse::width() const { return w; } /* Returns the height of the ellipse. */ int QtCanvasEllipse::height() const { return h; } /* Sets the \a width and \a height of the ellipse. */ void QtCanvasEllipse::setSize(int width, int height) { if (w != width || h != height) { removeFromChunks(); w = width; h = height; addToChunks(); } } /* \fn int QtCanvasEllipse::angleStart() const Returns the start angle in 16ths of a degree. Initially this will be 0. \sa setAngles(), angleLength() */ /* \fn int QtCanvasEllipse::angleLength() const Returns the length angle (the extent of the ellipse segment) in 16ths of a degree. Initially this will be 360 * 16 (a complete ellipse). \sa setAngles(), angleStart() */ /* Sets the angles for the ellipse. The start angle is \a start and the extent of the segment is \a length (the angle length) from the \a start. The angles are specified in 16ths of a degree. By default the ellipse will start at 0 and have an angle length of 360 * 16 (a complete ellipse). \sa angleStart(), angleLength() */ void QtCanvasEllipse::setAngles(int start, int length) { if (a1 != start || a2 != length) { removeFromChunks(); a1 = start; a2 = length; addToChunks(); } } /* \reimp */ QPolygon QtCanvasEllipse::areaPoints() const { QPainterPath path; path.arcTo(QRectF(x()-w/2.0+0.5-1, y()-h/2.0+0.5-1, w+3, h+3), a1/16., a2/16.); return path.toFillPolygon().toPolygon(); } /* Draws the ellipse, centered at x(), y() using the painter \a p. Note that QtCanvasEllipse does not support an outline (the pen is always NoPen). */ void QtCanvasEllipse::drawShape(QPainter & p) { p.setPen(NoPen); // since QRegion(QPolygon) excludes outline :-()-: if (!a1 && a2 == 360*16) { p.drawEllipse(int(x()-w/2.0+0.5), int(y()-h/2.0+0.5), w, h); } else { p.drawPie(int(x()-w/2.0+0.5), int(y()-h/2.0+0.5), w, h, a1, a2); } } /* \class QtCanvasText \brief The QtCanvasText class provides a text object on a QtCanvas. A canvas text item has text with font, color and alignment attributes. The text and font can be set in the constructor or set or changed later with setText() and setFont(). The color is set with setColor() and the alignment with setTextFlags(). The text item's bounding rectangle is retrieved with boundingRect(). The text can be drawn on a painter with draw(). Like any other canvas item text items can be moved with QtCanvasItem::move() and QtCanvasItem::moveBy(), or by setting coordinates with QtCanvasItem::setX(), QtCanvasItem::setY() and QtCanvasItem::setZ(). */ /* Constructs a QtCanvasText with the text "\", on \a canvas. */ QtCanvasText::QtCanvasText(QtCanvas* canvas) : QtCanvasItem(canvas), txt(""), flags(0) { setRect(); } // ### add textflags to the constructor? Lars /* Constructs a QtCanvasText with the text \a t, on canvas \a canvas. */ QtCanvasText::QtCanvasText(const QString& t, QtCanvas* canvas) : QtCanvasItem(canvas), txt(t), flags(0) { setRect(); } // ### see above /* Constructs a QtCanvasText with the text \a t and font \a f, on the canvas \a canvas. */ QtCanvasText::QtCanvasText(const QString& t, QFont f, QtCanvas* canvas) : QtCanvasItem(canvas), txt(t), flags(0), fnt(f) { setRect(); } /* Destroys the canvas text item. */ QtCanvasText::~QtCanvasText() { removeFromChunks(); } /* Returns the bounding rectangle of the text. */ QRect QtCanvasText::boundingRect() const { return brect; } void QtCanvasText::setRect() { brect = QFontMetrics(fnt).boundingRect(int(x()), int(y()), 0, 0, flags, txt); } /* \fn int QtCanvasText::textFlags() const Returns the currently set alignment flags. \sa setTextFlags() Qt::AlignmentFlag Qt::TextFlag */ /* Sets the alignment flags to \a f. These are a bitwise OR of the flags available to QPainter::drawText() -- see the \l{Qt::AlignmentFlag}s and \l{Qt::TextFlag}s. \sa setFont() setColor() */ void QtCanvasText::setTextFlags(int f) { if (flags != f) { removeFromChunks(); flags = f; setRect(); addToChunks(); } } /* Returns the text item's text. \sa setText() */ QString QtCanvasText::text() const { return txt; } /* Sets the text item's text to \a t. The text may contain newlines. \sa text(), setFont(), setColor() setTextFlags() */ void QtCanvasText::setText(const QString& t) { if (txt != t) { removeFromChunks(); txt = t; setRect(); addToChunks(); } } /* Returns the font in which the text is drawn. \sa setFont() */ QFont QtCanvasText::font() const { return fnt; } /* Sets the font in which the text is drawn to font \a f. \sa font() */ void QtCanvasText::setFont(const QFont& f) { if (f != fnt) { removeFromChunks(); fnt = f; setRect(); addToChunks(); } } /* Returns the color of the text. \sa setColor() */ QColor QtCanvasText::color() const { return col; } /* Sets the color of the text to the color \a c. \sa color(), setFont() */ void QtCanvasText::setColor(const QColor& c) { col = c; changeChunks(); } /* \reimp */ void QtCanvasText::moveBy(double dx, double dy) { int idx = int(x()+dx)-int(x()); int idy = int(y()+dy)-int(y()); if (idx || idy) { removeFromChunks(); } myx+= dx; myy+= dy; if (idx || idy) { brect.translate(idx, idy); addToChunks(); } } /* Draws the text using the painter \a painter. */ void QtCanvasText::draw(QPainter& painter) { painter.setFont(fnt); painter.setPen(col); painter.drawText(painter.fontMetrics().boundingRect(int(x()), int(y()), 0, 0, flags, txt), flags, txt); } /* \reimp */ void QtCanvasText::changeChunks() { if (isVisible() && canvas()) { int chunksize = canvas()->chunkSize(); for (int j = brect.top()/chunksize; j <= brect.bottom()/chunksize; j++) { for (int i = brect.left()/chunksize; i <= brect.right()/chunksize; i++) { canvas()->setChangedChunk(i, j); } } } } /* Adds the text item to the appropriate chunks. */ void QtCanvasText::addToChunks() { if (isVisible() && canvas()) { int chunksize = canvas()->chunkSize(); for (int j = brect.top()/chunksize; j <= brect.bottom()/chunksize; j++) { for (int i = brect.left()/chunksize; i <= brect.right()/chunksize; i++) { canvas()->addItemToChunk(this, i, j); } } } } /* Removes the text item from the appropriate chunks. */ void QtCanvasText::removeFromChunks() { if (isVisible() && canvas()) { int chunksize = canvas()->chunkSize(); for (int j = brect.top()/chunksize; j <= brect.bottom()/chunksize; j++) { for (int i = brect.left()/chunksize; i <= brect.right()/chunksize; i++) { canvas()->removeItemFromChunk(this, i, j); } } } } /* Returns 0 (QtCanvasItem::Rtti_Item). Make your derived classes return their own values for rtti(), so that you can distinguish between objects returned by QtCanvas::at(). You should use values greater than 1000 to allow for extensions to this class. Overuse of this functionality can damage its extensibility. For example, once you have identified a base class of a QtCanvasItem found by QtCanvas::at(), cast it to that type and call meaningful methods rather than acting upon the object based on its rtti value. For example: \code QtCanvasItem* item; // Find an item, e.g. with QtCanvasItem::collisions(). ... if (item->rtti() == MySprite::RTTI) { MySprite* s = (MySprite*)item; if (s->isDamagable()) s->loseHitPoints(1000); if (s->isHot()) myself->loseHitPoints(1000); ... } \endcode */ int QtCanvasItem::rtti() const { return RTTI; } int QtCanvasItem::RTTI = Rtti_Item; /* Returns 1 (QtCanvasItem::Rtti_Sprite). \sa QtCanvasItem::rtti() */ int QtCanvasSprite::rtti() const { return RTTI; } int QtCanvasSprite::RTTI = Rtti_Sprite; /* Returns 2 (QtCanvasItem::Rtti_PolygonalItem). \sa QtCanvasItem::rtti() */ int QtCanvasPolygonalItem::rtti() const { return RTTI; } int QtCanvasPolygonalItem::RTTI = Rtti_PolygonalItem; /* Returns 3 (QtCanvasItem::Rtti_Text). \sa QtCanvasItem::rtti() */ int QtCanvasText::rtti() const { return RTTI; } int QtCanvasText::RTTI = Rtti_Text; /* Returns 4 (QtCanvasItem::Rtti_Polygon). \sa QtCanvasItem::rtti() */ int QtCanvasPolygon::rtti() const { return RTTI; } int QtCanvasPolygon::RTTI = Rtti_Polygon; /* Returns 5 (QtCanvasItem::Rtti_Rectangle). \sa QtCanvasItem::rtti() */ int QtCanvasRectangle::rtti() const { return RTTI; } int QtCanvasRectangle::RTTI = Rtti_Rectangle; /* Returns 6 (QtCanvasItem::Rtti_Ellipse). \sa QtCanvasItem::rtti() */ int QtCanvasEllipse::rtti() const { return RTTI; } int QtCanvasEllipse::RTTI = Rtti_Ellipse; /* Returns 7 (QtCanvasItem::Rtti_Line). \sa QtCanvasItem::rtti() */ int QtCanvasLine::rtti() const { return RTTI; } int QtCanvasLine::RTTI = Rtti_Line; /* Returns 8 (QtCanvasItem::Rtti_Spline). \sa QtCanvasItem::rtti() */ int QtCanvasSpline::rtti() const { return RTTI; } int QtCanvasSpline::RTTI = Rtti_Spline; /* Constructs a QtCanvasSprite which uses images from the QtCanvasPixmapArray \a a. The sprite in initially positioned at (0, 0) on \a canvas, using frame 0. */ QtCanvasSprite::QtCanvasSprite(QtCanvasPixmapArray* a, QtCanvas* canvas) : QtCanvasItem(canvas), frm(0), anim_val(0), anim_state(0), anim_type(0), images(a) { } /* Set the array of images used for displaying the sprite to the QtCanvasPixmapArray \a a. If the current frame() is larger than the number of images in \a a, the current frame will be reset to 0. */ void QtCanvasSprite::setSequence(QtCanvasPixmapArray* a) { bool isvisible = isVisible(); if (isvisible && images) hide(); images = a; if (frm >= (int)images->count()) frm = 0; if (isvisible) show(); } /* \internal Marks any chunks the sprite touches as changed. */ void QtCanvasSprite::changeChunks() { if (isVisible() && canvas()) { int chunksize = canvas()->chunkSize(); for (int j = topEdge()/chunksize; j <= bottomEdge()/chunksize; j++) { for (int i = leftEdge()/chunksize; i <= rightEdge()/chunksize; i++) { canvas()->setChangedChunk(i, j); } } } } /* Destroys the sprite and removes it from the canvas. Does \e not delete the images. */ QtCanvasSprite::~QtCanvasSprite() { removeFromChunks(); } /* Sets the animation frame used for displaying the sprite to \a f, an index into the QtCanvasSprite's QtCanvasPixmapArray. The call will be ignored if \a f is larger than frameCount() or smaller than 0. \sa frame() move() */ void QtCanvasSprite::setFrame(int f) { move(x(), y(), f); } /* \enum QtCanvasSprite::FrameAnimationType This enum is used to identify the different types of frame animation offered by QtCanvasSprite. \value Cycle at each advance the frame number will be incremented by 1 (modulo the frame count). \value Oscillate at each advance the frame number will be incremented by 1 up to the frame count then decremented to by 1 to 0, repeating this sequence forever. */ /* Sets the animation characteristics for the sprite. For \a type == \c Cycle, the frames will increase by \a step at each advance, modulo the frameCount(). For \a type == \c Oscillate, the frames will increase by \a step at each advance, up to the frameCount(), then decrease by \a step back to 0, repeating forever. The \a state parameter is for internal use. */ void QtCanvasSprite::setFrameAnimation(FrameAnimationType type, int step, int state) { anim_val = step; anim_type = type; anim_state = state; setAnimated(true); } /* Extends the default QtCanvasItem implementation to provide the functionality of setFrameAnimation(). The \a phase is 0 or 1: see QtCanvasItem::advance() for details. \sa QtCanvasItem::advance() setVelocity() */ void QtCanvasSprite::advance(int phase) { if (phase == 1) { int nf = frame(); if (anim_type == Oscillate) { if (anim_state) nf += anim_val; else nf -= anim_val; if (nf < 0) { nf = abs(anim_val); anim_state = !anim_state; } else if (nf >= frameCount()) { nf = frameCount()-1-abs(anim_val); anim_state = !anim_state; } } else { nf = (nf + anim_val + frameCount()) % frameCount(); } move(x()+xVelocity(), y()+yVelocity(), nf); } } /* \fn int QtCanvasSprite::frame() const Returns the index of the current animation frame in the QtCanvasSprite's QtCanvasPixmapArray. \sa setFrame(), move() */ /* \fn int QtCanvasSprite::frameCount() const Returns the number of frames in the QtCanvasSprite's QtCanvasPixmapArray. */ /* Moves the sprite to (\a x, \a y). */ void QtCanvasSprite::move(double x, double y) { QtCanvasItem::move(x, y); } /* \fn void QtCanvasSprite::move(double nx, double ny, int nf) Moves the sprite to (\a nx, \a ny) and sets the current frame to \a nf. \a nf will be ignored if it is larger than frameCount() or smaller than 0. */ void QtCanvasSprite::move(double nx, double ny, int nf) { if (isVisible() && canvas()) { hide(); QtCanvasItem::move(nx, ny); if (nf >= 0 && nf < frameCount()) frm = nf; show(); } else { QtCanvasItem::move(nx, ny); if (nf >= 0 && nf < frameCount()) frm = nf; } } class QPoint; class QtPolygonScanner { public: virtual ~QtPolygonScanner() {} void scan(const QPolygon& pa, bool winding, int index = 0, int npoints = -1); void scan(const QPolygon& pa, bool winding, int index, int npoints, bool stitchable); enum Edge { Left = 1, Right = 2, Top = 4, Bottom = 8 }; void scan(const QPolygon& pa, bool winding, int index, int npoints, Edge edges); virtual void processSpans(int n, QPoint* point, int* width) = 0; }; // Based on Xserver code miFillGeneralPoly... /* * * Written by Brian Kelleher; Oct. 1985 * * Routine to fill a polygon. Two fill rules are * supported: frWINDING and frEVENODD. * * See fillpoly.h for a complete description of the algorithm. */ /* * These are the data structures needed to scan * convert regions. Two different scan conversion * methods are available -- the even-odd method, and * the winding number method. * The even-odd rule states that a point is inside * the polygon if a ray drawn from that point in any * direction will pass through an odd number of * path segments. * By the winding number rule, a point is decided * to be inside the polygon if a ray drawn from that * point in any direction passes through a different * number of clockwise and counterclockwise path * segments. * * These data structures are adapted somewhat from * the algorithm in (Foley/Van Dam) for scan converting * polygons. * The basic algorithm is to start at the top (smallest y) * of the polygon, stepping down to the bottom of * the polygon by incrementing the y coordinate. We * keep a list of edges which the current scanline crosses, * sorted by x. This list is called the Active Edge Table (AET) * As we change the y-coordinate, we update each entry in * in the active edge table to reflect the edges new xcoord. * This list must be sorted at each scanline in case * two edges intersect. * We also keep a data structure known as the Edge Table (ET), * which keeps track of all the edges which the current * scanline has not yet reached. The ET is basically a * list of ScanLineList structures containing a list of * edges which are entered at a given scanline. There is one * ScanLineList per scanline at which an edge is entered. * When we enter a new edge, we move it from the ET to the AET. * * From the AET, we can implement the even-odd rule as in * (Foley/Van Dam). * The winding number rule is a little trickier. We also * keep the EdgeTableEntries in the AET linked by the * nextWETE (winding EdgeTableEntry) link. This allows * the edges to be linked just as before for updating * purposes, but only uses the edges linked by the nextWETE * link as edges representing spans of the polygon to * drawn (as with the even-odd rule). */ /* $XConsortium: miscanfill.h, v 1.5 94/04/17 20:27:50 dpw Exp $ */ /* Copyright (c) 1987 X Consortium Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of the X Consortium shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the X Consortium. */ /* * scanfill.h * * Written by Brian Kelleher; Jan 1985 * * This file contains a few macros to help track * the edge of a filled object. The object is assumed * to be filled in scanline order, and thus the * algorithm used is an extension of Bresenham's line * drawing algorithm which assumes that y is always the * major axis. * Since these pieces of code are the same for any filled shape, * it is more convenient to gather the library in one * place, but since these pieces of code are also in * the inner loops of output primitives, procedure call * overhead is out of the question. * See the author for a derivation if needed. */ /* * In scan converting polygons, we want to choose those pixels * which are inside the polygon. Thus, we add .5 to the starting * x coordinate for both left and right edges. Now we choose the * first pixel which is inside the pgon for the left edge and the * first pixel which is outside the pgon for the right edge. * Draw the left pixel, but not the right. * * How to add .5 to the starting x coordinate: * If the edge is moving to the right, then subtract dy from the * error term from the general form of the algorithm. * If the edge is moving to the left, then add dy to the error term. * * The reason for the difference between edges moving to the left * and edges moving to the right is simple: If an edge is moving * to the right, then we want the algorithm to flip immediately. * If it is moving to the left, then we don't want it to flip until * we traverse an entire pixel. */ #define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \ int dx; /* local storage */ \ \ /* \ * if the edge is horizontal, then it is ignored \ * and assumed not to be processed. Otherwise, do this stuff. \ */ \ if ((dy) != 0) { \ xStart = (x1); \ dx = (x2) - xStart; \ if (dx < 0) { \ m = dx / (dy); \ m1 = m - 1; \ incr1 = -2 * dx + 2 * (dy) * m1; \ incr2 = -2 * dx + 2 * (dy) * m; \ d = 2 * m * (dy) - 2 * dx - 2 * (dy); \ } else { \ m = dx / (dy); \ m1 = m + 1; \ incr1 = 2 * dx - 2 * (dy) * m1; \ incr2 = 2 * dx - 2 * (dy) * m; \ d = -2 * m * (dy) + 2 * dx; \ } \ } \ } #define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \ if (m1 > 0) { \ if (d > 0) { \ minval += m1; \ d += incr1; \ } \ else { \ minval += m; \ d += incr2; \ } \ } else {\ if (d >= 0) { \ minval += m1; \ d += incr1; \ } \ else { \ minval += m; \ d += incr2; \ } \ } \ } /* * This structure contains all of the information needed * to run the bresenham algorithm. * The variables may be hardcoded into the declarations * instead of using this structure to make use of * register declarations. */ typedef struct { int minor; /* minor axis */ int d; /* decision variable */ int m, m1; /* slope and slope+1 */ int incr1, incr2; /* error increments */ } BRESINFO; #define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \ BRESINITPGON(dmaj, min1, min2, bres.minor, bres.d, \ bres.m, bres.m1, bres.incr1, bres.incr2) #define BRESINCRPGONSTRUCT(bres) \ BRESINCRPGON(bres.d, bres.minor, bres.m, bres.m1, bres.incr1, bres.incr2) typedef struct _EdgeTableEntry { int ymax; /* ycoord at which we exit this edge. */ BRESINFO bres; /* Bresenham info to run the edge */ struct _EdgeTableEntry *next; /* next in the list */ struct _EdgeTableEntry *back; /* for insertion sort */ struct _EdgeTableEntry *nextWETE; /* for winding num rule */ int ClockWise; /* flag for winding number rule */ } EdgeTableEntry; typedef struct _ScanLineList{ int scanline; /* the scanline represented */ EdgeTableEntry *edgelist; /* header node */ struct _ScanLineList *next; /* next in the list */ } ScanLineList; typedef struct { int ymax; /* ymax for the polygon */ int ymin; /* ymin for the polygon */ ScanLineList scanlines; /* header node */ } EdgeTable; /* * Here is a struct to help with storage allocation * so we can allocate a big chunk at a time, and then take * pieces from this heap when we need to. */ #define SLLSPERBLOCK 25 typedef struct _ScanLineListBlock { ScanLineList SLLs[SLLSPERBLOCK]; struct _ScanLineListBlock *next; } ScanLineListBlock; /* * number of points to buffer before sending them off * to scanlines() : Must be an even number */ #define NUMPTSTOBUFFER 200 /* * * a few macros for the inner loops of the fill code where * performance considerations don't allow a procedure call. * * Evaluate the given edge at the given scanline. * If the edge has expired, then we leave it and fix up * the active edge table; otherwise, we increment the * x value to be ready for the next scanline. * The winding number rule is in effect, so we must notify * the caller when the edge has been removed so he * can reorder the Winding Active Edge Table. */ #define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \ if (pAET->ymax == y) { /* leaving this edge */ \ pPrevAET->next = pAET->next; \ pAET = pPrevAET->next; \ fixWAET = 1; \ if (pAET) \ pAET->back = pPrevAET; \ } \ else { \ BRESINCRPGONSTRUCT(pAET->bres); \ pPrevAET = pAET; \ pAET = pAET->next; \ } \ } /* * Evaluate the given edge at the given scanline. * If the edge has expired, then we leave it and fix up * the active edge table; otherwise, we increment the * x value to be ready for the next scanline. * The even-odd rule is in effect. */ #define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \ if (pAET->ymax == y) { /* leaving this edge */ \ pPrevAET->next = pAET->next; \ pAET = pPrevAET->next; \ if (pAET) \ pAET->back = pPrevAET; \ } \ else { \ BRESINCRPGONSTRUCT(pAET->bres) \ pPrevAET = pAET; \ pAET = pAET->next; \ } \ } /*********************************************************** Copyright (c) 1987 X Consortium Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of the X Consortium shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the X Consortium. Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of Digital not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************/ #define MAXINT 0x7fffffff #define MININT -MAXINT /* * fillUtils.c * * Written by Brian Kelleher; Oct. 1985 * * This module contains all of the utility functions * needed to scan convert a polygon. * */ /* * InsertEdgeInET * * Insert the given edge into the edge table. * First we must find the correct bucket in the * Edge table, then find the right slot in the * bucket. Finally, we can insert it. * */ static bool miInsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE, int scanline, ScanLineListBlock **SLLBlock, int *iSLLBlock) { register EdgeTableEntry *start, *prev; register ScanLineList *pSLL, *pPrevSLL; ScanLineListBlock *tmpSLLBlock; /* * find the right bucket to put the edge into */ pPrevSLL = &ET->scanlines; pSLL = pPrevSLL->next; while (pSLL && (pSLL->scanline < scanline)) { pPrevSLL = pSLL; pSLL = pSLL->next; } /* * reassign pSLL (pointer to ScanLineList) if necessary */ if ((!pSLL) || (pSLL->scanline > scanline)) { if (*iSLLBlock > SLLSPERBLOCK-1) { tmpSLLBlock = (ScanLineListBlock *)malloc(sizeof(ScanLineListBlock)); if (!tmpSLLBlock) return false; (*SLLBlock)->next = tmpSLLBlock; tmpSLLBlock->next = 0; *SLLBlock = tmpSLLBlock; *iSLLBlock = 0; } pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]); pSLL->next = pPrevSLL->next; pSLL->edgelist = 0; pPrevSLL->next = pSLL; } pSLL->scanline = scanline; /* * now insert the edge in the right bucket */ prev = 0; start = pSLL->edgelist; while (start && (start->bres.minor < ETE->bres.minor)) { prev = start; start = start->next; } ETE->next = start; if (prev) prev->next = ETE; else pSLL->edgelist = ETE; return true; } /* * CreateEdgeTable * * This routine creates the edge table for * scan converting polygons. * The Edge Table (ET) looks like: * * EdgeTable * -------- * | ymax | ScanLineLists * |scanline|-->------------>-------------->... * -------- |scanline| |scanline| * |edgelist| |edgelist| * --------- --------- * | | * | | * V V * list of ETEs list of ETEs * * where ETE is an EdgeTableEntry data structure, * and there is one ScanLineList per scanline at * which an edge is initially entered. * */ typedef struct { #if defined(Q_OS_MAC) int y, x; #else int x, y; #endif } DDXPointRec, *DDXPointPtr; /* * Clean up our act. */ static void miFreeStorage(ScanLineListBlock *pSLLBlock) { register ScanLineListBlock *tmpSLLBlock; while (pSLLBlock) { tmpSLLBlock = pSLLBlock->next; free(pSLLBlock); pSLLBlock = tmpSLLBlock; } } static bool miCreateETandAET(int count, DDXPointPtr pts, EdgeTable *ET, EdgeTableEntry *AET, EdgeTableEntry *pETEs, ScanLineListBlock *pSLLBlock) { register DDXPointPtr top, bottom; register DDXPointPtr PrevPt, CurrPt; int iSLLBlock = 0; int dy; if (count < 2) return true; /* * initialize the Active Edge Table */ AET->next = 0; AET->back = 0; AET->nextWETE = 0; AET->bres.minor = MININT; /* * initialize the Edge Table. */ ET->scanlines.next = 0; ET->ymax = MININT; ET->ymin = MAXINT; pSLLBlock->next = 0; PrevPt = &pts[count-1]; /* * for each vertex in the array of points. * In this loop we are dealing with two vertices at * a time -- these make up one edge of the polygon. */ while (count--) { CurrPt = pts++; /* * find out which point is above and which is below. */ if (PrevPt->y > CurrPt->y) { bottom = PrevPt, top = CurrPt; pETEs->ClockWise = 0; } else { bottom = CurrPt, top = PrevPt; pETEs->ClockWise = 1; } /* * don't add horizontal edges to the Edge table. */ if (bottom->y != top->y) { pETEs->ymax = bottom->y-1; /* -1 so we don't get last scanline */ /* * initialize integer edge algorithm */ dy = bottom->y - top->y; BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres) if (!miInsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, &iSLLBlock)) { miFreeStorage(pSLLBlock->next); return false; } ET->ymax = qMax(ET->ymax, PrevPt->y); ET->ymin = qMin(ET->ymin, PrevPt->y); pETEs++; } PrevPt = CurrPt; } return true; } /* * loadAET * * This routine moves EdgeTableEntries from the * EdgeTable into the Active Edge Table, * leaving them sorted by smaller x coordinate. * */ static void miloadAET(EdgeTableEntry *AET, EdgeTableEntry *ETEs) { register EdgeTableEntry *pPrevAET; register EdgeTableEntry *tmp; pPrevAET = AET; AET = AET->next; while (ETEs) { while (AET && (AET->bres.minor < ETEs->bres.minor)) { pPrevAET = AET; AET = AET->next; } tmp = ETEs->next; ETEs->next = AET; if (AET) AET->back = ETEs; ETEs->back = pPrevAET; pPrevAET->next = ETEs; pPrevAET = ETEs; ETEs = tmp; } } /* * computeWAET * * This routine links the AET by the * nextWETE (winding EdgeTableEntry) link for * use by the winding number rule. The final * Active Edge Table (AET) might look something * like: * * AET * ---------- --------- --------- * |ymax | |ymax | |ymax | * | ... | |... | |... | * |next |->|next |->|next |->... * |nextWETE| |nextWETE| |nextWETE| * --------- --------- ^-------- * | | | * V-------------------> V---> ... * */ static void micomputeWAET(EdgeTableEntry *AET) { register EdgeTableEntry *pWETE; register int inside = 1; register int isInside = 0; AET->nextWETE = 0; pWETE = AET; AET = AET->next; while (AET) { if (AET->ClockWise) isInside++; else isInside--; if ((!inside && !isInside) || (inside && isInside)) { pWETE->nextWETE = AET; pWETE = AET; inside = !inside; } AET = AET->next; } pWETE->nextWETE = 0; } /* * InsertionSort * * Just a simple insertion sort using * pointers and back pointers to sort the Active * Edge Table. * */ static int miInsertionSort(EdgeTableEntry *AET) { register EdgeTableEntry *pETEchase; register EdgeTableEntry *pETEinsert; register EdgeTableEntry *pETEchaseBackTMP; register int changed = 0; AET = AET->next; while (AET) { pETEinsert = AET; pETEchase = AET; while (pETEchase->back->bres.minor > AET->bres.minor) pETEchase = pETEchase->back; AET = AET->next; if (pETEchase != pETEinsert) { pETEchaseBackTMP = pETEchase->back; pETEinsert->back->next = AET; if (AET) AET->back = pETEinsert->back; pETEinsert->next = pETEchase; pETEchase->back->next = pETEinsert; pETEchase->back = pETEinsert; pETEinsert->back = pETEchaseBackTMP; changed = 1; } } return changed; } /* \overload */ void QtPolygonScanner::scan(const QPolygon& pa, bool winding, int index, int npoints) { scan(pa, winding, index, npoints, true); } /* \overload If \a stitchable is false, the right and bottom edges of the polygon are included. This causes adjacent polygons to overlap. */ void QtPolygonScanner::scan(const QPolygon& pa, bool winding, int index, int npoints, bool stitchable) { scan(pa, winding, index, npoints, stitchable ? Edge(Left+Top) : Edge(Left+Right+Top+Bottom)); } /* Calls processSpans() for all scanlines of the polygon defined by \a npoints starting at \a index in \a pa. If \a winding is true, the Winding algorithm rather than the Odd-Even rule is used. The \a edges is any bitwise combination of: \list \i QtPolygonScanner::Left \i QtPolygonScanner::Right \i QtPolygonScanner::Top \i QtPolygonScanner::Bottom \endlist \a edges determines which edges are included. \warning The edges feature does not work properly. */ void QtPolygonScanner::scan(const QPolygon& pa, bool winding, int index, int npoints, Edge edges) { DDXPointPtr ptsIn = (DDXPointPtr)pa.data(); ptsIn += index; register EdgeTableEntry *pAET; /* the Active Edge Table */ register int y; /* the current scanline */ register int nPts = 0; /* number of pts in buffer */ register EdgeTableEntry *pWETE; /* Winding Edge Table */ register ScanLineList *pSLL; /* Current ScanLineList */ register DDXPointPtr ptsOut; /* ptr to output buffers */ int *width; DDXPointRec FirstPoint[NUMPTSTOBUFFER]; /* the output buffers */ int FirstWidth[NUMPTSTOBUFFER]; EdgeTableEntry *pPrevAET; /* previous AET entry */ EdgeTable ET; /* Edge Table header node */ EdgeTableEntry AET; /* Active ET header node */ EdgeTableEntry *pETEs; /* Edge Table Entries buff */ ScanLineListBlock SLLBlock; /* header for ScanLineList */ int fixWAET = 0; int edge_l = (edges & Left) ? 1 : 0; int edge_r = (edges & Right) ? 1 : 0; int edge_t = 1; //#### (edges & Top) ? 1 : 0; int edge_b = (edges & Bottom) ? 1 : 0; if (npoints == -1) npoints = pa.size(); if (npoints < 3) return; if(!(pETEs = (EdgeTableEntry *) malloc(sizeof(EdgeTableEntry) * npoints))) return; ptsOut = FirstPoint; width = FirstWidth; if (!miCreateETandAET(npoints, ptsIn, &ET, &AET, pETEs, &SLLBlock)) { free(pETEs); return; } pSLL = ET.scanlines.next; if (!winding) { /* * for each scanline */ for (y = ET.ymin+1-edge_t; y < ET.ymax+edge_b; y++) { /* * Add a new edge to the active edge table when we * get to the next edge. */ if (pSLL && y == pSLL->scanline) { miloadAET(&AET, pSLL->edgelist); pSLL = pSLL->next; } pPrevAET = &AET; pAET = AET.next; /* * for each active edge */ while (pAET) { ptsOut->x = pAET->bres.minor + 1 - edge_l; ptsOut++->y = y; *width++ = pAET->next->bres.minor - pAET->bres.minor - 1 + edge_l + edge_r; nPts++; /* * send out the buffer when its full */ if (nPts == NUMPTSTOBUFFER) { processSpans(nPts, (QPoint*)FirstPoint, FirstWidth); ptsOut = FirstPoint; width = FirstWidth; nPts = 0; } EVALUATEEDGEEVENODD(pAET, pPrevAET, y) EVALUATEEDGEEVENODD(pAET, pPrevAET, y) } miInsertionSort(&AET); } } else /* default to WindingNumber */ { /* * for each scanline */ for (y = ET.ymin+1-edge_t; y < ET.ymax+edge_b; y++) { /* * Add a new edge to the active edge table when we * get to the next edge. */ if (pSLL && y == pSLL->scanline) { miloadAET(&AET, pSLL->edgelist); micomputeWAET(&AET); pSLL = pSLL->next; } pPrevAET = &AET; pAET = AET.next; pWETE = pAET; /* * for each active edge */ while (pAET) { /* * if the next edge in the active edge table is * also the next edge in the winding active edge * table. */ if (pWETE == pAET) { ptsOut->x = pAET->bres.minor + 1 - edge_l; ptsOut++->y = y; *width++ = pAET->nextWETE->bres.minor - pAET->bres.minor - 1 + edge_l + edge_r; nPts++; /* * send out the buffer */ if (nPts == NUMPTSTOBUFFER) { processSpans(nPts, (QPoint*)FirstPoint, FirstWidth); ptsOut = FirstPoint; width = FirstWidth; nPts = 0; } pWETE = pWETE->nextWETE; while (pWETE != pAET) { EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) } pWETE = pWETE->nextWETE; } EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) } /* * reevaluate the Winding active edge table if we * just had to resort it or if we just exited an edge. */ if (miInsertionSort(&AET) || fixWAET) { micomputeWAET(&AET); fixWAET = 0; } } } /* * Get any spans that we missed by buffering */ processSpans(nPts, (QPoint*)FirstPoint, FirstWidth); free(pETEs); miFreeStorage(SLLBlock.next); } /***** END OF X11-based CODE *****/ class QtCanvasPolygonScanner : public QtPolygonScanner { QPolygonalProcessor& processor; public: QtCanvasPolygonScanner(QPolygonalProcessor& p) : processor(p) { } void processSpans(int n, QPoint* point, int* width) { processor.doSpans(n, point, width); } }; void QtCanvasPolygonalItem::scanPolygon(const QPolygon& pa, int winding, QPolygonalProcessor& process) const { QtCanvasPolygonScanner scanner(process); scanner.scan(pa, winding); } nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/canvas_variant/qtcanvas.h000066400000000000000000000466201455373415500306510ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #ifndef QTCANVAS_H #define QTCANVAS_H #include #include #include #include #include class QtCanvasSprite; class QtCanvasPolygonalItem; class QtCanvasRectangle; class QtCanvasPolygon; class QtCanvasEllipse; class QtCanvasText; class QtCanvasLine; class QtCanvasChunk; class QtCanvas; class QtCanvasItem; class QtCanvasView; class QtCanvasPixmap; typedef QList QtCanvasItemList; class QtCanvasItemExtra; class QtCanvasItem { public: QtCanvasItem(QtCanvas* canvas); virtual ~QtCanvasItem(); double x() const { return myx; } double y() const { return myy; } double z() const { return myz; } // (depth) virtual void moveBy(double dx, double dy); void move(double x, double y); void setX(double a) { move(a,y()); } void setY(double a) { move(x(),a); } void setZ(double a) { myz=a; changeChunks(); } bool animated() const; virtual void setAnimated(bool y); virtual void setVelocity(double vx, double vy); void setXVelocity(double vx) { setVelocity(vx,yVelocity()); } void setYVelocity(double vy) { setVelocity(xVelocity(),vy); } double xVelocity() const; double yVelocity() const; virtual void advance(int stage); virtual bool collidesWith(const QtCanvasItem*) const=0; QtCanvasItemList collisions(bool exact /* NO DEFAULT */) const; virtual void setCanvas(QtCanvas*); virtual void draw(QPainter&)=0; void show(); void hide(); virtual void setVisible(bool yes); bool isVisible() const { return (bool)vis; } virtual void setSelected(bool yes); bool isSelected() const { return (bool)sel; } virtual void setEnabled(bool yes); bool isEnabled() const { return (bool)ena; } virtual void setActive(bool yes); bool isActive() const { return (bool)act; } bool visible() const { return (bool)vis; } bool selected() const { return (bool)sel; } bool enabled() const { return (bool)ena; } bool active() const { return (bool)act; } enum RttiValues { Rtti_Item = 0, Rtti_Sprite = 1, Rtti_PolygonalItem = 2, Rtti_Text = 3, Rtti_Polygon = 4, Rtti_Rectangle = 5, Rtti_Ellipse = 6, Rtti_Line = 7, Rtti_Spline = 8 }; virtual int rtti() const; static int RTTI; virtual QRect boundingRect() const=0; virtual QRect boundingRectAdvanced() const; QtCanvas* canvas() const { return cnv; } protected: void update() { changeChunks(); } private: // For friendly subclasses... friend class QtCanvasPolygonalItem; friend class QtCanvasSprite; friend class QtCanvasRectangle; friend class QtCanvasPolygon; friend class QtCanvasEllipse; friend class QtCanvasText; friend class QtCanvasLine; virtual QPolygon chunks() const; virtual void addToChunks(); virtual void removeFromChunks(); virtual void changeChunks(); virtual bool collidesWith(const QtCanvasSprite*, const QtCanvasPolygonalItem*, const QtCanvasRectangle*, const QtCanvasEllipse*, const QtCanvasText*) const = 0; // End of friend stuff QtCanvas* cnv; static QtCanvas* current_canvas; double myx,myy,myz; QtCanvasItemExtra *ext; QtCanvasItemExtra& extra(); uint ani:1; uint vis:1; uint val:1; uint sel:1; uint ena:1; uint act:1; }; class QtCanvasData; class QtCanvas : public QObject { Q_OBJECT public: QtCanvas(QObject* parent = 0); QtCanvas(int w, int h); QtCanvas(QPixmap p, int h, int v, int tilewidth, int tileheight); virtual ~QtCanvas(); virtual void setTiles(QPixmap tiles, int h, int v, int tilewidth, int tileheight); virtual void setBackgroundPixmap(const QPixmap& p); QPixmap backgroundPixmap() const; virtual void setBackgroundColor(const QColor& c); QColor backgroundColor() const; virtual void setTile(int x, int y, int tilenum); int tile(int x, int y) const { return grid[x+y*htiles]; } int tilesHorizontally() const { return htiles; } int tilesVertically() const { return vtiles; } int tileWidth() const { return tilew; } int tileHeight() const { return tileh; } virtual void resize(int width, int height); int width() const { return awidth; } int height() const { return aheight; } QSize size() const { return QSize(awidth,aheight); } QRect rect() const { return QRect(0, 0, awidth, aheight); } bool onCanvas(int x, int y) const { return x>=0 && y>=0 && x=0 && y>=0 && x &pixmaps, const QPolygon &hotspots = QPolygon()); ~QtCanvasPixmapArray(); #ifndef QT_NO_IMAGEIO bool readPixmaps(const QString& datafilenamepattern, int framecount=0); bool readCollisionMasks(const QString& filenamepattern); #endif // deprecated bool operator!(); // Failure check. bool isValid() const; QtCanvasPixmap* image(int i) const { return img ? img[i] : 0; } void setImage(int i, QtCanvasPixmap* p); uint count() const { return (uint)framecount; } private: Q_DISABLE_COPY(QtCanvasPixmapArray) #ifndef QT_NO_IMAGEIO bool readPixmaps(const QString& datafilenamepattern, int framecount, bool maskonly); #endif void reset(); int framecount; QtCanvasPixmap** img; }; class QtCanvasSprite : public QtCanvasItem { public: QtCanvasSprite(QtCanvasPixmapArray* array, QtCanvas* canvas); void setSequence(QtCanvasPixmapArray* seq); virtual ~QtCanvasSprite(); void move(double x, double y); virtual void move(double x, double y, int frame); void setFrame(int); enum FrameAnimationType { Cycle, Oscillate }; virtual void setFrameAnimation(FrameAnimationType=Cycle, int step=1, int state=0); int frame() const { return frm; } int frameCount() const { return images->count(); } int rtti() const; static int RTTI; bool collidesWith(const QtCanvasItem*) const; QRect boundingRect() const; // is there a reason for these to be protected? Lars //protected: int width() const; int height() const; int leftEdge() const; int topEdge() const; int rightEdge() const; int bottomEdge() const; int leftEdge(int nx) const; int topEdge(int ny) const; int rightEdge(int nx) const; int bottomEdge(int ny) const; QtCanvasPixmap* image() const { return images->image(frm); } virtual QtCanvasPixmap* imageAdvanced() const; QtCanvasPixmap* image(int f) const { return images->image(f); } virtual void advance(int stage); public: void draw(QPainter& painter); private: Q_DISABLE_COPY(QtCanvasSprite) void addToChunks(); void removeFromChunks(); void changeChunks(); int frm; ushort anim_val; uint anim_state:2; uint anim_type:14; bool collidesWith(const QtCanvasSprite*, const QtCanvasPolygonalItem*, const QtCanvasRectangle*, const QtCanvasEllipse*, const QtCanvasText*) const; friend bool qt_testCollision(const QtCanvasSprite* s1, const QtCanvasSprite* s2); QtCanvasPixmapArray* images; }; class QPolygonalProcessor; class QtCanvasPolygonalItem : public QtCanvasItem { public: QtCanvasPolygonalItem(QtCanvas* canvas); virtual ~QtCanvasPolygonalItem(); bool collidesWith(const QtCanvasItem*) const; virtual void setPen(QPen p); virtual void setBrush(QBrush b); QPen pen() const { return pn; } QBrush brush() const { return br; } virtual QPolygon areaPoints() const=0; virtual QPolygon areaPointsAdvanced() const; QRect boundingRect() const; int rtti() const; static int RTTI; protected: void draw(QPainter &); virtual void drawShape(QPainter &) = 0; bool winding() const; void setWinding(bool); void invalidate(); bool isValid() const { return (bool)val; } private: void scanPolygon(const QPolygon& pa, int winding, QPolygonalProcessor& process) const; QPolygon chunks() const; bool collidesWith(const QtCanvasSprite*, const QtCanvasPolygonalItem*, const QtCanvasRectangle*, const QtCanvasEllipse*, const QtCanvasText*) const; QBrush br; QPen pn; uint wind:1; }; class QtCanvasRectangle : public QtCanvasPolygonalItem { public: QtCanvasRectangle(QtCanvas* canvas); QtCanvasRectangle(const QRect&, QtCanvas* canvas); QtCanvasRectangle(int x, int y, int width, int height, QtCanvas* canvas); ~QtCanvasRectangle(); int width() const; int height() const; void setSize(int w, int h); QSize size() const { return QSize(w,h); } QPolygon areaPoints() const; QRect rect() const { return QRect(int(x()),int(y()),w,h); } bool collidesWith(const QtCanvasItem*) const; int rtti() const; static int RTTI; protected: void drawShape(QPainter &); QPolygon chunks() const; private: bool collidesWith( const QtCanvasSprite*, const QtCanvasPolygonalItem*, const QtCanvasRectangle*, const QtCanvasEllipse*, const QtCanvasText*) const; int w, h; }; class QtCanvasPolygon : public QtCanvasPolygonalItem { public: QtCanvasPolygon(QtCanvas* canvas); ~QtCanvasPolygon(); void setPoints(QPolygon); QPolygon points() const; void moveBy(double dx, double dy); QPolygon areaPoints() const; int rtti() const; static int RTTI; protected: void drawShape(QPainter &); QPolygon poly; }; class QtCanvasSpline : public QtCanvasPolygon { public: QtCanvasSpline(QtCanvas* canvas); ~QtCanvasSpline(); void setControlPoints(QPolygon, bool closed=true); QPolygon controlPoints() const; bool closed() const; int rtti() const; static int RTTI; private: void recalcPoly(); QPolygon bez; bool cl; }; class QtCanvasLine : public QtCanvasPolygonalItem { public: QtCanvasLine(QtCanvas* canvas); ~QtCanvasLine(); void setPoints(int x1, int y1, int x2, int y2); QPoint startPoint() const { return QPoint(x1,y1); } QPoint endPoint() const { return QPoint(x2,y2); } int rtti() const; static int RTTI; void setPen(QPen p); void moveBy(double dx, double dy); protected: void drawShape(QPainter &); QPolygon areaPoints() const; private: int x1,y1,x2,y2; }; class QtCanvasEllipse : public QtCanvasPolygonalItem { public: QtCanvasEllipse(QtCanvas* canvas); QtCanvasEllipse(int width, int height, QtCanvas* canvas); QtCanvasEllipse(int width, int height, int startangle, int angle, QtCanvas* canvas); ~QtCanvasEllipse(); int width() const; int height() const; void setSize(int w, int h); void setAngles(int start, int length); int angleStart() const { return a1; } int angleLength() const { return a2; } QPolygon areaPoints() const; bool collidesWith(const QtCanvasItem*) const; int rtti() const; static int RTTI; protected: void drawShape(QPainter &); private: bool collidesWith(const QtCanvasSprite*, const QtCanvasPolygonalItem*, const QtCanvasRectangle*, const QtCanvasEllipse*, const QtCanvasText*) const; int w, h; int a1, a2; }; class QtCanvasTextExtra; class QtCanvasText : public QtCanvasItem { public: QtCanvasText(QtCanvas* canvas); QtCanvasText(const QString&, QtCanvas* canvas); QtCanvasText(const QString&, QFont, QtCanvas* canvas); virtual ~QtCanvasText(); void setText(const QString&); void setFont(const QFont&); void setColor(const QColor&); QString text() const; QFont font() const; QColor color() const; void moveBy(double dx, double dy); int textFlags() const { return flags; } void setTextFlags(int); QRect boundingRect() const; bool collidesWith(const QtCanvasItem*) const; int rtti() const; static int RTTI; protected: virtual void draw(QPainter&); private: Q_DISABLE_COPY(QtCanvasText) void addToChunks(); void removeFromChunks(); void changeChunks(); void setRect(); QRect brect; QString txt; int flags; QFont fnt; QColor col; QtCanvasTextExtra* extra; bool collidesWith(const QtCanvasSprite*, const QtCanvasPolygonalItem*, const QtCanvasRectangle*, const QtCanvasEllipse*, const QtCanvasText*) const; }; #endif // QTCANVAS_H nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/decoration/000077500000000000000000000000001455373415500260005ustar00rootroot00000000000000nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/decoration/CMakeLists.txt000066400000000000000000000005401455373415500305370ustar00rootroot00000000000000# Tell CMake to run moc when necessary: set(CMAKE_AUTOMOC ON) # As moc files are generated in the binary dir, tell CMake # to always look for includes there: set(CMAKE_INCLUDE_CURRENT_DIR ON) SET(example_name decoration) SET(KIT_SRCS main.cpp ) ADD_EXECUTABLE(${example_name} ${KIT_SRCS}) TARGET_LINK_LIBRARIES(${example_name} ${PROJECT_NAME}) nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/decoration/decoration.qdoc000066400000000000000000000047351455373415500310100ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ /*! \page qtpropertybrowser-example-decoration.html \title Decoration Example This example demonstrates how to decorate the existing QtDoublePropertyManager class with additional responsibilities. \image decoration.png It also shows how to write respective editor factory for decorated manager by delegating common responsibilities of undecorated base manager to the aggregated QtDoubleSpinBoxFactory member. The source files can be found in examples/decoration directory of the package. */ nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/decoration/main.cpp000066400000000000000000000257241455373415500274420ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #include #include #include #include "qtpropertybrowser.h" #include "qteditorfactory.h" #include "qttreepropertybrowser.h" class DecoratedDoublePropertyManager : public QtDoublePropertyManager { Q_OBJECT public: DecoratedDoublePropertyManager(QObject *parent = 0); ~DecoratedDoublePropertyManager(); QString prefix(const QtProperty *property) const; QString suffix(const QtProperty *property) const; public Q_SLOTS: void setPrefix(QtProperty *property, const QString &prefix); void setSuffix(QtProperty *property, const QString &suffix); Q_SIGNALS: void prefixChanged(QtProperty *property, const QString &prefix); void suffixChanged(QtProperty *property, const QString &suffix); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: struct Data { QString prefix; QString suffix; }; QMap propertyToData; }; DecoratedDoublePropertyManager::DecoratedDoublePropertyManager(QObject *parent) : QtDoublePropertyManager(parent) { } DecoratedDoublePropertyManager::~DecoratedDoublePropertyManager() { } QString DecoratedDoublePropertyManager::prefix(const QtProperty *property) const { if (!propertyToData.contains(property)) return QString(); return propertyToData[property].prefix; } QString DecoratedDoublePropertyManager::suffix(const QtProperty *property) const { if (!propertyToData.contains(property)) return QString(); return propertyToData[property].suffix; } void DecoratedDoublePropertyManager::setPrefix(QtProperty *property, const QString &prefix) { if (!propertyToData.contains(property)) return; DecoratedDoublePropertyManager::Data data = propertyToData[property]; if (data.prefix == prefix) return; data.prefix = prefix; propertyToData[property] = data; emit propertyChanged(property); emit prefixChanged(property, prefix); } void DecoratedDoublePropertyManager::setSuffix(QtProperty *property, const QString &suffix) { if (!propertyToData.contains(property)) return; DecoratedDoublePropertyManager::Data data = propertyToData[property]; if (data.suffix == suffix) return; data.suffix = suffix; propertyToData[property] = data; emit propertyChanged(property); emit suffixChanged(property, suffix); } QString DecoratedDoublePropertyManager::valueText(const QtProperty *property) const { QString text = QtDoublePropertyManager::valueText(property); if (!propertyToData.contains(property)) return text; DecoratedDoublePropertyManager::Data data = propertyToData[property]; text = data.prefix + text + data.suffix; return text; } void DecoratedDoublePropertyManager::initializeProperty(QtProperty *property) { propertyToData[property] = DecoratedDoublePropertyManager::Data(); QtDoublePropertyManager::initializeProperty(property); } void DecoratedDoublePropertyManager::uninitializeProperty(QtProperty *property) { propertyToData.remove(property); QtDoublePropertyManager::uninitializeProperty(property); } class DecoratedDoubleSpinBoxFactory : public QtAbstractEditorFactory { Q_OBJECT public: DecoratedDoubleSpinBoxFactory(QObject *parent = 0); ~DecoratedDoubleSpinBoxFactory(); protected: void connectPropertyManager(DecoratedDoublePropertyManager *manager); QWidget *createEditor(DecoratedDoublePropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(DecoratedDoublePropertyManager *manager); private slots: void slotPrefixChanged(QtProperty *property, const QString &prefix); void slotSuffixChanged(QtProperty *property, const QString &prefix); void slotEditorDestroyed(QObject *object); private: /* We delegate responsibilities for QtDoublePropertyManager, which is a base class of DecoratedDoublePropertyManager to appropriate QtDoubleSpinBoxFactory */ QtDoubleSpinBoxFactory *originalFactory; QMap > createdEditors; QMap editorToProperty; }; DecoratedDoubleSpinBoxFactory::DecoratedDoubleSpinBoxFactory(QObject *parent) : QtAbstractEditorFactory(parent) { originalFactory = new QtDoubleSpinBoxFactory(this); } DecoratedDoubleSpinBoxFactory::~DecoratedDoubleSpinBoxFactory() { // not need to delete editors because they will be deleted by originalFactory in its destructor } void DecoratedDoubleSpinBoxFactory::connectPropertyManager(DecoratedDoublePropertyManager *manager) { originalFactory->addPropertyManager(manager); connect(manager, SIGNAL(prefixChanged(QtProperty *, const QString &)), this, SLOT(slotPrefixChanged(QtProperty *, const QString &))); connect(manager, SIGNAL(suffixChanged(QtProperty *, const QString &)), this, SLOT(slotSuffixChanged(QtProperty *, const QString &))); } QWidget *DecoratedDoubleSpinBoxFactory::createEditor(DecoratedDoublePropertyManager *manager, QtProperty *property, QWidget *parent) { QtAbstractEditorFactoryBase *base = originalFactory; QWidget *w = base->createEditor(property, parent); if (!w) return 0; QDoubleSpinBox *spinBox = qobject_cast(w); if (!spinBox) return 0; spinBox->setPrefix(manager->prefix(property)); spinBox->setSuffix(manager->suffix(property)); createdEditors[property].append(spinBox); editorToProperty[spinBox] = property; return spinBox; } void DecoratedDoubleSpinBoxFactory::disconnectPropertyManager(DecoratedDoublePropertyManager *manager) { originalFactory->removePropertyManager(manager); disconnect(manager, SIGNAL(prefixChanged(QtProperty *, const QString &)), this, SLOT(slotPrefixChanged(QtProperty *, const QString &))); disconnect(manager, SIGNAL(suffixChanged(QtProperty *, const QString &)), this, SLOT(slotSuffixChanged(QtProperty *, const QString &))); } void DecoratedDoubleSpinBoxFactory::slotPrefixChanged(QtProperty *property, const QString &prefix) { if (!createdEditors.contains(property)) return; DecoratedDoublePropertyManager *manager = propertyManager(property); if (!manager) return; QList editors = createdEditors[property]; QListIterator itEditor(editors); while (itEditor.hasNext()) { QDoubleSpinBox *editor = itEditor.next(); editor->setPrefix(prefix); } } void DecoratedDoubleSpinBoxFactory::slotSuffixChanged(QtProperty *property, const QString &prefix) { if (!createdEditors.contains(property)) return; DecoratedDoublePropertyManager *manager = propertyManager(property); if (!manager) return; QList editors = createdEditors[property]; QListIterator itEditor(editors); while (itEditor.hasNext()) { QDoubleSpinBox *editor = itEditor.next(); editor->setSuffix(prefix); } } void DecoratedDoubleSpinBoxFactory::slotEditorDestroyed(QObject *object) { QMap::ConstIterator itEditor = editorToProperty.constBegin(); while (itEditor != editorToProperty.constEnd()) { if (itEditor.key() == object) { QDoubleSpinBox *editor = itEditor.key(); QtProperty *property = itEditor.value(); editorToProperty.remove(editor); createdEditors[property].removeAll(editor); if (createdEditors[property].isEmpty()) createdEditors.remove(property); return; } itEditor++; } } int main(int argc, char **argv) { QApplication app(argc, argv); QtDoublePropertyManager *undecoratedManager = new QtDoublePropertyManager(); QtProperty *undecoratedProperty = undecoratedManager->addProperty("Undecorated"); undecoratedManager->setValue(undecoratedProperty, 123.45); DecoratedDoublePropertyManager *decoratedManager = new DecoratedDoublePropertyManager(); QtProperty *decoratedProperty = decoratedManager->addProperty("Decorated"); decoratedManager->setPrefix(decoratedProperty, "speed: "); decoratedManager->setSuffix(decoratedProperty, " km/h"); decoratedManager->setValue(decoratedProperty, 123.45); QtDoubleSpinBoxFactory *undecoratedFactory = new QtDoubleSpinBoxFactory(); DecoratedDoubleSpinBoxFactory *decoratedFactory = new DecoratedDoubleSpinBoxFactory(); QtTreePropertyBrowser *editor = new QtTreePropertyBrowser(); editor->setFactoryForManager(undecoratedManager, undecoratedFactory); editor->setFactoryForManager(decoratedManager, decoratedFactory); editor->addProperty(undecoratedProperty); editor->addProperty(decoratedProperty); editor->show(); int ret = app.exec(); delete decoratedFactory; delete decoratedManager; delete undecoratedFactory; delete undecoratedManager; delete editor; return ret; } #include "main.moc" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/demo/000077500000000000000000000000001455373415500245755ustar00rootroot00000000000000nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/demo/CMakeLists.txt000066400000000000000000000003751455373415500273420ustar00rootroot00000000000000 SET(example_name demo) SET(KIT_SRCS main.cpp ) SET(KIT_resources demo.qrc ) QT5_ADD_RESOURCES(KIT_QRC_SRCS ${KIT_resources}) ADD_EXECUTABLE(${example_name} ${KIT_SRCS} ${KIT_QRC_SRCS}) TARGET_LINK_LIBRARIES(${example_name} ${PROJECT_NAME}) nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/demo/demo.pro000066400000000000000000000002141455373415500262400ustar00rootroot00000000000000TEMPLATE = app DEPENDPATH += . INCLUDEPATH += . include(../../src/qtpropertybrowser.pri) # Input SOURCES += main.cpp RESOURCES += demo.qrc nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/demo/demo.qdoc000066400000000000000000000051531455373415500263750ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ /*! \page qtpropertybrowser-example-demo.html \title Demo Example This example shows how to customize a property browser widget's appearance and behavior. \image demo.png The various property browsers presented in this example display the same set of properties, and are implementations of the QtTreePropertyBrowser class and the QtGroupBoxPropertyBrowser class, respectively. The example shows how a property browser's appearance and behavior can be varied using the QtPropertyBrowser framework's property managers and editor factories. The source files can be found in examples/demo directory of the package. */ nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/demo/demo.qrc000066400000000000000000000003361455373415500262320ustar00rootroot00000000000000 images/up.png images/down.png images/right.png images/left.png nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/demo/images/000077500000000000000000000000001455373415500260425ustar00rootroot00000000000000nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/demo/images/down.png000066400000000000000000000011221455373415500275130ustar00rootroot00000000000000PNG  IHDRĴl;gAMAOX2tEXtSoftwareAdobe ImageReadyqe<IDAT8O`[i;7̖hB8͋(HH nB#:cƏ9T@<)r/}jKg<}oYt&i)HF%(EF lxO-oxlP3zwQ4M=)칝^4xڽ!ǏC='/hwv9LKVQ=xGXr9:vQ*^vmTb/>ebսu־ϵ _`D*r`:x#P)v2Pqdd܉;#4Mlq3K9lil+RXxؤ*JS8%m1躏<=|ZQ7oJ #tV BIENDB`nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/demo/images/left.png000066400000000000000000000012461455373415500275050ustar00rootroot00000000000000PNG  IHDRĴl;gAMAOX2tEXtSoftwareAdobe ImageReadyqe<8IDAT8ݔAHTQssLDpeJS`[7-+ZedLB$ѪUZ(qe]PaR86ޜ|^upӁ˻{w{=73v|vSnO׀6Қ;ޛ`$@ w zt#I}G3colGz;iO Ɛ4p 65׍ uPl+ x~N`{2UTer:~f%|a~aQP@2{ȩ]'l~ T*U1ȭ˱474x@gL ay)v@%ԩn, FH,ͧVSVYNDχ?85:PՊvx)Q*rlQWDsq68 p$v"7(UԫY(";Dԅ>wXʃZW˅媝gf; M˨9-[څOUR1`XqB[.8^!檀ˑҠj)>@X1?IUjđ`]IENDB`nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/demo/images/right.png000066400000000000000000000012171455373415500276660ustar00rootroot00000000000000PNG  IHDRĴl;gAMAOX2tEXtSoftwareAdobe ImageReadyqe<!IDAT8Mka<ۋ(Ń7?'=AOoKV)mbPjP 1& K#Ҥm-yk2l67y13;pװ.wj]9pj_怊 ~^FDƕJ#0v~+Q3JY` ~" ƀbyERs.xLzF6P0Tj5!'o=nVŁcwbaQ8 cx$"A~ig$]D|?< ρQf+` h[Y? ,QX"BU%Te]VZz (њ)灼b<㲪/'6+mY@6,bnuK/0eeWV+C} ܺ`WM,x4 cT*Jn;cWz~4|zwIENDB`nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/demo/main.cpp000066400000000000000000000231011455373415500262220ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #include #include #include #include #include #include #include "qtpropertymanager.h" #include "qteditorfactory.h" #include "qttreepropertybrowser.h" #include "qtbuttonpropertybrowser.h" #include "qtgroupboxpropertybrowser.h" int main(int argc, char **argv) { QApplication app(argc, argv); QWidget *w = new QWidget(); QtBoolPropertyManager *boolManager = new QtBoolPropertyManager(w); QtIntPropertyManager *intManager = new QtIntPropertyManager(w); QtStringPropertyManager *stringManager = new QtStringPropertyManager(w); QtSizePropertyManager *sizeManager = new QtSizePropertyManager(w); QtRectPropertyManager *rectManager = new QtRectPropertyManager(w); QtSizePolicyPropertyManager *sizePolicyManager = new QtSizePolicyPropertyManager(w); QtEnumPropertyManager *enumManager = new QtEnumPropertyManager(w); QtGroupPropertyManager *groupManager = new QtGroupPropertyManager(w); QtProperty *item0 = groupManager->addProperty("QObject"); QtProperty *item1 = stringManager->addProperty("objectName"); item0->addSubProperty(item1); QtProperty *item2 = boolManager->addProperty("enabled"); item0->addSubProperty(item2); QtProperty *item3 = rectManager->addProperty("geometry"); item0->addSubProperty(item3); QtProperty *item4 = sizePolicyManager->addProperty("sizePolicy"); item0->addSubProperty(item4); QtProperty *item5 = sizeManager->addProperty("sizeIncrement"); item0->addSubProperty(item5); QtProperty *item7 = boolManager->addProperty("mouseTracking"); item0->addSubProperty(item7); QtProperty *item8 = enumManager->addProperty("direction"); QStringList enumNames; enumNames << "Up" << "Right" << "Down" << "Left"; enumManager->setEnumNames(item8, enumNames); QMap enumIcons; enumIcons[0] = QIcon(":/demo/images/up.png"); enumIcons[1] = QIcon(":/demo/images/right.png"); enumIcons[2] = QIcon(":/demo/images/down.png"); enumIcons[3] = QIcon(":/demo/images/left.png"); enumManager->setEnumIcons(item8, enumIcons); item0->addSubProperty(item8); QtProperty *item9 = intManager->addProperty("value"); intManager->setRange(item9, -100, 100); item0->addSubProperty(item9); QtCheckBoxFactory *checkBoxFactory = new QtCheckBoxFactory(w); QtSpinBoxFactory *spinBoxFactory = new QtSpinBoxFactory(w); QtSliderFactory *sliderFactory = new QtSliderFactory(w); QtScrollBarFactory *scrollBarFactory = new QtScrollBarFactory(w); QtLineEditFactory *lineEditFactory = new QtLineEditFactory(w); QtEnumEditorFactory *comboBoxFactory = new QtEnumEditorFactory(w); QtAbstractPropertyBrowser *editor1 = new QtTreePropertyBrowser(); editor1->setFactoryForManager(boolManager, checkBoxFactory); editor1->setFactoryForManager(intManager, spinBoxFactory); editor1->setFactoryForManager(stringManager, lineEditFactory); editor1->setFactoryForManager(sizeManager->subIntPropertyManager(), spinBoxFactory); editor1->setFactoryForManager(rectManager->subIntPropertyManager(), spinBoxFactory); editor1->setFactoryForManager(sizePolicyManager->subIntPropertyManager(), spinBoxFactory); editor1->setFactoryForManager(sizePolicyManager->subEnumPropertyManager(), comboBoxFactory); editor1->setFactoryForManager(enumManager, comboBoxFactory); editor1->addProperty(item0); QtAbstractPropertyBrowser *editor2 = new QtTreePropertyBrowser(); editor2->addProperty(item0); QtAbstractPropertyBrowser *editor3 = new QtGroupBoxPropertyBrowser(); editor3->setFactoryForManager(boolManager, checkBoxFactory); editor3->setFactoryForManager(intManager, spinBoxFactory); editor3->setFactoryForManager(stringManager, lineEditFactory); editor3->setFactoryForManager(sizeManager->subIntPropertyManager(), spinBoxFactory); editor3->setFactoryForManager(rectManager->subIntPropertyManager(), spinBoxFactory); editor3->setFactoryForManager(sizePolicyManager->subIntPropertyManager(), spinBoxFactory); editor3->setFactoryForManager(sizePolicyManager->subEnumPropertyManager(), comboBoxFactory); editor3->setFactoryForManager(enumManager, comboBoxFactory); editor3->addProperty(item0); QScrollArea *scroll3 = new QScrollArea(); scroll3->setWidgetResizable(true); scroll3->setWidget(editor3); QtAbstractPropertyBrowser *editor4 = new QtGroupBoxPropertyBrowser(); editor4->setFactoryForManager(boolManager, checkBoxFactory); editor4->setFactoryForManager(intManager, scrollBarFactory); editor4->setFactoryForManager(stringManager, lineEditFactory); editor4->setFactoryForManager(sizeManager->subIntPropertyManager(), spinBoxFactory); editor4->setFactoryForManager(rectManager->subIntPropertyManager(), spinBoxFactory); editor4->setFactoryForManager(sizePolicyManager->subIntPropertyManager(), sliderFactory); editor4->setFactoryForManager(sizePolicyManager->subEnumPropertyManager(), comboBoxFactory); editor4->setFactoryForManager(enumManager, comboBoxFactory); editor4->addProperty(item0); QScrollArea *scroll4 = new QScrollArea(); scroll4->setWidgetResizable(true); scroll4->setWidget(editor4); QtAbstractPropertyBrowser *editor5 = new QtButtonPropertyBrowser(); editor5->setFactoryForManager(boolManager, checkBoxFactory); editor5->setFactoryForManager(intManager, scrollBarFactory); editor5->setFactoryForManager(stringManager, lineEditFactory); editor5->setFactoryForManager(sizeManager->subIntPropertyManager(), spinBoxFactory); editor5->setFactoryForManager(rectManager->subIntPropertyManager(), spinBoxFactory); editor5->setFactoryForManager(sizePolicyManager->subIntPropertyManager(), sliderFactory); editor5->setFactoryForManager(sizePolicyManager->subEnumPropertyManager(), comboBoxFactory); editor5->setFactoryForManager(enumManager, comboBoxFactory); editor5->addProperty(item0); QScrollArea *scroll5 = new QScrollArea(); scroll5->setWidgetResizable(true); scroll5->setWidget(editor5); QGridLayout *layout = new QGridLayout(w); QLabel *label1 = new QLabel("Editable Tree Property Browser"); QLabel *label2 = new QLabel("Read Only Tree Property Browser, editor factories are not set"); QLabel *label3 = new QLabel("Group Box Property Browser"); QLabel *label4 = new QLabel("Group Box Property Browser with different editor factories"); QLabel *label5 = new QLabel("Button Property Browser"); label1->setWordWrap(true); label2->setWordWrap(true); label3->setWordWrap(true); label4->setWordWrap(true); label5->setWordWrap(true); label1->setFrameShadow(QFrame::Sunken); label2->setFrameShadow(QFrame::Sunken); label3->setFrameShadow(QFrame::Sunken); label4->setFrameShadow(QFrame::Sunken); label5->setFrameShadow(QFrame::Sunken); label1->setFrameShape(QFrame::Panel); label2->setFrameShape(QFrame::Panel); label3->setFrameShape(QFrame::Panel); label4->setFrameShape(QFrame::Panel); label5->setFrameShape(QFrame::Panel); label1->setAlignment(Qt::AlignCenter); label2->setAlignment(Qt::AlignCenter); label3->setAlignment(Qt::AlignCenter); label4->setAlignment(Qt::AlignCenter); label5->setAlignment(Qt::AlignCenter); layout->addWidget(label1, 0, 0); layout->addWidget(label2, 0, 1); layout->addWidget(label3, 0, 2); layout->addWidget(label4, 0, 3); layout->addWidget(label5, 0, 4); layout->addWidget(editor1, 1, 0); layout->addWidget(editor2, 1, 1); layout->addWidget(scroll3, 1, 2); layout->addWidget(scroll4, 1, 3); layout->addWidget(scroll5, 1, 4); w->show(); int ret = app.exec(); delete w; return ret; } nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/examples.pro000066400000000000000000000005001455373415500262040ustar00rootroot00000000000000###################################################################### # Automatically generated by qmake (2.00a) Wed Jun 15 15:53:34 2005 ###################################################################### TEMPLATE = subdirs SUBDIRS = simple canvas_variant canvas_typed demo decoration extension object_controller nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/extension/000077500000000000000000000000001455373415500256655ustar00rootroot00000000000000nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/extension/CMakeLists.txt000066400000000000000000000005401455373415500304240ustar00rootroot00000000000000# Tell CMake to run moc when necessary: set(CMAKE_AUTOMOC ON) # As moc files are generated in the binary dir, tell CMake # to always look for includes there: set(CMAKE_INCLUDE_CURRENT_DIR ON) SET(example_name extension) SET(KIT_SRCS main.cpp ) ADD_EXECUTABLE(${example_name} ${KIT_SRCS}) TARGET_LINK_LIBRARIES(${example_name} ${PROJECT_NAME})nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/extension/extension.pro000066400000000000000000000001671455373415500304270ustar00rootroot00000000000000TEMPLATE = app DEPENDPATH += . INCLUDEPATH += . include(../../src/qtpropertybrowser.pri) # Input SOURCES += main.cpp nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/extension/extension.qdoc000066400000000000000000000045141455373415500305550ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ /*! \page qtpropertybrowser-example-extension.html \title Extension Example This example demonstrates how to extend the QtVariantPropertyManager class to handle additional property types. \image extension.png The variant manager is extended to handle the QPointF type. The source files can be found in examples/extension directory of the package. */ nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/extension/main.cpp000066400000000000000000000175041455373415500273240ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #include #include "qtvariantproperty.h" #include "qteditorfactory.h" #include "qttreepropertybrowser.h" class VariantManager : public QtVariantPropertyManager { Q_OBJECT public: VariantManager(QObject *parent = 0); ~VariantManager(); virtual QVariant value(const QtProperty *property) const; virtual int valueType(int propertyType) const; virtual bool isPropertyTypeSupported(int propertyType) const; QString valueText(const QtProperty *property) const; public slots: virtual void setValue(QtProperty *property, const QVariant &val); protected: virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private slots: void slotValueChanged(QtProperty *property, const QVariant &value); void slotPropertyDestroyed(QtProperty *property); private: struct Data { QVariant value; QtVariantProperty *x; QtVariantProperty *y; }; QMap propertyToData; QMap xToProperty; QMap yToProperty; }; VariantManager::VariantManager(QObject *parent) : QtVariantPropertyManager(parent) { connect(this, SIGNAL(valueChanged(QtProperty *, const QVariant &)), this, SLOT(slotValueChanged(QtProperty *, const QVariant &))); connect(this, SIGNAL(propertyDestroyed(QtProperty *)), this, SLOT(slotPropertyDestroyed(QtProperty *))); } VariantManager::~VariantManager() { } void VariantManager::slotValueChanged(QtProperty *property, const QVariant &value) { if (xToProperty.contains(property)) { QtProperty *pointProperty = xToProperty[property]; QVariant v = this->value(pointProperty); QPointF p = v.value(); p.setX(value.value()); setValue(pointProperty, p); } else if (yToProperty.contains(property)) { QtProperty *pointProperty = yToProperty[property]; QVariant v = this->value(pointProperty); QPointF p = v.value(); p.setY(value.value()); setValue(pointProperty, p); } } void VariantManager::slotPropertyDestroyed(QtProperty *property) { if (xToProperty.contains(property)) { QtProperty *pointProperty = xToProperty[property]; propertyToData[pointProperty].x = 0; xToProperty.remove(property); } else if (yToProperty.contains(property)) { QtProperty *pointProperty = yToProperty[property]; propertyToData[pointProperty].y = 0; yToProperty.remove(property); } } bool VariantManager::isPropertyTypeSupported(int propertyType) const { if (propertyType == QVariant::PointF) return true; return QtVariantPropertyManager::isPropertyTypeSupported(propertyType); } int VariantManager::valueType(int propertyType) const { if (propertyType == QVariant::PointF) return QVariant::PointF; return QtVariantPropertyManager::valueType(propertyType); } QVariant VariantManager::value(const QtProperty *property) const { if (propertyToData.contains(property)) return propertyToData[property].value; return QtVariantPropertyManager::value(property); } QString VariantManager::valueText(const QtProperty *property) const { if (propertyToData.contains(property)) { QVariant v = propertyToData[property].value; QPointF p = v.value(); return QString(tr("(%1, %2)").arg(QString::number(p.x())) .arg(QString::number(p.y()))); } return QtVariantPropertyManager::valueText(property); } void VariantManager::setValue(QtProperty *property, const QVariant &val) { if (propertyToData.contains(property)) { if (val.type() != QVariant::PointF && !val.canConvert(QVariant::PointF)) return; QPointF p = val.value(); Data d = propertyToData[property]; d.value = p; if (d.x) d.x->setValue(p.x()); if (d.y) d.y->setValue(p.y()); propertyToData[property] = d; emit propertyChanged(property); emit valueChanged(property, p); return; } QtVariantPropertyManager::setValue(property, val); } void VariantManager::initializeProperty(QtProperty *property) { if (propertyType(property) == QVariant::PointF) { Data d; d.value = QPointF(0, 0); VariantManager *that = (VariantManager *)this; d.x = that->addProperty(QVariant::Double); d.x->setPropertyName(tr("Position X")); property->addSubProperty(d.x); xToProperty[d.x] = property; d.y = that->addProperty(QVariant::Double); d.y->setPropertyName(tr("Position Y")); property->addSubProperty(d.y); yToProperty[d.y] = property; propertyToData[property] = d; } QtVariantPropertyManager::initializeProperty(property); } void VariantManager::uninitializeProperty(QtProperty *property) { if (propertyToData.contains(property)) { Data d = propertyToData[property]; if (d.x) xToProperty.remove(d.x); if (d.y) yToProperty.remove(d.y); propertyToData.remove(property); } QtVariantPropertyManager::uninitializeProperty(property); } int main(int argc, char **argv) { QApplication app(argc, argv); VariantManager *variantManager = new VariantManager(); QtVariantProperty *item = variantManager->addProperty(QVariant::PointF, "PointF Property"); item->setValue(QPointF(2.5, 13.13)); QtVariantEditorFactory *variantFactory = new QtVariantEditorFactory(); QtTreePropertyBrowser ed1; QtVariantPropertyManager *varMan = variantManager; ed1.setFactoryForManager(varMan, variantFactory); ed1.addProperty(item); ed1.show(); int ret = app.exec(); delete variantFactory; delete variantManager; return ret; } #include "main.moc" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/object_controller/000077500000000000000000000000001455373415500273625ustar00rootroot00000000000000nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/object_controller/CMakeLists.txt000066400000000000000000000005771455373415500321330ustar00rootroot00000000000000# Tell CMake to run moc when necessary: set(CMAKE_AUTOMOC ON) # As moc files are generated in the binary dir, tell CMake # to always look for includes there: set(CMAKE_INCLUDE_CURRENT_DIR ON) SET(example_name object_controller) SET(KIT_SRCS main.cpp objectcontroller.cpp ) ADD_EXECUTABLE(${example_name} ${KIT_SRCS}) TARGET_LINK_LIBRARIES(${example_name} ${PROJECT_NAME})nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/object_controller/main.cpp000066400000000000000000000133711455373415500310170ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "objectcontroller.h" class MyController : public QDialog { Q_OBJECT public: MyController(QWidget *parent = 0); ~MyController(); private slots: void createAndControl(); private: QComboBox *theClassCombo; ObjectController *theController; QStringList theClassNames; QObject *theControlledObject; }; MyController::MyController(QWidget *parent) : QDialog(parent), theControlledObject(0) { theClassCombo = new QComboBox(this); QToolButton *button = new QToolButton(this); theController = new ObjectController(this); QDialogButtonBox *buttonBox = new QDialogButtonBox(this); connect(button, SIGNAL(clicked()), this, SLOT(createAndControl())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); button->setText(tr("Create And Control")); buttonBox->setStandardButtons(QDialogButtonBox::Close); QVBoxLayout *layout = new QVBoxLayout(this); QHBoxLayout *internalLayout = new QHBoxLayout(); internalLayout->addWidget(theClassCombo); internalLayout->addWidget(button); layout->addLayout(internalLayout); layout->addWidget(theController); layout->addWidget(buttonBox); theClassNames.append(QLatin1String("QWidget")); theClassNames.append(QLatin1String("QPushButton")); theClassNames.append(QLatin1String("QDialogButtonBox")); theClassNames.append(QLatin1String("QTreeWidget")); theClassNames.append(QLatin1String("QCalendarWidget")); theClassNames.append(QLatin1String("QAction")); theClassNames.append(QLatin1String("QTimeLine")); theClassNames.append(QLatin1String("QTextDocument")); theClassCombo->addItems(theClassNames); } MyController::~MyController() { if (theControlledObject) delete theControlledObject; } void MyController::createAndControl() { QObject *newObject = 0; QString className = theClassNames.at(theClassCombo->currentIndex()); if (className == QLatin1String("QWidget")) newObject = new QWidget(); else if (className == QLatin1String("QPushButton")) newObject = new QPushButton(); else if (className == QLatin1String("QDialogButtonBox")) newObject = new QDialogButtonBox(); else if (className == QLatin1String("QTreeWidget")) newObject = new QTreeWidget(); else if (className == QLatin1String("QCalendarWidget")) newObject = new QCalendarWidget(); else if (className == QLatin1String("QAction")) newObject = new QAction(0); else if (className == QLatin1String("QTimeLine")) newObject = new QTimeLine(); else if (className == QLatin1String("QTextDocument")) newObject = new QTextDocument(); if (!newObject) return; QWidget *newWidget = qobject_cast(newObject); if (newWidget) { QRect r = newWidget->geometry(); r.setSize(newWidget->sizeHint()); r.setWidth(qMax(r.width(), 150)); r.setHeight(qMax(r.height(), 50)); r.moveCenter(QApplication::desktop()->geometry().center()); newWidget->setGeometry(r); newWidget->setWindowTitle(tr("Controlled Object: %1").arg(className)); newWidget->show(); } if (theControlledObject) delete theControlledObject; theControlledObject = newObject; theController->setObject(theControlledObject); } int main(int argc, char **argv) { QApplication app(argc, argv); MyController *controller = new MyController(); controller->show(); int ret = app.exec(); return ret; } #include "main.moc" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/object_controller/object_controller.qdoc000066400000000000000000000052541455373415500337510ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ /*! \page qtpropertybrowser-example-object_controller.html \title The Object Controller Example. \image object_controller.png This example implements a simple widget component which shows QObject's and its subclasses' properties. The user can modify these properies interacively and the object controller applies the changes to the controlled object. The object controller is similar to the property editor used in QDesigner application. To control the object just instantiate ObjectController, set controlled object (any QObject subclass) by calling ObjectController::setObject() and show the controller. The source files can be found in examples/object_controller directory of the package. */ nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/object_controller/objectcontroller.cpp000066400000000000000000000343451455373415500334510ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #include #include #include #include #include "objectcontroller.h" #include "qtvariantproperty.h" #include "qtgroupboxpropertybrowser.h" #include "qttreepropertybrowser.h" #include "qtpropertybrowser.h" class ObjectControllerPrivate { ObjectController *q_ptr; Q_DECLARE_PUBLIC(ObjectController) public: void addClassProperties(const QMetaObject *metaObject); void updateClassProperties(const QMetaObject *metaObject, bool recursive); void saveExpandedState(); void restoreExpandedState(); void slotValueChanged(QtProperty *property, const QVariant &value); int enumToInt(const QMetaEnum &metaEnum, int enumValue) const; int intToEnum(const QMetaEnum &metaEnum, int intValue) const; int flagToInt(const QMetaEnum &metaEnum, int flagValue) const; int intToFlag(const QMetaEnum &metaEnum, int intValue) const; bool isSubValue(int value, int subValue) const; bool isPowerOf2(int value) const; QObject *m_object; QMap m_classToProperty; QMap m_propertyToClass; QMap m_propertyToIndex; QMap > m_classToIndexToProperty; QMap m_propertyToExpanded; QList m_topLevelProperties; QtAbstractPropertyBrowser *m_browser; QtVariantPropertyManager *m_manager; QtVariantPropertyManager *m_readOnlyManager; }; int ObjectControllerPrivate::enumToInt(const QMetaEnum &metaEnum, int enumValue) const { QMap valueMap; // dont show multiple enum values which have the same values int pos = 0; for (int i = 0; i < metaEnum.keyCount(); i++) { int value = metaEnum.value(i); if (!valueMap.contains(value)) { if (value == enumValue) return pos; valueMap[value] = pos++; } } return -1; } int ObjectControllerPrivate::intToEnum(const QMetaEnum &metaEnum, int intValue) const { QMap valueMap; // dont show multiple enum values which have the same values QList values; for (int i = 0; i < metaEnum.keyCount(); i++) { int value = metaEnum.value(i); if (!valueMap.contains(value)) { valueMap[value] = true; values.append(value); } } if (intValue >= values.count()) return -1; return values.at(intValue); } bool ObjectControllerPrivate::isSubValue(int value, int subValue) const { if (value == subValue) return true; int i = 0; while (subValue) { if (!(value & (1 << i))) { if (subValue & 1) return false; } i++; subValue = subValue >> 1; } return true; } bool ObjectControllerPrivate::isPowerOf2(int value) const { while (value) { if (value & 1) { return value == 1; } value = value >> 1; } return false; } int ObjectControllerPrivate::flagToInt(const QMetaEnum &metaEnum, int flagValue) const { if (!flagValue) return 0; int intValue = 0; QMap valueMap; // dont show multiple enum values which have the same values int pos = 0; for (int i = 0; i < metaEnum.keyCount(); i++) { int value = metaEnum.value(i); if (!valueMap.contains(value) && isPowerOf2(value)) { if (isSubValue(flagValue, value)) intValue |= (1 << pos); valueMap[value] = pos++; } } return intValue; } int ObjectControllerPrivate::intToFlag(const QMetaEnum &metaEnum, int intValue) const { QMap valueMap; // dont show multiple enum values which have the same values QList values; for (int i = 0; i < metaEnum.keyCount(); i++) { int value = metaEnum.value(i); if (!valueMap.contains(value) && isPowerOf2(value)) { valueMap[value] = true; values.append(value); } } int flagValue = 0; int temp = intValue; int i = 0; while (temp) { if (i >= values.count()) return -1; if (temp & 1) flagValue |= values.at(i); i++; temp = temp >> 1; } return flagValue; } void ObjectControllerPrivate::updateClassProperties(const QMetaObject *metaObject, bool recursive) { if (!metaObject) return; if (recursive) updateClassProperties(metaObject->superClass(), recursive); QtProperty *classProperty = m_classToProperty.value(metaObject); if (!classProperty) return; for (int idx = metaObject->propertyOffset(); idx < metaObject->propertyCount(); idx++) { QMetaProperty metaProperty = metaObject->property(idx); if (metaProperty.isReadable()) { if (m_classToIndexToProperty.contains(metaObject) && m_classToIndexToProperty[metaObject].contains(idx)) { QtVariantProperty *subProperty = m_classToIndexToProperty[metaObject][idx]; if (metaProperty.isEnumType()) { if (metaProperty.isFlagType()) subProperty->setValue(flagToInt(metaProperty.enumerator(), metaProperty.read(m_object).toInt())); else subProperty->setValue(enumToInt(metaProperty.enumerator(), metaProperty.read(m_object).toInt())); } else { subProperty->setValue(metaProperty.read(m_object)); } } } } } void ObjectControllerPrivate::addClassProperties(const QMetaObject *metaObject) { if (!metaObject) return; addClassProperties(metaObject->superClass()); QtProperty *classProperty = m_classToProperty.value(metaObject); if (!classProperty) { QString className = QLatin1String(metaObject->className()); classProperty = m_manager->addProperty(QtVariantPropertyManager::groupTypeId(), className); m_classToProperty[metaObject] = classProperty; m_propertyToClass[classProperty] = metaObject; for (int idx = metaObject->propertyOffset(); idx < metaObject->propertyCount(); idx++) { QMetaProperty metaProperty = metaObject->property(idx); int type = metaProperty.userType(); QtVariantProperty *subProperty = 0; if (!metaProperty.isReadable()) { subProperty = m_readOnlyManager->addProperty(QVariant::String, QLatin1String(metaProperty.name())); subProperty->setValue(QLatin1String("< Non Readable >")); } else if (metaProperty.isEnumType()) { if (metaProperty.isFlagType()) { subProperty = m_manager->addProperty(QtVariantPropertyManager::flagTypeId(), QLatin1String(metaProperty.name())); QMetaEnum metaEnum = metaProperty.enumerator(); QMap valueMap; QStringList flagNames; for (int i = 0; i < metaEnum.keyCount(); i++) { int value = metaEnum.value(i); if (!valueMap.contains(value) && isPowerOf2(value)) { valueMap[value] = true; flagNames.append(QLatin1String(metaEnum.key(i))); } subProperty->setAttribute(QLatin1String("flagNames"), flagNames); subProperty->setValue(flagToInt(metaEnum, metaProperty.read(m_object).toInt())); } } else { subProperty = m_manager->addProperty(QtVariantPropertyManager::enumTypeId(), QLatin1String(metaProperty.name())); QMetaEnum metaEnum = metaProperty.enumerator(); QMap valueMap; // dont show multiple enum values which have the same values QStringList enumNames; for (int i = 0; i < metaEnum.keyCount(); i++) { int value = metaEnum.value(i); if (!valueMap.contains(value)) { valueMap[value] = true; enumNames.append(QLatin1String(metaEnum.key(i))); } } subProperty->setAttribute(QLatin1String("enumNames"), enumNames); subProperty->setValue(enumToInt(metaEnum, metaProperty.read(m_object).toInt())); } } else if (m_manager->isPropertyTypeSupported(type)) { if (!metaProperty.isWritable()) subProperty = m_readOnlyManager->addProperty(type, QLatin1String(metaProperty.name()) + QLatin1String(" (Non Writable)")); if (!metaProperty.isDesignable()) subProperty = m_readOnlyManager->addProperty(type, QLatin1String(metaProperty.name()) + QLatin1String(" (Non Designable)")); else subProperty = m_manager->addProperty(type, QLatin1String(metaProperty.name())); subProperty->setValue(metaProperty.read(m_object)); } else { subProperty = m_readOnlyManager->addProperty(QVariant::String, QLatin1String(metaProperty.name())); subProperty->setValue(QLatin1String("< Unknown Type >")); subProperty->setEnabled(false); } classProperty->addSubProperty(subProperty); m_propertyToIndex[subProperty] = idx; m_classToIndexToProperty[metaObject][idx] = subProperty; } } else { updateClassProperties(metaObject, false); } m_topLevelProperties.append(classProperty); m_browser->addProperty(classProperty); } void ObjectControllerPrivate::saveExpandedState() { } void ObjectControllerPrivate::restoreExpandedState() { } void ObjectControllerPrivate::slotValueChanged(QtProperty *property, const QVariant &value) { if (!m_propertyToIndex.contains(property)) return; int idx = m_propertyToIndex.value(property); const QMetaObject *metaObject = m_object->metaObject(); QMetaProperty metaProperty = metaObject->property(idx); if (metaProperty.isEnumType()) { if (metaProperty.isFlagType()) metaProperty.write(m_object, intToFlag(metaProperty.enumerator(), value.toInt())); else metaProperty.write(m_object, intToEnum(metaProperty.enumerator(), value.toInt())); } else { metaProperty.write(m_object, value); } updateClassProperties(metaObject, true); } /////////////////// ObjectController::ObjectController(QWidget *parent) : QWidget(parent) { d_ptr = new ObjectControllerPrivate; d_ptr->q_ptr = this; d_ptr->m_object = 0; /* QScrollArea *scroll = new QScrollArea(this); scroll->setWidgetResizable(true); d_ptr->m_browser = new QtGroupBoxPropertyBrowser(this); QVBoxLayout *layout = new QVBoxLayout(this); layout->setMargin(0); layout->addWidget(scroll); scroll->setWidget(d_ptr->m_browser); */ QtTreePropertyBrowser *browser = new QtTreePropertyBrowser(this); browser->setRootIsDecorated(false); d_ptr->m_browser = browser; QVBoxLayout *layout = new QVBoxLayout(this); layout->setMargin(0); layout->addWidget(d_ptr->m_browser); d_ptr->m_readOnlyManager = new QtVariantPropertyManager(this); d_ptr->m_manager = new QtVariantPropertyManager(this); QtVariantEditorFactory *factory = new QtVariantEditorFactory(this); d_ptr->m_browser->setFactoryForManager(d_ptr->m_manager, factory); connect(d_ptr->m_manager, SIGNAL(valueChanged(QtProperty *, const QVariant &)), this, SLOT(slotValueChanged(QtProperty *, const QVariant &))); } ObjectController::~ObjectController() { delete d_ptr; } void ObjectController::setObject(QObject *object) { if (d_ptr->m_object == object) return; if (d_ptr->m_object) { d_ptr->saveExpandedState(); QListIterator it(d_ptr->m_topLevelProperties); while (it.hasNext()) { d_ptr->m_browser->removeProperty(it.next()); } d_ptr->m_topLevelProperties.clear(); } d_ptr->m_object = object; if (!d_ptr->m_object) return; d_ptr->addClassProperties(d_ptr->m_object->metaObject()); d_ptr->restoreExpandedState(); } QObject *ObjectController::object() const { return d_ptr->m_object; } #include "moc_objectcontroller.cpp" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/object_controller/objectcontroller.h000066400000000000000000000047241455373415500331140ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #ifndef OBJECTCONTROLLER_H #define OBJECTCONTROLLER_H #include class ObjectControllerPrivate; class ObjectController : public QWidget { Q_OBJECT public: ObjectController(QWidget *parent = 0); ~ObjectController(); void setObject(QObject *object); QObject *object() const; private: ObjectControllerPrivate *d_ptr; Q_DECLARE_PRIVATE(ObjectController) Q_DISABLE_COPY(ObjectController) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QVariant &)) }; #endif nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/simple/000077500000000000000000000000001455373415500251425ustar00rootroot00000000000000nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/simple/CMakeLists.txt000066400000000000000000000002341455373415500277010ustar00rootroot00000000000000SET(example_name simple) SET(KIT_SRCS main.cpp ) ADD_EXECUTABLE(${example_name} ${KIT_SRCS}) TARGET_LINK_LIBRARIES(${example_name} ${PROJECT_NAME}) nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/simple/main.cpp000066400000000000000000000201421455373415500265710ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #include #include #include #include "qtpropertymanager.h" #include "qtvariantproperty.h" #include "qttreepropertybrowser.h" int main(int argc, char **argv) { QApplication app(argc, argv); QtVariantPropertyManager *variantManager = new QtVariantPropertyManager(); int i = 0; QtProperty *topItem = variantManager->addProperty(QtVariantPropertyManager::groupTypeId(), QString::number(i++) + QLatin1String(" Group Property")); QtVariantProperty *item = variantManager->addProperty(QVariant::Bool, QString::number(i++) + QLatin1String(" Bool Property")); item->setValue(true); topItem->addSubProperty(item); item = variantManager->addProperty(QVariant::Int, QString::number(i++) + QLatin1String(" Int Property")); item->setValue(20); item->setAttribute(QLatin1String("minimum"), 0); item->setAttribute(QLatin1String("maximum"), 100); item->setAttribute(QLatin1String("singleStep"), 10); topItem->addSubProperty(item); item = variantManager->addProperty(QVariant::Double, QString::number(i++) + QLatin1String(" Double Property")); item->setValue(1.2345); item->setAttribute(QLatin1String("singleStep"), 0.1); item->setAttribute(QLatin1String("decimals"), 3); topItem->addSubProperty(item); item = variantManager->addProperty(QVariant::String, QString::number(i++) + QLatin1String(" String Property")); item->setValue("Value"); topItem->addSubProperty(item); item = variantManager->addProperty(QVariant::Date, QString::number(i++) + QLatin1String(" Date Property")); item->setValue(QDate::currentDate().addDays(2)); topItem->addSubProperty(item); item = variantManager->addProperty(QVariant::Time, QString::number(i++) + QLatin1String(" Time Property")); item->setValue(QTime::currentTime()); topItem->addSubProperty(item); item = variantManager->addProperty(QVariant::DateTime, QString::number(i++) + QLatin1String(" DateTime Property")); item->setValue(QDateTime::currentDateTime()); topItem->addSubProperty(item); item = variantManager->addProperty(QVariant::KeySequence, QString::number(i++) + QLatin1String(" KeySequence Property")); item->setValue(QKeySequence(Qt::ControlModifier | Qt::Key_Q)); topItem->addSubProperty(item); item = variantManager->addProperty(QVariant::Char, QString::number(i++) + QLatin1String(" Char Property")); item->setValue(QChar(386)); topItem->addSubProperty(item); item = variantManager->addProperty(QVariant::Locale, QString::number(i++) + QLatin1String(" Locale Property")); item->setValue(QLocale(QLocale::Polish, QLocale::Poland)); topItem->addSubProperty(item); item = variantManager->addProperty(QVariant::Point, QString::number(i++) + QLatin1String(" Point Property")); item->setValue(QPoint(10, 10)); topItem->addSubProperty(item); item = variantManager->addProperty(QVariant::PointF, QString::number(i++) + QLatin1String(" PointF Property")); item->setValue(QPointF(1.2345, -1.23451)); item->setAttribute(QLatin1String("decimals"), 3); topItem->addSubProperty(item); item = variantManager->addProperty(QVariant::Size, QString::number(i++) + QLatin1String(" Size Property")); item->setValue(QSize(20, 20)); item->setAttribute(QLatin1String("minimum"), QSize(10, 10)); item->setAttribute(QLatin1String("maximum"), QSize(30, 30)); topItem->addSubProperty(item); item = variantManager->addProperty(QVariant::SizeF, QString::number(i++) + QLatin1String(" SizeF Property")); item->setValue(QSizeF(1.2345, 1.2345)); item->setAttribute(QLatin1String("decimals"), 3); item->setAttribute(QLatin1String("minimum"), QSizeF(0.12, 0.34)); item->setAttribute(QLatin1String("maximum"), QSizeF(20.56, 20.78)); topItem->addSubProperty(item); item = variantManager->addProperty(QVariant::Rect, QString::number(i++) + QLatin1String(" Rect Property")); item->setValue(QRect(10, 10, 20, 20)); topItem->addSubProperty(item); item->setAttribute(QLatin1String("constraint"), QRect(0, 0, 50, 50)); item = variantManager->addProperty(QVariant::RectF, QString::number(i++) + QLatin1String(" RectF Property")); item->setValue(QRectF(1.2345, 1.2345, 1.2345, 1.2345)); topItem->addSubProperty(item); item->setAttribute(QLatin1String("constraint"), QRectF(0, 0, 50, 50)); item->setAttribute(QLatin1String("decimals"), 3); item = variantManager->addProperty(QtVariantPropertyManager::enumTypeId(), QString::number(i++) + QLatin1String(" Enum Property")); QStringList enumNames; enumNames << "Enum0" << "Enum1" << "Enum2"; item->setAttribute(QLatin1String("enumNames"), enumNames); item->setValue(1); topItem->addSubProperty(item); item = variantManager->addProperty(QtVariantPropertyManager::flagTypeId(), QString::number(i++) + QLatin1String(" Flag Property")); QStringList flagNames; flagNames << "Flag0" << "Flag1" << "Flag2"; item->setAttribute(QLatin1String("flagNames"), flagNames); item->setValue(5); topItem->addSubProperty(item); item = variantManager->addProperty(QVariant::SizePolicy, QString::number(i++) + QLatin1String(" SizePolicy Property")); topItem->addSubProperty(item); item = variantManager->addProperty(QVariant::Font, QString::number(i++) + QLatin1String(" Font Property")); topItem->addSubProperty(item); item = variantManager->addProperty(QVariant::Cursor, QString::number(i++) + QLatin1String(" Cursor Property")); topItem->addSubProperty(item); item = variantManager->addProperty(QVariant::Color, QString::number(i++) + QLatin1String(" Color Property")); topItem->addSubProperty(item); QtVariantEditorFactory *variantFactory = new QtVariantEditorFactory(); QtTreePropertyBrowser *variantEditor = new QtTreePropertyBrowser(); variantEditor->setFactoryForManager(variantManager, variantFactory); variantEditor->addProperty(topItem); variantEditor->setPropertiesWithoutValueMarked(true); variantEditor->setRootIsDecorated(false); variantEditor->show(); int ret = app.exec(); delete variantManager; delete variantFactory; delete variantEditor; return ret; } nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/examples/simple/simple.qdoc000066400000000000000000000044771455373415500273170ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ /*! \page qtpropertybrowser-example-simple.html \title Simple Tree Property Browser Example \image simple.png This example shows how to present various properties using a simple tree property browser, i.e. an implementation of the QtTreePropertyBrowser class. The source files can be found in examples/simple directory of the package. */ nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/000077500000000000000000000000001455373415500226225ustar00rootroot00000000000000nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/CMakeLists.txt000066400000000000000000000014561455373415500253700ustar00rootroot00000000000000# Tell CMake to run moc when necessary: set(CMAKE_AUTOMOC ON) # As moc files are generated in the binary dir, tell CMake # to always look for includes there: set(CMAKE_INCLUDE_CURRENT_DIR ON) set(_SRCS qtbuttonpropertybrowser.cpp qteditorfactory.cpp qtgroupboxpropertybrowser.cpp qtpropertybrowser.cpp qtpropertybrowserutils.cpp qtpropertymanager.cpp qttreepropertybrowser.cpp qtvariantproperty.cpp ) set(_UI_FORMS ) set(_RESOURCES qtpropertybrowser.qrc ) QT5_WRAP_UI(_UI_SRCS ${_UI_FORMS}) QT5_ADD_RESOURCES(_QRC_SRCS ${_RESOURCES}) set(TARGET_NAME ${PROJECT_NAME}) add_library(${TARGET_NAME} STATIC ${_SRCS} ${_UI_SRCS} ${_QRC_SRCS} ) if (MSVC) target_compile_options(${TARGET_NAME} PRIVATE /wd4457 /wd4718) endif() target_link_libraries(${TARGET_NAME} Qt5::Widgets) nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtAbstractEditorFactoryBase000066400000000000000000000000371455373415500301070ustar00rootroot00000000000000#include "qtpropertybrowser.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtAbstractPropertyBrowser000066400000000000000000000000371455373415500277260ustar00rootroot00000000000000#include "qtpropertybrowser.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtAbstractPropertyManager000066400000000000000000000000371455373415500276550ustar00rootroot00000000000000#include "qtpropertybrowser.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtBoolPropertyManager000066400000000000000000000000371455373415500270050ustar00rootroot00000000000000#include "qtpropertymanager.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtBrowserItem000066400000000000000000000000371455373415500253140ustar00rootroot00000000000000#include "qtpropertybrowser.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtButtonPropertyBrowser000066400000000000000000000000451455373415500274350ustar00rootroot00000000000000#include "qtbuttonpropertybrowser.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtCharEditorFactory000066400000000000000000000000351455373415500264240ustar00rootroot00000000000000#include "qteditorfactory.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtCharPropertyManager000066400000000000000000000000371455373415500267670ustar00rootroot00000000000000#include "qtpropertymanager.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtCheckBoxFactory000066400000000000000000000000351455373415500260660ustar00rootroot00000000000000#include "qteditorfactory.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtColorEditorFactory000066400000000000000000000000351455373415500266250ustar00rootroot00000000000000#include "qteditorfactory.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtColorPropertyManager000066400000000000000000000000371455373415500271700ustar00rootroot00000000000000#include "qtpropertymanager.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtCursorEditorFactory000066400000000000000000000000351455373415500270240ustar00rootroot00000000000000#include "qteditorfactory.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtCursorPropertyManager000066400000000000000000000000371455373415500273670ustar00rootroot00000000000000#include "qtpropertymanager.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtDateEditFactory000066400000000000000000000000351455373415500260630ustar00rootroot00000000000000#include "qteditorfactory.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtDatePropertyManager000066400000000000000000000000371455373415500267670ustar00rootroot00000000000000#include "qtpropertymanager.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtDateTimeEditFactory000066400000000000000000000000351455373415500267020ustar00rootroot00000000000000#include "qteditorfactory.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtDateTimePropertyManager000066400000000000000000000000371455373415500276060ustar00rootroot00000000000000#include "qtpropertymanager.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtDoublePropertyManager000066400000000000000000000000371455373415500273240ustar00rootroot00000000000000#include "qtpropertymanager.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtDoubleSpinBoxFactory000066400000000000000000000000351455373415500271150ustar00rootroot00000000000000#include "qteditorfactory.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtEnumEditorFactory000066400000000000000000000000351455373415500264530ustar00rootroot00000000000000#include "qteditorfactory.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtEnumPropertyManager000066400000000000000000000000371455373415500270160ustar00rootroot00000000000000#include "qtpropertymanager.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtFlagPropertyManager000066400000000000000000000000371455373415500267630ustar00rootroot00000000000000#include "qtpropertymanager.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtFontEditorFactory000066400000000000000000000000351455373415500264550ustar00rootroot00000000000000#include "qteditorfactory.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtFontPropertyManager000066400000000000000000000000371455373415500270200ustar00rootroot00000000000000#include "qtpropertymanager.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtGroupBoxPropertyBrowser000066400000000000000000000000471455373415500277310ustar00rootroot00000000000000#include "qtgroupboxpropertybrowser.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtGroupPropertyManager000066400000000000000000000000371455373415500272060ustar00rootroot00000000000000#include "qtpropertymanager.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtIntPropertyManager000066400000000000000000000000371455373415500266440ustar00rootroot00000000000000#include "qtpropertymanager.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtKeySequenceEditorFactory000066400000000000000000000000351455373415500277700ustar00rootroot00000000000000#include "qteditorfactory.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtKeySequencePropertyManager000066400000000000000000000000371455373415500303330ustar00rootroot00000000000000#include "qtpropertymanager.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtLineEditFactory000066400000000000000000000000351455373415500260750ustar00rootroot00000000000000#include "qteditorfactory.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtLocalePropertyManager000066400000000000000000000000371455373415500273110ustar00rootroot00000000000000#include "qtpropertymanager.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtPointFPropertyManager000066400000000000000000000000371455373415500273110ustar00rootroot00000000000000#include "qtpropertymanager.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtPointPropertyManager000066400000000000000000000000371455373415500272030ustar00rootroot00000000000000#include "qtpropertymanager.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtProperty000066400000000000000000000000371455373415500246760ustar00rootroot00000000000000#include "qtpropertybrowser.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtRectFPropertyManager000066400000000000000000000000371455373415500271150ustar00rootroot00000000000000#include "qtpropertymanager.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtRectPropertyManager000066400000000000000000000000371455373415500270070ustar00rootroot00000000000000#include "qtpropertymanager.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtScrollBarFactory000066400000000000000000000000351455373415500262630ustar00rootroot00000000000000#include "qteditorfactory.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtSizeFPropertyManager000066400000000000000000000000371455373415500271320ustar00rootroot00000000000000#include "qtpropertymanager.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtSizePolicyPropertyManager000066400000000000000000000000371455373415500302040ustar00rootroot00000000000000#include "qtpropertymanager.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtSizePropertyManager000066400000000000000000000000371455373415500270240ustar00rootroot00000000000000#include "qtpropertymanager.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtSliderFactory000066400000000000000000000000351455373415500256220ustar00rootroot00000000000000#include "qteditorfactory.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtSpinBoxFactory000066400000000000000000000000351455373415500257620ustar00rootroot00000000000000#include "qteditorfactory.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtStringPropertyManager000066400000000000000000000000371455373415500273600ustar00rootroot00000000000000#include "qtpropertymanager.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtTimeEditFactory000066400000000000000000000000351455373415500261040ustar00rootroot00000000000000#include "qteditorfactory.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtTimePropertyManager000066400000000000000000000000371455373415500270100ustar00rootroot00000000000000#include "qtpropertymanager.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtTreePropertyBrowser000066400000000000000000000000431455373415500270570ustar00rootroot00000000000000#include "qttreepropertybrowser.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtVariantEditorFactory000066400000000000000000000000371455373415500271550ustar00rootroot00000000000000#include "qtvariantproperty.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtVariantProperty000066400000000000000000000000371455373415500262230ustar00rootroot00000000000000#include "qtvariantproperty.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/QtVariantPropertyManager000066400000000000000000000000371455373415500275160ustar00rootroot00000000000000#include "qtvariantproperty.h" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/images/000077500000000000000000000000001455373415500240675ustar00rootroot00000000000000nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/images/cursor-arrow.png000066400000000000000000000002531455373415500272420ustar00rootroot00000000000000PNG  IHDRm PLTEtRNS@fPIDATx^=α 0 ѤA"9Oh؁-k^cK?m :V-@Gêeΰqo_NpoYք^]IuZIENDB`nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/images/cursor-busy.png000066400000000000000000000003111455373415500270650ustar00rootroot00000000000000PNG  IHDR g PLTE~OtRNS@fnIDATx^ͱ 0P ~)~6idJWO.l(@ X`@ tJ!9l&aqlQ] ~#-搫I 8{4u4IENDB`nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/images/cursor-closedhand.png000066400000000000000000000002231455373415500302110ustar00rootroot00000000000000PNG  IHDR7 pHYs 7˭EIDAT(ϭ D-$pzS逢B@@r(2`' ـM^ PIENDB`nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/images/cursor-cross.png000066400000000000000000000002021455373415500272330ustar00rootroot00000000000000PNG  IHDRm PLTEtRNS@f'IDATc`  P Vpm=XK "IENDB`nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/images/cursor-forbidden.png000066400000000000000000000003071455373415500300440ustar00rootroot00000000000000PNG  IHDRm PLTEtRNS@flIDATx^uα C1P y \`4.L`"EB \RAc!OҾU+2ֵ_d\l+ Zz<'r:#7$/sIENDB`nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/images/cursor-hand.png000066400000000000000000000002371455373415500270240ustar00rootroot00000000000000PNG  IHDRm PLTEtRNS@fDIDAT[c``aL(=XzjБ JcZd N Ѫf @&ЫV-J7U%IENDB`nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/images/cursor-hsplit.png000066400000000000000000000002331455373415500274110ustar00rootroot00000000000000PNG  IHDRm PLTE~OtRNS@f@IDATc`..@ ͡TY;AӀtS`` e Cap0 w/PܪIENDB`nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/images/cursor-ibeam.png000066400000000000000000000001741455373415500271670ustar00rootroot00000000000000PNG  IHDRm PLTE~OtRNS@f!IDATc`"`*@340܇^TIENDB`nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/images/cursor-openhand.png000066400000000000000000000002401455373415500277000ustar00rootroot00000000000000PNG  IHDR7 pHYs 7˭RIDAT(υ_tW&DNt^a'`O#9#V*~Wa`'-$2d_=J;Ҁ>x0tbIENDB`nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/images/cursor-sizeall.png000066400000000000000000000002561455373415500275560ustar00rootroot00000000000000PNG  IHDRm PLTE~OtRNS@fSIDAT[c`\ f^5P00:H0:%BD&pÁ f/0watêNXIENDB`nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/images/cursor-sizeb.png000066400000000000000000000002411455373415500272210ustar00rootroot00000000000000PNG  IHDRm PLTE~OtRNS@fFIDATc` VjSC!*ҌPJBN1 D`uN:5J@(ƀbv l= jIENDB`nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/images/cursor-sizef.png000066400000000000000000000002411455373415500272250ustar00rootroot00000000000000PNG  IHDRm PLTE~OtRNS@fFIDATc` VjSCtD|j!z(00AtpBhQU 5JsBiPTa.$,= 'IENDB`nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/images/cursor-sizeh.png000066400000000000000000000002211455373415500272250ustar00rootroot00000000000000PNG  IHDRm PLTE~OtRNS@f6IDAT[c`h00p% l LSXBtg(D h8LL# /97IENDB`nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/images/cursor-sizev.png000066400000000000000000000002151455373415500272460ustar00rootroot00000000000000PNG  IHDRm PLTE~OtRNS@f2IDAT[c`L+ 4W kKC驡 Emf>>0܇4 SvIENDB`nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/images/cursor-uparrow.png000066400000000000000000000002041455373415500276030ustar00rootroot00000000000000PNG  IHDRm PLTE~OtRNS@f)IDAT[c`L+ 4W kKC驡 0` B7~2IENDB`nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/images/cursor-vsplit.png000066400000000000000000000002411455373415500274260ustar00rootroot00000000000000PNG  IHDRm PLTE~OtRNS@fFIDAT[c`  9Cjh3UfZR p`G3f~{VOIENDB`nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/images/cursor-wait.png000066400000000000000000000002541455373415500270550ustar00rootroot00000000000000PNG  IHDRm PLTEtRNS@fQIDATc`@RVӡ|:r&KS.ьK& ʜ10bpfD~%󦢚37--{PY IENDB`nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/images/cursor-whatsthis.png000066400000000000000000000002771455373415500301340ustar00rootroot00000000000000PNG  IHDR g PLTEtRNS@fdIDATWch` ! U+Ai lS R #1B[&-3VHMa̘e,1TD֫6@D8 SÀ$W/qIENDB`nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/qtbuttonpropertybrowser.cpp000066400000000000000000000473261455373415500304330ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #include "qtbuttonpropertybrowser.h" #include #include #include #include #include #include #include #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif class QtButtonPropertyBrowserPrivate { QtButtonPropertyBrowser *q_ptr; Q_DECLARE_PUBLIC(QtButtonPropertyBrowser) public: void init(QWidget *parent); void propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex); void propertyRemoved(QtBrowserItem *index); void propertyChanged(QtBrowserItem *index); QWidget *createEditor(QtProperty *property, QWidget *parent) const { return q_ptr->createEditor(property, parent); } void slotEditorDestroyed(); void slotUpdate(); void slotToggled(bool checked); struct WidgetItem { WidgetItem() : widget(0), label(0), widgetLabel(0), button(0), container(0), layout(0), /*line(0), */parent(0), expanded(false) { } QWidget *widget; // can be null QLabel *label; // main label with property name QLabel *widgetLabel; // label substitute showing the current value if there is no widget QToolButton *button; // expandable button for items with children QWidget *container; // container which is expanded when the button is clicked QGridLayout *layout; // layout in container WidgetItem *parent; QList children; bool expanded; }; private: void updateLater(); void updateItem(WidgetItem *item); void insertRow(QGridLayout *layout, int row) const; void removeRow(QGridLayout *layout, int row) const; int gridRow(WidgetItem *item) const; int gridSpan(WidgetItem *item) const; void setExpanded(WidgetItem *item, bool expanded); QToolButton *createButton(QWidget *panret = 0) const; QMap m_indexToItem; QMap m_itemToIndex; QMap m_widgetToItem; QMap m_buttonToItem; QGridLayout *m_mainLayout; QList m_children; QList m_recreateQueue; }; QToolButton *QtButtonPropertyBrowserPrivate::createButton(QWidget *parent) const { QToolButton *button = new QToolButton(parent); button->setCheckable(true); button->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed)); button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); button->setArrowType(Qt::DownArrow); button->setIconSize(QSize(3, 16)); /* QIcon icon; icon.addPixmap(q_ptr->style()->standardPixmap(QStyle::SP_ArrowDown), QIcon::Normal, QIcon::Off); icon.addPixmap(q_ptr->style()->standardPixmap(QStyle::SP_ArrowUp), QIcon::Normal, QIcon::On); button->setIcon(icon); */ return button; } int QtButtonPropertyBrowserPrivate::gridRow(WidgetItem *item) const { QList siblings; if (item->parent) siblings = item->parent->children; else siblings = m_children; int row = 0; QListIterator it(siblings); while (it.hasNext()) { WidgetItem *sibling = it.next(); if (sibling == item) return row; row += gridSpan(sibling); } return -1; } int QtButtonPropertyBrowserPrivate::gridSpan(WidgetItem *item) const { if (item->container && item->expanded) return 2; return 1; } void QtButtonPropertyBrowserPrivate::init(QWidget *parent) { m_mainLayout = new QGridLayout(); parent->setLayout(m_mainLayout); QLayoutItem *item = new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding); m_mainLayout->addItem(item, 0, 0); } void QtButtonPropertyBrowserPrivate::slotEditorDestroyed() { QWidget *editor = qobject_cast(q_ptr->sender()); if (!editor) return; if (!m_widgetToItem.contains(editor)) return; m_widgetToItem[editor]->widget = 0; m_widgetToItem.remove(editor); } void QtButtonPropertyBrowserPrivate::slotUpdate() { QListIterator itItem(m_recreateQueue); while (itItem.hasNext()) { WidgetItem *item = itItem.next(); WidgetItem *parent = item->parent; QWidget *w = 0; QGridLayout *l = 0; const int oldRow = gridRow(item); if (parent) { w = parent->container; l = parent->layout; } else { w = q_ptr; l = m_mainLayout; } int span = 1; if (!item->widget && !item->widgetLabel) span = 2; item->label = new QLabel(w); item->label->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); l->addWidget(item->label, oldRow, 0, 1, span); updateItem(item); } m_recreateQueue.clear(); } void QtButtonPropertyBrowserPrivate::setExpanded(WidgetItem *item, bool expanded) { if (item->expanded == expanded) return; if (!item->container) return; item->expanded = expanded; const int row = gridRow(item); WidgetItem *parent = item->parent; QGridLayout *l = 0; if (parent) l = parent->layout; else l = m_mainLayout; if (expanded) { insertRow(l, row + 1); l->addWidget(item->container, row + 1, 0, 1, 2); item->container->show(); } else { l->removeWidget(item->container); item->container->hide(); removeRow(l, row + 1); } item->button->setChecked(expanded); item->button->setArrowType(expanded ? Qt::UpArrow : Qt::DownArrow); } void QtButtonPropertyBrowserPrivate::slotToggled(bool checked) { WidgetItem *item = m_buttonToItem.value(q_ptr->sender()); if (!item) return; setExpanded(item, checked); if (checked) emit q_ptr->expanded(m_itemToIndex.value(item)); else emit q_ptr->collapsed(m_itemToIndex.value(item)); } void QtButtonPropertyBrowserPrivate::updateLater() { QTimer::singleShot(0, q_ptr, SLOT(slotUpdate())); } void QtButtonPropertyBrowserPrivate::propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex) { WidgetItem *afterItem = m_indexToItem.value(afterIndex); WidgetItem *parentItem = m_indexToItem.value(index->parent()); WidgetItem *newItem = new WidgetItem(); newItem->parent = parentItem; QGridLayout *layout = 0; QWidget *parentWidget = 0; int row = -1; if (!afterItem) { row = 0; if (parentItem) parentItem->children.insert(0, newItem); else m_children.insert(0, newItem); } else { row = gridRow(afterItem) + gridSpan(afterItem); if (parentItem) parentItem->children.insert(parentItem->children.indexOf(afterItem) + 1, newItem); else m_children.insert(m_children.indexOf(afterItem) + 1, newItem); } if (!parentItem) { layout = m_mainLayout; parentWidget = q_ptr; } else { if (!parentItem->container) { m_recreateQueue.removeAll(parentItem); WidgetItem *grandParent = parentItem->parent; //QWidget *w = 0; QGridLayout *l = 0; const int oldRow = gridRow(parentItem); if (grandParent) { //w = grandParent->container; l = grandParent->layout; } else { //w = q_ptr; l = m_mainLayout; } QFrame *container = new QFrame(); container->setFrameShape(QFrame::Panel); container->setFrameShadow(QFrame::Raised); parentItem->container = container; parentItem->button = createButton(); m_buttonToItem[parentItem->button] = parentItem; q_ptr->connect(parentItem->button, SIGNAL(toggled(bool)), q_ptr, SLOT(slotToggled(bool))); parentItem->layout = new QGridLayout(); container->setLayout(parentItem->layout); if (parentItem->label) { l->removeWidget(parentItem->label); delete parentItem->label; parentItem->label = 0; } int span = 1; if (!parentItem->widget && !parentItem->widgetLabel) span = 2; l->addWidget(parentItem->button, oldRow, 0, 1, span); updateItem(parentItem); } layout = parentItem->layout; parentWidget = parentItem->container; } newItem->label = new QLabel(parentWidget); newItem->label->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); newItem->widget = createEditor(index->property(), parentWidget); if (newItem->widget) { QObject::connect(newItem->widget, SIGNAL(destroyed()), q_ptr, SLOT(slotEditorDestroyed())); m_widgetToItem[newItem->widget] = newItem; } else if (index->property()->hasValue()) { newItem->widgetLabel = new QLabel(parentWidget); newItem->widgetLabel->setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed)); } insertRow(layout, row); int span = 1; if (newItem->widget) layout->addWidget(newItem->widget, row, 1); else if (newItem->widgetLabel) layout->addWidget(newItem->widgetLabel, row, 1); else span = 2; layout->addWidget(newItem->label, row, 0, span, 1); m_itemToIndex[newItem] = index; m_indexToItem[index] = newItem; updateItem(newItem); } void QtButtonPropertyBrowserPrivate::propertyRemoved(QtBrowserItem *index) { WidgetItem *item = m_indexToItem.value(index); m_indexToItem.remove(index); m_itemToIndex.remove(item); WidgetItem *parentItem = item->parent; const int row = gridRow(item); if (parentItem) parentItem->children.removeAt(parentItem->children.indexOf(item)); else m_children.removeAt(m_children.indexOf(item)); const int colSpan = gridSpan(item); m_buttonToItem.remove(item->button); if (item->widget) delete item->widget; if (item->label) delete item->label; if (item->widgetLabel) delete item->widgetLabel; if (item->button) delete item->button; if (item->container) delete item->container; if (!parentItem) { removeRow(m_mainLayout, row); if (colSpan > 1) removeRow(m_mainLayout, row); } else if (parentItem->children.count() != 0) { removeRow(parentItem->layout, row); if (colSpan > 1) removeRow(parentItem->layout, row); } else { const WidgetItem *grandParent = parentItem->parent; QGridLayout *l = 0; if (grandParent) { l = grandParent->layout; } else { l = m_mainLayout; } const int parentRow = gridRow(parentItem); const int parentSpan = gridSpan(parentItem); l->removeWidget(parentItem->button); l->removeWidget(parentItem->container); delete parentItem->button; delete parentItem->container; parentItem->button = 0; parentItem->container = 0; parentItem->layout = 0; if (!m_recreateQueue.contains(parentItem)) m_recreateQueue.append(parentItem); if (parentSpan > 1) removeRow(l, parentRow + 1); updateLater(); } m_recreateQueue.removeAll(item); delete item; } void QtButtonPropertyBrowserPrivate::insertRow(QGridLayout *layout, int row) const { QMap itemToPos; int idx = 0; while (idx < layout->count()) { int r, c, rs, cs; layout->getItemPosition(idx, &r, &c, &rs, &cs); if (r >= row) { itemToPos[layout->takeAt(idx)] = QRect(r + 1, c, rs, cs); } else { idx++; } } const QMap::ConstIterator icend = itemToPos.constEnd(); for(QMap::ConstIterator it = itemToPos.constBegin(); it != icend; ++it) { const QRect r = it.value(); layout->addItem(it.key(), r.x(), r.y(), r.width(), r.height()); } } void QtButtonPropertyBrowserPrivate::removeRow(QGridLayout *layout, int row) const { QMap itemToPos; int idx = 0; while (idx < layout->count()) { int r, c, rs, cs; layout->getItemPosition(idx, &r, &c, &rs, &cs); if (r > row) { itemToPos[layout->takeAt(idx)] = QRect(r - 1, c, rs, cs); } else { idx++; } } const QMap::ConstIterator icend = itemToPos.constEnd(); for(QMap::ConstIterator it = itemToPos.constBegin(); it != icend; ++it) { const QRect r = it.value(); layout->addItem(it.key(), r.x(), r.y(), r.width(), r.height()); } } void QtButtonPropertyBrowserPrivate::propertyChanged(QtBrowserItem *index) { WidgetItem *item = m_indexToItem.value(index); updateItem(item); } void QtButtonPropertyBrowserPrivate::updateItem(WidgetItem *item) { QtProperty *property = m_itemToIndex[item]->property(); if (item->button) { QFont font = item->button->font(); font.setUnderline(property->isModified()); item->button->setFont(font); item->button->setText(property->propertyName()); item->button->setToolTip(property->toolTip()); item->button->setStatusTip(property->statusTip()); item->button->setWhatsThis(property->whatsThis()); item->button->setEnabled(property->isEnabled()); } if (item->label) { QFont font = item->label->font(); font.setUnderline(property->isModified()); item->label->setFont(font); item->label->setText(property->propertyName()); item->label->setToolTip(property->toolTip()); item->label->setStatusTip(property->statusTip()); item->label->setWhatsThis(property->whatsThis()); item->label->setEnabled(property->isEnabled()); } if (item->widgetLabel) { QFont font = item->widgetLabel->font(); font.setUnderline(false); item->widgetLabel->setFont(font); item->widgetLabel->setText(property->valueText()); item->widgetLabel->setToolTip(property->valueText()); item->widgetLabel->setEnabled(property->isEnabled()); } if (item->widget) { QFont font = item->widget->font(); font.setUnderline(false); item->widget->setFont(font); item->widget->setEnabled(property->isEnabled()); item->widget->setToolTip(property->valueText()); } } /*! \class QtButtonPropertyBrowser \brief The QtButtonPropertyBrowser class provides a drop down QToolButton based property browser. A property browser is a widget that enables the user to edit a given set of properties. Each property is represented by a label specifying the property's name, and an editing widget (e.g. a line edit or a combobox) holding its value. A property can have zero or more subproperties. QtButtonPropertyBrowser provides drop down button for all nested properties, i.e. subproperties are enclosed by a container associated with the drop down button. The parent property's name is displayed as button text. For example: \image qtbuttonpropertybrowser.png Use the QtAbstractPropertyBrowser API to add, insert and remove properties from an instance of the QtButtonPropertyBrowser class. The properties themselves are created and managed by implementations of the QtAbstractPropertyManager class. \sa QtTreePropertyBrowser, QtAbstractPropertyBrowser */ /*! \fn void QtButtonPropertyBrowser::collapsed(QtBrowserItem *item) This signal is emitted when the \a item is collapsed. \sa expanded(), setExpanded() */ /*! \fn void QtButtonPropertyBrowser::expanded(QtBrowserItem *item) This signal is emitted when the \a item is expanded. \sa collapsed(), setExpanded() */ /*! Creates a property browser with the given \a parent. */ QtButtonPropertyBrowser::QtButtonPropertyBrowser(QWidget *parent) : QtAbstractPropertyBrowser(parent) { d_ptr = new QtButtonPropertyBrowserPrivate; d_ptr->q_ptr = this; d_ptr->init(this); } /*! Destroys this property browser. Note that the properties that were inserted into this browser are \e not destroyed since they may still be used in other browsers. The properties are owned by the manager that created them. \sa QtProperty, QtAbstractPropertyManager */ QtButtonPropertyBrowser::~QtButtonPropertyBrowser() { const QMap::ConstIterator icend = d_ptr->m_itemToIndex.constEnd(); for (QMap::ConstIterator it = d_ptr->m_itemToIndex.constBegin(); it != icend; ++it) delete it.key(); delete d_ptr; } /*! \reimp */ void QtButtonPropertyBrowser::itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem) { d_ptr->propertyInserted(item, afterItem); } /*! \reimp */ void QtButtonPropertyBrowser::itemRemoved(QtBrowserItem *item) { d_ptr->propertyRemoved(item); } /*! \reimp */ void QtButtonPropertyBrowser::itemChanged(QtBrowserItem *item) { d_ptr->propertyChanged(item); } /*! Sets the \a item to either collapse or expanded, depending on the value of \a expanded. \sa isExpanded(), expanded(), collapsed() */ void QtButtonPropertyBrowser::setExpanded(QtBrowserItem *item, bool expanded) { QtButtonPropertyBrowserPrivate::WidgetItem *itm = d_ptr->m_indexToItem.value(item); if (itm) d_ptr->setExpanded(itm, expanded); } /*! Returns true if the \a item is expanded; otherwise returns false. \sa setExpanded() */ bool QtButtonPropertyBrowser::isExpanded(QtBrowserItem *item) const { QtButtonPropertyBrowserPrivate::WidgetItem *itm = d_ptr->m_indexToItem.value(item); if (itm) return itm->expanded; return false; } #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif #include "moc_qtbuttonpropertybrowser.cpp" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/qtbuttonpropertybrowser.h000066400000000000000000000061131455373415500300650ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #ifndef QTBUTTONPROPERTYBROWSER_H #define QTBUTTONPROPERTYBROWSER_H #include "qtpropertybrowser.h" #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif class QtButtonPropertyBrowserPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtButtonPropertyBrowser : public QtAbstractPropertyBrowser { Q_OBJECT public: QtButtonPropertyBrowser(QWidget *parent = 0); ~QtButtonPropertyBrowser(); void setExpanded(QtBrowserItem *item, bool expanded); bool isExpanded(QtBrowserItem *item) const; Q_SIGNALS: void collapsed(QtBrowserItem *item); void expanded(QtBrowserItem *item); protected: virtual void itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem); virtual void itemRemoved(QtBrowserItem *item); virtual void itemChanged(QtBrowserItem *item); private: QtButtonPropertyBrowserPrivate *d_ptr; Q_DECLARE_PRIVATE(QtButtonPropertyBrowser) Q_DISABLE_COPY(QtButtonPropertyBrowser) Q_PRIVATE_SLOT(d_func(), void slotUpdate()) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed()) Q_PRIVATE_SLOT(d_func(), void slotToggled(bool)) }; #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif #endif nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/qteditorfactory.cpp000066400000000000000000002344261455373415500265640ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #include "qteditorfactory.h" #include "qtpropertybrowserutils_p.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(Q_CC_MSVC) # pragma warning(disable: 4786) /* MS VS 6: truncating debug info after 255 characters */ #endif #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif // Set a hard coded left margin to account for the indentation // of the tree view icon when switching to an editor static inline void setupTreeViewEditorMargin(QLayout *lt) { enum { DecorationMargin = 4 }; if (QApplication::layoutDirection() == Qt::LeftToRight) lt->setContentsMargins(DecorationMargin, 0, 0, 0); else lt->setContentsMargins(0, 0, DecorationMargin, 0); } // ---------- EditorFactoryPrivate : // Base class for editor factory private classes. Manages mapping of properties to editors and vice versa. template class EditorFactoryPrivate { public: typedef QList EditorList; typedef QMap PropertyToEditorListMap; typedef QMap EditorToPropertyMap; Editor *createEditor(QtProperty *property, QWidget *parent); void initializeEditor(QtProperty *property, Editor *e); void slotEditorDestroyed(QObject *object); PropertyToEditorListMap m_createdEditors; EditorToPropertyMap m_editorToProperty; }; template Editor *EditorFactoryPrivate::createEditor(QtProperty *property, QWidget *parent) { Editor *editor = new Editor(parent); initializeEditor(property, editor); return editor; } template void EditorFactoryPrivate::initializeEditor(QtProperty *property, Editor *editor) { typename PropertyToEditorListMap::iterator it = m_createdEditors.find(property); if (it == m_createdEditors.end()) it = m_createdEditors.insert(property, EditorList()); it.value().append(editor); m_editorToProperty.insert(editor, property); } template void EditorFactoryPrivate::slotEditorDestroyed(QObject *object) { const typename EditorToPropertyMap::iterator ecend = m_editorToProperty.end(); for (typename EditorToPropertyMap::iterator itEditor = m_editorToProperty.begin(); itEditor != ecend; ++itEditor) { if (itEditor.key() == object) { Editor *editor = itEditor.key(); QtProperty *property = itEditor.value(); const typename PropertyToEditorListMap::iterator pit = m_createdEditors.find(property); if (pit != m_createdEditors.end()) { pit.value().removeAll(editor); if (pit.value().empty()) m_createdEditors.erase(pit); } m_editorToProperty.erase(itEditor); return; } } } // ------------ QtSpinBoxFactory class QtSpinBoxFactoryPrivate : public EditorFactoryPrivate { QtSpinBoxFactory *q_ptr; Q_DECLARE_PUBLIC(QtSpinBoxFactory) public: void slotPropertyChanged(QtProperty *property, int value); void slotRangeChanged(QtProperty *property, int min, int max); void slotSingleStepChanged(QtProperty *property, int step); void slotSetValue(int value); }; void QtSpinBoxFactoryPrivate::slotPropertyChanged(QtProperty *property, int value) { if (!m_createdEditors.contains(property)) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QSpinBox *editor = itEditor.next(); if (editor->value() != value) { editor->blockSignals(true); editor->setValue(value); editor->blockSignals(false); } } } void QtSpinBoxFactoryPrivate::slotRangeChanged(QtProperty *property, int min, int max) { if (!m_createdEditors.contains(property)) return; QtIntPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QSpinBox *editor = itEditor.next(); editor->blockSignals(true); editor->setRange(min, max); editor->setValue(manager->value(property)); editor->blockSignals(false); } } void QtSpinBoxFactoryPrivate::slotSingleStepChanged(QtProperty *property, int step) { if (!m_createdEditors.contains(property)) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QSpinBox *editor = itEditor.next(); editor->blockSignals(true); editor->setSingleStep(step); editor->blockSignals(false); } } void QtSpinBoxFactoryPrivate::slotSetValue(int value) { QObject *object = q_ptr->sender(); const QMap::ConstIterator ecend = m_editorToProperty.constEnd(); for (QMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) { if (itEditor.key() == object) { QtProperty *property = itEditor.value(); QtIntPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; manager->setValue(property, value); return; } } } /*! \class QtSpinBoxFactory \brief The QtSpinBoxFactory class provides QSpinBox widgets for properties created by QtIntPropertyManager objects. \sa QtAbstractEditorFactory, QtIntPropertyManager */ /*! Creates a factory with the given \a parent. */ QtSpinBoxFactory::QtSpinBoxFactory(QObject *parent) : QtAbstractEditorFactory(parent) { d_ptr = new QtSpinBoxFactoryPrivate(); d_ptr->q_ptr = this; } /*! Destroys this factory, and all the widgets it has created. */ QtSpinBoxFactory::~QtSpinBoxFactory() { qDeleteAll(d_ptr->m_editorToProperty.keys()); delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtSpinBoxFactory::connectPropertyManager(QtIntPropertyManager *manager) { connect(manager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotPropertyChanged(QtProperty *, int))); connect(manager, SIGNAL(rangeChanged(QtProperty *, int, int)), this, SLOT(slotRangeChanged(QtProperty *, int, int))); connect(manager, SIGNAL(singleStepChanged(QtProperty *, int)), this, SLOT(slotSingleStepChanged(QtProperty *, int))); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtSpinBoxFactory::createEditor(QtIntPropertyManager *manager, QtProperty *property, QWidget *parent) { QSpinBox *editor = d_ptr->createEditor(property, parent); editor->setSingleStep(manager->singleStep(property)); editor->setRange(manager->minimum(property), manager->maximum(property)); editor->setValue(manager->value(property)); editor->setKeyboardTracking(false); connect(editor, SIGNAL(valueChanged(int)), this, SLOT(slotSetValue(int))); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); return editor; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtSpinBoxFactory::disconnectPropertyManager(QtIntPropertyManager *manager) { disconnect(manager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotPropertyChanged(QtProperty *, int))); disconnect(manager, SIGNAL(rangeChanged(QtProperty *, int, int)), this, SLOT(slotRangeChanged(QtProperty *, int, int))); disconnect(manager, SIGNAL(singleStepChanged(QtProperty *, int)), this, SLOT(slotSingleStepChanged(QtProperty *, int))); } // QtSliderFactory class QtSliderFactoryPrivate : public EditorFactoryPrivate { QtSliderFactory *q_ptr; Q_DECLARE_PUBLIC(QtSliderFactory) public: void slotPropertyChanged(QtProperty *property, int value); void slotRangeChanged(QtProperty *property, int min, int max); void slotSingleStepChanged(QtProperty *property, int step); void slotSetValue(int value); }; void QtSliderFactoryPrivate::slotPropertyChanged(QtProperty *property, int value) { if (!m_createdEditors.contains(property)) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QSlider *editor = itEditor.next(); editor->blockSignals(true); editor->setValue(value); editor->blockSignals(false); } } void QtSliderFactoryPrivate::slotRangeChanged(QtProperty *property, int min, int max) { if (!m_createdEditors.contains(property)) return; QtIntPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QSlider *editor = itEditor.next(); editor->blockSignals(true); editor->setRange(min, max); editor->setValue(manager->value(property)); editor->blockSignals(false); } } void QtSliderFactoryPrivate::slotSingleStepChanged(QtProperty *property, int step) { if (!m_createdEditors.contains(property)) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QSlider *editor = itEditor.next(); editor->blockSignals(true); editor->setSingleStep(step); editor->blockSignals(false); } } void QtSliderFactoryPrivate::slotSetValue(int value) { QObject *object = q_ptr->sender(); const QMap::ConstIterator ecend = m_editorToProperty.constEnd(); for (QMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor ) { if (itEditor.key() == object) { QtProperty *property = itEditor.value(); QtIntPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; manager->setValue(property, value); return; } } } /*! \class QtSliderFactory \brief The QtSliderFactory class provides QSlider widgets for properties created by QtIntPropertyManager objects. \sa QtAbstractEditorFactory, QtIntPropertyManager */ /*! Creates a factory with the given \a parent. */ QtSliderFactory::QtSliderFactory(QObject *parent) : QtAbstractEditorFactory(parent) { d_ptr = new QtSliderFactoryPrivate(); d_ptr->q_ptr = this; } /*! Destroys this factory, and all the widgets it has created. */ QtSliderFactory::~QtSliderFactory() { qDeleteAll(d_ptr->m_editorToProperty.keys()); delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtSliderFactory::connectPropertyManager(QtIntPropertyManager *manager) { connect(manager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotPropertyChanged(QtProperty *, int))); connect(manager, SIGNAL(rangeChanged(QtProperty *, int, int)), this, SLOT(slotRangeChanged(QtProperty *, int, int))); connect(manager, SIGNAL(singleStepChanged(QtProperty *, int)), this, SLOT(slotSingleStepChanged(QtProperty *, int))); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtSliderFactory::createEditor(QtIntPropertyManager *manager, QtProperty *property, QWidget *parent) { QSlider *editor = new QSlider(Qt::Horizontal, parent); d_ptr->initializeEditor(property, editor); editor->setSingleStep(manager->singleStep(property)); editor->setRange(manager->minimum(property), manager->maximum(property)); editor->setValue(manager->value(property)); connect(editor, SIGNAL(valueChanged(int)), this, SLOT(slotSetValue(int))); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); return editor; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtSliderFactory::disconnectPropertyManager(QtIntPropertyManager *manager) { disconnect(manager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotPropertyChanged(QtProperty *, int))); disconnect(manager, SIGNAL(rangeChanged(QtProperty *, int, int)), this, SLOT(slotRangeChanged(QtProperty *, int, int))); disconnect(manager, SIGNAL(singleStepChanged(QtProperty *, int)), this, SLOT(slotSingleStepChanged(QtProperty *, int))); } // QtSliderFactory class QtScrollBarFactoryPrivate : public EditorFactoryPrivate { QtScrollBarFactory *q_ptr; Q_DECLARE_PUBLIC(QtScrollBarFactory) public: void slotPropertyChanged(QtProperty *property, int value); void slotRangeChanged(QtProperty *property, int min, int max); void slotSingleStepChanged(QtProperty *property, int step); void slotSetValue(int value); }; void QtScrollBarFactoryPrivate::slotPropertyChanged(QtProperty *property, int value) { if (!m_createdEditors.contains(property)) return; QListIterator itEditor( m_createdEditors[property]); while (itEditor.hasNext()) { QScrollBar *editor = itEditor.next(); editor->blockSignals(true); editor->setValue(value); editor->blockSignals(false); } } void QtScrollBarFactoryPrivate::slotRangeChanged(QtProperty *property, int min, int max) { if (!m_createdEditors.contains(property)) return; QtIntPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; QListIterator itEditor( m_createdEditors[property]); while (itEditor.hasNext()) { QScrollBar *editor = itEditor.next(); editor->blockSignals(true); editor->setRange(min, max); editor->setValue(manager->value(property)); editor->blockSignals(false); } } void QtScrollBarFactoryPrivate::slotSingleStepChanged(QtProperty *property, int step) { if (!m_createdEditors.contains(property)) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QScrollBar *editor = itEditor.next(); editor->blockSignals(true); editor->setSingleStep(step); editor->blockSignals(false); } } void QtScrollBarFactoryPrivate::slotSetValue(int value) { QObject *object = q_ptr->sender(); const QMap::ConstIterator ecend = m_editorToProperty.constEnd(); for (QMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) if (itEditor.key() == object) { QtProperty *property = itEditor.value(); QtIntPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; manager->setValue(property, value); return; } } /*! \class QtScrollBarFactory \brief The QtScrollBarFactory class provides QScrollBar widgets for properties created by QtIntPropertyManager objects. \sa QtAbstractEditorFactory, QtIntPropertyManager */ /*! Creates a factory with the given \a parent. */ QtScrollBarFactory::QtScrollBarFactory(QObject *parent) : QtAbstractEditorFactory(parent) { d_ptr = new QtScrollBarFactoryPrivate(); d_ptr->q_ptr = this; } /*! Destroys this factory, and all the widgets it has created. */ QtScrollBarFactory::~QtScrollBarFactory() { qDeleteAll(d_ptr->m_editorToProperty.keys()); delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtScrollBarFactory::connectPropertyManager(QtIntPropertyManager *manager) { connect(manager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotPropertyChanged(QtProperty *, int))); connect(manager, SIGNAL(rangeChanged(QtProperty *, int, int)), this, SLOT(slotRangeChanged(QtProperty *, int, int))); connect(manager, SIGNAL(singleStepChanged(QtProperty *, int)), this, SLOT(slotSingleStepChanged(QtProperty *, int))); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtScrollBarFactory::createEditor(QtIntPropertyManager *manager, QtProperty *property, QWidget *parent) { QScrollBar *editor = new QScrollBar(Qt::Horizontal, parent); d_ptr->initializeEditor(property, editor); editor->setSingleStep(manager->singleStep(property)); editor->setRange(manager->minimum(property), manager->maximum(property)); editor->setValue(manager->value(property)); connect(editor, SIGNAL(valueChanged(int)), this, SLOT(slotSetValue(int))); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); return editor; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtScrollBarFactory::disconnectPropertyManager(QtIntPropertyManager *manager) { disconnect(manager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotPropertyChanged(QtProperty *, int))); disconnect(manager, SIGNAL(rangeChanged(QtProperty *, int, int)), this, SLOT(slotRangeChanged(QtProperty *, int, int))); disconnect(manager, SIGNAL(singleStepChanged(QtProperty *, int)), this, SLOT(slotSingleStepChanged(QtProperty *, int))); } // QtCheckBoxFactory class QtCheckBoxFactoryPrivate : public EditorFactoryPrivate { QtCheckBoxFactory *q_ptr; Q_DECLARE_PUBLIC(QtCheckBoxFactory) public: void slotPropertyChanged(QtProperty *property, bool value); void slotSetValue(bool value); }; void QtCheckBoxFactoryPrivate::slotPropertyChanged(QtProperty *property, bool value) { if (!m_createdEditors.contains(property)) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QtBoolEdit *editor = itEditor.next(); editor->blockCheckBoxSignals(true); editor->setChecked(value); editor->blockCheckBoxSignals(false); } } void QtCheckBoxFactoryPrivate::slotSetValue(bool value) { QObject *object = q_ptr->sender(); const QMap::ConstIterator ecend = m_editorToProperty.constEnd(); for (QMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) if (itEditor.key() == object) { QtProperty *property = itEditor.value(); QtBoolPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; manager->setValue(property, value); return; } } /*! \class QtCheckBoxFactory \brief The QtCheckBoxFactory class provides QCheckBox widgets for properties created by QtBoolPropertyManager objects. \sa QtAbstractEditorFactory, QtBoolPropertyManager */ /*! Creates a factory with the given \a parent. */ QtCheckBoxFactory::QtCheckBoxFactory(QObject *parent) : QtAbstractEditorFactory(parent) { d_ptr = new QtCheckBoxFactoryPrivate(); d_ptr->q_ptr = this; } /*! Destroys this factory, and all the widgets it has created. */ QtCheckBoxFactory::~QtCheckBoxFactory() { qDeleteAll(d_ptr->m_editorToProperty.keys()); delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtCheckBoxFactory::connectPropertyManager(QtBoolPropertyManager *manager) { connect(manager, SIGNAL(valueChanged(QtProperty *, bool)), this, SLOT(slotPropertyChanged(QtProperty *, bool))); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtCheckBoxFactory::createEditor(QtBoolPropertyManager *manager, QtProperty *property, QWidget *parent) { QtBoolEdit *editor = d_ptr->createEditor(property, parent); editor->setChecked(manager->value(property)); connect(editor, SIGNAL(toggled(bool)), this, SLOT(slotSetValue(bool))); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); return editor; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtCheckBoxFactory::disconnectPropertyManager(QtBoolPropertyManager *manager) { disconnect(manager, SIGNAL(valueChanged(QtProperty *, bool)), this, SLOT(slotPropertyChanged(QtProperty *, bool))); } // QtDoubleSpinBoxFactory class QtDoubleSpinBoxFactoryPrivate : public EditorFactoryPrivate { QtDoubleSpinBoxFactory *q_ptr; Q_DECLARE_PUBLIC(QtDoubleSpinBoxFactory) public: void slotPropertyChanged(QtProperty *property, double value); void slotRangeChanged(QtProperty *property, double min, double max); void slotSingleStepChanged(QtProperty *property, double step); void slotDecimalsChanged(QtProperty *property, int prec); void slotSetValue(double value); }; void QtDoubleSpinBoxFactoryPrivate::slotPropertyChanged(QtProperty *property, double value) { QList editors = m_createdEditors[property]; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QDoubleSpinBox *editor = itEditor.next(); if (editor->value() != value) { editor->blockSignals(true); editor->setValue(value); editor->blockSignals(false); } } } void QtDoubleSpinBoxFactoryPrivate::slotRangeChanged(QtProperty *property, double min, double max) { if (!m_createdEditors.contains(property)) return; QtDoublePropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; QList editors = m_createdEditors[property]; QListIterator itEditor(editors); while (itEditor.hasNext()) { QDoubleSpinBox *editor = itEditor.next(); editor->blockSignals(true); editor->setRange(min, max); editor->setValue(manager->value(property)); editor->blockSignals(false); } } void QtDoubleSpinBoxFactoryPrivate::slotSingleStepChanged(QtProperty *property, double step) { if (!m_createdEditors.contains(property)) return; QtDoublePropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; QList editors = m_createdEditors[property]; QListIterator itEditor(editors); while (itEditor.hasNext()) { QDoubleSpinBox *editor = itEditor.next(); editor->blockSignals(true); editor->setSingleStep(step); editor->blockSignals(false); } } void QtDoubleSpinBoxFactoryPrivate::slotDecimalsChanged(QtProperty *property, int prec) { if (!m_createdEditors.contains(property)) return; QtDoublePropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; QList editors = m_createdEditors[property]; QListIterator itEditor(editors); while (itEditor.hasNext()) { QDoubleSpinBox *editor = itEditor.next(); editor->blockSignals(true); editor->setDecimals(prec); editor->setValue(manager->value(property)); editor->blockSignals(false); } } void QtDoubleSpinBoxFactoryPrivate::slotSetValue(double value) { QObject *object = q_ptr->sender(); const QMap::ConstIterator itcend = m_editorToProperty.constEnd(); for (QMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != itcend; ++itEditor) { if (itEditor.key() == object) { QtProperty *property = itEditor.value(); QtDoublePropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; manager->setValue(property, value); return; } } } /*! \class QtDoubleSpinBoxFactory \brief The QtDoubleSpinBoxFactory class provides QDoubleSpinBox widgets for properties created by QtDoublePropertyManager objects. \sa QtAbstractEditorFactory, QtDoublePropertyManager */ /*! Creates a factory with the given \a parent. */ QtDoubleSpinBoxFactory::QtDoubleSpinBoxFactory(QObject *parent) : QtAbstractEditorFactory(parent) { d_ptr = new QtDoubleSpinBoxFactoryPrivate(); d_ptr->q_ptr = this; } /*! Destroys this factory, and all the widgets it has created. */ QtDoubleSpinBoxFactory::~QtDoubleSpinBoxFactory() { qDeleteAll(d_ptr->m_editorToProperty.keys()); delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtDoubleSpinBoxFactory::connectPropertyManager(QtDoublePropertyManager *manager) { connect(manager, SIGNAL(valueChanged(QtProperty *, double)), this, SLOT(slotPropertyChanged(QtProperty *, double))); connect(manager, SIGNAL(rangeChanged(QtProperty *, double, double)), this, SLOT(slotRangeChanged(QtProperty *, double, double))); connect(manager, SIGNAL(singleStepChanged(QtProperty *, double)), this, SLOT(slotSingleStepChanged(QtProperty *, double))); connect(manager, SIGNAL(decimalsChanged(QtProperty *, int)), this, SLOT(slotDecimalsChanged(QtProperty *, int))); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtDoubleSpinBoxFactory::createEditor(QtDoublePropertyManager *manager, QtProperty *property, QWidget *parent) { QDoubleSpinBox *editor = d_ptr->createEditor(property, parent); editor->setSingleStep(manager->singleStep(property)); editor->setDecimals(manager->decimals(property)); editor->setRange(manager->minimum(property), manager->maximum(property)); editor->setValue(manager->value(property)); editor->setKeyboardTracking(false); connect(editor, SIGNAL(valueChanged(double)), this, SLOT(slotSetValue(double))); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); return editor; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtDoubleSpinBoxFactory::disconnectPropertyManager(QtDoublePropertyManager *manager) { disconnect(manager, SIGNAL(valueChanged(QtProperty *, double)), this, SLOT(slotPropertyChanged(QtProperty *, double))); disconnect(manager, SIGNAL(rangeChanged(QtProperty *, double, double)), this, SLOT(slotRangeChanged(QtProperty *, double, double))); disconnect(manager, SIGNAL(singleStepChanged(QtProperty *, double)), this, SLOT(slotSingleStepChanged(QtProperty *, double))); disconnect(manager, SIGNAL(decimalsChanged(QtProperty *, int)), this, SLOT(slotDecimalsChanged(QtProperty *, int))); } // QtLineEditFactory class QtLineEditFactoryPrivate : public EditorFactoryPrivate { QtLineEditFactory *q_ptr; Q_DECLARE_PUBLIC(QtLineEditFactory) public: void slotPropertyChanged(QtProperty *property, const QString &value); void slotRegExpChanged(QtProperty *property, const QRegExp ®Exp); void slotSetValue(const QString &value); }; void QtLineEditFactoryPrivate::slotPropertyChanged(QtProperty *property, const QString &value) { if (!m_createdEditors.contains(property)) return; QListIterator itEditor( m_createdEditors[property]); while (itEditor.hasNext()) { QLineEdit *editor = itEditor.next(); if (editor->text() != value) editor->setText(value); } } void QtLineEditFactoryPrivate::slotRegExpChanged(QtProperty *property, const QRegExp ®Exp) { if (!m_createdEditors.contains(property)) return; QtStringPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QLineEdit *editor = itEditor.next(); editor->blockSignals(true); const QValidator *oldValidator = editor->validator(); QValidator *newValidator = 0; if (regExp.isValid()) { newValidator = new QRegExpValidator(regExp, editor); } editor->setValidator(newValidator); if (oldValidator) delete oldValidator; editor->blockSignals(false); } } void QtLineEditFactoryPrivate::slotSetValue(const QString &value) { QObject *object = q_ptr->sender(); const QMap::ConstIterator ecend = m_editorToProperty.constEnd(); for (QMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) if (itEditor.key() == object) { QtProperty *property = itEditor.value(); QtStringPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; manager->setValue(property, value); return; } } /*! \class QtLineEditFactory \brief The QtLineEditFactory class provides QLineEdit widgets for properties created by QtStringPropertyManager objects. \sa QtAbstractEditorFactory, QtStringPropertyManager */ /*! Creates a factory with the given \a parent. */ QtLineEditFactory::QtLineEditFactory(QObject *parent) : QtAbstractEditorFactory(parent) { d_ptr = new QtLineEditFactoryPrivate(); d_ptr->q_ptr = this; } /*! Destroys this factory, and all the widgets it has created. */ QtLineEditFactory::~QtLineEditFactory() { qDeleteAll(d_ptr->m_editorToProperty.keys()); delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtLineEditFactory::connectPropertyManager(QtStringPropertyManager *manager) { connect(manager, SIGNAL(valueChanged(QtProperty *, const QString &)), this, SLOT(slotPropertyChanged(QtProperty *, const QString &))); connect(manager, SIGNAL(regExpChanged(QtProperty *, const QRegExp &)), this, SLOT(slotRegExpChanged(QtProperty *, const QRegExp &))); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtLineEditFactory::createEditor(QtStringPropertyManager *manager, QtProperty *property, QWidget *parent) { QLineEdit *editor = d_ptr->createEditor(property, parent); QRegExp regExp = manager->regExp(property); if (regExp.isValid()) { QValidator *validator = new QRegExpValidator(regExp, editor); editor->setValidator(validator); } editor->setText(manager->value(property)); connect(editor, SIGNAL(textEdited(const QString &)), this, SLOT(slotSetValue(const QString &))); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); return editor; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtLineEditFactory::disconnectPropertyManager(QtStringPropertyManager *manager) { disconnect(manager, SIGNAL(valueChanged(QtProperty *, const QString &)), this, SLOT(slotPropertyChanged(QtProperty *, const QString &))); disconnect(manager, SIGNAL(regExpChanged(QtProperty *, const QRegExp &)), this, SLOT(slotRegExpChanged(QtProperty *, const QRegExp &))); } // QtDateEditFactory class QtDateEditFactoryPrivate : public EditorFactoryPrivate { QtDateEditFactory *q_ptr; Q_DECLARE_PUBLIC(QtDateEditFactory) public: void slotPropertyChanged(QtProperty *property, const QDate &value); void slotRangeChanged(QtProperty *property, const QDate &min, const QDate &max); void slotSetValue(const QDate &value); }; void QtDateEditFactoryPrivate::slotPropertyChanged(QtProperty *property, const QDate &value) { if (!m_createdEditors.contains(property)) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QDateEdit *editor = itEditor.next(); editor->blockSignals(true); editor->setDate(value); editor->blockSignals(false); } } void QtDateEditFactoryPrivate::slotRangeChanged(QtProperty *property, const QDate &min, const QDate &max) { if (!m_createdEditors.contains(property)) return; QtDatePropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QDateEdit *editor = itEditor.next(); editor->blockSignals(true); editor->setDateRange(min, max); editor->setDate(manager->value(property)); editor->blockSignals(false); } } void QtDateEditFactoryPrivate::slotSetValue(const QDate &value) { QObject *object = q_ptr->sender(); const QMap::ConstIterator ecend = m_editorToProperty.constEnd(); for (QMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) if (itEditor.key() == object) { QtProperty *property = itEditor.value(); QtDatePropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; manager->setValue(property, value); return; } } /*! \class QtDateEditFactory \brief The QtDateEditFactory class provides QDateEdit widgets for properties created by QtDatePropertyManager objects. \sa QtAbstractEditorFactory, QtDatePropertyManager */ /*! Creates a factory with the given \a parent. */ QtDateEditFactory::QtDateEditFactory(QObject *parent) : QtAbstractEditorFactory(parent) { d_ptr = new QtDateEditFactoryPrivate(); d_ptr->q_ptr = this; } /*! Destroys this factory, and all the widgets it has created. */ QtDateEditFactory::~QtDateEditFactory() { qDeleteAll(d_ptr->m_editorToProperty.keys()); delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtDateEditFactory::connectPropertyManager(QtDatePropertyManager *manager) { connect(manager, SIGNAL(valueChanged(QtProperty *, const QDate &)), this, SLOT(slotPropertyChanged(QtProperty *, const QDate &))); connect(manager, SIGNAL(rangeChanged(QtProperty *, const QDate &, const QDate &)), this, SLOT(slotRangeChanged(QtProperty *, const QDate &, const QDate &))); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtDateEditFactory::createEditor(QtDatePropertyManager *manager, QtProperty *property, QWidget *parent) { QDateEdit *editor = d_ptr->createEditor(property, parent); editor->setCalendarPopup(true); editor->setDateRange(manager->minimum(property), manager->maximum(property)); editor->setDate(manager->value(property)); connect(editor, SIGNAL(dateChanged(const QDate &)), this, SLOT(slotSetValue(const QDate &))); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); return editor; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtDateEditFactory::disconnectPropertyManager(QtDatePropertyManager *manager) { disconnect(manager, SIGNAL(valueChanged(QtProperty *, const QDate &)), this, SLOT(slotPropertyChanged(QtProperty *, const QDate &))); disconnect(manager, SIGNAL(rangeChanged(QtProperty *, const QDate &, const QDate &)), this, SLOT(slotRangeChanged(QtProperty *, const QDate &, const QDate &))); } // QtTimeEditFactory class QtTimeEditFactoryPrivate : public EditorFactoryPrivate { QtTimeEditFactory *q_ptr; Q_DECLARE_PUBLIC(QtTimeEditFactory) public: void slotPropertyChanged(QtProperty *property, const QTime &value); void slotSetValue(const QTime &value); }; void QtTimeEditFactoryPrivate::slotPropertyChanged(QtProperty *property, const QTime &value) { if (!m_createdEditors.contains(property)) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QTimeEdit *editor = itEditor.next(); editor->blockSignals(true); editor->setTime(value); editor->blockSignals(false); } } void QtTimeEditFactoryPrivate::slotSetValue(const QTime &value) { QObject *object = q_ptr->sender(); const QMap::ConstIterator ecend = m_editorToProperty.constEnd(); for (QMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) if (itEditor.key() == object) { QtProperty *property = itEditor.value(); QtTimePropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; manager->setValue(property, value); return; } } /*! \class QtTimeEditFactory \brief The QtTimeEditFactory class provides QTimeEdit widgets for properties created by QtTimePropertyManager objects. \sa QtAbstractEditorFactory, QtTimePropertyManager */ /*! Creates a factory with the given \a parent. */ QtTimeEditFactory::QtTimeEditFactory(QObject *parent) : QtAbstractEditorFactory(parent) { d_ptr = new QtTimeEditFactoryPrivate(); d_ptr->q_ptr = this; } /*! Destroys this factory, and all the widgets it has created. */ QtTimeEditFactory::~QtTimeEditFactory() { qDeleteAll(d_ptr->m_editorToProperty.keys()); delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtTimeEditFactory::connectPropertyManager(QtTimePropertyManager *manager) { connect(manager, SIGNAL(valueChanged(QtProperty *, const QTime &)), this, SLOT(slotPropertyChanged(QtProperty *, const QTime &))); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtTimeEditFactory::createEditor(QtTimePropertyManager *manager, QtProperty *property, QWidget *parent) { QTimeEdit *editor = d_ptr->createEditor(property, parent); editor->setTime(manager->value(property)); connect(editor, SIGNAL(timeChanged(const QTime &)), this, SLOT(slotSetValue(const QTime &))); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); return editor; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtTimeEditFactory::disconnectPropertyManager(QtTimePropertyManager *manager) { disconnect(manager, SIGNAL(valueChanged(QtProperty *, const QTime &)), this, SLOT(slotPropertyChanged(QtProperty *, const QTime &))); } // QtDateTimeEditFactory class QtDateTimeEditFactoryPrivate : public EditorFactoryPrivate { QtDateTimeEditFactory *q_ptr; Q_DECLARE_PUBLIC(QtDateTimeEditFactory) public: void slotPropertyChanged(QtProperty *property, const QDateTime &value); void slotSetValue(const QDateTime &value); }; void QtDateTimeEditFactoryPrivate::slotPropertyChanged(QtProperty *property, const QDateTime &value) { if (!m_createdEditors.contains(property)) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QDateTimeEdit *editor = itEditor.next(); editor->blockSignals(true); editor->setDateTime(value); editor->blockSignals(false); } } void QtDateTimeEditFactoryPrivate::slotSetValue(const QDateTime &value) { QObject *object = q_ptr->sender(); const QMap::ConstIterator ecend = m_editorToProperty.constEnd(); for (QMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) if (itEditor.key() == object) { QtProperty *property = itEditor.value(); QtDateTimePropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; manager->setValue(property, value); return; } } /*! \class QtDateTimeEditFactory \brief The QtDateTimeEditFactory class provides QDateTimeEdit widgets for properties created by QtDateTimePropertyManager objects. \sa QtAbstractEditorFactory, QtDateTimePropertyManager */ /*! Creates a factory with the given \a parent. */ QtDateTimeEditFactory::QtDateTimeEditFactory(QObject *parent) : QtAbstractEditorFactory(parent) { d_ptr = new QtDateTimeEditFactoryPrivate(); d_ptr->q_ptr = this; } /*! Destroys this factory, and all the widgets it has created. */ QtDateTimeEditFactory::~QtDateTimeEditFactory() { qDeleteAll(d_ptr->m_editorToProperty.keys()); delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtDateTimeEditFactory::connectPropertyManager(QtDateTimePropertyManager *manager) { connect(manager, SIGNAL(valueChanged(QtProperty *, const QDateTime &)), this, SLOT(slotPropertyChanged(QtProperty *, const QDateTime &))); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtDateTimeEditFactory::createEditor(QtDateTimePropertyManager *manager, QtProperty *property, QWidget *parent) { QDateTimeEdit *editor = d_ptr->createEditor(property, parent); editor->setDateTime(manager->value(property)); connect(editor, SIGNAL(dateTimeChanged(const QDateTime &)), this, SLOT(slotSetValue(const QDateTime &))); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); return editor; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtDateTimeEditFactory::disconnectPropertyManager(QtDateTimePropertyManager *manager) { disconnect(manager, SIGNAL(valueChanged(QtProperty *, const QDateTime &)), this, SLOT(slotPropertyChanged(QtProperty *, const QDateTime &))); } // QtKeySequenceEditorFactory class QtKeySequenceEditorFactoryPrivate : public EditorFactoryPrivate { QtKeySequenceEditorFactory *q_ptr; Q_DECLARE_PUBLIC(QtKeySequenceEditorFactory) public: void slotPropertyChanged(QtProperty *property, const QKeySequence &value); void slotSetValue(const QKeySequence &value); }; void QtKeySequenceEditorFactoryPrivate::slotPropertyChanged(QtProperty *property, const QKeySequence &value) { if (!m_createdEditors.contains(property)) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QtKeySequenceEdit *editor = itEditor.next(); editor->blockSignals(true); editor->setKeySequence(value); editor->blockSignals(false); } } void QtKeySequenceEditorFactoryPrivate::slotSetValue(const QKeySequence &value) { QObject *object = q_ptr->sender(); const QMap::ConstIterator ecend = m_editorToProperty.constEnd(); for (QMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) if (itEditor.key() == object) { QtProperty *property = itEditor.value(); QtKeySequencePropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; manager->setValue(property, value); return; } } /*! \class QtKeySequenceEditorFactory \brief The QtKeySequenceEditorFactory class provides editor widgets for properties created by QtKeySequencePropertyManager objects. \sa QtAbstractEditorFactory */ /*! Creates a factory with the given \a parent. */ QtKeySequenceEditorFactory::QtKeySequenceEditorFactory(QObject *parent) : QtAbstractEditorFactory(parent) { d_ptr = new QtKeySequenceEditorFactoryPrivate(); d_ptr->q_ptr = this; } /*! Destroys this factory, and all the widgets it has created. */ QtKeySequenceEditorFactory::~QtKeySequenceEditorFactory() { qDeleteAll(d_ptr->m_editorToProperty.keys()); delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtKeySequenceEditorFactory::connectPropertyManager(QtKeySequencePropertyManager *manager) { connect(manager, SIGNAL(valueChanged(QtProperty *, const QKeySequence &)), this, SLOT(slotPropertyChanged(QtProperty *, const QKeySequence &))); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtKeySequenceEditorFactory::createEditor(QtKeySequencePropertyManager *manager, QtProperty *property, QWidget *parent) { QtKeySequenceEdit *editor = d_ptr->createEditor(property, parent); editor->setKeySequence(manager->value(property)); connect(editor, SIGNAL(keySequenceChanged(const QKeySequence &)), this, SLOT(slotSetValue(const QKeySequence &))); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); return editor; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtKeySequenceEditorFactory::disconnectPropertyManager(QtKeySequencePropertyManager *manager) { disconnect(manager, SIGNAL(valueChanged(QtProperty *, const QKeySequence &)), this, SLOT(slotPropertyChanged(QtProperty *, const QKeySequence &))); } // QtCharEdit class QtCharEdit : public QWidget { Q_OBJECT public: QtCharEdit(QWidget *parent = 0); QChar value() const; bool eventFilter(QObject *o, QEvent *e); public Q_SLOTS: void setValue(const QChar &value); Q_SIGNALS: void valueChanged(const QChar &value); protected: void focusInEvent(QFocusEvent *e); void focusOutEvent(QFocusEvent *e); void keyPressEvent(QKeyEvent *e); void keyReleaseEvent(QKeyEvent *e); void paintEvent(QPaintEvent *); bool event(QEvent *e); private slots: void slotClearChar(); private: void handleKeyEvent(QKeyEvent *e); QChar m_value; QLineEdit *m_lineEdit; }; QtCharEdit::QtCharEdit(QWidget *parent) : QWidget(parent), m_lineEdit(new QLineEdit(this)) { QHBoxLayout *layout = new QHBoxLayout(this); layout->addWidget(m_lineEdit); layout->setMargin(0); m_lineEdit->installEventFilter(this); m_lineEdit->setReadOnly(true); m_lineEdit->setFocusProxy(this); setFocusPolicy(m_lineEdit->focusPolicy()); setAttribute(Qt::WA_InputMethodEnabled); } bool QtCharEdit::eventFilter(QObject *o, QEvent *e) { if (o == m_lineEdit && e->type() == QEvent::ContextMenu) { QContextMenuEvent *c = static_cast(e); QMenu *menu = m_lineEdit->createStandardContextMenu(); QList actions = menu->actions(); QListIterator itAction(actions); while (itAction.hasNext()) { QAction *action = itAction.next(); action->setShortcut(QKeySequence()); QString actionString = action->text(); const int pos = actionString.lastIndexOf(QLatin1Char('\t')); if (pos > 0) actionString = actionString.remove(pos, actionString.length() - pos); action->setText(actionString); } QAction *actionBefore = 0; if (actions.count() > 0) actionBefore = actions[0]; QAction *clearAction = new QAction(tr("Clear Char"), menu); menu->insertAction(actionBefore, clearAction); menu->insertSeparator(actionBefore); clearAction->setEnabled(!m_value.isNull()); connect(clearAction, SIGNAL(triggered()), this, SLOT(slotClearChar())); menu->exec(c->globalPos()); delete menu; e->accept(); return true; } return QWidget::eventFilter(o, e); } void QtCharEdit::slotClearChar() { if (m_value.isNull()) return; setValue(QChar()); emit valueChanged(m_value); } void QtCharEdit::handleKeyEvent(QKeyEvent *e) { const int key = e->key(); switch (key) { case Qt::Key_Control: case Qt::Key_Shift: case Qt::Key_Meta: case Qt::Key_Alt: case Qt::Key_Super_L: case Qt::Key_Return: return; default: break; } const QString text = e->text(); if (text.count() != 1) return; const QChar c = text.at(0); if (!c.isPrint()) return; if (m_value == c) return; m_value = c; const QString str = m_value.isNull() ? QString() : QString(m_value); m_lineEdit->setText(str); e->accept(); emit valueChanged(m_value); } void QtCharEdit::setValue(const QChar &value) { if (value == m_value) return; m_value = value; QString str = value.isNull() ? QString() : QString(value); m_lineEdit->setText(str); } QChar QtCharEdit::value() const { return m_value; } void QtCharEdit::focusInEvent(QFocusEvent *e) { m_lineEdit->event(e); m_lineEdit->selectAll(); QWidget::focusInEvent(e); } void QtCharEdit::focusOutEvent(QFocusEvent *e) { m_lineEdit->event(e); QWidget::focusOutEvent(e); } void QtCharEdit::keyPressEvent(QKeyEvent *e) { handleKeyEvent(e); e->accept(); } void QtCharEdit::keyReleaseEvent(QKeyEvent *e) { m_lineEdit->event(e); } void QtCharEdit::paintEvent(QPaintEvent *) { QStyleOption opt; opt.init(this); QPainter p(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); } bool QtCharEdit::event(QEvent *e) { switch(e->type()) { case QEvent::Shortcut: case QEvent::ShortcutOverride: case QEvent::KeyRelease: e->accept(); return true; default: break; } return QWidget::event(e); } // QtCharEditorFactory class QtCharEditorFactoryPrivate : public EditorFactoryPrivate { QtCharEditorFactory *q_ptr; Q_DECLARE_PUBLIC(QtCharEditorFactory) public: void slotPropertyChanged(QtProperty *property, const QChar &value); void slotSetValue(const QChar &value); }; void QtCharEditorFactoryPrivate::slotPropertyChanged(QtProperty *property, const QChar &value) { if (!m_createdEditors.contains(property)) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QtCharEdit *editor = itEditor.next(); editor->blockSignals(true); editor->setValue(value); editor->blockSignals(false); } } void QtCharEditorFactoryPrivate::slotSetValue(const QChar &value) { QObject *object = q_ptr->sender(); const QMap::ConstIterator ecend = m_editorToProperty.constEnd(); for (QMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) if (itEditor.key() == object) { QtProperty *property = itEditor.value(); QtCharPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; manager->setValue(property, value); return; } } /*! \class QtCharEditorFactory \brief The QtCharEditorFactory class provides editor widgets for properties created by QtCharPropertyManager objects. \sa QtAbstractEditorFactory */ /*! Creates a factory with the given \a parent. */ QtCharEditorFactory::QtCharEditorFactory(QObject *parent) : QtAbstractEditorFactory(parent) { d_ptr = new QtCharEditorFactoryPrivate(); d_ptr->q_ptr = this; } /*! Destroys this factory, and all the widgets it has created. */ QtCharEditorFactory::~QtCharEditorFactory() { qDeleteAll(d_ptr->m_editorToProperty.keys()); delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtCharEditorFactory::connectPropertyManager(QtCharPropertyManager *manager) { connect(manager, SIGNAL(valueChanged(QtProperty *, const QChar &)), this, SLOT(slotPropertyChanged(QtProperty *, const QChar &))); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtCharEditorFactory::createEditor(QtCharPropertyManager *manager, QtProperty *property, QWidget *parent) { QtCharEdit *editor = d_ptr->createEditor(property, parent); editor->setValue(manager->value(property)); connect(editor, SIGNAL(valueChanged(const QChar &)), this, SLOT(slotSetValue(const QChar &))); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); return editor; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtCharEditorFactory::disconnectPropertyManager(QtCharPropertyManager *manager) { disconnect(manager, SIGNAL(valueChanged(QtProperty *, const QChar &)), this, SLOT(slotPropertyChanged(QtProperty *, const QChar &))); } // QtEnumEditorFactory class QtEnumEditorFactoryPrivate : public EditorFactoryPrivate { QtEnumEditorFactory *q_ptr; Q_DECLARE_PUBLIC(QtEnumEditorFactory) public: void slotPropertyChanged(QtProperty *property, int value); void slotEnumNamesChanged(QtProperty *property, const QStringList &); void slotEnumIconsChanged(QtProperty *property, const QMap &); void slotSetValue(int value); }; void QtEnumEditorFactoryPrivate::slotPropertyChanged(QtProperty *property, int value) { if (!m_createdEditors.contains(property)) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QComboBox *editor = itEditor.next(); editor->blockSignals(true); editor->setCurrentIndex(value); editor->blockSignals(false); } } void QtEnumEditorFactoryPrivate::slotEnumNamesChanged(QtProperty *property, const QStringList &enumNames) { if (!m_createdEditors.contains(property)) return; QtEnumPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; QMap enumIcons = manager->enumIcons(property); QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QComboBox *editor = itEditor.next(); editor->blockSignals(true); editor->clear(); editor->addItems(enumNames); const int nameCount = enumNames.count(); for (int i = 0; i < nameCount; i++) editor->setItemIcon(i, enumIcons.value(i)); editor->setCurrentIndex(manager->value(property)); editor->blockSignals(false); } } void QtEnumEditorFactoryPrivate::slotEnumIconsChanged(QtProperty *property, const QMap &enumIcons) { if (!m_createdEditors.contains(property)) return; QtEnumPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; const QStringList enumNames = manager->enumNames(property); QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QComboBox *editor = itEditor.next(); editor->blockSignals(true); const int nameCount = enumNames.count(); for (int i = 0; i < nameCount; i++) editor->setItemIcon(i, enumIcons.value(i)); editor->setCurrentIndex(manager->value(property)); editor->blockSignals(false); } } void QtEnumEditorFactoryPrivate::slotSetValue(int value) { QObject *object = q_ptr->sender(); const QMap::ConstIterator ecend = m_editorToProperty.constEnd(); for (QMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) if (itEditor.key() == object) { QtProperty *property = itEditor.value(); QtEnumPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; manager->setValue(property, value); return; } } /*! \class QtEnumEditorFactory \brief The QtEnumEditorFactory class provides QComboBox widgets for properties created by QtEnumPropertyManager objects. \sa QtAbstractEditorFactory, QtEnumPropertyManager */ /*! Creates a factory with the given \a parent. */ QtEnumEditorFactory::QtEnumEditorFactory(QObject *parent) : QtAbstractEditorFactory(parent) { d_ptr = new QtEnumEditorFactoryPrivate(); d_ptr->q_ptr = this; } /*! Destroys this factory, and all the widgets it has created. */ QtEnumEditorFactory::~QtEnumEditorFactory() { qDeleteAll(d_ptr->m_editorToProperty.keys()); delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtEnumEditorFactory::connectPropertyManager(QtEnumPropertyManager *manager) { connect(manager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotPropertyChanged(QtProperty *, int))); connect(manager, SIGNAL(enumNamesChanged(QtProperty *, const QStringList &)), this, SLOT(slotEnumNamesChanged(QtProperty *, const QStringList &))); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtEnumEditorFactory::createEditor(QtEnumPropertyManager *manager, QtProperty *property, QWidget *parent) { QComboBox *editor = d_ptr->createEditor(property, parent); editor->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon); editor->setMinimumContentsLength(1); editor->view()->setTextElideMode(Qt::ElideRight); QStringList enumNames = manager->enumNames(property); editor->addItems(enumNames); QMap enumIcons = manager->enumIcons(property); const int enumNamesCount = enumNames.count(); for (int i = 0; i < enumNamesCount; i++) editor->setItemIcon(i, enumIcons.value(i)); editor->setCurrentIndex(manager->value(property)); connect(editor, SIGNAL(currentIndexChanged(int)), this, SLOT(slotSetValue(int))); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); return editor; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtEnumEditorFactory::disconnectPropertyManager(QtEnumPropertyManager *manager) { disconnect(manager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotPropertyChanged(QtProperty *, int))); disconnect(manager, SIGNAL(enumNamesChanged(QtProperty *, const QStringList &)), this, SLOT(slotEnumNamesChanged(QtProperty *, const QStringList &))); } // QtCursorEditorFactory Q_GLOBAL_STATIC(QtCursorDatabase, cursorDatabase) class QtCursorEditorFactoryPrivate { QtCursorEditorFactory *q_ptr; Q_DECLARE_PUBLIC(QtCursorEditorFactory) public: QtCursorEditorFactoryPrivate(); void slotPropertyChanged(QtProperty *property, const QCursor &cursor); void slotEnumChanged(QtProperty *property, int value); void slotEditorDestroyed(QObject *object); QtEnumEditorFactory *m_enumEditorFactory; QtEnumPropertyManager *m_enumPropertyManager; QMap m_propertyToEnum; QMap m_enumToProperty; QMap > m_enumToEditors; QMap m_editorToEnum; bool m_updatingEnum; }; QtCursorEditorFactoryPrivate::QtCursorEditorFactoryPrivate() : m_updatingEnum(false) { } void QtCursorEditorFactoryPrivate::slotPropertyChanged(QtProperty *property, const QCursor &cursor) { // update enum property QtProperty *enumProp = m_propertyToEnum.value(property); if (!enumProp) return; m_updatingEnum = true; m_enumPropertyManager->setValue(enumProp, cursorDatabase()->cursorToValue(cursor)); m_updatingEnum = false; } void QtCursorEditorFactoryPrivate::slotEnumChanged(QtProperty *property, int value) { if (m_updatingEnum) return; // update cursor property QtProperty *prop = m_enumToProperty.value(property); if (!prop) return; QtCursorPropertyManager *cursorManager = q_ptr->propertyManager(prop); if (!cursorManager) return; #ifndef QT_NO_CURSOR cursorManager->setValue(prop, QCursor(cursorDatabase()->valueToCursor(value))); #endif } void QtCursorEditorFactoryPrivate::slotEditorDestroyed(QObject *object) { // remove from m_editorToEnum map; // remove from m_enumToEditors map; // if m_enumToEditors doesn't contains more editors delete enum property; const QMap::ConstIterator ecend = m_editorToEnum.constEnd(); for (QMap::ConstIterator itEditor = m_editorToEnum.constBegin(); itEditor != ecend; ++itEditor) if (itEditor.key() == object) { QWidget *editor = itEditor.key(); QtProperty *enumProp = itEditor.value(); m_editorToEnum.remove(editor); m_enumToEditors[enumProp].removeAll(editor); if (m_enumToEditors[enumProp].isEmpty()) { m_enumToEditors.remove(enumProp); QtProperty *property = m_enumToProperty.value(enumProp); m_enumToProperty.remove(enumProp); m_propertyToEnum.remove(property); delete enumProp; } return; } } /*! \class QtCursorEditorFactory \brief The QtCursorEditorFactory class provides QComboBox widgets for properties created by QtCursorPropertyManager objects. \sa QtAbstractEditorFactory, QtCursorPropertyManager */ /*! Creates a factory with the given \a parent. */ QtCursorEditorFactory::QtCursorEditorFactory(QObject *parent) : QtAbstractEditorFactory(parent) { d_ptr = new QtCursorEditorFactoryPrivate(); d_ptr->q_ptr = this; d_ptr->m_enumEditorFactory = new QtEnumEditorFactory(this); d_ptr->m_enumPropertyManager = new QtEnumPropertyManager(this); connect(d_ptr->m_enumPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotEnumChanged(QtProperty *, int))); d_ptr->m_enumEditorFactory->addPropertyManager(d_ptr->m_enumPropertyManager); } /*! Destroys this factory, and all the widgets it has created. */ QtCursorEditorFactory::~QtCursorEditorFactory() { delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtCursorEditorFactory::connectPropertyManager(QtCursorPropertyManager *manager) { connect(manager, SIGNAL(valueChanged(QtProperty *, const QCursor &)), this, SLOT(slotPropertyChanged(QtProperty *, const QCursor &))); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtCursorEditorFactory::createEditor(QtCursorPropertyManager *manager, QtProperty *property, QWidget *parent) { QtProperty *enumProp = 0; if (d_ptr->m_propertyToEnum.contains(property)) { enumProp = d_ptr->m_propertyToEnum[property]; } else { enumProp = d_ptr->m_enumPropertyManager->addProperty(property->propertyName()); d_ptr->m_enumPropertyManager->setEnumNames(enumProp, cursorDatabase()->cursorShapeNames()); d_ptr->m_enumPropertyManager->setEnumIcons(enumProp, cursorDatabase()->cursorShapeIcons()); #ifndef QT_NO_CURSOR d_ptr->m_enumPropertyManager->setValue(enumProp, cursorDatabase()->cursorToValue(manager->value(property))); #endif d_ptr->m_propertyToEnum[property] = enumProp; d_ptr->m_enumToProperty[enumProp] = property; } QtAbstractEditorFactoryBase *af = d_ptr->m_enumEditorFactory; QWidget *editor = af->createEditor(enumProp, parent); d_ptr->m_enumToEditors[enumProp].append(editor); d_ptr->m_editorToEnum[editor] = enumProp; connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); return editor; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtCursorEditorFactory::disconnectPropertyManager(QtCursorPropertyManager *manager) { disconnect(manager, SIGNAL(valueChanged(QtProperty *, const QCursor &)), this, SLOT(slotPropertyChanged(QtProperty *, const QCursor &))); } // QtColorEditWidget class QtColorEditWidget : public QWidget { Q_OBJECT public: QtColorEditWidget(QWidget *parent); bool eventFilter(QObject *obj, QEvent *ev); public Q_SLOTS: void setValue(const QColor &value); Q_SIGNALS: void valueChanged(const QColor &value); protected: void paintEvent(QPaintEvent *); private Q_SLOTS: void buttonClicked(); private: QColor m_color; QLabel *m_pixmapLabel; QLabel *m_label; QToolButton *m_button; }; QtColorEditWidget::QtColorEditWidget(QWidget *parent) : QWidget(parent), m_pixmapLabel(new QLabel), m_label(new QLabel), m_button(new QToolButton) { QHBoxLayout *lt = new QHBoxLayout(this); setupTreeViewEditorMargin(lt); lt->setSpacing(0); lt->addWidget(m_pixmapLabel); lt->addWidget(m_label); lt->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Ignored)); m_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Ignored); m_button->setFixedWidth(20); setFocusProxy(m_button); setFocusPolicy(m_button->focusPolicy()); m_button->setText(tr("...")); m_button->installEventFilter(this); connect(m_button, SIGNAL(clicked()), this, SLOT(buttonClicked())); lt->addWidget(m_button); m_pixmapLabel->setPixmap(QtPropertyBrowserUtils::brushValuePixmap(QBrush(m_color))); m_label->setText(QtPropertyBrowserUtils::colorValueText(m_color)); } void QtColorEditWidget::setValue(const QColor &c) { if (m_color != c) { m_color = c; m_pixmapLabel->setPixmap(QtPropertyBrowserUtils::brushValuePixmap(QBrush(c))); m_label->setText(QtPropertyBrowserUtils::colorValueText(c)); } } void QtColorEditWidget::buttonClicked() { QRgb oldRgba = m_color.rgba(); QColor newRgba = QColorDialog::getColor(oldRgba, this).rgba(); if (newRgba.isValid() && newRgba.rgba() != oldRgba) { setValue(newRgba); emit valueChanged(m_color); } } bool QtColorEditWidget::eventFilter(QObject *obj, QEvent *ev) { if (obj == m_button) { switch (ev->type()) { case QEvent::KeyPress: case QEvent::KeyRelease: { // Prevent the QToolButton from handling Enter/Escape meant control the delegate switch (static_cast(ev)->key()) { case Qt::Key_Escape: case Qt::Key_Enter: case Qt::Key_Return: ev->ignore(); return true; default: break; } } break; default: break; } } return QWidget::eventFilter(obj, ev); } void QtColorEditWidget::paintEvent(QPaintEvent *) { QStyleOption opt; opt.init(this); QPainter p(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); } // QtColorEditorFactoryPrivate class QtColorEditorFactoryPrivate : public EditorFactoryPrivate { QtColorEditorFactory *q_ptr; Q_DECLARE_PUBLIC(QtColorEditorFactory) public: void slotPropertyChanged(QtProperty *property, const QColor &value); void slotSetValue(const QColor &value); }; void QtColorEditorFactoryPrivate::slotPropertyChanged(QtProperty *property, const QColor &value) { const PropertyToEditorListMap::iterator it = m_createdEditors.find(property); if (it == m_createdEditors.end()) return; QListIterator itEditor(it.value()); while (itEditor.hasNext()) itEditor.next()->setValue(value); } void QtColorEditorFactoryPrivate::slotSetValue(const QColor &value) { QObject *object = q_ptr->sender(); const EditorToPropertyMap::ConstIterator ecend = m_editorToProperty.constEnd(); for (EditorToPropertyMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) if (itEditor.key() == object) { QtProperty *property = itEditor.value(); QtColorPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; manager->setValue(property, value); return; } } /*! \class QtColorEditorFactory \brief The QtColorEditorFactory class provides color editing for properties created by QtColorPropertyManager objects. \sa QtAbstractEditorFactory, QtColorPropertyManager */ /*! Creates a factory with the given \a parent. */ QtColorEditorFactory::QtColorEditorFactory(QObject *parent) : QtAbstractEditorFactory(parent), d_ptr(new QtColorEditorFactoryPrivate()) { d_ptr->q_ptr = this; } /*! Destroys this factory, and all the widgets it has created. */ QtColorEditorFactory::~QtColorEditorFactory() { qDeleteAll(d_ptr->m_editorToProperty.keys()); delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtColorEditorFactory::connectPropertyManager(QtColorPropertyManager *manager) { connect(manager, SIGNAL(valueChanged(QtProperty*,QColor)), this, SLOT(slotPropertyChanged(QtProperty*,QColor))); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtColorEditorFactory::createEditor(QtColorPropertyManager *manager, QtProperty *property, QWidget *parent) { QtColorEditWidget *editor = d_ptr->createEditor(property, parent); editor->setValue(manager->value(property)); connect(editor, SIGNAL(valueChanged(QColor)), this, SLOT(slotSetValue(QColor))); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); return editor; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtColorEditorFactory::disconnectPropertyManager(QtColorPropertyManager *manager) { disconnect(manager, SIGNAL(valueChanged(QtProperty*,QColor)), this, SLOT(slotPropertyChanged(QtProperty*,QColor))); } // QtFontEditWidget class QtFontEditWidget : public QWidget { Q_OBJECT public: QtFontEditWidget(QWidget *parent); bool eventFilter(QObject *obj, QEvent *ev); public Q_SLOTS: void setValue(const QFont &value); Q_SIGNALS: void valueChanged(const QFont &value); protected: void paintEvent(QPaintEvent *); private Q_SLOTS: void buttonClicked(); private: QFont m_font; QLabel *m_pixmapLabel; QLabel *m_label; QToolButton *m_button; }; QtFontEditWidget::QtFontEditWidget(QWidget *parent) : QWidget(parent), m_pixmapLabel(new QLabel), m_label(new QLabel), m_button(new QToolButton) { QHBoxLayout *lt = new QHBoxLayout(this); setupTreeViewEditorMargin(lt); lt->setSpacing(0); lt->addWidget(m_pixmapLabel); lt->addWidget(m_label); lt->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Ignored)); m_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Ignored); m_button->setFixedWidth(20); setFocusProxy(m_button); setFocusPolicy(m_button->focusPolicy()); m_button->setText(tr("...")); m_button->installEventFilter(this); connect(m_button, SIGNAL(clicked()), this, SLOT(buttonClicked())); lt->addWidget(m_button); m_pixmapLabel->setPixmap(QtPropertyBrowserUtils::fontValuePixmap(m_font)); m_label->setText(QtPropertyBrowserUtils::fontValueText(m_font)); } void QtFontEditWidget::setValue(const QFont &f) { if (m_font != f) { m_font = f; m_pixmapLabel->setPixmap(QtPropertyBrowserUtils::fontValuePixmap(f)); m_label->setText(QtPropertyBrowserUtils::fontValueText(f)); } } void QtFontEditWidget::buttonClicked() { bool ok = false; QFont newFont = QFontDialog::getFont(&ok, m_font, this, tr("Select Font")); if (ok && newFont != m_font) { QFont f = m_font; // prevent mask for unchanged attributes, don't change other attributes (like kerning, etc...) if (m_font.family() != newFont.family()) f.setFamily(newFont.family()); if (m_font.pointSize() != newFont.pointSize()) f.setPointSize(newFont.pointSize()); if (m_font.bold() != newFont.bold()) f.setBold(newFont.bold()); if (m_font.italic() != newFont.italic()) f.setItalic(newFont.italic()); if (m_font.underline() != newFont.underline()) f.setUnderline(newFont.underline()); if (m_font.strikeOut() != newFont.strikeOut()) f.setStrikeOut(newFont.strikeOut()); setValue(f); emit valueChanged(m_font); } } bool QtFontEditWidget::eventFilter(QObject *obj, QEvent *ev) { if (obj == m_button) { switch (ev->type()) { case QEvent::KeyPress: case QEvent::KeyRelease: { // Prevent the QToolButton from handling Enter/Escape meant control the delegate switch (static_cast(ev)->key()) { case Qt::Key_Escape: case Qt::Key_Enter: case Qt::Key_Return: ev->ignore(); return true; default: break; } } break; default: break; } } return QWidget::eventFilter(obj, ev); } void QtFontEditWidget::paintEvent(QPaintEvent *) { QStyleOption opt; opt.init(this); QPainter p(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); } // QtFontEditorFactoryPrivate class QtFontEditorFactoryPrivate : public EditorFactoryPrivate { QtFontEditorFactory *q_ptr; Q_DECLARE_PUBLIC(QtFontEditorFactory) public: void slotPropertyChanged(QtProperty *property, const QFont &value); void slotSetValue(const QFont &value); }; void QtFontEditorFactoryPrivate::slotPropertyChanged(QtProperty *property, const QFont &value) { const PropertyToEditorListMap::iterator it = m_createdEditors.find(property); if (it == m_createdEditors.end()) return; QListIterator itEditor(it.value()); while (itEditor.hasNext()) itEditor.next()->setValue(value); } void QtFontEditorFactoryPrivate::slotSetValue(const QFont &value) { QObject *object = q_ptr->sender(); const EditorToPropertyMap::ConstIterator ecend = m_editorToProperty.constEnd(); for (EditorToPropertyMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) if (itEditor.key() == object) { QtProperty *property = itEditor.value(); QtFontPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; manager->setValue(property, value); return; } } /*! \class QtFontEditorFactory \brief The QtFontEditorFactory class provides font editing for properties created by QtFontPropertyManager objects. \sa QtAbstractEditorFactory, QtFontPropertyManager */ /*! Creates a factory with the given \a parent. */ QtFontEditorFactory::QtFontEditorFactory(QObject *parent) : QtAbstractEditorFactory(parent), d_ptr(new QtFontEditorFactoryPrivate()) { d_ptr->q_ptr = this; } /*! Destroys this factory, and all the widgets it has created. */ QtFontEditorFactory::~QtFontEditorFactory() { qDeleteAll(d_ptr->m_editorToProperty.keys()); delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtFontEditorFactory::connectPropertyManager(QtFontPropertyManager *manager) { connect(manager, SIGNAL(valueChanged(QtProperty*,QFont)), this, SLOT(slotPropertyChanged(QtProperty*,QFont))); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtFontEditorFactory::createEditor(QtFontPropertyManager *manager, QtProperty *property, QWidget *parent) { QtFontEditWidget *editor = d_ptr->createEditor(property, parent); editor->setValue(manager->value(property)); connect(editor, SIGNAL(valueChanged(QFont)), this, SLOT(slotSetValue(QFont))); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); return editor; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtFontEditorFactory::disconnectPropertyManager(QtFontPropertyManager *manager) { disconnect(manager, SIGNAL(valueChanged(QtProperty*,QFont)), this, SLOT(slotPropertyChanged(QtProperty*,QFont))); } #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif #include "moc_qteditorfactory.cpp" #include "qteditorfactory.moc" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/qteditorfactory.h000066400000000000000000000372241455373415500262260ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #ifndef QTEDITORFACTORY_H #define QTEDITORFACTORY_H #include "qtpropertymanager.h" #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif class QtSpinBoxFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtSpinBoxFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtSpinBoxFactory(QObject *parent = 0); ~QtSpinBoxFactory(); protected: void connectPropertyManager(QtIntPropertyManager *manager); QWidget *createEditor(QtIntPropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtIntPropertyManager *manager); private: QtSpinBoxFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtSpinBoxFactory) Q_DISABLE_COPY(QtSpinBoxFactory) Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotRangeChanged(QtProperty *, int, int)) Q_PRIVATE_SLOT(d_func(), void slotSingleStepChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotSetValue(int)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) }; class QtSliderFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtSliderFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtSliderFactory(QObject *parent = 0); ~QtSliderFactory(); protected: void connectPropertyManager(QtIntPropertyManager *manager); QWidget *createEditor(QtIntPropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtIntPropertyManager *manager); private: QtSliderFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtSliderFactory) Q_DISABLE_COPY(QtSliderFactory) Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotRangeChanged(QtProperty *, int, int)) Q_PRIVATE_SLOT(d_func(), void slotSingleStepChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotSetValue(int)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) }; class QtScrollBarFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtScrollBarFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtScrollBarFactory(QObject *parent = 0); ~QtScrollBarFactory(); protected: void connectPropertyManager(QtIntPropertyManager *manager); QWidget *createEditor(QtIntPropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtIntPropertyManager *manager); private: QtScrollBarFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtScrollBarFactory) Q_DISABLE_COPY(QtScrollBarFactory) Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotRangeChanged(QtProperty *, int, int)) Q_PRIVATE_SLOT(d_func(), void slotSingleStepChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotSetValue(int)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) }; class QtCheckBoxFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtCheckBoxFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtCheckBoxFactory(QObject *parent = 0); ~QtCheckBoxFactory(); protected: void connectPropertyManager(QtBoolPropertyManager *manager); QWidget *createEditor(QtBoolPropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtBoolPropertyManager *manager); private: QtCheckBoxFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtCheckBoxFactory) Q_DISABLE_COPY(QtCheckBoxFactory) Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, bool)) Q_PRIVATE_SLOT(d_func(), void slotSetValue(bool)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) }; class QtDoubleSpinBoxFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtDoubleSpinBoxFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtDoubleSpinBoxFactory(QObject *parent = 0); ~QtDoubleSpinBoxFactory(); protected: void connectPropertyManager(QtDoublePropertyManager *manager); QWidget *createEditor(QtDoublePropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtDoublePropertyManager *manager); private: QtDoubleSpinBoxFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtDoubleSpinBoxFactory) Q_DISABLE_COPY(QtDoubleSpinBoxFactory) Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, double)) Q_PRIVATE_SLOT(d_func(), void slotRangeChanged(QtProperty *, double, double)) Q_PRIVATE_SLOT(d_func(), void slotSingleStepChanged(QtProperty *, double)) Q_PRIVATE_SLOT(d_func(), void slotDecimalsChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotSetValue(double)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) }; class QtLineEditFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtLineEditFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtLineEditFactory(QObject *parent = 0); ~QtLineEditFactory(); protected: void connectPropertyManager(QtStringPropertyManager *manager); QWidget *createEditor(QtStringPropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtStringPropertyManager *manager); private: QtLineEditFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtLineEditFactory) Q_DISABLE_COPY(QtLineEditFactory) Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, const QString &)) Q_PRIVATE_SLOT(d_func(), void slotRegExpChanged(QtProperty *, const QRegExp &)) Q_PRIVATE_SLOT(d_func(), void slotSetValue(const QString &)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) }; class QtDateEditFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtDateEditFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtDateEditFactory(QObject *parent = 0); ~QtDateEditFactory(); protected: void connectPropertyManager(QtDatePropertyManager *manager); QWidget *createEditor(QtDatePropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtDatePropertyManager *manager); private: QtDateEditFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtDateEditFactory) Q_DISABLE_COPY(QtDateEditFactory) Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, const QDate &)) Q_PRIVATE_SLOT(d_func(), void slotRangeChanged(QtProperty *, const QDate &, const QDate &)) Q_PRIVATE_SLOT(d_func(), void slotSetValue(const QDate &)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) }; class QtTimeEditFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtTimeEditFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtTimeEditFactory(QObject *parent = 0); ~QtTimeEditFactory(); protected: void connectPropertyManager(QtTimePropertyManager *manager); QWidget *createEditor(QtTimePropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtTimePropertyManager *manager); private: QtTimeEditFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtTimeEditFactory) Q_DISABLE_COPY(QtTimeEditFactory) Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, const QTime &)) Q_PRIVATE_SLOT(d_func(), void slotSetValue(const QTime &)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) }; class QtDateTimeEditFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtDateTimeEditFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtDateTimeEditFactory(QObject *parent = 0); ~QtDateTimeEditFactory(); protected: void connectPropertyManager(QtDateTimePropertyManager *manager); QWidget *createEditor(QtDateTimePropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtDateTimePropertyManager *manager); private: QtDateTimeEditFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtDateTimeEditFactory) Q_DISABLE_COPY(QtDateTimeEditFactory) Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, const QDateTime &)) Q_PRIVATE_SLOT(d_func(), void slotSetValue(const QDateTime &)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) }; class QtKeySequenceEditorFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtKeySequenceEditorFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtKeySequenceEditorFactory(QObject *parent = 0); ~QtKeySequenceEditorFactory(); protected: void connectPropertyManager(QtKeySequencePropertyManager *manager); QWidget *createEditor(QtKeySequencePropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtKeySequencePropertyManager *manager); private: QtKeySequenceEditorFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtKeySequenceEditorFactory) Q_DISABLE_COPY(QtKeySequenceEditorFactory) Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, const QKeySequence &)) Q_PRIVATE_SLOT(d_func(), void slotSetValue(const QKeySequence &)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) }; class QtCharEditorFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtCharEditorFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtCharEditorFactory(QObject *parent = 0); ~QtCharEditorFactory(); protected: void connectPropertyManager(QtCharPropertyManager *manager); QWidget *createEditor(QtCharPropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtCharPropertyManager *manager); private: QtCharEditorFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtCharEditorFactory) Q_DISABLE_COPY(QtCharEditorFactory) Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, const QChar &)) Q_PRIVATE_SLOT(d_func(), void slotSetValue(const QChar &)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) }; class QtEnumEditorFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtEnumEditorFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtEnumEditorFactory(QObject *parent = 0); ~QtEnumEditorFactory(); protected: void connectPropertyManager(QtEnumPropertyManager *manager); QWidget *createEditor(QtEnumPropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtEnumPropertyManager *manager); private: QtEnumEditorFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtEnumEditorFactory) Q_DISABLE_COPY(QtEnumEditorFactory) Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotEnumNamesChanged(QtProperty *, const QStringList &)) Q_PRIVATE_SLOT(d_func(), void slotEnumIconsChanged(QtProperty *, const QMap &)) Q_PRIVATE_SLOT(d_func(), void slotSetValue(int)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) }; class QtCursorEditorFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtCursorEditorFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtCursorEditorFactory(QObject *parent = 0); ~QtCursorEditorFactory(); protected: void connectPropertyManager(QtCursorPropertyManager *manager); QWidget *createEditor(QtCursorPropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtCursorPropertyManager *manager); private: QtCursorEditorFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtCursorEditorFactory) Q_DISABLE_COPY(QtCursorEditorFactory) Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, const QCursor &)) Q_PRIVATE_SLOT(d_func(), void slotEnumChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) }; class QtColorEditorFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtColorEditorFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtColorEditorFactory(QObject *parent = 0); ~QtColorEditorFactory(); protected: void connectPropertyManager(QtColorPropertyManager *manager); QWidget *createEditor(QtColorPropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtColorPropertyManager *manager); private: QtColorEditorFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtColorEditorFactory) Q_DISABLE_COPY(QtColorEditorFactory) Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, const QColor &)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) Q_PRIVATE_SLOT(d_func(), void slotSetValue(const QColor &)) }; class QtFontEditorFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtFontEditorFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtFontEditorFactory(QObject *parent = 0); ~QtFontEditorFactory(); protected: void connectPropertyManager(QtFontPropertyManager *manager); QWidget *createEditor(QtFontPropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtFontPropertyManager *manager); private: QtFontEditorFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtFontEditorFactory) Q_DISABLE_COPY(QtFontEditorFactory) Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, const QFont &)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) Q_PRIVATE_SLOT(d_func(), void slotSetValue(const QFont &)) }; #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif #endif nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/qtgroupboxpropertybrowser.cpp000066400000000000000000000425361455373415500307630ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #include "qtgroupboxpropertybrowser.h" #include #include #include #include #include #include #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif class QtGroupBoxPropertyBrowserPrivate { QtGroupBoxPropertyBrowser *q_ptr; Q_DECLARE_PUBLIC(QtGroupBoxPropertyBrowser) public: void init(QWidget *parent); void propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex); void propertyRemoved(QtBrowserItem *index); void propertyChanged(QtBrowserItem *index); QWidget *createEditor(QtProperty *property, QWidget *parent) const { return q_ptr->createEditor(property, parent); } void slotEditorDestroyed(); void slotUpdate(); struct WidgetItem { WidgetItem() : widget(0), label(0), widgetLabel(0), groupBox(0), layout(0), line(0), parent(0) { } QWidget *widget; // can be null QLabel *label; QLabel *widgetLabel; QGroupBox *groupBox; QGridLayout *layout; QFrame *line; WidgetItem *parent; QList children; }; private: void updateLater(); void updateItem(WidgetItem *item); void insertRow(QGridLayout *layout, int row) const; void removeRow(QGridLayout *layout, int row) const; bool hasHeader(WidgetItem *item) const; QMap m_indexToItem; QMap m_itemToIndex; QMap m_widgetToItem; QGridLayout *m_mainLayout; QList m_children; QList m_recreateQueue; }; void QtGroupBoxPropertyBrowserPrivate::init(QWidget *parent) { m_mainLayout = new QGridLayout(); parent->setLayout(m_mainLayout); QLayoutItem *item = new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding); m_mainLayout->addItem(item, 0, 0); } void QtGroupBoxPropertyBrowserPrivate::slotEditorDestroyed() { QWidget *editor = qobject_cast(q_ptr->sender()); if (!editor) return; if (!m_widgetToItem.contains(editor)) return; m_widgetToItem[editor]->widget = 0; m_widgetToItem.remove(editor); } void QtGroupBoxPropertyBrowserPrivate::slotUpdate() { QListIterator itItem(m_recreateQueue); while (itItem.hasNext()) { WidgetItem *item = itItem.next(); WidgetItem *par = item->parent; QWidget *w = 0; QGridLayout *l = 0; int oldRow = -1; if (!par) { w = q_ptr; l = m_mainLayout; oldRow = m_children.indexOf(item); } else { w = par->groupBox; l = par->layout; oldRow = par->children.indexOf(item); if (hasHeader(par)) oldRow += 2; } if (item->widget) { item->widget->setParent(w); } else if (item->widgetLabel) { item->widgetLabel->setParent(w); } else { item->widgetLabel = new QLabel(w); item->widgetLabel->setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed)); item->widgetLabel->setTextFormat(Qt::PlainText); } int span = 1; if (item->widget) l->addWidget(item->widget, oldRow, 1, 1, 1); else if (item->widgetLabel) l->addWidget(item->widgetLabel, oldRow, 1, 1, 1); else span = 2; item->label = new QLabel(w); item->label->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); l->addWidget(item->label, oldRow, 0, 1, span); updateItem(item); } m_recreateQueue.clear(); } void QtGroupBoxPropertyBrowserPrivate::updateLater() { QTimer::singleShot(0, q_ptr, SLOT(slotUpdate())); } void QtGroupBoxPropertyBrowserPrivate::propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex) { WidgetItem *afterItem = m_indexToItem.value(afterIndex); WidgetItem *parentItem = m_indexToItem.value(index->parent()); WidgetItem *newItem = new WidgetItem(); newItem->parent = parentItem; QGridLayout *layout = 0; QWidget *parentWidget = 0; int row = -1; if (!afterItem) { row = 0; if (parentItem) parentItem->children.insert(0, newItem); else m_children.insert(0, newItem); } else { if (parentItem) { row = parentItem->children.indexOf(afterItem) + 1; parentItem->children.insert(row, newItem); } else { row = m_children.indexOf(afterItem) + 1; m_children.insert(row, newItem); } } if (parentItem && hasHeader(parentItem)) row += 2; if (!parentItem) { layout = m_mainLayout; parentWidget = q_ptr;; } else { if (!parentItem->groupBox) { m_recreateQueue.removeAll(parentItem); WidgetItem *par = parentItem->parent; QWidget *w = 0; QGridLayout *l = 0; int oldRow = -1; if (!par) { w = q_ptr; l = m_mainLayout; oldRow = m_children.indexOf(parentItem); } else { w = par->groupBox; l = par->layout; oldRow = par->children.indexOf(parentItem); if (hasHeader(par)) oldRow += 2; } parentItem->groupBox = new QGroupBox(w); parentItem->layout = new QGridLayout(); parentItem->groupBox->setLayout(parentItem->layout); if (parentItem->label) { l->removeWidget(parentItem->label); delete parentItem->label; parentItem->label = 0; } if (parentItem->widget) { l->removeWidget(parentItem->widget); parentItem->widget->setParent(parentItem->groupBox); parentItem->layout->addWidget(parentItem->widget, 0, 0, 1, 2); parentItem->line = new QFrame(parentItem->groupBox); } else if (parentItem->widgetLabel) { l->removeWidget(parentItem->widgetLabel); delete parentItem->widgetLabel; parentItem->widgetLabel = 0; } if (parentItem->line) { parentItem->line->setFrameShape(QFrame::HLine); parentItem->line->setFrameShadow(QFrame::Sunken); parentItem->layout->addWidget(parentItem->line, 1, 0, 1, 2); } l->addWidget(parentItem->groupBox, oldRow, 0, 1, 2); updateItem(parentItem); } layout = parentItem->layout; parentWidget = parentItem->groupBox; } newItem->label = new QLabel(parentWidget); newItem->label->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); newItem->widget = createEditor(index->property(), parentWidget); if (!newItem->widget) { newItem->widgetLabel = new QLabel(parentWidget); newItem->widgetLabel->setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed)); newItem->widgetLabel->setTextFormat(Qt::PlainText); } else { QObject::connect(newItem->widget, SIGNAL(destroyed()), q_ptr, SLOT(slotEditorDestroyed())); m_widgetToItem[newItem->widget] = newItem; } insertRow(layout, row); int span = 1; if (newItem->widget) layout->addWidget(newItem->widget, row, 1); else if (newItem->widgetLabel) layout->addWidget(newItem->widgetLabel, row, 1); else span = 2; layout->addWidget(newItem->label, row, 0, 1, span); m_itemToIndex[newItem] = index; m_indexToItem[index] = newItem; updateItem(newItem); } void QtGroupBoxPropertyBrowserPrivate::propertyRemoved(QtBrowserItem *index) { WidgetItem *item = m_indexToItem.value(index); m_indexToItem.remove(index); m_itemToIndex.remove(item); WidgetItem *parentItem = item->parent; int row = -1; if (parentItem) { row = parentItem->children.indexOf(item); parentItem->children.removeAt(row); if (hasHeader(parentItem)) row += 2; } else { row = m_children.indexOf(item); m_children.removeAt(row); } if (item->widget) delete item->widget; if (item->label) delete item->label; if (item->widgetLabel) delete item->widgetLabel; if (item->groupBox) delete item->groupBox; if (!parentItem) { removeRow(m_mainLayout, row); } else if (parentItem->children.count() != 0) { removeRow(parentItem->layout, row); } else { WidgetItem *par = parentItem->parent; //QWidget *w = 0; QGridLayout *l = 0; int oldRow = -1; if (!par) { //w = q_ptr; l = m_mainLayout; oldRow = m_children.indexOf(parentItem); } else { //w = par->groupBox; l = par->layout; oldRow = par->children.indexOf(parentItem); if (hasHeader(par)) oldRow += 2; } if (parentItem->widget) { parentItem->widget->hide(); parentItem->widget->setParent(0); } else if (parentItem->widgetLabel) { parentItem->widgetLabel->hide(); parentItem->widgetLabel->setParent(0); } else { //parentItem->widgetLabel = new QLabel(w); } l->removeWidget(parentItem->groupBox); delete parentItem->groupBox; parentItem->groupBox = 0; parentItem->line = 0; parentItem->layout = 0; if (!m_recreateQueue.contains(parentItem)) m_recreateQueue.append(parentItem); updateLater(); } m_recreateQueue.removeAll(item); delete item; } void QtGroupBoxPropertyBrowserPrivate::insertRow(QGridLayout *layout, int row) const { QMap itemToPos; int idx = 0; while (idx < layout->count()) { int r, c, rs, cs; layout->getItemPosition(idx, &r, &c, &rs, &cs); if (r >= row) { itemToPos[layout->takeAt(idx)] = QRect(r + 1, c, rs, cs); } else { idx++; } } const QMap::ConstIterator icend = itemToPos.constEnd(); for (QMap::ConstIterator it = itemToPos.constBegin(); it != icend; ++it) { const QRect r = it.value(); layout->addItem(it.key(), r.x(), r.y(), r.width(), r.height()); } } void QtGroupBoxPropertyBrowserPrivate::removeRow(QGridLayout *layout, int row) const { QMap itemToPos; int idx = 0; while (idx < layout->count()) { int r, c, rs, cs; layout->getItemPosition(idx, &r, &c, &rs, &cs); if (r > row) { itemToPos[layout->takeAt(idx)] = QRect(r - 1, c, rs, cs); } else { idx++; } } const QMap::ConstIterator icend = itemToPos.constEnd(); for (QMap::ConstIterator it = itemToPos.constBegin(); it != icend; ++it) { const QRect r = it.value(); layout->addItem(it.key(), r.x(), r.y(), r.width(), r.height()); } } bool QtGroupBoxPropertyBrowserPrivate::hasHeader(WidgetItem *item) const { if (item->widget) return true; return false; } void QtGroupBoxPropertyBrowserPrivate::propertyChanged(QtBrowserItem *index) { WidgetItem *item = m_indexToItem.value(index); updateItem(item); } void QtGroupBoxPropertyBrowserPrivate::updateItem(WidgetItem *item) { QtProperty *property = m_itemToIndex[item]->property(); if (item->groupBox) { QFont font = item->groupBox->font(); font.setUnderline(property->isModified()); item->groupBox->setFont(font); item->groupBox->setTitle(property->propertyName()); item->groupBox->setToolTip(property->toolTip()); item->groupBox->setStatusTip(property->statusTip()); item->groupBox->setWhatsThis(property->whatsThis()); item->groupBox->setEnabled(property->isEnabled()); } if (item->label) { QFont font = item->label->font(); font.setUnderline(property->isModified()); item->label->setFont(font); item->label->setText(property->propertyName()); item->label->setToolTip(property->toolTip()); item->label->setStatusTip(property->statusTip()); item->label->setWhatsThis(property->whatsThis()); item->label->setEnabled(property->isEnabled()); } if (item->widgetLabel) { QFont font = item->widgetLabel->font(); font.setUnderline(false); item->widgetLabel->setFont(font); item->widgetLabel->setText(property->valueText()); item->widgetLabel->setToolTip(property->valueText()); item->widgetLabel->setEnabled(property->isEnabled()); } if (item->widget) { QFont font = item->widget->font(); font.setUnderline(false); item->widget->setFont(font); item->widget->setEnabled(property->isEnabled()); item->widget->setToolTip(property->valueText()); } //item->setIcon(1, property->valueIcon()); } /*! \class QtGroupBoxPropertyBrowser \brief The QtGroupBoxPropertyBrowser class provides a QGroupBox based property browser. A property browser is a widget that enables the user to edit a given set of properties. Each property is represented by a label specifying the property's name, and an editing widget (e.g. a line edit or a combobox) holding its value. A property can have zero or more subproperties. QtGroupBoxPropertyBrowser provides group boxes for all nested properties, i.e. subproperties are enclosed by a group box with the parent property's name as its title. For example: \image qtgroupboxpropertybrowser.png Use the QtAbstractPropertyBrowser API to add, insert and remove properties from an instance of the QtGroupBoxPropertyBrowser class. The properties themselves are created and managed by implementations of the QtAbstractPropertyManager class. \sa QtTreePropertyBrowser, QtAbstractPropertyBrowser */ /*! Creates a property browser with the given \a parent. */ QtGroupBoxPropertyBrowser::QtGroupBoxPropertyBrowser(QWidget *parent) : QtAbstractPropertyBrowser(parent) { d_ptr = new QtGroupBoxPropertyBrowserPrivate; d_ptr->q_ptr = this; d_ptr->init(this); } /*! Destroys this property browser. Note that the properties that were inserted into this browser are \e not destroyed since they may still be used in other browsers. The properties are owned by the manager that created them. \sa QtProperty, QtAbstractPropertyManager */ QtGroupBoxPropertyBrowser::~QtGroupBoxPropertyBrowser() { const QMap::ConstIterator icend = d_ptr->m_itemToIndex.constEnd(); for (QMap::ConstIterator it = d_ptr->m_itemToIndex.constBegin(); it != icend; ++it) delete it.key(); delete d_ptr; } /*! \reimp */ void QtGroupBoxPropertyBrowser::itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem) { d_ptr->propertyInserted(item, afterItem); } /*! \reimp */ void QtGroupBoxPropertyBrowser::itemRemoved(QtBrowserItem *item) { d_ptr->propertyRemoved(item); } /*! \reimp */ void QtGroupBoxPropertyBrowser::itemChanged(QtBrowserItem *item) { d_ptr->propertyChanged(item); } #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif #include "moc_qtgroupboxpropertybrowser.cpp" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/qtgroupboxpropertybrowser.h000066400000000000000000000055371455373415500304300ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #ifndef QTGROUPBOXPROPERTYBROWSER_H #define QTGROUPBOXPROPERTYBROWSER_H #include "qtpropertybrowser.h" #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif class QtGroupBoxPropertyBrowserPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtGroupBoxPropertyBrowser : public QtAbstractPropertyBrowser { Q_OBJECT public: QtGroupBoxPropertyBrowser(QWidget *parent = 0); ~QtGroupBoxPropertyBrowser(); protected: virtual void itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem); virtual void itemRemoved(QtBrowserItem *item); virtual void itemChanged(QtBrowserItem *item); private: QtGroupBoxPropertyBrowserPrivate *d_ptr; Q_DECLARE_PRIVATE(QtGroupBoxPropertyBrowser) Q_DISABLE_COPY(QtGroupBoxPropertyBrowser) Q_PRIVATE_SLOT(d_func(), void slotUpdate()) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed()) }; #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif #endif nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/qtpropertybrowser.cpp000066400000000000000000001776001455373415500271760ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #include "qtpropertybrowser.h" #include #include #include #if defined(Q_CC_MSVC) # pragma warning(disable: 4786) /* MS VS 6: truncating debug info after 255 characters */ #endif #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif class QtPropertyPrivate { public: QtPropertyPrivate(QtAbstractPropertyManager *manager) : m_enabled(true), m_selectable(true), m_modified(false), m_manager(manager) {} QtProperty *q_ptr; QSet m_parentItems; QList m_subItems; QString m_toolTip; QString m_statusTip; QString m_whatsThis; QString m_name; QString m_id; bool m_enabled; bool m_selectable; bool m_modified; QtAbstractPropertyManager * const m_manager; }; class QtAbstractPropertyManagerPrivate { QtAbstractPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtAbstractPropertyManager) public: void propertyDestroyed(QtProperty *property); void propertyChanged(QtProperty *property) const; void propertyRemoved(QtProperty *property, QtProperty *parentProperty) const; void propertyInserted(QtProperty *property, QtProperty *parentProperty, QtProperty *afterProperty) const; QSet m_properties; }; /*! \class QtProperty \brief The QtProperty class encapsulates an instance of a property. Properties are created by objects of QtAbstractPropertyManager subclasses; a manager can create properties of a given type, and is used in conjunction with the QtAbstractPropertyBrowser class. A property is always owned by the manager that created it, which can be retrieved using the propertyManager() function. QtProperty contains the most common property attributes, and provides functions for retrieving as well as setting their values: \table \header \o Getter \o Setter \row \o propertyName() \o setPropertyName() \row \o statusTip() \o setStatusTip() \row \o toolTip() \o setToolTip() \row \o whatsThis() \o setWhatsThis() \row \o isEnabled() \o setEnabled() \row \o isModified() \o setModified() \row \o valueText() \o Nop \row \o valueIcon() \o Nop \endtable It is also possible to nest properties: QtProperty provides the addSubProperty(), insertSubProperty() and removeSubProperty() functions to manipulate the set of subproperties. Use the subProperties() function to retrieve a property's current set of subproperties. Note that nested properties are not owned by the parent property, i.e. each subproperty is owned by the manager that created it. \sa QtAbstractPropertyManager, QtBrowserItem */ /*! Creates a property with the given \a manager. This constructor is only useful when creating a custom QtProperty subclass (e.g. QtVariantProperty). To create a regular QtProperty object, use the QtAbstractPropertyManager::addProperty() function instead. \sa QtAbstractPropertyManager::addProperty() */ QtProperty::QtProperty(QtAbstractPropertyManager *manager) { d_ptr = new QtPropertyPrivate(manager); d_ptr->q_ptr = this; } /*! Destroys this property. Note that subproperties are detached but not destroyed, i.e. they can still be used in another context. \sa QtAbstractPropertyManager::clear() */ QtProperty::~QtProperty() { QSetIterator itParent(d_ptr->m_parentItems); while (itParent.hasNext()) { QtProperty *property = itParent.next(); property->d_ptr->m_manager->d_ptr->propertyRemoved(this, property); } d_ptr->m_manager->d_ptr->propertyDestroyed(this); QListIterator itChild(d_ptr->m_subItems); while (itChild.hasNext()) { QtProperty *property = itChild.next(); property->d_ptr->m_parentItems.remove(this); } itParent.toFront(); while (itParent.hasNext()) { QtProperty *property = itParent.next(); property->d_ptr->m_subItems.removeAll(this); } delete d_ptr; } /*! Returns the set of subproperties. Note that subproperties are not owned by \e this property, but by the manager that created them. \sa insertSubProperty(), removeSubProperty() */ QList QtProperty::subProperties() const { return d_ptr->m_subItems; } /*! Returns a pointer to the manager that owns this property. */ QtAbstractPropertyManager *QtProperty::propertyManager() const { return d_ptr->m_manager; } /*! Returns the property's tool tip. \sa setToolTip() */ QString QtProperty::toolTip() const { return d_ptr->m_toolTip; } /*! Returns the property's status tip. \sa setStatusTip() */ QString QtProperty::statusTip() const { return d_ptr->m_statusTip; } /*! Returns the property's "What's This" help text. \sa setWhatsThis() */ QString QtProperty::whatsThis() const { return d_ptr->m_whatsThis; } /*! Returns the property's name. \sa setPropertyName() */ QString QtProperty::propertyName() const { return d_ptr->m_name; } /*! Returns the property's id. \sa setPropertyId() */ QString QtProperty::propertyId() const { return d_ptr->m_id; } /*! Returns whether the property is enabled. \sa setEnabled() */ bool QtProperty::isEnabled() const { return d_ptr->m_enabled; } bool QtProperty::isSelectable() const { return d_ptr->m_selectable; } /*! Returns whether the property is modified. \sa setModified() */ bool QtProperty::isModified() const { return d_ptr->m_modified; } /*! Returns whether the property has a value. \sa QtAbstractPropertyManager::hasValue() */ bool QtProperty::hasValue() const { return d_ptr->m_manager->hasValue(this); } /*! Returns an icon representing the current state of this property. If the given property type can not generate such an icon, this function returns an invalid icon. \sa QtAbstractPropertyManager::valueIcon() */ QIcon QtProperty::valueIcon() const { return d_ptr->m_manager->valueIcon(this); } /*! Returns a string representing the current state of this property. If the given property type can not generate such a string, this function returns an empty string. \sa QtAbstractPropertyManager::valueText() */ QString QtProperty::valueText() const { return d_ptr->m_manager->valueText(this); } /*! Returns True if this property is equal to \a otherProperty The list of parent or sub properties are not considered in the comparison. */ bool QtProperty::compare(QtProperty* otherProperty)const { return (this->propertyId() == otherProperty->propertyId() && this->propertyName() == otherProperty->propertyName() && this->toolTip() == otherProperty->toolTip() && this->statusTip() == otherProperty->statusTip() && this->whatsThis() == otherProperty->whatsThis() && this->isEnabled() == otherProperty->isEnabled() && this->isModified() == otherProperty->isModified()); } /*! Sets the property's tool tip to the given \a text. \sa toolTip() */ void QtProperty::setToolTip(const QString &text) { if (d_ptr->m_toolTip == text) return; d_ptr->m_toolTip = text; propertyChanged(); } /*! Sets the property's status tip to the given \a text. \sa statusTip() */ void QtProperty::setStatusTip(const QString &text) { if (d_ptr->m_statusTip == text) return; d_ptr->m_statusTip = text; propertyChanged(); } /*! Sets the property's "What's This" help text to the given \a text. \sa whatsThis() */ void QtProperty::setWhatsThis(const QString &text) { if (d_ptr->m_whatsThis == text) return; d_ptr->m_whatsThis = text; propertyChanged(); } /*! \fn void QtProperty::setPropertyName(const QString &name) Sets the property's name to the given \a name. \sa propertyName() */ void QtProperty::setPropertyName(const QString &text) { if (d_ptr->m_name == text) return; d_ptr->m_name = text; propertyChanged(); } /*! \fn void QtProperty::setPropertyId(const QString &id) Sets the property's id to the given \a id. \sa propertyId() */ void QtProperty::setPropertyId(const QString &text) { if (d_ptr->m_id == text) return; d_ptr->m_id = text; } /*! Enables or disables the property according to the passed \a enable value. \sa isEnabled() */ void QtProperty::setEnabled(bool enable) { if (d_ptr->m_enabled == enable) return; d_ptr->m_enabled = enable; propertyChanged(); } void QtProperty::setSelectable(bool selectable) { if (d_ptr->m_selectable == selectable) return; d_ptr->m_selectable = selectable; propertyChanged(); } /*! Sets the property's modified state according to the passed \a modified value. \sa isModified() */ void QtProperty::setModified(bool modified) { if (d_ptr->m_modified == modified) return; d_ptr->m_modified = modified; propertyChanged(); } /*! Returns whether the property is sub property. */ bool QtProperty::isSubProperty()const { return d_ptr->m_parentItems.count(); } /*! Appends the given \a property to this property's subproperties. If the given \a property already is added, this function does nothing. \sa insertSubProperty(), removeSubProperty() */ void QtProperty::addSubProperty(QtProperty *property) { QtProperty *after = 0; if (d_ptr->m_subItems.count() > 0) after = d_ptr->m_subItems.last(); insertSubProperty(property, after); } /*! \fn void QtProperty::insertSubProperty(QtProperty *property, QtProperty *precedingProperty) Inserts the given \a property after the specified \a precedingProperty into this property's list of subproperties. If \a precedingProperty is 0, the specified \a property is inserted at the beginning of the list. If the given \a property already is inserted, this function does nothing. \sa addSubProperty(), removeSubProperty() */ void QtProperty::insertSubProperty(QtProperty *property, QtProperty *afterProperty) { if (!property) return; if (property == this) return; // traverse all children of item. if this item is a child of item then cannot add. QList pendingList = property->subProperties(); QMap visited; while (!pendingList.isEmpty()) { QtProperty *i = pendingList.first(); if (i == this) return; pendingList.removeFirst(); if (visited.contains(i)) continue; visited[i] = true; pendingList += i->subProperties(); } pendingList = subProperties(); int pos = 0; int newPos = 0; QtProperty *properAfterProperty = 0; while (pos < pendingList.count()) { QtProperty *i = pendingList.at(pos); if (i == property) return; // if item is already inserted in this item then cannot add. if (i == afterProperty) { newPos = pos + 1; properAfterProperty = afterProperty; } pos++; } d_ptr->m_subItems.insert(newPos, property); property->d_ptr->m_parentItems.insert(this); d_ptr->m_manager->d_ptr->propertyInserted(property, this, properAfterProperty); } /*! Removes the given \a property from the list of subproperties without deleting it. \sa addSubProperty(), insertSubProperty() */ void QtProperty::removeSubProperty(QtProperty *property) { if (!property) return; d_ptr->m_manager->d_ptr->propertyRemoved(property, this); QList pendingList = subProperties(); int pos = 0; while (pos < pendingList.count()) { if (pendingList.at(pos) == property) { d_ptr->m_subItems.removeAt(pos); property->d_ptr->m_parentItems.remove(this); return; } pos++; } } /*! \internal */ void QtProperty::propertyChanged() { d_ptr->m_manager->d_ptr->propertyChanged(this); } //////////////////////////////// void QtAbstractPropertyManagerPrivate::propertyDestroyed(QtProperty *property) { if (m_properties.contains(property)) { emit q_ptr->propertyDestroyed(property); q_ptr->uninitializeProperty(property); m_properties.remove(property); } } void QtAbstractPropertyManagerPrivate::propertyChanged(QtProperty *property) const { emit q_ptr->propertyChanged(property); } void QtAbstractPropertyManagerPrivate::propertyRemoved(QtProperty *property, QtProperty *parentProperty) const { emit q_ptr->propertyRemoved(property, parentProperty); } void QtAbstractPropertyManagerPrivate::propertyInserted(QtProperty *property, QtProperty *parentProperty, QtProperty *afterProperty) const { emit q_ptr->propertyInserted(property, parentProperty, afterProperty); } /*! \class QtAbstractPropertyManager \brief The QtAbstractPropertyManager provides an interface for property managers. A manager can create and manage properties of a given type, and is used in conjunction with the QtAbstractPropertyBrowser class. When using a property browser widget, the properties are created and managed by implementations of the QtAbstractPropertyManager class. To ensure that the properties' values will be displayed using suitable editing widgets, the managers are associated with objects of QtAbstractEditorFactory subclasses. The property browser will use these associations to determine which factories it should use to create the preferred editing widgets. The QtAbstractPropertyManager class provides common functionality like creating a property using the addProperty() function, and retrieving the properties created by the manager using the properties() function. The class also provides signals that are emitted when the manager's properties change: propertyInserted(), propertyRemoved(), propertyChanged() and propertyDestroyed(). QtAbstractPropertyManager subclasses are supposed to provide their own type specific API. Note that several ready-made implementations are available: \list \o QtBoolPropertyManager \o QtColorPropertyManager \o QtDatePropertyManager \o QtDateTimePropertyManager \o QtDoublePropertyManager \o QtEnumPropertyManager \o QtFlagPropertyManager \o QtFontPropertyManager \o QtGroupPropertyManager \o QtIntPropertyManager \o QtPointPropertyManager \o QtRectPropertyManager \o QtSizePropertyManager \o QtSizePolicyPropertyManager \o QtStringPropertyManager \o QtTimePropertyManager \o QtVariantPropertyManager \endlist \sa QtAbstractEditorFactoryBase, QtAbstractPropertyBrowser, QtProperty */ /*! \fn void QtAbstractPropertyManager::propertyInserted(QtProperty *newProperty, QtProperty *parentProperty, QtProperty *precedingProperty) This signal is emitted when a new subproperty is inserted into an existing property, passing pointers to the \a newProperty, \a parentProperty and \a precedingProperty as parameters. If \a precedingProperty is 0, the \a newProperty was inserted at the beginning of the \a parentProperty's subproperties list. Note that signal is emitted only if the \a parentProperty is created by this manager. \sa QtAbstractPropertyBrowser::itemInserted() */ /*! \fn void QtAbstractPropertyManager::propertyChanged(QtProperty *property) This signal is emitted whenever a property's data changes, passing a pointer to the \a property as parameter. Note that signal is only emitted for properties that are created by this manager. \sa QtAbstractPropertyBrowser::itemChanged() */ /*! \fn void QtAbstractPropertyManager::propertyRemoved(QtProperty *property, QtProperty *parent) This signal is emitted when a subproperty is removed, passing pointers to the removed \a property and the \a parent property as parameters. Note that signal is emitted only when the \a parent property is created by this manager. \sa QtAbstractPropertyBrowser::itemRemoved() */ /*! \fn void QtAbstractPropertyManager::propertyDestroyed(QtProperty *property) This signal is emitted when the specified \a property is about to be destroyed. Note that signal is only emitted for properties that are created by this manager. \sa clear(), uninitializeProperty() */ /*! \fn void QtAbstractPropertyBrowser::currentItemChanged(QtBrowserItem *current) This signal is emitted when the current item changes. The current item is specified by \a current. \sa QtAbstractPropertyBrowser::setCurrentItem() */ /*! Creates an abstract property manager with the given \a parent. */ QtAbstractPropertyManager::QtAbstractPropertyManager(QObject *parent) : QObject(parent) { d_ptr = new QtAbstractPropertyManagerPrivate; d_ptr->q_ptr = this; } /*! Destroys the manager. All properties created by the manager are destroyed. */ QtAbstractPropertyManager::~QtAbstractPropertyManager() { clear(); delete d_ptr; } /*! Destroys all the properties that this manager has created. \sa propertyDestroyed(), uninitializeProperty() */ void QtAbstractPropertyManager::clear() const { while (!properties().isEmpty()) { QSetIterator itProperty(properties()); QtProperty *prop = itProperty.next(); delete prop; } } /*! Returns the set of properties created by this manager. \sa addProperty() */ QSet QtAbstractPropertyManager::properties() const { return d_ptr->m_properties; } /*! Returns whether the given \a property has a value. The default implementation of this function returns true. \sa QtProperty::hasValue() */ bool QtAbstractPropertyManager::hasValue(const QtProperty *property) const { Q_UNUSED(property) return true; } /*! Returns an icon representing the current state of the given \a property. The default implementation of this function returns an invalid icon. \sa QtProperty::valueIcon() */ QIcon QtAbstractPropertyManager::valueIcon(const QtProperty *property) const { Q_UNUSED(property) return QIcon(); } /*! Returns a string representing the current state of the given \a property. The default implementation of this function returns an empty string. \sa QtProperty::valueText() */ QString QtAbstractPropertyManager::valueText(const QtProperty *property) const { Q_UNUSED(property) return QString(); } /*! Creates a property with the given \a name which then is owned by this manager. Internally, this function calls the createProperty() and initializeProperty() functions. \sa initializeProperty(), properties() */ QtProperty *QtAbstractPropertyManager::addProperty(const QString &name) { QtProperty *property = createProperty(); if (property) { property->setPropertyName(name); d_ptr->m_properties.insert(property); initializeProperty(property); } return property; } /*! Return the QtProperty object matching \a id or Null if any. \sa addProperty(), setPropertyId(const QString&), properties() */ QtProperty * QtAbstractPropertyManager::qtProperty(const QString &id)const { foreach(QtProperty* prop, d_ptr->m_properties) { if (prop->propertyId() == id) { return prop; } } return 0; } /*! Creates a property. The base implementation produce QtProperty instances; Reimplement this function to make this manager produce objects of a QtProperty subclass. \sa addProperty(), initializeProperty() */ QtProperty *QtAbstractPropertyManager::createProperty() { return new QtProperty(this); } /*! \fn void QtAbstractPropertyManager::initializeProperty(QtProperty *property) = 0 This function is called whenever a new valid property pointer has been created, passing the pointer as parameter. The purpose is to let the manager know that the \a property has been created so that it can provide additional attributes for the new property, e.g. QtIntPropertyManager adds \l {QtIntPropertyManager::value()}{value}, \l {QtIntPropertyManager::minimum()}{minimum} and \l {QtIntPropertyManager::maximum()}{maximum} attributes. Since each manager subclass adds type specific attributes, this function is pure virtual and must be reimplemented when deriving from the QtAbstractPropertyManager class. \sa addProperty(), createProperty() */ /*! This function is called just before the specified \a property is destroyed. The purpose is to let the property manager know that the \a property is being destroyed so that it can remove the property's additional attributes. \sa clear(), propertyDestroyed() */ void QtAbstractPropertyManager::uninitializeProperty(QtProperty *property) { Q_UNUSED(property) } //////////////////////////////////// /*! \class QtAbstractEditorFactoryBase \brief The QtAbstractEditorFactoryBase provides an interface for editor factories. An editor factory is a class that is able to create an editing widget of a specified type (e.g. line edits or comboboxes) for a given QtProperty object, and it is used in conjunction with the QtAbstractPropertyManager and QtAbstractPropertyBrowser classes. When using a property browser widget, the properties are created and managed by implementations of the QtAbstractPropertyManager class. To ensure that the properties' values will be displayed using suitable editing widgets, the managers are associated with objects of QtAbstractEditorFactory subclasses. The property browser will use these associations to determine which factories it should use to create the preferred editing widgets. Typically, an editor factory is created by subclassing the QtAbstractEditorFactory template class which inherits QtAbstractEditorFactoryBase. But note that several ready-made implementations are available: \list \o QtCheckBoxFactory \o QtDateEditFactory \o QtDateTimeEditFactory \o QtDoubleSpinBoxFactory \o QtEnumEditorFactory \o QtLineEditFactory \o QtScrollBarFactory \o QtSliderFactory \o QtSpinBoxFactory \o QtTimeEditFactory \o QtVariantEditorFactory \endlist \sa QtAbstractPropertyManager, QtAbstractPropertyBrowser */ /*! \fn virtual QWidget *QtAbstractEditorFactoryBase::createEditor(QtProperty *property, QWidget *parent) = 0 Creates an editing widget (with the given \a parent) for the given \a property. This function is reimplemented in QtAbstractEditorFactory template class which also provides a pure virtual convenience overload of this function enabling access to the property's manager. \sa QtAbstractEditorFactory::createEditor() */ /*! \fn QtAbstractEditorFactoryBase::QtAbstractEditorFactoryBase(QObject *parent = 0) Creates an abstract editor factory with the given \a parent. */ /*! \fn virtual void QtAbstractEditorFactoryBase::breakConnection(QtAbstractPropertyManager *manager) = 0 \internal Detaches property manager from factory. This method is reimplemented in QtAbstractEditorFactory template subclass. You don't need to reimplement it in your subclasses. Instead implement more convenient QtAbstractEditorFactory::disconnectPropertyManager() which gives you access to particular manager subclass. */ /*! \fn virtual void QtAbstractEditorFactoryBase::managerDestroyed(QObject *manager) = 0 \internal This method is called when property manager is being destroyed. Basically it notifies factory not to produce editors for properties owned by \a manager. You don't need to reimplement it in your subclass. This method is implemented in QtAbstractEditorFactory template subclass. */ /*! \class QtAbstractEditorFactory \brief The QtAbstractEditorFactory is the base template class for editor factories. An editor factory is a class that is able to create an editing widget of a specified type (e.g. line edits or comboboxes) for a given QtProperty object, and it is used in conjunction with the QtAbstractPropertyManager and QtAbstractPropertyBrowser classes. Note that the QtAbstractEditorFactory functions are using the PropertyManager template argument class which can be any QtAbstractPropertyManager subclass. For example: \code QtSpinBoxFactory *factory; QSet managers = factory->propertyManagers(); \endcode Note that QtSpinBoxFactory by definition creates editing widgets \e only for properties created by QtIntPropertyManager. When using a property browser widget, the properties are created and managed by implementations of the QtAbstractPropertyManager class. To ensure that the properties' values will be displayed using suitable editing widgets, the managers are associated with objects of QtAbstractEditorFactory subclasses. The property browser will use these associations to determine which factories it should use to create the preferred editing widgets. A QtAbstractEditorFactory object is capable of producing editors for several property managers at the same time. To create an association between this factory and a given manager, use the addPropertyManager() function. Use the removePropertyManager() function to make this factory stop producing editors for a given property manager. Use the propertyManagers() function to retrieve the set of managers currently associated with this factory. Several ready-made implementations of the QtAbstractEditorFactory class are available: \list \o QtCheckBoxFactory \o QtDateEditFactory \o QtDateTimeEditFactory \o QtDoubleSpinBoxFactory \o QtEnumEditorFactory \o QtLineEditFactory \o QtScrollBarFactory \o QtSliderFactory \o QtSpinBoxFactory \o QtTimeEditFactory \o QtVariantEditorFactory \endlist When deriving from the QtAbstractEditorFactory class, several pure virtual functions must be implemented: the connectPropertyManager() function is used by the factory to connect to the given manager's signals, the createEditor() function is supposed to create an editor for the given property controlled by the given manager, and finally the disconnectPropertyManager() function is used by the factory to disconnect from the specified manager's signals. \sa QtAbstractEditorFactoryBase, QtAbstractPropertyManager */ /*! \fn QtAbstractEditorFactory::QtAbstractEditorFactory(QObject *parent = 0) Creates an editor factory with the given \a parent. \sa addPropertyManager() */ /*! \fn QWidget *QtAbstractEditorFactory::createEditor(QtProperty *property, QWidget *parent) Creates an editing widget (with the given \a parent) for the given \a property. */ /*! \fn void QtAbstractEditorFactory::addPropertyManager(PropertyManager *manager) Adds the given \a manager to this factory's set of managers, making this factory produce editing widgets for properties created by the given manager. The PropertyManager type is a template argument class, and represents the chosen QtAbstractPropertyManager subclass. \sa propertyManagers(), removePropertyManager() */ /*! \fn void QtAbstractEditorFactory::removePropertyManager(PropertyManager *manager) Removes the given \a manager from this factory's set of managers. The PropertyManager type is a template argument class, and may be any QtAbstractPropertyManager subclass. \sa propertyManagers(), addPropertyManager() */ /*! \fn virtual void QtAbstractEditorFactory::connectPropertyManager(PropertyManager *manager) = 0 Connects this factory to the given \a manager's signals. The PropertyManager type is a template argument class, and represents the chosen QtAbstractPropertyManager subclass. This function is used internally by the addPropertyManager() function, and makes it possible to update an editing widget when the associated property's data changes. This is typically done in custom slots responding to the signals emitted by the property's manager, e.g. QtIntPropertyManager::valueChanged() and QtIntPropertyManager::rangeChanged(). \sa propertyManagers(), disconnectPropertyManager() */ /*! \fn virtual QWidget *QtAbstractEditorFactory::createEditor(PropertyManager *manager, QtProperty *property, QWidget *parent) = 0 Creates an editing widget with the given \a parent for the specified \a property created by the given \a manager. The PropertyManager type is a template argument class, and represents the chosen QtAbstractPropertyManager subclass. This function must be implemented in derived classes: It is recommended to store a pointer to the widget and map it to the given \a property, since the widget must be updated whenever the associated property's data changes. This is typically done in custom slots responding to the signals emitted by the property's manager, e.g. QtIntPropertyManager::valueChanged() and QtIntPropertyManager::rangeChanged(). \sa connectPropertyManager() */ /*! \fn virtual void QtAbstractEditorFactory::disconnectPropertyManager(PropertyManager *manager) = 0 Disconnects this factory from the given \a manager's signals. The PropertyManager type is a template argument class, and represents the chosen QtAbstractPropertyManager subclass. This function is used internally by the removePropertyManager() function. \sa propertyManagers(), connectPropertyManager() */ /*! \fn QSet QtAbstractEditorFactory::propertyManagers() const Returns the factory's set of associated managers. The PropertyManager type is a template argument class, and represents the chosen QtAbstractPropertyManager subclass. \sa addPropertyManager(), removePropertyManager() */ /*! \fn PropertyManager *QtAbstractEditorFactory::propertyManager(QtProperty *property) const Returns the property manager for the given \a property, or 0 if the given \a property doesn't belong to any of this factory's registered managers. The PropertyManager type is a template argument class, and represents the chosen QtAbstractPropertyManager subclass. \sa propertyManagers() */ /*! \fn virtual void QtAbstractEditorFactory::managerDestroyed(QObject *manager) \internal \reimp */ //////////////////////////////////// class QtBrowserItemPrivate { public: QtBrowserItemPrivate(QtAbstractPropertyBrowser *browser, QtProperty *property, QtBrowserItem *parent) : m_browser(browser), m_property(property), m_parent(parent), q_ptr(0) {} void addChild(QtBrowserItem *index, QtBrowserItem *after); void removeChild(QtBrowserItem *index); QtAbstractPropertyBrowser * const m_browser; QtProperty *m_property; QtBrowserItem *m_parent; QtBrowserItem *q_ptr; QList m_children; }; void QtBrowserItemPrivate::addChild(QtBrowserItem *index, QtBrowserItem *after) { if (m_children.contains(index)) return; int idx = m_children.indexOf(after) + 1; // we insert after returned idx, if it was -1 then we set idx to 0; m_children.insert(idx, index); } void QtBrowserItemPrivate::removeChild(QtBrowserItem *index) { m_children.removeAll(index); } /*! \class QtBrowserItem \brief The QtBrowserItem class represents a property in a property browser instance. Browser items are created whenever a QtProperty is inserted to the property browser. A QtBrowserItem uniquely identifies a browser's item. Thus, if the same QtProperty is inserted multiple times, each occurrence gets its own unique QtBrowserItem. The items are owned by QtAbstractPropertyBrowser and automatically deleted when they are removed from the browser. You can traverse a browser's properties by calling parent() and children(). The property and the browser associated with an item are available as property() and browser(). \sa QtAbstractPropertyBrowser, QtProperty */ /*! Returns the property which is accosiated with this item. Note that several items can be associated with the same property instance in the same property browser. \sa QtAbstractPropertyBrowser::items() */ QtProperty *QtBrowserItem::property() const { return d_ptr->m_property; } /*! Returns the parent item of \e this item. Returns 0 if \e this item is associated with top-level property in item's property browser. \sa children() */ QtBrowserItem *QtBrowserItem::parent() const { return d_ptr->m_parent; } /*! Returns the children items of \e this item. The properties reproduced from children items are always the same as reproduced from associated property' children, for example: \code QtBrowserItem *item; QList childrenItems = item->children(); QList childrenProperties = item->property()->subProperties(); \endcode The \e childrenItems list represents the same list as \e childrenProperties. */ QList QtBrowserItem::children() const { return d_ptr->m_children; } /*! Returns the property browser which owns \e this item. */ QtAbstractPropertyBrowser *QtBrowserItem::browser() const { return d_ptr->m_browser; } QtBrowserItem::QtBrowserItem(QtAbstractPropertyBrowser *browser, QtProperty *property, QtBrowserItem *parent) { d_ptr = new QtBrowserItemPrivate(browser, property, parent); d_ptr->q_ptr = this; } QtBrowserItem::~QtBrowserItem() { delete d_ptr; } //////////////////////////////////// typedef QMap > Map1; typedef QMap > > Map2; Q_GLOBAL_STATIC(Map1, m_viewToManagerToFactory) Q_GLOBAL_STATIC(Map2, m_managerToFactoryToViews) class QtAbstractPropertyBrowserPrivate { QtAbstractPropertyBrowser *q_ptr; Q_DECLARE_PUBLIC(QtAbstractPropertyBrowser) public: QtAbstractPropertyBrowserPrivate(); void insertSubTree(QtProperty *property, QtProperty *parentProperty); void removeSubTree(QtProperty *property, QtProperty *parentProperty); void createBrowserIndexes(QtProperty *property, QtProperty *parentProperty, QtProperty *afterProperty); void removeBrowserIndexes(QtProperty *property, QtProperty *parentProperty); QtBrowserItem *createBrowserIndex(QtProperty *property, QtBrowserItem *parentIndex, QtBrowserItem *afterIndex); void removeBrowserIndex(QtBrowserItem *index); void clearIndex(QtBrowserItem *index); void slotPropertyInserted(QtProperty *property, QtProperty *parentProperty, QtProperty *afterProperty); void slotPropertyRemoved(QtProperty *property, QtProperty *parentProperty); void slotPropertyDestroyed(QtProperty *property); void slotPropertyDataChanged(QtProperty *property); QList m_subItems; QMap > m_managerToProperties; QMap > m_propertyToParents; QMap m_topLevelPropertyToIndex; QList m_topLevelIndexes; QMap > m_propertyToIndexes; QtBrowserItem *m_currentItem; }; QtAbstractPropertyBrowserPrivate::QtAbstractPropertyBrowserPrivate() : m_currentItem(0) { } void QtAbstractPropertyBrowserPrivate::insertSubTree(QtProperty *property, QtProperty *parentProperty) { if (m_propertyToParents.contains(property)) { // property was already inserted, so its manager is connected // and all its children are inserted and theirs managers are connected // we just register new parent (parent has to be new). m_propertyToParents[property].append(parentProperty); // don't need to update m_managerToProperties map since // m_managerToProperties[manager] already contains property. return; } QtAbstractPropertyManager *manager = property->propertyManager(); if (m_managerToProperties[manager].isEmpty()) { // connect manager's signals q_ptr->connect(manager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), q_ptr, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); q_ptr->connect(manager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), q_ptr, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); q_ptr->connect(manager, SIGNAL(propertyDestroyed(QtProperty *)), q_ptr, SLOT(slotPropertyDestroyed(QtProperty *))); q_ptr->connect(manager, SIGNAL(propertyChanged(QtProperty *)), q_ptr, SLOT(slotPropertyDataChanged(QtProperty *))); } m_managerToProperties[manager].append(property); m_propertyToParents[property].append(parentProperty); QList subList = property->subProperties(); QListIterator itSub(subList); while (itSub.hasNext()) { QtProperty *subProperty = itSub.next(); insertSubTree(subProperty, property); } } void QtAbstractPropertyBrowserPrivate::removeSubTree(QtProperty *property, QtProperty *parentProperty) { if (!m_propertyToParents.contains(property)) { // ASSERT return; } m_propertyToParents[property].removeAll(parentProperty); if (!m_propertyToParents[property].isEmpty()) return; m_propertyToParents.remove(property); QtAbstractPropertyManager *manager = property->propertyManager(); m_managerToProperties[manager].removeAll(property); if (m_managerToProperties[manager].isEmpty()) { // disconnect manager's signals q_ptr->disconnect(manager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), q_ptr, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); q_ptr->disconnect(manager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), q_ptr, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); q_ptr->disconnect(manager, SIGNAL(propertyDestroyed(QtProperty *)), q_ptr, SLOT(slotPropertyDestroyed(QtProperty *))); q_ptr->disconnect(manager, SIGNAL(propertyChanged(QtProperty *)), q_ptr, SLOT(slotPropertyDataChanged(QtProperty *))); m_managerToProperties.remove(manager); } QList subList = property->subProperties(); QListIterator itSub(subList); while (itSub.hasNext()) { QtProperty *subProperty = itSub.next(); removeSubTree(subProperty, property); } } void QtAbstractPropertyBrowserPrivate::createBrowserIndexes(QtProperty *property, QtProperty *parentProperty, QtProperty *afterProperty) { QMap parentToAfter; if (afterProperty) { QMap >::ConstIterator it = m_propertyToIndexes.find(afterProperty); if (it == m_propertyToIndexes.constEnd()) return; QList indexes = it.value(); QListIterator itIndex(indexes); while (itIndex.hasNext()) { QtBrowserItem *idx = itIndex.next(); QtBrowserItem *parentIdx = idx->parent(); if ((parentProperty && parentIdx && parentIdx->property() == parentProperty) || (!parentProperty && !parentIdx)) parentToAfter[idx->parent()] = idx; } } else if (parentProperty) { QMap >::ConstIterator it = m_propertyToIndexes.find(parentProperty); if (it == m_propertyToIndexes.constEnd()) return; QList indexes = it.value(); QListIterator itIndex(indexes); while (itIndex.hasNext()) { QtBrowserItem *idx = itIndex.next(); parentToAfter[idx] = 0; } } else { parentToAfter[0] = 0; } const QMap::ConstIterator pcend = parentToAfter.constEnd(); for (QMap::ConstIterator it = parentToAfter.constBegin(); it != pcend; ++it) createBrowserIndex(property, it.key(), it.value()); } QtBrowserItem *QtAbstractPropertyBrowserPrivate::createBrowserIndex(QtProperty *property, QtBrowserItem *parentIndex, QtBrowserItem *afterIndex) { QtBrowserItem *newIndex = new QtBrowserItem(q_ptr, property, parentIndex); if (parentIndex) { parentIndex->d_ptr->addChild(newIndex, afterIndex); } else { m_topLevelPropertyToIndex[property] = newIndex; m_topLevelIndexes.insert(m_topLevelIndexes.indexOf(afterIndex) + 1, newIndex); } m_propertyToIndexes[property].append(newIndex); q_ptr->itemInserted(newIndex, afterIndex); QList subItems = property->subProperties(); QListIterator itChild(subItems); QtBrowserItem *afterChild = 0; while (itChild.hasNext()) { QtProperty *child = itChild.next(); afterChild = createBrowserIndex(child, newIndex, afterChild); } return newIndex; } void QtAbstractPropertyBrowserPrivate::removeBrowserIndexes(QtProperty *property, QtProperty *parentProperty) { QList toRemove; QMap >::ConstIterator it = m_propertyToIndexes.find(property); if (it == m_propertyToIndexes.constEnd()) return; QList indexes = it.value(); QListIterator itIndex(indexes); while (itIndex.hasNext()) { QtBrowserItem *idx = itIndex.next(); QtBrowserItem *parentIdx = idx->parent(); if ((parentProperty && parentIdx && parentIdx->property() == parentProperty) || (!parentProperty && !parentIdx)) toRemove.append(idx); } QListIterator itRemove(toRemove); while (itRemove.hasNext()) { QtBrowserItem *index = itRemove.next(); removeBrowserIndex(index); } } void QtAbstractPropertyBrowserPrivate::removeBrowserIndex(QtBrowserItem *index) { QList children = index->children(); for (int i = children.count(); i > 0; i--) { removeBrowserIndex(children.at(i - 1)); } q_ptr->itemRemoved(index); if (index->parent()) { index->parent()->d_ptr->removeChild(index); } else { m_topLevelPropertyToIndex.remove(index->property()); m_topLevelIndexes.removeAll(index); } QtProperty *property = index->property(); m_propertyToIndexes[property].removeAll(index); if (m_propertyToIndexes[property].isEmpty()) m_propertyToIndexes.remove(property); delete index; } void QtAbstractPropertyBrowserPrivate::clearIndex(QtBrowserItem *index) { QList children = index->children(); QListIterator itChild(children); while (itChild.hasNext()) { clearIndex(itChild.next()); } delete index; } void QtAbstractPropertyBrowserPrivate::slotPropertyInserted(QtProperty *property, QtProperty *parentProperty, QtProperty *afterProperty) { if (!m_propertyToParents.contains(parentProperty)) return; createBrowserIndexes(property, parentProperty, afterProperty); insertSubTree(property, parentProperty); //q_ptr->propertyInserted(property, parentProperty, afterProperty); } void QtAbstractPropertyBrowserPrivate::slotPropertyRemoved(QtProperty *property, QtProperty *parentProperty) { if (!m_propertyToParents.contains(parentProperty)) return; removeSubTree(property, parentProperty); // this line should be probably moved down after propertyRemoved call //q_ptr->propertyRemoved(property, parentProperty); removeBrowserIndexes(property, parentProperty); } void QtAbstractPropertyBrowserPrivate::slotPropertyDestroyed(QtProperty *property) { if (!m_subItems.contains(property)) return; q_ptr->removeProperty(property); } void QtAbstractPropertyBrowserPrivate::slotPropertyDataChanged(QtProperty *property) { if (!m_propertyToParents.contains(property)) return; QMap >::ConstIterator it = m_propertyToIndexes.find(property); if (it == m_propertyToIndexes.constEnd()) return; QList indexes = it.value(); QListIterator itIndex(indexes); while (itIndex.hasNext()) { QtBrowserItem *idx = itIndex.next(); q_ptr->itemChanged(idx); } //q_ptr->propertyChanged(property); } /*! \class QtAbstractPropertyBrowser \brief QtAbstractPropertyBrowser provides a base class for implementing property browsers. A property browser is a widget that enables the user to edit a given set of properties. Each property is represented by a label specifying the property's name, and an editing widget (e.g. a line edit or a combobox) holding its value. A property can have zero or more subproperties. \image qtpropertybrowser.png The top level properties can be retrieved using the properties() function. To traverse each property's subproperties, use the QtProperty::subProperties() function. In addition, the set of top level properties can be manipulated using the addProperty(), insertProperty() and removeProperty() functions. Note that the QtProperty class provides a corresponding set of functions making it possible to manipulate the set of subproperties as well. To remove all the properties from the property browser widget, use the clear() function. This function will clear the editor, but it will not delete the properties since they can still be used in other editors. The properties themselves are created and managed by implementations of the QtAbstractPropertyManager class. A manager can handle (i.e. create and manage) properties of a given type. In the property browser the managers are associated with implementations of the QtAbstractEditorFactory: A factory is a class able to create an editing widget of a specified type. When using a property browser widget, managers must be created for each of the required property types before the properties themselves can be created. To ensure that the properties' values will be displayed using suitable editing widgets, the managers must be associated with objects of the preferred factory implementations using the setFactoryForManager() function. The property browser will use these associations to determine which factory it should use to create the preferred editing widget. Note that a factory can be associated with many managers, but a manager can only be associated with one single factory within the context of a single property browser. The associations between managers and factories can at any time be removed using the unsetFactoryForManager() function. Whenever the property data changes or a property is inserted or removed, the itemChanged(), itemInserted() or itemRemoved() functions are called, respectively. These functions must be reimplemented in derived classes in order to update the property browser widget. Be aware that some property instances can appear several times in an abstract tree structure. For example: \table 100% \row \o \code QtProperty *property1, *property2, *property3; property2->addSubProperty(property1); property3->addSubProperty(property2); QtAbstractPropertyBrowser *editor; editor->addProperty(property1); editor->addProperty(property2); editor->addProperty(property3); \endcode \o \image qtpropertybrowser-duplicate.png \endtable The addProperty() function returns a QtBrowserItem that uniquely identifies the created item. To make a property editable in the property browser, the createEditor() function must be called to provide the property with a suitable editing widget. Note that there are two ready-made property browser implementations: \list \o QtGroupBoxPropertyBrowser \o QtTreePropertyBrowser \endlist \sa QtAbstractPropertyManager, QtAbstractEditorFactoryBase */ /*! \fn void QtAbstractPropertyBrowser::setFactoryForManager(PropertyManager *manager, QtAbstractEditorFactory *factory) Connects the given \a manager to the given \a factory, ensuring that properties of the \a manager's type will be displayed with an editing widget suitable for their value. For example: \code QtIntPropertyManager *intManager; QtDoublePropertyManager *doubleManager; QtProperty *myInteger = intManager->addProperty(); QtProperty *myDouble = doubleManager->addProperty(); QtSpinBoxFactory *spinBoxFactory; QtDoubleSpinBoxFactory *doubleSpinBoxFactory; QtAbstractPropertyBrowser *editor; editor->setFactoryForManager(intManager, spinBoxFactory); editor->setFactoryForManager(doubleManager, doubleSpinBoxFactory); editor->addProperty(myInteger); editor->addProperty(myDouble); \endcode In this example the \c myInteger property's value is displayed with a QSpinBox widget, while the \c myDouble property's value is displayed with a QDoubleSpinBox widget. Note that a factory can be associated with many managers, but a manager can only be associated with one single factory. If the given \a manager already is associated with another factory, the old association is broken before the new one established. This function ensures that the given \a manager and the given \a factory are compatible, and it automatically calls the QtAbstractEditorFactory::addPropertyManager() function if necessary. \sa unsetFactoryForManager() */ /*! \fn virtual void QtAbstractPropertyBrowser::itemInserted(QtBrowserItem *insertedItem, QtBrowserItem *precedingItem) = 0 This function is called to update the widget whenever a property is inserted or added to the property browser, passing pointers to the \a insertedItem of property and the specified \a precedingItem as parameters. If \a precedingItem is 0, the \a insertedItem was put at the beginning of its parent item's list of subproperties. If the parent of \a insertedItem is 0, the \a insertedItem was added as a top level property of \e this property browser. This function must be reimplemented in derived classes. Note that if the \a insertedItem's property has subproperties, this method will be called for those properties as soon as the current call is finished. \sa insertProperty(), addProperty() */ /*! \fn virtual void QtAbstractPropertyBrowser::itemRemoved(QtBrowserItem *item) = 0 This function is called to update the widget whenever a property is removed from the property browser, passing the pointer to the \a item of the property as parameters. The passed \a item is deleted just after this call is finished. If the the parent of \a item is 0, the removed \a item was a top level property in this editor. This function must be reimplemented in derived classes. Note that if the removed \a item's property has subproperties, this method will be called for those properties just before the current call is started. \sa removeProperty() */ /*! \fn virtual void QtAbstractPropertyBrowser::itemChanged(QtBrowserItem *item) = 0 This function is called whenever a property's data changes, passing a pointer to the \a item of property as parameter. This function must be reimplemented in derived classes in order to update the property browser widget whenever a property's name, tool tip, status tip, "what's this" text, value text or value icon changes. Note that if the property browser contains several occurrences of the same property, this method will be called once for each occurrence (with a different item each time). \sa QtProperty, items() */ /*! Creates an abstract property browser with the given \a parent. */ QtAbstractPropertyBrowser::QtAbstractPropertyBrowser(QWidget *parent) : QWidget(parent) { d_ptr = new QtAbstractPropertyBrowserPrivate; d_ptr->q_ptr = this; } /*! Destroys the property browser, and destroys all the items that were created by this property browser. Note that the properties that were displayed in the editor are not deleted since they still can be used in other editors. Neither does the destructor delete the property managers and editor factories that were used by this property browser widget unless this widget was their parent. \sa QtAbstractPropertyManager::~QtAbstractPropertyManager() */ QtAbstractPropertyBrowser::~QtAbstractPropertyBrowser() { QList indexes = topLevelItems(); QListIterator itItem(indexes); while (itItem.hasNext()) d_ptr->clearIndex(itItem.next()); delete d_ptr; } /*! Returns the property browser's list of top level properties. To traverse the subproperties, use the QtProperty::subProperties() function. \sa addProperty(), insertProperty(), removeProperty() */ QList QtAbstractPropertyBrowser::properties() const { return d_ptr->m_subItems; } /*! Returns the property browser's list of all items associated with the given \a property. There is one item per instance of the property in the browser. \sa topLevelItem() */ QList QtAbstractPropertyBrowser::items(QtProperty *property) const { return d_ptr->m_propertyToIndexes.value(property); } /*! Returns the top-level items associated with the given \a property. Returns 0 if \a property wasn't inserted into this property browser or isn't a top-level one. \sa topLevelItems(), items() */ QtBrowserItem *QtAbstractPropertyBrowser::topLevelItem(QtProperty *property) const { return d_ptr->m_topLevelPropertyToIndex.value(property); } /*! Returns the list of top-level items. \sa topLevelItem() */ QList QtAbstractPropertyBrowser::topLevelItems() const { return d_ptr->m_topLevelIndexes; } /*! Removes all the properties from the editor, but does not delete them since they can still be used in other editors. \sa removeProperty(), QtAbstractPropertyManager::clear() */ void QtAbstractPropertyBrowser::clear() { QList subList = properties(); QListIterator itSub(subList); itSub.toBack(); while (itSub.hasPrevious()) { QtProperty *property = itSub.previous(); removeProperty(property); } } /*! Appends the given \a property (and its subproperties) to the property browser's list of top level properties. Returns the item created by property browser which is associated with the \a property. In order to get all children items created by the property browser in this call, the returned item should be traversed. If the specified \a property is already added, this function does nothing and returns 0. \sa insertProperty(), QtProperty::addSubProperty(), properties() */ QtBrowserItem *QtAbstractPropertyBrowser::addProperty(QtProperty *property) { QtProperty *afterProperty = 0; if (d_ptr->m_subItems.count() > 0) afterProperty = d_ptr->m_subItems.last(); return insertProperty(property, afterProperty); } /*! \fn QtBrowserItem *QtAbstractPropertyBrowser::insertProperty(QtProperty *property, QtProperty *afterProperty) Inserts the given \a property (and its subproperties) after the specified \a afterProperty in the browser's list of top level properties. Returns item created by property browser which is associated with the \a property. In order to get all children items created by the property browser in this call returned item should be traversed. If the specified \a afterProperty is 0, the given \a property is inserted at the beginning of the list. If \a property is already inserted, this function does nothing and returns 0. \sa addProperty(), QtProperty::insertSubProperty(), properties() */ QtBrowserItem *QtAbstractPropertyBrowser::insertProperty(QtProperty *property, QtProperty *afterProperty) { if (!property) return 0; // if item is already inserted in this item then cannot add. QList pendingList = properties(); int pos = 0; int newPos = 0; //QtProperty *properAfterProperty = 0; while (pos < pendingList.count()) { QtProperty *prop = pendingList.at(pos); if (prop == property) return 0; if (prop == afterProperty) { newPos = pos + 1; //properAfterProperty = afterProperty; } pos++; } d_ptr->createBrowserIndexes(property, 0, afterProperty); // traverse inserted subtree and connect to manager's signals d_ptr->insertSubTree(property, 0); d_ptr->m_subItems.insert(newPos, property); //propertyInserted(property, 0, properAfterProperty); return topLevelItem(property); } /*! Removes the specified \a property (and its subproperties) from the property browser's list of top level properties. All items that were associated with the given \a property and its children are deleted. Note that the properties are \e not deleted since they can still be used in other editors. \sa clear(), QtProperty::removeSubProperty(), properties() */ void QtAbstractPropertyBrowser::removeProperty(QtProperty *property) { if (!property) return; QList pendingList = properties(); int pos = 0; while (pos < pendingList.count()) { if (pendingList.at(pos) == property) { d_ptr->m_subItems.removeAt(pos); //perhaps this two lines d_ptr->removeSubTree(property, 0); //should be moved down after propertyRemoved call. //propertyRemoved(property, 0); d_ptr->removeBrowserIndexes(property, 0); // when item is deleted, item will call removeItem for top level items, // and itemRemoved for nested items. return; } pos++; } } /*! Creates an editing widget (with the given \a parent) for the given \a property according to the previously established associations between property managers and editor factories. If the property is created by a property manager which was not associated with any of the existing factories in \e this property editor, the function returns 0. To make a property editable in the property browser, the createEditor() function must be called to provide the property with a suitable editing widget. Reimplement this function to provide additional decoration for the editing widgets created by the installed factories. \sa setFactoryForManager() */ QWidget *QtAbstractPropertyBrowser::createEditor(QtProperty *property, QWidget *parent) { QtAbstractEditorFactoryBase *factory = 0; QtAbstractPropertyManager *manager = property->propertyManager(); if (m_viewToManagerToFactory()->contains(this) && (*m_viewToManagerToFactory())[this].contains(manager)) { factory = (*m_viewToManagerToFactory())[this][manager]; } if (!factory) return 0; return factory->createEditor(property, parent); } bool QtAbstractPropertyBrowser::addFactory(QtAbstractPropertyManager *abstractManager, QtAbstractEditorFactoryBase *abstractFactory) { bool connectNeeded = false; if (!m_managerToFactoryToViews()->contains(abstractManager) || !(*m_managerToFactoryToViews())[abstractManager].contains(abstractFactory)) { connectNeeded = true; } else if ((*m_managerToFactoryToViews())[abstractManager][abstractFactory] .contains(this)) { return connectNeeded; } if (m_viewToManagerToFactory()->contains(this) && (*m_viewToManagerToFactory())[this].contains(abstractManager)) { unsetFactoryForManager(abstractManager); } (*m_managerToFactoryToViews())[abstractManager][abstractFactory].append(this); (*m_viewToManagerToFactory())[this][abstractManager] = abstractFactory; return connectNeeded; } /*! Removes the association between the given \a manager and the factory bound to it, automatically calling the QtAbstractEditorFactory::removePropertyManager() function if necessary. \sa setFactoryForManager() */ void QtAbstractPropertyBrowser::unsetFactoryForManager(QtAbstractPropertyManager *manager) { if (!m_viewToManagerToFactory()->contains(this) || !(*m_viewToManagerToFactory())[this].contains(manager)) { return; } QtAbstractEditorFactoryBase *abstractFactory = (*m_viewToManagerToFactory())[this][manager]; (*m_viewToManagerToFactory())[this].remove(manager); if ((*m_viewToManagerToFactory())[this].isEmpty()) { (*m_viewToManagerToFactory()).remove(this); } (*m_managerToFactoryToViews())[manager][abstractFactory].removeAll(this); if ((*m_managerToFactoryToViews())[manager][abstractFactory].isEmpty()) { (*m_managerToFactoryToViews())[manager].remove(abstractFactory); abstractFactory->breakConnection(manager); if ((*m_managerToFactoryToViews())[manager].isEmpty()) { (*m_managerToFactoryToViews()).remove(manager); } } } /*! Returns the current item in the property browser. \sa setCurrentItem() */ QtBrowserItem *QtAbstractPropertyBrowser::currentItem() const { return d_ptr->m_currentItem; } /*! Sets the current item in the property browser to \a item. \sa currentItem(), currentItemChanged() */ void QtAbstractPropertyBrowser::setCurrentItem(QtBrowserItem *item) { QtBrowserItem *oldItem = d_ptr->m_currentItem; d_ptr->m_currentItem = item; if (oldItem != item) emit currentItemChanged(item); } #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif #include "moc_qtpropertybrowser.cpp" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/qtpropertybrowser.h000066400000000000000000000262641455373415500266420ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #ifndef QTPROPERTYBROWSER_H #define QTPROPERTYBROWSER_H #include #include #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif #if defined(Q_WS_WIN) # if !defined(QT_QTPROPERTYBROWSER_EXPORT) && !defined(QT_QTPROPERTYBROWSER_IMPORT) # define QT_QTPROPERTYBROWSER_EXPORT # elif defined(QT_QTPROPERTYBROWSER_IMPORT) # if defined(QT_QTPROPERTYBROWSER_EXPORT) # undef QT_QTPROPERTYBROWSER_EXPORT # endif # define QT_QTPROPERTYBROWSER_EXPORT __declspec(dllimport) # elif defined(QT_QTPROPERTYBROWSER_EXPORT) # undef QT_QTPROPERTYBROWSER_EXPORT # define QT_QTPROPERTYBROWSER_EXPORT __declspec(dllexport) # endif #else # define QT_QTPROPERTYBROWSER_EXPORT #endif class QtAbstractPropertyManager; class QtPropertyPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtProperty { public: virtual ~QtProperty(); QList subProperties() const; QtAbstractPropertyManager *propertyManager() const; QString toolTip() const; QString statusTip() const; QString whatsThis() const; QString propertyName() const; QString propertyId() const; bool isEnabled() const; bool isSelectable() const; bool isModified() const; bool hasValue() const; QIcon valueIcon() const; QString valueText() const; virtual bool compare(QtProperty* otherProperty)const; void setToolTip(const QString &text); void setStatusTip(const QString &text); void setWhatsThis(const QString &text); void setPropertyName(const QString &text); void setPropertyId(const QString &text); void setEnabled(bool enable); void setSelectable(bool selectable); void setModified(bool modified); bool isSubProperty()const; void addSubProperty(QtProperty *property); void insertSubProperty(QtProperty *property, QtProperty *afterProperty); void removeSubProperty(QtProperty *property); protected: explicit QtProperty(QtAbstractPropertyManager *manager); void propertyChanged(); private: friend class QtAbstractPropertyManager; QtPropertyPrivate *d_ptr; }; class QtAbstractPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtAbstractPropertyManager : public QObject { Q_OBJECT public: explicit QtAbstractPropertyManager(QObject *parent = 0); ~QtAbstractPropertyManager(); QSet properties() const; void clear() const; QtProperty *addProperty(const QString &name = QString()); QtProperty *qtProperty(const QString &id)const; Q_SIGNALS: void propertyInserted(QtProperty *property, QtProperty *parent, QtProperty *after); void propertyChanged(QtProperty *property); void propertyRemoved(QtProperty *property, QtProperty *parent); void propertyDestroyed(QtProperty *property); protected: virtual bool hasValue(const QtProperty *property) const; virtual QIcon valueIcon(const QtProperty *property) const; virtual QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property) = 0; virtual void uninitializeProperty(QtProperty *property); virtual QtProperty *createProperty(); private: friend class QtProperty; QtAbstractPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtAbstractPropertyManager) Q_DISABLE_COPY(QtAbstractPropertyManager) }; class QT_QTPROPERTYBROWSER_EXPORT QtAbstractEditorFactoryBase : public QObject { Q_OBJECT public: virtual QWidget *createEditor(QtProperty *property, QWidget *parent) = 0; protected: explicit QtAbstractEditorFactoryBase(QObject *parent = 0) : QObject(parent) {} virtual void breakConnection(QtAbstractPropertyManager *manager) = 0; protected Q_SLOTS: virtual void managerDestroyed(QObject *manager) = 0; friend class QtAbstractPropertyBrowser; }; template class QtAbstractEditorFactory : public QtAbstractEditorFactoryBase { public: explicit QtAbstractEditorFactory(QObject *parent) : QtAbstractEditorFactoryBase(parent) {} QWidget *createEditor(QtProperty *property, QWidget *parent) { QSetIterator it(m_managers); while (it.hasNext()) { PropertyManager *manager = it.next(); if (manager == property->propertyManager()) { return createEditor(manager, property, parent); } } return 0; } void addPropertyManager(PropertyManager *manager) { if (m_managers.contains(manager)) return; m_managers.insert(manager); connectPropertyManager(manager); connect(manager, SIGNAL(destroyed(QObject *)), this, SLOT(managerDestroyed(QObject *))); } void removePropertyManager(PropertyManager *manager) { if (!m_managers.contains(manager)) return; disconnect(manager, SIGNAL(destroyed(QObject *)), this, SLOT(managerDestroyed(QObject *))); disconnectPropertyManager(manager); m_managers.remove(manager); } QSet propertyManagers() const { return m_managers; } PropertyManager *propertyManager(QtProperty *property) const { QtAbstractPropertyManager *manager = property->propertyManager(); QSetIterator itManager(m_managers); while (itManager.hasNext()) { PropertyManager *m = itManager.next(); if (m == manager) { return m; } } return 0; } protected: virtual void connectPropertyManager(PropertyManager *manager) = 0; virtual QWidget *createEditor(PropertyManager *manager, QtProperty *property, QWidget *parent) = 0; virtual void disconnectPropertyManager(PropertyManager *manager) = 0; void managerDestroyed(QObject *manager) { QSetIterator it(m_managers); while (it.hasNext()) { PropertyManager *m = it.next(); if (m == manager) { m_managers.remove(m); return; } } } private: void breakConnection(QtAbstractPropertyManager *manager) { QSetIterator it(m_managers); while (it.hasNext()) { PropertyManager *m = it.next(); if (m == manager) { removePropertyManager(m); return; } } } private: QSet m_managers; friend class QtAbstractPropertyEditor; }; class QtAbstractPropertyBrowser; class QtBrowserItemPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtBrowserItem { public: QtProperty *property() const; QtBrowserItem *parent() const; QList children() const; QtAbstractPropertyBrowser *browser() const; private: explicit QtBrowserItem(QtAbstractPropertyBrowser *browser, QtProperty *property, QtBrowserItem *parent); ~QtBrowserItem(); QtBrowserItemPrivate *d_ptr; friend class QtAbstractPropertyBrowserPrivate; }; class QtAbstractPropertyBrowserPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtAbstractPropertyBrowser : public QWidget { Q_OBJECT public: explicit QtAbstractPropertyBrowser(QWidget *parent = 0); ~QtAbstractPropertyBrowser(); QList properties() const; QList items(QtProperty *property) const; QtBrowserItem *topLevelItem(QtProperty *property) const; QList topLevelItems() const; void clear(); template void setFactoryForManager(PropertyManager *manager, QtAbstractEditorFactory *factory) { QtAbstractPropertyManager *abstractManager = manager; QtAbstractEditorFactoryBase *abstractFactory = factory; if (addFactory(abstractManager, abstractFactory)) factory->addPropertyManager(manager); } void unsetFactoryForManager(QtAbstractPropertyManager *manager); QtBrowserItem *currentItem() const; void setCurrentItem(QtBrowserItem *); Q_SIGNALS: void currentItemChanged(QtBrowserItem *); public Q_SLOTS: QtBrowserItem *addProperty(QtProperty *property); QtBrowserItem *insertProperty(QtProperty *property, QtProperty *afterProperty); void removeProperty(QtProperty *property); protected: virtual void itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem) = 0; virtual void itemRemoved(QtBrowserItem *item) = 0; // can be tooltip, statustip, whatsthis, name, icon, text. virtual void itemChanged(QtBrowserItem *item) = 0; virtual QWidget *createEditor(QtProperty *property, QWidget *parent); private: bool addFactory(QtAbstractPropertyManager *abstractManager, QtAbstractEditorFactoryBase *abstractFactory); QtAbstractPropertyBrowserPrivate *d_ptr; Q_DECLARE_PRIVATE(QtAbstractPropertyBrowser) Q_DISABLE_COPY(QtAbstractPropertyBrowser) Q_PRIVATE_SLOT(d_func(), void slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *)) Q_PRIVATE_SLOT(d_func(), void slotPropertyRemoved(QtProperty *, QtProperty *)) Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) Q_PRIVATE_SLOT(d_func(), void slotPropertyDataChanged(QtProperty *)) }; #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif #endif // QTPROPERTYBROWSER_H nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/qtpropertybrowser.pri000066400000000000000000000021451455373415500271750ustar00rootroot00000000000000include(../common.pri) INCLUDEPATH += $$PWD DEPENDPATH += $$PWD qtpropertybrowser-uselib:!qtpropertybrowser-buildlib { LIBS += -L$$QTPROPERTYBROWSER_LIBDIR -l$$QTPROPERTYBROWSER_LIBNAME } else { SOURCES += $$PWD/qtpropertybrowser.cpp \ $$PWD/qtpropertymanager.cpp \ $$PWD/qteditorfactory.cpp \ $$PWD/qtvariantproperty.cpp \ $$PWD/qttreepropertybrowser.cpp \ $$PWD/qtbuttonpropertybrowser.cpp \ $$PWD/qtgroupboxpropertybrowser.cpp \ $$PWD/qtpropertybrowserutils.cpp HEADERS += $$PWD/qtpropertybrowser.h \ $$PWD/qtpropertymanager.h \ $$PWD/qteditorfactory.h \ $$PWD/qtvariantproperty.h \ $$PWD/qttreepropertybrowser.h \ $$PWD/qtbuttonpropertybrowser.h \ $$PWD/qtgroupboxpropertybrowser.h \ $$PWD/qtpropertybrowserutils_p.h RESOURCES += $$PWD/qtpropertybrowser.qrc } win32 { contains(TEMPLATE, lib):contains(CONFIG, shared):DEFINES += QT_QTPROPERTYBROWSER_EXPORT else:qtpropertybrowser-uselib:DEFINES += QT_QTPROPERTYBROWSER_IMPORT } nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/qtpropertybrowser.qrc000066400000000000000000000016421455373415500271710ustar00rootroot00000000000000 images/cursor-arrow.png images/cursor-busy.png images/cursor-closedhand.png images/cursor-cross.png images/cursor-forbidden.png images/cursor-hand.png images/cursor-hsplit.png images/cursor-ibeam.png images/cursor-openhand.png images/cursor-sizeall.png images/cursor-sizeb.png images/cursor-sizef.png images/cursor-sizeh.png images/cursor-sizev.png images/cursor-uparrow.png images/cursor-vsplit.png images/cursor-wait.png images/cursor-whatsthis.png nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/qtpropertybrowserutils.cpp000066400000000000000000000361461455373415500302560ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #include "qtpropertybrowserutils_p.h" #include #include #include #include #include #include #include #include #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif QtCursorDatabase::QtCursorDatabase() { appendCursor(Qt::ArrowCursor, QApplication::translate("QtCursorDatabase", "Arrow", 0), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-arrow.png"))); appendCursor(Qt::UpArrowCursor, QApplication::translate("QtCursorDatabase", "Up Arrow", 0), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-uparrow.png"))); appendCursor(Qt::CrossCursor, QApplication::translate("QtCursorDatabase", "Cross", 0), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-cross.png"))); appendCursor(Qt::WaitCursor, QApplication::translate("QtCursorDatabase", "Wait", 0), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-wait.png"))); appendCursor(Qt::IBeamCursor, QApplication::translate("QtCursorDatabase", "IBeam", 0), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-ibeam.png"))); appendCursor(Qt::SizeVerCursor, QApplication::translate("QtCursorDatabase", "Size Vertical", 0), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-sizev.png"))); appendCursor(Qt::SizeHorCursor, QApplication::translate("QtCursorDatabase", "Size Horizontal", 0), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-sizeh.png"))); appendCursor(Qt::SizeFDiagCursor, QApplication::translate("QtCursorDatabase", "Size Backslash", 0), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-sizef.png"))); appendCursor(Qt::SizeBDiagCursor, QApplication::translate("QtCursorDatabase", "Size Slash", 0), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-sizeb.png"))); appendCursor(Qt::SizeAllCursor, QApplication::translate("QtCursorDatabase", "Size All", 0), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-sizeall.png"))); appendCursor(Qt::BlankCursor, QApplication::translate("QtCursorDatabase", "Blank", 0), QIcon()); appendCursor(Qt::SplitVCursor, QApplication::translate("QtCursorDatabase", "Split Vertical", 0), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-vsplit.png"))); appendCursor(Qt::SplitHCursor, QApplication::translate("QtCursorDatabase", "Split Horizontal", 0), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-hsplit.png"))); appendCursor(Qt::PointingHandCursor, QApplication::translate("QtCursorDatabase", "Pointing Hand", 0), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-hand.png"))); appendCursor(Qt::ForbiddenCursor, QApplication::translate("QtCursorDatabase", "Forbidden", 0), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-forbidden.png"))); appendCursor(Qt::OpenHandCursor, QApplication::translate("QtCursorDatabase", "Open Hand", 0), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-openhand.png"))); appendCursor(Qt::ClosedHandCursor, QApplication::translate("QtCursorDatabase", "Closed Hand", 0), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-closedhand.png"))); appendCursor(Qt::WhatsThisCursor, QApplication::translate("QtCursorDatabase", "What's This", 0), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-whatsthis.png"))); appendCursor(Qt::BusyCursor, QApplication::translate("QtCursorDatabase", "Busy", 0), QIcon(QLatin1String(":/trolltech/qtpropertybrowser/images/cursor-busy.png"))); } void QtCursorDatabase::appendCursor(Qt::CursorShape shape, const QString &name, const QIcon &icon) { if (m_cursorShapeToValue.contains(shape)) return; int value = m_cursorNames.count(); m_cursorNames.append(name); m_cursorIcons[value] = icon; m_valueToCursorShape[value] = shape; m_cursorShapeToValue[shape] = value; } QStringList QtCursorDatabase::cursorShapeNames() const { return m_cursorNames; } QMap QtCursorDatabase::cursorShapeIcons() const { return m_cursorIcons; } QString QtCursorDatabase::cursorToShapeName(const QCursor &cursor) const { int val = cursorToValue(cursor); if (val >= 0) return m_cursorNames.at(val); return QString(); } QIcon QtCursorDatabase::cursorToShapeIcon(const QCursor &cursor) const { int val = cursorToValue(cursor); return m_cursorIcons.value(val); } int QtCursorDatabase::cursorToValue(const QCursor &cursor) const { #ifndef QT_NO_CURSOR Qt::CursorShape shape = cursor.shape(); if (m_cursorShapeToValue.contains(shape)) return m_cursorShapeToValue[shape]; #endif return -1; } #ifndef QT_NO_CURSOR QCursor QtCursorDatabase::valueToCursor(int value) const { if (m_valueToCursorShape.contains(value)) return QCursor(m_valueToCursorShape[value]); return QCursor(); } #endif QPixmap QtPropertyBrowserUtils::brushValuePixmap(const QBrush &b) { QImage img(16, 16, QImage::Format_ARGB32_Premultiplied); img.fill(0); QPainter painter(&img); painter.setCompositionMode(QPainter::CompositionMode_Source); painter.fillRect(0, 0, img.width(), img.height(), b); QColor color = b.color(); if (color.alpha() != 255) { // indicate alpha by an inset QBrush opaqueBrush = b; color.setAlpha(255); opaqueBrush.setColor(color); painter.fillRect(img.width() / 4, img.height() / 4, img.width() / 2, img.height() / 2, opaqueBrush); } painter.end(); return QPixmap::fromImage(img); } QIcon QtPropertyBrowserUtils::brushValueIcon(const QBrush &b) { return QIcon(brushValuePixmap(b)); } QString QtPropertyBrowserUtils::colorValueText(const QColor &c) { return QApplication::translate("QtPropertyBrowserUtils", "[%1, %2, %3] (%4)", 0) .arg(QString::number(c.red())) .arg(QString::number(c.green())) .arg(QString::number(c.blue())) .arg(QString::number(c.alpha())); } QPixmap QtPropertyBrowserUtils::fontValuePixmap(const QFont &font) { QFont f = font; QImage img(16, 16, QImage::Format_ARGB32_Premultiplied); img.fill(0); QPainter p(&img); p.setRenderHint(QPainter::TextAntialiasing, true); p.setRenderHint(QPainter::Antialiasing, true); f.setPointSize(13); p.setFont(f); QTextOption t; t.setAlignment(Qt::AlignCenter); p.drawText(QRect(0, 0, 16, 16), QString(QLatin1Char('A')), t); return QPixmap::fromImage(img); } QIcon QtPropertyBrowserUtils::fontValueIcon(const QFont &f) { return QIcon(fontValuePixmap(f)); } QString QtPropertyBrowserUtils::fontValueText(const QFont &f) { return QApplication::translate("QtPropertyBrowserUtils", "[%1, %2]", 0) .arg(f.family()) .arg(f.pointSize()); } QtBoolEdit::QtBoolEdit(QWidget *parent) : QWidget(parent), m_checkBox(new QCheckBox(this)), m_textVisible(true) { QHBoxLayout *lt = new QHBoxLayout; if (QApplication::layoutDirection() == Qt::LeftToRight) lt->setContentsMargins(4, 0, 0, 0); else lt->setContentsMargins(0, 0, 4, 0); lt->addWidget(m_checkBox); setLayout(lt); connect(m_checkBox, SIGNAL(toggled(bool)), this, SIGNAL(toggled(bool))); setFocusProxy(m_checkBox); m_checkBox->setText(tr("True")); } void QtBoolEdit::setTextVisible(bool textVisible) { if (m_textVisible == textVisible) return; m_textVisible = textVisible; if (m_textVisible) m_checkBox->setText(isChecked() ? tr("True") : tr("False")); else m_checkBox->setText(QString()); } Qt::CheckState QtBoolEdit::checkState() const { return m_checkBox->checkState(); } void QtBoolEdit::setCheckState(Qt::CheckState state) { m_checkBox->setCheckState(state); } bool QtBoolEdit::isChecked() const { return m_checkBox->isChecked(); } void QtBoolEdit::setChecked(bool c) { m_checkBox->setChecked(c); if (!m_textVisible) return; m_checkBox->setText(isChecked() ? tr("True") : tr("False")); } bool QtBoolEdit::blockCheckBoxSignals(bool block) { return m_checkBox->blockSignals(block); } void QtBoolEdit::mousePressEvent(QMouseEvent *event) { if (event->buttons() == Qt::LeftButton) { m_checkBox->click(); event->accept(); } else { QWidget::mousePressEvent(event); } } void QtBoolEdit::paintEvent(QPaintEvent *) { QStyleOption opt; opt.init(this); QPainter p(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); } QtKeySequenceEdit::QtKeySequenceEdit(QWidget *parent) : QWidget(parent), m_num(0), m_lineEdit(new QLineEdit(this)) { QHBoxLayout *layout = new QHBoxLayout(this); layout->addWidget(m_lineEdit); layout->setMargin(0); m_lineEdit->installEventFilter(this); m_lineEdit->setReadOnly(true); m_lineEdit->setFocusProxy(this); setFocusPolicy(m_lineEdit->focusPolicy()); setAttribute(Qt::WA_InputMethodEnabled); } bool QtKeySequenceEdit::eventFilter(QObject *o, QEvent *e) { if (o == m_lineEdit && e->type() == QEvent::ContextMenu) { QContextMenuEvent *c = static_cast(e); QMenu *menu = m_lineEdit->createStandardContextMenu(); const QList actions = menu->actions(); QListIterator itAction(actions); while (itAction.hasNext()) { QAction *action = itAction.next(); action->setShortcut(QKeySequence()); QString actionString = action->text(); const int pos = actionString.lastIndexOf(QLatin1Char('\t')); if (pos > 0) actionString.remove(pos, actionString.length() - pos); action->setText(actionString); } QAction *actionBefore = 0; if (actions.count() > 0) actionBefore = actions[0]; QAction *clearAction = new QAction(tr("Clear Shortcut"), menu); menu->insertAction(actionBefore, clearAction); menu->insertSeparator(actionBefore); clearAction->setEnabled(!m_keySequence.isEmpty()); connect(clearAction, SIGNAL(triggered()), this, SLOT(slotClearShortcut())); menu->exec(c->globalPos()); delete menu; e->accept(); return true; } return QWidget::eventFilter(o, e); } void QtKeySequenceEdit::slotClearShortcut() { if (m_keySequence.isEmpty()) return; setKeySequence(QKeySequence()); emit keySequenceChanged(m_keySequence); } void QtKeySequenceEdit::handleKeyEvent(QKeyEvent *e) { int nextKey = e->key(); if (nextKey == Qt::Key_Control || nextKey == Qt::Key_Shift || nextKey == Qt::Key_Meta || nextKey == Qt::Key_Alt || nextKey == Qt::Key_Super_L || nextKey == Qt::Key_AltGr) return; nextKey |= translateModifiers(e->modifiers(), e->text()); int k0 = m_keySequence[0]; int k1 = m_keySequence[1]; int k2 = m_keySequence[2]; int k3 = m_keySequence[3]; switch (m_num) { case 0: k0 = nextKey; k1 = 0; k2 = 0; k3 = 0; break; case 1: k1 = nextKey; k2 = 0; k3 = 0; break; case 2: k2 = nextKey; k3 = 0; break; case 3: k3 = nextKey; break; default: break; } ++m_num; if (m_num > 3) m_num = 0; m_keySequence = QKeySequence(k0, k1, k2, k3); m_lineEdit->setText(m_keySequence.toString(QKeySequence::NativeText)); e->accept(); emit keySequenceChanged(m_keySequence); } void QtKeySequenceEdit::setKeySequence(const QKeySequence &sequence) { if (sequence == m_keySequence) return; m_num = 0; m_keySequence = sequence; m_lineEdit->setText(m_keySequence.toString(QKeySequence::NativeText)); } QKeySequence QtKeySequenceEdit::keySequence() const { return m_keySequence; } int QtKeySequenceEdit::translateModifiers(Qt::KeyboardModifiers state, const QString &text) const { int result = 0; if ((state & Qt::ShiftModifier) && (text.size() == 0 || !text.at(0).isPrint() || text.at(0).isLetter() || text.at(0).isSpace())) result |= Qt::SHIFT; if (state & Qt::ControlModifier) result |= Qt::CTRL; if (state & Qt::MetaModifier) result |= Qt::META; if (state & Qt::AltModifier) result |= Qt::ALT; return result; } void QtKeySequenceEdit::focusInEvent(QFocusEvent *e) { m_lineEdit->event(e); m_lineEdit->selectAll(); QWidget::focusInEvent(e); } void QtKeySequenceEdit::focusOutEvent(QFocusEvent *e) { m_num = 0; m_lineEdit->event(e); QWidget::focusOutEvent(e); } void QtKeySequenceEdit::keyPressEvent(QKeyEvent *e) { handleKeyEvent(e); e->accept(); } void QtKeySequenceEdit::keyReleaseEvent(QKeyEvent *e) { m_lineEdit->event(e); } void QtKeySequenceEdit::paintEvent(QPaintEvent *) { QStyleOption opt; opt.init(this); QPainter p(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); } bool QtKeySequenceEdit::event(QEvent *e) { if (e->type() == QEvent::Shortcut || e->type() == QEvent::ShortcutOverride || e->type() == QEvent::KeyRelease) { e->accept(); return true; } return QWidget::event(e); } #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/qtpropertybrowserutils_p.h000066400000000000000000000115611455373415500302340ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists for the convenience // of Qt Designer. This header // file may change from version to version without notice, or even be removed. // // We mean it. // #ifndef QTPROPERTYBROWSERUTILS_H #define QTPROPERTYBROWSERUTILS_H #include #include #include #include #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif class QMouseEvent; class QCheckBox; class QLineEdit; class QtCursorDatabase { public: QtCursorDatabase(); QStringList cursorShapeNames() const; QMap cursorShapeIcons() const; QString cursorToShapeName(const QCursor &cursor) const; QIcon cursorToShapeIcon(const QCursor &cursor) const; int cursorToValue(const QCursor &cursor) const; #ifndef QT_NO_CURSOR QCursor valueToCursor(int value) const; #endif private: void appendCursor(Qt::CursorShape shape, const QString &name, const QIcon &icon); QStringList m_cursorNames; QMap m_cursorIcons; QMap m_valueToCursorShape; QMap m_cursorShapeToValue; }; class QtPropertyBrowserUtils { public: static QPixmap brushValuePixmap(const QBrush &b); static QIcon brushValueIcon(const QBrush &b); static QString colorValueText(const QColor &c); static QPixmap fontValuePixmap(const QFont &f); static QIcon fontValueIcon(const QFont &f); static QString fontValueText(const QFont &f); }; class QtBoolEdit : public QWidget { Q_OBJECT public: QtBoolEdit(QWidget *parent = 0); bool textVisible() const { return m_textVisible; } void setTextVisible(bool textVisible); Qt::CheckState checkState() const; void setCheckState(Qt::CheckState state); bool isChecked() const; void setChecked(bool c); bool blockCheckBoxSignals(bool block); Q_SIGNALS: void toggled(bool); protected: void mousePressEvent(QMouseEvent * event); void paintEvent(QPaintEvent *); private: QCheckBox *m_checkBox; bool m_textVisible; }; class QtKeySequenceEdit : public QWidget { Q_OBJECT public: QtKeySequenceEdit(QWidget *parent = 0); QKeySequence keySequence() const; bool eventFilter(QObject *o, QEvent *e); public Q_SLOTS: void setKeySequence(const QKeySequence &sequence); Q_SIGNALS: void keySequenceChanged(const QKeySequence &sequence); protected: void focusInEvent(QFocusEvent *e); void focusOutEvent(QFocusEvent *e); void keyPressEvent(QKeyEvent *e); void keyReleaseEvent(QKeyEvent *e); void paintEvent(QPaintEvent *); bool event(QEvent *e); private slots: void slotClearShortcut(); private: void handleKeyEvent(QKeyEvent *e); int translateModifiers(Qt::KeyboardModifiers state, const QString &text) const; int m_num; QKeySequence m_keySequence; QLineEdit *m_lineEdit; }; #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif #endif nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/qtpropertymanager.cpp000066400000000000000000006322411455373415500271220ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #include "qtpropertymanager.h" #include "qtpropertybrowserutils_p.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(Q_CC_MSVC) # pragma warning(disable: 4786) /* MS VS 6: truncating debug info after 255 characters */ #endif #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif template static void setSimpleMinimumData(PrivateData *data, const Value &minVal) { data->minVal = minVal; if (data->maxVal < data->minVal) data->maxVal = data->minVal; if (data->val < data->minVal) data->val = data->minVal; } template static void setSimpleMaximumData(PrivateData *data, const Value &maxVal) { data->maxVal = maxVal; if (data->minVal > data->maxVal) data->minVal = data->maxVal; if (data->val > data->maxVal) data->val = data->maxVal; } template static void setSizeMinimumData(PrivateData *data, const Value &newMinVal) { data->minVal = newMinVal; if (data->maxVal.width() < data->minVal.width()) data->maxVal.setWidth(data->minVal.width()); if (data->maxVal.height() < data->minVal.height()) data->maxVal.setHeight(data->minVal.height()); if (data->val.width() < data->minVal.width()) data->val.setWidth(data->minVal.width()); if (data->val.height() < data->minVal.height()) data->val.setHeight(data->minVal.height()); } template static void setSizeMaximumData(PrivateData *data, const Value &newMaxVal) { data->maxVal = newMaxVal; if (data->minVal.width() > data->maxVal.width()) data->minVal.setWidth(data->maxVal.width()); if (data->minVal.height() > data->maxVal.height()) data->minVal.setHeight(data->maxVal.height()); if (data->val.width() > data->maxVal.width()) data->val.setWidth(data->maxVal.width()); if (data->val.height() > data->maxVal.height()) data->val.setHeight(data->maxVal.height()); } template static SizeValue qBoundSize(const SizeValue &minVal, const SizeValue &val, const SizeValue &maxVal) { SizeValue croppedVal = val; if (minVal.width() > val.width()) croppedVal.setWidth(minVal.width()); else if (maxVal.width() < val.width()) croppedVal.setWidth(maxVal.width()); if (minVal.height() > val.height()) croppedVal.setHeight(minVal.height()); else if (maxVal.height() < val.height()) croppedVal.setHeight(maxVal.height()); return croppedVal; } // Match the exact signature of qBound for VS 6. QSize qBound(QSize minVal, QSize val, QSize maxVal) { return qBoundSize(minVal, val, maxVal); } QSizeF qBound(QSizeF minVal, QSizeF val, QSizeF maxVal) { return qBoundSize(minVal, val, maxVal); } namespace { namespace { template void orderBorders(Value &minVal, Value &maxVal) { if (minVal > maxVal) qSwap(minVal, maxVal); } template static void orderSizeBorders(Value &minVal, Value &maxVal) { Value fromSize = minVal; Value toSize = maxVal; if (fromSize.width() > toSize.width()) { fromSize.setWidth(maxVal.width()); toSize.setWidth(minVal.width()); } if (fromSize.height() > toSize.height()) { fromSize.setHeight(maxVal.height()); toSize.setHeight(minVal.height()); } minVal = fromSize; maxVal = toSize; } void orderBorders(QSize &minVal, QSize &maxVal) { orderSizeBorders(minVal, maxVal); } void orderBorders(QSizeF &minVal, QSizeF &maxVal) { orderSizeBorders(minVal, maxVal); } } } //////// template static Value getData(const QMap &propertyMap, Value PrivateData::*data, const QtProperty *property, const Value &defaultValue = Value()) { typedef QMap PropertyToData; typedef typename PropertyToData::const_iterator PropertyToDataConstIterator; const PropertyToDataConstIterator it = propertyMap.constFind(property); if (it == propertyMap.constEnd()) return defaultValue; return it.value().*data; } template static Value getValue(const QMap &propertyMap, const QtProperty *property, const Value &defaultValue = Value()) { return getData(propertyMap, &PrivateData::val, property, defaultValue); } template static Value getMinimum(const QMap &propertyMap, const QtProperty *property, const Value &defaultValue = Value()) { return getData(propertyMap, &PrivateData::minVal, property, defaultValue); } template static Value getMaximum(const QMap &propertyMap, const QtProperty *property, const Value &defaultValue = Value()) { return getData(propertyMap, &PrivateData::maxVal, property, defaultValue); } template static void setSimpleValue(QMap &propertyMap, PropertyManager *manager, void (PropertyManager::*propertyChangedSignal)(QtProperty *), void (PropertyManager::*valueChangedSignal)(QtProperty *, ValueChangeParameter), QtProperty *property, const Value &val) { typedef QMap PropertyToData; typedef typename PropertyToData::iterator PropertyToDataIterator; const PropertyToDataIterator it = propertyMap.find(property); if (it == propertyMap.end()) return; if (it.value() == val) return; it.value() = val; emit (manager->*propertyChangedSignal)(property); emit (manager->*valueChangedSignal)(property, val); } template static void setValueInRange(PropertyManager *manager, PropertyManagerPrivate *managerPrivate, void (PropertyManager::*propertyChangedSignal)(QtProperty *), void (PropertyManager::*valueChangedSignal)(QtProperty *, ValueChangeParameter), QtProperty *property, const Value &val, void (PropertyManagerPrivate::*setSubPropertyValue)(QtProperty *, ValueChangeParameter)) { typedef typename PropertyManagerPrivate::Data PrivateData; typedef QMap PropertyToData; typedef typename PropertyToData::iterator PropertyToDataIterator; const PropertyToDataIterator it = managerPrivate->m_values.find(property); if (it == managerPrivate->m_values.end()) return; PrivateData &data = it.value(); if (data.val == val) return; const Value oldVal = data.val; data.val = qBound(data.minVal, val, data.maxVal); if (data.val == oldVal) return; if (setSubPropertyValue) (managerPrivate->*setSubPropertyValue)(property, data.val); emit (manager->*propertyChangedSignal)(property); emit (manager->*valueChangedSignal)(property, data.val); } template static void setBorderValues(PropertyManager *manager, PropertyManagerPrivate *managerPrivate, void (PropertyManager::*propertyChangedSignal)(QtProperty *), void (PropertyManager::*valueChangedSignal)(QtProperty *, ValueChangeParameter), void (PropertyManager::*rangeChangedSignal)(QtProperty *, ValueChangeParameter, ValueChangeParameter), QtProperty *property, const Value &minVal, const Value &maxVal, void (PropertyManagerPrivate::*setSubPropertyRange)(QtProperty *, ValueChangeParameter, ValueChangeParameter, ValueChangeParameter)) { typedef typename PropertyManagerPrivate::Data PrivateData; typedef QMap PropertyToData; typedef typename PropertyToData::iterator PropertyToDataIterator; const PropertyToDataIterator it = managerPrivate->m_values.find(property); if (it == managerPrivate->m_values.end()) return; Value fromVal = minVal; Value toVal = maxVal; orderBorders(fromVal, toVal); PrivateData &data = it.value(); if (data.minVal == fromVal && data.maxVal == toVal) return; const Value oldVal = data.val; data.setMinimumValue(fromVal); data.setMaximumValue(toVal); emit (manager->*rangeChangedSignal)(property, data.minVal, data.maxVal); if (setSubPropertyRange) (managerPrivate->*setSubPropertyRange)(property, data.minVal, data.maxVal, data.val); if (data.val == oldVal) return; emit (manager->*propertyChangedSignal)(property); emit (manager->*valueChangedSignal)(property, data.val); } template static void setBorderValue(PropertyManager *manager, PropertyManagerPrivate *managerPrivate, void (PropertyManager::*propertyChangedSignal)(QtProperty *), void (PropertyManager::*valueChangedSignal)(QtProperty *, ValueChangeParameter), void (PropertyManager::*rangeChangedSignal)(QtProperty *, ValueChangeParameter, ValueChangeParameter), QtProperty *property, Value (PrivateData::*getRangeVal)() const, void (PrivateData::*setRangeVal)(ValueChangeParameter), const Value &borderVal, void (PropertyManagerPrivate::*setSubPropertyRange)(QtProperty *, ValueChangeParameter, ValueChangeParameter, ValueChangeParameter)) { typedef QMap PropertyToData; typedef typename PropertyToData::iterator PropertyToDataIterator; const PropertyToDataIterator it = managerPrivate->m_values.find(property); if (it == managerPrivate->m_values.end()) return; PrivateData &data = it.value(); if ((data.*getRangeVal)() == borderVal) return; const Value oldVal = data.val; (data.*setRangeVal)(borderVal); emit (manager->*rangeChangedSignal)(property, data.minVal, data.maxVal); if (setSubPropertyRange) (managerPrivate->*setSubPropertyRange)(property, data.minVal, data.maxVal, data.val); if (data.val == oldVal) return; emit (manager->*propertyChangedSignal)(property); emit (manager->*valueChangedSignal)(property, data.val); } template static void setMinimumValue(PropertyManager *manager, PropertyManagerPrivate *managerPrivate, void (PropertyManager::*propertyChangedSignal)(QtProperty *), void (PropertyManager::*valueChangedSignal)(QtProperty *, ValueChangeParameter), void (PropertyManager::*rangeChangedSignal)(QtProperty *, ValueChangeParameter, ValueChangeParameter), QtProperty *property, const Value &minVal) { void (PropertyManagerPrivate::*setSubPropertyRange)(QtProperty *, ValueChangeParameter, ValueChangeParameter, ValueChangeParameter) = 0; setBorderValue(manager, managerPrivate, propertyChangedSignal, valueChangedSignal, rangeChangedSignal, property, &PropertyManagerPrivate::Data::minimumValue, &PropertyManagerPrivate::Data::setMinimumValue, minVal, setSubPropertyRange); } template static void setMaximumValue(PropertyManager *manager, PropertyManagerPrivate *managerPrivate, void (PropertyManager::*propertyChangedSignal)(QtProperty *), void (PropertyManager::*valueChangedSignal)(QtProperty *, ValueChangeParameter), void (PropertyManager::*rangeChangedSignal)(QtProperty *, ValueChangeParameter, ValueChangeParameter), QtProperty *property, const Value &maxVal) { void (PropertyManagerPrivate::*setSubPropertyRange)(QtProperty *, ValueChangeParameter, ValueChangeParameter, ValueChangeParameter) = 0; setBorderValue(manager, managerPrivate, propertyChangedSignal, valueChangedSignal, rangeChangedSignal, property, &PropertyManagerPrivate::Data::maximumValue, &PropertyManagerPrivate::Data::setMaximumValue, maxVal, setSubPropertyRange); } class QtMetaEnumWrapper : public QObject { Q_OBJECT Q_PROPERTY(QSizePolicy::Policy policy READ policy) public: QSizePolicy::Policy policy() const { return QSizePolicy::Ignored; } private: QtMetaEnumWrapper(QObject *parent) : QObject(parent) {} }; class QtMetaEnumProvider { public: QtMetaEnumProvider(); QStringList policyEnumNames() const { return m_policyEnumNames; } QStringList languageEnumNames() const { return m_languageEnumNames; } QStringList countryEnumNames(QLocale::Language language) const { return m_countryEnumNames.value(language); } QSizePolicy::Policy indexToSizePolicy(int index) const; int sizePolicyToIndex(QSizePolicy::Policy policy) const; void indexToLocale(int languageIndex, int countryIndex, QLocale::Language *language, QLocale::Country *country) const; void localeToIndex(QLocale::Language language, QLocale::Country country, int *languageIndex, int *countryIndex) const; private: void initLocale(); QStringList m_policyEnumNames; QStringList m_languageEnumNames; QMap m_countryEnumNames; QMap m_indexToLanguage; QMap m_languageToIndex; QMap > m_indexToCountry; QMap > m_countryToIndex; QMetaEnum m_policyEnum; }; #if QT_VERSION < 0x040300 static QList countriesForLanguage(QLocale::Language language) { QList countries; QLocale::Country country = QLocale::AnyCountry; while (country <= QLocale::LastCountry) { QLocale locale(language, country); if (locale.language() == language && !countries.contains(locale.country())) countries << locale.country(); country = (QLocale::Country)((uint)country + 1); // ++country } return countries; } #endif static QList sortCountries(const QList &countries) { QMultiMap nameToCountry; QListIterator itCountry(countries); while (itCountry.hasNext()) { QLocale::Country country = itCountry.next(); nameToCountry.insert(QLocale::countryToString(country), country); } return nameToCountry.values(); } void QtMetaEnumProvider::initLocale() { QMultiMap nameToLanguage; QLocale::Language language = QLocale::C; while (language <= QLocale::LastLanguage) { QLocale locale(language); if (locale.language() == language) nameToLanguage.insert(QLocale::languageToString(language), language); language = (QLocale::Language)((uint)language + 1); // ++language } const QLocale system = QLocale::system(); if (!nameToLanguage.contains(QLocale::languageToString(system.language()))) nameToLanguage.insert(QLocale::languageToString(system.language()), system.language()); QList languages = nameToLanguage.values(); QListIterator itLang(languages); while (itLang.hasNext()) { QLocale::Language language = itLang.next(); QList countries; #if QT_VERSION < 0x040300 countries = countriesForLanguage(language); #else countries = QLocale::countriesForLanguage(language); #endif if (countries.isEmpty() && language == system.language()) countries << system.country(); if (!countries.isEmpty() && !m_languageToIndex.contains(language)) { countries = sortCountries(countries); int langIdx = m_languageEnumNames.count(); m_indexToLanguage[langIdx] = language; m_languageToIndex[language] = langIdx; QStringList countryNames; QListIterator it(countries); int countryIdx = 0; while (it.hasNext()) { QLocale::Country country = it.next(); countryNames << QLocale::countryToString(country); m_indexToCountry[langIdx][countryIdx] = country; m_countryToIndex[language][country] = countryIdx; ++countryIdx; } m_languageEnumNames << QLocale::languageToString(language); m_countryEnumNames[language] = countryNames; } } } QtMetaEnumProvider::QtMetaEnumProvider() { QMetaProperty p; p = QtMetaEnumWrapper::staticMetaObject.property( QtMetaEnumWrapper::staticMetaObject.propertyOffset() + 0); m_policyEnum = p.enumerator(); const int keyCount = m_policyEnum.keyCount(); for (int i = 0; i < keyCount; i++) m_policyEnumNames << QLatin1String(m_policyEnum.key(i)); initLocale(); } QSizePolicy::Policy QtMetaEnumProvider::indexToSizePolicy(int index) const { return static_cast(m_policyEnum.value(index)); } int QtMetaEnumProvider::sizePolicyToIndex(QSizePolicy::Policy policy) const { const int keyCount = m_policyEnum.keyCount(); for (int i = 0; i < keyCount; i++) if (indexToSizePolicy(i) == policy) return i; return -1; } void QtMetaEnumProvider::indexToLocale(int languageIndex, int countryIndex, QLocale::Language *language, QLocale::Country *country) const { QLocale::Language l = QLocale::C; QLocale::Country c = QLocale::AnyCountry; if (m_indexToLanguage.contains(languageIndex)) { l = m_indexToLanguage[languageIndex]; if (m_indexToCountry.contains(languageIndex) && m_indexToCountry[languageIndex].contains(countryIndex)) c = m_indexToCountry[languageIndex][countryIndex]; } if (language) *language = l; if (country) *country = c; } void QtMetaEnumProvider::localeToIndex(QLocale::Language language, QLocale::Country country, int *languageIndex, int *countryIndex) const { int l = -1; int c = -1; if (m_languageToIndex.contains(language)) { l = m_languageToIndex[language]; if (m_countryToIndex.contains(language) && m_countryToIndex[language].contains(country)) c = m_countryToIndex[language][country]; } if (languageIndex) *languageIndex = l; if (countryIndex) *countryIndex = c; } Q_GLOBAL_STATIC(QtMetaEnumProvider, metaEnumProvider) // QtGroupPropertyManager /*! \class QtGroupPropertyManager \brief The QtGroupPropertyManager provides and manages group properties. This class is intended to provide a grouping element without any value. \sa QtAbstractPropertyManager */ /*! Creates a manager with the given \a parent. */ QtGroupPropertyManager::QtGroupPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { } /*! Destroys this manager, and all the properties it has created. */ QtGroupPropertyManager::~QtGroupPropertyManager() { } /*! \reimp */ bool QtGroupPropertyManager::hasValue(const QtProperty *property) const { Q_UNUSED(property) return false; } /*! \reimp */ void QtGroupPropertyManager::initializeProperty(QtProperty *property) { Q_UNUSED(property) } /*! \reimp */ void QtGroupPropertyManager::uninitializeProperty(QtProperty *property) { Q_UNUSED(property) } // QtIntPropertyManager class QtIntPropertyManagerPrivate { QtIntPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtIntPropertyManager) public: struct Data { Data() : val(0), minVal(-INT_MAX), maxVal(INT_MAX), singleStep(1) {} int val; int minVal; int maxVal; int singleStep; int minimumValue() const { return minVal; } int maximumValue() const { return maxVal; } void setMinimumValue(int newMinVal) { setSimpleMinimumData(this, newMinVal); } void setMaximumValue(int newMaxVal) { setSimpleMaximumData(this, newMaxVal); } }; typedef QMap PropertyValueMap; PropertyValueMap m_values; }; /*! \class QtIntPropertyManager \brief The QtIntPropertyManager provides and manages int properties. An int property has a current value, and a range specifying the valid values. The range is defined by a minimum and a maximum value. The property's value and range can be retrieved using the value(), minimum() and maximum() functions, and can be set using the setValue(), setMinimum() and setMaximum() slots. Alternatively, the range can be defined in one go using the setRange() slot. In addition, QtIntPropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes, and the rangeChanged() signal which is emitted whenever such a property changes its range of valid values. \sa QtAbstractPropertyManager, QtSpinBoxFactory, QtSliderFactory, QtScrollBarFactory */ /*! \fn void QtIntPropertyManager::valueChanged(QtProperty *property, int value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! \fn void QtIntPropertyManager::rangeChanged(QtProperty *property, int minimum, int maximum) This signal is emitted whenever a property created by this manager changes its range of valid values, passing a pointer to the \a property and the new \a minimum and \a maximum values. \sa setRange() */ /*! \fn void QtIntPropertyManager::singleStepChanged(QtProperty *property, int step) This signal is emitted whenever a property created by this manager changes its single step property, passing a pointer to the \a property and the new \a step value \sa setSingleStep() */ /*! Creates a manager with the given \a parent. */ QtIntPropertyManager::QtIntPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtIntPropertyManagerPrivate; d_ptr->q_ptr = this; } /*! Destroys this manager, and all the properties it has created. */ QtIntPropertyManager::~QtIntPropertyManager() { clear(); delete d_ptr; } /*! Returns the given \a property's value. If the given property is not managed by this manager, this function returns 0. \sa setValue() */ int QtIntPropertyManager::value(const QtProperty *property) const { return getValue(d_ptr->m_values, property, 0); } /*! Returns the given \a property's minimum value. \sa setMinimum(), maximum(), setRange() */ int QtIntPropertyManager::minimum(const QtProperty *property) const { return getMinimum(d_ptr->m_values, property, 0); } /*! Returns the given \a property's maximum value. \sa setMaximum(), minimum(), setRange() */ int QtIntPropertyManager::maximum(const QtProperty *property) const { return getMaximum(d_ptr->m_values, property, 0); } /*! Returns the given \a property's step value. The step is typically used to increment or decrement a property value while pressing an arrow key. \sa setSingleStep() */ int QtIntPropertyManager::singleStep(const QtProperty *property) const { return getData(d_ptr->m_values, &QtIntPropertyManagerPrivate::Data::singleStep, property, 0); } /*! \reimp */ QString QtIntPropertyManager::valueText(const QtProperty *property) const { const QtIntPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); return QString::number(it.value().val); } /*! \fn void QtIntPropertyManager::setValue(QtProperty *property, int value) Sets the value of the given \a property to \a value. If the specified \a value is not valid according to the given \a property's range, the \a value is adjusted to the nearest valid value within the range. \sa value(), setRange(), valueChanged() */ void QtIntPropertyManager::setValue(QtProperty *property, int val) { void (QtIntPropertyManagerPrivate::*setSubPropertyValue)(QtProperty *, int) = 0; setValueInRange(this, d_ptr, &QtIntPropertyManager::propertyChanged, &QtIntPropertyManager::valueChanged, property, val, setSubPropertyValue); } /*! Sets the minimum value for the given \a property to \a minVal. When setting the minimum value, the maximum and current values are adjusted if necessary (ensuring that the range remains valid and that the current value is within the range). \sa minimum(), setRange(), rangeChanged() */ void QtIntPropertyManager::setMinimum(QtProperty *property, int minVal) { setMinimumValue(this, d_ptr, &QtIntPropertyManager::propertyChanged, &QtIntPropertyManager::valueChanged, &QtIntPropertyManager::rangeChanged, property, minVal); } /*! Sets the maximum value for the given \a property to \a maxVal. When setting maximum value, the minimum and current values are adjusted if necessary (ensuring that the range remains valid and that the current value is within the range). \sa maximum(), setRange(), rangeChanged() */ void QtIntPropertyManager::setMaximum(QtProperty *property, int maxVal) { setMaximumValue(this, d_ptr, &QtIntPropertyManager::propertyChanged, &QtIntPropertyManager::valueChanged, &QtIntPropertyManager::rangeChanged, property, maxVal); } /*! \fn void QtIntPropertyManager::setRange(QtProperty *property, int minimum, int maximum) Sets the range of valid values. This is a convenience function defining the range of valid values in one go; setting the \a minimum and \a maximum values for the given \a property with a single function call. When setting a new range, the current value is adjusted if necessary (ensuring that the value remains within range). \sa setMinimum(), setMaximum(), rangeChanged() */ void QtIntPropertyManager::setRange(QtProperty *property, int minVal, int maxVal) { void (QtIntPropertyManagerPrivate::*setSubPropertyRange)(QtProperty *, int, int, int) = 0; setBorderValues(this, d_ptr, &QtIntPropertyManager::propertyChanged, &QtIntPropertyManager::valueChanged, &QtIntPropertyManager::rangeChanged, property, minVal, maxVal, setSubPropertyRange); } /*! Sets the step value for the given \a property to \a step. The step is typically used to increment or decrement a property value while pressing an arrow key. \sa singleStep() */ void QtIntPropertyManager::setSingleStep(QtProperty *property, int step) { const QtIntPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtIntPropertyManagerPrivate::Data data = it.value(); if (step < 0) step = 0; if (data.singleStep == step) return; data.singleStep = step; it.value() = data; emit singleStepChanged(property, data.singleStep); } /*! \reimp */ void QtIntPropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QtIntPropertyManagerPrivate::Data(); } /*! \reimp */ void QtIntPropertyManager::uninitializeProperty(QtProperty *property) { d_ptr->m_values.remove(property); } // QtDoublePropertyManager class QtDoublePropertyManagerPrivate { QtDoublePropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtDoublePropertyManager) public: struct Data { Data() : val(0), minVal(-INT_MAX), maxVal(INT_MAX), singleStep(1), decimals(2) {} double val; double minVal; double maxVal; double singleStep; int decimals; double minimumValue() const { return minVal; } double maximumValue() const { return maxVal; } void setMinimumValue(double newMinVal) { setSimpleMinimumData(this, newMinVal); } void setMaximumValue(double newMaxVal) { setSimpleMaximumData(this, newMaxVal); } }; typedef QMap PropertyValueMap; PropertyValueMap m_values; }; /*! \class QtDoublePropertyManager \brief The QtDoublePropertyManager provides and manages double properties. A double property has a current value, and a range specifying the valid values. The range is defined by a minimum and a maximum value. The property's value and range can be retrieved using the value(), minimum() and maximum() functions, and can be set using the setValue(), setMinimum() and setMaximum() slots. Alternatively, the range can be defined in one go using the setRange() slot. In addition, QtDoublePropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes, and the rangeChanged() signal which is emitted whenever such a property changes its range of valid values. \sa QtAbstractPropertyManager, QtDoubleSpinBoxFactory */ /*! \fn void QtDoublePropertyManager::valueChanged(QtProperty *property, double value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! \fn void QtDoublePropertyManager::rangeChanged(QtProperty *property, double minimum, double maximum) This signal is emitted whenever a property created by this manager changes its range of valid values, passing a pointer to the \a property and the new \a minimum and \a maximum values \sa setRange() */ /*! \fn void QtDoublePropertyManager::decimalsChanged(QtProperty *property, int prec) This signal is emitted whenever a property created by this manager changes its precision of value, passing a pointer to the \a property and the new \a prec value \sa setDecimals() */ /*! \fn void QtDoublePropertyManager::singleStepChanged(QtProperty *property, double step) This signal is emitted whenever a property created by this manager changes its single step property, passing a pointer to the \a property and the new \a step value \sa setSingleStep() */ /*! Creates a manager with the given \a parent. */ QtDoublePropertyManager::QtDoublePropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtDoublePropertyManagerPrivate; d_ptr->q_ptr = this; } /*! Destroys this manager, and all the properties it has created. */ QtDoublePropertyManager::~QtDoublePropertyManager() { clear(); delete d_ptr; } /*! Returns the given \a property's value. If the given property is not managed by this manager, this function returns 0. \sa setValue() */ double QtDoublePropertyManager::value(const QtProperty *property) const { return getValue(d_ptr->m_values, property, 0.0); } /*! Returns the given \a property's minimum value. \sa maximum(), setRange() */ double QtDoublePropertyManager::minimum(const QtProperty *property) const { return getMinimum(d_ptr->m_values, property, 0.0); } /*! Returns the given \a property's maximum value. \sa minimum(), setRange() */ double QtDoublePropertyManager::maximum(const QtProperty *property) const { return getMaximum(d_ptr->m_values, property, 0.0); } /*! Returns the given \a property's step value. The step is typically used to increment or decrement a property value while pressing an arrow key. \sa setSingleStep() */ double QtDoublePropertyManager::singleStep(const QtProperty *property) const { return getData(d_ptr->m_values, &QtDoublePropertyManagerPrivate::Data::singleStep, property, 0); } /*! Returns the given \a property's precision, in decimals. \sa setDecimals() */ int QtDoublePropertyManager::decimals(const QtProperty *property) const { return getData(d_ptr->m_values, &QtDoublePropertyManagerPrivate::Data::decimals, property, 0); } /*! \reimp */ QString QtDoublePropertyManager::valueText(const QtProperty *property) const { const QtDoublePropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); return QString::number(it.value().val, 'f', it.value().decimals); } /*! \fn void QtDoublePropertyManager::setValue(QtProperty *property, double value) Sets the value of the given \a property to \a value. If the specified \a value is not valid according to the given \a property's range, the \a value is adjusted to the nearest valid value within the range. \sa value(), setRange(), valueChanged() */ void QtDoublePropertyManager::setValue(QtProperty *property, double val) { void (QtDoublePropertyManagerPrivate::*setSubPropertyValue)(QtProperty *, double) = 0; setValueInRange(this, d_ptr, &QtDoublePropertyManager::propertyChanged, &QtDoublePropertyManager::valueChanged, property, val, setSubPropertyValue); } /*! Sets the step value for the given \a property to \a step. The step is typically used to increment or decrement a property value while pressing an arrow key. \sa singleStep() */ void QtDoublePropertyManager::setSingleStep(QtProperty *property, double step) { const QtDoublePropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtDoublePropertyManagerPrivate::Data data = it.value(); if (step < 0) step = 0; if (data.singleStep == step) return; data.singleStep = step; it.value() = data; emit singleStepChanged(property, data.singleStep); } /*! \fn void QtDoublePropertyManager::setDecimals(QtProperty *property, int prec) Sets the precision of the given \a property to \a prec. The valid decimal range is 0-13. The default is 2. \sa decimals() */ void QtDoublePropertyManager::setDecimals(QtProperty *property, int prec) { const QtDoublePropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtDoublePropertyManagerPrivate::Data data = it.value(); if (prec > 13) prec = 13; else if (prec < 0) prec = 0; if (data.decimals == prec) return; data.decimals = prec; it.value() = data; emit decimalsChanged(property, data.decimals); } /*! Sets the minimum value for the given \a property to \a minVal. When setting the minimum value, the maximum and current values are adjusted if necessary (ensuring that the range remains valid and that the current value is within in the range). \sa minimum(), setRange(), rangeChanged() */ void QtDoublePropertyManager::setMinimum(QtProperty *property, double minVal) { setMinimumValue(this, d_ptr, &QtDoublePropertyManager::propertyChanged, &QtDoublePropertyManager::valueChanged, &QtDoublePropertyManager::rangeChanged, property, minVal); } /*! Sets the maximum value for the given \a property to \a maxVal. When setting the maximum value, the minimum and current values are adjusted if necessary (ensuring that the range remains valid and that the current value is within in the range). \sa maximum(), setRange(), rangeChanged() */ void QtDoublePropertyManager::setMaximum(QtProperty *property, double maxVal) { setMaximumValue(this, d_ptr, &QtDoublePropertyManager::propertyChanged, &QtDoublePropertyManager::valueChanged, &QtDoublePropertyManager::rangeChanged, property, maxVal); } /*! \fn void QtDoublePropertyManager::setRange(QtProperty *property, double minimum, double maximum) Sets the range of valid values. This is a convenience function defining the range of valid values in one go; setting the \a minimum and \a maximum values for the given \a property with a single function call. When setting a new range, the current value is adjusted if necessary (ensuring that the value remains within range). \sa setMinimum(), setMaximum(), rangeChanged() */ void QtDoublePropertyManager::setRange(QtProperty *property, double minVal, double maxVal) { void (QtDoublePropertyManagerPrivate::*setSubPropertyRange)(QtProperty *, double, double, double) = 0; setBorderValues(this, d_ptr, &QtDoublePropertyManager::propertyChanged, &QtDoublePropertyManager::valueChanged, &QtDoublePropertyManager::rangeChanged, property, minVal, maxVal, setSubPropertyRange); } /*! \reimp */ void QtDoublePropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QtDoublePropertyManagerPrivate::Data(); } /*! \reimp */ void QtDoublePropertyManager::uninitializeProperty(QtProperty *property) { d_ptr->m_values.remove(property); } // QtStringPropertyManager class QtStringPropertyManagerPrivate { QtStringPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtStringPropertyManager) public: struct Data { Data() : regExp(QString(QLatin1Char('*')), Qt::CaseSensitive, QRegExp::Wildcard) { } QString val; QRegExp regExp; }; typedef QMap PropertyValueMap; QMap m_values; }; /*! \class QtStringPropertyManager \brief The QtStringPropertyManager provides and manages QString properties. A string property's value can be retrieved using the value() function, and set using the setValue() slot. The current value can be checked against a regular expression. To set the regular expression use the setRegExp() slot, use the regExp() function to retrieve the currently set expression. In addition, QtStringPropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes, and the regExpChanged() signal which is emitted whenever such a property changes its currently set regular expression. \sa QtAbstractPropertyManager, QtLineEditFactory */ /*! \fn void QtStringPropertyManager::valueChanged(QtProperty *property, const QString &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! \fn void QtStringPropertyManager::regExpChanged(QtProperty *property, const QRegExp ®Exp) This signal is emitted whenever a property created by this manager changes its currenlty set regular expression, passing a pointer to the \a property and the new \a regExp as parameters. \sa setRegExp() */ /*! Creates a manager with the given \a parent. */ QtStringPropertyManager::QtStringPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtStringPropertyManagerPrivate; d_ptr->q_ptr = this; } /*! Destroys this manager, and all the properties it has created. */ QtStringPropertyManager::~QtStringPropertyManager() { clear(); delete d_ptr; } /*! Returns the given \a property's value. If the given property is not managed by this manager, this function returns an empty string. \sa setValue() */ QString QtStringPropertyManager::value(const QtProperty *property) const { return getValue(d_ptr->m_values, property); } /*! Returns the given \a property's currently set regular expression. If the given \a property is not managed by this manager, this function returns an empty expression. \sa setRegExp() */ QRegExp QtStringPropertyManager::regExp(const QtProperty *property) const { return getData(d_ptr->m_values, &QtStringPropertyManagerPrivate::Data::regExp, property, QRegExp()); } /*! \reimp */ QString QtStringPropertyManager::valueText(const QtProperty *property) const { const QtStringPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); return it.value().val; } /*! \fn void QtStringPropertyManager::setValue(QtProperty *property, const QString &value) Sets the value of the given \a property to \a value. If the specified \a value doesn't match the given \a property's regular expression, this function does nothing. \sa value(), setRegExp(), valueChanged() */ void QtStringPropertyManager::setValue(QtProperty *property, const QString &val) { const QtStringPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtStringPropertyManagerPrivate::Data data = it.value(); if (data.val == val) return; if (data.regExp.isValid() && !data.regExp.exactMatch(val)) return; data.val = val; it.value() = data; emit propertyChanged(property); emit valueChanged(property, data.val); } /*! Sets the regular expression of the given \a property to \a regExp. \sa regExp(), setValue(), regExpChanged() */ void QtStringPropertyManager::setRegExp(QtProperty *property, const QRegExp ®Exp) { const QtStringPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtStringPropertyManagerPrivate::Data data = it.value() ; if (data.regExp == regExp) return; data.regExp = regExp; it.value() = data; emit regExpChanged(property, data.regExp); } /*! \reimp */ void QtStringPropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QtStringPropertyManagerPrivate::Data(); } /*! \reimp */ void QtStringPropertyManager::uninitializeProperty(QtProperty *property) { d_ptr->m_values.remove(property); } // QtBoolPropertyManager class QtBoolPropertyManagerPrivate { QtBoolPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtBoolPropertyManager) public: QMap m_values; }; /*! \class QtBoolPropertyManager \brief The QtBoolPropertyManager class provides and manages boolean properties. The property's value can be retrieved using the value() function, and set using the setValue() slot. In addition, QtBoolPropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes. \sa QtAbstractPropertyManager, QtCheckBoxFactory */ /*! \fn void QtBoolPropertyManager::valueChanged(QtProperty *property, bool value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. */ /*! Creates a manager with the given \a parent. */ QtBoolPropertyManager::QtBoolPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtBoolPropertyManagerPrivate; d_ptr->q_ptr = this; } /*! Destroys this manager, and all the properties it has created. */ QtBoolPropertyManager::~QtBoolPropertyManager() { clear(); delete d_ptr; } /*! Returns the given \a property's value. If the given \a property is not managed by \e this manager, this function returns false. \sa setValue() */ bool QtBoolPropertyManager::value(const QtProperty *property) const { return d_ptr->m_values.value(property, false); } /*! \reimp */ QString QtBoolPropertyManager::valueText(const QtProperty *property) const { const QMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); static const QString trueText = tr("True"); static const QString falseText = tr("False"); return it.value() ? trueText : falseText; } // Return an icon containing a check box indicator static QIcon drawCheckBox(bool value) { QStyleOptionButton opt; opt.state |= value ? QStyle::State_On : QStyle::State_Off; opt.state |= QStyle::State_Enabled; const QStyle *style = QApplication::style(); // Figure out size of an indicator and make sure it is not scaled down in a list view item // by making the pixmap as big as a list view icon and centering the indicator in it. // (if it is smaller, it can't be helped) const int indicatorWidth = style->pixelMetric(QStyle::PM_IndicatorWidth, &opt); const int indicatorHeight = style->pixelMetric(QStyle::PM_IndicatorHeight, &opt); const int listViewIconSize = indicatorWidth; const int pixmapWidth = indicatorWidth; const int pixmapHeight = qMax(indicatorHeight, listViewIconSize); opt.rect = QRect(0, 0, indicatorWidth, indicatorHeight); QPixmap pixmap = QPixmap(pixmapWidth, pixmapHeight); pixmap.fill(Qt::transparent); { // Center? const int xoff = (pixmapWidth > indicatorWidth) ? (pixmapWidth - indicatorWidth) / 2 : 0; const int yoff = (pixmapHeight > indicatorHeight) ? (pixmapHeight - indicatorHeight) / 2 : 0; QPainter painter(&pixmap); painter.translate(xoff, yoff); QCheckBox cb; style->drawPrimitive(QStyle::PE_IndicatorCheckBox, &opt, &painter, &cb); } return QIcon(pixmap); } /*! \reimp */ QIcon QtBoolPropertyManager::valueIcon(const QtProperty *property) const { const QMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QIcon(); static const QIcon checkedIcon = drawCheckBox(true); static const QIcon uncheckedIcon = drawCheckBox(false); return it.value() ? checkedIcon : uncheckedIcon; } /*! \fn void QtBoolPropertyManager::setValue(QtProperty *property, bool value) Sets the value of the given \a property to \a value. \sa value() */ void QtBoolPropertyManager::setValue(QtProperty *property, bool val) { setSimpleValue(d_ptr->m_values, this, &QtBoolPropertyManager::propertyChanged, &QtBoolPropertyManager::valueChanged, property, val); } /*! \reimp */ void QtBoolPropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = false; } /*! \reimp */ void QtBoolPropertyManager::uninitializeProperty(QtProperty *property) { d_ptr->m_values.remove(property); } // QtDatePropertyManager class QtDatePropertyManagerPrivate { QtDatePropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtDatePropertyManager) public: struct Data { Data() : val(QDate::currentDate()), minVal(QDate(1752, 9, 14)), maxVal(QDate(7999, 12, 31)) {} QDate val; QDate minVal; QDate maxVal; QDate minimumValue() const { return minVal; } QDate maximumValue() const { return maxVal; } void setMinimumValue(const QDate &newMinVal) { setSimpleMinimumData(this, newMinVal); } void setMaximumValue(const QDate &newMaxVal) { setSimpleMaximumData(this, newMaxVal); } }; QString m_format; typedef QMap PropertyValueMap; QMap m_values; }; /*! \class QtDatePropertyManager \brief The QtDatePropertyManager provides and manages QDate properties. A date property has a current value, and a range specifying the valid dates. The range is defined by a minimum and a maximum value. The property's values can be retrieved using the minimum(), maximum() and value() functions, and can be set using the setMinimum(), setMaximum() and setValue() slots. Alternatively, the range can be defined in one go using the setRange() slot. In addition, QtDatePropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes, and the rangeChanged() signal which is emitted whenever such a property changes its range of valid dates. \sa QtAbstractPropertyManager, QtDateEditFactory, QtDateTimePropertyManager */ /*! \fn void QtDatePropertyManager::valueChanged(QtProperty *property, const QDate &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! \fn void QtDatePropertyManager::rangeChanged(QtProperty *property, const QDate &minimum, const QDate &maximum) This signal is emitted whenever a property created by this manager changes its range of valid dates, passing a pointer to the \a property and the new \a minimum and \a maximum dates. \sa setRange() */ /*! Creates a manager with the given \a parent. */ QtDatePropertyManager::QtDatePropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtDatePropertyManagerPrivate; d_ptr->q_ptr = this; QLocale loc; d_ptr->m_format = loc.dateFormat(QLocale::ShortFormat); } /*! Destroys this manager, and all the properties it has created. */ QtDatePropertyManager::~QtDatePropertyManager() { clear(); delete d_ptr; } /*! Returns the given \a property's value. If the given \a property is not managed by \e this manager, this function returns an invalid date. \sa setValue() */ QDate QtDatePropertyManager::value(const QtProperty *property) const { return getValue(d_ptr->m_values, property); } /*! Returns the given \a property's minimum date. \sa maximum(), setRange() */ QDate QtDatePropertyManager::minimum(const QtProperty *property) const { return getMinimum(d_ptr->m_values, property); } /*! Returns the given \a property's maximum date. \sa minimum(), setRange() */ QDate QtDatePropertyManager::maximum(const QtProperty *property) const { return getMaximum(d_ptr->m_values, property); } /*! \reimp */ QString QtDatePropertyManager::valueText(const QtProperty *property) const { const QtDatePropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); return it.value().val.toString(d_ptr->m_format); } /*! \fn void QtDatePropertyManager::setValue(QtProperty *property, const QDate &value) Sets the value of the given \a property to \a value. If the specified \a value is not a valid date according to the given \a property's range, the value is adjusted to the nearest valid value within the range. \sa value(), setRange(), valueChanged() */ void QtDatePropertyManager::setValue(QtProperty *property, const QDate &val) { void (QtDatePropertyManagerPrivate::*setSubPropertyValue)(QtProperty *, const QDate &) = 0; setValueInRange(this, d_ptr, &QtDatePropertyManager::propertyChanged, &QtDatePropertyManager::valueChanged, property, val, setSubPropertyValue); } /*! Sets the minimum value for the given \a property to \a minVal. When setting the minimum value, the maximum and current values are adjusted if necessary (ensuring that the range remains valid and that the current value is within in the range). \sa minimum(), setRange() */ void QtDatePropertyManager::setMinimum(QtProperty *property, const QDate &minVal) { setMinimumValue(this, d_ptr, &QtDatePropertyManager::propertyChanged, &QtDatePropertyManager::valueChanged, &QtDatePropertyManager::rangeChanged, property, minVal); } /*! Sets the maximum value for the given \a property to \a maxVal. When setting the maximum value, the minimum and current values are adjusted if necessary (ensuring that the range remains valid and that the current value is within in the range). \sa maximum(), setRange() */ void QtDatePropertyManager::setMaximum(QtProperty *property, const QDate &maxVal) { setMaximumValue(this, d_ptr, &QtDatePropertyManager::propertyChanged, &QtDatePropertyManager::valueChanged, &QtDatePropertyManager::rangeChanged, property, maxVal); } /*! \fn void QtDatePropertyManager::setRange(QtProperty *property, const QDate &minimum, const QDate &maximum) Sets the range of valid dates. This is a convenience function defining the range of valid dates in one go; setting the \a minimum and \a maximum values for the given \a property with a single function call. When setting a new date range, the current value is adjusted if necessary (ensuring that the value remains in date range). \sa setMinimum(), setMaximum(), rangeChanged() */ void QtDatePropertyManager::setRange(QtProperty *property, const QDate &minVal, const QDate &maxVal) { void (QtDatePropertyManagerPrivate::*setSubPropertyRange)(QtProperty *, const QDate &, const QDate &, const QDate &) = 0; setBorderValues(this, d_ptr, &QtDatePropertyManager::propertyChanged, &QtDatePropertyManager::valueChanged, &QtDatePropertyManager::rangeChanged, property, minVal, maxVal, setSubPropertyRange); } /*! \reimp */ void QtDatePropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QtDatePropertyManagerPrivate::Data(); } /*! \reimp */ void QtDatePropertyManager::uninitializeProperty(QtProperty *property) { d_ptr->m_values.remove(property); } // QtTimePropertyManager class QtTimePropertyManagerPrivate { QtTimePropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtTimePropertyManager) public: QString m_format; typedef QMap PropertyValueMap; PropertyValueMap m_values; }; /*! \class QtTimePropertyManager \brief The QtTimePropertyManager provides and manages QTime properties. A time property's value can be retrieved using the value() function, and set using the setValue() slot. In addition, QtTimePropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes. \sa QtAbstractPropertyManager, QtTimeEditFactory */ /*! \fn void QtTimePropertyManager::valueChanged(QtProperty *property, const QTime &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! Creates a manager with the given \a parent. */ QtTimePropertyManager::QtTimePropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtTimePropertyManagerPrivate; d_ptr->q_ptr = this; QLocale loc; d_ptr->m_format = loc.timeFormat(QLocale::ShortFormat); } /*! Destroys this manager, and all the properties it has created. */ QtTimePropertyManager::~QtTimePropertyManager() { clear(); delete d_ptr; } /*! Returns the given \a property's value. If the given property is not managed by this manager, this function returns an invalid time object. \sa setValue() */ QTime QtTimePropertyManager::value(const QtProperty *property) const { return d_ptr->m_values.value(property, QTime()); } /*! \reimp */ QString QtTimePropertyManager::valueText(const QtProperty *property) const { const QtTimePropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); return it.value().toString(d_ptr->m_format); } /*! \fn void QtTimePropertyManager::setValue(QtProperty *property, const QTime &value) Sets the value of the given \a property to \a value. \sa value(), valueChanged() */ void QtTimePropertyManager::setValue(QtProperty *property, const QTime &val) { setSimpleValue(d_ptr->m_values, this, &QtTimePropertyManager::propertyChanged, &QtTimePropertyManager::valueChanged, property, val); } /*! \reimp */ void QtTimePropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QTime::currentTime(); } /*! \reimp */ void QtTimePropertyManager::uninitializeProperty(QtProperty *property) { d_ptr->m_values.remove(property); } // QtDateTimePropertyManager class QtDateTimePropertyManagerPrivate { QtDateTimePropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtDateTimePropertyManager) public: QString m_format; typedef QMap PropertyValueMap; PropertyValueMap m_values; }; /*! \class QtDateTimePropertyManager \brief The QtDateTimePropertyManager provides and manages QDateTime properties. A date and time property has a current value which can be retrieved using the value() function, and set using the setValue() slot. In addition, QtDateTimePropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes. \sa QtAbstractPropertyManager, QtDateTimeEditFactory, QtDatePropertyManager */ /*! \fn void QtDateTimePropertyManager::valueChanged(QtProperty *property, const QDateTime &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. */ /*! Creates a manager with the given \a parent. */ QtDateTimePropertyManager::QtDateTimePropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtDateTimePropertyManagerPrivate; d_ptr->q_ptr = this; QLocale loc; d_ptr->m_format = loc.dateFormat(QLocale::ShortFormat); d_ptr->m_format += QLatin1Char(' '); d_ptr->m_format += loc.timeFormat(QLocale::ShortFormat); } /*! Destroys this manager, and all the properties it has created. */ QtDateTimePropertyManager::~QtDateTimePropertyManager() { clear(); delete d_ptr; } /*! Returns the given \a property's value. If the given \a property is not managed by this manager, this function returns an invalid QDateTime object. \sa setValue() */ QDateTime QtDateTimePropertyManager::value(const QtProperty *property) const { return d_ptr->m_values.value(property, QDateTime()); } /*! \reimp */ QString QtDateTimePropertyManager::valueText(const QtProperty *property) const { const QtDateTimePropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); return it.value().toString(d_ptr->m_format); } /*! \fn void QtDateTimePropertyManager::setValue(QtProperty *property, const QDateTime &value) Sets the value of the given \a property to \a value. \sa value(), valueChanged() */ void QtDateTimePropertyManager::setValue(QtProperty *property, const QDateTime &val) { setSimpleValue(d_ptr->m_values, this, &QtDateTimePropertyManager::propertyChanged, &QtDateTimePropertyManager::valueChanged, property, val); } /*! \reimp */ void QtDateTimePropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QDateTime::currentDateTime(); } /*! \reimp */ void QtDateTimePropertyManager::uninitializeProperty(QtProperty *property) { d_ptr->m_values.remove(property); } // QtKeySequencePropertyManager class QtKeySequencePropertyManagerPrivate { QtKeySequencePropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtKeySequencePropertyManager) public: QString m_format; typedef QMap PropertyValueMap; PropertyValueMap m_values; }; /*! \class QtKeySequencePropertyManager \brief The QtKeySequencePropertyManager provides and manages QKeySequence properties. A key sequence's value can be retrieved using the value() function, and set using the setValue() slot. In addition, QtKeySequencePropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes. \sa QtAbstractPropertyManager */ /*! \fn void QtKeySequencePropertyManager::valueChanged(QtProperty *property, const QKeySequence &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. */ /*! Creates a manager with the given \a parent. */ QtKeySequencePropertyManager::QtKeySequencePropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtKeySequencePropertyManagerPrivate; d_ptr->q_ptr = this; } /*! Destroys this manager, and all the properties it has created. */ QtKeySequencePropertyManager::~QtKeySequencePropertyManager() { clear(); delete d_ptr; } /*! Returns the given \a property's value. If the given \a property is not managed by this manager, this function returns an empty QKeySequence object. \sa setValue() */ QKeySequence QtKeySequencePropertyManager::value(const QtProperty *property) const { return d_ptr->m_values.value(property, QKeySequence()); } /*! \reimp */ QString QtKeySequencePropertyManager::valueText(const QtProperty *property) const { const QtKeySequencePropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); return it.value().toString(QKeySequence::NativeText); } /*! \fn void QtKeySequencePropertyManager::setValue(QtProperty *property, const QKeySequence &value) Sets the value of the given \a property to \a value. \sa value(), valueChanged() */ void QtKeySequencePropertyManager::setValue(QtProperty *property, const QKeySequence &val) { setSimpleValue(d_ptr->m_values, this, &QtKeySequencePropertyManager::propertyChanged, &QtKeySequencePropertyManager::valueChanged, property, val); } /*! \reimp */ void QtKeySequencePropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QKeySequence(); } /*! \reimp */ void QtKeySequencePropertyManager::uninitializeProperty(QtProperty *property) { d_ptr->m_values.remove(property); } // QtCharPropertyManager class QtCharPropertyManagerPrivate { QtCharPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtCharPropertyManager) public: typedef QMap PropertyValueMap; PropertyValueMap m_values; }; /*! \class QtCharPropertyManager \brief The QtCharPropertyManager provides and manages QChar properties. A char's value can be retrieved using the value() function, and set using the setValue() slot. In addition, QtCharPropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes. \sa QtAbstractPropertyManager */ /*! \fn void QtCharPropertyManager::valueChanged(QtProperty *property, const QChar &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. */ /*! Creates a manager with the given \a parent. */ QtCharPropertyManager::QtCharPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtCharPropertyManagerPrivate; d_ptr->q_ptr = this; } /*! Destroys this manager, and all the properties it has created. */ QtCharPropertyManager::~QtCharPropertyManager() { clear(); delete d_ptr; } /*! Returns the given \a property's value. If the given \a property is not managed by this manager, this function returns an null QChar object. \sa setValue() */ QChar QtCharPropertyManager::value(const QtProperty *property) const { return d_ptr->m_values.value(property, QChar()); } /*! \reimp */ QString QtCharPropertyManager::valueText(const QtProperty *property) const { const QtCharPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); const QChar c = it.value(); return c.isNull() ? QString() : QString(c); } /*! \fn void QtCharPropertyManager::setValue(QtProperty *property, const QChar &value) Sets the value of the given \a property to \a value. \sa value(), valueChanged() */ void QtCharPropertyManager::setValue(QtProperty *property, const QChar &val) { setSimpleValue(d_ptr->m_values, this, &QtCharPropertyManager::propertyChanged, &QtCharPropertyManager::valueChanged, property, val); } /*! \reimp */ void QtCharPropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QChar(); } /*! \reimp */ void QtCharPropertyManager::uninitializeProperty(QtProperty *property) { d_ptr->m_values.remove(property); } // QtLocalePropertyManager class QtLocalePropertyManagerPrivate { QtLocalePropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtLocalePropertyManager) public: QtLocalePropertyManagerPrivate(); void slotEnumChanged(QtProperty *property, int value); void slotPropertyDestroyed(QtProperty *property); typedef QMap PropertyValueMap; PropertyValueMap m_values; QtEnumPropertyManager *m_enumPropertyManager; QMap m_propertyToLanguage; QMap m_propertyToCountry; QMap m_languageToProperty; QMap m_countryToProperty; }; QtLocalePropertyManagerPrivate::QtLocalePropertyManagerPrivate() { } void QtLocalePropertyManagerPrivate::slotEnumChanged(QtProperty *property, int value) { if (QtProperty *prop = m_languageToProperty.value(property, 0)) { const QLocale loc = m_values[prop]; QLocale::Language newLanguage = loc.language(); QLocale::Country newCountry = loc.country(); metaEnumProvider()->indexToLocale(value, 0, &newLanguage, 0); QLocale newLoc(newLanguage, newCountry); q_ptr->setValue(prop, newLoc); } else if (QtProperty *prop = m_countryToProperty.value(property, 0)) { const QLocale loc = m_values[prop]; QLocale::Language newLanguage = loc.language(); QLocale::Country newCountry = loc.country(); metaEnumProvider()->indexToLocale(m_enumPropertyManager->value(m_propertyToLanguage.value(prop)), value, &newLanguage, &newCountry); QLocale newLoc(newLanguage, newCountry); q_ptr->setValue(prop, newLoc); } } void QtLocalePropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) { if (QtProperty *subProp = m_languageToProperty.value(property, 0)) { m_propertyToLanguage[subProp] = 0; m_languageToProperty.remove(property); } else if (QtProperty *subProp = m_countryToProperty.value(property, 0)) { m_propertyToCountry[subProp] = 0; m_countryToProperty.remove(property); } } /*! \class QtLocalePropertyManager \brief The QtLocalePropertyManager provides and manages QLocale properties. A locale property has nested \e language and \e country subproperties. The top-level property's value can be retrieved using the value() function, and set using the setValue() slot. The subproperties are created by QtEnumPropertyManager object. These submanager can be retrieved using the subEnumPropertyManager() function. In order to provide editing widgets for the subproperties in a property browser widget, this manager must be associated with editor factory. In addition, QtLocalePropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes. \sa QtAbstractPropertyManager, QtEnumPropertyManager */ /*! \fn void QtLocalePropertyManager::valueChanged(QtProperty *property, const QLocale &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! Creates a manager with the given \a parent. */ QtLocalePropertyManager::QtLocalePropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtLocalePropertyManagerPrivate; d_ptr->q_ptr = this; d_ptr->m_enumPropertyManager = new QtEnumPropertyManager(this); connect(d_ptr->m_enumPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotEnumChanged(QtProperty *, int))); connect(d_ptr->m_enumPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), this, SLOT(slotPropertyDestroyed(QtProperty *))); } /*! Destroys this manager, and all the properties it has created. */ QtLocalePropertyManager::~QtLocalePropertyManager() { clear(); delete d_ptr; } /*! Returns the manager that creates the nested \e language and \e country subproperties. In order to provide editing widgets for the mentioned subproperties in a property browser widget, this manager must be associated with an editor factory. \sa QtAbstractPropertyBrowser::setFactoryForManager() */ QtEnumPropertyManager *QtLocalePropertyManager::subEnumPropertyManager() const { return d_ptr->m_enumPropertyManager; } /*! Returns the given \a property's value. If the given property is not managed by this manager, this function returns the default locale. \sa setValue() */ QLocale QtLocalePropertyManager::value(const QtProperty *property) const { return d_ptr->m_values.value(property, QLocale()); } /*! \reimp */ QString QtLocalePropertyManager::valueText(const QtProperty *property) const { const QtLocalePropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); QLocale loc = it.value(); int langIdx = 0; int countryIdx = 0; metaEnumProvider()->localeToIndex(loc.language(), loc.country(), &langIdx, &countryIdx); QString str = tr("%1, %2") .arg(metaEnumProvider()->languageEnumNames().at(langIdx)) .arg(metaEnumProvider()->countryEnumNames(loc.language()).at(countryIdx)); return str; } /*! \fn void QtLocalePropertyManager::setValue(QtProperty *property, const QLocale &value) Sets the value of the given \a property to \a value. Nested properties are updated automatically. \sa value(), valueChanged() */ void QtLocalePropertyManager::setValue(QtProperty *property, const QLocale &val) { const QtLocalePropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; const QLocale loc = it.value(); if (loc == val) return; it.value() = val; int langIdx = 0; int countryIdx = 0; metaEnumProvider()->localeToIndex(val.language(), val.country(), &langIdx, &countryIdx); if (loc.language() != val.language()) { d_ptr->m_enumPropertyManager->setValue(d_ptr->m_propertyToLanguage.value(property), langIdx); d_ptr->m_enumPropertyManager->setEnumNames(d_ptr->m_propertyToCountry.value(property), metaEnumProvider()->countryEnumNames(val.language())); } d_ptr->m_enumPropertyManager->setValue(d_ptr->m_propertyToCountry.value(property), countryIdx); emit propertyChanged(property); emit valueChanged(property, val); } /*! \reimp */ void QtLocalePropertyManager::initializeProperty(QtProperty *property) { QLocale val; d_ptr->m_values[property] = val; int langIdx = 0; int countryIdx = 0; metaEnumProvider()->localeToIndex(val.language(), val.country(), &langIdx, &countryIdx); QtProperty *languageProp = d_ptr->m_enumPropertyManager->addProperty(); languageProp->setPropertyName(tr("Language")); d_ptr->m_enumPropertyManager->setEnumNames(languageProp, metaEnumProvider()->languageEnumNames()); d_ptr->m_enumPropertyManager->setValue(languageProp, langIdx); d_ptr->m_propertyToLanguage[property] = languageProp; d_ptr->m_languageToProperty[languageProp] = property; property->addSubProperty(languageProp); QtProperty *countryProp = d_ptr->m_enumPropertyManager->addProperty(); countryProp->setPropertyName(tr("Country")); d_ptr->m_enumPropertyManager->setEnumNames(countryProp, metaEnumProvider()->countryEnumNames(val.language())); d_ptr->m_enumPropertyManager->setValue(countryProp, countryIdx); d_ptr->m_propertyToCountry[property] = countryProp; d_ptr->m_countryToProperty[countryProp] = property; property->addSubProperty(countryProp); } /*! \reimp */ void QtLocalePropertyManager::uninitializeProperty(QtProperty *property) { QtProperty *languageProp = d_ptr->m_propertyToLanguage[property]; if (languageProp) { d_ptr->m_languageToProperty.remove(languageProp); delete languageProp; } d_ptr->m_propertyToLanguage.remove(property); QtProperty *countryProp = d_ptr->m_propertyToCountry[property]; if (countryProp) { d_ptr->m_countryToProperty.remove(countryProp); delete countryProp; } d_ptr->m_propertyToCountry.remove(property); d_ptr->m_values.remove(property); } // QtPointPropertyManager class QtPointPropertyManagerPrivate { QtPointPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtPointPropertyManager) public: void slotIntChanged(QtProperty *property, int value); void slotPropertyDestroyed(QtProperty *property); typedef QMap PropertyValueMap; PropertyValueMap m_values; QtIntPropertyManager *m_intPropertyManager; QMap m_propertyToX; QMap m_propertyToY; QMap m_xToProperty; QMap m_yToProperty; }; void QtPointPropertyManagerPrivate::slotIntChanged(QtProperty *property, int value) { if (QtProperty *xprop = m_xToProperty.value(property, 0)) { QPoint p = m_values[xprop]; p.setX(value); q_ptr->setValue(xprop, p); } else if (QtProperty *yprop = m_yToProperty.value(property, 0)) { QPoint p = m_values[yprop]; p.setY(value); q_ptr->setValue(yprop, p); } } void QtPointPropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) { if (QtProperty *pointProp = m_xToProperty.value(property, 0)) { m_propertyToX[pointProp] = 0; m_xToProperty.remove(property); } else if (QtProperty *pointProp = m_yToProperty.value(property, 0)) { m_propertyToY[pointProp] = 0; m_yToProperty.remove(property); } } /*! \class QtPointPropertyManager \brief The QtPointPropertyManager provides and manages QPoint properties. A point property has nested \e x and \e y subproperties. The top-level property's value can be retrieved using the value() function, and set using the setValue() slot. The subproperties are created by a QtIntPropertyManager object. This manager can be retrieved using the subIntPropertyManager() function. In order to provide editing widgets for the subproperties in a property browser widget, this manager must be associated with an editor factory. In addition, QtPointPropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes. \sa QtAbstractPropertyManager, QtIntPropertyManager, QtPointFPropertyManager */ /*! \fn void QtPointPropertyManager::valueChanged(QtProperty *property, const QPoint &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! Creates a manager with the given \a parent. */ QtPointPropertyManager::QtPointPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtPointPropertyManagerPrivate; d_ptr->q_ptr = this; d_ptr->m_intPropertyManager = new QtIntPropertyManager(this); connect(d_ptr->m_intPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotIntChanged(QtProperty *, int))); connect(d_ptr->m_intPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), this, SLOT(slotPropertyDestroyed(QtProperty *))); } /*! Destroys this manager, and all the properties it has created. */ QtPointPropertyManager::~QtPointPropertyManager() { clear(); delete d_ptr; } /*! Returns the manager that creates the nested \e x and \e y subproperties. In order to provide editing widgets for the subproperties in a property browser widget, this manager must be associated with an editor factory. \sa QtAbstractPropertyBrowser::setFactoryForManager() */ QtIntPropertyManager *QtPointPropertyManager::subIntPropertyManager() const { return d_ptr->m_intPropertyManager; } /*! Returns the given \a property's value. If the given \a property is not managed by this manager, this function returns a point with coordinates (0, 0). \sa setValue() */ QPoint QtPointPropertyManager::value(const QtProperty *property) const { return d_ptr->m_values.value(property, QPoint()); } /*! \reimp */ QString QtPointPropertyManager::valueText(const QtProperty *property) const { const QtPointPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); const QPoint v = it.value(); return QString(tr("(%1, %2)").arg(QString::number(v.x())) .arg(QString::number(v.y()))); } /*! \fn void QtPointPropertyManager::setValue(QtProperty *property, const QPoint &value) Sets the value of the given \a property to \a value. Nested properties are updated automatically. \sa value(), valueChanged() */ void QtPointPropertyManager::setValue(QtProperty *property, const QPoint &val) { const QtPointPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; if (it.value() == val) return; it.value() = val; d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToX[property], val.x()); d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToY[property], val.y()); emit propertyChanged(property); emit valueChanged(property, val); } /*! \reimp */ void QtPointPropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QPoint(0, 0); QtProperty *xProp = d_ptr->m_intPropertyManager->addProperty(); xProp->setPropertyName(tr("X")); d_ptr->m_intPropertyManager->setValue(xProp, 0); d_ptr->m_propertyToX[property] = xProp; d_ptr->m_xToProperty[xProp] = property; property->addSubProperty(xProp); QtProperty *yProp = d_ptr->m_intPropertyManager->addProperty(); yProp->setPropertyName(tr("Y")); d_ptr->m_intPropertyManager->setValue(yProp, 0); d_ptr->m_propertyToY[property] = yProp; d_ptr->m_yToProperty[yProp] = property; property->addSubProperty(yProp); } /*! \reimp */ void QtPointPropertyManager::uninitializeProperty(QtProperty *property) { QtProperty *xProp = d_ptr->m_propertyToX[property]; if (xProp) { d_ptr->m_xToProperty.remove(xProp); delete xProp; } d_ptr->m_propertyToX.remove(property); QtProperty *yProp = d_ptr->m_propertyToY[property]; if (yProp) { d_ptr->m_yToProperty.remove(yProp); delete yProp; } d_ptr->m_propertyToY.remove(property); d_ptr->m_values.remove(property); } // QtPointFPropertyManager class QtPointFPropertyManagerPrivate { QtPointFPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtPointFPropertyManager) public: struct Data { Data() : decimals(2) {} QPointF val; int decimals; }; void slotDoubleChanged(QtProperty *property, double value); void slotPropertyDestroyed(QtProperty *property); typedef QMap PropertyValueMap; PropertyValueMap m_values; QtDoublePropertyManager *m_doublePropertyManager; QMap m_propertyToX; QMap m_propertyToY; QMap m_xToProperty; QMap m_yToProperty; }; void QtPointFPropertyManagerPrivate::slotDoubleChanged(QtProperty *property, double value) { if (QtProperty *prop = m_xToProperty.value(property, 0)) { QPointF p = m_values[prop].val; p.setX(value); q_ptr->setValue(prop, p); } else if (QtProperty *prop = m_yToProperty.value(property, 0)) { QPointF p = m_values[prop].val; p.setY(value); q_ptr->setValue(prop, p); } } void QtPointFPropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) { if (QtProperty *pointProp = m_xToProperty.value(property, 0)) { m_propertyToX[pointProp] = 0; m_xToProperty.remove(property); } else if (QtProperty *pointProp = m_yToProperty.value(property, 0)) { m_propertyToY[pointProp] = 0; m_yToProperty.remove(property); } } /*! \class QtPointFPropertyManager \brief The QtPointFPropertyManager provides and manages QPointF properties. A point property has nested \e x and \e y subproperties. The top-level property's value can be retrieved using the value() function, and set using the setValue() slot. The subproperties are created by a QtDoublePropertyManager object. This manager can be retrieved using the subDoublePropertyManager() function. In order to provide editing widgets for the subproperties in a property browser widget, this manager must be associated with an editor factory. In addition, QtPointFPropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes. \sa QtAbstractPropertyManager, QtDoublePropertyManager, QtPointPropertyManager */ /*! \fn void QtPointFPropertyManager::valueChanged(QtProperty *property, const QPointF &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! \fn void QtPointFPropertyManager::decimalsChanged(QtProperty *property, int prec) This signal is emitted whenever a property created by this manager changes its precision of value, passing a pointer to the \a property and the new \a prec value \sa setDecimals() */ /*! Creates a manager with the given \a parent. */ QtPointFPropertyManager::QtPointFPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtPointFPropertyManagerPrivate; d_ptr->q_ptr = this; d_ptr->m_doublePropertyManager = new QtDoublePropertyManager(this); connect(d_ptr->m_doublePropertyManager, SIGNAL(valueChanged(QtProperty *, double)), this, SLOT(slotDoubleChanged(QtProperty *, double))); connect(d_ptr->m_doublePropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), this, SLOT(slotPropertyDestroyed(QtProperty *))); } /*! Destroys this manager, and all the properties it has created. */ QtPointFPropertyManager::~QtPointFPropertyManager() { clear(); delete d_ptr; } /*! Returns the manager that creates the nested \e x and \e y subproperties. In order to provide editing widgets for the subproperties in a property browser widget, this manager must be associated with an editor factory. \sa QtAbstractPropertyBrowser::setFactoryForManager() */ QtDoublePropertyManager *QtPointFPropertyManager::subDoublePropertyManager() const { return d_ptr->m_doublePropertyManager; } /*! Returns the given \a property's value. If the given \a property is not managed by this manager, this function returns a point with coordinates (0, 0). \sa setValue() */ QPointF QtPointFPropertyManager::value(const QtProperty *property) const { return getValue(d_ptr->m_values, property); } /*! Returns the given \a property's precision, in decimals. \sa setDecimals() */ int QtPointFPropertyManager::decimals(const QtProperty *property) const { return getData(d_ptr->m_values, &QtPointFPropertyManagerPrivate::Data::decimals, property, 0); } /*! \reimp */ QString QtPointFPropertyManager::valueText(const QtProperty *property) const { const QtPointFPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); const QPointF v = it.value().val; const int dec = it.value().decimals; return QString(tr("(%1, %2)").arg(QString::number(v.x(), 'f', dec)) .arg(QString::number(v.y(), 'f', dec))); } /*! \fn void QtPointFPropertyManager::setValue(QtProperty *property, const QPointF &value) Sets the value of the given \a property to \a value. Nested properties are updated automatically. \sa value(), valueChanged() */ void QtPointFPropertyManager::setValue(QtProperty *property, const QPointF &val) { const QtPointFPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; if (it.value().val == val) return; it.value().val = val; d_ptr->m_doublePropertyManager->setValue(d_ptr->m_propertyToX[property], val.x()); d_ptr->m_doublePropertyManager->setValue(d_ptr->m_propertyToY[property], val.y()); emit propertyChanged(property); emit valueChanged(property, val); } /*! \fn void QtPointFPropertyManager::setDecimals(QtProperty *property, int prec) Sets the precision of the given \a property to \a prec. The valid decimal range is 0-13. The default is 2. \sa decimals() */ void QtPointFPropertyManager::setDecimals(QtProperty *property, int prec) { const QtPointFPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtPointFPropertyManagerPrivate::Data data = it.value(); if (prec > 13) prec = 13; else if (prec < 0) prec = 0; if (data.decimals == prec) return; data.decimals = prec; d_ptr->m_doublePropertyManager->setDecimals(d_ptr->m_propertyToX[property], prec); d_ptr->m_doublePropertyManager->setDecimals(d_ptr->m_propertyToY[property], prec); it.value() = data; emit decimalsChanged(property, data.decimals); } /*! \reimp */ void QtPointFPropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QtPointFPropertyManagerPrivate::Data(); QtProperty *xProp = d_ptr->m_doublePropertyManager->addProperty(); xProp->setPropertyName(tr("X")); d_ptr->m_doublePropertyManager->setDecimals(xProp, decimals(property)); d_ptr->m_doublePropertyManager->setValue(xProp, 0); d_ptr->m_propertyToX[property] = xProp; d_ptr->m_xToProperty[xProp] = property; property->addSubProperty(xProp); QtProperty *yProp = d_ptr->m_doublePropertyManager->addProperty(); yProp->setPropertyName(tr("Y")); d_ptr->m_doublePropertyManager->setDecimals(yProp, decimals(property)); d_ptr->m_doublePropertyManager->setValue(yProp, 0); d_ptr->m_propertyToY[property] = yProp; d_ptr->m_yToProperty[yProp] = property; property->addSubProperty(yProp); } /*! \reimp */ void QtPointFPropertyManager::uninitializeProperty(QtProperty *property) { QtProperty *xProp = d_ptr->m_propertyToX[property]; if (xProp) { d_ptr->m_xToProperty.remove(xProp); delete xProp; } d_ptr->m_propertyToX.remove(property); QtProperty *yProp = d_ptr->m_propertyToY[property]; if (yProp) { d_ptr->m_yToProperty.remove(yProp); delete yProp; } d_ptr->m_propertyToY.remove(property); d_ptr->m_values.remove(property); } // QtSizePropertyManager class QtSizePropertyManagerPrivate { QtSizePropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtSizePropertyManager) public: void slotIntChanged(QtProperty *property, int value); void slotPropertyDestroyed(QtProperty *property); void setValue(QtProperty *property, const QSize &val); void setRange(QtProperty *property, const QSize &minVal, const QSize &maxVal, const QSize &val); struct Data { Data() : val(QSize(0, 0)), minVal(QSize(0, 0)), maxVal(QSize(INT_MAX, INT_MAX)) {} QSize val; QSize minVal; QSize maxVal; QSize minimumValue() const { return minVal; } QSize maximumValue() const { return maxVal; } void setMinimumValue(const QSize &newMinVal) { setSizeMinimumData(this, newMinVal); } void setMaximumValue(const QSize &newMaxVal) { setSizeMaximumData(this, newMaxVal); } }; typedef QMap PropertyValueMap; PropertyValueMap m_values; QtIntPropertyManager *m_intPropertyManager; QMap m_propertyToW; QMap m_propertyToH; QMap m_wToProperty; QMap m_hToProperty; }; void QtSizePropertyManagerPrivate::slotIntChanged(QtProperty *property, int value) { if (QtProperty *prop = m_wToProperty.value(property, 0)) { QSize s = m_values[prop].val; s.setWidth(value); q_ptr->setValue(prop, s); } else if (QtProperty *prop = m_hToProperty.value(property, 0)) { QSize s = m_values[prop].val; s.setHeight(value); q_ptr->setValue(prop, s); } } void QtSizePropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) { if (QtProperty *pointProp = m_wToProperty.value(property, 0)) { m_propertyToW[pointProp] = 0; m_wToProperty.remove(property); } else if (QtProperty *pointProp = m_hToProperty.value(property, 0)) { m_propertyToH[pointProp] = 0; m_hToProperty.remove(property); } } void QtSizePropertyManagerPrivate::setValue(QtProperty *property, const QSize &val) { m_intPropertyManager->setValue(m_propertyToW.value(property), val.width()); m_intPropertyManager->setValue(m_propertyToH.value(property), val.height()); } void QtSizePropertyManagerPrivate::setRange(QtProperty *property, const QSize &minVal, const QSize &maxVal, const QSize &val) { QtProperty *wProperty = m_propertyToW.value(property); QtProperty *hProperty = m_propertyToH.value(property); m_intPropertyManager->setRange(wProperty, minVal.width(), maxVal.width()); m_intPropertyManager->setValue(wProperty, val.width()); m_intPropertyManager->setRange(hProperty, minVal.height(), maxVal.height()); m_intPropertyManager->setValue(hProperty, val.height()); } /*! \class QtSizePropertyManager \brief The QtSizePropertyManager provides and manages QSize properties. A size property has nested \e width and \e height subproperties. The top-level property's value can be retrieved using the value() function, and set using the setValue() slot. The subproperties are created by a QtIntPropertyManager object. This manager can be retrieved using the subIntPropertyManager() function. In order to provide editing widgets for the subproperties in a property browser widget, this manager must be associated with an editor factory. A size property also has a range of valid values defined by a minimum size and a maximum size. These sizes can be retrieved using the minimum() and the maximum() functions, and set using the setMinimum() and setMaximum() slots. Alternatively, the range can be defined in one go using the setRange() slot. In addition, QtSizePropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes, and the rangeChanged() signal which is emitted whenever such a property changes its range of valid sizes. \sa QtAbstractPropertyManager, QtIntPropertyManager, QtSizeFPropertyManager */ /*! \fn void QtSizePropertyManager::valueChanged(QtProperty *property, const QSize &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! \fn void QtSizePropertyManager::rangeChanged(QtProperty *property, const QSize &minimum, const QSize &maximum) This signal is emitted whenever a property created by this manager changes its range of valid sizes, passing a pointer to the \a property and the new \a minimum and \a maximum sizes. \sa setRange() */ /*! Creates a manager with the given \a parent. */ QtSizePropertyManager::QtSizePropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtSizePropertyManagerPrivate; d_ptr->q_ptr = this; d_ptr->m_intPropertyManager = new QtIntPropertyManager(this); connect(d_ptr->m_intPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotIntChanged(QtProperty *, int))); connect(d_ptr->m_intPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), this, SLOT(slotPropertyDestroyed(QtProperty *))); } /*! Destroys this manager, and all the properties it has created. */ QtSizePropertyManager::~QtSizePropertyManager() { clear(); delete d_ptr; } /*! Returns the manager that creates the nested \e width and \e height subproperties. In order to provide editing widgets for the \e width and \e height properties in a property browser widget, this manager must be associated with an editor factory. \sa QtAbstractPropertyBrowser::setFactoryForManager() */ QtIntPropertyManager *QtSizePropertyManager::subIntPropertyManager() const { return d_ptr->m_intPropertyManager; } /*! Returns the given \a property's value. If the given \a property is not managed by this manager, this function returns an invalid size \sa setValue() */ QSize QtSizePropertyManager::value(const QtProperty *property) const { return getValue(d_ptr->m_values, property); } /*! Returns the given \a property's minimum size value. \sa setMinimum(), maximum(), setRange() */ QSize QtSizePropertyManager::minimum(const QtProperty *property) const { return getMinimum(d_ptr->m_values, property); } /*! Returns the given \a property's maximum size value. \sa setMaximum(), minimum(), setRange() */ QSize QtSizePropertyManager::maximum(const QtProperty *property) const { return getMaximum(d_ptr->m_values, property); } /*! \reimp */ QString QtSizePropertyManager::valueText(const QtProperty *property) const { const QtSizePropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); const QSize v = it.value().val; return QString(tr("%1 x %2").arg(QString::number(v.width())) .arg(QString::number(v.height()))); } /*! \fn void QtSizePropertyManager::setValue(QtProperty *property, const QSize &value) Sets the value of the given \a property to \a value. If the specified \a value is not valid according to the given \a property's size range, the \a value is adjusted to the nearest valid value within the size range. \sa value(), setRange(), valueChanged() */ void QtSizePropertyManager::setValue(QtProperty *property, const QSize &val) { setValueInRange(this, d_ptr, &QtSizePropertyManager::propertyChanged, &QtSizePropertyManager::valueChanged, property, val, &QtSizePropertyManagerPrivate::setValue); } /*! Sets the minimum size value for the given \a property to \a minVal. When setting the minimum size value, the maximum and current values are adjusted if necessary (ensuring that the size range remains valid and that the current value is within the range). \sa minimum(), setRange(), rangeChanged() */ void QtSizePropertyManager::setMinimum(QtProperty *property, const QSize &minVal) { setBorderValue(this, d_ptr, &QtSizePropertyManager::propertyChanged, &QtSizePropertyManager::valueChanged, &QtSizePropertyManager::rangeChanged, property, &QtSizePropertyManagerPrivate::Data::minimumValue, &QtSizePropertyManagerPrivate::Data::setMinimumValue, minVal, &QtSizePropertyManagerPrivate::setRange); } /*! Sets the maximum size value for the given \a property to \a maxVal. When setting the maximum size value, the minimum and current values are adjusted if necessary (ensuring that the size range remains valid and that the current value is within the range). \sa maximum(), setRange(), rangeChanged() */ void QtSizePropertyManager::setMaximum(QtProperty *property, const QSize &maxVal) { setBorderValue(this, d_ptr, &QtSizePropertyManager::propertyChanged, &QtSizePropertyManager::valueChanged, &QtSizePropertyManager::rangeChanged, property, &QtSizePropertyManagerPrivate::Data::maximumValue, &QtSizePropertyManagerPrivate::Data::setMaximumValue, maxVal, &QtSizePropertyManagerPrivate::setRange); } /*! \fn void QtSizePropertyManager::setRange(QtProperty *property, const QSize &minimum, const QSize &maximum) Sets the range of valid values. This is a convenience function defining the range of valid values in one go; setting the \a minimum and \a maximum values for the given \a property with a single function call. When setting a new range, the current value is adjusted if necessary (ensuring that the value remains within the range). \sa setMinimum(), setMaximum(), rangeChanged() */ void QtSizePropertyManager::setRange(QtProperty *property, const QSize &minVal, const QSize &maxVal) { setBorderValues(this, d_ptr, &QtSizePropertyManager::propertyChanged, &QtSizePropertyManager::valueChanged, &QtSizePropertyManager::rangeChanged, property, minVal, maxVal, &QtSizePropertyManagerPrivate::setRange); } /*! \reimp */ void QtSizePropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QtSizePropertyManagerPrivate::Data(); QtProperty *wProp = d_ptr->m_intPropertyManager->addProperty(); wProp->setPropertyName(tr("Width")); d_ptr->m_intPropertyManager->setValue(wProp, 0); d_ptr->m_intPropertyManager->setMinimum(wProp, 0); d_ptr->m_propertyToW[property] = wProp; d_ptr->m_wToProperty[wProp] = property; property->addSubProperty(wProp); QtProperty *hProp = d_ptr->m_intPropertyManager->addProperty(); hProp->setPropertyName(tr("Height")); d_ptr->m_intPropertyManager->setValue(hProp, 0); d_ptr->m_intPropertyManager->setMinimum(hProp, 0); d_ptr->m_propertyToH[property] = hProp; d_ptr->m_hToProperty[hProp] = property; property->addSubProperty(hProp); } /*! \reimp */ void QtSizePropertyManager::uninitializeProperty(QtProperty *property) { QtProperty *wProp = d_ptr->m_propertyToW[property]; if (wProp) { d_ptr->m_wToProperty.remove(wProp); delete wProp; } d_ptr->m_propertyToW.remove(property); QtProperty *hProp = d_ptr->m_propertyToH[property]; if (hProp) { d_ptr->m_hToProperty.remove(hProp); delete hProp; } d_ptr->m_propertyToH.remove(property); d_ptr->m_values.remove(property); } // QtSizeFPropertyManager class QtSizeFPropertyManagerPrivate { QtSizeFPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtSizeFPropertyManager) public: void slotDoubleChanged(QtProperty *property, double value); void slotPropertyDestroyed(QtProperty *property); void setValue(QtProperty *property, const QSizeF &val); void setRange(QtProperty *property, const QSizeF &minVal, const QSizeF &maxVal, const QSizeF &val); struct Data { Data() : val(QSizeF(0, 0)), minVal(QSizeF(0, 0)), maxVal(QSizeF(INT_MAX, INT_MAX)), decimals(2) {} QSizeF val; QSizeF minVal; QSizeF maxVal; int decimals; QSizeF minimumValue() const { return minVal; } QSizeF maximumValue() const { return maxVal; } void setMinimumValue(const QSizeF &newMinVal) { setSizeMinimumData(this, newMinVal); } void setMaximumValue(const QSizeF &newMaxVal) { setSizeMaximumData(this, newMaxVal); } }; typedef QMap PropertyValueMap; PropertyValueMap m_values; QtDoublePropertyManager *m_doublePropertyManager; QMap m_propertyToW; QMap m_propertyToH; QMap m_wToProperty; QMap m_hToProperty; }; void QtSizeFPropertyManagerPrivate::slotDoubleChanged(QtProperty *property, double value) { if (QtProperty *prop = m_wToProperty.value(property, 0)) { QSizeF s = m_values[prop].val; s.setWidth(value); q_ptr->setValue(prop, s); } else if (QtProperty *prop = m_hToProperty.value(property, 0)) { QSizeF s = m_values[prop].val; s.setHeight(value); q_ptr->setValue(prop, s); } } void QtSizeFPropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) { if (QtProperty *pointProp = m_wToProperty.value(property, 0)) { m_propertyToW[pointProp] = 0; m_wToProperty.remove(property); } else if (QtProperty *pointProp = m_hToProperty.value(property, 0)) { m_propertyToH[pointProp] = 0; m_hToProperty.remove(property); } } void QtSizeFPropertyManagerPrivate::setValue(QtProperty *property, const QSizeF &val) { m_doublePropertyManager->setValue(m_propertyToW.value(property), val.width()); m_doublePropertyManager->setValue(m_propertyToH.value(property), val.height()); } void QtSizeFPropertyManagerPrivate::setRange(QtProperty *property, const QSizeF &minVal, const QSizeF &maxVal, const QSizeF &val) { m_doublePropertyManager->setRange(m_propertyToW[property], minVal.width(), maxVal.width()); m_doublePropertyManager->setValue(m_propertyToW[property], val.width()); m_doublePropertyManager->setRange(m_propertyToH[property], minVal.height(), maxVal.height()); m_doublePropertyManager->setValue(m_propertyToH[property], val.height()); } /*! \class QtSizeFPropertyManager \brief The QtSizeFPropertyManager provides and manages QSizeF properties. A size property has nested \e width and \e height subproperties. The top-level property's value can be retrieved using the value() function, and set using the setValue() slot. The subproperties are created by a QtDoublePropertyManager object. This manager can be retrieved using the subDoublePropertyManager() function. In order to provide editing widgets for the subproperties in a property browser widget, this manager must be associated with an editor factory. A size property also has a range of valid values defined by a minimum size and a maximum size. These sizes can be retrieved using the minimum() and the maximum() functions, and set using the setMinimum() and setMaximum() slots. Alternatively, the range can be defined in one go using the setRange() slot. In addition, QtSizeFPropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes, and the rangeChanged() signal which is emitted whenever such a property changes its range of valid sizes. \sa QtAbstractPropertyManager, QtDoublePropertyManager, QtSizePropertyManager */ /*! \fn void QtSizeFPropertyManager::valueChanged(QtProperty *property, const QSizeF &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! \fn void QtSizeFPropertyManager::rangeChanged(QtProperty *property, const QSizeF &minimum, const QSizeF &maximum) This signal is emitted whenever a property created by this manager changes its range of valid sizes, passing a pointer to the \a property and the new \a minimum and \a maximum sizes. \sa setRange() */ /*! \fn void QtSizeFPropertyManager::decimalsChanged(QtProperty *property, int prec) This signal is emitted whenever a property created by this manager changes its precision of value, passing a pointer to the \a property and the new \a prec value \sa setDecimals() */ /*! Creates a manager with the given \a parent. */ QtSizeFPropertyManager::QtSizeFPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtSizeFPropertyManagerPrivate; d_ptr->q_ptr = this; d_ptr->m_doublePropertyManager = new QtDoublePropertyManager(this); connect(d_ptr->m_doublePropertyManager, SIGNAL(valueChanged(QtProperty *, double)), this, SLOT(slotDoubleChanged(QtProperty *, double))); connect(d_ptr->m_doublePropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), this, SLOT(slotPropertyDestroyed(QtProperty *))); } /*! Destroys this manager, and all the properties it has created. */ QtSizeFPropertyManager::~QtSizeFPropertyManager() { clear(); delete d_ptr; } /*! Returns the manager that creates the nested \e width and \e height subproperties. In order to provide editing widgets for the \e width and \e height properties in a property browser widget, this manager must be associated with an editor factory. \sa QtAbstractPropertyBrowser::setFactoryForManager() */ QtDoublePropertyManager *QtSizeFPropertyManager::subDoublePropertyManager() const { return d_ptr->m_doublePropertyManager; } /*! Returns the given \a property's value. If the given \a property is not managed by this manager, this function returns an invalid size \sa setValue() */ QSizeF QtSizeFPropertyManager::value(const QtProperty *property) const { return getValue(d_ptr->m_values, property); } /*! Returns the given \a property's precision, in decimals. \sa setDecimals() */ int QtSizeFPropertyManager::decimals(const QtProperty *property) const { return getData(d_ptr->m_values, &QtSizeFPropertyManagerPrivate::Data::decimals, property, 0); } /*! Returns the given \a property's minimum size value. \sa setMinimum(), maximum(), setRange() */ QSizeF QtSizeFPropertyManager::minimum(const QtProperty *property) const { return getMinimum(d_ptr->m_values, property); } /*! Returns the given \a property's maximum size value. \sa setMaximum(), minimum(), setRange() */ QSizeF QtSizeFPropertyManager::maximum(const QtProperty *property) const { return getMaximum(d_ptr->m_values, property); } /*! \reimp */ QString QtSizeFPropertyManager::valueText(const QtProperty *property) const { const QtSizeFPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); const QSizeF v = it.value().val; const int dec = it.value().decimals; return QString(tr("%1 x %2").arg(QString::number(v.width(), 'f', dec)) .arg(QString::number(v.height(), 'f', dec))); } /*! \fn void QtSizeFPropertyManager::setValue(QtProperty *property, const QSizeF &value) Sets the value of the given \a property to \a value. If the specified \a value is not valid according to the given \a property's size range, the \a value is adjusted to the nearest valid value within the size range. \sa value(), setRange(), valueChanged() */ void QtSizeFPropertyManager::setValue(QtProperty *property, const QSizeF &val) { setValueInRange(this, d_ptr, &QtSizeFPropertyManager::propertyChanged, &QtSizeFPropertyManager::valueChanged, property, val, &QtSizeFPropertyManagerPrivate::setValue); } /*! \fn void QtSizeFPropertyManager::setDecimals(QtProperty *property, int prec) Sets the precision of the given \a property to \a prec. The valid decimal range is 0-13. The default is 2. \sa decimals() */ void QtSizeFPropertyManager::setDecimals(QtProperty *property, int prec) { const QtSizeFPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtSizeFPropertyManagerPrivate::Data data = it.value(); if (prec > 13) prec = 13; else if (prec < 0) prec = 0; if (data.decimals == prec) return; data.decimals = prec; d_ptr->m_doublePropertyManager->setDecimals(d_ptr->m_propertyToW[property], prec); d_ptr->m_doublePropertyManager->setDecimals(d_ptr->m_propertyToH[property], prec); it.value() = data; emit decimalsChanged(property, data.decimals); } /*! Sets the minimum size value for the given \a property to \a minVal. When setting the minimum size value, the maximum and current values are adjusted if necessary (ensuring that the size range remains valid and that the current value is within the range). \sa minimum(), setRange(), rangeChanged() */ void QtSizeFPropertyManager::setMinimum(QtProperty *property, const QSizeF &minVal) { setBorderValue(this, d_ptr, &QtSizeFPropertyManager::propertyChanged, &QtSizeFPropertyManager::valueChanged, &QtSizeFPropertyManager::rangeChanged, property, &QtSizeFPropertyManagerPrivate::Data::minimumValue, &QtSizeFPropertyManagerPrivate::Data::setMinimumValue, minVal, &QtSizeFPropertyManagerPrivate::setRange); } /*! Sets the maximum size value for the given \a property to \a maxVal. When setting the maximum size value, the minimum and current values are adjusted if necessary (ensuring that the size range remains valid and that the current value is within the range). \sa maximum(), setRange(), rangeChanged() */ void QtSizeFPropertyManager::setMaximum(QtProperty *property, const QSizeF &maxVal) { setBorderValue(this, d_ptr, &QtSizeFPropertyManager::propertyChanged, &QtSizeFPropertyManager::valueChanged, &QtSizeFPropertyManager::rangeChanged, property, &QtSizeFPropertyManagerPrivate::Data::maximumValue, &QtSizeFPropertyManagerPrivate::Data::setMaximumValue, maxVal, &QtSizeFPropertyManagerPrivate::setRange); } /*! \fn void QtSizeFPropertyManager::setRange(QtProperty *property, const QSizeF &minimum, const QSizeF &maximum) Sets the range of valid values. This is a convenience function defining the range of valid values in one go; setting the \a minimum and \a maximum values for the given \a property with a single function call. When setting a new range, the current value is adjusted if necessary (ensuring that the value remains within the range). \sa setMinimum(), setMaximum(), rangeChanged() */ void QtSizeFPropertyManager::setRange(QtProperty *property, const QSizeF &minVal, const QSizeF &maxVal) { setBorderValues(this, d_ptr, &QtSizeFPropertyManager::propertyChanged, &QtSizeFPropertyManager::valueChanged, &QtSizeFPropertyManager::rangeChanged, property, minVal, maxVal, &QtSizeFPropertyManagerPrivate::setRange); } /*! \reimp */ void QtSizeFPropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QtSizeFPropertyManagerPrivate::Data(); QtProperty *wProp = d_ptr->m_doublePropertyManager->addProperty(); wProp->setPropertyName(tr("Width")); d_ptr->m_doublePropertyManager->setDecimals(wProp, decimals(property)); d_ptr->m_doublePropertyManager->setValue(wProp, 0); d_ptr->m_doublePropertyManager->setMinimum(wProp, 0); d_ptr->m_propertyToW[property] = wProp; d_ptr->m_wToProperty[wProp] = property; property->addSubProperty(wProp); QtProperty *hProp = d_ptr->m_doublePropertyManager->addProperty(); hProp->setPropertyName(tr("Height")); d_ptr->m_doublePropertyManager->setDecimals(hProp, decimals(property)); d_ptr->m_doublePropertyManager->setValue(hProp, 0); d_ptr->m_doublePropertyManager->setMinimum(hProp, 0); d_ptr->m_propertyToH[property] = hProp; d_ptr->m_hToProperty[hProp] = property; property->addSubProperty(hProp); } /*! \reimp */ void QtSizeFPropertyManager::uninitializeProperty(QtProperty *property) { QtProperty *wProp = d_ptr->m_propertyToW[property]; if (wProp) { d_ptr->m_wToProperty.remove(wProp); delete wProp; } d_ptr->m_propertyToW.remove(property); QtProperty *hProp = d_ptr->m_propertyToH[property]; if (hProp) { d_ptr->m_hToProperty.remove(hProp); delete hProp; } d_ptr->m_propertyToH.remove(property); d_ptr->m_values.remove(property); } // QtRectPropertyManager class QtRectPropertyManagerPrivate { QtRectPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtRectPropertyManager) public: void slotIntChanged(QtProperty *property, int value); void slotPropertyDestroyed(QtProperty *property); void setConstraint(QtProperty *property, const QRect &constraint, const QRect &val); struct Data { Data() : val(0, 0, 0, 0) {} QRect val; QRect constraint; }; typedef QMap PropertyValueMap; PropertyValueMap m_values; QtIntPropertyManager *m_intPropertyManager; QMap m_propertyToX; QMap m_propertyToY; QMap m_propertyToW; QMap m_propertyToH; QMap m_xToProperty; QMap m_yToProperty; QMap m_wToProperty; QMap m_hToProperty; }; void QtRectPropertyManagerPrivate::slotIntChanged(QtProperty *property, int value) { if (QtProperty *prop = m_xToProperty.value(property, 0)) { QRect r = m_values[prop].val; r.moveLeft(value); q_ptr->setValue(prop, r); } else if (QtProperty *prop = m_yToProperty.value(property)) { QRect r = m_values[prop].val; r.moveTop(value); q_ptr->setValue(prop, r); } else if (QtProperty *prop = m_wToProperty.value(property, 0)) { Data data = m_values[prop]; QRect r = data.val; r.setWidth(value); if (!data.constraint.isNull() && data.constraint.x() + data.constraint.width() < r.x() + r.width()) { r.moveLeft(data.constraint.left() + data.constraint.width() - r.width()); } q_ptr->setValue(prop, r); } else if (QtProperty *prop = m_hToProperty.value(property, 0)) { Data data = m_values[prop]; QRect r = data.val; r.setHeight(value); if (!data.constraint.isNull() && data.constraint.y() + data.constraint.height() < r.y() + r.height()) { r.moveTop(data.constraint.top() + data.constraint.height() - r.height()); } q_ptr->setValue(prop, r); } } void QtRectPropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) { if (QtProperty *pointProp = m_xToProperty.value(property, 0)) { m_propertyToX[pointProp] = 0; m_xToProperty.remove(property); } else if (QtProperty *pointProp = m_yToProperty.value(property, 0)) { m_propertyToY[pointProp] = 0; m_yToProperty.remove(property); } else if (QtProperty *pointProp = m_wToProperty.value(property, 0)) { m_propertyToW[pointProp] = 0; m_wToProperty.remove(property); } else if (QtProperty *pointProp = m_hToProperty.value(property, 0)) { m_propertyToH[pointProp] = 0; m_hToProperty.remove(property); } } void QtRectPropertyManagerPrivate::setConstraint(QtProperty *property, const QRect &constraint, const QRect &val) { const bool isNull = constraint.isNull(); const int left = isNull ? INT_MIN : constraint.left(); const int right = isNull ? INT_MAX : constraint.left() + constraint.width(); const int top = isNull ? INT_MIN : constraint.top(); const int bottom = isNull ? INT_MAX : constraint.top() + constraint.height(); const int width = isNull ? INT_MAX : constraint.width(); const int height = isNull ? INT_MAX : constraint.height(); m_intPropertyManager->setRange(m_propertyToX[property], left, right); m_intPropertyManager->setRange(m_propertyToY[property], top, bottom); m_intPropertyManager->setRange(m_propertyToW[property], 0, width); m_intPropertyManager->setRange(m_propertyToH[property], 0, height); m_intPropertyManager->setValue(m_propertyToX[property], val.x()); m_intPropertyManager->setValue(m_propertyToY[property], val.y()); m_intPropertyManager->setValue(m_propertyToW[property], val.width()); m_intPropertyManager->setValue(m_propertyToH[property], val.height()); } /*! \class QtRectPropertyManager \brief The QtRectPropertyManager provides and manages QRect properties. A rectangle property has nested \e x, \e y, \e width and \e height subproperties. The top-level property's value can be retrieved using the value() function, and set using the setValue() slot. The subproperties are created by a QtIntPropertyManager object. This manager can be retrieved using the subIntPropertyManager() function. In order to provide editing widgets for the subproperties in a property browser widget, this manager must be associated with an editor factory. A rectangle property also has a constraint rectangle which can be retrieved using the constraint() function, and set using the setConstraint() slot. In addition, QtRectPropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes, and the constraintChanged() signal which is emitted whenever such a property changes its constraint rectangle. \sa QtAbstractPropertyManager, QtIntPropertyManager, QtRectFPropertyManager */ /*! \fn void QtRectPropertyManager::valueChanged(QtProperty *property, const QRect &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! \fn void QtRectPropertyManager::constraintChanged(QtProperty *property, const QRect &constraint) This signal is emitted whenever property changes its constraint rectangle, passing a pointer to the \a property and the new \a constraint rectangle as parameters. \sa setConstraint() */ /*! Creates a manager with the given \a parent. */ QtRectPropertyManager::QtRectPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtRectPropertyManagerPrivate; d_ptr->q_ptr = this; d_ptr->m_intPropertyManager = new QtIntPropertyManager(this); connect(d_ptr->m_intPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotIntChanged(QtProperty *, int))); connect(d_ptr->m_intPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), this, SLOT(slotPropertyDestroyed(QtProperty *))); } /*! Destroys this manager, and all the properties it has created. */ QtRectPropertyManager::~QtRectPropertyManager() { clear(); delete d_ptr; } /*! Returns the manager that creates the nested \e x, \e y, \e width and \e height subproperties. In order to provide editing widgets for the mentioned subproperties in a property browser widget, this manager must be associated with an editor factory. \sa QtAbstractPropertyBrowser::setFactoryForManager() */ QtIntPropertyManager *QtRectPropertyManager::subIntPropertyManager() const { return d_ptr->m_intPropertyManager; } /*! Returns the given \a property's value. If the given \a property is not managed by this manager, this function returns an invalid rectangle. \sa setValue(), constraint() */ QRect QtRectPropertyManager::value(const QtProperty *property) const { return getValue(d_ptr->m_values, property); } /*! Returns the given \a property's constraining rectangle. If returned value is null QRect it means there is no constraint applied. \sa value(), setConstraint() */ QRect QtRectPropertyManager::constraint(const QtProperty *property) const { return getData(d_ptr->m_values, &QtRectPropertyManagerPrivate::Data::constraint, property, QRect()); } /*! \reimp */ QString QtRectPropertyManager::valueText(const QtProperty *property) const { const QtRectPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); const QRect v = it.value().val; return QString(tr("[(%1, %2), %3 x %4]").arg(QString::number(v.x())) .arg(QString::number(v.y())) .arg(QString::number(v.width())) .arg(QString::number(v.height()))); } /*! \fn void QtRectPropertyManager::setValue(QtProperty *property, const QRect &value) Sets the value of the given \a property to \a value. Nested properties are updated automatically. If the specified \a value is not inside the given \a property's constraining rectangle, the value is adjusted accordingly to fit within the constraint. \sa value(), setConstraint(), valueChanged() */ void QtRectPropertyManager::setValue(QtProperty *property, const QRect &val) { const QtRectPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtRectPropertyManagerPrivate::Data data = it.value(); QRect newRect = val.normalized(); if (!data.constraint.isNull() && !data.constraint.contains(newRect)) { const QRect r1 = data.constraint; const QRect r2 = newRect; newRect.setLeft(qMax(r1.left(), r2.left())); newRect.setRight(qMin(r1.right(), r2.right())); newRect.setTop(qMax(r1.top(), r2.top())); newRect.setBottom(qMin(r1.bottom(), r2.bottom())); if (newRect.width() < 0 || newRect.height() < 0) return; } if (data.val == newRect) return; data.val = newRect; it.value() = data; d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToX[property], newRect.x()); d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToY[property], newRect.y()); d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToW[property], newRect.width()); d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToH[property], newRect.height()); emit propertyChanged(property); emit valueChanged(property, data.val); } /*! Sets the given \a property's constraining rectangle to \a constraint. When setting the constraint, the current value is adjusted if necessary (ensuring that the current rectangle value is inside the constraint). In order to reset the constraint pass a null QRect value. \sa setValue(), constraint(), constraintChanged() */ void QtRectPropertyManager::setConstraint(QtProperty *property, const QRect &constraint) { const QtRectPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtRectPropertyManagerPrivate::Data data = it.value(); QRect newConstraint = constraint.normalized(); if (data.constraint == newConstraint) return; const QRect oldVal = data.val; data.constraint = newConstraint; if (!data.constraint.isNull() && !data.constraint.contains(oldVal)) { QRect r1 = data.constraint; QRect r2 = data.val; if (r2.width() > r1.width()) r2.setWidth(r1.width()); if (r2.height() > r1.height()) r2.setHeight(r1.height()); if (r2.left() < r1.left()) r2.moveLeft(r1.left()); else if (r2.right() > r1.right()) r2.moveRight(r1.right()); if (r2.top() < r1.top()) r2.moveTop(r1.top()); else if (r2.bottom() > r1.bottom()) r2.moveBottom(r1.bottom()); data.val = r2; } it.value() = data; emit constraintChanged(property, data.constraint); d_ptr->setConstraint(property, data.constraint, data.val); if (data.val == oldVal) return; emit propertyChanged(property); emit valueChanged(property, data.val); } /*! \reimp */ void QtRectPropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QtRectPropertyManagerPrivate::Data(); QtProperty *xProp = d_ptr->m_intPropertyManager->addProperty(); xProp->setPropertyName(tr("X")); d_ptr->m_intPropertyManager->setValue(xProp, 0); d_ptr->m_propertyToX[property] = xProp; d_ptr->m_xToProperty[xProp] = property; property->addSubProperty(xProp); QtProperty *yProp = d_ptr->m_intPropertyManager->addProperty(); yProp->setPropertyName(tr("Y")); d_ptr->m_intPropertyManager->setValue(yProp, 0); d_ptr->m_propertyToY[property] = yProp; d_ptr->m_yToProperty[yProp] = property; property->addSubProperty(yProp); QtProperty *wProp = d_ptr->m_intPropertyManager->addProperty(); wProp->setPropertyName(tr("Width")); d_ptr->m_intPropertyManager->setValue(wProp, 0); d_ptr->m_intPropertyManager->setMinimum(wProp, 0); d_ptr->m_propertyToW[property] = wProp; d_ptr->m_wToProperty[wProp] = property; property->addSubProperty(wProp); QtProperty *hProp = d_ptr->m_intPropertyManager->addProperty(); hProp->setPropertyName(tr("Height")); d_ptr->m_intPropertyManager->setValue(hProp, 0); d_ptr->m_intPropertyManager->setMinimum(hProp, 0); d_ptr->m_propertyToH[property] = hProp; d_ptr->m_hToProperty[hProp] = property; property->addSubProperty(hProp); } /*! \reimp */ void QtRectPropertyManager::uninitializeProperty(QtProperty *property) { QtProperty *xProp = d_ptr->m_propertyToX[property]; if (xProp) { d_ptr->m_xToProperty.remove(xProp); delete xProp; } d_ptr->m_propertyToX.remove(property); QtProperty *yProp = d_ptr->m_propertyToY[property]; if (yProp) { d_ptr->m_yToProperty.remove(yProp); delete yProp; } d_ptr->m_propertyToY.remove(property); QtProperty *wProp = d_ptr->m_propertyToW[property]; if (wProp) { d_ptr->m_wToProperty.remove(wProp); delete wProp; } d_ptr->m_propertyToW.remove(property); QtProperty *hProp = d_ptr->m_propertyToH[property]; if (hProp) { d_ptr->m_hToProperty.remove(hProp); delete hProp; } d_ptr->m_propertyToH.remove(property); d_ptr->m_values.remove(property); } // QtRectFPropertyManager class QtRectFPropertyManagerPrivate { QtRectFPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtRectFPropertyManager) public: void slotDoubleChanged(QtProperty *property, double value); void slotPropertyDestroyed(QtProperty *property); void setConstraint(QtProperty *property, const QRectF &constraint, const QRectF &val); struct Data { Data() : val(0, 0, 0, 0), decimals(2) {} QRectF val; QRectF constraint; int decimals; }; typedef QMap PropertyValueMap; PropertyValueMap m_values; QtDoublePropertyManager *m_doublePropertyManager; QMap m_propertyToX; QMap m_propertyToY; QMap m_propertyToW; QMap m_propertyToH; QMap m_xToProperty; QMap m_yToProperty; QMap m_wToProperty; QMap m_hToProperty; }; void QtRectFPropertyManagerPrivate::slotDoubleChanged(QtProperty *property, double value) { if (QtProperty *prop = m_xToProperty.value(property, 0)) { QRectF r = m_values[prop].val; r.moveLeft(value); q_ptr->setValue(prop, r); } else if (QtProperty *prop = m_yToProperty.value(property, 0)) { QRectF r = m_values[prop].val; r.moveTop(value); q_ptr->setValue(prop, r); } else if (QtProperty *prop = m_wToProperty.value(property, 0)) { Data data = m_values[prop]; QRectF r = data.val; r.setWidth(value); if (!data.constraint.isNull() && data.constraint.x() + data.constraint.width() < r.x() + r.width()) { r.moveLeft(data.constraint.left() + data.constraint.width() - r.width()); } q_ptr->setValue(prop, r); } else if (QtProperty *prop = m_hToProperty.value(property, 0)) { Data data = m_values[prop]; QRectF r = data.val; r.setHeight(value); if (!data.constraint.isNull() && data.constraint.y() + data.constraint.height() < r.y() + r.height()) { r.moveTop(data.constraint.top() + data.constraint.height() - r.height()); } q_ptr->setValue(prop, r); } } void QtRectFPropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) { if (QtProperty *pointProp = m_xToProperty.value(property, 0)) { m_propertyToX[pointProp] = 0; m_xToProperty.remove(property); } else if (QtProperty *pointProp = m_yToProperty.value(property, 0)) { m_propertyToY[pointProp] = 0; m_yToProperty.remove(property); } else if (QtProperty *pointProp = m_wToProperty.value(property, 0)) { m_propertyToW[pointProp] = 0; m_wToProperty.remove(property); } else if (QtProperty *pointProp = m_hToProperty.value(property, 0)) { m_propertyToH[pointProp] = 0; m_hToProperty.remove(property); } } void QtRectFPropertyManagerPrivate::setConstraint(QtProperty *property, const QRectF &constraint, const QRectF &val) { const bool isNull = constraint.isNull(); const float left = isNull ? FLT_MIN : constraint.left(); const float right = isNull ? FLT_MAX : constraint.left() + constraint.width(); const float top = isNull ? FLT_MIN : constraint.top(); const float bottom = isNull ? FLT_MAX : constraint.top() + constraint.height(); const float width = isNull ? FLT_MAX : constraint.width(); const float height = isNull ? FLT_MAX : constraint.height(); m_doublePropertyManager->setRange(m_propertyToX[property], left, right); m_doublePropertyManager->setRange(m_propertyToY[property], top, bottom); m_doublePropertyManager->setRange(m_propertyToW[property], 0, width); m_doublePropertyManager->setRange(m_propertyToH[property], 0, height); m_doublePropertyManager->setValue(m_propertyToX[property], val.x()); m_doublePropertyManager->setValue(m_propertyToY[property], val.y()); m_doublePropertyManager->setValue(m_propertyToW[property], val.width()); m_doublePropertyManager->setValue(m_propertyToH[property], val.height()); } /*! \class QtRectFPropertyManager \brief The QtRectFPropertyManager provides and manages QRectF properties. A rectangle property has nested \e x, \e y, \e width and \e height subproperties. The top-level property's value can be retrieved using the value() function, and set using the setValue() slot. The subproperties are created by a QtDoublePropertyManager object. This manager can be retrieved using the subDoublePropertyManager() function. In order to provide editing widgets for the subproperties in a property browser widget, this manager must be associated with an editor factory. A rectangle property also has a constraint rectangle which can be retrieved using the constraint() function, and set using the setConstraint() slot. In addition, QtRectFPropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes, and the constraintChanged() signal which is emitted whenever such a property changes its constraint rectangle. \sa QtAbstractPropertyManager, QtDoublePropertyManager, QtRectPropertyManager */ /*! \fn void QtRectFPropertyManager::valueChanged(QtProperty *property, const QRectF &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! \fn void QtRectFPropertyManager::constraintChanged(QtProperty *property, const QRectF &constraint) This signal is emitted whenever property changes its constraint rectangle, passing a pointer to the \a property and the new \a constraint rectangle as parameters. \sa setConstraint() */ /*! \fn void QtRectFPropertyManager::decimalsChanged(QtProperty *property, int prec) This signal is emitted whenever a property created by this manager changes its precision of value, passing a pointer to the \a property and the new \a prec value \sa setDecimals() */ /*! Creates a manager with the given \a parent. */ QtRectFPropertyManager::QtRectFPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtRectFPropertyManagerPrivate; d_ptr->q_ptr = this; d_ptr->m_doublePropertyManager = new QtDoublePropertyManager(this); connect(d_ptr->m_doublePropertyManager, SIGNAL(valueChanged(QtProperty *, double)), this, SLOT(slotDoubleChanged(QtProperty *, double))); connect(d_ptr->m_doublePropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), this, SLOT(slotPropertyDestroyed(QtProperty *))); } /*! Destroys this manager, and all the properties it has created. */ QtRectFPropertyManager::~QtRectFPropertyManager() { clear(); delete d_ptr; } /*! Returns the manager that creates the nested \e x, \e y, \e width and \e height subproperties. In order to provide editing widgets for the mentioned subproperties in a property browser widget, this manager must be associated with an editor factory. \sa QtAbstractPropertyBrowser::setFactoryForManager() */ QtDoublePropertyManager *QtRectFPropertyManager::subDoublePropertyManager() const { return d_ptr->m_doublePropertyManager; } /*! Returns the given \a property's value. If the given \a property is not managed by this manager, this function returns an invalid rectangle. \sa setValue(), constraint() */ QRectF QtRectFPropertyManager::value(const QtProperty *property) const { return getValue(d_ptr->m_values, property); } /*! Returns the given \a property's precision, in decimals. \sa setDecimals() */ int QtRectFPropertyManager::decimals(const QtProperty *property) const { return getData(d_ptr->m_values, &QtRectFPropertyManagerPrivate::Data::decimals, property, 0); } /*! Returns the given \a property's constraining rectangle. If returned value is null QRectF it means there is no constraint applied. \sa value(), setConstraint() */ QRectF QtRectFPropertyManager::constraint(const QtProperty *property) const { return getData(d_ptr->m_values, &QtRectFPropertyManagerPrivate::Data::constraint, property, QRect()); } /*! \reimp */ QString QtRectFPropertyManager::valueText(const QtProperty *property) const { const QtRectFPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); const QRectF v = it.value().val; const int dec = it.value().decimals; return QString(tr("[(%1, %2), %3 x %4]").arg(QString::number(v.x(), 'f', dec)) .arg(QString::number(v.y(), 'f', dec)) .arg(QString::number(v.width(), 'f', dec)) .arg(QString::number(v.height(), 'f', dec))); } /*! \fn void QtRectFPropertyManager::setValue(QtProperty *property, const QRectF &value) Sets the value of the given \a property to \a value. Nested properties are updated automatically. If the specified \a value is not inside the given \a property's constraining rectangle, the value is adjusted accordingly to fit within the constraint. \sa value(), setConstraint(), valueChanged() */ void QtRectFPropertyManager::setValue(QtProperty *property, const QRectF &val) { const QtRectFPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtRectFPropertyManagerPrivate::Data data = it.value(); QRectF newRect = val.normalized(); if (!data.constraint.isNull() && !data.constraint.contains(newRect)) { const QRectF r1 = data.constraint; const QRectF r2 = newRect; newRect.setLeft(qMax(r1.left(), r2.left())); newRect.setRight(qMin(r1.right(), r2.right())); newRect.setTop(qMax(r1.top(), r2.top())); newRect.setBottom(qMin(r1.bottom(), r2.bottom())); if (newRect.width() < 0 || newRect.height() < 0) return; } if (data.val == newRect) return; data.val = newRect; it.value() = data; d_ptr->m_doublePropertyManager->setValue(d_ptr->m_propertyToX[property], newRect.x()); d_ptr->m_doublePropertyManager->setValue(d_ptr->m_propertyToY[property], newRect.y()); d_ptr->m_doublePropertyManager->setValue(d_ptr->m_propertyToW[property], newRect.width()); d_ptr->m_doublePropertyManager->setValue(d_ptr->m_propertyToH[property], newRect.height()); emit propertyChanged(property); emit valueChanged(property, data.val); } /*! Sets the given \a property's constraining rectangle to \a constraint. When setting the constraint, the current value is adjusted if necessary (ensuring that the current rectangle value is inside the constraint). In order to reset the constraint pass a null QRectF value. \sa setValue(), constraint(), constraintChanged() */ void QtRectFPropertyManager::setConstraint(QtProperty *property, const QRectF &constraint) { const QtRectFPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtRectFPropertyManagerPrivate::Data data = it.value(); QRectF newConstraint = constraint.normalized(); if (data.constraint == newConstraint) return; const QRectF oldVal = data.val; data.constraint = newConstraint; if (!data.constraint.isNull() && !data.constraint.contains(oldVal)) { QRectF r1 = data.constraint; QRectF r2 = data.val; if (r2.width() > r1.width()) r2.setWidth(r1.width()); if (r2.height() > r1.height()) r2.setHeight(r1.height()); if (r2.left() < r1.left()) r2.moveLeft(r1.left()); else if (r2.right() > r1.right()) r2.moveRight(r1.right()); if (r2.top() < r1.top()) r2.moveTop(r1.top()); else if (r2.bottom() > r1.bottom()) r2.moveBottom(r1.bottom()); data.val = r2; } it.value() = data; emit constraintChanged(property, data.constraint); d_ptr->setConstraint(property, data.constraint, data.val); if (data.val == oldVal) return; emit propertyChanged(property); emit valueChanged(property, data.val); } /*! \fn void QtRectFPropertyManager::setDecimals(QtProperty *property, int prec) Sets the precision of the given \a property to \a prec. The valid decimal range is 0-13. The default is 2. \sa decimals() */ void QtRectFPropertyManager::setDecimals(QtProperty *property, int prec) { const QtRectFPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtRectFPropertyManagerPrivate::Data data = it.value(); if (prec > 13) prec = 13; else if (prec < 0) prec = 0; if (data.decimals == prec) return; data.decimals = prec; d_ptr->m_doublePropertyManager->setDecimals(d_ptr->m_propertyToX[property], prec); d_ptr->m_doublePropertyManager->setDecimals(d_ptr->m_propertyToY[property], prec); d_ptr->m_doublePropertyManager->setDecimals(d_ptr->m_propertyToW[property], prec); d_ptr->m_doublePropertyManager->setDecimals(d_ptr->m_propertyToH[property], prec); it.value() = data; emit decimalsChanged(property, data.decimals); } /*! \reimp */ void QtRectFPropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QtRectFPropertyManagerPrivate::Data(); QtProperty *xProp = d_ptr->m_doublePropertyManager->addProperty(); xProp->setPropertyName(tr("X")); d_ptr->m_doublePropertyManager->setDecimals(xProp, decimals(property)); d_ptr->m_doublePropertyManager->setValue(xProp, 0); d_ptr->m_propertyToX[property] = xProp; d_ptr->m_xToProperty[xProp] = property; property->addSubProperty(xProp); QtProperty *yProp = d_ptr->m_doublePropertyManager->addProperty(); yProp->setPropertyName(tr("Y")); d_ptr->m_doublePropertyManager->setDecimals(yProp, decimals(property)); d_ptr->m_doublePropertyManager->setValue(yProp, 0); d_ptr->m_propertyToY[property] = yProp; d_ptr->m_yToProperty[yProp] = property; property->addSubProperty(yProp); QtProperty *wProp = d_ptr->m_doublePropertyManager->addProperty(); wProp->setPropertyName(tr("Width")); d_ptr->m_doublePropertyManager->setDecimals(wProp, decimals(property)); d_ptr->m_doublePropertyManager->setValue(wProp, 0); d_ptr->m_doublePropertyManager->setMinimum(wProp, 0); d_ptr->m_propertyToW[property] = wProp; d_ptr->m_wToProperty[wProp] = property; property->addSubProperty(wProp); QtProperty *hProp = d_ptr->m_doublePropertyManager->addProperty(); hProp->setPropertyName(tr("Height")); d_ptr->m_doublePropertyManager->setDecimals(hProp, decimals(property)); d_ptr->m_doublePropertyManager->setValue(hProp, 0); d_ptr->m_doublePropertyManager->setMinimum(hProp, 0); d_ptr->m_propertyToH[property] = hProp; d_ptr->m_hToProperty[hProp] = property; property->addSubProperty(hProp); } /*! \reimp */ void QtRectFPropertyManager::uninitializeProperty(QtProperty *property) { QtProperty *xProp = d_ptr->m_propertyToX[property]; if (xProp) { d_ptr->m_xToProperty.remove(xProp); delete xProp; } d_ptr->m_propertyToX.remove(property); QtProperty *yProp = d_ptr->m_propertyToY[property]; if (yProp) { d_ptr->m_yToProperty.remove(yProp); delete yProp; } d_ptr->m_propertyToY.remove(property); QtProperty *wProp = d_ptr->m_propertyToW[property]; if (wProp) { d_ptr->m_wToProperty.remove(wProp); delete wProp; } d_ptr->m_propertyToW.remove(property); QtProperty *hProp = d_ptr->m_propertyToH[property]; if (hProp) { d_ptr->m_hToProperty.remove(hProp); delete hProp; } d_ptr->m_propertyToH.remove(property); d_ptr->m_values.remove(property); } // QtEnumPropertyManager class QtEnumPropertyManagerPrivate { QtEnumPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtEnumPropertyManager) public: struct Data { Data() : val(-1) {} int val; QStringList enumNames; QMap enumIcons; }; typedef QMap PropertyValueMap; PropertyValueMap m_values; }; /*! \class QtEnumPropertyManager \brief The QtEnumPropertyManager provides and manages enum properties. Each enum property has an associated list of enum names which can be retrieved using the enumNames() function, and set using the corresponding setEnumNames() function. An enum property's value is represented by an index in this list, and can be retrieved and set using the value() and setValue() slots respectively. Each enum value can also have an associated icon. The mapping from values to icons can be set using the setEnumIcons() function and queried with the enumIcons() function. In addition, QtEnumPropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes. The enumNamesChanged() or enumIconsChanged() signal is emitted whenever the list of enum names or icons is altered. \sa QtAbstractPropertyManager, QtEnumEditorFactory */ /*! \fn void QtEnumPropertyManager::valueChanged(QtProperty *property, int value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! \fn void QtEnumPropertyManager::enumNamesChanged(QtProperty *property, const QStringList &names) This signal is emitted whenever a property created by this manager changes its enum names, passing a pointer to the \a property and the new \a names as parameters. \sa setEnumNames() */ /*! \fn void QtEnumPropertyManager::enumIconsChanged(QtProperty *property, const QMap &icons) This signal is emitted whenever a property created by this manager changes its enum icons, passing a pointer to the \a property and the new mapping of values to \a icons as parameters. \sa setEnumIcons() */ /*! Creates a manager with the given \a parent. */ QtEnumPropertyManager::QtEnumPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtEnumPropertyManagerPrivate; d_ptr->q_ptr = this; } /*! Destroys this manager, and all the properties it has created. */ QtEnumPropertyManager::~QtEnumPropertyManager() { clear(); delete d_ptr; } /*! Returns the given \a property's value which is an index in the list returned by enumNames() If the given property is not managed by this manager, this function returns -1. \sa enumNames(), setValue() */ int QtEnumPropertyManager::value(const QtProperty *property) const { return getValue(d_ptr->m_values, property, -1); } /*! Returns the given \a property's list of enum names. \sa value(), setEnumNames() */ QStringList QtEnumPropertyManager::enumNames(const QtProperty *property) const { return getData(d_ptr->m_values, &QtEnumPropertyManagerPrivate::Data::enumNames, property, QStringList()); } /*! Returns the given \a property's map of enum values to their icons. \sa value(), setEnumIcons() */ QMap QtEnumPropertyManager::enumIcons(const QtProperty *property) const { return getData >(d_ptr->m_values, &QtEnumPropertyManagerPrivate::Data::enumIcons, property, QMap()); } /*! \reimp */ QString QtEnumPropertyManager::valueText(const QtProperty *property) const { const QtEnumPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); const QtEnumPropertyManagerPrivate::Data &data = it.value(); const int v = data.val; if (v >= 0 && v < data.enumNames.count()) return data.enumNames.at(v); return QString(); } /*! \reimp */ QIcon QtEnumPropertyManager::valueIcon(const QtProperty *property) const { const QtEnumPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QIcon(); const QtEnumPropertyManagerPrivate::Data &data = it.value(); const int v = data.val; return data.enumIcons.value(v); } /*! \fn void QtEnumPropertyManager::setValue(QtProperty *property, int value) Sets the value of the given \a property to \a value. The specified \a value must be less than the size of the given \a property's enumNames() list, and larger than (or equal to) 0. \sa value(), valueChanged() */ void QtEnumPropertyManager::setValue(QtProperty *property, int val) { const QtEnumPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtEnumPropertyManagerPrivate::Data data = it.value(); if (val >= data.enumNames.count()) return; if (val < 0 && data.enumNames.count() > 0) return; if (val < 0) val = -1; if (data.val == val) return; data.val = val; it.value() = data; emit propertyChanged(property); emit valueChanged(property, data.val); } /*! Sets the given \a property's list of enum names to \a enumNames. The \a property's current value is reset to 0 indicating the first item of the list. If the specified \a enumNames list is empty, the \a property's current value is set to -1. \sa enumNames(), enumNamesChanged() */ void QtEnumPropertyManager::setEnumNames(QtProperty *property, const QStringList &enumNames) { const QtEnumPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtEnumPropertyManagerPrivate::Data data = it.value(); if (data.enumNames == enumNames) return; data.enumNames = enumNames; data.val = -1; if (enumNames.count() > 0) data.val = 0; it.value() = data; emit enumNamesChanged(property, data.enumNames); emit propertyChanged(property); emit valueChanged(property, data.val); } /*! Sets the given \a property's map of enum values to their icons to \a enumIcons. Each enum value can have associated icon. This association is represented with passed \a enumIcons map. \sa enumNames(), enumNamesChanged() */ void QtEnumPropertyManager::setEnumIcons(QtProperty *property, const QMap &enumIcons) { const QtEnumPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; it.value().enumIcons = enumIcons; emit enumIconsChanged(property, it.value().enumIcons); emit propertyChanged(property); } /*! \reimp */ void QtEnumPropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QtEnumPropertyManagerPrivate::Data(); } /*! \reimp */ void QtEnumPropertyManager::uninitializeProperty(QtProperty *property) { d_ptr->m_values.remove(property); } // QtFlagPropertyManager class QtFlagPropertyManagerPrivate { QtFlagPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtFlagPropertyManager) public: void slotBoolChanged(QtProperty *property, bool value); void slotPropertyDestroyed(QtProperty *property); struct Data { Data() : val(-1) {} int val; QStringList flagNames; }; typedef QMap PropertyValueMap; PropertyValueMap m_values; QtBoolPropertyManager *m_boolPropertyManager; QMap > m_propertyToFlags; QMap m_flagToProperty; }; void QtFlagPropertyManagerPrivate::slotBoolChanged(QtProperty *property, bool value) { QtProperty *prop = m_flagToProperty.value(property, 0); if (prop == 0) return; QListIterator itProp(m_propertyToFlags[prop]); int level = 0; while (itProp.hasNext()) { QtProperty *p = itProp.next(); if (p == property) { int v = m_values[prop].val; if (value) { v |= (1 << level); } else { v &= ~(1 << level); } q_ptr->setValue(prop, v); return; } level++; } } void QtFlagPropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) { QtProperty *flagProperty = m_flagToProperty.value(property, 0); if (flagProperty == 0) return; m_propertyToFlags[flagProperty].replace(m_propertyToFlags[flagProperty].indexOf(property), 0); m_flagToProperty.remove(property); } /*! \class QtFlagPropertyManager \brief The QtFlagPropertyManager provides and manages flag properties. Each flag property has an associated list of flag names which can be retrieved using the flagNames() function, and set using the corresponding setFlagNames() function. The flag manager provides properties with nested boolean subproperties representing each flag, i.e. a flag property's value is the binary combination of the subproperties' values. A property's value can be retrieved and set using the value() and setValue() slots respectively. The combination of flags is represented by single int value - that's why it's possible to store up to 32 independent flags in one flag property. The subproperties are created by a QtBoolPropertyManager object. This manager can be retrieved using the subBoolPropertyManager() function. In order to provide editing widgets for the subproperties in a property browser widget, this manager must be associated with an editor factory. In addition, QtFlagPropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes, and the flagNamesChanged() signal which is emitted whenever the list of flag names is altered. \sa QtAbstractPropertyManager, QtBoolPropertyManager */ /*! \fn void QtFlagPropertyManager::valueChanged(QtProperty *property, int value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! \fn void QtFlagPropertyManager::flagNamesChanged(QtProperty *property, const QStringList &names) This signal is emitted whenever a property created by this manager changes its flag names, passing a pointer to the \a property and the new \a names as parameters. \sa setFlagNames() */ /*! Creates a manager with the given \a parent. */ QtFlagPropertyManager::QtFlagPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtFlagPropertyManagerPrivate; d_ptr->q_ptr = this; d_ptr->m_boolPropertyManager = new QtBoolPropertyManager(this); connect(d_ptr->m_boolPropertyManager, SIGNAL(valueChanged(QtProperty *, bool)), this, SLOT(slotBoolChanged(QtProperty *, bool))); connect(d_ptr->m_boolPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), this, SLOT(slotPropertyDestroyed(QtProperty *))); } /*! Destroys this manager, and all the properties it has created. */ QtFlagPropertyManager::~QtFlagPropertyManager() { clear(); delete d_ptr; } /*! Returns the manager that produces the nested boolean subproperties representing each flag. In order to provide editing widgets for the subproperties in a property browser widget, this manager must be associated with an editor factory. \sa QtAbstractPropertyBrowser::setFactoryForManager() */ QtBoolPropertyManager *QtFlagPropertyManager::subBoolPropertyManager() const { return d_ptr->m_boolPropertyManager; } /*! Returns the given \a property's value. If the given property is not managed by this manager, this function returns 0. \sa flagNames(), setValue() */ int QtFlagPropertyManager::value(const QtProperty *property) const { return getValue(d_ptr->m_values, property, 0); } /*! Returns the given \a property's list of flag names. \sa value(), setFlagNames() */ QStringList QtFlagPropertyManager::flagNames(const QtProperty *property) const { return getData(d_ptr->m_values, &QtFlagPropertyManagerPrivate::Data::flagNames, property, QStringList()); } /*! \reimp */ QString QtFlagPropertyManager::valueText(const QtProperty *property) const { const QtFlagPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); const QtFlagPropertyManagerPrivate::Data &data = it.value(); QString str; int level = 0; const QChar bar = QLatin1Char('|'); const QStringList::const_iterator fncend = data.flagNames.constEnd(); for (QStringList::const_iterator it = data.flagNames.constBegin(); it != fncend; ++it) { if (data.val & (1 << level)) { if (!str.isEmpty()) str += bar; str += *it; } level++; } return str; } /*! \fn void QtFlagPropertyManager::setValue(QtProperty *property, int value) Sets the value of the given \a property to \a value. Nested properties are updated automatically. The specified \a value must be less than the binary combination of the property's flagNames() list size (i.e. less than 2\sup n, where \c n is the size of the list) and larger than (or equal to) 0. \sa value(), valueChanged() */ void QtFlagPropertyManager::setValue(QtProperty *property, int val) { const QtFlagPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtFlagPropertyManagerPrivate::Data data = it.value(); if (data.val == val) return; if (val > (1 << data.flagNames.count()) - 1) return; if (val < 0) return; data.val = val; it.value() = data; QListIterator itProp(d_ptr->m_propertyToFlags[property]); int level = 0; while (itProp.hasNext()) { QtProperty *prop = itProp.next(); if (prop) d_ptr->m_boolPropertyManager->setValue(prop, val & (1 << level)); level++; } emit propertyChanged(property); emit valueChanged(property, data.val); } /*! Sets the given \a property's list of flag names to \a flagNames. The property's current value is reset to 0 indicating the first item of the list. \sa flagNames(), flagNamesChanged() */ void QtFlagPropertyManager::setFlagNames(QtProperty *property, const QStringList &flagNames) { const QtFlagPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtFlagPropertyManagerPrivate::Data data = it.value(); if (data.flagNames == flagNames) return; data.flagNames = flagNames; data.val = 0; it.value() = data; QListIterator itProp(d_ptr->m_propertyToFlags[property]); while (itProp.hasNext()) { QtProperty *prop = itProp.next(); if (prop) { delete prop; d_ptr->m_flagToProperty.remove(prop); } } d_ptr->m_propertyToFlags[property].clear(); QStringListIterator itFlag(flagNames); while (itFlag.hasNext()) { const QString flagName = itFlag.next(); QtProperty *prop = d_ptr->m_boolPropertyManager->addProperty(); prop->setPropertyName(flagName); property->addSubProperty(prop); d_ptr->m_propertyToFlags[property].append(prop); d_ptr->m_flagToProperty[prop] = property; } emit flagNamesChanged(property, data.flagNames); emit propertyChanged(property); emit valueChanged(property, data.val); } /*! \reimp */ void QtFlagPropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QtFlagPropertyManagerPrivate::Data(); d_ptr->m_propertyToFlags[property] = QList(); } /*! \reimp */ void QtFlagPropertyManager::uninitializeProperty(QtProperty *property) { QListIterator itProp(d_ptr->m_propertyToFlags[property]); while (itProp.hasNext()) { QtProperty *prop = itProp.next(); if (prop) { delete prop; d_ptr->m_flagToProperty.remove(prop); } } d_ptr->m_propertyToFlags.remove(property); d_ptr->m_values.remove(property); } // QtSizePolicyPropertyManager class QtSizePolicyPropertyManagerPrivate { QtSizePolicyPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtSizePolicyPropertyManager) public: QtSizePolicyPropertyManagerPrivate(); void slotIntChanged(QtProperty *property, int value); void slotEnumChanged(QtProperty *property, int value); void slotPropertyDestroyed(QtProperty *property); typedef QMap PropertyValueMap; PropertyValueMap m_values; QtIntPropertyManager *m_intPropertyManager; QtEnumPropertyManager *m_enumPropertyManager; QMap m_propertyToHPolicy; QMap m_propertyToVPolicy; QMap m_propertyToHStretch; QMap m_propertyToVStretch; QMap m_hPolicyToProperty; QMap m_vPolicyToProperty; QMap m_hStretchToProperty; QMap m_vStretchToProperty; }; QtSizePolicyPropertyManagerPrivate::QtSizePolicyPropertyManagerPrivate() { } void QtSizePolicyPropertyManagerPrivate::slotIntChanged(QtProperty *property, int value) { if (QtProperty *prop = m_hStretchToProperty.value(property, 0)) { QSizePolicy sp = m_values[prop]; sp.setHorizontalStretch(value); q_ptr->setValue(prop, sp); } else if (QtProperty *prop = m_vStretchToProperty.value(property, 0)) { QSizePolicy sp = m_values[prop]; sp.setVerticalStretch(value); q_ptr->setValue(prop, sp); } } void QtSizePolicyPropertyManagerPrivate::slotEnumChanged(QtProperty *property, int value) { if (QtProperty *prop = m_hPolicyToProperty.value(property, 0)) { QSizePolicy sp = m_values[prop]; sp.setHorizontalPolicy(metaEnumProvider()->indexToSizePolicy(value)); q_ptr->setValue(prop, sp); } else if (QtProperty *prop = m_vPolicyToProperty.value(property, 0)) { QSizePolicy sp = m_values[prop]; sp.setVerticalPolicy(metaEnumProvider()->indexToSizePolicy(value)); q_ptr->setValue(prop, sp); } } void QtSizePolicyPropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) { if (QtProperty *pointProp = m_hStretchToProperty.value(property, 0)) { m_propertyToHStretch[pointProp] = 0; m_hStretchToProperty.remove(property); } else if (QtProperty *pointProp = m_vStretchToProperty.value(property, 0)) { m_propertyToVStretch[pointProp] = 0; m_vStretchToProperty.remove(property); } else if (QtProperty *pointProp = m_hPolicyToProperty.value(property, 0)) { m_propertyToHPolicy[pointProp] = 0; m_hPolicyToProperty.remove(property); } else if (QtProperty *pointProp = m_vPolicyToProperty.value(property, 0)) { m_propertyToVPolicy[pointProp] = 0; m_vPolicyToProperty.remove(property); } } /*! \class QtSizePolicyPropertyManager \brief The QtSizePolicyPropertyManager provides and manages QSizePolicy properties. A size policy property has nested \e horizontalPolicy, \e verticalPolicy, \e horizontalStretch and \e verticalStretch subproperties. The top-level property's value can be retrieved using the value() function, and set using the setValue() slot. The subproperties are created by QtIntPropertyManager and QtEnumPropertyManager objects. These managers can be retrieved using the subIntPropertyManager() and subEnumPropertyManager() functions respectively. In order to provide editing widgets for the subproperties in a property browser widget, these managers must be associated with editor factories. In addition, QtSizePolicyPropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes. \sa QtAbstractPropertyManager, QtIntPropertyManager, QtEnumPropertyManager */ /*! \fn void QtSizePolicyPropertyManager::valueChanged(QtProperty *property, const QSizePolicy &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! Creates a manager with the given \a parent. */ QtSizePolicyPropertyManager::QtSizePolicyPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtSizePolicyPropertyManagerPrivate; d_ptr->q_ptr = this; d_ptr->m_intPropertyManager = new QtIntPropertyManager(this); connect(d_ptr->m_intPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotIntChanged(QtProperty *, int))); d_ptr->m_enumPropertyManager = new QtEnumPropertyManager(this); connect(d_ptr->m_enumPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotEnumChanged(QtProperty *, int))); connect(d_ptr->m_intPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), this, SLOT(slotPropertyDestroyed(QtProperty *))); connect(d_ptr->m_enumPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), this, SLOT(slotPropertyDestroyed(QtProperty *))); } /*! Destroys this manager, and all the properties it has created. */ QtSizePolicyPropertyManager::~QtSizePolicyPropertyManager() { clear(); delete d_ptr; } /*! Returns the manager that creates the nested \e horizontalStretch and \e verticalStretch subproperties. In order to provide editing widgets for the mentioned subproperties in a property browser widget, this manager must be associated with an editor factory. \sa QtAbstractPropertyBrowser::setFactoryForManager() */ QtIntPropertyManager *QtSizePolicyPropertyManager::subIntPropertyManager() const { return d_ptr->m_intPropertyManager; } /*! Returns the manager that creates the nested \e horizontalPolicy and \e verticalPolicy subproperties. In order to provide editing widgets for the mentioned subproperties in a property browser widget, this manager must be associated with an editor factory. \sa QtAbstractPropertyBrowser::setFactoryForManager() */ QtEnumPropertyManager *QtSizePolicyPropertyManager::subEnumPropertyManager() const { return d_ptr->m_enumPropertyManager; } /*! Returns the given \a property's value. If the given property is not managed by this manager, this function returns the default size policy. \sa setValue() */ QSizePolicy QtSizePolicyPropertyManager::value(const QtProperty *property) const { return d_ptr->m_values.value(property, QSizePolicy()); } /*! \reimp */ QString QtSizePolicyPropertyManager::valueText(const QtProperty *property) const { const QtSizePolicyPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); const QSizePolicy sp = it.value(); const QtMetaEnumProvider *mep = metaEnumProvider(); const int hIndex = mep->sizePolicyToIndex(sp.horizontalPolicy()); const int vIndex = mep->sizePolicyToIndex(sp.verticalPolicy()); //! Unknown size policy on reading invalid uic3 files const QString hPolicy = hIndex != -1 ? mep->policyEnumNames().at(hIndex) : tr(""); const QString vPolicy = vIndex != -1 ? mep->policyEnumNames().at(vIndex) : tr(""); const QString str = tr("[%1, %2, %3, %4]").arg(hPolicy, vPolicy).arg(sp.horizontalStretch()).arg(sp.verticalStretch()); return str; } /*! \fn void QtSizePolicyPropertyManager::setValue(QtProperty *property, const QSizePolicy &value) Sets the value of the given \a property to \a value. Nested properties are updated automatically. \sa value(), valueChanged() */ void QtSizePolicyPropertyManager::setValue(QtProperty *property, const QSizePolicy &val) { const QtSizePolicyPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; if (it.value() == val) return; it.value() = val; d_ptr->m_enumPropertyManager->setValue(d_ptr->m_propertyToHPolicy[property], metaEnumProvider()->sizePolicyToIndex(val.horizontalPolicy())); d_ptr->m_enumPropertyManager->setValue(d_ptr->m_propertyToVPolicy[property], metaEnumProvider()->sizePolicyToIndex(val.verticalPolicy())); d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToHStretch[property], val.horizontalStretch()); d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToVStretch[property], val.verticalStretch()); emit propertyChanged(property); emit valueChanged(property, val); } /*! \reimp */ void QtSizePolicyPropertyManager::initializeProperty(QtProperty *property) { QSizePolicy val; d_ptr->m_values[property] = val; QtProperty *hPolicyProp = d_ptr->m_enumPropertyManager->addProperty(); hPolicyProp->setPropertyName(tr("Horizontal Policy")); d_ptr->m_enumPropertyManager->setEnumNames(hPolicyProp, metaEnumProvider()->policyEnumNames()); d_ptr->m_enumPropertyManager->setValue(hPolicyProp, metaEnumProvider()->sizePolicyToIndex(val.horizontalPolicy())); d_ptr->m_propertyToHPolicy[property] = hPolicyProp; d_ptr->m_hPolicyToProperty[hPolicyProp] = property; property->addSubProperty(hPolicyProp); QtProperty *vPolicyProp = d_ptr->m_enumPropertyManager->addProperty(); vPolicyProp->setPropertyName(tr("Vertical Policy")); d_ptr->m_enumPropertyManager->setEnumNames(vPolicyProp, metaEnumProvider()->policyEnumNames()); d_ptr->m_enumPropertyManager->setValue(vPolicyProp, metaEnumProvider()->sizePolicyToIndex(val.verticalPolicy())); d_ptr->m_propertyToVPolicy[property] = vPolicyProp; d_ptr->m_vPolicyToProperty[vPolicyProp] = property; property->addSubProperty(vPolicyProp); QtProperty *hStretchProp = d_ptr->m_intPropertyManager->addProperty(); hStretchProp->setPropertyName(tr("Horizontal Stretch")); d_ptr->m_intPropertyManager->setValue(hStretchProp, val.horizontalStretch()); d_ptr->m_intPropertyManager->setRange(hStretchProp, 0, 0xff); d_ptr->m_propertyToHStretch[property] = hStretchProp; d_ptr->m_hStretchToProperty[hStretchProp] = property; property->addSubProperty(hStretchProp); QtProperty *vStretchProp = d_ptr->m_intPropertyManager->addProperty(); vStretchProp->setPropertyName(tr("Vertical Stretch")); d_ptr->m_intPropertyManager->setValue(vStretchProp, val.verticalStretch()); d_ptr->m_intPropertyManager->setRange(vStretchProp, 0, 0xff); d_ptr->m_propertyToVStretch[property] = vStretchProp; d_ptr->m_vStretchToProperty[vStretchProp] = property; property->addSubProperty(vStretchProp); } /*! \reimp */ void QtSizePolicyPropertyManager::uninitializeProperty(QtProperty *property) { QtProperty *hPolicyProp = d_ptr->m_propertyToHPolicy[property]; if (hPolicyProp) { d_ptr->m_hPolicyToProperty.remove(hPolicyProp); delete hPolicyProp; } d_ptr->m_propertyToHPolicy.remove(property); QtProperty *vPolicyProp = d_ptr->m_propertyToVPolicy[property]; if (vPolicyProp) { d_ptr->m_vPolicyToProperty.remove(vPolicyProp); delete vPolicyProp; } d_ptr->m_propertyToVPolicy.remove(property); QtProperty *hStretchProp = d_ptr->m_propertyToHStretch[property]; if (hStretchProp) { d_ptr->m_hStretchToProperty.remove(hStretchProp); delete hStretchProp; } d_ptr->m_propertyToHStretch.remove(property); QtProperty *vStretchProp = d_ptr->m_propertyToVStretch[property]; if (vStretchProp) { d_ptr->m_vStretchToProperty.remove(vStretchProp); delete vStretchProp; } d_ptr->m_propertyToVStretch.remove(property); d_ptr->m_values.remove(property); } // QtFontPropertyManager: // QtFontPropertyManagerPrivate has a mechanism for reacting // to QApplication::fontDatabaseChanged() [4.5], which is emitted // when someone loads an application font. The signals are compressed // using a timer with interval 0, which then causes the family // enumeration manager to re-set its strings and index values // for each property. Q_GLOBAL_STATIC(QFontDatabase, fontDatabase) class QtFontPropertyManagerPrivate { QtFontPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtFontPropertyManager) public: QtFontPropertyManagerPrivate(); void slotIntChanged(QtProperty *property, int value); void slotEnumChanged(QtProperty *property, int value); void slotBoolChanged(QtProperty *property, bool value); void slotPropertyDestroyed(QtProperty *property); void slotFontDatabaseChanged(); void slotFontDatabaseDelayedChange(); QStringList m_familyNames; typedef QMap PropertyValueMap; PropertyValueMap m_values; QtIntPropertyManager *m_intPropertyManager; QtEnumPropertyManager *m_enumPropertyManager; QtBoolPropertyManager *m_boolPropertyManager; QMap m_propertyToFamily; QMap m_propertyToPointSize; QMap m_propertyToBold; QMap m_propertyToItalic; QMap m_propertyToUnderline; QMap m_propertyToStrikeOut; QMap m_propertyToKerning; QMap m_familyToProperty; QMap m_pointSizeToProperty; QMap m_boldToProperty; QMap m_italicToProperty; QMap m_underlineToProperty; QMap m_strikeOutToProperty; QMap m_kerningToProperty; bool m_settingValue; QTimer *m_fontDatabaseChangeTimer; }; QtFontPropertyManagerPrivate::QtFontPropertyManagerPrivate() : m_settingValue(false), m_fontDatabaseChangeTimer(0) { } void QtFontPropertyManagerPrivate::slotIntChanged(QtProperty *property, int value) { if (m_settingValue) return; if (QtProperty *prop = m_pointSizeToProperty.value(property, 0)) { QFont f = m_values[prop]; f.setPointSize(value); q_ptr->setValue(prop, f); } } void QtFontPropertyManagerPrivate::slotEnumChanged(QtProperty *property, int value) { if (m_settingValue) return; if (QtProperty *prop = m_familyToProperty.value(property, 0)) { QFont f = m_values[prop]; f.setFamily(m_familyNames.at(value)); q_ptr->setValue(prop, f); } } void QtFontPropertyManagerPrivate::slotBoolChanged(QtProperty *property, bool value) { if (m_settingValue) return; if (QtProperty *prop = m_boldToProperty.value(property, 0)) { QFont f = m_values[prop]; f.setBold(value); q_ptr->setValue(prop, f); } else if (QtProperty *prop = m_italicToProperty.value(property, 0)) { QFont f = m_values[prop]; f.setItalic(value); q_ptr->setValue(prop, f); } else if (QtProperty *prop = m_underlineToProperty.value(property, 0)) { QFont f = m_values[prop]; f.setUnderline(value); q_ptr->setValue(prop, f); } else if (QtProperty *prop = m_strikeOutToProperty.value(property, 0)) { QFont f = m_values[prop]; f.setStrikeOut(value); q_ptr->setValue(prop, f); } else if (QtProperty *prop = m_kerningToProperty.value(property, 0)) { QFont f = m_values[prop]; f.setKerning(value); q_ptr->setValue(prop, f); } } void QtFontPropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) { if (QtProperty *pointProp = m_pointSizeToProperty.value(property, 0)) { m_propertyToPointSize[pointProp] = 0; m_pointSizeToProperty.remove(property); } else if (QtProperty *pointProp = m_familyToProperty.value(property, 0)) { m_propertyToFamily[pointProp] = 0; m_familyToProperty.remove(property); } else if (QtProperty *pointProp = m_boldToProperty.value(property, 0)) { m_propertyToBold[pointProp] = 0; m_boldToProperty.remove(property); } else if (QtProperty *pointProp = m_italicToProperty.value(property, 0)) { m_propertyToItalic[pointProp] = 0; m_italicToProperty.remove(property); } else if (QtProperty *pointProp = m_underlineToProperty.value(property, 0)) { m_propertyToUnderline[pointProp] = 0; m_underlineToProperty.remove(property); } else if (QtProperty *pointProp = m_strikeOutToProperty.value(property, 0)) { m_propertyToStrikeOut[pointProp] = 0; m_strikeOutToProperty.remove(property); } else if (QtProperty *pointProp = m_kerningToProperty.value(property, 0)) { m_propertyToKerning[pointProp] = 0; m_kerningToProperty.remove(property); } } void QtFontPropertyManagerPrivate::slotFontDatabaseChanged() { if (!m_fontDatabaseChangeTimer) { m_fontDatabaseChangeTimer = new QTimer(q_ptr); m_fontDatabaseChangeTimer->setInterval(0); m_fontDatabaseChangeTimer->setSingleShot(true); QObject::connect(m_fontDatabaseChangeTimer, SIGNAL(timeout()), q_ptr, SLOT(slotFontDatabaseDelayedChange())); } if (!m_fontDatabaseChangeTimer->isActive()) m_fontDatabaseChangeTimer->start(); } void QtFontPropertyManagerPrivate::slotFontDatabaseDelayedChange() { typedef QMap PropertyPropertyMap; // rescan available font names const QStringList oldFamilies = m_familyNames; m_familyNames = fontDatabase()->families(); // Adapt all existing properties if (!m_propertyToFamily.empty()) { PropertyPropertyMap::const_iterator cend = m_propertyToFamily.constEnd(); for (PropertyPropertyMap::const_iterator it = m_propertyToFamily.constBegin(); it != cend; ++it) { QtProperty *familyProp = it.value(); const int oldIdx = m_enumPropertyManager->value(familyProp); int newIdx = m_familyNames.indexOf(oldFamilies.at(oldIdx)); if (newIdx < 0) newIdx = 0; m_enumPropertyManager->setEnumNames(familyProp, m_familyNames); m_enumPropertyManager->setValue(familyProp, newIdx); } } } /*! \class QtFontPropertyManager \brief The QtFontPropertyManager provides and manages QFont properties. A font property has nested \e family, \e pointSize, \e bold, \e italic, \e underline, \e strikeOut and \e kerning subproperties. The top-level property's value can be retrieved using the value() function, and set using the setValue() slot. The subproperties are created by QtIntPropertyManager, QtEnumPropertyManager and QtBoolPropertyManager objects. These managers can be retrieved using the corresponding subIntPropertyManager(), subEnumPropertyManager() and subBoolPropertyManager() functions. In order to provide editing widgets for the subproperties in a property browser widget, these managers must be associated with editor factories. In addition, QtFontPropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes. \sa QtAbstractPropertyManager, QtEnumPropertyManager, QtIntPropertyManager, QtBoolPropertyManager */ /*! \fn void QtFontPropertyManager::valueChanged(QtProperty *property, const QFont &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! Creates a manager with the given \a parent. */ QtFontPropertyManager::QtFontPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtFontPropertyManagerPrivate; d_ptr->q_ptr = this; #if QT_VERSION >= 0x040500 QObject::connect(qApp, SIGNAL(fontDatabaseChanged()), this, SLOT(slotFontDatabaseChanged())); #endif d_ptr->m_intPropertyManager = new QtIntPropertyManager(this); connect(d_ptr->m_intPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotIntChanged(QtProperty *, int))); d_ptr->m_enumPropertyManager = new QtEnumPropertyManager(this); connect(d_ptr->m_enumPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotEnumChanged(QtProperty *, int))); d_ptr->m_boolPropertyManager = new QtBoolPropertyManager(this); connect(d_ptr->m_boolPropertyManager, SIGNAL(valueChanged(QtProperty *, bool)), this, SLOT(slotBoolChanged(QtProperty *, bool))); connect(d_ptr->m_intPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), this, SLOT(slotPropertyDestroyed(QtProperty *))); connect(d_ptr->m_enumPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), this, SLOT(slotPropertyDestroyed(QtProperty *))); connect(d_ptr->m_boolPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), this, SLOT(slotPropertyDestroyed(QtProperty *))); } /*! Destroys this manager, and all the properties it has created. */ QtFontPropertyManager::~QtFontPropertyManager() { clear(); delete d_ptr; } /*! Returns the manager that creates the \e pointSize subproperty. In order to provide editing widgets for the \e pointSize property in a property browser widget, this manager must be associated with an editor factory. \sa QtAbstractPropertyBrowser::setFactoryForManager() */ QtIntPropertyManager *QtFontPropertyManager::subIntPropertyManager() const { return d_ptr->m_intPropertyManager; } /*! Returns the manager that create the \e family subproperty. In order to provide editing widgets for the \e family property in a property browser widget, this manager must be associated with an editor factory. \sa QtAbstractPropertyBrowser::setFactoryForManager() */ QtEnumPropertyManager *QtFontPropertyManager::subEnumPropertyManager() const { return d_ptr->m_enumPropertyManager; } /*! Returns the manager that creates the \e bold, \e italic, \e underline, \e strikeOut and \e kerning subproperties. In order to provide editing widgets for the mentioned properties in a property browser widget, this manager must be associated with an editor factory. \sa QtAbstractPropertyBrowser::setFactoryForManager() */ QtBoolPropertyManager *QtFontPropertyManager::subBoolPropertyManager() const { return d_ptr->m_boolPropertyManager; } /*! Returns the given \a property's value. If the given property is not managed by this manager, this function returns a font object that uses the application's default font. \sa setValue() */ QFont QtFontPropertyManager::value(const QtProperty *property) const { return d_ptr->m_values.value(property, QFont()); } /*! \reimp */ QString QtFontPropertyManager::valueText(const QtProperty *property) const { const QtFontPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); return QtPropertyBrowserUtils::fontValueText(it.value()); } /*! \reimp */ QIcon QtFontPropertyManager::valueIcon(const QtProperty *property) const { const QtFontPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QIcon(); return QtPropertyBrowserUtils::fontValueIcon(it.value()); } /*! \fn void QtFontPropertyManager::setValue(QtProperty *property, const QFont &value) Sets the value of the given \a property to \a value. Nested properties are updated automatically. \sa value(), valueChanged() */ void QtFontPropertyManager::setValue(QtProperty *property, const QFont &val) { const QtFontPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; const QFont oldVal = it.value(); if (oldVal == val && oldVal.resolve() == val.resolve()) return; it.value() = val; int idx = d_ptr->m_familyNames.indexOf(val.family()); if (idx == -1) idx = 0; bool settingValue = d_ptr->m_settingValue; d_ptr->m_settingValue = true; d_ptr->m_enumPropertyManager->setValue(d_ptr->m_propertyToFamily[property], idx); d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToPointSize[property], val.pointSize()); d_ptr->m_boolPropertyManager->setValue(d_ptr->m_propertyToBold[property], val.bold()); d_ptr->m_boolPropertyManager->setValue(d_ptr->m_propertyToItalic[property], val.italic()); d_ptr->m_boolPropertyManager->setValue(d_ptr->m_propertyToUnderline[property], val.underline()); d_ptr->m_boolPropertyManager->setValue(d_ptr->m_propertyToStrikeOut[property], val.strikeOut()); d_ptr->m_boolPropertyManager->setValue(d_ptr->m_propertyToKerning[property], val.kerning()); d_ptr->m_settingValue = settingValue; emit propertyChanged(property); emit valueChanged(property, val); } /*! \reimp */ void QtFontPropertyManager::initializeProperty(QtProperty *property) { QFont val; d_ptr->m_values[property] = val; QtProperty *familyProp = d_ptr->m_enumPropertyManager->addProperty(); familyProp->setPropertyName(tr("Family")); if (d_ptr->m_familyNames.empty()) d_ptr->m_familyNames = fontDatabase()->families(); d_ptr->m_enumPropertyManager->setEnumNames(familyProp, d_ptr->m_familyNames); int idx = d_ptr->m_familyNames.indexOf(val.family()); if (idx == -1) idx = 0; d_ptr->m_enumPropertyManager->setValue(familyProp, idx); d_ptr->m_propertyToFamily[property] = familyProp; d_ptr->m_familyToProperty[familyProp] = property; property->addSubProperty(familyProp); QtProperty *pointSizeProp = d_ptr->m_intPropertyManager->addProperty(); pointSizeProp->setPropertyName(tr("Point Size")); d_ptr->m_intPropertyManager->setValue(pointSizeProp, val.pointSize()); d_ptr->m_intPropertyManager->setMinimum(pointSizeProp, 1); d_ptr->m_propertyToPointSize[property] = pointSizeProp; d_ptr->m_pointSizeToProperty[pointSizeProp] = property; property->addSubProperty(pointSizeProp); QtProperty *boldProp = d_ptr->m_boolPropertyManager->addProperty(); boldProp->setPropertyName(tr("Bold")); d_ptr->m_boolPropertyManager->setValue(boldProp, val.bold()); d_ptr->m_propertyToBold[property] = boldProp; d_ptr->m_boldToProperty[boldProp] = property; property->addSubProperty(boldProp); QtProperty *italicProp = d_ptr->m_boolPropertyManager->addProperty(); italicProp->setPropertyName(tr("Italic")); d_ptr->m_boolPropertyManager->setValue(italicProp, val.italic()); d_ptr->m_propertyToItalic[property] = italicProp; d_ptr->m_italicToProperty[italicProp] = property; property->addSubProperty(italicProp); QtProperty *underlineProp = d_ptr->m_boolPropertyManager->addProperty(); underlineProp->setPropertyName(tr("Underline")); d_ptr->m_boolPropertyManager->setValue(underlineProp, val.underline()); d_ptr->m_propertyToUnderline[property] = underlineProp; d_ptr->m_underlineToProperty[underlineProp] = property; property->addSubProperty(underlineProp); QtProperty *strikeOutProp = d_ptr->m_boolPropertyManager->addProperty(); strikeOutProp->setPropertyName(tr("Strikeout")); d_ptr->m_boolPropertyManager->setValue(strikeOutProp, val.strikeOut()); d_ptr->m_propertyToStrikeOut[property] = strikeOutProp; d_ptr->m_strikeOutToProperty[strikeOutProp] = property; property->addSubProperty(strikeOutProp); QtProperty *kerningProp = d_ptr->m_boolPropertyManager->addProperty(); kerningProp->setPropertyName(tr("Kerning")); d_ptr->m_boolPropertyManager->setValue(kerningProp, val.kerning()); d_ptr->m_propertyToKerning[property] = kerningProp; d_ptr->m_kerningToProperty[kerningProp] = property; property->addSubProperty(kerningProp); } /*! \reimp */ void QtFontPropertyManager::uninitializeProperty(QtProperty *property) { QtProperty *familyProp = d_ptr->m_propertyToFamily[property]; if (familyProp) { d_ptr->m_familyToProperty.remove(familyProp); delete familyProp; } d_ptr->m_propertyToFamily.remove(property); QtProperty *pointSizeProp = d_ptr->m_propertyToPointSize[property]; if (pointSizeProp) { d_ptr->m_pointSizeToProperty.remove(pointSizeProp); delete pointSizeProp; } d_ptr->m_propertyToPointSize.remove(property); QtProperty *boldProp = d_ptr->m_propertyToBold[property]; if (boldProp) { d_ptr->m_boldToProperty.remove(boldProp); delete boldProp; } d_ptr->m_propertyToBold.remove(property); QtProperty *italicProp = d_ptr->m_propertyToItalic[property]; if (italicProp) { d_ptr->m_italicToProperty.remove(italicProp); delete italicProp; } d_ptr->m_propertyToItalic.remove(property); QtProperty *underlineProp = d_ptr->m_propertyToUnderline[property]; if (underlineProp) { d_ptr->m_underlineToProperty.remove(underlineProp); delete underlineProp; } d_ptr->m_propertyToUnderline.remove(property); QtProperty *strikeOutProp = d_ptr->m_propertyToStrikeOut[property]; if (strikeOutProp) { d_ptr->m_strikeOutToProperty.remove(strikeOutProp); delete strikeOutProp; } d_ptr->m_propertyToStrikeOut.remove(property); QtProperty *kerningProp = d_ptr->m_propertyToKerning[property]; if (kerningProp) { d_ptr->m_kerningToProperty.remove(kerningProp); delete kerningProp; } d_ptr->m_propertyToKerning.remove(property); d_ptr->m_values.remove(property); } // QtColorPropertyManager class QtColorPropertyManagerPrivate { QtColorPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtColorPropertyManager) public: void slotIntChanged(QtProperty *property, int value); void slotPropertyDestroyed(QtProperty *property); typedef QMap PropertyValueMap; PropertyValueMap m_values; QtIntPropertyManager *m_intPropertyManager; QMap m_propertyToR; QMap m_propertyToG; QMap m_propertyToB; QMap m_propertyToA; QMap m_rToProperty; QMap m_gToProperty; QMap m_bToProperty; QMap m_aToProperty; }; void QtColorPropertyManagerPrivate::slotIntChanged(QtProperty *property, int value) { if (QtProperty *prop = m_rToProperty.value(property, 0)) { QColor c = m_values[prop]; c.setRed(value); q_ptr->setValue(prop, c); } else if (QtProperty *prop = m_gToProperty.value(property, 0)) { QColor c = m_values[prop]; c.setGreen(value); q_ptr->setValue(prop, c); } else if (QtProperty *prop = m_bToProperty.value(property, 0)) { QColor c = m_values[prop]; c.setBlue(value); q_ptr->setValue(prop, c); } else if (QtProperty *prop = m_aToProperty.value(property, 0)) { QColor c = m_values[prop]; c.setAlpha(value); q_ptr->setValue(prop, c); } } void QtColorPropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) { if (QtProperty *pointProp = m_rToProperty.value(property, 0)) { m_propertyToR[pointProp] = 0; m_rToProperty.remove(property); } else if (QtProperty *pointProp = m_gToProperty.value(property, 0)) { m_propertyToG[pointProp] = 0; m_gToProperty.remove(property); } else if (QtProperty *pointProp = m_bToProperty.value(property, 0)) { m_propertyToB[pointProp] = 0; m_bToProperty.remove(property); } else if (QtProperty *pointProp = m_aToProperty.value(property, 0)) { m_propertyToA[pointProp] = 0; m_aToProperty.remove(property); } } /*! \class QtColorPropertyManager \brief The QtColorPropertyManager provides and manages QColor properties. A color property has nested \e red, \e green and \e blue subproperties. The top-level property's value can be retrieved using the value() function, and set using the setValue() slot. The subproperties are created by a QtIntPropertyManager object. This manager can be retrieved using the subIntPropertyManager() function. In order to provide editing widgets for the subproperties in a property browser widget, this manager must be associated with an editor factory. In addition, QtColorPropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes. \sa QtAbstractPropertyManager, QtAbstractPropertyBrowser, QtIntPropertyManager */ /*! \fn void QtColorPropertyManager::valueChanged(QtProperty *property, const QColor &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! Creates a manager with the given \a parent. */ QtColorPropertyManager::QtColorPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtColorPropertyManagerPrivate; d_ptr->q_ptr = this; d_ptr->m_intPropertyManager = new QtIntPropertyManager(this); connect(d_ptr->m_intPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotIntChanged(QtProperty *, int))); connect(d_ptr->m_intPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), this, SLOT(slotPropertyDestroyed(QtProperty *))); } /*! Destroys this manager, and all the properties it has created. */ QtColorPropertyManager::~QtColorPropertyManager() { clear(); delete d_ptr; } /*! Returns the manager that produces the nested \e red, \e green and \e blue subproperties. In order to provide editing widgets for the subproperties in a property browser widget, this manager must be associated with an editor factory. \sa QtAbstractPropertyBrowser::setFactoryForManager() */ QtIntPropertyManager *QtColorPropertyManager::subIntPropertyManager() const { return d_ptr->m_intPropertyManager; } /*! Returns the given \a property's value. If the given \a property is not managed by \e this manager, this function returns an invalid color. \sa setValue() */ QColor QtColorPropertyManager::value(const QtProperty *property) const { return d_ptr->m_values.value(property, QColor()); } /*! \reimp */ QString QtColorPropertyManager::valueText(const QtProperty *property) const { const QtColorPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); return QtPropertyBrowserUtils::colorValueText(it.value()); } /*! \reimp */ QIcon QtColorPropertyManager::valueIcon(const QtProperty *property) const { const QtColorPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QIcon(); return QtPropertyBrowserUtils::brushValueIcon(QBrush(it.value())); } /*! \fn void QtColorPropertyManager::setValue(QtProperty *property, const QColor &value) Sets the value of the given \a property to \a value. Nested properties are updated automatically. \sa value(), valueChanged() */ void QtColorPropertyManager::setValue(QtProperty *property, const QColor &val) { const QtColorPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; if (it.value() == val) return; it.value() = val; d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToR[property], val.red()); d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToG[property], val.green()); d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToB[property], val.blue()); d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToA[property], val.alpha()); emit propertyChanged(property); emit valueChanged(property, val); } /*! \reimp */ void QtColorPropertyManager::initializeProperty(QtProperty *property) { QColor val; d_ptr->m_values[property] = val; QtProperty *rProp = d_ptr->m_intPropertyManager->addProperty(); rProp->setPropertyName(tr("Red")); d_ptr->m_intPropertyManager->setValue(rProp, val.red()); d_ptr->m_intPropertyManager->setRange(rProp, 0, 0xFF); d_ptr->m_propertyToR[property] = rProp; d_ptr->m_rToProperty[rProp] = property; property->addSubProperty(rProp); QtProperty *gProp = d_ptr->m_intPropertyManager->addProperty(); gProp->setPropertyName(tr("Green")); d_ptr->m_intPropertyManager->setValue(gProp, val.green()); d_ptr->m_intPropertyManager->setRange(gProp, 0, 0xFF); d_ptr->m_propertyToG[property] = gProp; d_ptr->m_gToProperty[gProp] = property; property->addSubProperty(gProp); QtProperty *bProp = d_ptr->m_intPropertyManager->addProperty(); bProp->setPropertyName(tr("Blue")); d_ptr->m_intPropertyManager->setValue(bProp, val.blue()); d_ptr->m_intPropertyManager->setRange(bProp, 0, 0xFF); d_ptr->m_propertyToB[property] = bProp; d_ptr->m_bToProperty[bProp] = property; property->addSubProperty(bProp); QtProperty *aProp = d_ptr->m_intPropertyManager->addProperty(); aProp->setPropertyName(tr("Alpha")); d_ptr->m_intPropertyManager->setValue(aProp, val.alpha()); d_ptr->m_intPropertyManager->setRange(aProp, 0, 0xFF); d_ptr->m_propertyToA[property] = aProp; d_ptr->m_aToProperty[aProp] = property; property->addSubProperty(aProp); } /*! \reimp */ void QtColorPropertyManager::uninitializeProperty(QtProperty *property) { QtProperty *rProp = d_ptr->m_propertyToR[property]; if (rProp) { d_ptr->m_rToProperty.remove(rProp); delete rProp; } d_ptr->m_propertyToR.remove(property); QtProperty *gProp = d_ptr->m_propertyToG[property]; if (gProp) { d_ptr->m_gToProperty.remove(gProp); delete gProp; } d_ptr->m_propertyToG.remove(property); QtProperty *bProp = d_ptr->m_propertyToB[property]; if (bProp) { d_ptr->m_bToProperty.remove(bProp); delete bProp; } d_ptr->m_propertyToB.remove(property); QtProperty *aProp = d_ptr->m_propertyToA[property]; if (aProp) { d_ptr->m_aToProperty.remove(aProp); delete aProp; } d_ptr->m_propertyToA.remove(property); d_ptr->m_values.remove(property); } // QtCursorPropertyManager Q_GLOBAL_STATIC(QtCursorDatabase, cursorDatabase) class QtCursorPropertyManagerPrivate { QtCursorPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtCursorPropertyManager) public: typedef QMap PropertyValueMap; PropertyValueMap m_values; }; /*! \class QtCursorPropertyManager \brief The QtCursorPropertyManager provides and manages QCursor properties. A cursor property has a current value which can be retrieved using the value() function, and set using the setValue() slot. In addition, QtCursorPropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes. \sa QtAbstractPropertyManager */ /*! \fn void QtCursorPropertyManager::valueChanged(QtProperty *property, const QCursor &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! Creates a manager with the given \a parent. */ QtCursorPropertyManager::QtCursorPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtCursorPropertyManagerPrivate; d_ptr->q_ptr = this; } /*! Destroys this manager, and all the properties it has created. */ QtCursorPropertyManager::~QtCursorPropertyManager() { clear(); delete d_ptr; } /*! Returns the given \a property's value. If the given \a property is not managed by this manager, this function returns a default QCursor object. \sa setValue() */ #ifndef QT_NO_CURSOR QCursor QtCursorPropertyManager::value(const QtProperty *property) const { return d_ptr->m_values.value(property, QCursor()); } #endif /*! \reimp */ QString QtCursorPropertyManager::valueText(const QtProperty *property) const { const QtCursorPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); return cursorDatabase()->cursorToShapeName(it.value()); } /*! \reimp */ QIcon QtCursorPropertyManager::valueIcon(const QtProperty *property) const { const QtCursorPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QIcon(); return cursorDatabase()->cursorToShapeIcon(it.value()); } /*! \fn void QtCursorPropertyManager::setValue(QtProperty *property, const QCursor &value) Sets the value of the given \a property to \a value. \sa value(), valueChanged() */ void QtCursorPropertyManager::setValue(QtProperty *property, const QCursor &value) { #ifndef QT_NO_CURSOR const QtCursorPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; if (it.value().shape() == value.shape() && value.shape() != Qt::BitmapCursor) return; it.value() = value; emit propertyChanged(property); emit valueChanged(property, value); #endif } /*! \reimp */ void QtCursorPropertyManager::initializeProperty(QtProperty *property) { #ifndef QT_NO_CURSOR d_ptr->m_values[property] = QCursor(); #endif } /*! \reimp */ void QtCursorPropertyManager::uninitializeProperty(QtProperty *property) { d_ptr->m_values.remove(property); } #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif #include "moc_qtpropertymanager.cpp" #include "qtpropertymanager.moc" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/qtpropertymanager.h000066400000000000000000000643021455373415500265640ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #ifndef QTPROPERTYMANAGER_H #define QTPROPERTYMANAGER_H #include "qtpropertybrowser.h" #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif class QDate; class QTime; class QDateTime; class QLocale; class QT_QTPROPERTYBROWSER_EXPORT QtGroupPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtGroupPropertyManager(QObject *parent = 0); ~QtGroupPropertyManager(); protected: virtual bool hasValue(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); }; class QtIntPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtIntPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtIntPropertyManager(QObject *parent = 0); ~QtIntPropertyManager(); int value(const QtProperty *property) const; int minimum(const QtProperty *property) const; int maximum(const QtProperty *property) const; int singleStep(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, int val); void setMinimum(QtProperty *property, int minVal); void setMaximum(QtProperty *property, int maxVal); void setRange(QtProperty *property, int minVal, int maxVal); void setSingleStep(QtProperty *property, int step); Q_SIGNALS: void valueChanged(QtProperty *property, int val); void rangeChanged(QtProperty *property, int minVal, int maxVal); void singleStepChanged(QtProperty *property, int step); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtIntPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtIntPropertyManager) Q_DISABLE_COPY(QtIntPropertyManager) }; class QtBoolPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtBoolPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtBoolPropertyManager(QObject *parent = 0); ~QtBoolPropertyManager(); bool value(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, bool val); Q_SIGNALS: void valueChanged(QtProperty *property, bool val); protected: QString valueText(const QtProperty *property) const; QIcon valueIcon(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtBoolPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtBoolPropertyManager) Q_DISABLE_COPY(QtBoolPropertyManager) }; class QtDoublePropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtDoublePropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtDoublePropertyManager(QObject *parent = 0); ~QtDoublePropertyManager(); double value(const QtProperty *property) const; double minimum(const QtProperty *property) const; double maximum(const QtProperty *property) const; double singleStep(const QtProperty *property) const; int decimals(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, double val); void setMinimum(QtProperty *property, double minVal); void setMaximum(QtProperty *property, double maxVal); void setRange(QtProperty *property, double minVal, double maxVal); void setSingleStep(QtProperty *property, double step); void setDecimals(QtProperty *property, int prec); Q_SIGNALS: void valueChanged(QtProperty *property, double val); void rangeChanged(QtProperty *property, double minVal, double maxVal); void singleStepChanged(QtProperty *property, double step); void decimalsChanged(QtProperty *property, int prec); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtDoublePropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtDoublePropertyManager) Q_DISABLE_COPY(QtDoublePropertyManager) }; class QtStringPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtStringPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtStringPropertyManager(QObject *parent = 0); ~QtStringPropertyManager(); QString value(const QtProperty *property) const; QRegExp regExp(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QString &val); void setRegExp(QtProperty *property, const QRegExp ®Exp); Q_SIGNALS: void valueChanged(QtProperty *property, const QString &val); void regExpChanged(QtProperty *property, const QRegExp ®Exp); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtStringPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtStringPropertyManager) Q_DISABLE_COPY(QtStringPropertyManager) }; class QtDatePropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtDatePropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtDatePropertyManager(QObject *parent = 0); ~QtDatePropertyManager(); QDate value(const QtProperty *property) const; QDate minimum(const QtProperty *property) const; QDate maximum(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QDate &val); void setMinimum(QtProperty *property, const QDate &minVal); void setMaximum(QtProperty *property, const QDate &maxVal); void setRange(QtProperty *property, const QDate &minVal, const QDate &maxVal); Q_SIGNALS: void valueChanged(QtProperty *property, const QDate &val); void rangeChanged(QtProperty *property, const QDate &minVal, const QDate &maxVal); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtDatePropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtDatePropertyManager) Q_DISABLE_COPY(QtDatePropertyManager) }; class QtTimePropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtTimePropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtTimePropertyManager(QObject *parent = 0); ~QtTimePropertyManager(); QTime value(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QTime &val); Q_SIGNALS: void valueChanged(QtProperty *property, const QTime &val); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtTimePropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtTimePropertyManager) Q_DISABLE_COPY(QtTimePropertyManager) }; class QtDateTimePropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtDateTimePropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtDateTimePropertyManager(QObject *parent = 0); ~QtDateTimePropertyManager(); QDateTime value(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QDateTime &val); Q_SIGNALS: void valueChanged(QtProperty *property, const QDateTime &val); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtDateTimePropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtDateTimePropertyManager) Q_DISABLE_COPY(QtDateTimePropertyManager) }; class QtKeySequencePropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtKeySequencePropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtKeySequencePropertyManager(QObject *parent = 0); ~QtKeySequencePropertyManager(); QKeySequence value(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QKeySequence &val); Q_SIGNALS: void valueChanged(QtProperty *property, const QKeySequence &val); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtKeySequencePropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtKeySequencePropertyManager) Q_DISABLE_COPY(QtKeySequencePropertyManager) }; class QtCharPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtCharPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtCharPropertyManager(QObject *parent = 0); ~QtCharPropertyManager(); QChar value(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QChar &val); Q_SIGNALS: void valueChanged(QtProperty *property, const QChar &val); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtCharPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtCharPropertyManager) Q_DISABLE_COPY(QtCharPropertyManager) }; class QtEnumPropertyManager; class QtLocalePropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtLocalePropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtLocalePropertyManager(QObject *parent = 0); ~QtLocalePropertyManager(); QtEnumPropertyManager *subEnumPropertyManager() const; QLocale value(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QLocale &val); Q_SIGNALS: void valueChanged(QtProperty *property, const QLocale &val); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtLocalePropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtLocalePropertyManager) Q_DISABLE_COPY(QtLocalePropertyManager) Q_PRIVATE_SLOT(d_func(), void slotEnumChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) }; class QtPointPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtPointPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtPointPropertyManager(QObject *parent = 0); ~QtPointPropertyManager(); QtIntPropertyManager *subIntPropertyManager() const; QPoint value(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QPoint &val); Q_SIGNALS: void valueChanged(QtProperty *property, const QPoint &val); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtPointPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtPointPropertyManager) Q_DISABLE_COPY(QtPointPropertyManager) Q_PRIVATE_SLOT(d_func(), void slotIntChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) }; class QtPointFPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtPointFPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtPointFPropertyManager(QObject *parent = 0); ~QtPointFPropertyManager(); QtDoublePropertyManager *subDoublePropertyManager() const; QPointF value(const QtProperty *property) const; int decimals(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QPointF &val); void setDecimals(QtProperty *property, int prec); Q_SIGNALS: void valueChanged(QtProperty *property, const QPointF &val); void decimalsChanged(QtProperty *property, int prec); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtPointFPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtPointFPropertyManager) Q_DISABLE_COPY(QtPointFPropertyManager) Q_PRIVATE_SLOT(d_func(), void slotDoubleChanged(QtProperty *, double)) Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) }; class QtSizePropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtSizePropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtSizePropertyManager(QObject *parent = 0); ~QtSizePropertyManager(); QtIntPropertyManager *subIntPropertyManager() const; QSize value(const QtProperty *property) const; QSize minimum(const QtProperty *property) const; QSize maximum(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QSize &val); void setMinimum(QtProperty *property, const QSize &minVal); void setMaximum(QtProperty *property, const QSize &maxVal); void setRange(QtProperty *property, const QSize &minVal, const QSize &maxVal); Q_SIGNALS: void valueChanged(QtProperty *property, const QSize &val); void rangeChanged(QtProperty *property, const QSize &minVal, const QSize &maxVal); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtSizePropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtSizePropertyManager) Q_DISABLE_COPY(QtSizePropertyManager) Q_PRIVATE_SLOT(d_func(), void slotIntChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) }; class QtSizeFPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtSizeFPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtSizeFPropertyManager(QObject *parent = 0); ~QtSizeFPropertyManager(); QtDoublePropertyManager *subDoublePropertyManager() const; QSizeF value(const QtProperty *property) const; QSizeF minimum(const QtProperty *property) const; QSizeF maximum(const QtProperty *property) const; int decimals(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QSizeF &val); void setMinimum(QtProperty *property, const QSizeF &minVal); void setMaximum(QtProperty *property, const QSizeF &maxVal); void setRange(QtProperty *property, const QSizeF &minVal, const QSizeF &maxVal); void setDecimals(QtProperty *property, int prec); Q_SIGNALS: void valueChanged(QtProperty *property, const QSizeF &val); void rangeChanged(QtProperty *property, const QSizeF &minVal, const QSizeF &maxVal); void decimalsChanged(QtProperty *property, int prec); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtSizeFPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtSizeFPropertyManager) Q_DISABLE_COPY(QtSizeFPropertyManager) Q_PRIVATE_SLOT(d_func(), void slotDoubleChanged(QtProperty *, double)) Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) }; class QtRectPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtRectPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtRectPropertyManager(QObject *parent = 0); ~QtRectPropertyManager(); QtIntPropertyManager *subIntPropertyManager() const; QRect value(const QtProperty *property) const; QRect constraint(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QRect &val); void setConstraint(QtProperty *property, const QRect &constraint); Q_SIGNALS: void valueChanged(QtProperty *property, const QRect &val); void constraintChanged(QtProperty *property, const QRect &constraint); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtRectPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtRectPropertyManager) Q_DISABLE_COPY(QtRectPropertyManager) Q_PRIVATE_SLOT(d_func(), void slotIntChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) }; class QtRectFPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtRectFPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtRectFPropertyManager(QObject *parent = 0); ~QtRectFPropertyManager(); QtDoublePropertyManager *subDoublePropertyManager() const; QRectF value(const QtProperty *property) const; QRectF constraint(const QtProperty *property) const; int decimals(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QRectF &val); void setConstraint(QtProperty *property, const QRectF &constraint); void setDecimals(QtProperty *property, int prec); Q_SIGNALS: void valueChanged(QtProperty *property, const QRectF &val); void constraintChanged(QtProperty *property, const QRectF &constraint); void decimalsChanged(QtProperty *property, int prec); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtRectFPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtRectFPropertyManager) Q_DISABLE_COPY(QtRectFPropertyManager) Q_PRIVATE_SLOT(d_func(), void slotDoubleChanged(QtProperty *, double)) Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) }; class QtEnumPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtEnumPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtEnumPropertyManager(QObject *parent = 0); ~QtEnumPropertyManager(); int value(const QtProperty *property) const; QStringList enumNames(const QtProperty *property) const; QMap enumIcons(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, int val); void setEnumNames(QtProperty *property, const QStringList &names); void setEnumIcons(QtProperty *property, const QMap &icons); Q_SIGNALS: void valueChanged(QtProperty *property, int val); void enumNamesChanged(QtProperty *property, const QStringList &names); void enumIconsChanged(QtProperty *property, const QMap &icons); protected: QString valueText(const QtProperty *property) const; QIcon valueIcon(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtEnumPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtEnumPropertyManager) Q_DISABLE_COPY(QtEnumPropertyManager) }; class QtFlagPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtFlagPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtFlagPropertyManager(QObject *parent = 0); ~QtFlagPropertyManager(); QtBoolPropertyManager *subBoolPropertyManager() const; int value(const QtProperty *property) const; QStringList flagNames(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, int val); void setFlagNames(QtProperty *property, const QStringList &names); Q_SIGNALS: void valueChanged(QtProperty *property, int val); void flagNamesChanged(QtProperty *property, const QStringList &names); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtFlagPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtFlagPropertyManager) Q_DISABLE_COPY(QtFlagPropertyManager) Q_PRIVATE_SLOT(d_func(), void slotBoolChanged(QtProperty *, bool)) Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) }; class QtSizePolicyPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtSizePolicyPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtSizePolicyPropertyManager(QObject *parent = 0); ~QtSizePolicyPropertyManager(); QtIntPropertyManager *subIntPropertyManager() const; QtEnumPropertyManager *subEnumPropertyManager() const; QSizePolicy value(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QSizePolicy &val); Q_SIGNALS: void valueChanged(QtProperty *property, const QSizePolicy &val); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtSizePolicyPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtSizePolicyPropertyManager) Q_DISABLE_COPY(QtSizePolicyPropertyManager) Q_PRIVATE_SLOT(d_func(), void slotIntChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotEnumChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) }; class QtFontPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtFontPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtFontPropertyManager(QObject *parent = 0); ~QtFontPropertyManager(); QtIntPropertyManager *subIntPropertyManager() const; QtEnumPropertyManager *subEnumPropertyManager() const; QtBoolPropertyManager *subBoolPropertyManager() const; QFont value(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QFont &val); Q_SIGNALS: void valueChanged(QtProperty *property, const QFont &val); protected: QString valueText(const QtProperty *property) const; QIcon valueIcon(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtFontPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtFontPropertyManager) Q_DISABLE_COPY(QtFontPropertyManager) Q_PRIVATE_SLOT(d_func(), void slotIntChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotEnumChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotBoolChanged(QtProperty *, bool)) Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) Q_PRIVATE_SLOT(d_func(), void slotFontDatabaseChanged()) Q_PRIVATE_SLOT(d_func(), void slotFontDatabaseDelayedChange()) }; class QtColorPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtColorPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtColorPropertyManager(QObject *parent = 0); ~QtColorPropertyManager(); QtIntPropertyManager *subIntPropertyManager() const; QColor value(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QColor &val); Q_SIGNALS: void valueChanged(QtProperty *property, const QColor &val); protected: QString valueText(const QtProperty *property) const; QIcon valueIcon(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtColorPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtColorPropertyManager) Q_DISABLE_COPY(QtColorPropertyManager) Q_PRIVATE_SLOT(d_func(), void slotIntChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) }; class QtCursorPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtCursorPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtCursorPropertyManager(QObject *parent = 0); ~QtCursorPropertyManager(); #ifndef QT_NO_CURSOR QCursor value(const QtProperty *property) const; #endif public Q_SLOTS: void setValue(QtProperty *property, const QCursor &val); Q_SIGNALS: void valueChanged(QtProperty *property, const QCursor &val); protected: QString valueText(const QtProperty *property) const; QIcon valueIcon(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtCursorPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtCursorPropertyManager) Q_DISABLE_COPY(QtCursorPropertyManager) }; #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif #endif nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/qttreepropertybrowser.cpp000066400000000000000000001101501455373415500300410ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #include "qttreepropertybrowser.h" #include #include #include #include #include #include #include #include #include #include #include #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif class QtPropertyEditorView; class QtTreePropertyBrowserPrivate { QtTreePropertyBrowser *q_ptr; Q_DECLARE_PUBLIC(QtTreePropertyBrowser) public: QtTreePropertyBrowserPrivate(); void init(QWidget *parent); void propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex); void propertyRemoved(QtBrowserItem *index); void propertyChanged(QtBrowserItem *index); QWidget *createEditor(QtProperty *property, QWidget *parent) const { return q_ptr->createEditor(property, parent); } QtProperty *indexToProperty(const QModelIndex &index) const; QTreeWidgetItem *indexToItem(const QModelIndex &index) const; QtBrowserItem *indexToBrowserItem(const QModelIndex &index) const; QtBrowserItem *itemToBrowserItem(QTreeWidgetItem *item) const { return m_itemToIndex.value(item); }; bool lastColumn(int column) const; void disableItem(QTreeWidgetItem *item) const; void enableItem(QTreeWidgetItem *item) const; bool hasValue(QTreeWidgetItem *item) const; void slotCollapsed(const QModelIndex &index); void slotExpanded(const QModelIndex &index); void onHoverPropertyChanged(QtBrowserItem *item); QColor calculatedBackgroundColor(QtBrowserItem *item) const; QtPropertyEditorView *treeWidget() const { return m_treeWidget; } bool markPropertiesWithoutValue() const { return m_markPropertiesWithoutValue; } QtBrowserItem *currentItem() const; void setCurrentItem(QtBrowserItem *browserItem, bool block); void editItem(QtBrowserItem *browserItem); void slotCurrentBrowserItemChanged(QtBrowserItem *item); void slotCurrentTreeItemChanged(QTreeWidgetItem *newItem, QTreeWidgetItem *); QTreeWidgetItem *editedItem() const; private: void updateItem(QTreeWidgetItem *item); QMap m_indexToItem; QMap m_itemToIndex; QMap m_indexToBackgroundColor; QtPropertyEditorView *m_treeWidget; bool m_headerVisible; QtTreePropertyBrowser::ResizeMode m_resizeMode; class QtPropertyEditorDelegate *m_delegate; bool m_markPropertiesWithoutValue; bool m_browserChangedBlocked; QIcon m_expandIcon; }; // ------------ QtPropertyEditorView class QtPropertyEditorView : public QTreeWidget { Q_OBJECT public: QtPropertyEditorView(QWidget *parent = 0); void setEditorPrivate(QtTreePropertyBrowserPrivate *editorPrivate) { m_editorPrivate = editorPrivate; } QTreeWidgetItem *indexToItem(const QModelIndex &index) const { return itemFromIndex(index); } protected: void mouseMoveEvent(QMouseEvent *event) override; void leaveEvent(QEvent *event) override; void keyPressEvent(QKeyEvent *event) override; void mousePressEvent(QMouseEvent *event) override; void drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; Q_SIGNALS: void hoverPropertyChanged(QtBrowserItem *item); private: QtTreePropertyBrowserPrivate *m_editorPrivate; QModelIndex current; }; QtPropertyEditorView::QtPropertyEditorView(QWidget *parent) : QTreeWidget(parent), m_editorPrivate(0) { connect(header(), SIGNAL(sectionDoubleClicked(int)), this, SLOT(resizeColumnToContents(int))); } void QtPropertyEditorView::drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QStyleOptionViewItem opt = option; bool hasValue = true; if (m_editorPrivate) { QtProperty *property = m_editorPrivate->indexToProperty(index); if (property) hasValue = property->hasValue(); } if (!hasValue && m_editorPrivate->markPropertiesWithoutValue()) { const QColor c = option.palette.color(QPalette::Dark); painter->fillRect(option.rect, c); opt.palette.setColor(QPalette::AlternateBase, c); } else { const QColor c = m_editorPrivate->calculatedBackgroundColor(m_editorPrivate->indexToBrowserItem(index)); if (c.isValid()) { painter->fillRect(option.rect, c); opt.palette.setColor(QPalette::AlternateBase, c.lighter(112)); } } QTreeWidget::drawRow(painter, opt, index); QColor color = static_cast(QApplication::style()->styleHint(QStyle::SH_Table_GridLineColor, &opt)); painter->save(); painter->setPen(QPen(color)); painter->drawLine(opt.rect.x(), opt.rect.bottom(), opt.rect.right(), opt.rect.bottom()); painter->restore(); } void QtPropertyEditorView::mouseMoveEvent(QMouseEvent *event) { QModelIndex index = indexAt(event->pos()); if (index!=current) { current = index; Q_EMIT hoverPropertyChanged(m_editorPrivate->indexToBrowserItem(index)); } QTreeWidget::mouseMoveEvent(event); } void QtPropertyEditorView::leaveEvent(QEvent *event) { Q_EMIT hoverPropertyChanged(nullptr); } void QtPropertyEditorView::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Return: case Qt::Key_Enter: case Qt::Key_Space: // Trigger Edit if (!m_editorPrivate->editedItem()) if (const QTreeWidgetItem *item = currentItem()) if (item->columnCount() >= 2 && ((item->flags() & (Qt::ItemIsEditable | Qt::ItemIsEnabled)) == (Qt::ItemIsEditable | Qt::ItemIsEnabled))) { event->accept(); // If the current position is at column 0, move to 1. QModelIndex index = currentIndex(); if (index.column() == 0) { index = index.sibling(index.row(), 1); setCurrentIndex(index); } edit(index); return; } break; default: break; } QTreeWidget::keyPressEvent(event); } void QtPropertyEditorView::mousePressEvent(QMouseEvent *event) { QTreeWidget::mousePressEvent(event); QTreeWidgetItem *item = itemAt(event->pos()); if (item) { if ((item != m_editorPrivate->editedItem()) && (event->button() == Qt::LeftButton) && (header()->logicalIndexAt(event->pos().x()) == 1) && ((item->flags() & (Qt::ItemIsEditable | Qt::ItemIsEnabled)) == (Qt::ItemIsEditable | Qt::ItemIsEnabled))) { editItem(item, 1); } else if (!m_editorPrivate->hasValue(item) && m_editorPrivate->markPropertiesWithoutValue() && !rootIsDecorated()) { if (event->pos().x() + header()->offset() < 20) item->setExpanded(!item->isExpanded()); } } } // ------------ QtPropertyEditorDelegate class QtPropertyEditorDelegate : public QItemDelegate { Q_OBJECT public: QtPropertyEditorDelegate(QObject *parent = 0) : QItemDelegate(parent), m_editorPrivate(0), m_editedItem(0), m_editedWidget(0), m_disablePainting(false) {} void setEditorPrivate(QtTreePropertyBrowserPrivate *editorPrivate) { m_editorPrivate = editorPrivate; } QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const; void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; void setModelData(QWidget *, QAbstractItemModel *, const QModelIndex &) const {} void setEditorData(QWidget *, const QModelIndex &) const {} bool eventFilter(QObject *object, QEvent *event); void closeEditor(QtProperty *property); QTreeWidgetItem *editedItem() const { return m_editedItem; } protected: void drawDecoration(QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect, const QPixmap &pixmap) const; void drawDisplay(QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect, const QString &text) const; private slots: void slotEditorDestroyed(QObject *object); private: int indentation(const QModelIndex &index) const; typedef QMap EditorToPropertyMap; mutable EditorToPropertyMap m_editorToProperty; typedef QMap PropertyToEditorMap; mutable PropertyToEditorMap m_propertyToEditor; QtTreePropertyBrowserPrivate *m_editorPrivate; mutable QTreeWidgetItem *m_editedItem; mutable QWidget *m_editedWidget; mutable bool m_disablePainting; }; int QtPropertyEditorDelegate::indentation(const QModelIndex &index) const { if (!m_editorPrivate) return 0; QTreeWidgetItem *item = m_editorPrivate->indexToItem(index); int indent = 0; while (item->parent()) { item = item->parent(); ++indent; } if (m_editorPrivate->treeWidget()->rootIsDecorated()) ++indent; return indent * m_editorPrivate->treeWidget()->indentation(); } void QtPropertyEditorDelegate::slotEditorDestroyed(QObject *object) { if (QWidget *w = qobject_cast(object)) { const EditorToPropertyMap::iterator it = m_editorToProperty.find(w); if (it != m_editorToProperty.end()) { m_propertyToEditor.remove(it.value()); m_editorToProperty.erase(it); } if (m_editedWidget == w) { m_editedWidget = 0; m_editedItem = 0; } } } void QtPropertyEditorDelegate::closeEditor(QtProperty *property) { if (QWidget *w = m_propertyToEditor.value(property, 0)) w->deleteLater(); } QWidget *QtPropertyEditorDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &index) const { if (index.column() == 1 && m_editorPrivate) { QtProperty *property = m_editorPrivate->indexToProperty(index); QTreeWidgetItem *item = m_editorPrivate->indexToItem(index); if (property && item && (item->flags() & Qt::ItemIsEnabled)) { QWidget *editor = m_editorPrivate->createEditor(property, parent); if (editor) { editor->setAutoFillBackground(true); editor->installEventFilter(const_cast(this)); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); m_propertyToEditor[property] = editor; m_editorToProperty[editor] = property; m_editedItem = item; m_editedWidget = editor; } return editor; } } return 0; } void QtPropertyEditorDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const { Q_UNUSED(index) editor->setGeometry(option.rect.adjusted(0, 0, 0, -1)); } void QtPropertyEditorDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { bool hasValue = true; if (m_editorPrivate) { QtProperty *property = m_editorPrivate->indexToProperty(index); if (property) hasValue = property->hasValue(); } QStyleOptionViewItem opt = option; if ((m_editorPrivate && index.column() == 0) || !hasValue) { QtProperty *property = m_editorPrivate->indexToProperty(index); if (property && property->isModified()) { opt.font.setBold(true); opt.fontMetrics = QFontMetrics(opt.font); } } QColor c; if (!hasValue && m_editorPrivate->markPropertiesWithoutValue()) { c = opt.palette.color(QPalette::Dark); opt.palette.setColor(QPalette::Text, opt.palette.color(QPalette::BrightText)); } else { c = m_editorPrivate->calculatedBackgroundColor(m_editorPrivate->indexToBrowserItem(index)); if (c.isValid() && (opt.features & QStyleOptionViewItem::Alternate)) c = c.lighter(112); } if (c.isValid()) painter->fillRect(option.rect, c); opt.state &= ~QStyle::State_HasFocus; if (index.column() == 1) { QTreeWidgetItem *item = m_editorPrivate->indexToItem(index); if (m_editedItem && m_editedItem == item) m_disablePainting = true; } QItemDelegate::paint(painter, opt, index); m_disablePainting = false; opt.palette.setCurrentColorGroup(QPalette::Active); QColor color = static_cast(QApplication::style()->styleHint(QStyle::SH_Table_GridLineColor, &opt)); painter->save(); painter->setPen(QPen(color)); if (!m_editorPrivate || (!m_editorPrivate->lastColumn(index.column()) && hasValue)) { int right = (option.direction == Qt::LeftToRight) ? option.rect.right() : option.rect.left(); painter->drawLine(right, option.rect.y(), right, option.rect.bottom()); } painter->restore(); } void QtPropertyEditorDelegate::drawDecoration(QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect, const QPixmap &pixmap) const { if (m_disablePainting) return; QItemDelegate::drawDecoration(painter, option, rect, pixmap); } void QtPropertyEditorDelegate::drawDisplay(QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect, const QString &text) const { if (m_disablePainting) return; QItemDelegate::drawDisplay(painter, option, rect, text); } QSize QtPropertyEditorDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { return QItemDelegate::sizeHint(option, index) + QSize(3, 4); } bool QtPropertyEditorDelegate::eventFilter(QObject *object, QEvent *event) { if (event->type() == QEvent::FocusOut) { QFocusEvent *fe = static_cast(event); if (fe->reason() == Qt::ActiveWindowFocusReason) return false; } return QItemDelegate::eventFilter(object, event); } // -------- QtTreePropertyBrowserPrivate implementation QtTreePropertyBrowserPrivate::QtTreePropertyBrowserPrivate() : m_treeWidget(0), m_headerVisible(true), m_resizeMode(QtTreePropertyBrowser::Stretch), m_delegate(0), m_markPropertiesWithoutValue(false), m_browserChangedBlocked(false) { } // Draw an icon indicating opened/closing branches static QIcon drawIndicatorIcon(const QPalette &palette, QStyle *style) { QPixmap pix(14, 14); pix.fill(Qt::transparent); QStyleOption branchOption; QRect r(QPoint(0, 0), pix.size()); branchOption.rect = QRect(2, 2, 9, 9); // ### hardcoded in qcommonstyle.cpp branchOption.palette = palette; branchOption.state = QStyle::State_Children; QPainter p; // Draw closed state p.begin(&pix); style->drawPrimitive(QStyle::PE_IndicatorBranch, &branchOption, &p); p.end(); QIcon rc = pix; rc.addPixmap(pix, QIcon::Selected, QIcon::Off); // Draw opened state branchOption.state |= QStyle::State_Open; pix.fill(Qt::transparent); p.begin(&pix); style->drawPrimitive(QStyle::PE_IndicatorBranch, &branchOption, &p); p.end(); rc.addPixmap(pix, QIcon::Normal, QIcon::On); rc.addPixmap(pix, QIcon::Selected, QIcon::On); return rc; } void QtTreePropertyBrowserPrivate::init(QWidget *parent) { QHBoxLayout *layout = new QHBoxLayout(parent); layout->setMargin(0); m_treeWidget = new QtPropertyEditorView(parent); m_treeWidget->setEditorPrivate(this); m_treeWidget->setIconSize(QSize(18, 18)); layout->addWidget(m_treeWidget); m_treeWidget->setColumnCount(2); QStringList labels; labels.append(QApplication::translate("QtTreePropertyBrowser", "Property", 0)); labels.append(QApplication::translate("QtTreePropertyBrowser", "Value", 0)); m_treeWidget->setHeaderLabels(labels); m_treeWidget->setAlternatingRowColors(true); m_treeWidget->setEditTriggers(QAbstractItemView::EditKeyPressed); m_delegate = new QtPropertyEditorDelegate(parent); m_delegate->setEditorPrivate(this); m_treeWidget->setItemDelegate(m_delegate); m_treeWidget->header()->setSectionsMovable(false); m_treeWidget->header()->setSectionResizeMode(QHeaderView::Stretch); m_expandIcon = drawIndicatorIcon(q_ptr->palette(), q_ptr->style()); QObject::connect(m_treeWidget, SIGNAL(collapsed(const QModelIndex &)), q_ptr, SLOT(slotCollapsed(const QModelIndex &))); QObject::connect(m_treeWidget, SIGNAL(expanded(const QModelIndex &)), q_ptr, SLOT(slotExpanded(const QModelIndex &))); QObject::connect(m_treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), q_ptr, SLOT(slotCurrentTreeItemChanged(QTreeWidgetItem*,QTreeWidgetItem*))); QObject::connect(m_treeWidget, SIGNAL(hoverPropertyChanged(QtBrowserItem *)), q_ptr, SLOT(onHoverPropertyChanged(QtBrowserItem *))); } QtBrowserItem *QtTreePropertyBrowserPrivate::currentItem() const { if (QTreeWidgetItem *treeItem = m_treeWidget->currentItem()) return m_itemToIndex.value(treeItem); return 0; } void QtTreePropertyBrowserPrivate::setCurrentItem(QtBrowserItem *browserItem, bool block) { const bool blocked = block ? m_treeWidget->blockSignals(true) : false; if (browserItem == 0) m_treeWidget->setCurrentItem(0); else m_treeWidget->setCurrentItem(m_indexToItem.value(browserItem)); if (block) m_treeWidget->blockSignals(blocked); } QtProperty *QtTreePropertyBrowserPrivate::indexToProperty(const QModelIndex &index) const { QTreeWidgetItem *item = m_treeWidget->indexToItem(index); QtBrowserItem *idx = m_itemToIndex.value(item); if (idx) return idx->property(); return 0; } QtBrowserItem *QtTreePropertyBrowserPrivate::indexToBrowserItem(const QModelIndex &index) const { QTreeWidgetItem *item = m_treeWidget->indexToItem(index); return m_itemToIndex.value(item); } QTreeWidgetItem *QtTreePropertyBrowserPrivate::indexToItem(const QModelIndex &index) const { return m_treeWidget->indexToItem(index); } bool QtTreePropertyBrowserPrivate::lastColumn(int column) const { return m_treeWidget->header()->visualIndex(column) == m_treeWidget->columnCount() - 1; } void QtTreePropertyBrowserPrivate::disableItem(QTreeWidgetItem *item) const { Qt::ItemFlags flags = item->flags(); if (flags & Qt::ItemIsEnabled) { flags &= ~Qt::ItemIsEnabled; item->setFlags(flags); m_delegate->closeEditor(m_itemToIndex[item]->property()); const int childCount = item->childCount(); for (int i = 0; i < childCount; i++) { QTreeWidgetItem *child = item->child(i); disableItem(child); } } } void QtTreePropertyBrowserPrivate::enableItem(QTreeWidgetItem *item) const { Qt::ItemFlags flags = item->flags(); flags |= Qt::ItemIsEnabled; item->setFlags(flags); const int childCount = item->childCount(); for (int i = 0; i < childCount; i++) { QTreeWidgetItem *child = item->child(i); QtProperty *property = m_itemToIndex[child]->property(); if (property->isEnabled()) { enableItem(child); } } } bool QtTreePropertyBrowserPrivate::hasValue(QTreeWidgetItem *item) const { QtBrowserItem *browserItem = m_itemToIndex.value(item); if (browserItem) return browserItem->property()->hasValue(); return false; } void QtTreePropertyBrowserPrivate::propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex) { QTreeWidgetItem *afterItem = m_indexToItem.value(afterIndex); QTreeWidgetItem *parentItem = m_indexToItem.value(index->parent()); QTreeWidgetItem *newItem = 0; if (parentItem) { newItem = new QTreeWidgetItem(parentItem, afterItem); } else { newItem = new QTreeWidgetItem(m_treeWidget, afterItem); } m_itemToIndex[newItem] = index; m_indexToItem[index] = newItem; newItem->setFlags(newItem->flags() | Qt::ItemIsEditable); newItem->setExpanded(true); updateItem(newItem); } void QtTreePropertyBrowserPrivate::propertyRemoved(QtBrowserItem *index) { QTreeWidgetItem *item = m_indexToItem.value(index); if (m_treeWidget->currentItem() == item) { m_treeWidget->setCurrentItem(0); } delete item; m_indexToItem.remove(index); m_itemToIndex.remove(item); m_indexToBackgroundColor.remove(index); } void QtTreePropertyBrowserPrivate::propertyChanged(QtBrowserItem *index) { QTreeWidgetItem *item = m_indexToItem.value(index); updateItem(item); } void QtTreePropertyBrowserPrivate::updateItem(QTreeWidgetItem *item) { QtProperty *property = m_itemToIndex[item]->property(); QIcon expandIcon; if (property->hasValue()) { QString toolTip = property->toolTip(); if (toolTip.isEmpty()) toolTip = property->valueText(); item->setToolTip(1, toolTip); item->setIcon(1, property->valueIcon()); item->setText(1, property->valueText()); } else if (markPropertiesWithoutValue() && !m_treeWidget->rootIsDecorated()) { expandIcon = m_expandIcon; } item->setIcon(0, expandIcon); item->setFirstColumnSpanned(!property->hasValue()); item->setToolTip(0, property->propertyName()); item->setStatusTip(0, property->statusTip()); item->setWhatsThis(0, property->whatsThis()); item->setText(0, property->propertyName()); bool wasEnabled = item->flags() & Qt::ItemIsEnabled; bool isEnabled = wasEnabled; if (property->isEnabled()) { QTreeWidgetItem *parent = item->parent(); if (!parent || (parent->flags() & Qt::ItemIsEnabled)) isEnabled = true; else isEnabled = false; } else { isEnabled = false; } if (wasEnabled != isEnabled) { if (isEnabled) enableItem(item); else disableItem(item); } if (property->isSelectable()) { item->setFlags(item->flags() | Qt::ItemIsSelectable); } else { item->setFlags(item->flags() & ~Qt::ItemIsSelectable); } m_treeWidget->viewport()->update(); } QColor QtTreePropertyBrowserPrivate::calculatedBackgroundColor(QtBrowserItem *item) const { QtBrowserItem *i = item; const QMap::const_iterator itEnd = m_indexToBackgroundColor.constEnd(); while (i) { QMap::const_iterator it = m_indexToBackgroundColor.constFind(i); if (it != itEnd) return it.value(); i = i->parent(); } return QColor(); } void QtTreePropertyBrowserPrivate::slotCollapsed(const QModelIndex &index) { QTreeWidgetItem *item = indexToItem(index); QtBrowserItem *idx = m_itemToIndex.value(item); if (item) emit q_ptr->collapsed(idx); } void QtTreePropertyBrowserPrivate::slotExpanded(const QModelIndex &index) { QTreeWidgetItem *item = indexToItem(index); QtBrowserItem *idx = m_itemToIndex.value(item); if (item) emit q_ptr->expanded(idx); } void QtTreePropertyBrowserPrivate::onHoverPropertyChanged(QtBrowserItem *item) { emit q_ptr->hoverPropertyChanged(item); } void QtTreePropertyBrowserPrivate::slotCurrentBrowserItemChanged(QtBrowserItem *item) { if (!m_browserChangedBlocked && item != currentItem()) setCurrentItem(item, true); } void QtTreePropertyBrowserPrivate::slotCurrentTreeItemChanged(QTreeWidgetItem *newItem, QTreeWidgetItem *) { QtBrowserItem *browserItem = newItem ? m_itemToIndex.value(newItem) : 0; m_browserChangedBlocked = true; q_ptr->setCurrentItem(browserItem); m_browserChangedBlocked = false; } QTreeWidgetItem *QtTreePropertyBrowserPrivate::editedItem() const { return m_delegate->editedItem(); } void QtTreePropertyBrowserPrivate::editItem(QtBrowserItem *browserItem) { if (QTreeWidgetItem *treeItem = m_indexToItem.value(browserItem, 0)) { m_treeWidget->setCurrentItem (treeItem, 1); m_treeWidget->editItem(treeItem, 1); } } /*! \class QtTreePropertyBrowser \brief The QtTreePropertyBrowser class provides QTreeWidget based property browser. A property browser is a widget that enables the user to edit a given set of properties. Each property is represented by a label specifying the property's name, and an editing widget (e.g. a line edit or a combobox) holding its value. A property can have zero or more subproperties. QtTreePropertyBrowser provides a tree based view for all nested properties, i.e. properties that have subproperties can be in an expanded (subproperties are visible) or collapsed (subproperties are hidden) state. For example: \image qttreepropertybrowser.png Use the QtAbstractPropertyBrowser API to add, insert and remove properties from an instance of the QtTreePropertyBrowser class. The properties themselves are created and managed by implementations of the QtAbstractPropertyManager class. \sa QtGroupBoxPropertyBrowser, QtAbstractPropertyBrowser */ /*! \fn void QtTreePropertyBrowser::collapsed(QtBrowserItem *item) This signal is emitted when the \a item is collapsed. \sa expanded(), setExpanded() */ /*! \fn void QtTreePropertyBrowser::expanded(QtBrowserItem *item) This signal is emitted when the \a item is expanded. \sa collapsed(), setExpanded() */ /*! Creates a property browser with the given \a parent. */ QtTreePropertyBrowser::QtTreePropertyBrowser(QWidget *parent) : QtAbstractPropertyBrowser(parent) { d_ptr = new QtTreePropertyBrowserPrivate; d_ptr->q_ptr = this; d_ptr->init(this); connect(this, SIGNAL(currentItemChanged(QtBrowserItem*)), this, SLOT(slotCurrentBrowserItemChanged(QtBrowserItem*))); } /*! Destroys this property browser. Note that the properties that were inserted into this browser are \e not destroyed since they may still be used in other browsers. The properties are owned by the manager that created them. \sa QtProperty, QtAbstractPropertyManager */ QtTreePropertyBrowser::~QtTreePropertyBrowser() { delete d_ptr; } /*! \property QtTreePropertyBrowser::indentation \brief indentation of the items in the tree view. */ int QtTreePropertyBrowser::indentation() const { return d_ptr->m_treeWidget->indentation(); } void QtTreePropertyBrowser::setIndentation(int i) { d_ptr->m_treeWidget->setIndentation(i); } /*! \property QtTreePropertyBrowser::rootIsDecorated \brief whether to show controls for expanding and collapsing root items. */ bool QtTreePropertyBrowser::rootIsDecorated() const { return d_ptr->m_treeWidget->rootIsDecorated(); } void QtTreePropertyBrowser::setRootIsDecorated(bool show) { d_ptr->m_treeWidget->setRootIsDecorated(show); QMapIterator it(d_ptr->m_itemToIndex); while (it.hasNext()) { QtProperty *property = it.next().value()->property(); if (!property->hasValue()) d_ptr->updateItem(it.key()); } } /*! \property QtTreePropertyBrowser::alternatingRowColors \brief whether to draw the background using alternating colors. By default this property is set to true. */ bool QtTreePropertyBrowser::alternatingRowColors() const { return d_ptr->m_treeWidget->alternatingRowColors(); } void QtTreePropertyBrowser::setAlternatingRowColors(bool enable) { d_ptr->m_treeWidget->setAlternatingRowColors(enable); QMapIterator it(d_ptr->m_itemToIndex); } /*! \property QtTreePropertyBrowser::headerVisible \brief whether to show the header. */ bool QtTreePropertyBrowser::isHeaderVisible() const { return d_ptr->m_headerVisible; } void QtTreePropertyBrowser::setHeaderVisible(bool visible) { if (d_ptr->m_headerVisible == visible) return; d_ptr->m_headerVisible = visible; d_ptr->m_treeWidget->header()->setVisible(visible); } /*! \enum QtTreePropertyBrowser::ResizeMode The resize mode specifies the behavior of the header sections. \value Interactive The user can resize the sections. The sections can also be resized programmatically using setSplitterPosition(). \value Fixed The user cannot resize the section. The section can only be resized programmatically using setSplitterPosition(). \value Stretch QHeaderView will automatically resize the section to fill the available space. The size cannot be changed by the user or programmatically. \value ResizeToContents QHeaderView will automatically resize the section to its optimal size based on the contents of the entire column. The size cannot be changed by the user or programmatically. \sa setResizeMode() */ /*! \property QtTreePropertyBrowser::resizeMode \brief the resize mode of setions in the header. */ QtTreePropertyBrowser::ResizeMode QtTreePropertyBrowser::resizeMode() const { return d_ptr->m_resizeMode; } void QtTreePropertyBrowser::setResizeMode(QtTreePropertyBrowser::ResizeMode mode) { if (d_ptr->m_resizeMode == mode) return; d_ptr->m_resizeMode = mode; QHeaderView::ResizeMode m = QHeaderView::Stretch; switch (mode) { case QtTreePropertyBrowser::Interactive: m = QHeaderView::Interactive; break; case QtTreePropertyBrowser::Fixed: m = QHeaderView::Fixed; break; case QtTreePropertyBrowser::ResizeToContents: m = QHeaderView::ResizeToContents; break; case QtTreePropertyBrowser::Stretch: default: m = QHeaderView::Stretch; break; } d_ptr->m_treeWidget->header()->setSectionResizeMode(m); } /*! \property QtTreePropertyBrowser::splitterPosition \brief the position of the splitter between the colunms. */ int QtTreePropertyBrowser::splitterPosition() const { return d_ptr->m_treeWidget->header()->sectionSize(0); } void QtTreePropertyBrowser::setSplitterPosition(int position) { d_ptr->m_treeWidget->header()->resizeSection(0, position); } /*! Sets the \a item to either collapse or expanded, depending on the value of \a expanded. \sa isExpanded(), expanded(), collapsed() */ void QtTreePropertyBrowser::setExpanded(QtBrowserItem *item, bool expanded) { QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item); if (treeItem) treeItem->setExpanded(expanded); } /*! Returns true if the \a item is expanded; otherwise returns false. \sa setExpanded() */ bool QtTreePropertyBrowser::isExpanded(QtBrowserItem *item) const { QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item); if (treeItem) return treeItem->isExpanded(); return false; } /*! Returns true if the \a item is visible; otherwise returns false. \sa setItemVisible() \since 4.5 */ bool QtTreePropertyBrowser::isItemVisible(QtBrowserItem *item) const { if (const QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item)) return !treeItem->isHidden(); return false; } /*! Sets the \a item to be visible, depending on the value of \a visible. \sa isItemVisible() \since 4.5 */ void QtTreePropertyBrowser::setItemVisible(QtBrowserItem *item, bool visible) { if (QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item)) treeItem->setHidden(!visible); } /*! Sets the \a item's background color to \a color. Note that while item's background is rendered every second row is being drawn with alternate color (which is a bit lighter than items \a color) \sa backgroundColor(), calculatedBackgroundColor() */ void QtTreePropertyBrowser::setBackgroundColor(QtBrowserItem *item, const QColor &color) { if (!d_ptr->m_indexToItem.contains(item)) return; if (color.isValid()) d_ptr->m_indexToBackgroundColor[item] = color; else d_ptr->m_indexToBackgroundColor.remove(item); d_ptr->m_treeWidget->viewport()->update(); } /*! Returns the \a item's color. If there is no color set for item it returns invalid color. \sa calculatedBackgroundColor(), setBackgroundColor() */ QColor QtTreePropertyBrowser::backgroundColor(QtBrowserItem *item) const { return d_ptr->m_indexToBackgroundColor.value(item); } /*! Returns the \a item's color. If there is no color set for item it returns parent \a item's color (if there is no color set for parent it returns grandparent's color and so on). In case the color is not set for \a item and it's top level item it returns invalid color. \sa backgroundColor(), setBackgroundColor() */ QColor QtTreePropertyBrowser::calculatedBackgroundColor(QtBrowserItem *item) const { return d_ptr->calculatedBackgroundColor(item); } /*! \property QtTreePropertyBrowser::propertiesWithoutValueMarked \brief whether to enable or disable marking properties without value. When marking is enabled the item's background is rendered in dark color and item's foreground is rendered with light color. \sa propertiesWithoutValueMarked() */ void QtTreePropertyBrowser::setPropertiesWithoutValueMarked(bool mark) { if (d_ptr->m_markPropertiesWithoutValue == mark) return; d_ptr->m_markPropertiesWithoutValue = mark; QMapIterator it(d_ptr->m_itemToIndex); while (it.hasNext()) { QtProperty *property = it.next().value()->property(); if (!property->hasValue()) d_ptr->updateItem(it.key()); } d_ptr->m_treeWidget->viewport()->update(); } bool QtTreePropertyBrowser::propertiesWithoutValueMarked() const { return d_ptr->m_markPropertiesWithoutValue; } /*! \reimp */ void QtTreePropertyBrowser::itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem) { d_ptr->propertyInserted(item, afterItem); } /*! \reimp */ void QtTreePropertyBrowser::itemRemoved(QtBrowserItem *item) { d_ptr->propertyRemoved(item); } /*! \reimp */ void QtTreePropertyBrowser::itemChanged(QtBrowserItem *item) { d_ptr->propertyChanged(item); } /*! Sets the current item to \a item and opens the relevant editor for it. */ void QtTreePropertyBrowser::editItem(QtBrowserItem *item) { d_ptr->editItem(item); } QTreeWidget *QtTreePropertyBrowser::treeWidget() const { return d_ptr->treeWidget(); } QtBrowserItem *QtTreePropertyBrowser::itemToBrowserItem(QTreeWidgetItem *item) { return d_ptr->itemToBrowserItem(item); } #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif #include "moc_qttreepropertybrowser.cpp" #include "qttreepropertybrowser.moc" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/qttreepropertybrowser.h000066400000000000000000000121601455373415500275100ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #ifndef QTTREEPROPERTYBROWSER_H #define QTTREEPROPERTYBROWSER_H #include "qtpropertybrowser.h" #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif class QTreeWidget; class QTreeWidgetItem; class QtTreePropertyBrowserPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtTreePropertyBrowser : public QtAbstractPropertyBrowser { Q_OBJECT Q_ENUMS(ResizeMode) Q_PROPERTY(int indentation READ indentation WRITE setIndentation) Q_PROPERTY(bool rootIsDecorated READ rootIsDecorated WRITE setRootIsDecorated) Q_PROPERTY(bool alternatingRowColors READ alternatingRowColors WRITE setAlternatingRowColors) Q_PROPERTY(bool headerVisible READ isHeaderVisible WRITE setHeaderVisible) Q_PROPERTY(ResizeMode resizeMode READ resizeMode WRITE setResizeMode) Q_PROPERTY(int splitterPosition READ splitterPosition WRITE setSplitterPosition) Q_PROPERTY(bool propertiesWithoutValueMarked READ propertiesWithoutValueMarked WRITE setPropertiesWithoutValueMarked) public: enum ResizeMode { Interactive, Stretch, Fixed, ResizeToContents }; QtTreePropertyBrowser(QWidget *parent = 0); ~QtTreePropertyBrowser(); int indentation() const; void setIndentation(int i); bool rootIsDecorated() const; void setRootIsDecorated(bool show); bool alternatingRowColors() const; void setAlternatingRowColors(bool enable); bool isHeaderVisible() const; void setHeaderVisible(bool visible); ResizeMode resizeMode() const; void setResizeMode(ResizeMode mode); int splitterPosition() const; void setSplitterPosition(int position); void setExpanded(QtBrowserItem *item, bool expanded); bool isExpanded(QtBrowserItem *item) const; bool isItemVisible(QtBrowserItem *item) const; void setItemVisible(QtBrowserItem *item, bool visible); void setBackgroundColor(QtBrowserItem *item, const QColor &color); QColor backgroundColor(QtBrowserItem *item) const; QColor calculatedBackgroundColor(QtBrowserItem *item) const; void setPropertiesWithoutValueMarked(bool mark); bool propertiesWithoutValueMarked() const; void editItem(QtBrowserItem *item); //ADDED:miodrag QTreeWidget *treeWidget() const; QtBrowserItem *itemToBrowserItem(QTreeWidgetItem *item); Q_SIGNALS: void collapsed(QtBrowserItem *item); void expanded(QtBrowserItem *item); void hoverPropertyChanged(QtBrowserItem *item); protected: virtual void itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem); virtual void itemRemoved(QtBrowserItem *item); virtual void itemChanged(QtBrowserItem *item); private: QtTreePropertyBrowserPrivate *d_ptr; Q_DECLARE_PRIVATE(QtTreePropertyBrowser) Q_DISABLE_COPY(QtTreePropertyBrowser) Q_PRIVATE_SLOT(d_func(), void slotCollapsed(const QModelIndex &)) Q_PRIVATE_SLOT(d_func(), void slotExpanded(const QModelIndex &)) Q_PRIVATE_SLOT(d_func(), void slotCurrentBrowserItemChanged(QtBrowserItem *)) Q_PRIVATE_SLOT(d_func(), void slotCurrentTreeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)) Q_PRIVATE_SLOT(d_func(), void onHoverPropertyChanged(QtBrowserItem *)) }; #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif #endif nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/qtvariantproperty.cpp000066400000000000000000003065371455373415500271620ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #include "qtvariantproperty.h" #include "qtpropertymanager.h" #include "qteditorfactory.h" #include #include #include #include #if defined(Q_CC_MSVC) # pragma warning(disable: 4786) /* MS VS 6: truncating debug info after 255 characters */ #endif #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif class QtEnumPropertyType { }; class QtFlagPropertyType { }; class QtGroupPropertyType { }; #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif Q_DECLARE_METATYPE(QtEnumPropertyType) Q_DECLARE_METATYPE(QtFlagPropertyType) Q_DECLARE_METATYPE(QtGroupPropertyType) #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif /*! Returns the type id for an enum property. Note that the property's value type can be retrieved using the valueType() function (which is QVariant::Int for the enum property type). \sa propertyType(), valueType() */ int QtVariantPropertyManager::enumTypeId() { return qMetaTypeId(); } /*! Returns the type id for a flag property. Note that the property's value type can be retrieved using the valueType() function (which is QVariant::Int for the flag property type). \sa propertyType(), valueType() */ int QtVariantPropertyManager::flagTypeId() { return qMetaTypeId(); } /*! Returns the type id for a group property. Note that the property's value type can be retrieved using the valueType() function (which is QVariant::Invalid for the group property type, since it doesn't provide any value). \sa propertyType(), valueType() */ int QtVariantPropertyManager::groupTypeId() { return qMetaTypeId(); } /*! Returns the type id for a icon map attribute. Note that the property's attribute type can be retrieved using the attributeType() function. \sa attributeType(), QtEnumPropertyManager::enumIcons() */ int QtVariantPropertyManager::iconMapTypeId() { return qMetaTypeId(); } typedef QMap PropertyMap; Q_GLOBAL_STATIC(PropertyMap, propertyToWrappedProperty) static QtProperty *wrappedProperty(QtProperty *property) { return propertyToWrappedProperty()->value(property, 0); } class QtVariantPropertyPrivate { public: QtVariantPropertyPrivate(QtVariantPropertyManager *m) : manager(m) {} QtVariantPropertyManager *manager; }; /*! \class QtVariantProperty \brief The QtVariantProperty class is a convenience class handling QVariant based properties. QtVariantProperty provides additional API: A property's type, value type, attribute values and current value can easily be retrieved using the propertyType(), valueType(), attributeValue() and value() functions respectively. In addition, the attribute values and the current value can be set using the corresponding setValue() and setAttribute() functions. For example, instead of writing: \code QtVariantPropertyManager *variantPropertyManager; QtProperty *property; variantPropertyManager->setValue(property, 10); \endcode you can write: \code QtVariantPropertyManager *variantPropertyManager; QtVariantProperty *property; property->setValue(10); \endcode QtVariantProperty instances can only be created by the QtVariantPropertyManager class. \sa QtProperty, QtVariantPropertyManager, QtVariantEditorFactory */ /*! Creates a variant property using the given \a manager. Do not use this constructor to create variant property instances; use the QtVariantPropertyManager::addProperty() function instead. This constructor is used internally by the QtVariantPropertyManager::createProperty() function. \sa QtVariantPropertyManager */ QtVariantProperty::QtVariantProperty(QtVariantPropertyManager *manager) : QtProperty(manager), d_ptr(new QtVariantPropertyPrivate(manager)) { } /*! Destroys this property. \sa QtProperty::~QtProperty() */ QtVariantProperty::~QtVariantProperty() { delete d_ptr; } /*! Returns the property's current value. \sa valueType(), setValue() */ QVariant QtVariantProperty::value() const { return d_ptr->manager->value(this); } /*! Returns this property's value for the specified \a attribute. QtVariantPropertyManager provides a couple of related functions: \l{QtVariantPropertyManager::attributes()}{attributes()} and \l{QtVariantPropertyManager::attributeType()}{attributeType()}. \sa setAttribute() */ QVariant QtVariantProperty::attributeValue(const QString &attribute) const { return d_ptr->manager->attributeValue(this, attribute); } /*! Returns the type of this property's value. \sa propertyType() */ int QtVariantProperty::valueType() const { return d_ptr->manager->valueType(this); } /*! Returns this property's type. QtVariantPropertyManager provides several related functions: \l{QtVariantPropertyManager::enumTypeId()}{enumTypeId()}, \l{QtVariantPropertyManager::flagTypeId()}{flagTypeId()} and \l{QtVariantPropertyManager::groupTypeId()}{groupTypeId()}. \sa valueType() */ int QtVariantProperty::propertyType() const { return d_ptr->manager->propertyType(this); } bool QtVariantProperty::compare(QtProperty* otherProperty)const { bool baseEqual = QtProperty::compare(otherProperty); if (!baseEqual) { return false; } const QtVariantProperty* otherVariantProperty = dynamic_cast(otherProperty); return (this->value() == otherVariantProperty->value() && this->valueType() == otherVariantProperty->valueType()); } /*! Sets the value of this property to \a value. The specified \a value must be of the type returned by valueType(), or of a type that can be converted to valueType() using the QVariant::canConvert() function; otherwise this function does nothing. \sa value() */ void QtVariantProperty::setValue(const QVariant &value) { d_ptr->manager->setValue(this, value); } /*! Sets the \a attribute of property to \a value. QtVariantPropertyManager provides the related \l{QtVariantPropertyManager::setAttribute()}{setAttribute()} function. \sa attributeValue() */ void QtVariantProperty::setAttribute(const QString &attribute, const QVariant &value) { d_ptr->manager->setAttribute(this, attribute, value); } class QtVariantPropertyManagerPrivate { QtVariantPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtVariantPropertyManager) public: QtVariantPropertyManagerPrivate(); bool m_creatingProperty; bool m_creatingSubProperties; bool m_destroyingSubProperties; int m_propertyType; void slotValueChanged(QtProperty *property, int val); void slotRangeChanged(QtProperty *property, int min, int max); void slotSingleStepChanged(QtProperty *property, int step); void slotValueChanged(QtProperty *property, double val); void slotRangeChanged(QtProperty *property, double min, double max); void slotSingleStepChanged(QtProperty *property, double step); void slotDecimalsChanged(QtProperty *property, int prec); void slotValueChanged(QtProperty *property, bool val); void slotValueChanged(QtProperty *property, const QString &val); void slotRegExpChanged(QtProperty *property, const QRegExp ®Exp); void slotValueChanged(QtProperty *property, const QDate &val); void slotRangeChanged(QtProperty *property, const QDate &min, const QDate &max); void slotValueChanged(QtProperty *property, const QTime &val); void slotValueChanged(QtProperty *property, const QDateTime &val); void slotValueChanged(QtProperty *property, const QKeySequence &val); void slotValueChanged(QtProperty *property, const QChar &val); void slotValueChanged(QtProperty *property, const QLocale &val); void slotValueChanged(QtProperty *property, const QPoint &val); void slotValueChanged(QtProperty *property, const QPointF &val); void slotValueChanged(QtProperty *property, const QSize &val); void slotRangeChanged(QtProperty *property, const QSize &min, const QSize &max); void slotValueChanged(QtProperty *property, const QSizeF &val); void slotRangeChanged(QtProperty *property, const QSizeF &min, const QSizeF &max); void slotValueChanged(QtProperty *property, const QRect &val); void slotConstraintChanged(QtProperty *property, const QRect &val); void slotValueChanged(QtProperty *property, const QRectF &val); void slotConstraintChanged(QtProperty *property, const QRectF &val); void slotValueChanged(QtProperty *property, const QColor &val); void slotEnumChanged(QtProperty *property, int val); void slotEnumNamesChanged(QtProperty *property, const QStringList &enumNames); void slotEnumIconsChanged(QtProperty *property, const QMap &enumIcons); void slotValueChanged(QtProperty *property, const QSizePolicy &val); void slotValueChanged(QtProperty *property, const QFont &val); void slotValueChanged(QtProperty *property, const QCursor &val); void slotFlagChanged(QtProperty *property, int val); void slotFlagNamesChanged(QtProperty *property, const QStringList &flagNames); void slotPropertyInserted(QtProperty *property, QtProperty *parent, QtProperty *after); void slotPropertyRemoved(QtProperty *property, QtProperty *parent); void valueChanged(QtProperty *property, const QVariant &val); int internalPropertyToType(QtProperty *property) const; QtVariantProperty *createSubProperty(QtVariantProperty *parent, QtVariantProperty *after, QtProperty *internal); void removeSubProperty(QtVariantProperty *property); QMap m_typeToPropertyManager; QMap > m_typeToAttributeToAttributeType; QMap > m_propertyToType; QMap m_typeToValueType; QMap m_internalToProperty; const QString m_constraintAttribute; const QString m_singleStepAttribute; const QString m_decimalsAttribute; const QString m_enumIconsAttribute; const QString m_enumNamesAttribute; const QString m_flagNamesAttribute; const QString m_maximumAttribute; const QString m_minimumAttribute; const QString m_regExpAttribute; }; QtVariantPropertyManagerPrivate::QtVariantPropertyManagerPrivate() : m_constraintAttribute(QLatin1String("constraint")), m_singleStepAttribute(QLatin1String("singleStep")), m_decimalsAttribute(QLatin1String("decimals")), m_enumIconsAttribute(QLatin1String("enumIcons")), m_enumNamesAttribute(QLatin1String("enumNames")), m_flagNamesAttribute(QLatin1String("flagNames")), m_maximumAttribute(QLatin1String("maximum")), m_minimumAttribute(QLatin1String("minimum")), m_regExpAttribute(QLatin1String("regExp")) { } int QtVariantPropertyManagerPrivate::internalPropertyToType(QtProperty *property) const { int type = 0; QtAbstractPropertyManager *internPropertyManager = property->propertyManager(); if (qobject_cast(internPropertyManager)) type = QVariant::Int; else if (qobject_cast(internPropertyManager)) type = QtVariantPropertyManager::enumTypeId(); else if (qobject_cast(internPropertyManager)) type = QVariant::Bool; else if (qobject_cast(internPropertyManager)) type = QVariant::Double; return type; } QtVariantProperty *QtVariantPropertyManagerPrivate::createSubProperty(QtVariantProperty *parent, QtVariantProperty *after, QtProperty *internal) { int type = internalPropertyToType(internal); if (!type) return 0; bool wasCreatingSubProperties = m_creatingSubProperties; m_creatingSubProperties = true; QtVariantProperty *varChild = q_ptr->addProperty(type, internal->propertyName()); m_creatingSubProperties = wasCreatingSubProperties; varChild->setPropertyName(internal->propertyName()); varChild->setToolTip(internal->toolTip()); varChild->setStatusTip(internal->statusTip()); varChild->setWhatsThis(internal->whatsThis()); parent->insertSubProperty(varChild, after); m_internalToProperty[internal] = varChild; propertyToWrappedProperty()->insert(varChild, internal); return varChild; } void QtVariantPropertyManagerPrivate::removeSubProperty(QtVariantProperty *property) { QtProperty *internChild = wrappedProperty(property); bool wasDestroyingSubProperties = m_destroyingSubProperties; m_destroyingSubProperties = true; delete property; m_destroyingSubProperties = wasDestroyingSubProperties; m_internalToProperty.remove(internChild); propertyToWrappedProperty()->remove(property); } void QtVariantPropertyManagerPrivate::slotPropertyInserted(QtProperty *property, QtProperty *parent, QtProperty *after) { if (m_creatingProperty) return; QtVariantProperty *varParent = m_internalToProperty.value(parent, 0); if (!varParent) return; QtVariantProperty *varAfter = 0; if (after) { varAfter = m_internalToProperty.value(after, 0); if (!varAfter) return; } createSubProperty(varParent, varAfter, property); } void QtVariantPropertyManagerPrivate::slotPropertyRemoved(QtProperty *property, QtProperty *parent) { Q_UNUSED(parent) QtVariantProperty *varProperty = m_internalToProperty.value(property, 0); if (!varProperty) return; removeSubProperty(varProperty); } void QtVariantPropertyManagerPrivate::valueChanged(QtProperty *property, const QVariant &val) { QtVariantProperty *varProp = m_internalToProperty.value(property, 0); if (!varProp) return; emit q_ptr->valueChanged(varProp, val); emit q_ptr->propertyChanged(varProp); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, int val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotRangeChanged(QtProperty *property, int min, int max) { if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) { emit q_ptr->attributeChanged(varProp, m_minimumAttribute, QVariant(min)); emit q_ptr->attributeChanged(varProp, m_maximumAttribute, QVariant(max)); } } void QtVariantPropertyManagerPrivate::slotSingleStepChanged(QtProperty *property, int step) { if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) emit q_ptr->attributeChanged(varProp, m_singleStepAttribute, QVariant(step)); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, double val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotRangeChanged(QtProperty *property, double min, double max) { if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) { emit q_ptr->attributeChanged(varProp, m_minimumAttribute, QVariant(min)); emit q_ptr->attributeChanged(varProp, m_maximumAttribute, QVariant(max)); } } void QtVariantPropertyManagerPrivate::slotSingleStepChanged(QtProperty *property, double step) { if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) emit q_ptr->attributeChanged(varProp, m_singleStepAttribute, QVariant(step)); } void QtVariantPropertyManagerPrivate::slotDecimalsChanged(QtProperty *property, int prec) { if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) emit q_ptr->attributeChanged(varProp, m_decimalsAttribute, QVariant(prec)); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, bool val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QString &val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotRegExpChanged(QtProperty *property, const QRegExp ®Exp) { if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) emit q_ptr->attributeChanged(varProp, m_regExpAttribute, QVariant(regExp)); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QDate &val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotRangeChanged(QtProperty *property, const QDate &min, const QDate &max) { if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) { emit q_ptr->attributeChanged(varProp, m_minimumAttribute, QVariant(min)); emit q_ptr->attributeChanged(varProp, m_maximumAttribute, QVariant(max)); } } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QTime &val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QDateTime &val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QKeySequence &val) { QVariant v; v.setValue(val); valueChanged(property, v); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QChar &val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QLocale &val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QPoint &val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QPointF &val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QSize &val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotRangeChanged(QtProperty *property, const QSize &min, const QSize &max) { if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) { emit q_ptr->attributeChanged(varProp, m_minimumAttribute, QVariant(min)); emit q_ptr->attributeChanged(varProp, m_maximumAttribute, QVariant(max)); } } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QSizeF &val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotRangeChanged(QtProperty *property, const QSizeF &min, const QSizeF &max) { if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) { emit q_ptr->attributeChanged(varProp, m_minimumAttribute, QVariant(min)); emit q_ptr->attributeChanged(varProp, m_maximumAttribute, QVariant(max)); } } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QRect &val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotConstraintChanged(QtProperty *property, const QRect &constraint) { if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) emit q_ptr->attributeChanged(varProp, m_constraintAttribute, QVariant(constraint)); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QRectF &val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotConstraintChanged(QtProperty *property, const QRectF &constraint) { if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) emit q_ptr->attributeChanged(varProp, m_constraintAttribute, QVariant(constraint)); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QColor &val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotEnumNamesChanged(QtProperty *property, const QStringList &enumNames) { if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) emit q_ptr->attributeChanged(varProp, m_enumNamesAttribute, QVariant(enumNames)); } void QtVariantPropertyManagerPrivate::slotEnumIconsChanged(QtProperty *property, const QMap &enumIcons) { if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) { QVariant v; v.setValue(enumIcons); emit q_ptr->attributeChanged(varProp, m_enumIconsAttribute, v); } } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QSizePolicy &val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QFont &val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QCursor &val) { #ifndef QT_NO_CURSOR valueChanged(property, QVariant(val)); #endif } void QtVariantPropertyManagerPrivate::slotFlagNamesChanged(QtProperty *property, const QStringList &flagNames) { if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) emit q_ptr->attributeChanged(varProp, m_flagNamesAttribute, QVariant(flagNames)); } /*! \class QtVariantPropertyManager \brief The QtVariantPropertyManager class provides and manages QVariant based properties. QtVariantPropertyManager provides the addProperty() function which creates QtVariantProperty objects. The QtVariantProperty class is a convenience class handling QVariant based properties inheriting QtProperty. A QtProperty object created by a QtVariantPropertyManager instance can be converted into a QtVariantProperty object using the variantProperty() function. The property's value can be retrieved using the value(), and set using the setValue() slot. In addition the property's type, and the type of its value, can be retrieved using the propertyType() and valueType() functions respectively. A property's type is a QVariant::Type enumerator value, and usually a property's type is the same as its value type. But for some properties the types differ, for example for enums, flags and group types in which case QtVariantPropertyManager provides the enumTypeId(), flagTypeId() and groupTypeId() functions, respectively, to identify their property type (the value types are QVariant::Int for the enum and flag types, and QVariant::Invalid for the group type). Use the isPropertyTypeSupported() function to check if a particular property type is supported. The currently supported property types are: \table \header \o Property Type \o Property Type Id \row \o int \o QVariant::Int \row \o double \o QVariant::Double \row \o bool \o QVariant::Bool \row \o QString \o QVariant::String \row \o QDate \o QVariant::Date \row \o QTime \o QVariant::Time \row \o QDateTime \o QVariant::DateTime \row \o QKeySequence \o QVariant::KeySequence \row \o QChar \o QVariant::Char \row \o QLocale \o QVariant::Locale \row \o QPoint \o QVariant::Point \row \o QPointF \o QVariant::PointF \row \o QSize \o QVariant::Size \row \o QSizeF \o QVariant::SizeF \row \o QRect \o QVariant::Rect \row \o QRectF \o QVariant::RectF \row \o QColor \o QVariant::Color \row \o QSizePolicy \o QVariant::SizePolicy \row \o QFont \o QVariant::Font \row \o QCursor \o QVariant::Cursor \row \o enum \o enumTypeId() \row \o flag \o flagTypeId() \row \o group \o groupTypeId() \endtable Each property type can provide additional attributes, e.g. QVariant::Int and QVariant::Double provides minimum and maximum values. The currently supported attributes are: \table \header \o Property Type \o Attribute Name \o Attribute Type \row \o \c int \o minimum \o QVariant::Int \row \o \o maximum \o QVariant::Int \row \o \o singleStep \o QVariant::Int \row \o \c double \o minimum \o QVariant::Double \row \o \o maximum \o QVariant::Double \row \o \o singleStep \o QVariant::Double \row \o \o decimals \o QVariant::Int \row \o QString \o regExp \o QVariant::RegExp \row \o QDate \o minimum \o QVariant::Date \row \o \o maximum \o QVariant::Date \row \o QPointF \o decimals \o QVariant::Int \row \o QSize \o minimum \o QVariant::Size \row \o \o maximum \o QVariant::Size \row \o QSizeF \o minimum \o QVariant::SizeF \row \o \o maximum \o QVariant::SizeF \row \o \o decimals \o QVariant::Int \row \o QRect \o constraint \o QVariant::Rect \row \o QRectF \o constraint \o QVariant::RectF \row \o \o decimals \o QVariant::Int \row \o \c enum \o enumNames \o QVariant::StringList \row \o \o enumIcons \o iconMapTypeId() \row \o \c flag \o flagNames \o QVariant::StringList \endtable The attributes for a given property type can be retrieved using the attributes() function. Each attribute has a value type which can be retrieved using the attributeType() function, and a value accessible through the attributeValue() function. In addition, the value can be set using the setAttribute() slot. QtVariantManager also provides the valueChanged() signal which is emitted whenever a property created by this manager change, and the attributeChanged() signal which is emitted whenever an attribute of such a property changes. \sa QtVariantProperty, QtVariantEditorFactory */ /*! \fn void QtVariantPropertyManager::valueChanged(QtProperty *property, const QVariant &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! \fn void QtVariantPropertyManager::attributeChanged(QtProperty *property, const QString &attribute, const QVariant &value) This signal is emitted whenever an attribute of a property created by this manager changes its value, passing a pointer to the \a property, the \a attribute and the new \a value as parameters. \sa setAttribute() */ /*! Creates a manager with the given \a parent. */ QtVariantPropertyManager::QtVariantPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtVariantPropertyManagerPrivate; d_ptr->q_ptr = this; d_ptr->m_creatingProperty = false; d_ptr->m_creatingSubProperties = false; d_ptr->m_destroyingSubProperties = false; d_ptr->m_propertyType = 0; // IntPropertyManager QtIntPropertyManager *intPropertyManager = new QtIntPropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::Int] = intPropertyManager; d_ptr->m_typeToAttributeToAttributeType[QVariant::Int][d_ptr->m_minimumAttribute] = QVariant::Int; d_ptr->m_typeToAttributeToAttributeType[QVariant::Int][d_ptr->m_maximumAttribute] = QVariant::Int; d_ptr->m_typeToAttributeToAttributeType[QVariant::Int][d_ptr->m_singleStepAttribute] = QVariant::Int; d_ptr->m_typeToValueType[QVariant::Int] = QVariant::Int; connect(intPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotValueChanged(QtProperty *, int))); connect(intPropertyManager, SIGNAL(rangeChanged(QtProperty *, int, int)), this, SLOT(slotRangeChanged(QtProperty *, int, int))); connect(intPropertyManager, SIGNAL(singleStepChanged(QtProperty *, int)), this, SLOT(slotSingleStepChanged(QtProperty *, int))); // DoublePropertyManager QtDoublePropertyManager *doublePropertyManager = new QtDoublePropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::Double] = doublePropertyManager; d_ptr->m_typeToAttributeToAttributeType[QVariant::Double][d_ptr->m_minimumAttribute] = QVariant::Double; d_ptr->m_typeToAttributeToAttributeType[QVariant::Double][d_ptr->m_maximumAttribute] = QVariant::Double; d_ptr->m_typeToAttributeToAttributeType[QVariant::Double][d_ptr->m_singleStepAttribute] = QVariant::Double; d_ptr->m_typeToAttributeToAttributeType[QVariant::Double][d_ptr->m_decimalsAttribute] = QVariant::Int; d_ptr->m_typeToValueType[QVariant::Double] = QVariant::Double; connect(doublePropertyManager, SIGNAL(valueChanged(QtProperty *, double)), this, SLOT(slotValueChanged(QtProperty *, double))); connect(doublePropertyManager, SIGNAL(rangeChanged(QtProperty *, double, double)), this, SLOT(slotRangeChanged(QtProperty *, double, double))); connect(doublePropertyManager, SIGNAL(singleStepChanged(QtProperty *, double)), this, SLOT(slotSingleStepChanged(QtProperty *, double))); connect(doublePropertyManager, SIGNAL(decimalsChanged(QtProperty *, int)), this, SLOT(slotDecimalsChanged(QtProperty *, int))); // BoolPropertyManager QtBoolPropertyManager *boolPropertyManager = new QtBoolPropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::Bool] = boolPropertyManager; d_ptr->m_typeToValueType[QVariant::Bool] = QVariant::Bool; connect(boolPropertyManager, SIGNAL(valueChanged(QtProperty *, bool)), this, SLOT(slotValueChanged(QtProperty *, bool))); // StringPropertyManager QtStringPropertyManager *stringPropertyManager = new QtStringPropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::String] = stringPropertyManager; d_ptr->m_typeToValueType[QVariant::String] = QVariant::String; d_ptr->m_typeToAttributeToAttributeType[QVariant::String][d_ptr->m_regExpAttribute] = QVariant::RegExp; connect(stringPropertyManager, SIGNAL(valueChanged(QtProperty *, const QString &)), this, SLOT(slotValueChanged(QtProperty *, const QString &))); connect(stringPropertyManager, SIGNAL(regExpChanged(QtProperty *, const QRegExp &)), this, SLOT(slotRegExpChanged(QtProperty *, const QRegExp &))); // DatePropertyManager QtDatePropertyManager *datePropertyManager = new QtDatePropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::Date] = datePropertyManager; d_ptr->m_typeToValueType[QVariant::Date] = QVariant::Date; d_ptr->m_typeToAttributeToAttributeType[QVariant::Date][d_ptr->m_minimumAttribute] = QVariant::Date; d_ptr->m_typeToAttributeToAttributeType[QVariant::Date][d_ptr->m_maximumAttribute] = QVariant::Date; connect(datePropertyManager, SIGNAL(valueChanged(QtProperty *, const QDate &)), this, SLOT(slotValueChanged(QtProperty *, const QDate &))); connect(datePropertyManager, SIGNAL(rangeChanged(QtProperty *, const QDate &, const QDate &)), this, SLOT(slotRangeChanged(QtProperty *, const QDate &, const QDate &))); // TimePropertyManager QtTimePropertyManager *timePropertyManager = new QtTimePropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::Time] = timePropertyManager; d_ptr->m_typeToValueType[QVariant::Time] = QVariant::Time; connect(timePropertyManager, SIGNAL(valueChanged(QtProperty *, const QTime &)), this, SLOT(slotValueChanged(QtProperty *, const QTime &))); // DateTimePropertyManager QtDateTimePropertyManager *dateTimePropertyManager = new QtDateTimePropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::DateTime] = dateTimePropertyManager; d_ptr->m_typeToValueType[QVariant::DateTime] = QVariant::DateTime; connect(dateTimePropertyManager, SIGNAL(valueChanged(QtProperty *, const QDateTime &)), this, SLOT(slotValueChanged(QtProperty *, const QDateTime &))); // KeySequencePropertyManager QtKeySequencePropertyManager *keySequencePropertyManager = new QtKeySequencePropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::KeySequence] = keySequencePropertyManager; d_ptr->m_typeToValueType[QVariant::KeySequence] = QVariant::KeySequence; connect(keySequencePropertyManager, SIGNAL(valueChanged(QtProperty *, const QKeySequence &)), this, SLOT(slotValueChanged(QtProperty *, const QKeySequence &))); // CharPropertyManager QtCharPropertyManager *charPropertyManager = new QtCharPropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::Char] = charPropertyManager; d_ptr->m_typeToValueType[QVariant::Char] = QVariant::Char; connect(charPropertyManager, SIGNAL(valueChanged(QtProperty *, const QChar &)), this, SLOT(slotValueChanged(QtProperty *, const QChar &))); // LocalePropertyManager QtLocalePropertyManager *localePropertyManager = new QtLocalePropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::Locale] = localePropertyManager; d_ptr->m_typeToValueType[QVariant::Locale] = QVariant::Locale; connect(localePropertyManager, SIGNAL(valueChanged(QtProperty *, const QLocale &)), this, SLOT(slotValueChanged(QtProperty *, const QLocale &))); connect(localePropertyManager->subEnumPropertyManager(), SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotValueChanged(QtProperty *, int))); connect(localePropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); connect(localePropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); // PointPropertyManager QtPointPropertyManager *pointPropertyManager = new QtPointPropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::Point] = pointPropertyManager; d_ptr->m_typeToValueType[QVariant::Point] = QVariant::Point; connect(pointPropertyManager, SIGNAL(valueChanged(QtProperty *, const QPoint &)), this, SLOT(slotValueChanged(QtProperty *, const QPoint &))); connect(pointPropertyManager->subIntPropertyManager(), SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotValueChanged(QtProperty *, int))); connect(pointPropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); connect(pointPropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); // PointFPropertyManager QtPointFPropertyManager *pointFPropertyManager = new QtPointFPropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::PointF] = pointFPropertyManager; d_ptr->m_typeToValueType[QVariant::PointF] = QVariant::PointF; d_ptr->m_typeToAttributeToAttributeType[QVariant::PointF][d_ptr->m_decimalsAttribute] = QVariant::Int; connect(pointFPropertyManager, SIGNAL(valueChanged(QtProperty *, const QPointF &)), this, SLOT(slotValueChanged(QtProperty *, const QPointF &))); connect(pointFPropertyManager, SIGNAL(decimalsChanged(QtProperty *, int)), this, SLOT(slotDecimalsChanged(QtProperty *, int))); connect(pointFPropertyManager->subDoublePropertyManager(), SIGNAL(valueChanged(QtProperty *, double)), this, SLOT(slotValueChanged(QtProperty *, double))); connect(pointFPropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); connect(pointFPropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); // SizePropertyManager QtSizePropertyManager *sizePropertyManager = new QtSizePropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::Size] = sizePropertyManager; d_ptr->m_typeToValueType[QVariant::Size] = QVariant::Size; d_ptr->m_typeToAttributeToAttributeType[QVariant::Size][d_ptr->m_minimumAttribute] = QVariant::Size; d_ptr->m_typeToAttributeToAttributeType[QVariant::Size][d_ptr->m_maximumAttribute] = QVariant::Size; connect(sizePropertyManager, SIGNAL(valueChanged(QtProperty *, const QSize &)), this, SLOT(slotValueChanged(QtProperty *, const QSize &))); connect(sizePropertyManager, SIGNAL(rangeChanged(QtProperty *, const QSize &, const QSize &)), this, SLOT(slotRangeChanged(QtProperty *, const QSize &, const QSize &))); connect(sizePropertyManager->subIntPropertyManager(), SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotValueChanged(QtProperty *, int))); connect(sizePropertyManager->subIntPropertyManager(), SIGNAL(rangeChanged(QtProperty *, int, int)), this, SLOT(slotRangeChanged(QtProperty *, int, int))); connect(sizePropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); connect(sizePropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); // SizeFPropertyManager QtSizeFPropertyManager *sizeFPropertyManager = new QtSizeFPropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::SizeF] = sizeFPropertyManager; d_ptr->m_typeToValueType[QVariant::SizeF] = QVariant::SizeF; d_ptr->m_typeToAttributeToAttributeType[QVariant::SizeF][d_ptr->m_minimumAttribute] = QVariant::SizeF; d_ptr->m_typeToAttributeToAttributeType[QVariant::SizeF][d_ptr->m_maximumAttribute] = QVariant::SizeF; d_ptr->m_typeToAttributeToAttributeType[QVariant::SizeF][d_ptr->m_decimalsAttribute] = QVariant::Int; connect(sizeFPropertyManager, SIGNAL(valueChanged(QtProperty *, const QSizeF &)), this, SLOT(slotValueChanged(QtProperty *, const QSizeF &))); connect(sizeFPropertyManager, SIGNAL(rangeChanged(QtProperty *, const QSizeF &, const QSizeF &)), this, SLOT(slotRangeChanged(QtProperty *, const QSizeF &, const QSizeF &))); connect(sizeFPropertyManager, SIGNAL(decimalsChanged(QtProperty *, int)), this, SLOT(slotDecimalsChanged(QtProperty *, int))); connect(sizeFPropertyManager->subDoublePropertyManager(), SIGNAL(valueChanged(QtProperty *, double)), this, SLOT(slotValueChanged(QtProperty *, double))); connect(sizeFPropertyManager->subDoublePropertyManager(), SIGNAL(rangeChanged(QtProperty *, double, double)), this, SLOT(slotRangeChanged(QtProperty *, double, double))); connect(sizeFPropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); connect(sizeFPropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); // RectPropertyManager QtRectPropertyManager *rectPropertyManager = new QtRectPropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::Rect] = rectPropertyManager; d_ptr->m_typeToValueType[QVariant::Rect] = QVariant::Rect; d_ptr->m_typeToAttributeToAttributeType[QVariant::Rect][d_ptr->m_constraintAttribute] = QVariant::Rect; connect(rectPropertyManager, SIGNAL(valueChanged(QtProperty *, const QRect &)), this, SLOT(slotValueChanged(QtProperty *, const QRect &))); connect(rectPropertyManager, SIGNAL(constraintChanged(QtProperty *, const QRect &)), this, SLOT(slotConstraintChanged(QtProperty *, const QRect &))); connect(rectPropertyManager->subIntPropertyManager(), SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotValueChanged(QtProperty *, int))); connect(rectPropertyManager->subIntPropertyManager(), SIGNAL(rangeChanged(QtProperty *, int, int)), this, SLOT(slotRangeChanged(QtProperty *, int, int))); connect(rectPropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); connect(rectPropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); // RectFPropertyManager QtRectFPropertyManager *rectFPropertyManager = new QtRectFPropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::RectF] = rectFPropertyManager; d_ptr->m_typeToValueType[QVariant::RectF] = QVariant::RectF; d_ptr->m_typeToAttributeToAttributeType[QVariant::RectF][d_ptr->m_constraintAttribute] = QVariant::RectF; d_ptr->m_typeToAttributeToAttributeType[QVariant::RectF][d_ptr->m_decimalsAttribute] = QVariant::Int; connect(rectFPropertyManager, SIGNAL(valueChanged(QtProperty *, const QRectF &)), this, SLOT(slotValueChanged(QtProperty *, const QRectF &))); connect(rectFPropertyManager, SIGNAL(constraintChanged(QtProperty *, const QRectF &)), this, SLOT(slotConstraintChanged(QtProperty *, const QRectF &))); connect(rectFPropertyManager, SIGNAL(decimalsChanged(QtProperty *, int)), this, SLOT(slotDecimalsChanged(QtProperty *, int))); connect(rectFPropertyManager->subDoublePropertyManager(), SIGNAL(valueChanged(QtProperty *, double)), this, SLOT(slotValueChanged(QtProperty *, double))); connect(rectFPropertyManager->subDoublePropertyManager(), SIGNAL(rangeChanged(QtProperty *, double, double)), this, SLOT(slotRangeChanged(QtProperty *, double, double))); connect(rectFPropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); connect(rectFPropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); // ColorPropertyManager QtColorPropertyManager *colorPropertyManager = new QtColorPropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::Color] = colorPropertyManager; d_ptr->m_typeToValueType[QVariant::Color] = QVariant::Color; connect(colorPropertyManager, SIGNAL(valueChanged(QtProperty *, const QColor &)), this, SLOT(slotValueChanged(QtProperty *, const QColor &))); connect(colorPropertyManager->subIntPropertyManager(), SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotValueChanged(QtProperty *, int))); connect(colorPropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); connect(colorPropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); // EnumPropertyManager int enumId = enumTypeId(); QtEnumPropertyManager *enumPropertyManager = new QtEnumPropertyManager(this); d_ptr->m_typeToPropertyManager[enumId] = enumPropertyManager; d_ptr->m_typeToValueType[enumId] = QVariant::Int; d_ptr->m_typeToAttributeToAttributeType[enumId][d_ptr->m_enumNamesAttribute] = QVariant::StringList; d_ptr->m_typeToAttributeToAttributeType[enumId][d_ptr->m_enumIconsAttribute] = iconMapTypeId(); connect(enumPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotValueChanged(QtProperty *, int))); connect(enumPropertyManager, SIGNAL(enumNamesChanged(QtProperty *, const QStringList &)), this, SLOT(slotEnumNamesChanged(QtProperty *, const QStringList &))); connect(enumPropertyManager, SIGNAL(enumIconsChanged(QtProperty *, const QMap &)), this, SLOT(slotEnumIconsChanged(QtProperty *, const QMap &))); // SizePolicyPropertyManager QtSizePolicyPropertyManager *sizePolicyPropertyManager = new QtSizePolicyPropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::SizePolicy] = sizePolicyPropertyManager; d_ptr->m_typeToValueType[QVariant::SizePolicy] = QVariant::SizePolicy; connect(sizePolicyPropertyManager, SIGNAL(valueChanged(QtProperty *, const QSizePolicy &)), this, SLOT(slotValueChanged(QtProperty *, const QSizePolicy &))); connect(sizePolicyPropertyManager->subIntPropertyManager(), SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotValueChanged(QtProperty *, int))); connect(sizePolicyPropertyManager->subIntPropertyManager(), SIGNAL(rangeChanged(QtProperty *, int, int)), this, SLOT(slotRangeChanged(QtProperty *, int, int))); connect(sizePolicyPropertyManager->subEnumPropertyManager(), SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotValueChanged(QtProperty *, int))); connect(sizePolicyPropertyManager->subEnumPropertyManager(), SIGNAL(enumNamesChanged(QtProperty *, const QStringList &)), this, SLOT(slotEnumNamesChanged(QtProperty *, const QStringList &))); connect(sizePolicyPropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); connect(sizePolicyPropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); // FontPropertyManager QtFontPropertyManager *fontPropertyManager = new QtFontPropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::Font] = fontPropertyManager; d_ptr->m_typeToValueType[QVariant::Font] = QVariant::Font; connect(fontPropertyManager, SIGNAL(valueChanged(QtProperty *, const QFont &)), this, SLOT(slotValueChanged(QtProperty *, const QFont &))); connect(fontPropertyManager->subIntPropertyManager(), SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotValueChanged(QtProperty *, int))); connect(fontPropertyManager->subIntPropertyManager(), SIGNAL(rangeChanged(QtProperty *, int, int)), this, SLOT(slotRangeChanged(QtProperty *, int, int))); connect(fontPropertyManager->subEnumPropertyManager(), SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotValueChanged(QtProperty *, int))); connect(fontPropertyManager->subEnumPropertyManager(), SIGNAL(enumNamesChanged(QtProperty *, const QStringList &)), this, SLOT(slotEnumNamesChanged(QtProperty *, const QStringList &))); connect(fontPropertyManager->subBoolPropertyManager(), SIGNAL(valueChanged(QtProperty *, bool)), this, SLOT(slotValueChanged(QtProperty *, bool))); connect(fontPropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); connect(fontPropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); // CursorPropertyManager QtCursorPropertyManager *cursorPropertyManager = new QtCursorPropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::Cursor] = cursorPropertyManager; d_ptr->m_typeToValueType[QVariant::Cursor] = QVariant::Cursor; connect(cursorPropertyManager, SIGNAL(valueChanged(QtProperty *, const QCursor &)), this, SLOT(slotValueChanged(QtProperty *, const QCursor &))); // FlagPropertyManager int flagId = flagTypeId(); QtFlagPropertyManager *flagPropertyManager = new QtFlagPropertyManager(this); d_ptr->m_typeToPropertyManager[flagId] = flagPropertyManager; d_ptr->m_typeToValueType[flagId] = QVariant::Int; d_ptr->m_typeToAttributeToAttributeType[flagId][d_ptr->m_flagNamesAttribute] = QVariant::StringList; connect(flagPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotValueChanged(QtProperty *, int))); connect(flagPropertyManager, SIGNAL(flagNamesChanged(QtProperty *, const QStringList &)), this, SLOT(slotFlagNamesChanged(QtProperty *, const QStringList &))); connect(flagPropertyManager->subBoolPropertyManager(), SIGNAL(valueChanged(QtProperty *, bool)), this, SLOT(slotValueChanged(QtProperty *, bool))); connect(flagPropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); connect(flagPropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); // FlagPropertyManager int groupId = groupTypeId(); QtGroupPropertyManager *groupPropertyManager = new QtGroupPropertyManager(this); d_ptr->m_typeToPropertyManager[groupId] = groupPropertyManager; d_ptr->m_typeToValueType[groupId] = QVariant::Invalid; } /*! Destroys this manager, and all the properties it has created. */ QtVariantPropertyManager::~QtVariantPropertyManager() { clear(); delete d_ptr; } /*! Returns the given \a property converted into a QtVariantProperty. If the \a property was not created by this variant manager, the function returns 0. \sa createProperty() */ QtVariantProperty *QtVariantPropertyManager::variantProperty(const QtProperty *property) const { const QMap >::const_iterator it = d_ptr->m_propertyToType.constFind(property); if (it == d_ptr->m_propertyToType.constEnd()) return 0; return it.value().first; } /*! Returns true if the given \a propertyType is supported by this variant manager; otherwise false. \sa propertyType() */ bool QtVariantPropertyManager::isPropertyTypeSupported(int propertyType) const { if (d_ptr->m_typeToValueType.contains(propertyType)) return true; return false; } /*! Creates and returns a variant property of the given \a propertyType with the given \a name. If the specified \a propertyType is not supported by this variant manager, this function returns 0. Do not use the inherited QtAbstractPropertyManager::addProperty() function to create a variant property (that function will always return 0 since it will not be clear what type the property should have). \sa isPropertyTypeSupported() */ QtVariantProperty *QtVariantPropertyManager::addProperty(int propertyType, const QString &name) { if (!isPropertyTypeSupported(propertyType)) return 0; bool wasCreating = d_ptr->m_creatingProperty; d_ptr->m_creatingProperty = true; d_ptr->m_propertyType = propertyType; QtProperty *property = QtAbstractPropertyManager::addProperty(name); d_ptr->m_creatingProperty = wasCreating; d_ptr->m_propertyType = 0; if (!property) return 0; return variantProperty(property); } namespace{ void addPropertyRecusively(QtVariantPropertyManager * manager, QtVariantProperty * prop, QtVariantProperty * newProp = 0) { if (!newProp) { newProp = manager->addProperty(prop->propertyType(), prop->propertyName()); } // Copy values QStringList attributes = manager->attributes(prop->propertyType()); foreach(const QString& attribute, attributes) { newProp->setAttribute(attribute, prop->attributeValue(attribute)); } newProp->setPropertyId(prop->propertyId()); newProp->setStatusTip(prop->statusTip()); newProp->setWhatsThis(prop->whatsThis()); newProp->setModified(prop->isModified()); newProp->setEnabled(prop->isEnabled()); newProp->setSelectable(prop->isSelectable()); newProp->setValue(prop->value()); foreach(QtProperty * subProp, prop->subProperties()) { QtVariantProperty * variantSubProp = dynamic_cast(subProp); Q_ASSERT(variantSubProp); QtVariantProperty * newVariantSubProp = manager->addProperty(variantSubProp->propertyType(), variantSubProp->propertyName()); newProp->addSubProperty(newVariantSubProp); addPropertyRecusively(manager, variantSubProp, newVariantSubProp); } } } /*! Set properties used by this manager. \sa properties(), addProperty() */ void QtVariantPropertyManager::setProperties(QSet properties) { this->clear(); foreach(QtProperty * prop, properties) { QtVariantProperty * variantProp = dynamic_cast(prop); if (!variantProp){ continue; } if (!variantProp->isSubProperty()) { addPropertyRecusively(this, variantProp); } } } /*! Returns the given \a property's value. If the given \a property is not managed by this manager, this function returns an invalid variant. \sa setValue() */ QVariant QtVariantPropertyManager::value(const QtProperty *property) const { QtProperty *internProp = propertyToWrappedProperty()->value(property, 0); if (internProp == 0) return QVariant(); QtAbstractPropertyManager *manager = internProp->propertyManager(); if (QtIntPropertyManager *intManager = qobject_cast(manager)) { return intManager->value(internProp); } else if (QtDoublePropertyManager *doubleManager = qobject_cast(manager)) { return doubleManager->value(internProp); } else if (QtBoolPropertyManager *boolManager = qobject_cast(manager)) { return boolManager->value(internProp); } else if (QtStringPropertyManager *stringManager = qobject_cast(manager)) { return stringManager->value(internProp); } else if (QtDatePropertyManager *dateManager = qobject_cast(manager)) { return dateManager->value(internProp); } else if (QtTimePropertyManager *timeManager = qobject_cast(manager)) { return timeManager->value(internProp); } else if (QtDateTimePropertyManager *dateTimeManager = qobject_cast(manager)) { return dateTimeManager->value(internProp); } else if (QtKeySequencePropertyManager *keySequenceManager = qobject_cast(manager)) { return keySequenceManager->value(internProp); } else if (QtCharPropertyManager *charManager = qobject_cast(manager)) { return charManager->value(internProp); } else if (QtLocalePropertyManager *localeManager = qobject_cast(manager)) { return localeManager->value(internProp); } else if (QtPointPropertyManager *pointManager = qobject_cast(manager)) { return pointManager->value(internProp); } else if (QtPointFPropertyManager *pointFManager = qobject_cast(manager)) { return pointFManager->value(internProp); } else if (QtSizePropertyManager *sizeManager = qobject_cast(manager)) { return sizeManager->value(internProp); } else if (QtSizeFPropertyManager *sizeFManager = qobject_cast(manager)) { return sizeFManager->value(internProp); } else if (QtRectPropertyManager *rectManager = qobject_cast(manager)) { return rectManager->value(internProp); } else if (QtRectFPropertyManager *rectFManager = qobject_cast(manager)) { return rectFManager->value(internProp); } else if (QtColorPropertyManager *colorManager = qobject_cast(manager)) { return colorManager->value(internProp); } else if (QtEnumPropertyManager *enumManager = qobject_cast(manager)) { return enumManager->value(internProp); } else if (QtSizePolicyPropertyManager *sizePolicyManager = qobject_cast(manager)) { return sizePolicyManager->value(internProp); } else if (QtFontPropertyManager *fontManager = qobject_cast(manager)) { return fontManager->value(internProp); #ifndef QT_NO_CURSOR } else if (QtCursorPropertyManager *cursorManager = qobject_cast(manager)) { return cursorManager->value(internProp); #endif } else if (QtFlagPropertyManager *flagManager = qobject_cast(manager)) { return flagManager->value(internProp); } return QVariant(); } /*! Returns the given \a property's value type. \sa propertyType() */ int QtVariantPropertyManager::valueType(const QtProperty *property) const { int propType = propertyType(property); return valueType(propType); } /*! \overload Returns the value type associated with the given \a propertyType. */ int QtVariantPropertyManager::valueType(int propertyType) const { if (d_ptr->m_typeToValueType.contains(propertyType)) return d_ptr->m_typeToValueType[propertyType]; return 0; } /*! Returns the given \a property's type. \sa valueType() */ int QtVariantPropertyManager::propertyType(const QtProperty *property) const { const QMap >::const_iterator it = d_ptr->m_propertyToType.constFind(property); if (it == d_ptr->m_propertyToType.constEnd()) return 0; return it.value().second; } /*! Returns the given \a property's value for the specified \a attribute If the given \a property was not created by \e this manager, or if the specified \a attribute does not exist, this function returns an invalid variant. \sa attributes(), attributeType(), setAttribute() */ QVariant QtVariantPropertyManager::attributeValue(const QtProperty *property, const QString &attribute) const { int propType = propertyType(property); if (!propType) return QVariant(); QMap >::ConstIterator it = d_ptr->m_typeToAttributeToAttributeType.find(propType); if (it == d_ptr->m_typeToAttributeToAttributeType.constEnd()) return QVariant(); QMap attributes = it.value(); QMap::ConstIterator itAttr = attributes.find(attribute); if (itAttr == attributes.constEnd()) return QVariant(); QtProperty *internProp = propertyToWrappedProperty()->value(property, 0); if (internProp == 0) return QVariant(); QtAbstractPropertyManager *manager = internProp->propertyManager(); if (QtIntPropertyManager *intManager = qobject_cast(manager)) { if (attribute == d_ptr->m_maximumAttribute) return intManager->maximum(internProp); if (attribute == d_ptr->m_minimumAttribute) return intManager->minimum(internProp); if (attribute == d_ptr->m_singleStepAttribute) return intManager->singleStep(internProp); return QVariant(); } else if (QtDoublePropertyManager *doubleManager = qobject_cast(manager)) { if (attribute == d_ptr->m_maximumAttribute) return doubleManager->maximum(internProp); if (attribute == d_ptr->m_minimumAttribute) return doubleManager->minimum(internProp); if (attribute == d_ptr->m_singleStepAttribute) return doubleManager->singleStep(internProp); if (attribute == d_ptr->m_decimalsAttribute) return doubleManager->decimals(internProp); return QVariant(); } else if (QtStringPropertyManager *stringManager = qobject_cast(manager)) { if (attribute == d_ptr->m_regExpAttribute) return stringManager->regExp(internProp); return QVariant(); } else if (QtDatePropertyManager *dateManager = qobject_cast(manager)) { if (attribute == d_ptr->m_maximumAttribute) return dateManager->maximum(internProp); if (attribute == d_ptr->m_minimumAttribute) return dateManager->minimum(internProp); return QVariant(); } else if (QtPointFPropertyManager *pointFManager = qobject_cast(manager)) { if (attribute == d_ptr->m_decimalsAttribute) return pointFManager->decimals(internProp); return QVariant(); } else if (QtSizePropertyManager *sizeManager = qobject_cast(manager)) { if (attribute == d_ptr->m_maximumAttribute) return sizeManager->maximum(internProp); if (attribute == d_ptr->m_minimumAttribute) return sizeManager->minimum(internProp); return QVariant(); } else if (QtSizeFPropertyManager *sizeFManager = qobject_cast(manager)) { if (attribute == d_ptr->m_maximumAttribute) return sizeFManager->maximum(internProp); if (attribute == d_ptr->m_minimumAttribute) return sizeFManager->minimum(internProp); if (attribute == d_ptr->m_decimalsAttribute) return sizeFManager->decimals(internProp); return QVariant(); } else if (QtRectPropertyManager *rectManager = qobject_cast(manager)) { if (attribute == d_ptr->m_constraintAttribute) return rectManager->constraint(internProp); return QVariant(); } else if (QtRectFPropertyManager *rectFManager = qobject_cast(manager)) { if (attribute == d_ptr->m_constraintAttribute) return rectFManager->constraint(internProp); if (attribute == d_ptr->m_decimalsAttribute) return rectFManager->decimals(internProp); return QVariant(); } else if (QtEnumPropertyManager *enumManager = qobject_cast(manager)) { if (attribute == d_ptr->m_enumNamesAttribute) return enumManager->enumNames(internProp); if (attribute == d_ptr->m_enumIconsAttribute) { QVariant v; v.setValue(enumManager->enumIcons(internProp)); return v; } return QVariant(); } else if (QtFlagPropertyManager *flagManager = qobject_cast(manager)) { if (attribute == d_ptr->m_flagNamesAttribute) return flagManager->flagNames(internProp); return QVariant(); } return QVariant(); } /*! Returns a list of the given \a propertyType 's attributes. \sa attributeValue(), attributeType() */ QStringList QtVariantPropertyManager::attributes(int propertyType) const { QMap >::ConstIterator it = d_ptr->m_typeToAttributeToAttributeType.find(propertyType); if (it == d_ptr->m_typeToAttributeToAttributeType.constEnd()) return QStringList(); return it.value().keys(); } /*! Returns the type of the specified \a attribute of the given \a propertyType. If the given \a propertyType is not supported by \e this manager, or if the given \a propertyType does not possess the specified \a attribute, this function returns QVariant::Invalid. \sa attributes(), valueType() */ int QtVariantPropertyManager::attributeType(int propertyType, const QString &attribute) const { QMap >::ConstIterator it = d_ptr->m_typeToAttributeToAttributeType.find(propertyType); if (it == d_ptr->m_typeToAttributeToAttributeType.constEnd()) return 0; QMap attributes = it.value(); QMap::ConstIterator itAttr = attributes.find(attribute); if (itAttr == attributes.constEnd()) return 0; return itAttr.value(); } /*! \fn void QtVariantPropertyManager::setValue(QtProperty *property, const QVariant &value) Sets the value of the given \a property to \a value. The specified \a value must be of a type returned by valueType(), or of type that can be converted to valueType() using the QVariant::canConvert() function, otherwise this function does nothing. \sa value(), QtVariantProperty::setValue(), valueChanged() */ void QtVariantPropertyManager::setValue(QtProperty *property, const QVariant &val) { int propType = val.userType(); if (!propType) return; int valType = valueType(property); if (propType != valType && !val.canConvert(static_cast(valType))) return; QtProperty *internProp = propertyToWrappedProperty()->value(property, 0); if (internProp == 0) return; QtAbstractPropertyManager *manager = internProp->propertyManager(); if (QtIntPropertyManager *intManager = qobject_cast(manager)) { intManager->setValue(internProp, val.value()); return; } else if (QtDoublePropertyManager *doubleManager = qobject_cast(manager)) { doubleManager->setValue(internProp, val.value()); return; } else if (QtBoolPropertyManager *boolManager = qobject_cast(manager)) { boolManager->setValue(internProp, val.value()); return; } else if (QtStringPropertyManager *stringManager = qobject_cast(manager)) { stringManager->setValue(internProp, val.value()); return; } else if (QtDatePropertyManager *dateManager = qobject_cast(manager)) { dateManager->setValue(internProp, val.value()); return; } else if (QtTimePropertyManager *timeManager = qobject_cast(manager)) { timeManager->setValue(internProp, val.value()); return; } else if (QtDateTimePropertyManager *dateTimeManager = qobject_cast(manager)) { dateTimeManager->setValue(internProp, val.value()); return; } else if (QtKeySequencePropertyManager *keySequenceManager = qobject_cast(manager)) { keySequenceManager->setValue(internProp, val.value()); return; } else if (QtCharPropertyManager *charManager = qobject_cast(manager)) { charManager->setValue(internProp, val.value()); return; } else if (QtLocalePropertyManager *localeManager = qobject_cast(manager)) { localeManager->setValue(internProp, val.value()); return; } else if (QtPointPropertyManager *pointManager = qobject_cast(manager)) { pointManager->setValue(internProp, val.value()); return; } else if (QtPointFPropertyManager *pointFManager = qobject_cast(manager)) { pointFManager->setValue(internProp, val.value()); return; } else if (QtSizePropertyManager *sizeManager = qobject_cast(manager)) { sizeManager->setValue(internProp, val.value()); return; } else if (QtSizeFPropertyManager *sizeFManager = qobject_cast(manager)) { sizeFManager->setValue(internProp, val.value()); return; } else if (QtRectPropertyManager *rectManager = qobject_cast(manager)) { rectManager->setValue(internProp, val.value()); return; } else if (QtRectFPropertyManager *rectFManager = qobject_cast(manager)) { rectFManager->setValue(internProp, val.value()); return; } else if (QtColorPropertyManager *colorManager = qobject_cast(manager)) { colorManager->setValue(internProp, val.value()); return; } else if (QtEnumPropertyManager *enumManager = qobject_cast(manager)) { enumManager->setValue(internProp, val.value()); return; } else if (QtSizePolicyPropertyManager *sizePolicyManager = qobject_cast(manager)) { sizePolicyManager->setValue(internProp, val.value()); return; } else if (QtFontPropertyManager *fontManager = qobject_cast(manager)) { fontManager->setValue(internProp, val.value()); return; #ifndef QT_NO_CURSOR } else if (QtCursorPropertyManager *cursorManager = qobject_cast(manager)) { cursorManager->setValue(internProp, val.value()); return; #endif } else if (QtFlagPropertyManager *flagManager = qobject_cast(manager)) { flagManager->setValue(internProp, val.value()); return; } } /*! Sets the value of the specified \a attribute of the given \a property, to \a value. The new \a value's type must be of the type returned by attributeType(), or of a type that can be converted to attributeType() using the QVariant::canConvert() function, otherwise this function does nothing. \sa attributeValue(), QtVariantProperty::setAttribute(), attributeChanged() */ void QtVariantPropertyManager::setAttribute(QtProperty *property, const QString &attribute, const QVariant &value) { QVariant oldAttr = attributeValue(property, attribute); if (!oldAttr.isValid()) return; int attrType = value.userType(); if (!attrType) return; if (attrType != attributeType(propertyType(property), attribute) && !value.canConvert((QVariant::Type)attrType)) return; QtProperty *internProp = propertyToWrappedProperty()->value(property, 0); if (internProp == 0) return; QtAbstractPropertyManager *manager = internProp->propertyManager(); if (QtIntPropertyManager *intManager = qobject_cast(manager)) { if (attribute == d_ptr->m_maximumAttribute) intManager->setMaximum(internProp, value.value()); else if (attribute == d_ptr->m_minimumAttribute) intManager->setMinimum(internProp, value.value()); else if (attribute == d_ptr->m_singleStepAttribute) intManager->setSingleStep(internProp, value.value()); return; } else if (QtDoublePropertyManager *doubleManager = qobject_cast(manager)) { if (attribute == d_ptr->m_maximumAttribute) doubleManager->setMaximum(internProp, value.value()); if (attribute == d_ptr->m_minimumAttribute) doubleManager->setMinimum(internProp, value.value()); if (attribute == d_ptr->m_singleStepAttribute) doubleManager->setSingleStep(internProp, value.value()); if (attribute == d_ptr->m_decimalsAttribute) doubleManager->setDecimals(internProp, value.value()); return; } else if (QtStringPropertyManager *stringManager = qobject_cast(manager)) { if (attribute == d_ptr->m_regExpAttribute) stringManager->setRegExp(internProp, value.value()); return; } else if (QtDatePropertyManager *dateManager = qobject_cast(manager)) { if (attribute == d_ptr->m_maximumAttribute) dateManager->setMaximum(internProp, value.value()); if (attribute == d_ptr->m_minimumAttribute) dateManager->setMinimum(internProp, value.value()); return; } else if (QtPointFPropertyManager *pointFManager = qobject_cast(manager)) { if (attribute == d_ptr->m_decimalsAttribute) pointFManager->setDecimals(internProp, value.value()); return; } else if (QtSizePropertyManager *sizeManager = qobject_cast(manager)) { if (attribute == d_ptr->m_maximumAttribute) sizeManager->setMaximum(internProp, value.value()); if (attribute == d_ptr->m_minimumAttribute) sizeManager->setMinimum(internProp, value.value()); return; } else if (QtSizeFPropertyManager *sizeFManager = qobject_cast(manager)) { if (attribute == d_ptr->m_maximumAttribute) sizeFManager->setMaximum(internProp, value.value()); if (attribute == d_ptr->m_minimumAttribute) sizeFManager->setMinimum(internProp, value.value()); if (attribute == d_ptr->m_decimalsAttribute) sizeFManager->setDecimals(internProp, value.value()); return; } else if (QtRectPropertyManager *rectManager = qobject_cast(manager)) { if (attribute == d_ptr->m_constraintAttribute) rectManager->setConstraint(internProp, value.value()); return; } else if (QtRectFPropertyManager *rectFManager = qobject_cast(manager)) { if (attribute == d_ptr->m_constraintAttribute) rectFManager->setConstraint(internProp, value.value()); if (attribute == d_ptr->m_decimalsAttribute) rectFManager->setDecimals(internProp, value.value()); return; } else if (QtEnumPropertyManager *enumManager = qobject_cast(manager)) { if (attribute == d_ptr->m_enumNamesAttribute) enumManager->setEnumNames(internProp, value.value()); if (attribute == d_ptr->m_enumIconsAttribute) enumManager->setEnumIcons(internProp, value.value()); return; } else if (QtFlagPropertyManager *flagManager = qobject_cast(manager)) { if (attribute == d_ptr->m_flagNamesAttribute) flagManager->setFlagNames(internProp, value.value()); return; } } /*! \reimp */ bool QtVariantPropertyManager::hasValue(const QtProperty *property) const { if (propertyType(property) == groupTypeId()) return false; return true; } /*! \reimp */ QString QtVariantPropertyManager::valueText(const QtProperty *property) const { const QtProperty *internProp = propertyToWrappedProperty()->value(property, 0); return internProp ? internProp->valueText() : QString(); } /*! \reimp */ QIcon QtVariantPropertyManager::valueIcon(const QtProperty *property) const { const QtProperty *internProp = propertyToWrappedProperty()->value(property, 0); return internProp ? internProp->valueIcon() : QIcon(); } /*! \reimp */ void QtVariantPropertyManager::initializeProperty(QtProperty *property) { QtVariantProperty *varProp = variantProperty(property); if (!varProp) return; QMap::ConstIterator it = d_ptr->m_typeToPropertyManager.find(d_ptr->m_propertyType); if (it != d_ptr->m_typeToPropertyManager.constEnd()) { QtProperty *internProp = 0; if (!d_ptr->m_creatingSubProperties) { QtAbstractPropertyManager *manager = it.value(); internProp = manager->addProperty(); d_ptr->m_internalToProperty[internProp] = varProp; } propertyToWrappedProperty()->insert(varProp, internProp); if (internProp) { QList children = internProp->subProperties(); QListIterator itChild(children); QtVariantProperty *lastProperty = 0; while (itChild.hasNext()) { QtVariantProperty *prop = d_ptr->createSubProperty(varProp, lastProperty, itChild.next()); lastProperty = prop ? prop : lastProperty; } } } } /*! \reimp */ void QtVariantPropertyManager::uninitializeProperty(QtProperty *property) { const QMap >::iterator type_it = d_ptr->m_propertyToType.find(property); if (type_it == d_ptr->m_propertyToType.end()) return; PropertyMap::iterator it = propertyToWrappedProperty()->find(property); if (it != propertyToWrappedProperty()->end()) { QtProperty *internProp = it.value(); if (internProp) { d_ptr->m_internalToProperty.remove(internProp); if (!d_ptr->m_destroyingSubProperties) { delete internProp; } } propertyToWrappedProperty()->erase(it); } d_ptr->m_propertyToType.erase(type_it); } /*! \reimp */ QtProperty *QtVariantPropertyManager::createProperty() { if (!d_ptr->m_creatingProperty) return 0; QtVariantProperty *property = new QtVariantProperty(this); d_ptr->m_propertyToType.insert(property, qMakePair(property, d_ptr->m_propertyType)); return property; } ///////////////////////////// class QtVariantEditorFactoryPrivate { QtVariantEditorFactory *q_ptr; Q_DECLARE_PUBLIC(QtVariantEditorFactory) public: QtSpinBoxFactory *m_spinBoxFactory; QtDoubleSpinBoxFactory *m_doubleSpinBoxFactory; QtCheckBoxFactory *m_checkBoxFactory; QtLineEditFactory *m_lineEditFactory; QtDateEditFactory *m_dateEditFactory; QtTimeEditFactory *m_timeEditFactory; QtDateTimeEditFactory *m_dateTimeEditFactory; QtKeySequenceEditorFactory *m_keySequenceEditorFactory; QtCharEditorFactory *m_charEditorFactory; QtEnumEditorFactory *m_comboBoxFactory; QtCursorEditorFactory *m_cursorEditorFactory; QtColorEditorFactory *m_colorEditorFactory; QtFontEditorFactory *m_fontEditorFactory; QMap m_factoryToType; QMap m_typeToFactory; }; /*! \class QtVariantEditorFactory \brief The QtVariantEditorFactory class provides widgets for properties created by QtVariantPropertyManager objects. The variant factory provides the following widgets for the specified property types: \table \header \o Property Type \o Widget \row \o \c int \o QSpinBox \row \o \c double \o QDoubleSpinBox \row \o \c bool \o QCheckBox \row \o QString \o QLineEdit \row \o QDate \o QDateEdit \row \o QTime \o QTimeEdit \row \o QDateTime \o QDateTimeEdit \row \o QKeySequence \o customized editor \row \o QChar \o customized editor \row \o \c enum \o QComboBox \row \o QCursor \o QComboBox \endtable Note that QtVariantPropertyManager supports several additional property types for which the QtVariantEditorFactory class does not provide editing widgets, e.g. QPoint and QSize. To provide widgets for other types using the variant approach, derive from the QtVariantEditorFactory class. \sa QtAbstractEditorFactory, QtVariantPropertyManager */ /*! Creates a factory with the given \a parent. */ QtVariantEditorFactory::QtVariantEditorFactory(QObject *parent) : QtAbstractEditorFactory(parent) { d_ptr = new QtVariantEditorFactoryPrivate(); d_ptr->q_ptr = this; d_ptr->m_spinBoxFactory = new QtSpinBoxFactory(this); d_ptr->m_factoryToType[d_ptr->m_spinBoxFactory] = QVariant::Int; d_ptr->m_typeToFactory[QVariant::Int] = d_ptr->m_spinBoxFactory; d_ptr->m_doubleSpinBoxFactory = new QtDoubleSpinBoxFactory(this); d_ptr->m_factoryToType[d_ptr->m_doubleSpinBoxFactory] = QVariant::Double; d_ptr->m_typeToFactory[QVariant::Double] = d_ptr->m_doubleSpinBoxFactory; d_ptr->m_checkBoxFactory = new QtCheckBoxFactory(this); d_ptr->m_factoryToType[d_ptr->m_checkBoxFactory] = QVariant::Bool; d_ptr->m_typeToFactory[QVariant::Bool] = d_ptr->m_checkBoxFactory; d_ptr->m_lineEditFactory = new QtLineEditFactory(this); d_ptr->m_factoryToType[d_ptr->m_lineEditFactory] = QVariant::String; d_ptr->m_typeToFactory[QVariant::String] = d_ptr->m_lineEditFactory; d_ptr->m_dateEditFactory = new QtDateEditFactory(this); d_ptr->m_factoryToType[d_ptr->m_dateEditFactory] = QVariant::Date; d_ptr->m_typeToFactory[QVariant::Date] = d_ptr->m_dateEditFactory; d_ptr->m_timeEditFactory = new QtTimeEditFactory(this); d_ptr->m_factoryToType[d_ptr->m_timeEditFactory] = QVariant::Time; d_ptr->m_typeToFactory[QVariant::Time] = d_ptr->m_timeEditFactory; d_ptr->m_dateTimeEditFactory = new QtDateTimeEditFactory(this); d_ptr->m_factoryToType[d_ptr->m_dateTimeEditFactory] = QVariant::DateTime; d_ptr->m_typeToFactory[QVariant::DateTime] = d_ptr->m_dateTimeEditFactory; d_ptr->m_keySequenceEditorFactory = new QtKeySequenceEditorFactory(this); d_ptr->m_factoryToType[d_ptr->m_keySequenceEditorFactory] = QVariant::KeySequence; d_ptr->m_typeToFactory[QVariant::KeySequence] = d_ptr->m_keySequenceEditorFactory; d_ptr->m_charEditorFactory = new QtCharEditorFactory(this); d_ptr->m_factoryToType[d_ptr->m_charEditorFactory] = QVariant::Char; d_ptr->m_typeToFactory[QVariant::Char] = d_ptr->m_charEditorFactory; d_ptr->m_cursorEditorFactory = new QtCursorEditorFactory(this); d_ptr->m_factoryToType[d_ptr->m_cursorEditorFactory] = QVariant::Cursor; d_ptr->m_typeToFactory[QVariant::Cursor] = d_ptr->m_cursorEditorFactory; d_ptr->m_colorEditorFactory = new QtColorEditorFactory(this); d_ptr->m_factoryToType[d_ptr->m_colorEditorFactory] = QVariant::Color; d_ptr->m_typeToFactory[QVariant::Color] = d_ptr->m_colorEditorFactory; d_ptr->m_fontEditorFactory = new QtFontEditorFactory(this); d_ptr->m_factoryToType[d_ptr->m_fontEditorFactory] = QVariant::Font; d_ptr->m_typeToFactory[QVariant::Font] = d_ptr->m_fontEditorFactory; d_ptr->m_comboBoxFactory = new QtEnumEditorFactory(this); const int enumId = QtVariantPropertyManager::enumTypeId(); d_ptr->m_factoryToType[d_ptr->m_comboBoxFactory] = enumId; d_ptr->m_typeToFactory[enumId] = d_ptr->m_comboBoxFactory; } /*! Destroys this factory, and all the widgets it has created. */ QtVariantEditorFactory::~QtVariantEditorFactory() { delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtVariantEditorFactory::connectPropertyManager(QtVariantPropertyManager *manager) { QList intPropertyManagers = manager->findChildren(); QListIterator itInt(intPropertyManagers); while (itInt.hasNext()) d_ptr->m_spinBoxFactory->addPropertyManager(itInt.next()); QList doublePropertyManagers = manager->findChildren(); QListIterator itDouble(doublePropertyManagers); while (itDouble.hasNext()) d_ptr->m_doubleSpinBoxFactory->addPropertyManager(itDouble.next()); QList boolPropertyManagers = manager->findChildren(); QListIterator itBool(boolPropertyManagers); while (itBool.hasNext()) d_ptr->m_checkBoxFactory->addPropertyManager(itBool.next()); QList stringPropertyManagers = manager->findChildren(); QListIterator itString(stringPropertyManagers); while (itString.hasNext()) d_ptr->m_lineEditFactory->addPropertyManager(itString.next()); QList datePropertyManagers = manager->findChildren(); QListIterator itDate(datePropertyManagers); while (itDate.hasNext()) d_ptr->m_dateEditFactory->addPropertyManager(itDate.next()); QList timePropertyManagers = manager->findChildren(); QListIterator itTime(timePropertyManagers); while (itTime.hasNext()) d_ptr->m_timeEditFactory->addPropertyManager(itTime.next()); QList dateTimePropertyManagers = manager->findChildren(); QListIterator itDateTime(dateTimePropertyManagers); while (itDateTime.hasNext()) d_ptr->m_dateTimeEditFactory->addPropertyManager(itDateTime.next()); QList keySequencePropertyManagers = manager->findChildren(); QListIterator itKeySequence(keySequencePropertyManagers); while (itKeySequence.hasNext()) d_ptr->m_keySequenceEditorFactory->addPropertyManager(itKeySequence.next()); QList charPropertyManagers = manager->findChildren(); QListIterator itChar(charPropertyManagers); while (itChar.hasNext()) d_ptr->m_charEditorFactory->addPropertyManager(itChar.next()); QList localePropertyManagers = manager->findChildren(); QListIterator itLocale(localePropertyManagers); while (itLocale.hasNext()) d_ptr->m_comboBoxFactory->addPropertyManager(itLocale.next()->subEnumPropertyManager()); QList pointPropertyManagers = manager->findChildren(); QListIterator itPoint(pointPropertyManagers); while (itPoint.hasNext()) d_ptr->m_spinBoxFactory->addPropertyManager(itPoint.next()->subIntPropertyManager()); QList pointFPropertyManagers = manager->findChildren(); QListIterator itPointF(pointFPropertyManagers); while (itPointF.hasNext()) d_ptr->m_doubleSpinBoxFactory->addPropertyManager(itPointF.next()->subDoublePropertyManager()); QList sizePropertyManagers = manager->findChildren(); QListIterator itSize(sizePropertyManagers); while (itSize.hasNext()) d_ptr->m_spinBoxFactory->addPropertyManager(itSize.next()->subIntPropertyManager()); QList sizeFPropertyManagers = manager->findChildren(); QListIterator itSizeF(sizeFPropertyManagers); while (itSizeF.hasNext()) d_ptr->m_doubleSpinBoxFactory->addPropertyManager(itSizeF.next()->subDoublePropertyManager()); QList rectPropertyManagers = manager->findChildren(); QListIterator itRect(rectPropertyManagers); while (itRect.hasNext()) d_ptr->m_spinBoxFactory->addPropertyManager(itRect.next()->subIntPropertyManager()); QList rectFPropertyManagers = manager->findChildren(); QListIterator itRectF(rectFPropertyManagers); while (itRectF.hasNext()) d_ptr->m_doubleSpinBoxFactory->addPropertyManager(itRectF.next()->subDoublePropertyManager()); QList colorPropertyManagers = manager->findChildren(); QListIterator itColor(colorPropertyManagers); while (itColor.hasNext()) { QtColorPropertyManager *manager = itColor.next(); d_ptr->m_colorEditorFactory->addPropertyManager(manager); d_ptr->m_spinBoxFactory->addPropertyManager(manager->subIntPropertyManager()); } QList enumPropertyManagers = manager->findChildren(); QListIterator itEnum(enumPropertyManagers); while (itEnum.hasNext()) d_ptr->m_comboBoxFactory->addPropertyManager(itEnum.next()); QList sizePolicyPropertyManagers = manager->findChildren(); QListIterator itSizePolicy(sizePolicyPropertyManagers); while (itSizePolicy.hasNext()) { QtSizePolicyPropertyManager *manager = itSizePolicy.next(); d_ptr->m_spinBoxFactory->addPropertyManager(manager->subIntPropertyManager()); d_ptr->m_comboBoxFactory->addPropertyManager(manager->subEnumPropertyManager()); } QList fontPropertyManagers = manager->findChildren(); QListIterator itFont(fontPropertyManagers); while (itFont.hasNext()) { QtFontPropertyManager *manager = itFont.next(); d_ptr->m_fontEditorFactory->addPropertyManager(manager); d_ptr->m_spinBoxFactory->addPropertyManager(manager->subIntPropertyManager()); d_ptr->m_comboBoxFactory->addPropertyManager(manager->subEnumPropertyManager()); d_ptr->m_checkBoxFactory->addPropertyManager(manager->subBoolPropertyManager()); } QList cursorPropertyManagers = manager->findChildren(); QListIterator itCursor(cursorPropertyManagers); while (itCursor.hasNext()) d_ptr->m_cursorEditorFactory->addPropertyManager(itCursor.next()); QList flagPropertyManagers = manager->findChildren(); QListIterator itFlag(flagPropertyManagers); while (itFlag.hasNext()) d_ptr->m_checkBoxFactory->addPropertyManager(itFlag.next()->subBoolPropertyManager()); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtVariantEditorFactory::createEditor(QtVariantPropertyManager *manager, QtProperty *property, QWidget *parent) { const int propType = manager->propertyType(property); QtAbstractEditorFactoryBase *factory = d_ptr->m_typeToFactory.value(propType, 0); if (!factory) return 0; return factory->createEditor(wrappedProperty(property), parent); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtVariantEditorFactory::createEditor(QtProperty *property, QWidget *parent) { // Overlaoded to avoid "-Woverloaded-virtual" warning return this->QtAbstractEditorFactory::createEditor(property, parent); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtVariantEditorFactory::disconnectPropertyManager(QtVariantPropertyManager *manager) { QList intPropertyManagers = manager->findChildren(); QListIterator itInt(intPropertyManagers); while (itInt.hasNext()) d_ptr->m_spinBoxFactory->removePropertyManager(itInt.next()); QList doublePropertyManagers = manager->findChildren(); QListIterator itDouble(doublePropertyManagers); while (itDouble.hasNext()) d_ptr->m_doubleSpinBoxFactory->removePropertyManager(itDouble.next()); QList boolPropertyManagers = manager->findChildren(); QListIterator itBool(boolPropertyManagers); while (itBool.hasNext()) d_ptr->m_checkBoxFactory->removePropertyManager(itBool.next()); QList stringPropertyManagers = manager->findChildren(); QListIterator itString(stringPropertyManagers); while (itString.hasNext()) d_ptr->m_lineEditFactory->removePropertyManager(itString.next()); QList datePropertyManagers = manager->findChildren(); QListIterator itDate(datePropertyManagers); while (itDate.hasNext()) d_ptr->m_dateEditFactory->removePropertyManager(itDate.next()); QList timePropertyManagers = manager->findChildren(); QListIterator itTime(timePropertyManagers); while (itTime.hasNext()) d_ptr->m_timeEditFactory->removePropertyManager(itTime.next()); QList dateTimePropertyManagers = manager->findChildren(); QListIterator itDateTime(dateTimePropertyManagers); while (itDateTime.hasNext()) d_ptr->m_dateTimeEditFactory->removePropertyManager(itDateTime.next()); QList keySequencePropertyManagers = manager->findChildren(); QListIterator itKeySequence(keySequencePropertyManagers); while (itKeySequence.hasNext()) d_ptr->m_keySequenceEditorFactory->removePropertyManager(itKeySequence.next()); QList charPropertyManagers = manager->findChildren(); QListIterator itChar(charPropertyManagers); while (itChar.hasNext()) d_ptr->m_charEditorFactory->removePropertyManager(itChar.next()); QList localePropertyManagers = manager->findChildren(); QListIterator itLocale(localePropertyManagers); while (itLocale.hasNext()) d_ptr->m_comboBoxFactory->removePropertyManager(itLocale.next()->subEnumPropertyManager()); QList pointPropertyManagers = manager->findChildren(); QListIterator itPoint(pointPropertyManagers); while (itPoint.hasNext()) d_ptr->m_spinBoxFactory->removePropertyManager(itPoint.next()->subIntPropertyManager()); QList pointFPropertyManagers = manager->findChildren(); QListIterator itPointF(pointFPropertyManagers); while (itPointF.hasNext()) d_ptr->m_doubleSpinBoxFactory->removePropertyManager(itPointF.next()->subDoublePropertyManager()); QList sizePropertyManagers = manager->findChildren(); QListIterator itSize(sizePropertyManagers); while (itSize.hasNext()) d_ptr->m_spinBoxFactory->removePropertyManager(itSize.next()->subIntPropertyManager()); QList sizeFPropertyManagers = manager->findChildren(); QListIterator itSizeF(sizeFPropertyManagers); while (itSizeF.hasNext()) d_ptr->m_doubleSpinBoxFactory->removePropertyManager(itSizeF.next()->subDoublePropertyManager()); QList rectPropertyManagers = manager->findChildren(); QListIterator itRect(rectPropertyManagers); while (itRect.hasNext()) d_ptr->m_spinBoxFactory->removePropertyManager(itRect.next()->subIntPropertyManager()); QList rectFPropertyManagers = manager->findChildren(); QListIterator itRectF(rectFPropertyManagers); while (itRectF.hasNext()) d_ptr->m_doubleSpinBoxFactory->removePropertyManager(itRectF.next()->subDoublePropertyManager()); QList colorPropertyManagers = manager->findChildren(); QListIterator itColor(colorPropertyManagers); while (itColor.hasNext()) { QtColorPropertyManager *manager = itColor.next(); d_ptr->m_colorEditorFactory->removePropertyManager(manager); d_ptr->m_spinBoxFactory->removePropertyManager(manager->subIntPropertyManager()); } QList enumPropertyManagers = manager->findChildren(); QListIterator itEnum(enumPropertyManagers); while (itEnum.hasNext()) d_ptr->m_comboBoxFactory->removePropertyManager(itEnum.next()); QList sizePolicyPropertyManagers = manager->findChildren(); QListIterator itSizePolicy(sizePolicyPropertyManagers); while (itSizePolicy.hasNext()) { QtSizePolicyPropertyManager *manager = itSizePolicy.next(); d_ptr->m_spinBoxFactory->removePropertyManager(manager->subIntPropertyManager()); d_ptr->m_comboBoxFactory->removePropertyManager(manager->subEnumPropertyManager()); } QList fontPropertyManagers = manager->findChildren(); QListIterator itFont(fontPropertyManagers); while (itFont.hasNext()) { QtFontPropertyManager *manager = itFont.next(); d_ptr->m_fontEditorFactory->removePropertyManager(manager); d_ptr->m_spinBoxFactory->removePropertyManager(manager->subIntPropertyManager()); d_ptr->m_comboBoxFactory->removePropertyManager(manager->subEnumPropertyManager()); d_ptr->m_checkBoxFactory->removePropertyManager(manager->subBoolPropertyManager()); } QList cursorPropertyManagers = manager->findChildren(); QListIterator itCursor(cursorPropertyManagers); while (itCursor.hasNext()) d_ptr->m_cursorEditorFactory->removePropertyManager(itCursor.next()); QList flagPropertyManagers = manager->findChildren(); QListIterator itFlag(flagPropertyManagers); while (itFlag.hasNext()) d_ptr->m_checkBoxFactory->removePropertyManager(itFlag.next()->subBoolPropertyManager()); } #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif #include "moc_qtvariantproperty.cpp" nextpnr-nextpnr-0.7/3rdparty/QtPropertyBrowser/src/qtvariantproperty.h000066400000000000000000000210571455373415500266160ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of a Qt Solutions component. ** ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ #ifndef QTVARIANTPROPERTY_H #define QTVARIANTPROPERTY_H #include "qtpropertybrowser.h" #include #include #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif typedef QMap QtIconMap; class QtVariantPropertyManager; class QtVariantPropertyPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtVariantProperty : public QtProperty { public: ~QtVariantProperty(); QVariant value() const; QVariant attributeValue(const QString &attribute) const; int valueType() const; int propertyType() const; virtual bool compare(QtProperty* otherProperty)const; void setValue(const QVariant &value); void setAttribute(const QString &attribute, const QVariant &value); protected: QtVariantProperty(QtVariantPropertyManager *manager); private: friend class QtVariantPropertyManager; QtVariantPropertyPrivate *d_ptr; }; class QtVariantPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtVariantPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtVariantPropertyManager(QObject *parent = 0); ~QtVariantPropertyManager(); virtual QtVariantProperty *addProperty(int propertyType, const QString &name = QString()); void setProperties(QSet properties); int propertyType(const QtProperty *property) const; int valueType(const QtProperty *property) const; QtVariantProperty *variantProperty(const QtProperty *property) const; virtual bool isPropertyTypeSupported(int propertyType) const; virtual int valueType(int propertyType) const; virtual QStringList attributes(int propertyType) const; virtual int attributeType(int propertyType, const QString &attribute) const; virtual QVariant value(const QtProperty *property) const; virtual QVariant attributeValue(const QtProperty *property, const QString &attribute) const; static int enumTypeId(); static int flagTypeId(); static int groupTypeId(); static int iconMapTypeId(); public Q_SLOTS: virtual void setValue(QtProperty *property, const QVariant &val); virtual void setAttribute(QtProperty *property, const QString &attribute, const QVariant &value); Q_SIGNALS: void valueChanged(QtProperty *property, const QVariant &val); void attributeChanged(QtProperty *property, const QString &attribute, const QVariant &val); protected: virtual bool hasValue(const QtProperty *property) const; QString valueText(const QtProperty *property) const; QIcon valueIcon(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); virtual QtProperty *createProperty(); private: QtVariantPropertyManagerPrivate *d_ptr; Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotRangeChanged(QtProperty *, int, int)) Q_PRIVATE_SLOT(d_func(), void slotSingleStepChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, double)) Q_PRIVATE_SLOT(d_func(), void slotRangeChanged(QtProperty *, double, double)) Q_PRIVATE_SLOT(d_func(), void slotSingleStepChanged(QtProperty *, double)) Q_PRIVATE_SLOT(d_func(), void slotDecimalsChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, bool)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QString &)) Q_PRIVATE_SLOT(d_func(), void slotRegExpChanged(QtProperty *, const QRegExp &)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QDate &)) Q_PRIVATE_SLOT(d_func(), void slotRangeChanged(QtProperty *, const QDate &, const QDate &)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QTime &)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QDateTime &)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QKeySequence &)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QChar &)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QLocale &)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QPoint &)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QPointF &)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QSize &)) Q_PRIVATE_SLOT(d_func(), void slotRangeChanged(QtProperty *, const QSize &, const QSize &)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QSizeF &)) Q_PRIVATE_SLOT(d_func(), void slotRangeChanged(QtProperty *, const QSizeF &, const QSizeF &)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QRect &)) Q_PRIVATE_SLOT(d_func(), void slotConstraintChanged(QtProperty *, const QRect &)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QRectF &)) Q_PRIVATE_SLOT(d_func(), void slotConstraintChanged(QtProperty *, const QRectF &)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QColor &)) Q_PRIVATE_SLOT(d_func(), void slotEnumNamesChanged(QtProperty *, const QStringList &)) Q_PRIVATE_SLOT(d_func(), void slotEnumIconsChanged(QtProperty *, const QMap &)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QSizePolicy &)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QFont &)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QCursor &)) Q_PRIVATE_SLOT(d_func(), void slotFlagNamesChanged(QtProperty *, const QStringList &)) Q_PRIVATE_SLOT(d_func(), void slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *)) Q_PRIVATE_SLOT(d_func(), void slotPropertyRemoved(QtProperty *, QtProperty *)) Q_DECLARE_PRIVATE(QtVariantPropertyManager) Q_DISABLE_COPY(QtVariantPropertyManager) }; class QtVariantEditorFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtVariantEditorFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtVariantEditorFactory(QObject *parent = 0); ~QtVariantEditorFactory(); protected: void connectPropertyManager(QtVariantPropertyManager *manager); QWidget *createEditor(QtVariantPropertyManager *manager, QtProperty *property, QWidget *parent); QWidget *createEditor(QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtVariantPropertyManager *manager); private: QtVariantEditorFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtVariantEditorFactory) Q_DISABLE_COPY(QtVariantEditorFactory) }; #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif Q_DECLARE_METATYPE(QIcon) Q_DECLARE_METATYPE(QtIconMap) #endif nextpnr-nextpnr-0.7/3rdparty/corrosion/000077500000000000000000000000001455373415500203535ustar00rootroot00000000000000nextpnr-nextpnr-0.7/3rdparty/fpga-interchange-schema/000077500000000000000000000000001455373415500227765ustar00rootroot00000000000000nextpnr-nextpnr-0.7/3rdparty/googletest/000077500000000000000000000000001455373415500205125ustar00rootroot00000000000000nextpnr-nextpnr-0.7/3rdparty/googletest/.gitignore000066400000000000000000000000431455373415500224770ustar00rootroot00000000000000# Ignore CI build directory build/ nextpnr-nextpnr-0.7/3rdparty/googletest/.travis.yml000066400000000000000000000033201455373415500226210ustar00rootroot00000000000000# Build matrix / environment variable are explained on: # http://about.travis-ci.org/docs/user/build-configuration/ # This file can be validated on: # http://lint.travis-ci.org/ install: # /usr/bin/gcc is 4.6 always, but gcc-X.Y is available. - if [ "$CXX" = "g++" ]; then export CXX="g++-4.9" CC="gcc-4.9"; fi # /usr/bin/clang is 3.4, lets override with modern one. - if [ "$CXX" = "clang++" ] && [ "$TRAVIS_OS_NAME" = "linux" ]; then export CXX="clang++-3.7" CC="clang-3.7"; fi - echo ${PATH} - echo ${CXX} - ${CXX} --version - ${CXX} -v addons: apt: # List of whitelisted in travis packages for ubuntu-precise can be found here: # https://github.com/travis-ci/apt-package-whitelist/blob/master/ubuntu-precise # List of whitelisted in travis apt-sources: # https://github.com/travis-ci/apt-source-whitelist/blob/master/ubuntu.json sources: - ubuntu-toolchain-r-test - llvm-toolchain-precise-3.7 packages: - gcc-4.9 - g++-4.9 - clang-3.7 - valgrind os: - linux - osx language: cpp compiler: - gcc - clang script: ./travis.sh env: matrix: - GTEST_TARGET=googletest SHARED_LIB=OFF STATIC_LIB=ON CMAKE_PKG=OFF BUILD_TYPE=debug VERBOSE_MAKE=true VERBOSE - GTEST_TARGET=googlemock SHARED_LIB=OFF STATIC_LIB=ON CMAKE_PKG=OFF BUILD_TYPE=debug VERBOSE_MAKE=true VERBOSE - GTEST_TARGET=googlemock SHARED_LIB=OFF STATIC_LIB=ON CMAKE_PKG=OFF BUILD_TYPE=debug CXX_FLAGS=-std=c++11 VERBOSE_MAKE=true VERBOSE # - GTEST_TARGET=googletest SHARED_LIB=ON STATIC_LIB=ON CMAKE_PKG=ON BUILD_TYPE=release VERBOSE_MAKE=false # - GTEST_TARGET=googlemock SHARED_LIB=ON STATIC_LIB=ON CMAKE_PKG=ON BUILD_TYPE=release VERBOSE_MAKE=false notifications: email: false sudo: false nextpnr-nextpnr-0.7/3rdparty/googletest/CMakeLists.txt000066400000000000000000000005711455373415500232550ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.6.2) project( googletest-distribution ) enable_testing() option(BUILD_GTEST "Builds the googletest subproject" OFF) #Note that googlemock target already builds googletest option(BUILD_GMOCK "Builds the googlemock subproject" ON) if(BUILD_GMOCK) add_subdirectory( googlemock ) elseif(BUILD_GTEST) add_subdirectory( googletest ) endif() nextpnr-nextpnr-0.7/3rdparty/googletest/README.md000066400000000000000000000116451455373415500220000ustar00rootroot00000000000000 # Google Test # [![Build Status](https://travis-ci.org/google/googletest.svg?branch=master)](https://travis-ci.org/google/googletest) [![Build status](https://ci.appveyor.com/api/projects/status/4o38plt0xbo1ubc8/branch/master?svg=true)](https://ci.appveyor.com/project/BillyDonahue/googletest/branch/master) Welcome to **Google Test**, Google's C++ test framework! This repository is a merger of the formerly separate GoogleTest and GoogleMock projects. These were so closely related that it makes sense to maintain and release them together. Please see the project page above for more information as well as the mailing list for questions, discussions, and development. There is also an IRC channel on OFTC (irc.oftc.net) #gtest available. Please join us! Getting started information for **Google Test** is available in the [Google Test Primer](googletest/docs/Primer.md) documentation. **Google Mock** is an extension to Google Test for writing and using C++ mock classes. See the separate [Google Mock documentation](googlemock/README.md). More detailed documentation for googletest (including build instructions) are in its interior [googletest/README.md](googletest/README.md) file. ## Features ## * An [XUnit](https://en.wikipedia.org/wiki/XUnit) test framework. * Test discovery. * A rich set of assertions. * User-defined assertions. * Death tests. * Fatal and non-fatal failures. * Value-parameterized tests. * Type-parameterized tests. * Various options for running the tests. * XML test report generation. ## Platforms ## Google test has been used on a variety of platforms: * Linux * Mac OS X * Windows * Cygwin * MinGW * Windows Mobile * Symbian ## Who Is Using Google Test? ## In addition to many internal projects at Google, Google Test is also used by the following notable projects: * The [Chromium projects](http://www.chromium.org/) (behind the Chrome browser and Chrome OS). * The [LLVM](http://llvm.org/) compiler. * [Protocol Buffers](https://github.com/google/protobuf), Google's data interchange format. * The [OpenCV](http://opencv.org/) computer vision library. ## Related Open Source Projects ## [Google Test UI](https://github.com/ospector/gtest-gbar) is test runner that runs your test binary, allows you to track its progress via a progress bar, and displays a list of test failures. Clicking on one shows failure text. Google Test UI is written in C#. [GTest TAP Listener](https://github.com/kinow/gtest-tap-listener) is an event listener for Google Test that implements the [TAP protocol](https://en.wikipedia.org/wiki/Test_Anything_Protocol) for test result output. If your test runner understands TAP, you may find it useful. ## Requirements ## Google Test is designed to have fairly minimal requirements to build and use with your projects, but there are some. Currently, we support Linux, Windows, Mac OS X, and Cygwin. We will also make our best effort to support other platforms (e.g. Solaris, AIX, and z/OS). However, since core members of the Google Test project have no access to these platforms, Google Test may have outstanding issues there. If you notice any problems on your platform, please notify . Patches for fixing them are even more welcome! ### Linux Requirements ### These are the base requirements to build and use Google Test from a source package (as described below): * GNU-compatible Make or gmake * POSIX-standard shell * POSIX(-2) Regular Expressions (regex.h) * A C++98-standard-compliant compiler ### Windows Requirements ### * Microsoft Visual C++ v7.1 or newer ### Cygwin Requirements ### * Cygwin v1.5.25-14 or newer ### Mac OS X Requirements ### * Mac OS X v10.4 Tiger or newer * Xcode Developer Tools ### Requirements for Contributors ### We welcome patches. If you plan to contribute a patch, you need to build Google Test and its own tests from a git checkout (described below), which has further requirements: * [Python](https://www.python.org/) v2.3 or newer (for running some of the tests and re-generating certain source files from templates) * [CMake](https://cmake.org/) v2.6.4 or newer ## Regenerating Source Files ## Some of Google Test's source files are generated from templates (not in the C++ sense) using a script. For example, the file include/gtest/internal/gtest-type-util.h.pump is used to generate gtest-type-util.h in the same directory. You don't need to worry about regenerating the source files unless you need to modify them. You would then modify the corresponding `.pump` files and run the '[pump.py](googletest/scripts/pump.py)' generator script. See the [Pump Manual](googletest/docs/PumpManual.md). ### Contributing Code ### We welcome patches. Please read the [Developer's Guide](googletest/docs/DevGuide.md) for how you can contribute. In particular, make sure you have signed the Contributor License Agreement, or we won't be able to accept the patch. Happy testing! nextpnr-nextpnr-0.7/3rdparty/googletest/appveyor.yml000066400000000000000000000027051455373415500231060ustar00rootroot00000000000000version: '{build}' os: Visual Studio 2015 environment: matrix: - Toolset: v140 - Toolset: v120 - Toolset: v110 - Toolset: v100 platform: - Win32 - x64 configuration: # - Release - Debug build: verbosity: minimal artifacts: - path: '_build/Testing/Temporary/*' name: test_results before_build: - ps: | Write-Output "Configuration: $env:CONFIGURATION" Write-Output "Platform: $env:PLATFORM" $generator = switch ($env:TOOLSET) { "v140" {"Visual Studio 14 2015"} "v120" {"Visual Studio 12 2013"} "v110" {"Visual Studio 11 2012"} "v100" {"Visual Studio 10 2010"} } if ($env:PLATFORM -eq "x64") { $generator = "$generator Win64" } build_script: - ps: | if (($env:TOOLSET -eq "v100") -and ($env:PLATFORM -eq "x64")) { return } md _build -Force | Out-Null cd _build & cmake -G "$generator" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -Dgtest_build_tests=ON -Dgtest_build_samples=ON -Dgmock_build_tests=ON .. if ($LastExitCode -ne 0) { throw "Exec: $ErrorMessage" } & cmake --build . --config $env:CONFIGURATION if ($LastExitCode -ne 0) { throw "Exec: $ErrorMessage" } test_script: - ps: | if (($env:Toolset -eq "v100") -and ($env:PLATFORM -eq "x64")) { return } & ctest -C $env:CONFIGURATION --output-on-failure if ($LastExitCode -ne 0) { throw "Exec: $ErrorMessage" } nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/000077500000000000000000000000001455373415500226405ustar00rootroot00000000000000nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/CHANGES000066400000000000000000000126731455373415500236440ustar00rootroot00000000000000Changes for 1.7.0: * All new improvements in Google Test 1.7.0. * New feature: matchers DoubleNear(), FloatNear(), NanSensitiveDoubleNear(), NanSensitiveFloatNear(), UnorderedElementsAre(), UnorderedElementsAreArray(), WhenSorted(), WhenSortedBy(), IsEmpty(), and SizeIs(). * Improvement: Google Mock can now be built as a DLL. * Improvement: when compiled by a C++11 compiler, matchers AllOf() and AnyOf() can accept an arbitrary number of matchers. * Improvement: when compiled by a C++11 compiler, matchers ElementsAreArray() can accept an initializer list. * Improvement: when exceptions are enabled, a mock method with no default action now throws instead crashing the test. * Improvement: added class testing::StringMatchResultListener to aid definition of composite matchers. * Improvement: function return types used in MOCK_METHOD*() macros can now contain unprotected commas. * Improvement (potentially breaking): EXPECT_THAT() and ASSERT_THAT() are now more strict in ensuring that the value type and the matcher type are compatible, catching potential bugs in tests. * Improvement: Pointee() now works on an optional. * Improvement: the ElementsAreArray() matcher can now take a vector or iterator range as input, and makes a copy of its input elements before the conversion to a Matcher. * Improvement: the Google Mock Generator can now generate mocks for some class templates. * Bug fix: mock object destruction triggerred by another mock object's destruction no longer hangs. * Improvement: Google Mock Doctor works better with newer Clang and GCC now. * Compatibility fixes. * Bug/warning fixes. Changes for 1.6.0: * Compilation is much faster and uses much less memory, especially when the constructor and destructor of a mock class are moved out of the class body. * New matchers: Pointwise(), Each(). * New actions: ReturnPointee() and ReturnRefOfCopy(). * CMake support. * Project files for Visual Studio 2010. * AllOf() and AnyOf() can handle up-to 10 arguments now. * Google Mock doctor understands Clang error messages now. * SetArgPointee<> now accepts string literals. * gmock_gen.py handles storage specifier macros and template return types now. * Compatibility fixes. * Bug fixes and implementation clean-ups. * Potentially incompatible changes: disables the harmful 'make install' command in autotools. Potentially breaking changes: * The description string for MATCHER*() changes from Python-style interpolation to an ordinary C++ string expression. * SetArgumentPointee is deprecated in favor of SetArgPointee. * Some non-essential project files for Visual Studio 2005 are removed. Changes for 1.5.0: * New feature: Google Mock can be safely used in multi-threaded tests on platforms having pthreads. * New feature: function for printing a value of arbitrary type. * New feature: function ExplainMatchResult() for easy definition of composite matchers. * The new matcher API lets user-defined matchers generate custom explanations more directly and efficiently. * Better failure messages all around. * NotNull() and IsNull() now work with smart pointers. * Field() and Property() now work when the matcher argument is a pointer passed by reference. * Regular expression matchers on all platforms. * Added GCC 4.0 support for Google Mock Doctor. * Added gmock_all_test.cc for compiling most Google Mock tests in a single file. * Significantly cleaned up compiler warnings. * Bug fixes, better test coverage, and implementation clean-ups. Potentially breaking changes: * Custom matchers defined using MatcherInterface or MakePolymorphicMatcher() need to be updated after upgrading to Google Mock 1.5.0; matchers defined using MATCHER or MATCHER_P* aren't affected. * Dropped support for 'make install'. Changes for 1.4.0 (we skipped 1.2.* and 1.3.* to match the version of Google Test): * Works in more environments: Symbian and minGW, Visual C++ 7.1. * Lighter weight: comes with our own implementation of TR1 tuple (no more dependency on Boost!). * New feature: --gmock_catch_leaked_mocks for detecting leaked mocks. * New feature: ACTION_TEMPLATE for defining templatized actions. * New feature: the .After() clause for specifying expectation order. * New feature: the .With() clause for for specifying inter-argument constraints. * New feature: actions ReturnArg(), ReturnNew(...), and DeleteArg(). * New feature: matchers Key(), Pair(), Args<...>(), AllArgs(), IsNull(), and Contains(). * New feature: utility class MockFunction, useful for checkpoints, etc. * New feature: functions Value(x, m) and SafeMatcherCast(m). * New feature: copying a mock object is rejected at compile time. * New feature: a script for fusing all Google Mock and Google Test source files for easy deployment. * Improved the Google Mock doctor to diagnose more diseases. * Improved the Google Mock generator script. * Compatibility fixes for Mac OS X and gcc. * Bug fixes and implementation clean-ups. Changes for 1.1.0: * New feature: ability to use Google Mock with any testing framework. * New feature: macros for easily defining new matchers * New feature: macros for easily defining new actions. * New feature: more container matchers. * New feature: actions for accessing function arguments and throwing exceptions. * Improved the Google Mock doctor script for diagnosing compiler errors. * Bug fixes and implementation clean-ups. Changes for 1.0.0: * Initial Open Source release of Google Mock nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/CMakeLists.txt000066400000000000000000000174461455373415500254140ustar00rootroot00000000000000######################################################################## # CMake build script for Google Mock. # # To run the tests for Google Mock itself on Linux, use 'make test' or # ctest. You can select which tests to run using 'ctest -R regex'. # For more options, run 'ctest --help'. # BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to # make it prominent in the GUI. option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." OFF) option(gmock_build_tests "Build all of Google Mock's own tests." OFF) # A directory to find Google Test sources. if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/gtest/CMakeLists.txt") set(gtest_dir gtest) else() set(gtest_dir ../googletest) endif() # Defines pre_project_set_up_hermetic_build() and set_up_hermetic_build(). include("${gtest_dir}/cmake/hermetic_build.cmake" OPTIONAL) if (COMMAND pre_project_set_up_hermetic_build) # Google Test also calls hermetic setup functions from add_subdirectory, # although its changes will not affect things at the current scope. pre_project_set_up_hermetic_build() endif() ######################################################################## # # Project-wide settings # Name of the project. # # CMake files in this project can refer to the root source directory # as ${gmock_SOURCE_DIR} and to the root binary directory as # ${gmock_BINARY_DIR}. # Language "C" is required for find_package(Threads). project(gmock CXX C) cmake_minimum_required(VERSION 2.6.2) if (COMMAND set_up_hermetic_build) set_up_hermetic_build() endif() # Instructs CMake to process Google Test's CMakeLists.txt and add its # targets to the current scope. We are placing Google Test's binary # directory in a subdirectory of our own as VC compilation may break # if they are the same (the default). add_subdirectory("${gtest_dir}" "${gmock_BINARY_DIR}/gtest") # Although Google Test's CMakeLists.txt calls this function, the # changes there don't affect the current scope. Therefore we have to # call it again here. config_compiler_and_linker() # from ${gtest_dir}/cmake/internal_utils.cmake # Adds Google Mock's and Google Test's header directories to the search path. include_directories("${gmock_SOURCE_DIR}/include" "${gmock_SOURCE_DIR}" "${gtest_SOURCE_DIR}/include" # This directory is needed to build directly from Google # Test sources. "${gtest_SOURCE_DIR}") # Summary of tuple support for Microsoft Visual Studio: # Compiler version(MS) version(cmake) Support # ---------- ----------- -------------- ----------------------------- # <= VS 2010 <= 10 <= 1600 Use Google Tests's own tuple. # VS 2012 11 1700 std::tr1::tuple + _VARIADIC_MAX=10 # VS 2013 12 1800 std::tr1::tuple if (MSVC AND MSVC_VERSION EQUAL 1700) add_definitions(/D _VARIADIC_MAX=10) endif() ######################################################################## # # Defines the gmock & gmock_main libraries. User tests should link # with one of them. # Google Mock libraries. We build them using more strict warnings than what # are used for other targets, to ensure that Google Mock can be compiled by # a user aggressive about warnings. cxx_library(gmock "${cxx_strict}" "${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc) cxx_library(gmock_main "${cxx_strict}" "${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc src/gmock_main.cc) # If the CMake version supports it, attach header directory information # to the targets for when we are part of a parent build (ie being pulled # in via add_subdirectory() rather than being a standalone build). if (DEFINED CMAKE_VERSION AND NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11") target_include_directories(gmock INTERFACE "${gmock_SOURCE_DIR}/include") target_include_directories(gmock_main INTERFACE "${gmock_SOURCE_DIR}/include") endif() ######################################################################## # # Install rules install(TARGETS gmock gmock_main DESTINATION lib) install(DIRECTORY ${gmock_SOURCE_DIR}/include/gmock DESTINATION include) ######################################################################## # # Google Mock's own tests. # # You can skip this section if you aren't interested in testing # Google Mock itself. # # The tests are not built by default. To build them, set the # gmock_build_tests option to ON. You can do it by running ccmake # or specifying the -Dgmock_build_tests=ON flag when running cmake. if (gmock_build_tests) # This must be set in the root directory for the tests to be run by # 'make test' or ctest. enable_testing() ############################################################ # C++ tests built with standard compiler flags. cxx_test(gmock-actions_test gmock_main) cxx_test(gmock-cardinalities_test gmock_main) cxx_test(gmock_ex_test gmock_main) cxx_test(gmock-generated-actions_test gmock_main) cxx_test(gmock-generated-function-mockers_test gmock_main) cxx_test(gmock-generated-internal-utils_test gmock_main) cxx_test(gmock-generated-matchers_test gmock_main) cxx_test(gmock-internal-utils_test gmock_main) cxx_test(gmock-matchers_test gmock_main) cxx_test(gmock-more-actions_test gmock_main) cxx_test(gmock-nice-strict_test gmock_main) cxx_test(gmock-port_test gmock_main) cxx_test(gmock-spec-builders_test gmock_main) cxx_test(gmock_link_test gmock_main test/gmock_link2_test.cc) cxx_test(gmock_test gmock_main) if (CMAKE_USE_PTHREADS_INIT) cxx_test(gmock_stress_test gmock) endif() # gmock_all_test is commented to save time building and running tests. # Uncomment if necessary. # cxx_test(gmock_all_test gmock_main) ############################################################ # C++ tests built with non-standard compiler flags. cxx_library(gmock_main_no_exception "${cxx_no_exception}" "${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc src/gmock_main.cc) cxx_library(gmock_main_no_rtti "${cxx_no_rtti}" "${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc src/gmock_main.cc) if (NOT MSVC OR MSVC_VERSION LESS 1600) # 1600 is Visual Studio 2010. # Visual Studio 2010, 2012, and 2013 define symbols in std::tr1 that # conflict with our own definitions. Therefore using our own tuple does not # work on those compilers. cxx_library(gmock_main_use_own_tuple "${cxx_use_own_tuple}" "${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc src/gmock_main.cc) cxx_test_with_flags(gmock_use_own_tuple_test "${cxx_use_own_tuple}" gmock_main_use_own_tuple test/gmock-spec-builders_test.cc) endif() cxx_test_with_flags(gmock-more-actions_no_exception_test "${cxx_no_exception}" gmock_main_no_exception test/gmock-more-actions_test.cc) cxx_test_with_flags(gmock_no_rtti_test "${cxx_no_rtti}" gmock_main_no_rtti test/gmock-spec-builders_test.cc) cxx_shared_library(shared_gmock_main "${cxx_default}" "${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc src/gmock_main.cc) # Tests that a binary can be built with Google Mock as a shared library. On # some system configurations, it may not possible to run the binary without # knowing more details about the system configurations. We do not try to run # this binary. To get a more robust shared library coverage, configure with # -DBUILD_SHARED_LIBS=ON. cxx_executable_with_flags(shared_gmock_test_ "${cxx_default}" shared_gmock_main test/gmock-spec-builders_test.cc) set_target_properties(shared_gmock_test_ PROPERTIES COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1") ############################################################ # Python tests. cxx_executable(gmock_leak_test_ test gmock_main) py_test(gmock_leak_test) cxx_executable(gmock_output_test_ test gmock) py_test(gmock_output_test) endif() nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/CONTRIBUTORS000066400000000000000000000025311455373415500245210ustar00rootroot00000000000000# This file contains a list of people who've made non-trivial # contribution to the Google C++ Mocking Framework project. People # who commit code to the project are encouraged to add their names # here. Please keep the list sorted by first names. Benoit Sigoure Bogdan Piloca Chandler Carruth Dave MacLachlan David Anderson Dean Sturtevant Gene Volovich Hal Burch Jeffrey Yasskin Jim Keller Joe Walnes Jon Wray Keir Mierle Keith Ray Kostya Serebryany Lev Makhlis Manuel Klimek Mario Tanev Mark Paskin Markus Heule Matthew Simmons Mike Bland Neal Norwitz Nermin Ozkiranartli Owen Carlsen Paneendra Ba Paul Menage Piotr Kaminski Russ Rufer Sverre Sundsdal Takeshi Yoshino Vadim Berman Vlad Losev Wolfgang Klier Zhanyong Wan nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/LICENSE000066400000000000000000000027031455373415500236470ustar00rootroot00000000000000Copyright 2008, Google Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/Makefile.am000066400000000000000000000167131455373415500247040ustar00rootroot00000000000000# Automake file # Nonstandard package files for distribution. EXTRA_DIST = LICENSE # We may need to build our internally packaged gtest. If so, it will be # included in the 'subdirs' variable. SUBDIRS = $(subdirs) # This is generated by the configure script, so clean it for distribution. DISTCLEANFILES = scripts/gmock-config # We define the global AM_CPPFLAGS as everything we compile includes from these # directories. AM_CPPFLAGS = $(GTEST_CPPFLAGS) -I$(srcdir)/include # Modifies compiler and linker flags for pthreads compatibility. if HAVE_PTHREADS AM_CXXFLAGS = @PTHREAD_CFLAGS@ -DGTEST_HAS_PTHREAD=1 AM_LIBS = @PTHREAD_LIBS@ endif # Build rules for libraries. lib_LTLIBRARIES = lib/libgmock.la lib/libgmock_main.la lib_libgmock_la_SOURCES = src/gmock-all.cc pkginclude_HEADERS = \ include/gmock/gmock-actions.h \ include/gmock/gmock-cardinalities.h \ include/gmock/gmock-generated-actions.h \ include/gmock/gmock-generated-function-mockers.h \ include/gmock/gmock-generated-matchers.h \ include/gmock/gmock-generated-nice-strict.h \ include/gmock/gmock-matchers.h \ include/gmock/gmock-more-actions.h \ include/gmock/gmock-more-matchers.h \ include/gmock/gmock-spec-builders.h \ include/gmock/gmock.h pkginclude_internaldir = $(pkgincludedir)/internal pkginclude_internal_HEADERS = \ include/gmock/internal/gmock-generated-internal-utils.h \ include/gmock/internal/gmock-internal-utils.h \ include/gmock/internal/gmock-port.h \ include/gmock/internal/custom/gmock-generated-actions.h \ include/gmock/internal/custom/gmock-matchers.h \ include/gmock/internal/custom/gmock-port.h lib_libgmock_main_la_SOURCES = src/gmock_main.cc lib_libgmock_main_la_LIBADD = lib/libgmock.la # Build rules for tests. Automake's naming for some of these variables isn't # terribly obvious, so this is a brief reference: # # TESTS -- Programs run automatically by "make check" # check_PROGRAMS -- Programs built by "make check" but not necessarily run TESTS= check_PROGRAMS= AM_LDFLAGS = $(GTEST_LDFLAGS) # This exercises all major components of Google Mock. It also # verifies that libgmock works. TESTS += test/gmock-spec-builders_test check_PROGRAMS += test/gmock-spec-builders_test test_gmock_spec_builders_test_SOURCES = test/gmock-spec-builders_test.cc test_gmock_spec_builders_test_LDADD = $(GTEST_LIBS) lib/libgmock.la # This tests using Google Mock in multiple translation units. It also # verifies that libgmock_main and libgmock work. TESTS += test/gmock_link_test check_PROGRAMS += test/gmock_link_test test_gmock_link_test_SOURCES = \ test/gmock_link2_test.cc \ test/gmock_link_test.cc \ test/gmock_link_test.h test_gmock_link_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la lib/libgmock.la if HAVE_PYTHON # Tests that fused gmock files compile and work. TESTS += test/gmock_fused_test check_PROGRAMS += test/gmock_fused_test test_gmock_fused_test_SOURCES = \ fused-src/gmock-gtest-all.cc \ fused-src/gmock/gmock.h \ fused-src/gmock_main.cc \ fused-src/gtest/gtest.h \ test/gmock_test.cc test_gmock_fused_test_CPPFLAGS = -I"$(srcdir)/fused-src" endif # Google Mock source files that we don't compile directly. GMOCK_SOURCE_INGLUDES = \ src/gmock-cardinalities.cc \ src/gmock-internal-utils.cc \ src/gmock-matchers.cc \ src/gmock-spec-builders.cc \ src/gmock.cc EXTRA_DIST += $(GMOCK_SOURCE_INGLUDES) # C++ tests that we don't compile using autotools. EXTRA_DIST += \ test/gmock-actions_test.cc \ test/gmock_all_test.cc \ test/gmock-cardinalities_test.cc \ test/gmock_ex_test.cc \ test/gmock-generated-actions_test.cc \ test/gmock-generated-function-mockers_test.cc \ test/gmock-generated-internal-utils_test.cc \ test/gmock-generated-matchers_test.cc \ test/gmock-internal-utils_test.cc \ test/gmock-matchers_test.cc \ test/gmock-more-actions_test.cc \ test/gmock-nice-strict_test.cc \ test/gmock-port_test.cc \ test/gmock_stress_test.cc # Python tests, which we don't run using autotools. EXTRA_DIST += \ test/gmock_leak_test.py \ test/gmock_leak_test_.cc \ test/gmock_output_test.py \ test/gmock_output_test_.cc \ test/gmock_output_test_golden.txt \ test/gmock_test_utils.py # Nonstandard package files for distribution. EXTRA_DIST += \ CHANGES \ CONTRIBUTORS \ make/Makefile # Pump scripts for generating Google Mock headers. # TODO(chandlerc@google.com): automate the generation of *.h from *.h.pump. EXTRA_DIST += \ include/gmock/gmock-generated-actions.h.pump \ include/gmock/gmock-generated-function-mockers.h.pump \ include/gmock/gmock-generated-matchers.h.pump \ include/gmock/gmock-generated-nice-strict.h.pump \ include/gmock/internal/gmock-generated-internal-utils.h.pump \ include/gmock/internal/custom/gmock-generated-actions.h.pump # Script for fusing Google Mock and Google Test source files. EXTRA_DIST += scripts/fuse_gmock_files.py # The Google Mock Generator tool from the cppclean project. EXTRA_DIST += \ scripts/generator/LICENSE \ scripts/generator/README \ scripts/generator/README.cppclean \ scripts/generator/cpp/__init__.py \ scripts/generator/cpp/ast.py \ scripts/generator/cpp/gmock_class.py \ scripts/generator/cpp/keywords.py \ scripts/generator/cpp/tokenize.py \ scripts/generator/cpp/utils.py \ scripts/generator/gmock_gen.py # Script for diagnosing compiler errors in programs that use Google # Mock. EXTRA_DIST += scripts/gmock_doctor.py # CMake scripts. EXTRA_DIST += \ CMakeLists.txt # Microsoft Visual Studio 2005 projects. EXTRA_DIST += \ msvc/2005/gmock.sln \ msvc/2005/gmock.vcproj \ msvc/2005/gmock_config.vsprops \ msvc/2005/gmock_main.vcproj \ msvc/2005/gmock_test.vcproj # Microsoft Visual Studio 2010 projects. EXTRA_DIST += \ msvc/2010/gmock.sln \ msvc/2010/gmock.vcxproj \ msvc/2010/gmock_config.props \ msvc/2010/gmock_main.vcxproj \ msvc/2010/gmock_test.vcxproj if HAVE_PYTHON # gmock_test.cc does not really depend on files generated by the # fused-gmock-internal rule. However, gmock_test.o does, and it is # important to include test/gmock_test.cc as part of this rule in order to # prevent compiling gmock_test.o until all dependent files have been # generated. $(test_gmock_fused_test_SOURCES): fused-gmock-internal # TODO(vladl@google.com): Find a way to add Google Tests's sources here. fused-gmock-internal: $(pkginclude_HEADERS) $(pkginclude_internal_HEADERS) \ $(lib_libgmock_la_SOURCES) $(GMOCK_SOURCE_INGLUDES) \ $(lib_libgmock_main_la_SOURCES) \ scripts/fuse_gmock_files.py mkdir -p "$(srcdir)/fused-src" chmod -R u+w "$(srcdir)/fused-src" rm -f "$(srcdir)/fused-src/gtest/gtest.h" rm -f "$(srcdir)/fused-src/gmock/gmock.h" rm -f "$(srcdir)/fused-src/gmock-gtest-all.cc" "$(srcdir)/scripts/fuse_gmock_files.py" "$(srcdir)/fused-src" cp -f "$(srcdir)/src/gmock_main.cc" "$(srcdir)/fused-src" maintainer-clean-local: rm -rf "$(srcdir)/fused-src" endif # Death tests may produce core dumps in the build directory. In case # this happens, clean them to keep distcleancheck happy. CLEANFILES = core # Disables 'make install' as installing a compiled version of Google # Mock can lead to undefined behavior due to violation of the # One-Definition Rule. install-exec-local: echo "'make install' is dangerous and not supported. Instead, see README for how to integrate Google Mock into your build system." false install-data-local: echo "'make install' is dangerous and not supported. Instead, see README for how to integrate Google Mock into your build system." false nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/README.md000066400000000000000000000305741455373415500241300ustar00rootroot00000000000000## Google Mock ## The Google C++ mocking framework. ### Overview ### Google's framework for writing and using C++ mock classes. It can help you derive better designs of your system and write better tests. It is inspired by: * [jMock](http://www.jmock.org/), * [EasyMock](http://www.easymock.org/), and * [Hamcrest](http://code.google.com/p/hamcrest/), and designed with C++'s specifics in mind. Google mock: * lets you create mock classes trivially using simple macros. * supports a rich set of matchers and actions. * handles unordered, partially ordered, or completely ordered expectations. * is extensible by users. We hope you find it useful! ### Features ### * Provides a declarative syntax for defining mocks. * Can easily define partial (hybrid) mocks, which are a cross of real and mock objects. * Handles functions of arbitrary types and overloaded functions. * Comes with a rich set of matchers for validating function arguments. * Uses an intuitive syntax for controlling the behavior of a mock. * Does automatic verification of expectations (no record-and-replay needed). * Allows arbitrary (partial) ordering constraints on function calls to be expressed,. * Lets a user extend it by defining new matchers and actions. * Does not use exceptions. * Is easy to learn and use. Please see the project page above for more information as well as the mailing list for questions, discussions, and development. There is also an IRC channel on OFTC (irc.oftc.net) #gtest available. Please join us! Please note that code under [scripts/generator](scripts/generator/) is from [cppclean](http://code.google.com/p/cppclean/) and released under the Apache License, which is different from Google Mock's license. ## Getting Started ## If you are new to the project, we suggest that you read the user documentation in the following order: * Learn the [basics](../googletest/docs/Primer.md) of Google Test, if you choose to use Google Mock with it (recommended). * Read [Google Mock for Dummies](docs/ForDummies.md). * Read the instructions below on how to build Google Mock. You can also watch Zhanyong's [talk](http://www.youtube.com/watch?v=sYpCyLI47rM) on Google Mock's usage and implementation. Once you understand the basics, check out the rest of the docs: * [CheatSheet](docs/CheatSheet.md) - all the commonly used stuff at a glance. * [CookBook](docs/CookBook.md) - recipes for getting things done, including advanced techniques. If you need help, please check the [KnownIssues](docs/KnownIssues.md) and [FrequentlyAskedQuestions](docs/FrequentlyAskedQuestions.md) before posting a question on the [discussion group](http://groups.google.com/group/googlemock). ### Using Google Mock Without Google Test ### Google Mock is not a testing framework itself. Instead, it needs a testing framework for writing tests. Google Mock works seamlessly with [Google Test](http://code.google.com/p/googletest/), but you can also use it with [any C++ testing framework](googlemock/ForDummies.md#Using_Google_Mock_with_Any_Testing_Framework). ### Requirements for End Users ### Google Mock is implemented on top of [Google Test]( http://github.com/google/googletest/), and depends on it. You must use the bundled version of Google Test when using Google Mock. You can also easily configure Google Mock to work with another testing framework, although it will still need Google Test. Please read ["Using_Google_Mock_with_Any_Testing_Framework"]( docs/ForDummies.md#Using_Google_Mock_with_Any_Testing_Framework) for instructions. Google Mock depends on advanced C++ features and thus requires a more modern compiler. The following are needed to use Google Mock: #### Linux Requirements #### * GNU-compatible Make or "gmake" * POSIX-standard shell * POSIX(-2) Regular Expressions (regex.h) * C++98-standard-compliant compiler (e.g. GCC 3.4 or newer) #### Windows Requirements #### * Microsoft Visual C++ 8.0 SP1 or newer #### Mac OS X Requirements #### * Mac OS X 10.4 Tiger or newer * Developer Tools Installed ### Requirements for Contributors ### We welcome patches. If you plan to contribute a patch, you need to build Google Mock and its tests, which has further requirements: * Automake version 1.9 or newer * Autoconf version 2.59 or newer * Libtool / Libtoolize * Python version 2.3 or newer (for running some of the tests and re-generating certain source files from templates) ### Building Google Mock ### #### Preparing to Build (Unix only) #### If you are using a Unix system and plan to use the GNU Autotools build system to build Google Mock (described below), you'll need to configure it now. To prepare the Autotools build system: cd googlemock autoreconf -fvi To build Google Mock and your tests that use it, you need to tell your build system where to find its headers and source files. The exact way to do it depends on which build system you use, and is usually straightforward. This section shows how you can integrate Google Mock into your existing build system. Suppose you put Google Mock in directory `${GMOCK_DIR}` and Google Test in `${GTEST_DIR}` (the latter is `${GMOCK_DIR}/gtest` by default). To build Google Mock, create a library build target (or a project as called by Visual Studio and Xcode) to compile ${GTEST_DIR}/src/gtest-all.cc and ${GMOCK_DIR}/src/gmock-all.cc with ${GTEST_DIR}/include and ${GMOCK_DIR}/include in the system header search path, and ${GTEST_DIR} and ${GMOCK_DIR} in the normal header search path. Assuming a Linux-like system and gcc, something like the following will do: g++ -isystem ${GTEST_DIR}/include -I${GTEST_DIR} \ -isystem ${GMOCK_DIR}/include -I${GMOCK_DIR} \ -pthread -c ${GTEST_DIR}/src/gtest-all.cc g++ -isystem ${GTEST_DIR}/include -I${GTEST_DIR} \ -isystem ${GMOCK_DIR}/include -I${GMOCK_DIR} \ -pthread -c ${GMOCK_DIR}/src/gmock-all.cc ar -rv libgmock.a gtest-all.o gmock-all.o (We need -pthread as Google Test and Google Mock use threads.) Next, you should compile your test source file with ${GTEST\_DIR}/include and ${GMOCK\_DIR}/include in the header search path, and link it with gmock and any other necessary libraries: g++ -isystem ${GTEST_DIR}/include -isystem ${GMOCK_DIR}/include \ -pthread path/to/your_test.cc libgmock.a -o your_test As an example, the make/ directory contains a Makefile that you can use to build Google Mock on systems where GNU make is available (e.g. Linux, Mac OS X, and Cygwin). It doesn't try to build Google Mock's own tests. Instead, it just builds the Google Mock library and a sample test. You can use it as a starting point for your own build script. If the default settings are correct for your environment, the following commands should succeed: cd ${GMOCK_DIR}/make make ./gmock_test If you see errors, try to tweak the contents of [make/Makefile](make/Makefile) to make them go away. ### Windows ### The msvc/2005 directory contains VC++ 2005 projects and the msvc/2010 directory contains VC++ 2010 projects for building Google Mock and selected tests. Change to the appropriate directory and run "msbuild gmock.sln" to build the library and tests (or open the gmock.sln in the MSVC IDE). If you want to create your own project to use with Google Mock, you'll have to configure it to use the `gmock_config` propety sheet. For that: * Open the Property Manager window (View | Other Windows | Property Manager) * Right-click on your project and select "Add Existing Property Sheet..." * Navigate to `gmock_config.vsprops` or `gmock_config.props` and select it. * In Project Properties | Configuration Properties | General | Additional Include Directories, type /include. ### Tweaking Google Mock ### Google Mock can be used in diverse environments. The default configuration may not work (or may not work well) out of the box in some environments. However, you can easily tweak Google Mock by defining control macros on the compiler command line. Generally, these macros are named like `GTEST_XYZ` and you define them to either 1 or 0 to enable or disable a certain feature. We list the most frequently used macros below. For a complete list, see file [${GTEST\_DIR}/include/gtest/internal/gtest-port.h]( ../googletest/include/gtest/internal/gtest-port.h). ### Choosing a TR1 Tuple Library ### Google Mock uses the C++ Technical Report 1 (TR1) tuple library heavily. Unfortunately TR1 tuple is not yet widely available with all compilers. The good news is that Google Test 1.4.0+ implements a subset of TR1 tuple that's enough for Google Mock's need. Google Mock will automatically use that implementation when the compiler doesn't provide TR1 tuple. Usually you don't need to care about which tuple library Google Test and Google Mock use. However, if your project already uses TR1 tuple, you need to tell Google Test and Google Mock to use the same TR1 tuple library the rest of your project uses, or the two tuple implementations will clash. To do that, add -DGTEST_USE_OWN_TR1_TUPLE=0 to the compiler flags while compiling Google Test, Google Mock, and your tests. If you want to force Google Test and Google Mock to use their own tuple library, just add -DGTEST_USE_OWN_TR1_TUPLE=1 to the compiler flags instead. If you want to use Boost's TR1 tuple library with Google Mock, please refer to the Boost website (http://www.boost.org/) for how to obtain it and set it up. ### As a Shared Library (DLL) ### Google Mock is compact, so most users can build and link it as a static library for the simplicity. Google Mock can be used as a DLL, but the same DLL must contain Google Test as well. See [Google Test's README][gtest_readme] for instructions on how to set up necessary compiler settings. ### Tweaking Google Mock ### Most of Google Test's control macros apply to Google Mock as well. Please see [Google Test's README][gtest_readme] for how to tweak them. ### Upgrading from an Earlier Version ### We strive to keep Google Mock releases backward compatible. Sometimes, though, we have to make some breaking changes for the users' long-term benefits. This section describes what you'll need to do if you are upgrading from an earlier version of Google Mock. #### Upgrading from 1.1.0 or Earlier #### You may need to explicitly enable or disable Google Test's own TR1 tuple library. See the instructions in section "[Choosing a TR1 Tuple Library](../googletest/#choosing-a-tr1-tuple-library)". #### Upgrading from 1.4.0 or Earlier #### On platforms where the pthread library is available, Google Test and Google Mock use it in order to be thread-safe. For this to work, you may need to tweak your compiler and/or linker flags. Please see the "[Multi-threaded Tests](../googletest#multi-threaded-tests )" section in file Google Test's README for what you may need to do. If you have custom matchers defined using `MatcherInterface` or `MakePolymorphicMatcher()`, you'll need to update their definitions to use the new matcher API ( [monomorphic](http://code.google.com/p/googlemock/wiki/CookBook#Writing_New_Monomorphic_Matchers), [polymorphic](http://code.google.com/p/googlemock/wiki/CookBook#Writing_New_Polymorphic_Matchers)). Matchers defined using `MATCHER()` or `MATCHER_P*()` aren't affected. ### Developing Google Mock ### This section discusses how to make your own changes to Google Mock. #### Testing Google Mock Itself #### To make sure your changes work as intended and don't break existing functionality, you'll want to compile and run Google Test's own tests. For that you'll need Autotools. First, make sure you have followed the instructions above to configure Google Mock. Then, create a build output directory and enter it. Next, ${GMOCK_DIR}/configure # try --help for more info Once you have successfully configured Google Mock, the build steps are standard for GNU-style OSS packages. make # Standard makefile following GNU conventions make check # Builds and runs all tests - all should pass. Note that when building your project against Google Mock, you are building against Google Test as well. There is no need to configure Google Test separately. #### Contributing a Patch #### We welcome patches. Please read the [Developer's Guide](docs/DevGuide.md) for how you can contribute. In particular, make sure you have signed the Contributor License Agreement, or we won't be able to accept the patch. Happy testing! [gtest_readme]: ../googletest/README.md "googletest" nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/build-aux/000077500000000000000000000000001455373415500245325ustar00rootroot00000000000000nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/build-aux/.keep000066400000000000000000000000001455373415500254450ustar00rootroot00000000000000nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/configure.ac000066400000000000000000000142261455373415500251330ustar00rootroot00000000000000m4_include(../googletest/m4/acx_pthread.m4) AC_INIT([Google C++ Mocking Framework], [1.7.0], [googlemock@googlegroups.com], [gmock]) # Provide various options to initialize the Autoconf and configure processes. AC_PREREQ([2.59]) AC_CONFIG_SRCDIR([./LICENSE]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_HEADERS([build-aux/config.h]) AC_CONFIG_FILES([Makefile]) AC_CONFIG_FILES([scripts/gmock-config], [chmod +x scripts/gmock-config]) # Initialize Automake with various options. We require at least v1.9, prevent # pedantic complaints about package files, and enable various distribution # targets. AM_INIT_AUTOMAKE([1.9 dist-bzip2 dist-zip foreign subdir-objects]) # Check for programs used in building Google Test. AC_PROG_CC AC_PROG_CXX AC_LANG([C++]) AC_PROG_LIBTOOL # TODO(chandlerc@google.com): Currently we aren't running the Python tests # against the interpreter detected by AM_PATH_PYTHON, and so we condition # HAVE_PYTHON by requiring "python" to be in the PATH, and that interpreter's # version to be >= 2.3. This will allow the scripts to use a "/usr/bin/env" # hashbang. PYTHON= # We *do not* allow the user to specify a python interpreter AC_PATH_PROG([PYTHON],[python],[:]) AS_IF([test "$PYTHON" != ":"], [AM_PYTHON_CHECK_VERSION([$PYTHON],[2.3],[:],[PYTHON=":"])]) AM_CONDITIONAL([HAVE_PYTHON],[test "$PYTHON" != ":"]) # TODO(chandlerc@google.com) Check for the necessary system headers. # Configure pthreads. AC_ARG_WITH([pthreads], [AS_HELP_STRING([--with-pthreads], [use pthreads (default is yes)])], [with_pthreads=$withval], [with_pthreads=check]) have_pthreads=no AS_IF([test "x$with_pthreads" != "xno"], [ACX_PTHREAD( [], [AS_IF([test "x$with_pthreads" != "xcheck"], [AC_MSG_FAILURE( [--with-pthreads was specified, but unable to be used])])]) have_pthreads="$acx_pthread_ok"]) AM_CONDITIONAL([HAVE_PTHREADS],[test "x$have_pthreads" == "xyes"]) AC_SUBST(PTHREAD_CFLAGS) AC_SUBST(PTHREAD_LIBS) # GoogleMock currently has hard dependencies upon GoogleTest above and beyond # running its own test suite, so we both provide our own version in # a subdirectory and provide some logic to use a custom version or a system # installed version. AC_ARG_WITH([gtest], [AS_HELP_STRING([--with-gtest], [Specifies how to find the gtest package. If no arguments are given, the default behavior, a system installed gtest will be used if present, and an internal version built otherwise. If a path is provided, the gtest built or installed at that prefix will be used.])], [], [with_gtest=yes]) AC_ARG_ENABLE([external-gtest], [AS_HELP_STRING([--disable-external-gtest], [Disables any detection or use of a system installed or user provided gtest. Any option to '--with-gtest' is ignored. (Default is enabled.)]) ], [], [enable_external_gtest=yes]) AS_IF([test "x$with_gtest" == "xno"], [AC_MSG_ERROR([dnl Support for GoogleTest was explicitly disabled. Currently GoogleMock has a hard dependency upon GoogleTest to build, please provide a version, or allow GoogleMock to use any installed version and fall back upon its internal version.])]) # Setup various GTEST variables. TODO(chandlerc@google.com): When these are # used below, they should be used such that any pre-existing values always # trump values we set them to, so that they can be used to selectively override # details of the detection process. AC_ARG_VAR([GTEST_CONFIG], [The exact path of Google Test's 'gtest-config' script.]) AC_ARG_VAR([GTEST_CPPFLAGS], [C-like preprocessor flags for Google Test.]) AC_ARG_VAR([GTEST_CXXFLAGS], [C++ compile flags for Google Test.]) AC_ARG_VAR([GTEST_LDFLAGS], [Linker path and option flags for Google Test.]) AC_ARG_VAR([GTEST_LIBS], [Library linking flags for Google Test.]) AC_ARG_VAR([GTEST_VERSION], [The version of Google Test available.]) HAVE_BUILT_GTEST="no" GTEST_MIN_VERSION="1.7.0" AS_IF([test "x${enable_external_gtest}" = "xyes"], [# Begin filling in variables as we are able. AS_IF([test "x${with_gtest}" != "xyes"], [AS_IF([test -x "${with_gtest}/scripts/gtest-config"], [GTEST_CONFIG="${with_gtest}/scripts/gtest-config"], [GTEST_CONFIG="${with_gtest}/bin/gtest-config"]) AS_IF([test -x "${GTEST_CONFIG}"], [], [AC_MSG_ERROR([dnl Unable to locate either a built or installed Google Test at '${with_gtest}'.]) ])]) AS_IF([test -x "${GTEST_CONFIG}"], [], [AC_PATH_PROG([GTEST_CONFIG], [gtest-config])]) AS_IF([test -x "${GTEST_CONFIG}"], [AC_MSG_CHECKING([for Google Test version >= ${GTEST_MIN_VERSION}]) AS_IF([${GTEST_CONFIG} --min-version=${GTEST_MIN_VERSION}], [AC_MSG_RESULT([yes]) HAVE_BUILT_GTEST="yes"], [AC_MSG_RESULT([no])])])]) AS_IF([test "x${HAVE_BUILT_GTEST}" = "xyes"], [GTEST_CPPFLAGS=`${GTEST_CONFIG} --cppflags` GTEST_CXXFLAGS=`${GTEST_CONFIG} --cxxflags` GTEST_LDFLAGS=`${GTEST_CONFIG} --ldflags` GTEST_LIBS=`${GTEST_CONFIG} --libs` GTEST_VERSION=`${GTEST_CONFIG} --version`], [AC_CONFIG_SUBDIRS([../googletest]) # GTEST_CONFIG needs to be executable both in a Makefile environmont and # in a shell script environment, so resolve an absolute path for it here. GTEST_CONFIG="`pwd -P`/../googletest/scripts/gtest-config" GTEST_CPPFLAGS='-I$(top_srcdir)/../googletest/include' GTEST_CXXFLAGS='-g' GTEST_LDFLAGS='' GTEST_LIBS='$(top_builddir)/../googletest/lib/libgtest.la' GTEST_VERSION="${GTEST_MIN_VERSION}"]) # TODO(chandlerc@google.com) Check the types, structures, and other compiler # and architecture characteristics. # Output the generated files. No further autoconf macros may be used. AC_OUTPUT nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/docs/000077500000000000000000000000001455373415500235705ustar00rootroot00000000000000nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/docs/CheatSheet.md000066400000000000000000000670061455373415500261400ustar00rootroot00000000000000 # Defining a Mock Class # ## Mocking a Normal Class ## Given ``` class Foo { ... virtual ~Foo(); virtual int GetSize() const = 0; virtual string Describe(const char* name) = 0; virtual string Describe(int type) = 0; virtual bool Process(Bar elem, int count) = 0; }; ``` (note that `~Foo()` **must** be virtual) we can define its mock as ``` #include "gmock/gmock.h" class MockFoo : public Foo { MOCK_CONST_METHOD0(GetSize, int()); MOCK_METHOD1(Describe, string(const char* name)); MOCK_METHOD1(Describe, string(int type)); MOCK_METHOD2(Process, bool(Bar elem, int count)); }; ``` To create a "nice" mock object which ignores all uninteresting calls, or a "strict" mock object, which treats them as failures: ``` NiceMock nice_foo; // The type is a subclass of MockFoo. StrictMock strict_foo; // The type is a subclass of MockFoo. ``` ## Mocking a Class Template ## To mock ``` template class StackInterface { public: ... virtual ~StackInterface(); virtual int GetSize() const = 0; virtual void Push(const Elem& x) = 0; }; ``` (note that `~StackInterface()` **must** be virtual) just append `_T` to the `MOCK_*` macros: ``` template class MockStack : public StackInterface { public: ... MOCK_CONST_METHOD0_T(GetSize, int()); MOCK_METHOD1_T(Push, void(const Elem& x)); }; ``` ## Specifying Calling Conventions for Mock Functions ## If your mock function doesn't use the default calling convention, you can specify it by appending `_WITH_CALLTYPE` to any of the macros described in the previous two sections and supplying the calling convention as the first argument to the macro. For example, ``` MOCK_METHOD_1_WITH_CALLTYPE(STDMETHODCALLTYPE, Foo, bool(int n)); MOCK_CONST_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, Bar, int(double x, double y)); ``` where `STDMETHODCALLTYPE` is defined by `` on Windows. # Using Mocks in Tests # The typical flow is: 1. Import the Google Mock names you need to use. All Google Mock names are in the `testing` namespace unless they are macros or otherwise noted. 1. Create the mock objects. 1. Optionally, set the default actions of the mock objects. 1. Set your expectations on the mock objects (How will they be called? What wil they do?). 1. Exercise code that uses the mock objects; if necessary, check the result using [Google Test](../../googletest/) assertions. 1. When a mock objects is destructed, Google Mock automatically verifies that all expectations on it have been satisfied. Here is an example: ``` using ::testing::Return; // #1 TEST(BarTest, DoesThis) { MockFoo foo; // #2 ON_CALL(foo, GetSize()) // #3 .WillByDefault(Return(1)); // ... other default actions ... EXPECT_CALL(foo, Describe(5)) // #4 .Times(3) .WillRepeatedly(Return("Category 5")); // ... other expectations ... EXPECT_EQ("good", MyProductionFunction(&foo)); // #5 } // #6 ``` # Setting Default Actions # Google Mock has a **built-in default action** for any function that returns `void`, `bool`, a numeric value, or a pointer. To customize the default action for functions with return type `T` globally: ``` using ::testing::DefaultValue; // Sets the default value to be returned. T must be CopyConstructible. DefaultValue::Set(value); // Sets a factory. Will be invoked on demand. T must be MoveConstructible. // T MakeT(); DefaultValue::SetFactory(&MakeT); // ... use the mocks ... // Resets the default value. DefaultValue::Clear(); ``` To customize the default action for a particular method, use `ON_CALL()`: ``` ON_CALL(mock_object, method(matchers)) .With(multi_argument_matcher) ? .WillByDefault(action); ``` # Setting Expectations # `EXPECT_CALL()` sets **expectations** on a mock method (How will it be called? What will it do?): ``` EXPECT_CALL(mock_object, method(matchers)) .With(multi_argument_matcher) ? .Times(cardinality) ? .InSequence(sequences) * .After(expectations) * .WillOnce(action) * .WillRepeatedly(action) ? .RetiresOnSaturation(); ? ``` If `Times()` is omitted, the cardinality is assumed to be: * `Times(1)` when there is neither `WillOnce()` nor `WillRepeatedly()`; * `Times(n)` when there are `n WillOnce()`s but no `WillRepeatedly()`, where `n` >= 1; or * `Times(AtLeast(n))` when there are `n WillOnce()`s and a `WillRepeatedly()`, where `n` >= 0. A method with no `EXPECT_CALL()` is free to be invoked _any number of times_, and the default action will be taken each time. # Matchers # A **matcher** matches a _single_ argument. You can use it inside `ON_CALL()` or `EXPECT_CALL()`, or use it to validate a value directly: | `EXPECT_THAT(value, matcher)` | Asserts that `value` matches `matcher`. | |:------------------------------|:----------------------------------------| | `ASSERT_THAT(value, matcher)` | The same as `EXPECT_THAT(value, matcher)`, except that it generates a **fatal** failure. | Built-in matchers (where `argument` is the function argument) are divided into several categories: ## Wildcard ## |`_`|`argument` can be any value of the correct type.| |:--|:-----------------------------------------------| |`A()` or `An()`|`argument` can be any value of type `type`. | ## Generic Comparison ## |`Eq(value)` or `value`|`argument == value`| |:---------------------|:------------------| |`Ge(value)` |`argument >= value`| |`Gt(value)` |`argument > value` | |`Le(value)` |`argument <= value`| |`Lt(value)` |`argument < value` | |`Ne(value)` |`argument != value`| |`IsNull()` |`argument` is a `NULL` pointer (raw or smart).| |`NotNull()` |`argument` is a non-null pointer (raw or smart).| |`Ref(variable)` |`argument` is a reference to `variable`.| |`TypedEq(value)`|`argument` has type `type` and is equal to `value`. You may need to use this instead of `Eq(value)` when the mock function is overloaded.| Except `Ref()`, these matchers make a _copy_ of `value` in case it's modified or destructed later. If the compiler complains that `value` doesn't have a public copy constructor, try wrap it in `ByRef()`, e.g. `Eq(ByRef(non_copyable_value))`. If you do that, make sure `non_copyable_value` is not changed afterwards, or the meaning of your matcher will be changed. ## Floating-Point Matchers ## |`DoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as unequal.| |:-------------------|:----------------------------------------------------------------------------------------------| |`FloatEq(a_float)` |`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as unequal. | |`NanSensitiveDoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as equal. | |`NanSensitiveFloatEq(a_float)`|`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as equal. | The above matchers use ULP-based comparison (the same as used in [Google Test](../../googletest/)). They automatically pick a reasonable error bound based on the absolute value of the expected value. `DoubleEq()` and `FloatEq()` conform to the IEEE standard, which requires comparing two NaNs for equality to return false. The `NanSensitive*` version instead treats two NaNs as equal, which is often what a user wants. |`DoubleNear(a_double, max_abs_error)`|`argument` is a `double` value close to `a_double` (absolute error <= `max_abs_error`), treating two NaNs as unequal.| |:------------------------------------|:--------------------------------------------------------------------------------------------------------------------| |`FloatNear(a_float, max_abs_error)` |`argument` is a `float` value close to `a_float` (absolute error <= `max_abs_error`), treating two NaNs as unequal. | |`NanSensitiveDoubleNear(a_double, max_abs_error)`|`argument` is a `double` value close to `a_double` (absolute error <= `max_abs_error`), treating two NaNs as equal. | |`NanSensitiveFloatNear(a_float, max_abs_error)`|`argument` is a `float` value close to `a_float` (absolute error <= `max_abs_error`), treating two NaNs as equal. | ## String Matchers ## The `argument` can be either a C string or a C++ string object: |`ContainsRegex(string)`|`argument` matches the given regular expression.| |:----------------------|:-----------------------------------------------| |`EndsWith(suffix)` |`argument` ends with string `suffix`. | |`HasSubstr(string)` |`argument` contains `string` as a sub-string. | |`MatchesRegex(string)` |`argument` matches the given regular expression with the match starting at the first character and ending at the last character.| |`StartsWith(prefix)` |`argument` starts with string `prefix`. | |`StrCaseEq(string)` |`argument` is equal to `string`, ignoring case. | |`StrCaseNe(string)` |`argument` is not equal to `string`, ignoring case.| |`StrEq(string)` |`argument` is equal to `string`. | |`StrNe(string)` |`argument` is not equal to `string`. | `ContainsRegex()` and `MatchesRegex()` use the regular expression syntax defined [here](../../googletest/docs/AdvancedGuide.md#regular-expression-syntax). `StrCaseEq()`, `StrCaseNe()`, `StrEq()`, and `StrNe()` work for wide strings as well. ## Container Matchers ## Most STL-style containers support `==`, so you can use `Eq(expected_container)` or simply `expected_container` to match a container exactly. If you want to write the elements in-line, match them more flexibly, or get more informative messages, you can use: | `ContainerEq(container)` | The same as `Eq(container)` except that the failure message also includes which elements are in one container but not the other. | |:-------------------------|:---------------------------------------------------------------------------------------------------------------------------------| | `Contains(e)` | `argument` contains an element that matches `e`, which can be either a value or a matcher. | | `Each(e)` | `argument` is a container where _every_ element matches `e`, which can be either a value or a matcher. | | `ElementsAre(e0, e1, ..., en)` | `argument` has `n + 1` elements, where the i-th element matches `ei`, which can be a value or a matcher. 0 to 10 arguments are allowed. | | `ElementsAreArray({ e0, e1, ..., en })`, `ElementsAreArray(array)`, or `ElementsAreArray(array, count)` | The same as `ElementsAre()` except that the expected element values/matchers come from an initializer list, STL-style container, or C-style array. | | `IsEmpty()` | `argument` is an empty container (`container.empty()`). | | `Pointwise(m, container)` | `argument` contains the same number of elements as in `container`, and for all i, (the i-th element in `argument`, the i-th element in `container`) match `m`, which is a matcher on 2-tuples. E.g. `Pointwise(Le(), upper_bounds)` verifies that each element in `argument` doesn't exceed the corresponding element in `upper_bounds`. See more detail below. | | `SizeIs(m)` | `argument` is a container whose size matches `m`. E.g. `SizeIs(2)` or `SizeIs(Lt(2))`. | | `UnorderedElementsAre(e0, e1, ..., en)` | `argument` has `n + 1` elements, and under some permutation each element matches an `ei` (for a different `i`), which can be a value or a matcher. 0 to 10 arguments are allowed. | | `UnorderedElementsAreArray({ e0, e1, ..., en })`, `UnorderedElementsAreArray(array)`, or `UnorderedElementsAreArray(array, count)` | The same as `UnorderedElementsAre()` except that the expected element values/matchers come from an initializer list, STL-style container, or C-style array. | | `WhenSorted(m)` | When `argument` is sorted using the `<` operator, it matches container matcher `m`. E.g. `WhenSorted(UnorderedElementsAre(1, 2, 3))` verifies that `argument` contains elements `1`, `2`, and `3`, ignoring order. | | `WhenSortedBy(comparator, m)` | The same as `WhenSorted(m)`, except that the given comparator instead of `<` is used to sort `argument`. E.g. `WhenSortedBy(std::greater(), ElementsAre(3, 2, 1))`. | Notes: * These matchers can also match: 1. a native array passed by reference (e.g. in `Foo(const int (&a)[5])`), and 1. an array passed as a pointer and a count (e.g. in `Bar(const T* buffer, int len)` -- see [Multi-argument Matchers](#Multiargument_Matchers.md)). * The array being matched may be multi-dimensional (i.e. its elements can be arrays). * `m` in `Pointwise(m, ...)` should be a matcher for `::testing::tuple` where `T` and `U` are the element type of the actual container and the expected container, respectively. For example, to compare two `Foo` containers where `Foo` doesn't support `operator==` but has an `Equals()` method, one might write: ``` using ::testing::get; MATCHER(FooEq, "") { return get<0>(arg).Equals(get<1>(arg)); } ... EXPECT_THAT(actual_foos, Pointwise(FooEq(), expected_foos)); ``` ## Member Matchers ## |`Field(&class::field, m)`|`argument.field` (or `argument->field` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.| |:------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------| |`Key(e)` |`argument.first` matches `e`, which can be either a value or a matcher. E.g. `Contains(Key(Le(5)))` can verify that a `map` contains a key `<= 5`.| |`Pair(m1, m2)` |`argument` is an `std::pair` whose `first` field matches `m1` and `second` field matches `m2`. | |`Property(&class::property, m)`|`argument.property()` (or `argument->property()` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.| ## Matching the Result of a Function or Functor ## |`ResultOf(f, m)`|`f(argument)` matches matcher `m`, where `f` is a function or functor.| |:---------------|:---------------------------------------------------------------------| ## Pointer Matchers ## |`Pointee(m)`|`argument` (either a smart pointer or a raw pointer) points to a value that matches matcher `m`.| |:-----------|:-----------------------------------------------------------------------------------------------| |`WhenDynamicCastTo(m)`| when `argument` is passed through `dynamic_cast()`, it matches matcher `m`. | ## Multiargument Matchers ## Technically, all matchers match a _single_ value. A "multi-argument" matcher is just one that matches a _tuple_. The following matchers can be used to match a tuple `(x, y)`: |`Eq()`|`x == y`| |:-----|:-------| |`Ge()`|`x >= y`| |`Gt()`|`x > y` | |`Le()`|`x <= y`| |`Lt()`|`x < y` | |`Ne()`|`x != y`| You can use the following selectors to pick a subset of the arguments (or reorder them) to participate in the matching: |`AllArgs(m)`|Equivalent to `m`. Useful as syntactic sugar in `.With(AllArgs(m))`.| |:-----------|:-------------------------------------------------------------------| |`Args(m)`|The tuple of the `k` selected (using 0-based indices) arguments matches `m`, e.g. `Args<1, 2>(Eq())`.| ## Composite Matchers ## You can make a matcher from one or more other matchers: |`AllOf(m1, m2, ..., mn)`|`argument` matches all of the matchers `m1` to `mn`.| |:-----------------------|:---------------------------------------------------| |`AnyOf(m1, m2, ..., mn)`|`argument` matches at least one of the matchers `m1` to `mn`.| |`Not(m)` |`argument` doesn't match matcher `m`. | ## Adapters for Matchers ## |`MatcherCast(m)`|casts matcher `m` to type `Matcher`.| |:------------------|:--------------------------------------| |`SafeMatcherCast(m)`| [safely casts](CookBook.md#casting-matchers) matcher `m` to type `Matcher`. | |`Truly(predicate)` |`predicate(argument)` returns something considered by C++ to be true, where `predicate` is a function or functor.| ## Matchers as Predicates ## |`Matches(m)(value)`|evaluates to `true` if `value` matches `m`. You can use `Matches(m)` alone as a unary functor.| |:------------------|:---------------------------------------------------------------------------------------------| |`ExplainMatchResult(m, value, result_listener)`|evaluates to `true` if `value` matches `m`, explaining the result to `result_listener`. | |`Value(value, m)` |evaluates to `true` if `value` matches `m`. | ## Defining Matchers ## | `MATCHER(IsEven, "") { return (arg % 2) == 0; }` | Defines a matcher `IsEven()` to match an even number. | |:-------------------------------------------------|:------------------------------------------------------| | `MATCHER_P(IsDivisibleBy, n, "") { *result_listener << "where the remainder is " << (arg % n); return (arg % n) == 0; }` | Defines a macher `IsDivisibleBy(n)` to match a number divisible by `n`. | | `MATCHER_P2(IsBetween, a, b, std::string(negation ? "isn't" : "is") + " between " + PrintToString(a) + " and " + PrintToString(b)) { return a <= arg && arg <= b; }` | Defines a matcher `IsBetween(a, b)` to match a value in the range [`a`, `b`]. | **Notes:** 1. The `MATCHER*` macros cannot be used inside a function or class. 1. The matcher body must be _purely functional_ (i.e. it cannot have any side effect, and the result must not depend on anything other than the value being matched and the matcher parameters). 1. You can use `PrintToString(x)` to convert a value `x` of any type to a string. ## Matchers as Test Assertions ## |`ASSERT_THAT(expression, m)`|Generates a [fatal failure](../../googletest/docs/Primer.md#assertions) if the value of `expression` doesn't match matcher `m`.| |:---------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------| |`EXPECT_THAT(expression, m)`|Generates a non-fatal failure if the value of `expression` doesn't match matcher `m`. | # Actions # **Actions** specify what a mock function should do when invoked. ## Returning a Value ## |`Return()`|Return from a `void` mock function.| |:---------|:----------------------------------| |`Return(value)`|Return `value`. If the type of `value` is different to the mock function's return type, `value` is converted to the latter type at the time the expectation is set, not when the action is executed.| |`ReturnArg()`|Return the `N`-th (0-based) argument.| |`ReturnNew(a1, ..., ak)`|Return `new T(a1, ..., ak)`; a different object is created each time.| |`ReturnNull()`|Return a null pointer. | |`ReturnPointee(ptr)`|Return the value pointed to by `ptr`.| |`ReturnRef(variable)`|Return a reference to `variable`. | |`ReturnRefOfCopy(value)`|Return a reference to a copy of `value`; the copy lives as long as the action.| ## Side Effects ## |`Assign(&variable, value)`|Assign `value` to variable.| |:-------------------------|:--------------------------| | `DeleteArg()` | Delete the `N`-th (0-based) argument, which must be a pointer. | | `SaveArg(pointer)` | Save the `N`-th (0-based) argument to `*pointer`. | | `SaveArgPointee(pointer)` | Save the value pointed to by the `N`-th (0-based) argument to `*pointer`. | | `SetArgReferee(value)` | Assign value to the variable referenced by the `N`-th (0-based) argument. | |`SetArgPointee(value)` |Assign `value` to the variable pointed by the `N`-th (0-based) argument.| |`SetArgumentPointee(value)`|Same as `SetArgPointee(value)`. Deprecated. Will be removed in v1.7.0.| |`SetArrayArgument(first, last)`|Copies the elements in source range [`first`, `last`) to the array pointed to by the `N`-th (0-based) argument, which can be either a pointer or an iterator. The action does not take ownership of the elements in the source range.| |`SetErrnoAndReturn(error, value)`|Set `errno` to `error` and return `value`.| |`Throw(exception)` |Throws the given exception, which can be any copyable value. Available since v1.1.0.| ## Using a Function or a Functor as an Action ## |`Invoke(f)`|Invoke `f` with the arguments passed to the mock function, where `f` can be a global/static function or a functor.| |:----------|:-----------------------------------------------------------------------------------------------------------------| |`Invoke(object_pointer, &class::method)`|Invoke the {method on the object with the arguments passed to the mock function. | |`InvokeWithoutArgs(f)`|Invoke `f`, which can be a global/static function or a functor. `f` must take no arguments. | |`InvokeWithoutArgs(object_pointer, &class::method)`|Invoke the method on the object, which takes no arguments. | |`InvokeArgument(arg1, arg2, ..., argk)`|Invoke the mock function's `N`-th (0-based) argument, which must be a function or a functor, with the `k` arguments.| The return value of the invoked function is used as the return value of the action. When defining a function or functor to be used with `Invoke*()`, you can declare any unused parameters as `Unused`: ``` double Distance(Unused, double x, double y) { return sqrt(x*x + y*y); } ... EXPECT_CALL(mock, Foo("Hi", _, _)).WillOnce(Invoke(Distance)); ``` In `InvokeArgument(...)`, if an argument needs to be passed by reference, wrap it inside `ByRef()`. For example, ``` InvokeArgument<2>(5, string("Hi"), ByRef(foo)) ``` calls the mock function's #2 argument, passing to it `5` and `string("Hi")` by value, and `foo` by reference. ## Default Action ## |`DoDefault()`|Do the default action (specified by `ON_CALL()` or the built-in one).| |:------------|:--------------------------------------------------------------------| **Note:** due to technical reasons, `DoDefault()` cannot be used inside a composite action - trying to do so will result in a run-time error. ## Composite Actions ## |`DoAll(a1, a2, ..., an)`|Do all actions `a1` to `an` and return the result of `an` in each invocation. The first `n - 1` sub-actions must return void. | |:-----------------------|:-----------------------------------------------------------------------------------------------------------------------------| |`IgnoreResult(a)` |Perform action `a` and ignore its result. `a` must not return void. | |`WithArg(a)` |Pass the `N`-th (0-based) argument of the mock function to action `a` and perform it. | |`WithArgs(a)`|Pass the selected (0-based) arguments of the mock function to action `a` and perform it. | |`WithoutArgs(a)` |Perform action `a` without any arguments. | ## Defining Actions ## | `ACTION(Sum) { return arg0 + arg1; }` | Defines an action `Sum()` to return the sum of the mock function's argument #0 and #1. | |:--------------------------------------|:---------------------------------------------------------------------------------------| | `ACTION_P(Plus, n) { return arg0 + n; }` | Defines an action `Plus(n)` to return the sum of the mock function's argument #0 and `n`. | | `ACTION_Pk(Foo, p1, ..., pk) { statements; }` | Defines a parameterized action `Foo(p1, ..., pk)` to execute the given `statements`. | The `ACTION*` macros cannot be used inside a function or class. # Cardinalities # These are used in `Times()` to specify how many times a mock function will be called: |`AnyNumber()`|The function can be called any number of times.| |:------------|:----------------------------------------------| |`AtLeast(n)` |The call is expected at least `n` times. | |`AtMost(n)` |The call is expected at most `n` times. | |`Between(m, n)`|The call is expected between `m` and `n` (inclusive) times.| |`Exactly(n) or n`|The call is expected exactly `n` times. In particular, the call should never happen when `n` is 0.| # Expectation Order # By default, the expectations can be matched in _any_ order. If some or all expectations must be matched in a given order, there are two ways to specify it. They can be used either independently or together. ## The After Clause ## ``` using ::testing::Expectation; ... Expectation init_x = EXPECT_CALL(foo, InitX()); Expectation init_y = EXPECT_CALL(foo, InitY()); EXPECT_CALL(foo, Bar()) .After(init_x, init_y); ``` says that `Bar()` can be called only after both `InitX()` and `InitY()` have been called. If you don't know how many pre-requisites an expectation has when you write it, you can use an `ExpectationSet` to collect them: ``` using ::testing::ExpectationSet; ... ExpectationSet all_inits; for (int i = 0; i < element_count; i++) { all_inits += EXPECT_CALL(foo, InitElement(i)); } EXPECT_CALL(foo, Bar()) .After(all_inits); ``` says that `Bar()` can be called only after all elements have been initialized (but we don't care about which elements get initialized before the others). Modifying an `ExpectationSet` after using it in an `.After()` doesn't affect the meaning of the `.After()`. ## Sequences ## When you have a long chain of sequential expectations, it's easier to specify the order using **sequences**, which don't require you to given each expectation in the chain a different name. All expected
calls
in the same sequence must occur in the order they are specified. ``` using ::testing::Sequence; Sequence s1, s2; ... EXPECT_CALL(foo, Reset()) .InSequence(s1, s2) .WillOnce(Return(true)); EXPECT_CALL(foo, GetSize()) .InSequence(s1) .WillOnce(Return(1)); EXPECT_CALL(foo, Describe(A())) .InSequence(s2) .WillOnce(Return("dummy")); ``` says that `Reset()` must be called before _both_ `GetSize()` _and_ `Describe()`, and the latter two can occur in any order. To put many expectations in a sequence conveniently: ``` using ::testing::InSequence; { InSequence dummy; EXPECT_CALL(...)...; EXPECT_CALL(...)...; ... EXPECT_CALL(...)...; } ``` says that all expected calls in the scope of `dummy` must occur in strict order. The name `dummy` is irrelevant.) # Verifying and Resetting a Mock # Google Mock will verify the expectations on a mock object when it is destructed, or you can do it earlier: ``` using ::testing::Mock; ... // Verifies and removes the expectations on mock_obj; // returns true iff successful. Mock::VerifyAndClearExpectations(&mock_obj); ... // Verifies and removes the expectations on mock_obj; // also removes the default actions set by ON_CALL(); // returns true iff successful. Mock::VerifyAndClear(&mock_obj); ``` You can also tell Google Mock that a mock object can be leaked and doesn't need to be verified: ``` Mock::AllowLeak(&mock_obj); ``` # Mock Classes # Google Mock defines a convenient mock class template ``` class MockFunction { public: MOCK_METHODn(Call, R(A1, ..., An)); }; ``` See this [recipe](CookBook.md#using-check-points) for one application of it. # Flags # | `--gmock_catch_leaked_mocks=0` | Don't report leaked mock objects as failures. | |:-------------------------------|:----------------------------------------------| | `--gmock_verbose=LEVEL` | Sets the default verbosity level (`info`, `warning`, or `error`) of Google Mock messages. | nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/docs/CookBook.md000066400000000000000000003773601455373415500256400ustar00rootroot00000000000000 You can find recipes for using Google Mock here. If you haven't yet, please read the [ForDummies](ForDummies.md) document first to make sure you understand the basics. **Note:** Google Mock lives in the `testing` name space. For readability, it is recommended to write `using ::testing::Foo;` once in your file before using the name `Foo` defined by Google Mock. We omit such `using` statements in this page for brevity, but you should do it in your own code. # Creating Mock Classes # ## Mocking Private or Protected Methods ## You must always put a mock method definition (`MOCK_METHOD*`) in a `public:` section of the mock class, regardless of the method being mocked being `public`, `protected`, or `private` in the base class. This allows `ON_CALL` and `EXPECT_CALL` to reference the mock function from outside of the mock class. (Yes, C++ allows a subclass to change the access level of a virtual function in the base class.) Example: ``` class Foo { public: ... virtual bool Transform(Gadget* g) = 0; protected: virtual void Resume(); private: virtual int GetTimeOut(); }; class MockFoo : public Foo { public: ... MOCK_METHOD1(Transform, bool(Gadget* g)); // The following must be in the public section, even though the // methods are protected or private in the base class. MOCK_METHOD0(Resume, void()); MOCK_METHOD0(GetTimeOut, int()); }; ``` ## Mocking Overloaded Methods ## You can mock overloaded functions as usual. No special attention is required: ``` class Foo { ... // Must be virtual as we'll inherit from Foo. virtual ~Foo(); // Overloaded on the types and/or numbers of arguments. virtual int Add(Element x); virtual int Add(int times, Element x); // Overloaded on the const-ness of this object. virtual Bar& GetBar(); virtual const Bar& GetBar() const; }; class MockFoo : public Foo { ... MOCK_METHOD1(Add, int(Element x)); MOCK_METHOD2(Add, int(int times, Element x); MOCK_METHOD0(GetBar, Bar&()); MOCK_CONST_METHOD0(GetBar, const Bar&()); }; ``` **Note:** if you don't mock all versions of the overloaded method, the compiler will give you a warning about some methods in the base class being hidden. To fix that, use `using` to bring them in scope: ``` class MockFoo : public Foo { ... using Foo::Add; MOCK_METHOD1(Add, int(Element x)); // We don't want to mock int Add(int times, Element x); ... }; ``` ## Mocking Class Templates ## To mock a class template, append `_T` to the `MOCK_*` macros: ``` template class StackInterface { ... // Must be virtual as we'll inherit from StackInterface. virtual ~StackInterface(); virtual int GetSize() const = 0; virtual void Push(const Elem& x) = 0; }; template class MockStack : public StackInterface { ... MOCK_CONST_METHOD0_T(GetSize, int()); MOCK_METHOD1_T(Push, void(const Elem& x)); }; ``` ## Mocking Nonvirtual Methods ## Google Mock can mock non-virtual functions to be used in what we call _hi-perf dependency injection_. In this case, instead of sharing a common base class with the real class, your mock class will be _unrelated_ to the real class, but contain methods with the same signatures. The syntax for mocking non-virtual methods is the _same_ as mocking virtual methods: ``` // A simple packet stream class. None of its members is virtual. class ConcretePacketStream { public: void AppendPacket(Packet* new_packet); const Packet* GetPacket(size_t packet_number) const; size_t NumberOfPackets() const; ... }; // A mock packet stream class. It inherits from no other, but defines // GetPacket() and NumberOfPackets(). class MockPacketStream { public: MOCK_CONST_METHOD1(GetPacket, const Packet*(size_t packet_number)); MOCK_CONST_METHOD0(NumberOfPackets, size_t()); ... }; ``` Note that the mock class doesn't define `AppendPacket()`, unlike the real class. That's fine as long as the test doesn't need to call it. Next, you need a way to say that you want to use `ConcretePacketStream` in production code, and use `MockPacketStream` in tests. Since the functions are not virtual and the two classes are unrelated, you must specify your choice at _compile time_ (as opposed to run time). One way to do it is to templatize your code that needs to use a packet stream. More specifically, you will give your code a template type argument for the type of the packet stream. In production, you will instantiate your template with `ConcretePacketStream` as the type argument. In tests, you will instantiate the same template with `MockPacketStream`. For example, you may write: ``` template void CreateConnection(PacketStream* stream) { ... } template class PacketReader { public: void ReadPackets(PacketStream* stream, size_t packet_num); }; ``` Then you can use `CreateConnection()` and `PacketReader` in production code, and use `CreateConnection()` and `PacketReader` in tests. ``` MockPacketStream mock_stream; EXPECT_CALL(mock_stream, ...)...; .. set more expectations on mock_stream ... PacketReader reader(&mock_stream); ... exercise reader ... ``` ## Mocking Free Functions ## It's possible to use Google Mock to mock a free function (i.e. a C-style function or a static method). You just need to rewrite your code to use an interface (abstract class). Instead of calling a free function (say, `OpenFile`) directly, introduce an interface for it and have a concrete subclass that calls the free function: ``` class FileInterface { public: ... virtual bool Open(const char* path, const char* mode) = 0; }; class File : public FileInterface { public: ... virtual bool Open(const char* path, const char* mode) { return OpenFile(path, mode); } }; ``` Your code should talk to `FileInterface` to open a file. Now it's easy to mock out the function. This may seem much hassle, but in practice you often have multiple related functions that you can put in the same interface, so the per-function syntactic overhead will be much lower. If you are concerned about the performance overhead incurred by virtual functions, and profiling confirms your concern, you can combine this with the recipe for [mocking non-virtual methods](#Mocking_Nonvirtual_Methods.md). ## The Nice, the Strict, and the Naggy ## If a mock method has no `EXPECT_CALL` spec but is called, Google Mock will print a warning about the "uninteresting call". The rationale is: * New methods may be added to an interface after a test is written. We shouldn't fail a test just because a method it doesn't know about is called. * However, this may also mean there's a bug in the test, so Google Mock shouldn't be silent either. If the user believes these calls are harmless, he can add an `EXPECT_CALL()` to suppress the warning. However, sometimes you may want to suppress all "uninteresting call" warnings, while sometimes you may want the opposite, i.e. to treat all of them as errors. Google Mock lets you make the decision on a per-mock-object basis. Suppose your test uses a mock class `MockFoo`: ``` TEST(...) { MockFoo mock_foo; EXPECT_CALL(mock_foo, DoThis()); ... code that uses mock_foo ... } ``` If a method of `mock_foo` other than `DoThis()` is called, it will be reported by Google Mock as a warning. However, if you rewrite your test to use `NiceMock` instead, the warning will be gone, resulting in a cleaner test output: ``` using ::testing::NiceMock; TEST(...) { NiceMock mock_foo; EXPECT_CALL(mock_foo, DoThis()); ... code that uses mock_foo ... } ``` `NiceMock` is a subclass of `MockFoo`, so it can be used wherever `MockFoo` is accepted. It also works if `MockFoo`'s constructor takes some arguments, as `NiceMock` "inherits" `MockFoo`'s constructors: ``` using ::testing::NiceMock; TEST(...) { NiceMock mock_foo(5, "hi"); // Calls MockFoo(5, "hi"). EXPECT_CALL(mock_foo, DoThis()); ... code that uses mock_foo ... } ``` The usage of `StrictMock` is similar, except that it makes all uninteresting calls failures: ``` using ::testing::StrictMock; TEST(...) { StrictMock mock_foo; EXPECT_CALL(mock_foo, DoThis()); ... code that uses mock_foo ... // The test will fail if a method of mock_foo other than DoThis() // is called. } ``` There are some caveats though (I don't like them just as much as the next guy, but sadly they are side effects of C++'s limitations): 1. `NiceMock` and `StrictMock` only work for mock methods defined using the `MOCK_METHOD*` family of macros **directly** in the `MockFoo` class. If a mock method is defined in a **base class** of `MockFoo`, the "nice" or "strict" modifier may not affect it, depending on the compiler. In particular, nesting `NiceMock` and `StrictMock` (e.g. `NiceMock >`) is **not** supported. 1. The constructors of the base mock (`MockFoo`) cannot have arguments passed by non-const reference, which happens to be banned by the [Google C++ style guide](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml). 1. During the constructor or destructor of `MockFoo`, the mock object is _not_ nice or strict. This may cause surprises if the constructor or destructor calls a mock method on `this` object. (This behavior, however, is consistent with C++'s general rule: if a constructor or destructor calls a virtual method of `this` object, that method is treated as non-virtual. In other words, to the base class's constructor or destructor, `this` object behaves like an instance of the base class, not the derived class. This rule is required for safety. Otherwise a base constructor may use members of a derived class before they are initialized, or a base destructor may use members of a derived class after they have been destroyed.) Finally, you should be **very cautious** about when to use naggy or strict mocks, as they tend to make tests more brittle and harder to maintain. When you refactor your code without changing its externally visible behavior, ideally you should't need to update any tests. If your code interacts with a naggy mock, however, you may start to get spammed with warnings as the result of your change. Worse, if your code interacts with a strict mock, your tests may start to fail and you'll be forced to fix them. Our general recommendation is to use nice mocks (not yet the default) most of the time, use naggy mocks (the current default) when developing or debugging tests, and use strict mocks only as the last resort. ## Simplifying the Interface without Breaking Existing Code ## Sometimes a method has a long list of arguments that is mostly uninteresting. For example, ``` class LogSink { public: ... virtual void send(LogSeverity severity, const char* full_filename, const char* base_filename, int line, const struct tm* tm_time, const char* message, size_t message_len) = 0; }; ``` This method's argument list is lengthy and hard to work with (let's say that the `message` argument is not even 0-terminated). If we mock it as is, using the mock will be awkward. If, however, we try to simplify this interface, we'll need to fix all clients depending on it, which is often infeasible. The trick is to re-dispatch the method in the mock class: ``` class ScopedMockLog : public LogSink { public: ... virtual void send(LogSeverity severity, const char* full_filename, const char* base_filename, int line, const tm* tm_time, const char* message, size_t message_len) { // We are only interested in the log severity, full file name, and // log message. Log(severity, full_filename, std::string(message, message_len)); } // Implements the mock method: // // void Log(LogSeverity severity, // const string& file_path, // const string& message); MOCK_METHOD3(Log, void(LogSeverity severity, const string& file_path, const string& message)); }; ``` By defining a new mock method with a trimmed argument list, we make the mock class much more user-friendly. ## Alternative to Mocking Concrete Classes ## Often you may find yourself using classes that don't implement interfaces. In order to test your code that uses such a class (let's call it `Concrete`), you may be tempted to make the methods of `Concrete` virtual and then mock it. Try not to do that. Making a non-virtual function virtual is a big decision. It creates an extension point where subclasses can tweak your class' behavior. This weakens your control on the class because now it's harder to maintain the class' invariants. You should make a function virtual only when there is a valid reason for a subclass to override it. Mocking concrete classes directly is problematic as it creates a tight coupling between the class and the tests - any small change in the class may invalidate your tests and make test maintenance a pain. To avoid such problems, many programmers have been practicing "coding to interfaces": instead of talking to the `Concrete` class, your code would define an interface and talk to it. Then you implement that interface as an adaptor on top of `Concrete`. In tests, you can easily mock that interface to observe how your code is doing. This technique incurs some overhead: * You pay the cost of virtual function calls (usually not a problem). * There is more abstraction for the programmers to learn. However, it can also bring significant benefits in addition to better testability: * `Concrete`'s API may not fit your problem domain very well, as you may not be the only client it tries to serve. By designing your own interface, you have a chance to tailor it to your need - you may add higher-level functionalities, rename stuff, etc instead of just trimming the class. This allows you to write your code (user of the interface) in a more natural way, which means it will be more readable, more maintainable, and you'll be more productive. * If `Concrete`'s implementation ever has to change, you don't have to rewrite everywhere it is used. Instead, you can absorb the change in your implementation of the interface, and your other code and tests will be insulated from this change. Some people worry that if everyone is practicing this technique, they will end up writing lots of redundant code. This concern is totally understandable. However, there are two reasons why it may not be the case: * Different projects may need to use `Concrete` in different ways, so the best interfaces for them will be different. Therefore, each of them will have its own domain-specific interface on top of `Concrete`, and they will not be the same code. * If enough projects want to use the same interface, they can always share it, just like they have been sharing `Concrete`. You can check in the interface and the adaptor somewhere near `Concrete` (perhaps in a `contrib` sub-directory) and let many projects use it. You need to weigh the pros and cons carefully for your particular problem, but I'd like to assure you that the Java community has been practicing this for a long time and it's a proven effective technique applicable in a wide variety of situations. :-) ## Delegating Calls to a Fake ## Some times you have a non-trivial fake implementation of an interface. For example: ``` class Foo { public: virtual ~Foo() {} virtual char DoThis(int n) = 0; virtual void DoThat(const char* s, int* p) = 0; }; class FakeFoo : public Foo { public: virtual char DoThis(int n) { return (n > 0) ? '+' : (n < 0) ? '-' : '0'; } virtual void DoThat(const char* s, int* p) { *p = strlen(s); } }; ``` Now you want to mock this interface such that you can set expectations on it. However, you also want to use `FakeFoo` for the default behavior, as duplicating it in the mock object is, well, a lot of work. When you define the mock class using Google Mock, you can have it delegate its default action to a fake class you already have, using this pattern: ``` using ::testing::_; using ::testing::Invoke; class MockFoo : public Foo { public: // Normal mock method definitions using Google Mock. MOCK_METHOD1(DoThis, char(int n)); MOCK_METHOD2(DoThat, void(const char* s, int* p)); // Delegates the default actions of the methods to a FakeFoo object. // This must be called *before* the custom ON_CALL() statements. void DelegateToFake() { ON_CALL(*this, DoThis(_)) .WillByDefault(Invoke(&fake_, &FakeFoo::DoThis)); ON_CALL(*this, DoThat(_, _)) .WillByDefault(Invoke(&fake_, &FakeFoo::DoThat)); } private: FakeFoo fake_; // Keeps an instance of the fake in the mock. }; ``` With that, you can use `MockFoo` in your tests as usual. Just remember that if you don't explicitly set an action in an `ON_CALL()` or `EXPECT_CALL()`, the fake will be called upon to do it: ``` using ::testing::_; TEST(AbcTest, Xyz) { MockFoo foo; foo.DelegateToFake(); // Enables the fake for delegation. // Put your ON_CALL(foo, ...)s here, if any. // No action specified, meaning to use the default action. EXPECT_CALL(foo, DoThis(5)); EXPECT_CALL(foo, DoThat(_, _)); int n = 0; EXPECT_EQ('+', foo.DoThis(5)); // FakeFoo::DoThis() is invoked. foo.DoThat("Hi", &n); // FakeFoo::DoThat() is invoked. EXPECT_EQ(2, n); } ``` **Some tips:** * If you want, you can still override the default action by providing your own `ON_CALL()` or using `.WillOnce()` / `.WillRepeatedly()` in `EXPECT_CALL()`. * In `DelegateToFake()`, you only need to delegate the methods whose fake implementation you intend to use. * The general technique discussed here works for overloaded methods, but you'll need to tell the compiler which version you mean. To disambiguate a mock function (the one you specify inside the parentheses of `ON_CALL()`), see the "Selecting Between Overloaded Functions" section on this page; to disambiguate a fake function (the one you place inside `Invoke()`), use a `static_cast` to specify the function's type. For instance, if class `Foo` has methods `char DoThis(int n)` and `bool DoThis(double x) const`, and you want to invoke the latter, you need to write `Invoke(&fake_, static_cast(&FakeFoo::DoThis))` instead of `Invoke(&fake_, &FakeFoo::DoThis)` (The strange-looking thing inside the angled brackets of `static_cast` is the type of a function pointer to the second `DoThis()` method.). * Having to mix a mock and a fake is often a sign of something gone wrong. Perhaps you haven't got used to the interaction-based way of testing yet. Or perhaps your interface is taking on too many roles and should be split up. Therefore, **don't abuse this**. We would only recommend to do it as an intermediate step when you are refactoring your code. Regarding the tip on mixing a mock and a fake, here's an example on why it may be a bad sign: Suppose you have a class `System` for low-level system operations. In particular, it does file and I/O operations. And suppose you want to test how your code uses `System` to do I/O, and you just want the file operations to work normally. If you mock out the entire `System` class, you'll have to provide a fake implementation for the file operation part, which suggests that `System` is taking on too many roles. Instead, you can define a `FileOps` interface and an `IOOps` interface and split `System`'s functionalities into the two. Then you can mock `IOOps` without mocking `FileOps`. ## Delegating Calls to a Real Object ## When using testing doubles (mocks, fakes, stubs, and etc), sometimes their behaviors will differ from those of the real objects. This difference could be either intentional (as in simulating an error such that you can test the error handling code) or unintentional. If your mocks have different behaviors than the real objects by mistake, you could end up with code that passes the tests but fails in production. You can use the _delegating-to-real_ technique to ensure that your mock has the same behavior as the real object while retaining the ability to validate calls. This technique is very similar to the delegating-to-fake technique, the difference being that we use a real object instead of a fake. Here's an example: ``` using ::testing::_; using ::testing::AtLeast; using ::testing::Invoke; class MockFoo : public Foo { public: MockFoo() { // By default, all calls are delegated to the real object. ON_CALL(*this, DoThis()) .WillByDefault(Invoke(&real_, &Foo::DoThis)); ON_CALL(*this, DoThat(_)) .WillByDefault(Invoke(&real_, &Foo::DoThat)); ... } MOCK_METHOD0(DoThis, ...); MOCK_METHOD1(DoThat, ...); ... private: Foo real_; }; ... MockFoo mock; EXPECT_CALL(mock, DoThis()) .Times(3); EXPECT_CALL(mock, DoThat("Hi")) .Times(AtLeast(1)); ... use mock in test ... ``` With this, Google Mock will verify that your code made the right calls (with the right arguments, in the right order, called the right number of times, etc), and a real object will answer the calls (so the behavior will be the same as in production). This gives you the best of both worlds. ## Delegating Calls to a Parent Class ## Ideally, you should code to interfaces, whose methods are all pure virtual. In reality, sometimes you do need to mock a virtual method that is not pure (i.e, it already has an implementation). For example: ``` class Foo { public: virtual ~Foo(); virtual void Pure(int n) = 0; virtual int Concrete(const char* str) { ... } }; class MockFoo : public Foo { public: // Mocking a pure method. MOCK_METHOD1(Pure, void(int n)); // Mocking a concrete method. Foo::Concrete() is shadowed. MOCK_METHOD1(Concrete, int(const char* str)); }; ``` Sometimes you may want to call `Foo::Concrete()` instead of `MockFoo::Concrete()`. Perhaps you want to do it as part of a stub action, or perhaps your test doesn't need to mock `Concrete()` at all (but it would be oh-so painful to have to define a new mock class whenever you don't need to mock one of its methods). The trick is to leave a back door in your mock class for accessing the real methods in the base class: ``` class MockFoo : public Foo { public: // Mocking a pure method. MOCK_METHOD1(Pure, void(int n)); // Mocking a concrete method. Foo::Concrete() is shadowed. MOCK_METHOD1(Concrete, int(const char* str)); // Use this to call Concrete() defined in Foo. int FooConcrete(const char* str) { return Foo::Concrete(str); } }; ``` Now, you can call `Foo::Concrete()` inside an action by: ``` using ::testing::_; using ::testing::Invoke; ... EXPECT_CALL(foo, Concrete(_)) .WillOnce(Invoke(&foo, &MockFoo::FooConcrete)); ``` or tell the mock object that you don't want to mock `Concrete()`: ``` using ::testing::Invoke; ... ON_CALL(foo, Concrete(_)) .WillByDefault(Invoke(&foo, &MockFoo::FooConcrete)); ``` (Why don't we just write `Invoke(&foo, &Foo::Concrete)`? If you do that, `MockFoo::Concrete()` will be called (and cause an infinite recursion) since `Foo::Concrete()` is virtual. That's just how C++ works.) # Using Matchers # ## Matching Argument Values Exactly ## You can specify exactly which arguments a mock method is expecting: ``` using ::testing::Return; ... EXPECT_CALL(foo, DoThis(5)) .WillOnce(Return('a')); EXPECT_CALL(foo, DoThat("Hello", bar)); ``` ## Using Simple Matchers ## You can use matchers to match arguments that have a certain property: ``` using ::testing::Ge; using ::testing::NotNull; using ::testing::Return; ... EXPECT_CALL(foo, DoThis(Ge(5))) // The argument must be >= 5. .WillOnce(Return('a')); EXPECT_CALL(foo, DoThat("Hello", NotNull())); // The second argument must not be NULL. ``` A frequently used matcher is `_`, which matches anything: ``` using ::testing::_; using ::testing::NotNull; ... EXPECT_CALL(foo, DoThat(_, NotNull())); ``` ## Combining Matchers ## You can build complex matchers from existing ones using `AllOf()`, `AnyOf()`, and `Not()`: ``` using ::testing::AllOf; using ::testing::Gt; using ::testing::HasSubstr; using ::testing::Ne; using ::testing::Not; ... // The argument must be > 5 and != 10. EXPECT_CALL(foo, DoThis(AllOf(Gt(5), Ne(10)))); // The first argument must not contain sub-string "blah". EXPECT_CALL(foo, DoThat(Not(HasSubstr("blah")), NULL)); ``` ## Casting Matchers ## Google Mock matchers are statically typed, meaning that the compiler can catch your mistake if you use a matcher of the wrong type (for example, if you use `Eq(5)` to match a `string` argument). Good for you! Sometimes, however, you know what you're doing and want the compiler to give you some slack. One example is that you have a matcher for `long` and the argument you want to match is `int`. While the two types aren't exactly the same, there is nothing really wrong with using a `Matcher` to match an `int` - after all, we can first convert the `int` argument to a `long` before giving it to the matcher. To support this need, Google Mock gives you the `SafeMatcherCast(m)` function. It casts a matcher `m` to type `Matcher`. To ensure safety, Google Mock checks that (let `U` be the type `m` accepts): 1. Type `T` can be implicitly cast to type `U`; 1. When both `T` and `U` are built-in arithmetic types (`bool`, integers, and floating-point numbers), the conversion from `T` to `U` is not lossy (in other words, any value representable by `T` can also be represented by `U`); and 1. When `U` is a reference, `T` must also be a reference (as the underlying matcher may be interested in the address of the `U` value). The code won't compile if any of these conditions isn't met. Here's one example: ``` using ::testing::SafeMatcherCast; // A base class and a child class. class Base { ... }; class Derived : public Base { ... }; class MockFoo : public Foo { public: MOCK_METHOD1(DoThis, void(Derived* derived)); }; ... MockFoo foo; // m is a Matcher we got from somewhere. EXPECT_CALL(foo, DoThis(SafeMatcherCast(m))); ``` If you find `SafeMatcherCast(m)` too limiting, you can use a similar function `MatcherCast(m)`. The difference is that `MatcherCast` works as long as you can `static_cast` type `T` to type `U`. `MatcherCast` essentially lets you bypass C++'s type system (`static_cast` isn't always safe as it could throw away information, for example), so be careful not to misuse/abuse it. ## Selecting Between Overloaded Functions ## If you expect an overloaded function to be called, the compiler may need some help on which overloaded version it is. To disambiguate functions overloaded on the const-ness of this object, use the `Const()` argument wrapper. ``` using ::testing::ReturnRef; class MockFoo : public Foo { ... MOCK_METHOD0(GetBar, Bar&()); MOCK_CONST_METHOD0(GetBar, const Bar&()); }; ... MockFoo foo; Bar bar1, bar2; EXPECT_CALL(foo, GetBar()) // The non-const GetBar(). .WillOnce(ReturnRef(bar1)); EXPECT_CALL(Const(foo), GetBar()) // The const GetBar(). .WillOnce(ReturnRef(bar2)); ``` (`Const()` is defined by Google Mock and returns a `const` reference to its argument.) To disambiguate overloaded functions with the same number of arguments but different argument types, you may need to specify the exact type of a matcher, either by wrapping your matcher in `Matcher()`, or using a matcher whose type is fixed (`TypedEq`, `An()`, etc): ``` using ::testing::An; using ::testing::Lt; using ::testing::Matcher; using ::testing::TypedEq; class MockPrinter : public Printer { public: MOCK_METHOD1(Print, void(int n)); MOCK_METHOD1(Print, void(char c)); }; TEST(PrinterTest, Print) { MockPrinter printer; EXPECT_CALL(printer, Print(An())); // void Print(int); EXPECT_CALL(printer, Print(Matcher(Lt(5)))); // void Print(int); EXPECT_CALL(printer, Print(TypedEq('a'))); // void Print(char); printer.Print(3); printer.Print(6); printer.Print('a'); } ``` ## Performing Different Actions Based on the Arguments ## When a mock method is called, the _last_ matching expectation that's still active will be selected (think "newer overrides older"). So, you can make a method do different things depending on its argument values like this: ``` using ::testing::_; using ::testing::Lt; using ::testing::Return; ... // The default case. EXPECT_CALL(foo, DoThis(_)) .WillRepeatedly(Return('b')); // The more specific case. EXPECT_CALL(foo, DoThis(Lt(5))) .WillRepeatedly(Return('a')); ``` Now, if `foo.DoThis()` is called with a value less than 5, `'a'` will be returned; otherwise `'b'` will be returned. ## Matching Multiple Arguments as a Whole ## Sometimes it's not enough to match the arguments individually. For example, we may want to say that the first argument must be less than the second argument. The `With()` clause allows us to match all arguments of a mock function as a whole. For example, ``` using ::testing::_; using ::testing::Lt; using ::testing::Ne; ... EXPECT_CALL(foo, InRange(Ne(0), _)) .With(Lt()); ``` says that the first argument of `InRange()` must not be 0, and must be less than the second argument. The expression inside `With()` must be a matcher of type `Matcher< ::testing::tuple >`, where `A1`, ..., `An` are the types of the function arguments. You can also write `AllArgs(m)` instead of `m` inside `.With()`. The two forms are equivalent, but `.With(AllArgs(Lt()))` is more readable than `.With(Lt())`. You can use `Args(m)` to match the `n` selected arguments (as a tuple) against `m`. For example, ``` using ::testing::_; using ::testing::AllOf; using ::testing::Args; using ::testing::Lt; ... EXPECT_CALL(foo, Blah(_, _, _)) .With(AllOf(Args<0, 1>(Lt()), Args<1, 2>(Lt()))); ``` says that `Blah()` will be called with arguments `x`, `y`, and `z` where `x < y < z`. As a convenience and example, Google Mock provides some matchers for 2-tuples, including the `Lt()` matcher above. See the [CheatSheet](CheatSheet.md) for the complete list. Note that if you want to pass the arguments to a predicate of your own (e.g. `.With(Args<0, 1>(Truly(&MyPredicate)))`), that predicate MUST be written to take a `::testing::tuple` as its argument; Google Mock will pass the `n` selected arguments as _one_ single tuple to the predicate. ## Using Matchers as Predicates ## Have you noticed that a matcher is just a fancy predicate that also knows how to describe itself? Many existing algorithms take predicates as arguments (e.g. those defined in STL's `` header), and it would be a shame if Google Mock matchers are not allowed to participate. Luckily, you can use a matcher where a unary predicate functor is expected by wrapping it inside the `Matches()` function. For example, ``` #include #include std::vector v; ... // How many elements in v are >= 10? const int count = count_if(v.begin(), v.end(), Matches(Ge(10))); ``` Since you can build complex matchers from simpler ones easily using Google Mock, this gives you a way to conveniently construct composite predicates (doing the same using STL's `` header is just painful). For example, here's a predicate that's satisfied by any number that is >= 0, <= 100, and != 50: ``` Matches(AllOf(Ge(0), Le(100), Ne(50))) ``` ## Using Matchers in Google Test Assertions ## Since matchers are basically predicates that also know how to describe themselves, there is a way to take advantage of them in [Google Test](../../googletest/) assertions. It's called `ASSERT_THAT` and `EXPECT_THAT`: ``` ASSERT_THAT(value, matcher); // Asserts that value matches matcher. EXPECT_THAT(value, matcher); // The non-fatal version. ``` For example, in a Google Test test you can write: ``` #include "gmock/gmock.h" using ::testing::AllOf; using ::testing::Ge; using ::testing::Le; using ::testing::MatchesRegex; using ::testing::StartsWith; ... EXPECT_THAT(Foo(), StartsWith("Hello")); EXPECT_THAT(Bar(), MatchesRegex("Line \\d+")); ASSERT_THAT(Baz(), AllOf(Ge(5), Le(10))); ``` which (as you can probably guess) executes `Foo()`, `Bar()`, and `Baz()`, and verifies that: * `Foo()` returns a string that starts with `"Hello"`. * `Bar()` returns a string that matches regular expression `"Line \\d+"`. * `Baz()` returns a number in the range [5, 10]. The nice thing about these macros is that _they read like English_. They generate informative messages too. For example, if the first `EXPECT_THAT()` above fails, the message will be something like: ``` Value of: Foo() Actual: "Hi, world!" Expected: starts with "Hello" ``` **Credit:** The idea of `(ASSERT|EXPECT)_THAT` was stolen from the [Hamcrest](https://github.com/hamcrest/) project, which adds `assertThat()` to JUnit. ## Using Predicates as Matchers ## Google Mock provides a built-in set of matchers. In case you find them lacking, you can use an arbitray unary predicate function or functor as a matcher - as long as the predicate accepts a value of the type you want. You do this by wrapping the predicate inside the `Truly()` function, for example: ``` using ::testing::Truly; int IsEven(int n) { return (n % 2) == 0 ? 1 : 0; } ... // Bar() must be called with an even number. EXPECT_CALL(foo, Bar(Truly(IsEven))); ``` Note that the predicate function / functor doesn't have to return `bool`. It works as long as the return value can be used as the condition in statement `if (condition) ...`. ## Matching Arguments that Are Not Copyable ## When you do an `EXPECT_CALL(mock_obj, Foo(bar))`, Google Mock saves away a copy of `bar`. When `Foo()` is called later, Google Mock compares the argument to `Foo()` with the saved copy of `bar`. This way, you don't need to worry about `bar` being modified or destroyed after the `EXPECT_CALL()` is executed. The same is true when you use matchers like `Eq(bar)`, `Le(bar)`, and so on. But what if `bar` cannot be copied (i.e. has no copy constructor)? You could define your own matcher function and use it with `Truly()`, as the previous couple of recipes have shown. Or, you may be able to get away from it if you can guarantee that `bar` won't be changed after the `EXPECT_CALL()` is executed. Just tell Google Mock that it should save a reference to `bar`, instead of a copy of it. Here's how: ``` using ::testing::Eq; using ::testing::ByRef; using ::testing::Lt; ... // Expects that Foo()'s argument == bar. EXPECT_CALL(mock_obj, Foo(Eq(ByRef(bar)))); // Expects that Foo()'s argument < bar. EXPECT_CALL(mock_obj, Foo(Lt(ByRef(bar)))); ``` Remember: if you do this, don't change `bar` after the `EXPECT_CALL()`, or the result is undefined. ## Validating a Member of an Object ## Often a mock function takes a reference to object as an argument. When matching the argument, you may not want to compare the entire object against a fixed object, as that may be over-specification. Instead, you may need to validate a certain member variable or the result of a certain getter method of the object. You can do this with `Field()` and `Property()`. More specifically, ``` Field(&Foo::bar, m) ``` is a matcher that matches a `Foo` object whose `bar` member variable satisfies matcher `m`. ``` Property(&Foo::baz, m) ``` is a matcher that matches a `Foo` object whose `baz()` method returns a value that satisfies matcher `m`. For example: > | `Field(&Foo::number, Ge(3))` | Matches `x` where `x.number >= 3`. | |:-----------------------------|:-----------------------------------| > | `Property(&Foo::name, StartsWith("John "))` | Matches `x` where `x.name()` starts with `"John "`. | Note that in `Property(&Foo::baz, ...)`, method `baz()` must take no argument and be declared as `const`. BTW, `Field()` and `Property()` can also match plain pointers to objects. For instance, ``` Field(&Foo::number, Ge(3)) ``` matches a plain pointer `p` where `p->number >= 3`. If `p` is `NULL`, the match will always fail regardless of the inner matcher. What if you want to validate more than one members at the same time? Remember that there is `AllOf()`. ## Validating the Value Pointed to by a Pointer Argument ## C++ functions often take pointers as arguments. You can use matchers like `IsNull()`, `NotNull()`, and other comparison matchers to match a pointer, but what if you want to make sure the value _pointed to_ by the pointer, instead of the pointer itself, has a certain property? Well, you can use the `Pointee(m)` matcher. `Pointee(m)` matches a pointer iff `m` matches the value the pointer points to. For example: ``` using ::testing::Ge; using ::testing::Pointee; ... EXPECT_CALL(foo, Bar(Pointee(Ge(3)))); ``` expects `foo.Bar()` to be called with a pointer that points to a value greater than or equal to 3. One nice thing about `Pointee()` is that it treats a `NULL` pointer as a match failure, so you can write `Pointee(m)` instead of ``` AllOf(NotNull(), Pointee(m)) ``` without worrying that a `NULL` pointer will crash your test. Also, did we tell you that `Pointee()` works with both raw pointers **and** smart pointers (`linked_ptr`, `shared_ptr`, `scoped_ptr`, and etc)? What if you have a pointer to pointer? You guessed it - you can use nested `Pointee()` to probe deeper inside the value. For example, `Pointee(Pointee(Lt(3)))` matches a pointer that points to a pointer that points to a number less than 3 (what a mouthful...). ## Testing a Certain Property of an Object ## Sometimes you want to specify that an object argument has a certain property, but there is no existing matcher that does this. If you want good error messages, you should define a matcher. If you want to do it quick and dirty, you could get away with writing an ordinary function. Let's say you have a mock function that takes an object of type `Foo`, which has an `int bar()` method and an `int baz()` method, and you want to constrain that the argument's `bar()` value plus its `baz()` value is a given number. Here's how you can define a matcher to do it: ``` using ::testing::MatcherInterface; using ::testing::MatchResultListener; class BarPlusBazEqMatcher : public MatcherInterface { public: explicit BarPlusBazEqMatcher(int expected_sum) : expected_sum_(expected_sum) {} virtual bool MatchAndExplain(const Foo& foo, MatchResultListener* listener) const { return (foo.bar() + foo.baz()) == expected_sum_; } virtual void DescribeTo(::std::ostream* os) const { *os << "bar() + baz() equals " << expected_sum_; } virtual void DescribeNegationTo(::std::ostream* os) const { *os << "bar() + baz() does not equal " << expected_sum_; } private: const int expected_sum_; }; inline Matcher BarPlusBazEq(int expected_sum) { return MakeMatcher(new BarPlusBazEqMatcher(expected_sum)); } ... EXPECT_CALL(..., DoThis(BarPlusBazEq(5)))...; ``` ## Matching Containers ## Sometimes an STL container (e.g. list, vector, map, ...) is passed to a mock function and you may want to validate it. Since most STL containers support the `==` operator, you can write `Eq(expected_container)` or simply `expected_container` to match a container exactly. Sometimes, though, you may want to be more flexible (for example, the first element must be an exact match, but the second element can be any positive number, and so on). Also, containers used in tests often have a small number of elements, and having to define the expected container out-of-line is a bit of a hassle. You can use the `ElementsAre()` or `UnorderedElementsAre()` matcher in such cases: ``` using ::testing::_; using ::testing::ElementsAre; using ::testing::Gt; ... MOCK_METHOD1(Foo, void(const vector& numbers)); ... EXPECT_CALL(mock, Foo(ElementsAre(1, Gt(0), _, 5))); ``` The above matcher says that the container must have 4 elements, which must be 1, greater than 0, anything, and 5 respectively. If you instead write: ``` using ::testing::_; using ::testing::Gt; using ::testing::UnorderedElementsAre; ... MOCK_METHOD1(Foo, void(const vector& numbers)); ... EXPECT_CALL(mock, Foo(UnorderedElementsAre(1, Gt(0), _, 5))); ``` It means that the container must have 4 elements, which under some permutation must be 1, greater than 0, anything, and 5 respectively. `ElementsAre()` and `UnorderedElementsAre()` are overloaded to take 0 to 10 arguments. If more are needed, you can place them in a C-style array and use `ElementsAreArray()` or `UnorderedElementsAreArray()` instead: ``` using ::testing::ElementsAreArray; ... // ElementsAreArray accepts an array of element values. const int expected_vector1[] = { 1, 5, 2, 4, ... }; EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector1))); // Or, an array of element matchers. Matcher expected_vector2 = { 1, Gt(2), _, 3, ... }; EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector2))); ``` In case the array needs to be dynamically created (and therefore the array size cannot be inferred by the compiler), you can give `ElementsAreArray()` an additional argument to specify the array size: ``` using ::testing::ElementsAreArray; ... int* const expected_vector3 = new int[count]; ... fill expected_vector3 with values ... EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector3, count))); ``` **Tips:** * `ElementsAre*()` can be used to match _any_ container that implements the STL iterator pattern (i.e. it has a `const_iterator` type and supports `begin()/end()`), not just the ones defined in STL. It will even work with container types yet to be written - as long as they follows the above pattern. * You can use nested `ElementsAre*()` to match nested (multi-dimensional) containers. * If the container is passed by pointer instead of by reference, just write `Pointee(ElementsAre*(...))`. * The order of elements _matters_ for `ElementsAre*()`. Therefore don't use it with containers whose element order is undefined (e.g. `hash_map`). ## Sharing Matchers ## Under the hood, a Google Mock matcher object consists of a pointer to a ref-counted implementation object. Copying matchers is allowed and very efficient, as only the pointer is copied. When the last matcher that references the implementation object dies, the implementation object will be deleted. Therefore, if you have some complex matcher that you want to use again and again, there is no need to build it everytime. Just assign it to a matcher variable and use that variable repeatedly! For example, ``` Matcher in_range = AllOf(Gt(5), Le(10)); ... use in_range as a matcher in multiple EXPECT_CALLs ... ``` # Setting Expectations # ## Knowing When to Expect ## `ON_CALL` is likely the single most under-utilized construct in Google Mock. There are basically two constructs for defining the behavior of a mock object: `ON_CALL` and `EXPECT_CALL`. The difference? `ON_CALL` defines what happens when a mock method is called, but _doesn't imply any expectation on the method being called._ `EXPECT_CALL` not only defines the behavior, but also sets an expectation that _the method will be called with the given arguments, for the given number of times_ (and _in the given order_ when you specify the order too). Since `EXPECT_CALL` does more, isn't it better than `ON_CALL`? Not really. Every `EXPECT_CALL` adds a constraint on the behavior of the code under test. Having more constraints than necessary is _baaad_ - even worse than not having enough constraints. This may be counter-intuitive. How could tests that verify more be worse than tests that verify less? Isn't verification the whole point of tests? The answer, lies in _what_ a test should verify. **A good test verifies the contract of the code.** If a test over-specifies, it doesn't leave enough freedom to the implementation. As a result, changing the implementation without breaking the contract (e.g. refactoring and optimization), which should be perfectly fine to do, can break such tests. Then you have to spend time fixing them, only to see them broken again the next time the implementation is changed. Keep in mind that one doesn't have to verify more than one property in one test. In fact, **it's a good style to verify only one thing in one test.** If you do that, a bug will likely break only one or two tests instead of dozens (which case would you rather debug?). If you are also in the habit of giving tests descriptive names that tell what they verify, you can often easily guess what's wrong just from the test log itself. So use `ON_CALL` by default, and only use `EXPECT_CALL` when you actually intend to verify that the call is made. For example, you may have a bunch of `ON_CALL`s in your test fixture to set the common mock behavior shared by all tests in the same group, and write (scarcely) different `EXPECT_CALL`s in different `TEST_F`s to verify different aspects of the code's behavior. Compared with the style where each `TEST` has many `EXPECT_CALL`s, this leads to tests that are more resilient to implementational changes (and thus less likely to require maintenance) and makes the intent of the tests more obvious (so they are easier to maintain when you do need to maintain them). If you are bothered by the "Uninteresting mock function call" message printed when a mock method without an `EXPECT_CALL` is called, you may use a `NiceMock` instead to suppress all such messages for the mock object, or suppress the message for specific methods by adding `EXPECT_CALL(...).Times(AnyNumber())`. DO NOT suppress it by blindly adding an `EXPECT_CALL(...)`, or you'll have a test that's a pain to maintain. ## Ignoring Uninteresting Calls ## If you are not interested in how a mock method is called, just don't say anything about it. In this case, if the method is ever called, Google Mock will perform its default action to allow the test program to continue. If you are not happy with the default action taken by Google Mock, you can override it using `DefaultValue::Set()` (described later in this document) or `ON_CALL()`. Please note that once you expressed interest in a particular mock method (via `EXPECT_CALL()`), all invocations to it must match some expectation. If this function is called but the arguments don't match any `EXPECT_CALL()` statement, it will be an error. ## Disallowing Unexpected Calls ## If a mock method shouldn't be called at all, explicitly say so: ``` using ::testing::_; ... EXPECT_CALL(foo, Bar(_)) .Times(0); ``` If some calls to the method are allowed, but the rest are not, just list all the expected calls: ``` using ::testing::AnyNumber; using ::testing::Gt; ... EXPECT_CALL(foo, Bar(5)); EXPECT_CALL(foo, Bar(Gt(10))) .Times(AnyNumber()); ``` A call to `foo.Bar()` that doesn't match any of the `EXPECT_CALL()` statements will be an error. ## Understanding Uninteresting vs Unexpected Calls ## _Uninteresting_ calls and _unexpected_ calls are different concepts in Google Mock. _Very_ different. A call `x.Y(...)` is **uninteresting** if there's _not even a single_ `EXPECT_CALL(x, Y(...))` set. In other words, the test isn't interested in the `x.Y()` method at all, as evident in that the test doesn't care to say anything about it. A call `x.Y(...)` is **unexpected** if there are some `EXPECT_CALL(x, Y(...))s` set, but none of them matches the call. Put another way, the test is interested in the `x.Y()` method (therefore it _explicitly_ sets some `EXPECT_CALL` to verify how it's called); however, the verification fails as the test doesn't expect this particular call to happen. **An unexpected call is always an error,** as the code under test doesn't behave the way the test expects it to behave. **By default, an uninteresting call is not an error,** as it violates no constraint specified by the test. (Google Mock's philosophy is that saying nothing means there is no constraint.) However, it leads to a warning, as it _might_ indicate a problem (e.g. the test author might have forgotten to specify a constraint). In Google Mock, `NiceMock` and `StrictMock` can be used to make a mock class "nice" or "strict". How does this affect uninteresting calls and unexpected calls? A **nice mock** suppresses uninteresting call warnings. It is less chatty than the default mock, but otherwise is the same. If a test fails with a default mock, it will also fail using a nice mock instead. And vice versa. Don't expect making a mock nice to change the test's result. A **strict mock** turns uninteresting call warnings into errors. So making a mock strict may change the test's result. Let's look at an example: ``` TEST(...) { NiceMock mock_registry; EXPECT_CALL(mock_registry, GetDomainOwner("google.com")) .WillRepeatedly(Return("Larry Page")); // Use mock_registry in code under test. ... &mock_registry ... } ``` The sole `EXPECT_CALL` here says that all calls to `GetDomainOwner()` must have `"google.com"` as the argument. If `GetDomainOwner("yahoo.com")` is called, it will be an unexpected call, and thus an error. Having a nice mock doesn't change the severity of an unexpected call. So how do we tell Google Mock that `GetDomainOwner()` can be called with some other arguments as well? The standard technique is to add a "catch all" `EXPECT_CALL`: ``` EXPECT_CALL(mock_registry, GetDomainOwner(_)) .Times(AnyNumber()); // catches all other calls to this method. EXPECT_CALL(mock_registry, GetDomainOwner("google.com")) .WillRepeatedly(Return("Larry Page")); ``` Remember that `_` is the wildcard matcher that matches anything. With this, if `GetDomainOwner("google.com")` is called, it will do what the second `EXPECT_CALL` says; if it is called with a different argument, it will do what the first `EXPECT_CALL` says. Note that the order of the two `EXPECT_CALLs` is important, as a newer `EXPECT_CALL` takes precedence over an older one. For more on uninteresting calls, nice mocks, and strict mocks, read ["The Nice, the Strict, and the Naggy"](#the-nice-the-strict-and-the-naggy). ## Expecting Ordered Calls ## Although an `EXPECT_CALL()` statement defined earlier takes precedence when Google Mock tries to match a function call with an expectation, by default calls don't have to happen in the order `EXPECT_CALL()` statements are written. For example, if the arguments match the matchers in the third `EXPECT_CALL()`, but not those in the first two, then the third expectation will be used. If you would rather have all calls occur in the order of the expectations, put the `EXPECT_CALL()` statements in a block where you define a variable of type `InSequence`: ``` using ::testing::_; using ::testing::InSequence; { InSequence s; EXPECT_CALL(foo, DoThis(5)); EXPECT_CALL(bar, DoThat(_)) .Times(2); EXPECT_CALL(foo, DoThis(6)); } ``` In this example, we expect a call to `foo.DoThis(5)`, followed by two calls to `bar.DoThat()` where the argument can be anything, which are in turn followed by a call to `foo.DoThis(6)`. If a call occurred out-of-order, Google Mock will report an error. ## Expecting Partially Ordered Calls ## Sometimes requiring everything to occur in a predetermined order can lead to brittle tests. For example, we may care about `A` occurring before both `B` and `C`, but aren't interested in the relative order of `B` and `C`. In this case, the test should reflect our real intent, instead of being overly constraining. Google Mock allows you to impose an arbitrary DAG (directed acyclic graph) on the calls. One way to express the DAG is to use the [After](CheatSheet.md#the-after-clause) clause of `EXPECT_CALL`. Another way is via the `InSequence()` clause (not the same as the `InSequence` class), which we borrowed from jMock 2. It's less flexible than `After()`, but more convenient when you have long chains of sequential calls, as it doesn't require you to come up with different names for the expectations in the chains. Here's how it works: If we view `EXPECT_CALL()` statements as nodes in a graph, and add an edge from node A to node B wherever A must occur before B, we can get a DAG. We use the term "sequence" to mean a directed path in this DAG. Now, if we decompose the DAG into sequences, we just need to know which sequences each `EXPECT_CALL()` belongs to in order to be able to reconstruct the orginal DAG. So, to specify the partial order on the expectations we need to do two things: first to define some `Sequence` objects, and then for each `EXPECT_CALL()` say which `Sequence` objects it is part of. Expectations in the same sequence must occur in the order they are written. For example, ``` using ::testing::Sequence; Sequence s1, s2; EXPECT_CALL(foo, A()) .InSequence(s1, s2); EXPECT_CALL(bar, B()) .InSequence(s1); EXPECT_CALL(bar, C()) .InSequence(s2); EXPECT_CALL(foo, D()) .InSequence(s2); ``` specifies the following DAG (where `s1` is `A -> B`, and `s2` is `A -> C -> D`): ``` +---> B | A ---| | +---> C ---> D ``` This means that A must occur before B and C, and C must occur before D. There's no restriction about the order other than these. ## Controlling When an Expectation Retires ## When a mock method is called, Google Mock only consider expectations that are still active. An expectation is active when created, and becomes inactive (aka _retires_) when a call that has to occur later has occurred. For example, in ``` using ::testing::_; using ::testing::Sequence; Sequence s1, s2; EXPECT_CALL(log, Log(WARNING, _, "File too large.")) // #1 .Times(AnyNumber()) .InSequence(s1, s2); EXPECT_CALL(log, Log(WARNING, _, "Data set is empty.")) // #2 .InSequence(s1); EXPECT_CALL(log, Log(WARNING, _, "User not found.")) // #3 .InSequence(s2); ``` as soon as either #2 or #3 is matched, #1 will retire. If a warning `"File too large."` is logged after this, it will be an error. Note that an expectation doesn't retire automatically when it's saturated. For example, ``` using ::testing::_; ... EXPECT_CALL(log, Log(WARNING, _, _)); // #1 EXPECT_CALL(log, Log(WARNING, _, "File too large.")); // #2 ``` says that there will be exactly one warning with the message `"File too large."`. If the second warning contains this message too, #2 will match again and result in an upper-bound-violated error. If this is not what you want, you can ask an expectation to retire as soon as it becomes saturated: ``` using ::testing::_; ... EXPECT_CALL(log, Log(WARNING, _, _)); // #1 EXPECT_CALL(log, Log(WARNING, _, "File too large.")) // #2 .RetiresOnSaturation(); ``` Here #2 can be used only once, so if you have two warnings with the message `"File too large."`, the first will match #2 and the second will match #1 - there will be no error. # Using Actions # ## Returning References from Mock Methods ## If a mock function's return type is a reference, you need to use `ReturnRef()` instead of `Return()` to return a result: ``` using ::testing::ReturnRef; class MockFoo : public Foo { public: MOCK_METHOD0(GetBar, Bar&()); }; ... MockFoo foo; Bar bar; EXPECT_CALL(foo, GetBar()) .WillOnce(ReturnRef(bar)); ``` ## Returning Live Values from Mock Methods ## The `Return(x)` action saves a copy of `x` when the action is _created_, and always returns the same value whenever it's executed. Sometimes you may want to instead return the _live_ value of `x` (i.e. its value at the time when the action is _executed_.). If the mock function's return type is a reference, you can do it using `ReturnRef(x)`, as shown in the previous recipe ("Returning References from Mock Methods"). However, Google Mock doesn't let you use `ReturnRef()` in a mock function whose return type is not a reference, as doing that usually indicates a user error. So, what shall you do? You may be tempted to try `ByRef()`: ``` using testing::ByRef; using testing::Return; class MockFoo : public Foo { public: MOCK_METHOD0(GetValue, int()); }; ... int x = 0; MockFoo foo; EXPECT_CALL(foo, GetValue()) .WillRepeatedly(Return(ByRef(x))); x = 42; EXPECT_EQ(42, foo.GetValue()); ``` Unfortunately, it doesn't work here. The above code will fail with error: ``` Value of: foo.GetValue() Actual: 0 Expected: 42 ``` The reason is that `Return(value)` converts `value` to the actual return type of the mock function at the time when the action is _created_, not when it is _executed_. (This behavior was chosen for the action to be safe when `value` is a proxy object that references some temporary objects.) As a result, `ByRef(x)` is converted to an `int` value (instead of a `const int&`) when the expectation is set, and `Return(ByRef(x))` will always return 0. `ReturnPointee(pointer)` was provided to solve this problem specifically. It returns the value pointed to by `pointer` at the time the action is _executed_: ``` using testing::ReturnPointee; ... int x = 0; MockFoo foo; EXPECT_CALL(foo, GetValue()) .WillRepeatedly(ReturnPointee(&x)); // Note the & here. x = 42; EXPECT_EQ(42, foo.GetValue()); // This will succeed now. ``` ## Combining Actions ## Want to do more than one thing when a function is called? That's fine. `DoAll()` allow you to do sequence of actions every time. Only the return value of the last action in the sequence will be used. ``` using ::testing::DoAll; class MockFoo : public Foo { public: MOCK_METHOD1(Bar, bool(int n)); }; ... EXPECT_CALL(foo, Bar(_)) .WillOnce(DoAll(action_1, action_2, ... action_n)); ``` ## Mocking Side Effects ## Sometimes a method exhibits its effect not via returning a value but via side effects. For example, it may change some global state or modify an output argument. To mock side effects, in general you can define your own action by implementing `::testing::ActionInterface`. If all you need to do is to change an output argument, the built-in `SetArgPointee()` action is convenient: ``` using ::testing::SetArgPointee; class MockMutator : public Mutator { public: MOCK_METHOD2(Mutate, void(bool mutate, int* value)); ... }; ... MockMutator mutator; EXPECT_CALL(mutator, Mutate(true, _)) .WillOnce(SetArgPointee<1>(5)); ``` In this example, when `mutator.Mutate()` is called, we will assign 5 to the `int` variable pointed to by argument #1 (0-based). `SetArgPointee()` conveniently makes an internal copy of the value you pass to it, removing the need to keep the value in scope and alive. The implication however is that the value must have a copy constructor and assignment operator. If the mock method also needs to return a value as well, you can chain `SetArgPointee()` with `Return()` using `DoAll()`: ``` using ::testing::_; using ::testing::Return; using ::testing::SetArgPointee; class MockMutator : public Mutator { public: ... MOCK_METHOD1(MutateInt, bool(int* value)); }; ... MockMutator mutator; EXPECT_CALL(mutator, MutateInt(_)) .WillOnce(DoAll(SetArgPointee<0>(5), Return(true))); ``` If the output argument is an array, use the `SetArrayArgument(first, last)` action instead. It copies the elements in source range `[first, last)` to the array pointed to by the `N`-th (0-based) argument: ``` using ::testing::NotNull; using ::testing::SetArrayArgument; class MockArrayMutator : public ArrayMutator { public: MOCK_METHOD2(Mutate, void(int* values, int num_values)); ... }; ... MockArrayMutator mutator; int values[5] = { 1, 2, 3, 4, 5 }; EXPECT_CALL(mutator, Mutate(NotNull(), 5)) .WillOnce(SetArrayArgument<0>(values, values + 5)); ``` This also works when the argument is an output iterator: ``` using ::testing::_; using ::testing::SeArrayArgument; class MockRolodex : public Rolodex { public: MOCK_METHOD1(GetNames, void(std::back_insert_iterator >)); ... }; ... MockRolodex rolodex; vector names; names.push_back("George"); names.push_back("John"); names.push_back("Thomas"); EXPECT_CALL(rolodex, GetNames(_)) .WillOnce(SetArrayArgument<0>(names.begin(), names.end())); ``` ## Changing a Mock Object's Behavior Based on the State ## If you expect a call to change the behavior of a mock object, you can use `::testing::InSequence` to specify different behaviors before and after the call: ``` using ::testing::InSequence; using ::testing::Return; ... { InSequence seq; EXPECT_CALL(my_mock, IsDirty()) .WillRepeatedly(Return(true)); EXPECT_CALL(my_mock, Flush()); EXPECT_CALL(my_mock, IsDirty()) .WillRepeatedly(Return(false)); } my_mock.FlushIfDirty(); ``` This makes `my_mock.IsDirty()` return `true` before `my_mock.Flush()` is called and return `false` afterwards. If the behavior change is more complex, you can store the effects in a variable and make a mock method get its return value from that variable: ``` using ::testing::_; using ::testing::SaveArg; using ::testing::Return; ACTION_P(ReturnPointee, p) { return *p; } ... int previous_value = 0; EXPECT_CALL(my_mock, GetPrevValue()) .WillRepeatedly(ReturnPointee(&previous_value)); EXPECT_CALL(my_mock, UpdateValue(_)) .WillRepeatedly(SaveArg<0>(&previous_value)); my_mock.DoSomethingToUpdateValue(); ``` Here `my_mock.GetPrevValue()` will always return the argument of the last `UpdateValue()` call. ## Setting the Default Value for a Return Type ## If a mock method's return type is a built-in C++ type or pointer, by default it will return 0 when invoked. Also, in C++ 11 and above, a mock method whose return type has a default constructor will return a default-constructed value by default. You only need to specify an action if this default value doesn't work for you. Sometimes, you may want to change this default value, or you may want to specify a default value for types Google Mock doesn't know about. You can do this using the `::testing::DefaultValue` class template: ``` class MockFoo : public Foo { public: MOCK_METHOD0(CalculateBar, Bar()); }; ... Bar default_bar; // Sets the default return value for type Bar. DefaultValue::Set(default_bar); MockFoo foo; // We don't need to specify an action here, as the default // return value works for us. EXPECT_CALL(foo, CalculateBar()); foo.CalculateBar(); // This should return default_bar. // Unsets the default return value. DefaultValue::Clear(); ``` Please note that changing the default value for a type can make you tests hard to understand. We recommend you to use this feature judiciously. For example, you may want to make sure the `Set()` and `Clear()` calls are right next to the code that uses your mock. ## Setting the Default Actions for a Mock Method ## You've learned how to change the default value of a given type. However, this may be too coarse for your purpose: perhaps you have two mock methods with the same return type and you want them to have different behaviors. The `ON_CALL()` macro allows you to customize your mock's behavior at the method level: ``` using ::testing::_; using ::testing::AnyNumber; using ::testing::Gt; using ::testing::Return; ... ON_CALL(foo, Sign(_)) .WillByDefault(Return(-1)); ON_CALL(foo, Sign(0)) .WillByDefault(Return(0)); ON_CALL(foo, Sign(Gt(0))) .WillByDefault(Return(1)); EXPECT_CALL(foo, Sign(_)) .Times(AnyNumber()); foo.Sign(5); // This should return 1. foo.Sign(-9); // This should return -1. foo.Sign(0); // This should return 0. ``` As you may have guessed, when there are more than one `ON_CALL()` statements, the news order take precedence over the older ones. In other words, the **last** one that matches the function arguments will be used. This matching order allows you to set up the common behavior in a mock object's constructor or the test fixture's set-up phase and specialize the mock's behavior later. ## Using Functions/Methods/Functors as Actions ## If the built-in actions don't suit you, you can easily use an existing function, method, or functor as an action: ``` using ::testing::_; using ::testing::Invoke; class MockFoo : public Foo { public: MOCK_METHOD2(Sum, int(int x, int y)); MOCK_METHOD1(ComplexJob, bool(int x)); }; int CalculateSum(int x, int y) { return x + y; } class Helper { public: bool ComplexJob(int x); }; ... MockFoo foo; Helper helper; EXPECT_CALL(foo, Sum(_, _)) .WillOnce(Invoke(CalculateSum)); EXPECT_CALL(foo, ComplexJob(_)) .WillOnce(Invoke(&helper, &Helper::ComplexJob)); foo.Sum(5, 6); // Invokes CalculateSum(5, 6). foo.ComplexJob(10); // Invokes helper.ComplexJob(10); ``` The only requirement is that the type of the function, etc must be _compatible_ with the signature of the mock function, meaning that the latter's arguments can be implicitly converted to the corresponding arguments of the former, and the former's return type can be implicitly converted to that of the latter. So, you can invoke something whose type is _not_ exactly the same as the mock function, as long as it's safe to do so - nice, huh? ## Invoking a Function/Method/Functor Without Arguments ## `Invoke()` is very useful for doing actions that are more complex. It passes the mock function's arguments to the function or functor being invoked such that the callee has the full context of the call to work with. If the invoked function is not interested in some or all of the arguments, it can simply ignore them. Yet, a common pattern is that a test author wants to invoke a function without the arguments of the mock function. `Invoke()` allows her to do that using a wrapper function that throws away the arguments before invoking an underlining nullary function. Needless to say, this can be tedious and obscures the intent of the test. `InvokeWithoutArgs()` solves this problem. It's like `Invoke()` except that it doesn't pass the mock function's arguments to the callee. Here's an example: ``` using ::testing::_; using ::testing::InvokeWithoutArgs; class MockFoo : public Foo { public: MOCK_METHOD1(ComplexJob, bool(int n)); }; bool Job1() { ... } ... MockFoo foo; EXPECT_CALL(foo, ComplexJob(_)) .WillOnce(InvokeWithoutArgs(Job1)); foo.ComplexJob(10); // Invokes Job1(). ``` ## Invoking an Argument of the Mock Function ## Sometimes a mock function will receive a function pointer or a functor (in other words, a "callable") as an argument, e.g. ``` class MockFoo : public Foo { public: MOCK_METHOD2(DoThis, bool(int n, bool (*fp)(int))); }; ``` and you may want to invoke this callable argument: ``` using ::testing::_; ... MockFoo foo; EXPECT_CALL(foo, DoThis(_, _)) .WillOnce(...); // Will execute (*fp)(5), where fp is the // second argument DoThis() receives. ``` Arghh, you need to refer to a mock function argument but C++ has no lambda (yet), so you have to define your own action. :-( Or do you really? Well, Google Mock has an action to solve _exactly_ this problem: ``` InvokeArgument(arg_1, arg_2, ..., arg_m) ``` will invoke the `N`-th (0-based) argument the mock function receives, with `arg_1`, `arg_2`, ..., and `arg_m`. No matter if the argument is a function pointer or a functor, Google Mock handles them both. With that, you could write: ``` using ::testing::_; using ::testing::InvokeArgument; ... EXPECT_CALL(foo, DoThis(_, _)) .WillOnce(InvokeArgument<1>(5)); // Will execute (*fp)(5), where fp is the // second argument DoThis() receives. ``` What if the callable takes an argument by reference? No problem - just wrap it inside `ByRef()`: ``` ... MOCK_METHOD1(Bar, bool(bool (*fp)(int, const Helper&))); ... using ::testing::_; using ::testing::ByRef; using ::testing::InvokeArgument; ... MockFoo foo; Helper helper; ... EXPECT_CALL(foo, Bar(_)) .WillOnce(InvokeArgument<0>(5, ByRef(helper))); // ByRef(helper) guarantees that a reference to helper, not a copy of it, // will be passed to the callable. ``` What if the callable takes an argument by reference and we do **not** wrap the argument in `ByRef()`? Then `InvokeArgument()` will _make a copy_ of the argument, and pass a _reference to the copy_, instead of a reference to the original value, to the callable. This is especially handy when the argument is a temporary value: ``` ... MOCK_METHOD1(DoThat, bool(bool (*f)(const double& x, const string& s))); ... using ::testing::_; using ::testing::InvokeArgument; ... MockFoo foo; ... EXPECT_CALL(foo, DoThat(_)) .WillOnce(InvokeArgument<0>(5.0, string("Hi"))); // Will execute (*f)(5.0, string("Hi")), where f is the function pointer // DoThat() receives. Note that the values 5.0 and string("Hi") are // temporary and dead once the EXPECT_CALL() statement finishes. Yet // it's fine to perform this action later, since a copy of the values // are kept inside the InvokeArgument action. ``` ## Ignoring an Action's Result ## Sometimes you have an action that returns _something_, but you need an action that returns `void` (perhaps you want to use it in a mock function that returns `void`, or perhaps it needs to be used in `DoAll()` and it's not the last in the list). `IgnoreResult()` lets you do that. For example: ``` using ::testing::_; using ::testing::Invoke; using ::testing::Return; int Process(const MyData& data); string DoSomething(); class MockFoo : public Foo { public: MOCK_METHOD1(Abc, void(const MyData& data)); MOCK_METHOD0(Xyz, bool()); }; ... MockFoo foo; EXPECT_CALL(foo, Abc(_)) // .WillOnce(Invoke(Process)); // The above line won't compile as Process() returns int but Abc() needs // to return void. .WillOnce(IgnoreResult(Invoke(Process))); EXPECT_CALL(foo, Xyz()) .WillOnce(DoAll(IgnoreResult(Invoke(DoSomething)), // Ignores the string DoSomething() returns. Return(true))); ``` Note that you **cannot** use `IgnoreResult()` on an action that already returns `void`. Doing so will lead to ugly compiler errors. ## Selecting an Action's Arguments ## Say you have a mock function `Foo()` that takes seven arguments, and you have a custom action that you want to invoke when `Foo()` is called. Trouble is, the custom action only wants three arguments: ``` using ::testing::_; using ::testing::Invoke; ... MOCK_METHOD7(Foo, bool(bool visible, const string& name, int x, int y, const map, double>& weight, double min_weight, double max_wight)); ... bool IsVisibleInQuadrant1(bool visible, int x, int y) { return visible && x >= 0 && y >= 0; } ... EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) .WillOnce(Invoke(IsVisibleInQuadrant1)); // Uh, won't compile. :-( ``` To please the compiler God, you can to define an "adaptor" that has the same signature as `Foo()` and calls the custom action with the right arguments: ``` using ::testing::_; using ::testing::Invoke; bool MyIsVisibleInQuadrant1(bool visible, const string& name, int x, int y, const map, double>& weight, double min_weight, double max_wight) { return IsVisibleInQuadrant1(visible, x, y); } ... EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) .WillOnce(Invoke(MyIsVisibleInQuadrant1)); // Now it works. ``` But isn't this awkward? Google Mock provides a generic _action adaptor_, so you can spend your time minding more important business than writing your own adaptors. Here's the syntax: ``` WithArgs(action) ``` creates an action that passes the arguments of the mock function at the given indices (0-based) to the inner `action` and performs it. Using `WithArgs`, our original example can be written as: ``` using ::testing::_; using ::testing::Invoke; using ::testing::WithArgs; ... EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) .WillOnce(WithArgs<0, 2, 3>(Invoke(IsVisibleInQuadrant1))); // No need to define your own adaptor. ``` For better readability, Google Mock also gives you: * `WithoutArgs(action)` when the inner `action` takes _no_ argument, and * `WithArg(action)` (no `s` after `Arg`) when the inner `action` takes _one_ argument. As you may have realized, `InvokeWithoutArgs(...)` is just syntactic sugar for `WithoutArgs(Invoke(...))`. Here are more tips: * The inner action used in `WithArgs` and friends does not have to be `Invoke()` -- it can be anything. * You can repeat an argument in the argument list if necessary, e.g. `WithArgs<2, 3, 3, 5>(...)`. * You can change the order of the arguments, e.g. `WithArgs<3, 2, 1>(...)`. * The types of the selected arguments do _not_ have to match the signature of the inner action exactly. It works as long as they can be implicitly converted to the corresponding arguments of the inner action. For example, if the 4-th argument of the mock function is an `int` and `my_action` takes a `double`, `WithArg<4>(my_action)` will work. ## Ignoring Arguments in Action Functions ## The selecting-an-action's-arguments recipe showed us one way to make a mock function and an action with incompatible argument lists fit together. The downside is that wrapping the action in `WithArgs<...>()` can get tedious for people writing the tests. If you are defining a function, method, or functor to be used with `Invoke*()`, and you are not interested in some of its arguments, an alternative to `WithArgs` is to declare the uninteresting arguments as `Unused`. This makes the definition less cluttered and less fragile in case the types of the uninteresting arguments change. It could also increase the chance the action function can be reused. For example, given ``` MOCK_METHOD3(Foo, double(const string& label, double x, double y)); MOCK_METHOD3(Bar, double(int index, double x, double y)); ``` instead of ``` using ::testing::_; using ::testing::Invoke; double DistanceToOriginWithLabel(const string& label, double x, double y) { return sqrt(x*x + y*y); } double DistanceToOriginWithIndex(int index, double x, double y) { return sqrt(x*x + y*y); } ... EXEPCT_CALL(mock, Foo("abc", _, _)) .WillOnce(Invoke(DistanceToOriginWithLabel)); EXEPCT_CALL(mock, Bar(5, _, _)) .WillOnce(Invoke(DistanceToOriginWithIndex)); ``` you could write ``` using ::testing::_; using ::testing::Invoke; using ::testing::Unused; double DistanceToOrigin(Unused, double x, double y) { return sqrt(x*x + y*y); } ... EXEPCT_CALL(mock, Foo("abc", _, _)) .WillOnce(Invoke(DistanceToOrigin)); EXEPCT_CALL(mock, Bar(5, _, _)) .WillOnce(Invoke(DistanceToOrigin)); ``` ## Sharing Actions ## Just like matchers, a Google Mock action object consists of a pointer to a ref-counted implementation object. Therefore copying actions is also allowed and very efficient. When the last action that references the implementation object dies, the implementation object will be deleted. If you have some complex action that you want to use again and again, you may not have to build it from scratch everytime. If the action doesn't have an internal state (i.e. if it always does the same thing no matter how many times it has been called), you can assign it to an action variable and use that variable repeatedly. For example: ``` Action set_flag = DoAll(SetArgPointee<0>(5), Return(true)); ... use set_flag in .WillOnce() and .WillRepeatedly() ... ``` However, if the action has its own state, you may be surprised if you share the action object. Suppose you have an action factory `IncrementCounter(init)` which creates an action that increments and returns a counter whose initial value is `init`, using two actions created from the same expression and using a shared action will exihibit different behaviors. Example: ``` EXPECT_CALL(foo, DoThis()) .WillRepeatedly(IncrementCounter(0)); EXPECT_CALL(foo, DoThat()) .WillRepeatedly(IncrementCounter(0)); foo.DoThis(); // Returns 1. foo.DoThis(); // Returns 2. foo.DoThat(); // Returns 1 - Blah() uses a different // counter than Bar()'s. ``` versus ``` Action increment = IncrementCounter(0); EXPECT_CALL(foo, DoThis()) .WillRepeatedly(increment); EXPECT_CALL(foo, DoThat()) .WillRepeatedly(increment); foo.DoThis(); // Returns 1. foo.DoThis(); // Returns 2. foo.DoThat(); // Returns 3 - the counter is shared. ``` # Misc Recipes on Using Google Mock # ## Mocking Methods That Use Move-Only Types ## C++11 introduced move-only types. A move-only-typed value can be moved from one object to another, but cannot be copied. `std::unique_ptr` is probably the most commonly used move-only type. Mocking a method that takes and/or returns move-only types presents some challenges, but nothing insurmountable. This recipe shows you how you can do it. Let’s say we are working on a fictional project that lets one post and share snippets called “buzzes”. Your code uses these types: ``` enum class AccessLevel { kInternal, kPublic }; class Buzz { public: explicit Buzz(AccessLevel access) { … } ... }; class Buzzer { public: virtual ~Buzzer() {} virtual std::unique_ptr MakeBuzz(const std::string& text) = 0; virtual bool ShareBuzz(std::unique_ptr buzz, Time timestamp) = 0; ... }; ``` A `Buzz` object represents a snippet being posted. A class that implements the `Buzzer` interface is capable of creating and sharing `Buzz`. Methods in `Buzzer` may return a `unique_ptr` or take a `unique_ptr`. Now we need to mock `Buzzer` in our tests. To mock a method that returns a move-only type, you just use the familiar `MOCK_METHOD` syntax as usual: ``` class MockBuzzer : public Buzzer { public: MOCK_METHOD1(MakeBuzz, std::unique_ptr(const std::string& text)); … }; ``` However, if you attempt to use the same `MOCK_METHOD` pattern to mock a method that takes a move-only parameter, you’ll get a compiler error currently: ``` // Does NOT compile! MOCK_METHOD2(ShareBuzz, bool(std::unique_ptr buzz, Time timestamp)); ``` While it’s highly desirable to make this syntax just work, it’s not trivial and the work hasn’t been done yet. Fortunately, there is a trick you can apply today to get something that works nearly as well as this. The trick, is to delegate the `ShareBuzz()` method to a mock method (let’s call it `DoShareBuzz()`) that does not take move-only parameters: ``` class MockBuzzer : public Buzzer { public: MOCK_METHOD1(MakeBuzz, std::unique_ptr(const std::string& text)); MOCK_METHOD2(DoShareBuzz, bool(Buzz* buzz, Time timestamp)); bool ShareBuzz(std::unique_ptr buzz, Time timestamp) { return DoShareBuzz(buzz.get(), timestamp); } }; ``` Note that there's no need to define or declare `DoShareBuzz()` in a base class. You only need to define it as a `MOCK_METHOD` in the mock class. Now that we have the mock class defined, we can use it in tests. In the following code examples, we assume that we have defined a `MockBuzzer` object named `mock_buzzer_`: ``` MockBuzzer mock_buzzer_; ``` First let’s see how we can set expectations on the `MakeBuzz()` method, which returns a `unique_ptr`. As usual, if you set an expectation without an action (i.e. the `.WillOnce()` or `.WillRepeated()` clause), when that expectation fires, the default action for that method will be taken. Since `unique_ptr<>` has a default constructor that returns a null `unique_ptr`, that’s what you’ll get if you don’t specify an action: ``` // Use the default action. EXPECT_CALL(mock_buzzer_, MakeBuzz("hello")); // Triggers the previous EXPECT_CALL. EXPECT_EQ(nullptr, mock_buzzer_.MakeBuzz("hello")); ``` If you are not happy with the default action, you can tweak it. Depending on what you need, you may either tweak the default action for a specific (mock object, mock method) combination using `ON_CALL()`, or you may tweak the default action for all mock methods that return a specific type. The usage of `ON_CALL()` is similar to `EXPECT_CALL()`, so we’ll skip it and just explain how to do the latter (tweaking the default action for a specific return type). You do this via the `DefaultValue<>::SetFactory()` and `DefaultValue<>::Clear()` API: ``` // Sets the default action for return type std::unique_ptr to // creating a new Buzz every time. DefaultValue>::SetFactory( [] { return MakeUnique(AccessLevel::kInternal); }); // When this fires, the default action of MakeBuzz() will run, which // will return a new Buzz object. EXPECT_CALL(mock_buzzer_, MakeBuzz("hello")).Times(AnyNumber()); auto buzz1 = mock_buzzer_.MakeBuzz("hello"); auto buzz2 = mock_buzzer_.MakeBuzz("hello"); EXPECT_NE(nullptr, buzz1); EXPECT_NE(nullptr, buzz2); EXPECT_NE(buzz1, buzz2); // Resets the default action for return type std::unique_ptr, // to avoid interfere with other tests. DefaultValue>::Clear(); ``` What if you want the method to do something other than the default action? If you just need to return a pre-defined move-only value, you can use the `Return(ByMove(...))` action: ``` // When this fires, the unique_ptr<> specified by ByMove(...) will // be returned. EXPECT_CALL(mock_buzzer_, MakeBuzz("world")) .WillOnce(Return(ByMove(MakeUnique(AccessLevel::kInternal)))); EXPECT_NE(nullptr, mock_buzzer_.MakeBuzz("world")); ``` Note that `ByMove()` is essential here - if you drop it, the code won’t compile. Quiz time! What do you think will happen if a `Return(ByMove(...))` action is performed more than once (e.g. you write `….WillRepeatedly(Return(ByMove(...)));`)? Come think of it, after the first time the action runs, the source value will be consumed (since it’s a move-only value), so the next time around, there’s no value to move from -- you’ll get a run-time error that `Return(ByMove(...))` can only be run once. If you need your mock method to do more than just moving a pre-defined value, remember that you can always use `Invoke()` to call a lambda or a callable object, which can do pretty much anything you want: ``` EXPECT_CALL(mock_buzzer_, MakeBuzz("x")) .WillRepeatedly(Invoke([](const std::string& text) { return std::make_unique(AccessLevel::kInternal); })); EXPECT_NE(nullptr, mock_buzzer_.MakeBuzz("x")); EXPECT_NE(nullptr, mock_buzzer_.MakeBuzz("x")); ``` Every time this `EXPECT_CALL` fires, a new `unique_ptr` will be created and returned. You cannot do this with `Return(ByMove(...))`. Now there’s one topic we haven’t covered: how do you set expectations on `ShareBuzz()`, which takes a move-only-typed parameter? The answer is you don’t. Instead, you set expectations on the `DoShareBuzz()` mock method (remember that we defined a `MOCK_METHOD` for `DoShareBuzz()`, not `ShareBuzz()`): ``` EXPECT_CALL(mock_buzzer_, DoShareBuzz(NotNull(), _)); // When one calls ShareBuzz() on the MockBuzzer like this, the call is // forwarded to DoShareBuzz(), which is mocked. Therefore this statement // will trigger the above EXPECT_CALL. mock_buzzer_.ShareBuzz(MakeUnique<Buzz>(AccessLevel::kInternal), ::base::Now()); ``` Some of you may have spotted one problem with this approach: the `DoShareBuzz()` mock method differs from the real `ShareBuzz()` method in that it cannot take ownership of the buzz parameter - `ShareBuzz()` will always delete buzz after `DoShareBuzz()` returns. What if you need to save the buzz object somewhere for later use when `ShareBuzz()` is called? Indeed, you'd be stuck. Another problem with the `DoShareBuzz()` we had is that it can surprise people reading or maintaining the test, as one would expect that `DoShareBuzz()` has (logically) the same contract as `ShareBuzz()`. Fortunately, these problems can be fixed with a bit more code. Let's try to get it right this time: ``` class MockBuzzer : public Buzzer { public: MockBuzzer() { // Since DoShareBuzz(buzz, time) is supposed to take ownership of // buzz, define a default behavior for DoShareBuzz(buzz, time) to // delete buzz. ON_CALL(*this, DoShareBuzz(_, _)) .WillByDefault(Invoke([](Buzz* buzz, Time timestamp) { delete buzz; return true; })); } MOCK_METHOD1(MakeBuzz, std::unique_ptr(const std::string& text)); // Takes ownership of buzz. MOCK_METHOD2(DoShareBuzz, bool(Buzz* buzz, Time timestamp)); bool ShareBuzz(std::unique_ptr buzz, Time timestamp) { return DoShareBuzz(buzz.release(), timestamp); } }; ``` Now, the mock `DoShareBuzz()` method is free to save the buzz argument for later use if this is what you want: ``` std::unique_ptr intercepted_buzz; EXPECT_CALL(mock_buzzer_, DoShareBuzz(NotNull(), _)) .WillOnce(Invoke([&intercepted_buzz](Buzz* buzz, Time timestamp) { // Save buzz in intercepted_buzz for analysis later. intercepted_buzz.reset(buzz); return false; })); mock_buzzer_.ShareBuzz(std::make_unique(AccessLevel::kInternal), Now()); EXPECT_NE(nullptr, intercepted_buzz); ``` Using the tricks covered in this recipe, you are now able to mock methods that take and/or return move-only types. Put your newly-acquired power to good use - when you design a new API, you can now feel comfortable using `unique_ptrs` as appropriate, without fearing that doing so will compromise your tests. ## Making the Compilation Faster ## Believe it or not, the _vast majority_ of the time spent on compiling a mock class is in generating its constructor and destructor, as they perform non-trivial tasks (e.g. verification of the expectations). What's more, mock methods with different signatures have different types and thus their constructors/destructors need to be generated by the compiler separately. As a result, if you mock many different types of methods, compiling your mock class can get really slow. If you are experiencing slow compilation, you can move the definition of your mock class' constructor and destructor out of the class body and into a `.cpp` file. This way, even if you `#include` your mock class in N files, the compiler only needs to generate its constructor and destructor once, resulting in a much faster compilation. Let's illustrate the idea using an example. Here's the definition of a mock class before applying this recipe: ``` // File mock_foo.h. ... class MockFoo : public Foo { public: // Since we don't declare the constructor or the destructor, // the compiler will generate them in every translation unit // where this mock class is used. MOCK_METHOD0(DoThis, int()); MOCK_METHOD1(DoThat, bool(const char* str)); ... more mock methods ... }; ``` After the change, it would look like: ``` // File mock_foo.h. ... class MockFoo : public Foo { public: // The constructor and destructor are declared, but not defined, here. MockFoo(); virtual ~MockFoo(); MOCK_METHOD0(DoThis, int()); MOCK_METHOD1(DoThat, bool(const char* str)); ... more mock methods ... }; ``` and ``` // File mock_foo.cpp. #include "path/to/mock_foo.h" // The definitions may appear trivial, but the functions actually do a // lot of things through the constructors/destructors of the member // variables used to implement the mock methods. MockFoo::MockFoo() {} MockFoo::~MockFoo() {} ``` ## Forcing a Verification ## When it's being destoyed, your friendly mock object will automatically verify that all expectations on it have been satisfied, and will generate [Google Test](../../googletest/) failures if not. This is convenient as it leaves you with one less thing to worry about. That is, unless you are not sure if your mock object will be destoyed. How could it be that your mock object won't eventually be destroyed? Well, it might be created on the heap and owned by the code you are testing. Suppose there's a bug in that code and it doesn't delete the mock object properly - you could end up with a passing test when there's actually a bug. Using a heap checker is a good idea and can alleviate the concern, but its implementation may not be 100% reliable. So, sometimes you do want to _force_ Google Mock to verify a mock object before it is (hopefully) destructed. You can do this with `Mock::VerifyAndClearExpectations(&mock_object)`: ``` TEST(MyServerTest, ProcessesRequest) { using ::testing::Mock; MockFoo* const foo = new MockFoo; EXPECT_CALL(*foo, ...)...; // ... other expectations ... // server now owns foo. MyServer server(foo); server.ProcessRequest(...); // In case that server's destructor will forget to delete foo, // this will verify the expectations anyway. Mock::VerifyAndClearExpectations(foo); } // server is destroyed when it goes out of scope here. ``` **Tip:** The `Mock::VerifyAndClearExpectations()` function returns a `bool` to indicate whether the verification was successful (`true` for yes), so you can wrap that function call inside a `ASSERT_TRUE()` if there is no point going further when the verification has failed. ## Using Check Points ## Sometimes you may want to "reset" a mock object at various check points in your test: at each check point, you verify that all existing expectations on the mock object have been satisfied, and then you set some new expectations on it as if it's newly created. This allows you to work with a mock object in "phases" whose sizes are each manageable. One such scenario is that in your test's `SetUp()` function, you may want to put the object you are testing into a certain state, with the help from a mock object. Once in the desired state, you want to clear all expectations on the mock, such that in the `TEST_F` body you can set fresh expectations on it. As you may have figured out, the `Mock::VerifyAndClearExpectations()` function we saw in the previous recipe can help you here. Or, if you are using `ON_CALL()` to set default actions on the mock object and want to clear the default actions as well, use `Mock::VerifyAndClear(&mock_object)` instead. This function does what `Mock::VerifyAndClearExpectations(&mock_object)` does and returns the same `bool`, **plus** it clears the `ON_CALL()` statements on `mock_object` too. Another trick you can use to achieve the same effect is to put the expectations in sequences and insert calls to a dummy "check-point" function at specific places. Then you can verify that the mock function calls do happen at the right time. For example, if you are exercising code: ``` Foo(1); Foo(2); Foo(3); ``` and want to verify that `Foo(1)` and `Foo(3)` both invoke `mock.Bar("a")`, but `Foo(2)` doesn't invoke anything. You can write: ``` using ::testing::MockFunction; TEST(FooTest, InvokesBarCorrectly) { MyMock mock; // Class MockFunction has exactly one mock method. It is named // Call() and has type F. MockFunction check; { InSequence s; EXPECT_CALL(mock, Bar("a")); EXPECT_CALL(check, Call("1")); EXPECT_CALL(check, Call("2")); EXPECT_CALL(mock, Bar("a")); } Foo(1); check.Call("1"); Foo(2); check.Call("2"); Foo(3); } ``` The expectation spec says that the first `Bar("a")` must happen before check point "1", the second `Bar("a")` must happen after check point "2", and nothing should happen between the two check points. The explicit check points make it easy to tell which `Bar("a")` is called by which call to `Foo()`. ## Mocking Destructors ## Sometimes you want to make sure a mock object is destructed at the right time, e.g. after `bar->A()` is called but before `bar->B()` is called. We already know that you can specify constraints on the order of mock function calls, so all we need to do is to mock the destructor of the mock function. This sounds simple, except for one problem: a destructor is a special function with special syntax and special semantics, and the `MOCK_METHOD0` macro doesn't work for it: ``` MOCK_METHOD0(~MockFoo, void()); // Won't compile! ``` The good news is that you can use a simple pattern to achieve the same effect. First, add a mock function `Die()` to your mock class and call it in the destructor, like this: ``` class MockFoo : public Foo { ... // Add the following two lines to the mock class. MOCK_METHOD0(Die, void()); virtual ~MockFoo() { Die(); } }; ``` (If the name `Die()` clashes with an existing symbol, choose another name.) Now, we have translated the problem of testing when a `MockFoo` object dies to testing when its `Die()` method is called: ``` MockFoo* foo = new MockFoo; MockBar* bar = new MockBar; ... { InSequence s; // Expects *foo to die after bar->A() and before bar->B(). EXPECT_CALL(*bar, A()); EXPECT_CALL(*foo, Die()); EXPECT_CALL(*bar, B()); } ``` And that's that. ## Using Google Mock and Threads ## **IMPORTANT NOTE:** What we describe in this recipe is **ONLY** true on platforms where Google Mock is thread-safe. Currently these are only platforms that support the pthreads library (this includes Linux and Mac). To make it thread-safe on other platforms we only need to implement some synchronization operations in `"gtest/internal/gtest-port.h"`. In a **unit** test, it's best if you could isolate and test a piece of code in a single-threaded context. That avoids race conditions and dead locks, and makes debugging your test much easier. Yet many programs are multi-threaded, and sometimes to test something we need to pound on it from more than one thread. Google Mock works for this purpose too. Remember the steps for using a mock: 1. Create a mock object `foo`. 1. Set its default actions and expectations using `ON_CALL()` and `EXPECT_CALL()`. 1. The code under test calls methods of `foo`. 1. Optionally, verify and reset the mock. 1. Destroy the mock yourself, or let the code under test destroy it. The destructor will automatically verify it. If you follow the following simple rules, your mocks and threads can live happily together: * Execute your _test code_ (as opposed to the code being tested) in _one_ thread. This makes your test easy to follow. * Obviously, you can do step #1 without locking. * When doing step #2 and #5, make sure no other thread is accessing `foo`. Obvious too, huh? * #3 and #4 can be done either in one thread or in multiple threads - anyway you want. Google Mock takes care of the locking, so you don't have to do any - unless required by your test logic. If you violate the rules (for example, if you set expectations on a mock while another thread is calling its methods), you get undefined behavior. That's not fun, so don't do it. Google Mock guarantees that the action for a mock function is done in the same thread that called the mock function. For example, in ``` EXPECT_CALL(mock, Foo(1)) .WillOnce(action1); EXPECT_CALL(mock, Foo(2)) .WillOnce(action2); ``` if `Foo(1)` is called in thread 1 and `Foo(2)` is called in thread 2, Google Mock will execute `action1` in thread 1 and `action2` in thread 2. Google Mock does _not_ impose a sequence on actions performed in different threads (doing so may create deadlocks as the actions may need to cooperate). This means that the execution of `action1` and `action2` in the above example _may_ interleave. If this is a problem, you should add proper synchronization logic to `action1` and `action2` to make the test thread-safe. Also, remember that `DefaultValue` is a global resource that potentially affects _all_ living mock objects in your program. Naturally, you won't want to mess with it from multiple threads or when there still are mocks in action. ## Controlling How Much Information Google Mock Prints ## When Google Mock sees something that has the potential of being an error (e.g. a mock function with no expectation is called, a.k.a. an uninteresting call, which is allowed but perhaps you forgot to explicitly ban the call), it prints some warning messages, including the arguments of the function and the return value. Hopefully this will remind you to take a look and see if there is indeed a problem. Sometimes you are confident that your tests are correct and may not appreciate such friendly messages. Some other times, you are debugging your tests or learning about the behavior of the code you are testing, and wish you could observe every mock call that happens (including argument values and the return value). Clearly, one size doesn't fit all. You can control how much Google Mock tells you using the `--gmock_verbose=LEVEL` command-line flag, where `LEVEL` is a string with three possible values: * `info`: Google Mock will print all informational messages, warnings, and errors (most verbose). At this setting, Google Mock will also log any calls to the `ON_CALL/EXPECT_CALL` macros. * `warning`: Google Mock will print both warnings and errors (less verbose). This is the default. * `error`: Google Mock will print errors only (least verbose). Alternatively, you can adjust the value of that flag from within your tests like so: ``` ::testing::FLAGS_gmock_verbose = "error"; ``` Now, judiciously use the right flag to enable Google Mock serve you better! ## Gaining Super Vision into Mock Calls ## You have a test using Google Mock. It fails: Google Mock tells you that some expectations aren't satisfied. However, you aren't sure why: Is there a typo somewhere in the matchers? Did you mess up the order of the `EXPECT_CALL`s? Or is the code under test doing something wrong? How can you find out the cause? Won't it be nice if you have X-ray vision and can actually see the trace of all `EXPECT_CALL`s and mock method calls as they are made? For each call, would you like to see its actual argument values and which `EXPECT_CALL` Google Mock thinks it matches? You can unlock this power by running your test with the `--gmock_verbose=info` flag. For example, given the test program: ``` using testing::_; using testing::HasSubstr; using testing::Return; class MockFoo { public: MOCK_METHOD2(F, void(const string& x, const string& y)); }; TEST(Foo, Bar) { MockFoo mock; EXPECT_CALL(mock, F(_, _)).WillRepeatedly(Return()); EXPECT_CALL(mock, F("a", "b")); EXPECT_CALL(mock, F("c", HasSubstr("d"))); mock.F("a", "good"); mock.F("a", "b"); } ``` if you run it with `--gmock_verbose=info`, you will see this output: ``` [ RUN ] Foo.Bar foo_test.cc:14: EXPECT_CALL(mock, F(_, _)) invoked foo_test.cc:15: EXPECT_CALL(mock, F("a", "b")) invoked foo_test.cc:16: EXPECT_CALL(mock, F("c", HasSubstr("d"))) invoked foo_test.cc:14: Mock function call matches EXPECT_CALL(mock, F(_, _))... Function call: F(@0x7fff7c8dad40"a", @0x7fff7c8dad10"good") foo_test.cc:15: Mock function call matches EXPECT_CALL(mock, F("a", "b"))... Function call: F(@0x7fff7c8dada0"a", @0x7fff7c8dad70"b") foo_test.cc:16: Failure Actual function call count doesn't match EXPECT_CALL(mock, F("c", HasSubstr("d")))... Expected: to be called once Actual: never called - unsatisfied and active [ FAILED ] Foo.Bar ``` Suppose the bug is that the `"c"` in the third `EXPECT_CALL` is a typo and should actually be `"a"`. With the above message, you should see that the actual `F("a", "good")` call is matched by the first `EXPECT_CALL`, not the third as you thought. From that it should be obvious that the third `EXPECT_CALL` is written wrong. Case solved. ## Running Tests in Emacs ## If you build and run your tests in Emacs, the source file locations of Google Mock and [Google Test](../../googletest/) errors will be highlighted. Just press `` on one of them and you'll be taken to the offending line. Or, you can just type `C-x `` to jump to the next error. To make it even easier, you can add the following lines to your `~/.emacs` file: ``` (global-set-key "\M-m" 'compile) ; m is for make (global-set-key [M-down] 'next-error) (global-set-key [M-up] '(lambda () (interactive) (next-error -1))) ``` Then you can type `M-m` to start a build, or `M-up`/`M-down` to move back and forth between errors. ## Fusing Google Mock Source Files ## Google Mock's implementation consists of dozens of files (excluding its own tests). Sometimes you may want them to be packaged up in fewer files instead, such that you can easily copy them to a new machine and start hacking there. For this we provide an experimental Python script `fuse_gmock_files.py` in the `scripts/` directory (starting with release 1.2.0). Assuming you have Python 2.4 or above installed on your machine, just go to that directory and run ``` python fuse_gmock_files.py OUTPUT_DIR ``` and you should see an `OUTPUT_DIR` directory being created with files `gtest/gtest.h`, `gmock/gmock.h`, and `gmock-gtest-all.cc` in it. These three files contain everything you need to use Google Mock (and Google Test). Just copy them to anywhere you want and you are ready to write tests and use mocks. You can use the [scrpts/test/Makefile](../scripts/test/Makefile) file as an example on how to compile your tests against them. # Extending Google Mock # ## Writing New Matchers Quickly ## The `MATCHER*` family of macros can be used to define custom matchers easily. The syntax: ``` MATCHER(name, description_string_expression) { statements; } ``` will define a matcher with the given name that executes the statements, which must return a `bool` to indicate if the match succeeds. Inside the statements, you can refer to the value being matched by `arg`, and refer to its type by `arg_type`. The description string is a `string`-typed expression that documents what the matcher does, and is used to generate the failure message when the match fails. It can (and should) reference the special `bool` variable `negation`, and should evaluate to the description of the matcher when `negation` is `false`, or that of the matcher's negation when `negation` is `true`. For convenience, we allow the description string to be empty (`""`), in which case Google Mock will use the sequence of words in the matcher name as the description. For example: ``` MATCHER(IsDivisibleBy7, "") { return (arg % 7) == 0; } ``` allows you to write ``` // Expects mock_foo.Bar(n) to be called where n is divisible by 7. EXPECT_CALL(mock_foo, Bar(IsDivisibleBy7())); ``` or, ``` using ::testing::Not; ... EXPECT_THAT(some_expression, IsDivisibleBy7()); EXPECT_THAT(some_other_expression, Not(IsDivisibleBy7())); ``` If the above assertions fail, they will print something like: ``` Value of: some_expression Expected: is divisible by 7 Actual: 27 ... Value of: some_other_expression Expected: not (is divisible by 7) Actual: 21 ``` where the descriptions `"is divisible by 7"` and `"not (is divisible by 7)"` are automatically calculated from the matcher name `IsDivisibleBy7`. As you may have noticed, the auto-generated descriptions (especially those for the negation) may not be so great. You can always override them with a string expression of your own: ``` MATCHER(IsDivisibleBy7, std::string(negation ? "isn't" : "is") + " divisible by 7") { return (arg % 7) == 0; } ``` Optionally, you can stream additional information to a hidden argument named `result_listener` to explain the match result. For example, a better definition of `IsDivisibleBy7` is: ``` MATCHER(IsDivisibleBy7, "") { if ((arg % 7) == 0) return true; *result_listener << "the remainder is " << (arg % 7); return false; } ``` With this definition, the above assertion will give a better message: ``` Value of: some_expression Expected: is divisible by 7 Actual: 27 (the remainder is 6) ``` You should let `MatchAndExplain()` print _any additional information_ that can help a user understand the match result. Note that it should explain why the match succeeds in case of a success (unless it's obvious) - this is useful when the matcher is used inside `Not()`. There is no need to print the argument value itself, as Google Mock already prints it for you. **Notes:** 1. The type of the value being matched (`arg_type`) is determined by the context in which you use the matcher and is supplied to you by the compiler, so you don't need to worry about declaring it (nor can you). This allows the matcher to be polymorphic. For example, `IsDivisibleBy7()` can be used to match any type where the value of `(arg % 7) == 0` can be implicitly converted to a `bool`. In the `Bar(IsDivisibleBy7())` example above, if method `Bar()` takes an `int`, `arg_type` will be `int`; if it takes an `unsigned long`, `arg_type` will be `unsigned long`; and so on. 1. Google Mock doesn't guarantee when or how many times a matcher will be invoked. Therefore the matcher logic must be _purely functional_ (i.e. it cannot have any side effect, and the result must not depend on anything other than the value being matched and the matcher parameters). This requirement must be satisfied no matter how you define the matcher (e.g. using one of the methods described in the following recipes). In particular, a matcher can never call a mock function, as that will affect the state of the mock object and Google Mock. ## Writing New Parameterized Matchers Quickly ## Sometimes you'll want to define a matcher that has parameters. For that you can use the macro: ``` MATCHER_P(name, param_name, description_string) { statements; } ``` where the description string can be either `""` or a string expression that references `negation` and `param_name`. For example: ``` MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; } ``` will allow you to write: ``` EXPECT_THAT(Blah("a"), HasAbsoluteValue(n)); ``` which may lead to this message (assuming `n` is 10): ``` Value of: Blah("a") Expected: has absolute value 10 Actual: -9 ``` Note that both the matcher description and its parameter are printed, making the message human-friendly. In the matcher definition body, you can write `foo_type` to reference the type of a parameter named `foo`. For example, in the body of `MATCHER_P(HasAbsoluteValue, value)` above, you can write `value_type` to refer to the type of `value`. Google Mock also provides `MATCHER_P2`, `MATCHER_P3`, ..., up to `MATCHER_P10` to support multi-parameter matchers: ``` MATCHER_Pk(name, param_1, ..., param_k, description_string) { statements; } ``` Please note that the custom description string is for a particular **instance** of the matcher, where the parameters have been bound to actual values. Therefore usually you'll want the parameter values to be part of the description. Google Mock lets you do that by referencing the matcher parameters in the description string expression. For example, ``` using ::testing::PrintToString; MATCHER_P2(InClosedRange, low, hi, std::string(negation ? "isn't" : "is") + " in range [" + PrintToString(low) + ", " + PrintToString(hi) + "]") { return low <= arg && arg <= hi; } ... EXPECT_THAT(3, InClosedRange(4, 6)); ``` would generate a failure that contains the message: ``` Expected: is in range [4, 6] ``` If you specify `""` as the description, the failure message will contain the sequence of words in the matcher name followed by the parameter values printed as a tuple. For example, ``` MATCHER_P2(InClosedRange, low, hi, "") { ... } ... EXPECT_THAT(3, InClosedRange(4, 6)); ``` would generate a failure that contains the text: ``` Expected: in closed range (4, 6) ``` For the purpose of typing, you can view ``` MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... } ``` as shorthand for ``` template FooMatcherPk Foo(p1_type p1, ..., pk_type pk) { ... } ``` When you write `Foo(v1, ..., vk)`, the compiler infers the types of the parameters `v1`, ..., and `vk` for you. If you are not happy with the result of the type inference, you can specify the types by explicitly instantiating the template, as in `Foo(5, false)`. As said earlier, you don't get to (or need to) specify `arg_type` as that's determined by the context in which the matcher is used. You can assign the result of expression `Foo(p1, ..., pk)` to a variable of type `FooMatcherPk`. This can be useful when composing matchers. Matchers that don't have a parameter or have only one parameter have special types: you can assign `Foo()` to a `FooMatcher`-typed variable, and assign `Foo(p)` to a `FooMatcherP`-typed variable. While you can instantiate a matcher template with reference types, passing the parameters by pointer usually makes your code more readable. If, however, you still want to pass a parameter by reference, be aware that in the failure message generated by the matcher you will see the value of the referenced object but not its address. You can overload matchers with different numbers of parameters: ``` MATCHER_P(Blah, a, description_string_1) { ... } MATCHER_P2(Blah, a, b, description_string_2) { ... } ``` While it's tempting to always use the `MATCHER*` macros when defining a new matcher, you should also consider implementing `MatcherInterface` or using `MakePolymorphicMatcher()` instead (see the recipes that follow), especially if you need to use the matcher a lot. While these approaches require more work, they give you more control on the types of the value being matched and the matcher parameters, which in general leads to better compiler error messages that pay off in the long run. They also allow overloading matchers based on parameter types (as opposed to just based on the number of parameters). ## Writing New Monomorphic Matchers ## A matcher of argument type `T` implements `::testing::MatcherInterface` and does two things: it tests whether a value of type `T` matches the matcher, and can describe what kind of values it matches. The latter ability is used for generating readable error messages when expectations are violated. The interface looks like this: ``` class MatchResultListener { public: ... // Streams x to the underlying ostream; does nothing if the ostream // is NULL. template MatchResultListener& operator<<(const T& x); // Returns the underlying ostream. ::std::ostream* stream(); }; template class MatcherInterface { public: virtual ~MatcherInterface(); // Returns true iff the matcher matches x; also explains the match // result to 'listener'. virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0; // Describes this matcher to an ostream. virtual void DescribeTo(::std::ostream* os) const = 0; // Describes the negation of this matcher to an ostream. virtual void DescribeNegationTo(::std::ostream* os) const; }; ``` If you need a custom matcher but `Truly()` is not a good option (for example, you may not be happy with the way `Truly(predicate)` describes itself, or you may want your matcher to be polymorphic as `Eq(value)` is), you can define a matcher to do whatever you want in two steps: first implement the matcher interface, and then define a factory function to create a matcher instance. The second step is not strictly needed but it makes the syntax of using the matcher nicer. For example, you can define a matcher to test whether an `int` is divisible by 7 and then use it like this: ``` using ::testing::MakeMatcher; using ::testing::Matcher; using ::testing::MatcherInterface; using ::testing::MatchResultListener; class DivisibleBy7Matcher : public MatcherInterface { public: virtual bool MatchAndExplain(int n, MatchResultListener* listener) const { return (n % 7) == 0; } virtual void DescribeTo(::std::ostream* os) const { *os << "is divisible by 7"; } virtual void DescribeNegationTo(::std::ostream* os) const { *os << "is not divisible by 7"; } }; inline Matcher DivisibleBy7() { return MakeMatcher(new DivisibleBy7Matcher); } ... EXPECT_CALL(foo, Bar(DivisibleBy7())); ``` You may improve the matcher message by streaming additional information to the `listener` argument in `MatchAndExplain()`: ``` class DivisibleBy7Matcher : public MatcherInterface { public: virtual bool MatchAndExplain(int n, MatchResultListener* listener) const { const int remainder = n % 7; if (remainder != 0) { *listener << "the remainder is " << remainder; } return remainder == 0; } ... }; ``` Then, `EXPECT_THAT(x, DivisibleBy7());` may general a message like this: ``` Value of: x Expected: is divisible by 7 Actual: 23 (the remainder is 2) ``` ## Writing New Polymorphic Matchers ## You've learned how to write your own matchers in the previous recipe. Just one problem: a matcher created using `MakeMatcher()` only works for one particular type of arguments. If you want a _polymorphic_ matcher that works with arguments of several types (for instance, `Eq(x)` can be used to match a `value` as long as `value` == `x` compiles -- `value` and `x` don't have to share the same type), you can learn the trick from `"gmock/gmock-matchers.h"` but it's a bit involved. Fortunately, most of the time you can define a polymorphic matcher easily with the help of `MakePolymorphicMatcher()`. Here's how you can define `NotNull()` as an example: ``` using ::testing::MakePolymorphicMatcher; using ::testing::MatchResultListener; using ::testing::NotNull; using ::testing::PolymorphicMatcher; class NotNullMatcher { public: // To implement a polymorphic matcher, first define a COPYABLE class // that has three members MatchAndExplain(), DescribeTo(), and // DescribeNegationTo(), like the following. // In this example, we want to use NotNull() with any pointer, so // MatchAndExplain() accepts a pointer of any type as its first argument. // In general, you can define MatchAndExplain() as an ordinary method or // a method template, or even overload it. template bool MatchAndExplain(T* p, MatchResultListener* /* listener */) const { return p != NULL; } // Describes the property of a value matching this matcher. void DescribeTo(::std::ostream* os) const { *os << "is not NULL"; } // Describes the property of a value NOT matching this matcher. void DescribeNegationTo(::std::ostream* os) const { *os << "is NULL"; } }; // To construct a polymorphic matcher, pass an instance of the class // to MakePolymorphicMatcher(). Note the return type. inline PolymorphicMatcher NotNull() { return MakePolymorphicMatcher(NotNullMatcher()); } ... EXPECT_CALL(foo, Bar(NotNull())); // The argument must be a non-NULL pointer. ``` **Note:** Your polymorphic matcher class does **not** need to inherit from `MatcherInterface` or any other class, and its methods do **not** need to be virtual. Like in a monomorphic matcher, you may explain the match result by streaming additional information to the `listener` argument in `MatchAndExplain()`. ## Writing New Cardinalities ## A cardinality is used in `Times()` to tell Google Mock how many times you expect a call to occur. It doesn't have to be exact. For example, you can say `AtLeast(5)` or `Between(2, 4)`. If the built-in set of cardinalities doesn't suit you, you are free to define your own by implementing the following interface (in namespace `testing`): ``` class CardinalityInterface { public: virtual ~CardinalityInterface(); // Returns true iff call_count calls will satisfy this cardinality. virtual bool IsSatisfiedByCallCount(int call_count) const = 0; // Returns true iff call_count calls will saturate this cardinality. virtual bool IsSaturatedByCallCount(int call_count) const = 0; // Describes self to an ostream. virtual void DescribeTo(::std::ostream* os) const = 0; }; ``` For example, to specify that a call must occur even number of times, you can write ``` using ::testing::Cardinality; using ::testing::CardinalityInterface; using ::testing::MakeCardinality; class EvenNumberCardinality : public CardinalityInterface { public: virtual bool IsSatisfiedByCallCount(int call_count) const { return (call_count % 2) == 0; } virtual bool IsSaturatedByCallCount(int call_count) const { return false; } virtual void DescribeTo(::std::ostream* os) const { *os << "called even number of times"; } }; Cardinality EvenNumber() { return MakeCardinality(new EvenNumberCardinality); } ... EXPECT_CALL(foo, Bar(3)) .Times(EvenNumber()); ``` ## Writing New Actions Quickly ## If the built-in actions don't work for you, and you find it inconvenient to use `Invoke()`, you can use a macro from the `ACTION*` family to quickly define a new action that can be used in your code as if it's a built-in action. By writing ``` ACTION(name) { statements; } ``` in a namespace scope (i.e. not inside a class or function), you will define an action with the given name that executes the statements. The value returned by `statements` will be used as the return value of the action. Inside the statements, you can refer to the K-th (0-based) argument of the mock function as `argK`. For example: ``` ACTION(IncrementArg1) { return ++(*arg1); } ``` allows you to write ``` ... WillOnce(IncrementArg1()); ``` Note that you don't need to specify the types of the mock function arguments. Rest assured that your code is type-safe though: you'll get a compiler error if `*arg1` doesn't support the `++` operator, or if the type of `++(*arg1)` isn't compatible with the mock function's return type. Another example: ``` ACTION(Foo) { (*arg2)(5); Blah(); *arg1 = 0; return arg0; } ``` defines an action `Foo()` that invokes argument #2 (a function pointer) with 5, calls function `Blah()`, sets the value pointed to by argument #1 to 0, and returns argument #0. For more convenience and flexibility, you can also use the following pre-defined symbols in the body of `ACTION`: | `argK_type` | The type of the K-th (0-based) argument of the mock function | |:------------|:-------------------------------------------------------------| | `args` | All arguments of the mock function as a tuple | | `args_type` | The type of all arguments of the mock function as a tuple | | `return_type` | The return type of the mock function | | `function_type` | The type of the mock function | For example, when using an `ACTION` as a stub action for mock function: ``` int DoSomething(bool flag, int* ptr); ``` we have: | **Pre-defined Symbol** | **Is Bound To** | |:-----------------------|:----------------| | `arg0` | the value of `flag` | | `arg0_type` | the type `bool` | | `arg1` | the value of `ptr` | | `arg1_type` | the type `int*` | | `args` | the tuple `(flag, ptr)` | | `args_type` | the type `::testing::tuple` | | `return_type` | the type `int` | | `function_type` | the type `int(bool, int*)` | ## Writing New Parameterized Actions Quickly ## Sometimes you'll want to parameterize an action you define. For that we have another macro ``` ACTION_P(name, param) { statements; } ``` For example, ``` ACTION_P(Add, n) { return arg0 + n; } ``` will allow you to write ``` // Returns argument #0 + 5. ... WillOnce(Add(5)); ``` For convenience, we use the term _arguments_ for the values used to invoke the mock function, and the term _parameters_ for the values used to instantiate an action. Note that you don't need to provide the type of the parameter either. Suppose the parameter is named `param`, you can also use the Google-Mock-defined symbol `param_type` to refer to the type of the parameter as inferred by the compiler. For example, in the body of `ACTION_P(Add, n)` above, you can write `n_type` for the type of `n`. Google Mock also provides `ACTION_P2`, `ACTION_P3`, and etc to support multi-parameter actions. For example, ``` ACTION_P2(ReturnDistanceTo, x, y) { double dx = arg0 - x; double dy = arg1 - y; return sqrt(dx*dx + dy*dy); } ``` lets you write ``` ... WillOnce(ReturnDistanceTo(5.0, 26.5)); ``` You can view `ACTION` as a degenerated parameterized action where the number of parameters is 0. You can also easily define actions overloaded on the number of parameters: ``` ACTION_P(Plus, a) { ... } ACTION_P2(Plus, a, b) { ... } ``` ## Restricting the Type of an Argument or Parameter in an ACTION ## For maximum brevity and reusability, the `ACTION*` macros don't ask you to provide the types of the mock function arguments and the action parameters. Instead, we let the compiler infer the types for us. Sometimes, however, we may want to be more explicit about the types. There are several tricks to do that. For example: ``` ACTION(Foo) { // Makes sure arg0 can be converted to int. int n = arg0; ... use n instead of arg0 here ... } ACTION_P(Bar, param) { // Makes sure the type of arg1 is const char*. ::testing::StaticAssertTypeEq(); // Makes sure param can be converted to bool. bool flag = param; } ``` where `StaticAssertTypeEq` is a compile-time assertion in Google Test that verifies two types are the same. ## Writing New Action Templates Quickly ## Sometimes you want to give an action explicit template parameters that cannot be inferred from its value parameters. `ACTION_TEMPLATE()` supports that and can be viewed as an extension to `ACTION()` and `ACTION_P*()`. The syntax: ``` ACTION_TEMPLATE(ActionName, HAS_m_TEMPLATE_PARAMS(kind1, name1, ..., kind_m, name_m), AND_n_VALUE_PARAMS(p1, ..., p_n)) { statements; } ``` defines an action template that takes _m_ explicit template parameters and _n_ value parameters, where _m_ is between 1 and 10, and _n_ is between 0 and 10. `name_i` is the name of the i-th template parameter, and `kind_i` specifies whether it's a `typename`, an integral constant, or a template. `p_i` is the name of the i-th value parameter. Example: ``` // DuplicateArg(output) converts the k-th argument of the mock // function to type T and copies it to *output. ACTION_TEMPLATE(DuplicateArg, // Note the comma between int and k: HAS_2_TEMPLATE_PARAMS(int, k, typename, T), AND_1_VALUE_PARAMS(output)) { *output = T(::testing::get(args)); } ``` To create an instance of an action template, write: ``` ActionName(v1, ..., v_n) ``` where the `t`s are the template arguments and the `v`s are the value arguments. The value argument types are inferred by the compiler. For example: ``` using ::testing::_; ... int n; EXPECT_CALL(mock, Foo(_, _)) .WillOnce(DuplicateArg<1, unsigned char>(&n)); ``` If you want to explicitly specify the value argument types, you can provide additional template arguments: ``` ActionName(v1, ..., v_n) ``` where `u_i` is the desired type of `v_i`. `ACTION_TEMPLATE` and `ACTION`/`ACTION_P*` can be overloaded on the number of value parameters, but not on the number of template parameters. Without the restriction, the meaning of the following is unclear: ``` OverloadedAction(x); ``` Are we using a single-template-parameter action where `bool` refers to the type of `x`, or a two-template-parameter action where the compiler is asked to infer the type of `x`? ## Using the ACTION Object's Type ## If you are writing a function that returns an `ACTION` object, you'll need to know its type. The type depends on the macro used to define the action and the parameter types. The rule is relatively simple: | **Given Definition** | **Expression** | **Has Type** | |:---------------------|:---------------|:-------------| | `ACTION(Foo)` | `Foo()` | `FooAction` | | `ACTION_TEMPLATE(Foo, HAS_m_TEMPLATE_PARAMS(...), AND_0_VALUE_PARAMS())` | `Foo()` | `FooAction` | | `ACTION_P(Bar, param)` | `Bar(int_value)` | `BarActionP` | | `ACTION_TEMPLATE(Bar, HAS_m_TEMPLATE_PARAMS(...), AND_1_VALUE_PARAMS(p1))` | `Bar(int_value)` | `FooActionP` | | `ACTION_P2(Baz, p1, p2)` | `Baz(bool_value, int_value)` | `BazActionP2` | | `ACTION_TEMPLATE(Baz, HAS_m_TEMPLATE_PARAMS(...), AND_2_VALUE_PARAMS(p1, p2))` | `Baz(bool_value, int_value)` | `FooActionP2` | | ... | ... | ... | Note that we have to pick different suffixes (`Action`, `ActionP`, `ActionP2`, and etc) for actions with different numbers of value parameters, or the action definitions cannot be overloaded on the number of them. ## Writing New Monomorphic Actions ## While the `ACTION*` macros are very convenient, sometimes they are inappropriate. For example, despite the tricks shown in the previous recipes, they don't let you directly specify the types of the mock function arguments and the action parameters, which in general leads to unoptimized compiler error messages that can baffle unfamiliar users. They also don't allow overloading actions based on parameter types without jumping through some hoops. An alternative to the `ACTION*` macros is to implement `::testing::ActionInterface`, where `F` is the type of the mock function in which the action will be used. For example: ``` template class ActionInterface { public: virtual ~ActionInterface(); // Performs the action. Result is the return type of function type // F, and ArgumentTuple is the tuple of arguments of F. // // For example, if F is int(bool, const string&), then Result would // be int, and ArgumentTuple would be ::testing::tuple. virtual Result Perform(const ArgumentTuple& args) = 0; }; using ::testing::_; using ::testing::Action; using ::testing::ActionInterface; using ::testing::MakeAction; typedef int IncrementMethod(int*); class IncrementArgumentAction : public ActionInterface { public: virtual int Perform(const ::testing::tuple& args) { int* p = ::testing::get<0>(args); // Grabs the first argument. return *p++; } }; Action IncrementArgument() { return MakeAction(new IncrementArgumentAction); } ... EXPECT_CALL(foo, Baz(_)) .WillOnce(IncrementArgument()); int n = 5; foo.Baz(&n); // Should return 5 and change n to 6. ``` ## Writing New Polymorphic Actions ## The previous recipe showed you how to define your own action. This is all good, except that you need to know the type of the function in which the action will be used. Sometimes that can be a problem. For example, if you want to use the action in functions with _different_ types (e.g. like `Return()` and `SetArgPointee()`). If an action can be used in several types of mock functions, we say it's _polymorphic_. The `MakePolymorphicAction()` function template makes it easy to define such an action: ``` namespace testing { template PolymorphicAction MakePolymorphicAction(const Impl& impl); } // namespace testing ``` As an example, let's define an action that returns the second argument in the mock function's argument list. The first step is to define an implementation class: ``` class ReturnSecondArgumentAction { public: template Result Perform(const ArgumentTuple& args) const { // To get the i-th (0-based) argument, use ::testing::get(args). return ::testing::get<1>(args); } }; ``` This implementation class does _not_ need to inherit from any particular class. What matters is that it must have a `Perform()` method template. This method template takes the mock function's arguments as a tuple in a **single** argument, and returns the result of the action. It can be either `const` or not, but must be invokable with exactly one template argument, which is the result type. In other words, you must be able to call `Perform(args)` where `R` is the mock function's return type and `args` is its arguments in a tuple. Next, we use `MakePolymorphicAction()` to turn an instance of the implementation class into the polymorphic action we need. It will be convenient to have a wrapper for this: ``` using ::testing::MakePolymorphicAction; using ::testing::PolymorphicAction; PolymorphicAction ReturnSecondArgument() { return MakePolymorphicAction(ReturnSecondArgumentAction()); } ``` Now, you can use this polymorphic action the same way you use the built-in ones: ``` using ::testing::_; class MockFoo : public Foo { public: MOCK_METHOD2(DoThis, int(bool flag, int n)); MOCK_METHOD3(DoThat, string(int x, const char* str1, const char* str2)); }; ... MockFoo foo; EXPECT_CALL(foo, DoThis(_, _)) .WillOnce(ReturnSecondArgument()); EXPECT_CALL(foo, DoThat(_, _, _)) .WillOnce(ReturnSecondArgument()); ... foo.DoThis(true, 5); // Will return 5. foo.DoThat(1, "Hi", "Bye"); // Will return "Hi". ``` ## Teaching Google Mock How to Print Your Values ## When an uninteresting or unexpected call occurs, Google Mock prints the argument values and the stack trace to help you debug. Assertion macros like `EXPECT_THAT` and `EXPECT_EQ` also print the values in question when the assertion fails. Google Mock and Google Test do this using Google Test's user-extensible value printer. This printer knows how to print built-in C++ types, native arrays, STL containers, and any type that supports the `<<` operator. For other types, it prints the raw bytes in the value and hopes that you the user can figure it out. [Google Test's advanced guide](../../googletest/docs/AdvancedGuide.md#teaching-google-test-how-to-print-your-values) explains how to extend the printer to do a better job at printing your particular type than to dump the bytes. nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/docs/DesignDoc.md000066400000000000000000000233041455373415500257530ustar00rootroot00000000000000This page discusses the design of new Google Mock features. # Macros for Defining Actions # ## Problem ## Due to the lack of closures in C++, it currently requires some non-trivial effort to define a custom action in Google Mock. For example, suppose you want to "increment the value pointed to by the second argument of the mock function and return it", you could write: ``` int IncrementArg1(Unused, int* p, Unused) { return ++(*p); } ... WillOnce(Invoke(IncrementArg1)); ``` There are several things unsatisfactory about this approach: * Even though the action only cares about the second argument of the mock function, its definition needs to list other arguments as dummies. This is tedious. * The defined action is usable only in mock functions that takes exactly 3 arguments - an unnecessary restriction. * To use the action, one has to say `Invoke(IncrementArg1)`, which isn't as nice as `IncrementArg1()`. The latter two problems can be overcome using `MakePolymorphicAction()`, but it requires much more boilerplate code: ``` class IncrementArg1Action { public: template Result Perform(const ArgumentTuple& args) const { return ++(*tr1::get<1>(args)); } }; PolymorphicAction IncrementArg1() { return MakePolymorphicAction(IncrementArg1Action()); } ... WillOnce(IncrementArg1()); ``` Our goal is to allow defining custom actions with the least amount of boiler-plate C++ requires. ## Solution ## We propose to introduce a new macro: ``` ACTION(name) { statements; } ``` Using this in a namespace scope will define an action with the given name that executes the statements. Inside the statements, you can refer to the K-th (0-based) argument of the mock function as `argK`. For example: ``` ACTION(IncrementArg1) { return ++(*arg1); } ``` allows you to write ``` ... WillOnce(IncrementArg1()); ``` Note that you don't need to specify the types of the mock function arguments, as brevity is a top design goal here. Rest assured that your code is still type-safe though: you'll get a compiler error if `*arg1` doesn't support the `++` operator, or if the type of `++(*arg1)` isn't compatible with the mock function's return type. Another example: ``` ACTION(Foo) { (*arg2)(5); Blah(); *arg1 = 0; return arg0; } ``` defines an action `Foo()` that invokes argument #2 (a function pointer) with 5, calls function `Blah()`, sets the value pointed to by argument #1 to 0, and returns argument #0. For more convenience and flexibility, you can also use the following pre-defined symbols in the body of `ACTION`: | `argK_type` | The type of the K-th (0-based) argument of the mock function | |:------------|:-------------------------------------------------------------| | `args` | All arguments of the mock function as a tuple | | `args_type` | The type of all arguments of the mock function as a tuple | | `return_type` | The return type of the mock function | | `function_type` | The type of the mock function | For example, when using an `ACTION` as a stub action for mock function: ``` int DoSomething(bool flag, int* ptr); ``` we have: | **Pre-defined Symbol** | **Is Bound To** | |:-----------------------|:----------------| | `arg0` | the value of `flag` | | `arg0_type` | the type `bool` | | `arg1` | the value of `ptr` | | `arg1_type` | the type `int*` | | `args` | the tuple `(flag, ptr)` | | `args_type` | the type `std::tr1::tuple` | | `return_type` | the type `int` | | `function_type` | the type `int(bool, int*)` | ## Parameterized actions ## Sometimes you'll want to parameterize the action. For that we propose another macro ``` ACTION_P(name, param) { statements; } ``` For example, ``` ACTION_P(Add, n) { return arg0 + n; } ``` will allow you to write ``` // Returns argument #0 + 5. ... WillOnce(Add(5)); ``` For convenience, we use the term _arguments_ for the values used to invoke the mock function, and the term _parameters_ for the values used to instantiate an action. Note that you don't need to provide the type of the parameter either. Suppose the parameter is named `param`, you can also use the Google-Mock-defined symbol `param_type` to refer to the type of the parameter as inferred by the compiler. We will also provide `ACTION_P2`, `ACTION_P3`, and etc to support multi-parameter actions. For example, ``` ACTION_P2(ReturnDistanceTo, x, y) { double dx = arg0 - x; double dy = arg1 - y; return sqrt(dx*dx + dy*dy); } ``` lets you write ``` ... WillOnce(ReturnDistanceTo(5.0, 26.5)); ``` You can view `ACTION` as a degenerated parameterized action where the number of parameters is 0. ## Advanced Usages ## ### Overloading Actions ### You can easily define actions overloaded on the number of parameters: ``` ACTION_P(Plus, a) { ... } ACTION_P2(Plus, a, b) { ... } ``` ### Restricting the Type of an Argument or Parameter ### For maximum brevity and reusability, the `ACTION*` macros don't let you specify the types of the mock function arguments and the action parameters. Instead, we let the compiler infer the types for us. Sometimes, however, we may want to be more explicit about the types. There are several tricks to do that. For example: ``` ACTION(Foo) { // Makes sure arg0 can be converted to int. int n = arg0; ... use n instead of arg0 here ... } ACTION_P(Bar, param) { // Makes sure the type of arg1 is const char*. ::testing::StaticAssertTypeEq(); // Makes sure param can be converted to bool. bool flag = param; } ``` where `StaticAssertTypeEq` is a compile-time assertion we plan to add to Google Test (the name is chosen to match `static_assert` in C++0x). ### Using the ACTION Object's Type ### If you are writing a function that returns an `ACTION` object, you'll need to know its type. The type depends on the macro used to define the action and the parameter types. The rule is relatively simple: | **Given Definition** | **Expression** | **Has Type** | |:---------------------|:---------------|:-------------| | `ACTION(Foo)` | `Foo()` | `FooAction` | | `ACTION_P(Bar, param)` | `Bar(int_value)` | `BarActionP` | | `ACTION_P2(Baz, p1, p2)` | `Baz(bool_value, int_value)` | `BazActionP2` | | ... | ... | ... | Note that we have to pick different suffixes (`Action`, `ActionP`, `ActionP2`, and etc) for actions with different numbers of parameters, or the action definitions cannot be overloaded on the number of parameters. ## When to Use ## While the new macros are very convenient, please also consider other means of implementing actions (e.g. via `ActionInterface` or `MakePolymorphicAction()`), especially if you need to use the defined action a lot. While the other approaches require more work, they give you more control on the types of the mock function arguments and the action parameters, which in general leads to better compiler error messages that pay off in the long run. They also allow overloading actions based on parameter types, as opposed to just the number of parameters. ## Related Work ## As you may have realized, the `ACTION*` macros resemble closures (also known as lambda expressions or anonymous functions). Indeed, both of them seek to lower the syntactic overhead for defining a function. C++0x will support lambdas, but they are not part of C++ right now. Some non-standard libraries (most notably BLL or Boost Lambda Library) try to alleviate this problem. However, they are not a good choice for defining actions as: * They are non-standard and not widely installed. Google Mock only depends on standard libraries and `tr1::tuple`, which is part of the new C++ standard and comes with gcc 4+. We want to keep it that way. * They are not trivial to learn. * They will become obsolete when C++0x's lambda feature is widely supported. We don't want to make our users use a dying library. * Since they are based on operators, they are rather ad hoc: you cannot use statements, and you cannot pass the lambda arguments to a function, for example. * They have subtle semantics that easily confuses new users. For example, in expression `_1++ + foo++`, `foo` will be incremented only once where the expression is evaluated, while `_1` will be incremented every time the unnamed function is invoked. This is far from intuitive. `ACTION*` avoid all these problems. ## Future Improvements ## There may be a need for composing `ACTION*` definitions (i.e. invoking another `ACTION` inside the definition of one `ACTION*`). We are not sure we want it yet, as one can get a similar effect by putting `ACTION` definitions in function templates and composing the function templates. We'll revisit this based on user feedback. The reason we don't allow `ACTION*()` inside a function body is that the current C++ standard doesn't allow function-local types to be used to instantiate templates. The upcoming C++0x standard will lift this restriction. Once this feature is widely supported by compilers, we can revisit the implementation and add support for using `ACTION*()` inside a function. C++0x will also support lambda expressions. When they become available, we may want to support using lambdas as actions. # Macros for Defining Matchers # Once the macros for defining actions are implemented, we plan to do the same for matchers: ``` MATCHER(name) { statements; } ``` where you can refer to the value being matched as `arg`. For example, given: ``` MATCHER(IsPositive) { return arg > 0; } ``` you can use `IsPositive()` as a matcher that matches a value iff it is greater than 0. We will also add `MATCHER_P`, `MATCHER_P2`, and etc for parameterized matchers.nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/docs/DevGuide.md000066400000000000000000000162341455373415500256140ustar00rootroot00000000000000 If you are interested in understanding the internals of Google Mock, building from source, or contributing ideas or modifications to the project, then this document is for you. # Introduction # First, let's give you some background of the project. ## Licensing ## All Google Mock source and pre-built packages are provided under the [New BSD License](http://www.opensource.org/licenses/bsd-license.php). ## The Google Mock Community ## The Google Mock community exists primarily through the [discussion group](http://groups.google.com/group/googlemock), the [issue tracker](https://github.com/google/googletest/issues) and, to a lesser extent, the [source control repository](../). You are definitely encouraged to contribute to the discussion and you can also help us to keep the effectiveness of the group high by following and promoting the guidelines listed here. ### Please Be Friendly ### Showing courtesy and respect to others is a vital part of the Google culture, and we strongly encourage everyone participating in Google Mock development to join us in accepting nothing less. Of course, being courteous is not the same as failing to constructively disagree with each other, but it does mean that we should be respectful of each other when enumerating the 42 technical reasons that a particular proposal may not be the best choice. There's never a reason to be antagonistic or dismissive toward anyone who is sincerely trying to contribute to a discussion. Sure, C++ testing is serious business and all that, but it's also a lot of fun. Let's keep it that way. Let's strive to be one of the friendliest communities in all of open source. ### Where to Discuss Google Mock ### As always, discuss Google Mock in the official [Google C++ Mocking Framework discussion group](http://groups.google.com/group/googlemock). You don't have to actually submit code in order to sign up. Your participation itself is a valuable contribution. # Working with the Code # If you want to get your hands dirty with the code inside Google Mock, this is the section for you. ## Checking Out the Source from Subversion ## Checking out the Google Mock source is most useful if you plan to tweak it yourself. You check out the source for Google Mock using a [Subversion](http://subversion.tigris.org/) client as you would for any other project hosted on Google Code. Please see the instruction on the [source code access page](../) for how to do it. ## Compiling from Source ## Once you check out the code, you can find instructions on how to compile it in the [README](../README.md) file. ## Testing ## A mocking framework is of no good if itself is not thoroughly tested. Tests should be written for any new code, and changes should be verified to not break existing tests before they are submitted for review. To perform the tests, follow the instructions in [README](http://code.google.com/p/googlemock/source/browse/trunk/README) and verify that there are no failures. # Contributing Code # We are excited that Google Mock is now open source, and hope to get great patches from the community. Before you fire up your favorite IDE and begin hammering away at that new feature, though, please take the time to read this section and understand the process. While it seems rigorous, we want to keep a high standard of quality in the code base. ## Contributor License Agreements ## You must sign a Contributor License Agreement (CLA) before we can accept any code. The CLA protects you and us. * If you are an individual writing original source code and you're sure you own the intellectual property, then you'll need to sign an [individual CLA](http://code.google.com/legal/individual-cla-v1.0.html). * If you work for a company that wants to allow you to contribute your work to Google Mock, then you'll need to sign a [corporate CLA](http://code.google.com/legal/corporate-cla-v1.0.html). Follow either of the two links above to access the appropriate CLA and instructions for how to sign and return it. ## Coding Style ## To keep the source consistent, readable, diffable and easy to merge, we use a fairly rigid coding style, as defined by the [google-styleguide](https://github.com/google/styleguide) project. All patches will be expected to conform to the style outlined [here](https://github.com/google/styleguide/blob/gh-pages/cppguide.xml). ## Submitting Patches ## Please do submit code. Here's what you need to do: 1. Normally you should make your change against the SVN trunk instead of a branch or a tag, as the latter two are for release control and should be treated mostly as read-only. 1. Decide which code you want to submit. A submission should be a set of changes that addresses one issue in the [Google Mock issue tracker](http://code.google.com/p/googlemock/issues/list). Please don't mix more than one logical change per submittal, because it makes the history hard to follow. If you want to make a change that doesn't have a corresponding issue in the issue tracker, please create one. 1. Also, coordinate with team members that are listed on the issue in question. This ensures that work isn't being duplicated and communicating your plan early also generally leads to better patches. 1. Ensure that your code adheres to the [Google Mock source code style](#Coding_Style.md). 1. Ensure that there are unit tests for your code. 1. Sign a Contributor License Agreement. 1. Create a patch file using `svn diff`. 1. We use [Rietveld](http://codereview.appspot.com/) to do web-based code reviews. You can read about the tool [here](https://github.com/rietveld-codereview/rietveld/wiki). When you are ready, upload your patch via Rietveld and notify `googlemock@googlegroups.com` to review it. There are several ways to upload the patch. We recommend using the [upload\_gmock.py](../scripts/upload_gmock.py) script, which you can find in the `scripts/` folder in the SVN trunk. ## Google Mock Committers ## The current members of the Google Mock engineering team are the only committers at present. In the great tradition of eating one's own dogfood, we will be requiring each new Google Mock engineering team member to earn the right to become a committer by following the procedures in this document, writing consistently great code, and demonstrating repeatedly that he or she truly gets the zen of Google Mock. # Release Process # We follow the typical release process for Subversion-based projects: 1. A release branch named `release-X.Y` is created. 1. Bugs are fixed and features are added in trunk; those individual patches are merged into the release branch until it's stable. 1. An individual point release (the `Z` in `X.Y.Z`) is made by creating a tag from the branch. 1. Repeat steps 2 and 3 throughout one release cycle (as determined by features or time). 1. Go back to step 1 to create another release branch and so on. --- This page is based on the [Making GWT Better](http://code.google.com/webtoolkit/makinggwtbetter.html) guide from the [Google Web Toolkit](http://code.google.com/webtoolkit/) project. Except as otherwise [noted](http://code.google.com/policies.html#restrictions), the content of this page is licensed under the [Creative Commons Attribution 2.5 License](http://creativecommons.org/licenses/by/2.5/). nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/docs/Documentation.md000066400000000000000000000013761455373415500267320ustar00rootroot00000000000000This page lists all documentation wiki pages for Google Mock **(the SVN trunk version)** - **if you use a released version of Google Mock, please read the documentation for that specific version instead.** * [ForDummies](ForDummies.md) -- start here if you are new to Google Mock. * [CheatSheet](CheatSheet.md) -- a quick reference. * [CookBook](CookBook.md) -- recipes for doing various tasks using Google Mock. * [FrequentlyAskedQuestions](FrequentlyAskedQuestions.md) -- check here before asking a question on the mailing list. To contribute code to Google Mock, read: * [DevGuide](DevGuide.md) -- read this _before_ writing your first patch. * [Pump Manual](../googletest/docs/PumpManual.md) -- how we generate some of Google Mock's source files. nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/docs/ForDummies.md000066400000000000000000000725731455373415500262020ustar00rootroot00000000000000 (**Note:** If you get compiler errors that you don't understand, be sure to consult [Google Mock Doctor](FrequentlyAskedQuestions.md#how-am-i-supposed-to-make-sense-of-these-horrible-template-errors).) # What Is Google C++ Mocking Framework? # When you write a prototype or test, often it's not feasible or wise to rely on real objects entirely. A **mock object** implements the same interface as a real object (so it can be used as one), but lets you specify at run time how it will be used and what it should do (which methods will be called? in which order? how many times? with what arguments? what will they return? etc). **Note:** It is easy to confuse the term _fake objects_ with mock objects. Fakes and mocks actually mean very different things in the Test-Driven Development (TDD) community: * **Fake** objects have working implementations, but usually take some shortcut (perhaps to make the operations less expensive), which makes them not suitable for production. An in-memory file system would be an example of a fake. * **Mocks** are objects pre-programmed with _expectations_, which form a specification of the calls they are expected to receive. If all this seems too abstract for you, don't worry - the most important thing to remember is that a mock allows you to check the _interaction_ between itself and code that uses it. The difference between fakes and mocks will become much clearer once you start to use mocks. **Google C++ Mocking Framework** (or **Google Mock** for short) is a library (sometimes we also call it a "framework" to make it sound cool) for creating mock classes and using them. It does to C++ what [jMock](http://www.jmock.org/) and [EasyMock](http://www.easymock.org/) do to Java. Using Google Mock involves three basic steps: 1. Use some simple macros to describe the interface you want to mock, and they will expand to the implementation of your mock class; 1. Create some mock objects and specify its expectations and behavior using an intuitive syntax; 1. Exercise code that uses the mock objects. Google Mock will catch any violation of the expectations as soon as it arises. # Why Google Mock? # While mock objects help you remove unnecessary dependencies in tests and make them fast and reliable, using mocks manually in C++ is _hard_: * Someone has to implement the mocks. The job is usually tedious and error-prone. No wonder people go great distance to avoid it. * The quality of those manually written mocks is a bit, uh, unpredictable. You may see some really polished ones, but you may also see some that were hacked up in a hurry and have all sorts of ad hoc restrictions. * The knowledge you gained from using one mock doesn't transfer to the next. In contrast, Java and Python programmers have some fine mock frameworks, which automate the creation of mocks. As a result, mocking is a proven effective technique and widely adopted practice in those communities. Having the right tool absolutely makes the difference. Google Mock was built to help C++ programmers. It was inspired by [jMock](http://www.jmock.org/) and [EasyMock](http://www.easymock.org/), but designed with C++'s specifics in mind. It is your friend if any of the following problems is bothering you: * You are stuck with a sub-optimal design and wish you had done more prototyping before it was too late, but prototyping in C++ is by no means "rapid". * Your tests are slow as they depend on too many libraries or use expensive resources (e.g. a database). * Your tests are brittle as some resources they use are unreliable (e.g. the network). * You want to test how your code handles a failure (e.g. a file checksum error), but it's not easy to cause one. * You need to make sure that your module interacts with other modules in the right way, but it's hard to observe the interaction; therefore you resort to observing the side effects at the end of the action, which is awkward at best. * You want to "mock out" your dependencies, except that they don't have mock implementations yet; and, frankly, you aren't thrilled by some of those hand-written mocks. We encourage you to use Google Mock as: * a _design_ tool, for it lets you experiment with your interface design early and often. More iterations lead to better designs! * a _testing_ tool to cut your tests' outbound dependencies and probe the interaction between your module and its collaborators. # Getting Started # Using Google Mock is easy! Inside your C++ source file, just `#include` `"gtest/gtest.h"` and `"gmock/gmock.h"`, and you are ready to go. # A Case for Mock Turtles # Let's look at an example. Suppose you are developing a graphics program that relies on a LOGO-like API for drawing. How would you test that it does the right thing? Well, you can run it and compare the screen with a golden screen snapshot, but let's admit it: tests like this are expensive to run and fragile (What if you just upgraded to a shiny new graphics card that has better anti-aliasing? Suddenly you have to update all your golden images.). It would be too painful if all your tests are like this. Fortunately, you learned about Dependency Injection and know the right thing to do: instead of having your application talk to the drawing API directly, wrap the API in an interface (say, `Turtle`) and code to that interface: ``` class Turtle { ... virtual ~Turtle() {} virtual void PenUp() = 0; virtual void PenDown() = 0; virtual void Forward(int distance) = 0; virtual void Turn(int degrees) = 0; virtual void GoTo(int x, int y) = 0; virtual int GetX() const = 0; virtual int GetY() const = 0; }; ``` (Note that the destructor of `Turtle` **must** be virtual, as is the case for **all** classes you intend to inherit from - otherwise the destructor of the derived class will not be called when you delete an object through a base pointer, and you'll get corrupted program states like memory leaks.) You can control whether the turtle's movement will leave a trace using `PenUp()` and `PenDown()`, and control its movement using `Forward()`, `Turn()`, and `GoTo()`. Finally, `GetX()` and `GetY()` tell you the current position of the turtle. Your program will normally use a real implementation of this interface. In tests, you can use a mock implementation instead. This allows you to easily check what drawing primitives your program is calling, with what arguments, and in which order. Tests written this way are much more robust (they won't break because your new machine does anti-aliasing differently), easier to read and maintain (the intent of a test is expressed in the code, not in some binary images), and run _much, much faster_. # Writing the Mock Class # If you are lucky, the mocks you need to use have already been implemented by some nice people. If, however, you find yourself in the position to write a mock class, relax - Google Mock turns this task into a fun game! (Well, almost.) ## How to Define It ## Using the `Turtle` interface as example, here are the simple steps you need to follow: 1. Derive a class `MockTurtle` from `Turtle`. 1. Take a _virtual_ function of `Turtle` (while it's possible to [mock non-virtual methods using templates](CookBook.md#mocking-nonvirtual-methods), it's much more involved). Count how many arguments it has. 1. In the `public:` section of the child class, write `MOCK_METHODn();` (or `MOCK_CONST_METHODn();` if you are mocking a `const` method), where `n` is the number of the arguments; if you counted wrong, shame on you, and a compiler error will tell you so. 1. Now comes the fun part: you take the function signature, cut-and-paste the _function name_ as the _first_ argument to the macro, and leave what's left as the _second_ argument (in case you're curious, this is the _type of the function_). 1. Repeat until all virtual functions you want to mock are done. After the process, you should have something like: ``` #include "gmock/gmock.h" // Brings in Google Mock. class MockTurtle : public Turtle { public: ... MOCK_METHOD0(PenUp, void()); MOCK_METHOD0(PenDown, void()); MOCK_METHOD1(Forward, void(int distance)); MOCK_METHOD1(Turn, void(int degrees)); MOCK_METHOD2(GoTo, void(int x, int y)); MOCK_CONST_METHOD0(GetX, int()); MOCK_CONST_METHOD0(GetY, int()); }; ``` You don't need to define these mock methods somewhere else - the `MOCK_METHOD*` macros will generate the definitions for you. It's that simple! Once you get the hang of it, you can pump out mock classes faster than your source-control system can handle your check-ins. **Tip:** If even this is too much work for you, you'll find the `gmock_gen.py` tool in Google Mock's `scripts/generator/` directory (courtesy of the [cppclean](http://code.google.com/p/cppclean/) project) useful. This command-line tool requires that you have Python 2.4 installed. You give it a C++ file and the name of an abstract class defined in it, and it will print the definition of the mock class for you. Due to the complexity of the C++ language, this script may not always work, but it can be quite handy when it does. For more details, read the [user documentation](../scripts/generator/README). ## Where to Put It ## When you define a mock class, you need to decide where to put its definition. Some people put it in a `*_test.cc`. This is fine when the interface being mocked (say, `Foo`) is owned by the same person or team. Otherwise, when the owner of `Foo` changes it, your test could break. (You can't really expect `Foo`'s maintainer to fix every test that uses `Foo`, can you?) So, the rule of thumb is: if you need to mock `Foo` and it's owned by others, define the mock class in `Foo`'s package (better, in a `testing` sub-package such that you can clearly separate production code and testing utilities), and put it in a `mock_foo.h`. Then everyone can reference `mock_foo.h` from their tests. If `Foo` ever changes, there is only one copy of `MockFoo` to change, and only tests that depend on the changed methods need to be fixed. Another way to do it: you can introduce a thin layer `FooAdaptor` on top of `Foo` and code to this new interface. Since you own `FooAdaptor`, you can absorb changes in `Foo` much more easily. While this is more work initially, carefully choosing the adaptor interface can make your code easier to write and more readable (a net win in the long run), as you can choose `FooAdaptor` to fit your specific domain much better than `Foo` does. # Using Mocks in Tests # Once you have a mock class, using it is easy. The typical work flow is: 1. Import the Google Mock names from the `testing` namespace such that you can use them unqualified (You only have to do it once per file. Remember that namespaces are a good idea and good for your health.). 1. Create some mock objects. 1. Specify your expectations on them (How many times will a method be called? With what arguments? What should it do? etc.). 1. Exercise some code that uses the mocks; optionally, check the result using Google Test assertions. If a mock method is called more than expected or with wrong arguments, you'll get an error immediately. 1. When a mock is destructed, Google Mock will automatically check whether all expectations on it have been satisfied. Here's an example: ``` #include "path/to/mock-turtle.h" #include "gmock/gmock.h" #include "gtest/gtest.h" using ::testing::AtLeast; // #1 TEST(PainterTest, CanDrawSomething) { MockTurtle turtle; // #2 EXPECT_CALL(turtle, PenDown()) // #3 .Times(AtLeast(1)); Painter painter(&turtle); // #4 EXPECT_TRUE(painter.DrawCircle(0, 0, 10)); } // #5 int main(int argc, char** argv) { // The following line must be executed to initialize Google Mock // (and Google Test) before running the tests. ::testing::InitGoogleMock(&argc, argv); return RUN_ALL_TESTS(); } ``` As you might have guessed, this test checks that `PenDown()` is called at least once. If the `painter` object didn't call this method, your test will fail with a message like this: ``` path/to/my_test.cc:119: Failure Actual function call count doesn't match this expectation: Actually: never called; Expected: called at least once. ``` **Tip 1:** If you run the test from an Emacs buffer, you can hit `` on the line number displayed in the error message to jump right to the failed expectation. **Tip 2:** If your mock objects are never deleted, the final verification won't happen. Therefore it's a good idea to use a heap leak checker in your tests when you allocate mocks on the heap. **Important note:** Google Mock requires expectations to be set **before** the mock functions are called, otherwise the behavior is **undefined**. In particular, you mustn't interleave `EXPECT_CALL()`s and calls to the mock functions. This means `EXPECT_CALL()` should be read as expecting that a call will occur _in the future_, not that a call has occurred. Why does Google Mock work like that? Well, specifying the expectation beforehand allows Google Mock to report a violation as soon as it arises, when the context (stack trace, etc) is still available. This makes debugging much easier. Admittedly, this test is contrived and doesn't do much. You can easily achieve the same effect without using Google Mock. However, as we shall reveal soon, Google Mock allows you to do _much more_ with the mocks. ## Using Google Mock with Any Testing Framework ## If you want to use something other than Google Test (e.g. [CppUnit](http://sourceforge.net/projects/cppunit/) or [CxxTest](http://cxxtest.tigris.org/)) as your testing framework, just change the `main()` function in the previous section to: ``` int main(int argc, char** argv) { // The following line causes Google Mock to throw an exception on failure, // which will be interpreted by your testing framework as a test failure. ::testing::GTEST_FLAG(throw_on_failure) = true; ::testing::InitGoogleMock(&argc, argv); ... whatever your testing framework requires ... } ``` This approach has a catch: it makes Google Mock throw an exception from a mock object's destructor sometimes. With some compilers, this sometimes causes the test program to crash. You'll still be able to notice that the test has failed, but it's not a graceful failure. A better solution is to use Google Test's [event listener API](../../googletest/docs/AdvancedGuide.md#extending-google-test-by-handling-test-events) to report a test failure to your testing framework properly. You'll need to implement the `OnTestPartResult()` method of the event listener interface, but it should be straightforward. If this turns out to be too much work, we suggest that you stick with Google Test, which works with Google Mock seamlessly (in fact, it is technically part of Google Mock.). If there is a reason that you cannot use Google Test, please let us know. # Setting Expectations # The key to using a mock object successfully is to set the _right expectations_ on it. If you set the expectations too strict, your test will fail as the result of unrelated changes. If you set them too loose, bugs can slip through. You want to do it just right such that your test can catch exactly the kind of bugs you intend it to catch. Google Mock provides the necessary means for you to do it "just right." ## General Syntax ## In Google Mock we use the `EXPECT_CALL()` macro to set an expectation on a mock method. The general syntax is: ``` EXPECT_CALL(mock_object, method(matchers)) .Times(cardinality) .WillOnce(action) .WillRepeatedly(action); ``` The macro has two arguments: first the mock object, and then the method and its arguments. Note that the two are separated by a comma (`,`), not a period (`.`). (Why using a comma? The answer is that it was necessary for technical reasons.) The macro can be followed by some optional _clauses_ that provide more information about the expectation. We'll discuss how each clause works in the coming sections. This syntax is designed to make an expectation read like English. For example, you can probably guess that ``` using ::testing::Return;... EXPECT_CALL(turtle, GetX()) .Times(5) .WillOnce(Return(100)) .WillOnce(Return(150)) .WillRepeatedly(Return(200)); ``` says that the `turtle` object's `GetX()` method will be called five times, it will return 100 the first time, 150 the second time, and then 200 every time. Some people like to call this style of syntax a Domain-Specific Language (DSL). **Note:** Why do we use a macro to do this? It serves two purposes: first it makes expectations easily identifiable (either by `grep` or by a human reader), and second it allows Google Mock to include the source file location of a failed expectation in messages, making debugging easier. ## Matchers: What Arguments Do We Expect? ## When a mock function takes arguments, we must specify what arguments we are expecting; for example: ``` // Expects the turtle to move forward by 100 units. EXPECT_CALL(turtle, Forward(100)); ``` Sometimes you may not want to be too specific (Remember that talk about tests being too rigid? Over specification leads to brittle tests and obscures the intent of tests. Therefore we encourage you to specify only what's necessary - no more, no less.). If you care to check that `Forward()` will be called but aren't interested in its actual argument, write `_` as the argument, which means "anything goes": ``` using ::testing::_; ... // Expects the turtle to move forward. EXPECT_CALL(turtle, Forward(_)); ``` `_` is an instance of what we call **matchers**. A matcher is like a predicate and can test whether an argument is what we'd expect. You can use a matcher inside `EXPECT_CALL()` wherever a function argument is expected. A list of built-in matchers can be found in the [CheatSheet](CheatSheet.md). For example, here's the `Ge` (greater than or equal) matcher: ``` using ::testing::Ge;... EXPECT_CALL(turtle, Forward(Ge(100))); ``` This checks that the turtle will be told to go forward by at least 100 units. ## Cardinalities: How Many Times Will It Be Called? ## The first clause we can specify following an `EXPECT_CALL()` is `Times()`. We call its argument a **cardinality** as it tells _how many times_ the call should occur. It allows us to repeat an expectation many times without actually writing it as many times. More importantly, a cardinality can be "fuzzy", just like a matcher can be. This allows a user to express the intent of a test exactly. An interesting special case is when we say `Times(0)`. You may have guessed - it means that the function shouldn't be called with the given arguments at all, and Google Mock will report a Google Test failure whenever the function is (wrongfully) called. We've seen `AtLeast(n)` as an example of fuzzy cardinalities earlier. For the list of built-in cardinalities you can use, see the [CheatSheet](CheatSheet.md). The `Times()` clause can be omitted. **If you omit `Times()`, Google Mock will infer the cardinality for you.** The rules are easy to remember: * If **neither** `WillOnce()` **nor** `WillRepeatedly()` is in the `EXPECT_CALL()`, the inferred cardinality is `Times(1)`. * If there are `n WillOnce()`'s but **no** `WillRepeatedly()`, where `n` >= 1, the cardinality is `Times(n)`. * If there are `n WillOnce()`'s and **one** `WillRepeatedly()`, where `n` >= 0, the cardinality is `Times(AtLeast(n))`. **Quick quiz:** what do you think will happen if a function is expected to be called twice but actually called four times? ## Actions: What Should It Do? ## Remember that a mock object doesn't really have a working implementation? We as users have to tell it what to do when a method is invoked. This is easy in Google Mock. First, if the return type of a mock function is a built-in type or a pointer, the function has a **default action** (a `void` function will just return, a `bool` function will return `false`, and other functions will return 0). In addition, in C++ 11 and above, a mock function whose return type is default-constructible (i.e. has a default constructor) has a default action of returning a default-constructed value. If you don't say anything, this behavior will be used. Second, if a mock function doesn't have a default action, or the default action doesn't suit you, you can specify the action to be taken each time the expectation matches using a series of `WillOnce()` clauses followed by an optional `WillRepeatedly()`. For example, ``` using ::testing::Return;... EXPECT_CALL(turtle, GetX()) .WillOnce(Return(100)) .WillOnce(Return(200)) .WillOnce(Return(300)); ``` This says that `turtle.GetX()` will be called _exactly three times_ (Google Mock inferred this from how many `WillOnce()` clauses we've written, since we didn't explicitly write `Times()`), and will return 100, 200, and 300 respectively. ``` using ::testing::Return;... EXPECT_CALL(turtle, GetY()) .WillOnce(Return(100)) .WillOnce(Return(200)) .WillRepeatedly(Return(300)); ``` says that `turtle.GetY()` will be called _at least twice_ (Google Mock knows this as we've written two `WillOnce()` clauses and a `WillRepeatedly()` while having no explicit `Times()`), will return 100 the first time, 200 the second time, and 300 from the third time on. Of course, if you explicitly write a `Times()`, Google Mock will not try to infer the cardinality itself. What if the number you specified is larger than there are `WillOnce()` clauses? Well, after all `WillOnce()`s are used up, Google Mock will do the _default_ action for the function every time (unless, of course, you have a `WillRepeatedly()`.). What can we do inside `WillOnce()` besides `Return()`? You can return a reference using `ReturnRef(variable)`, or invoke a pre-defined function, among [others](CheatSheet.md#actions). **Important note:** The `EXPECT_CALL()` statement evaluates the action clause only once, even though the action may be performed many times. Therefore you must be careful about side effects. The following may not do what you want: ``` int n = 100; EXPECT_CALL(turtle, GetX()) .Times(4) .WillRepeatedly(Return(n++)); ``` Instead of returning 100, 101, 102, ..., consecutively, this mock function will always return 100 as `n++` is only evaluated once. Similarly, `Return(new Foo)` will create a new `Foo` object when the `EXPECT_CALL()` is executed, and will return the same pointer every time. If you want the side effect to happen every time, you need to define a custom action, which we'll teach in the [CookBook](CookBook.md). Time for another quiz! What do you think the following means? ``` using ::testing::Return;... EXPECT_CALL(turtle, GetY()) .Times(4) .WillOnce(Return(100)); ``` Obviously `turtle.GetY()` is expected to be called four times. But if you think it will return 100 every time, think twice! Remember that one `WillOnce()` clause will be consumed each time the function is invoked and the default action will be taken afterwards. So the right answer is that `turtle.GetY()` will return 100 the first time, but **return 0 from the second time on**, as returning 0 is the default action for `int` functions. ## Using Multiple Expectations ## So far we've only shown examples where you have a single expectation. More realistically, you're going to specify expectations on multiple mock methods, which may be from multiple mock objects. By default, when a mock method is invoked, Google Mock will search the expectations in the **reverse order** they are defined, and stop when an active expectation that matches the arguments is found (you can think of it as "newer rules override older ones."). If the matching expectation cannot take any more calls, you will get an upper-bound-violated failure. Here's an example: ``` using ::testing::_;... EXPECT_CALL(turtle, Forward(_)); // #1 EXPECT_CALL(turtle, Forward(10)) // #2 .Times(2); ``` If `Forward(10)` is called three times in a row, the third time it will be an error, as the last matching expectation (#2) has been saturated. If, however, the third `Forward(10)` call is replaced by `Forward(20)`, then it would be OK, as now #1 will be the matching expectation. **Side note:** Why does Google Mock search for a match in the _reverse_ order of the expectations? The reason is that this allows a user to set up the default expectations in a mock object's constructor or the test fixture's set-up phase and then customize the mock by writing more specific expectations in the test body. So, if you have two expectations on the same method, you want to put the one with more specific matchers **after** the other, or the more specific rule would be shadowed by the more general one that comes after it. ## Ordered vs Unordered Calls ## By default, an expectation can match a call even though an earlier expectation hasn't been satisfied. In other words, the calls don't have to occur in the order the expectations are specified. Sometimes, you may want all the expected calls to occur in a strict order. To say this in Google Mock is easy: ``` using ::testing::InSequence;... TEST(FooTest, DrawsLineSegment) { ... { InSequence dummy; EXPECT_CALL(turtle, PenDown()); EXPECT_CALL(turtle, Forward(100)); EXPECT_CALL(turtle, PenUp()); } Foo(); } ``` By creating an object of type `InSequence`, all expectations in its scope are put into a _sequence_ and have to occur _sequentially_. Since we are just relying on the constructor and destructor of this object to do the actual work, its name is really irrelevant. In this example, we test that `Foo()` calls the three expected functions in the order as written. If a call is made out-of-order, it will be an error. (What if you care about the relative order of some of the calls, but not all of them? Can you specify an arbitrary partial order? The answer is ... yes! If you are impatient, the details can be found in the [CookBook](CookBook#Expecting_Partially_Ordered_Calls.md).) ## All Expectations Are Sticky (Unless Said Otherwise) ## Now let's do a quick quiz to see how well you can use this mock stuff already. How would you test that the turtle is asked to go to the origin _exactly twice_ (you want to ignore any other instructions it receives)? After you've come up with your answer, take a look at ours and compare notes (solve it yourself first - don't cheat!): ``` using ::testing::_;... EXPECT_CALL(turtle, GoTo(_, _)) // #1 .Times(AnyNumber()); EXPECT_CALL(turtle, GoTo(0, 0)) // #2 .Times(2); ``` Suppose `turtle.GoTo(0, 0)` is called three times. In the third time, Google Mock will see that the arguments match expectation #2 (remember that we always pick the last matching expectation). Now, since we said that there should be only two such calls, Google Mock will report an error immediately. This is basically what we've told you in the "Using Multiple Expectations" section above. This example shows that **expectations in Google Mock are "sticky" by default**, in the sense that they remain active even after we have reached their invocation upper bounds. This is an important rule to remember, as it affects the meaning of the spec, and is **different** to how it's done in many other mocking frameworks (Why'd we do that? Because we think our rule makes the common cases easier to express and understand.). Simple? Let's see if you've really understood it: what does the following code say? ``` using ::testing::Return; ... for (int i = n; i > 0; i--) { EXPECT_CALL(turtle, GetX()) .WillOnce(Return(10*i)); } ``` If you think it says that `turtle.GetX()` will be called `n` times and will return 10, 20, 30, ..., consecutively, think twice! The problem is that, as we said, expectations are sticky. So, the second time `turtle.GetX()` is called, the last (latest) `EXPECT_CALL()` statement will match, and will immediately lead to an "upper bound exceeded" error - this piece of code is not very useful! One correct way of saying that `turtle.GetX()` will return 10, 20, 30, ..., is to explicitly say that the expectations are _not_ sticky. In other words, they should _retire_ as soon as they are saturated: ``` using ::testing::Return; ... for (int i = n; i > 0; i--) { EXPECT_CALL(turtle, GetX()) .WillOnce(Return(10*i)) .RetiresOnSaturation(); } ``` And, there's a better way to do it: in this case, we expect the calls to occur in a specific order, and we line up the actions to match the order. Since the order is important here, we should make it explicit using a sequence: ``` using ::testing::InSequence; using ::testing::Return; ... { InSequence s; for (int i = 1; i <= n; i++) { EXPECT_CALL(turtle, GetX()) .WillOnce(Return(10*i)) .RetiresOnSaturation(); } } ``` By the way, the other situation where an expectation may _not_ be sticky is when it's in a sequence - as soon as another expectation that comes after it in the sequence has been used, it automatically retires (and will never be used to match any call). ## Uninteresting Calls ## A mock object may have many methods, and not all of them are that interesting. For example, in some tests we may not care about how many times `GetX()` and `GetY()` get called. In Google Mock, if you are not interested in a method, just don't say anything about it. If a call to this method occurs, you'll see a warning in the test output, but it won't be a failure. # What Now? # Congratulations! You've learned enough about Google Mock to start using it. Now, you might want to join the [googlemock](http://groups.google.com/group/googlemock) discussion group and actually write some tests using Google Mock - it will be fun. Hey, it may even be addictive - you've been warned. Then, if you feel like increasing your mock quotient, you should move on to the [CookBook](CookBook.md). You can learn many advanced features of Google Mock there -- and advance your level of enjoyment and testing bliss. nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/docs/FrequentlyAskedQuestions.md000066400000000000000000000555221455373415500311440ustar00rootroot00000000000000 Please send your questions to the [googlemock](http://groups.google.com/group/googlemock) discussion group. If you need help with compiler errors, make sure you have tried [Google Mock Doctor](#How_am_I_supposed_to_make_sense_of_these_horrible_template_error.md) first. ## When I call a method on my mock object, the method for the real object is invoked instead. What's the problem? ## In order for a method to be mocked, it must be _virtual_, unless you use the [high-perf dependency injection technique](CookBook.md#mocking-nonvirtual-methods). ## I wrote some matchers. After I upgraded to a new version of Google Mock, they no longer compile. What's going on? ## After version 1.4.0 of Google Mock was released, we had an idea on how to make it easier to write matchers that can generate informative messages efficiently. We experimented with this idea and liked what we saw. Therefore we decided to implement it. Unfortunately, this means that if you have defined your own matchers by implementing `MatcherInterface` or using `MakePolymorphicMatcher()`, your definitions will no longer compile. Matchers defined using the `MATCHER*` family of macros are not affected. Sorry for the hassle if your matchers are affected. We believe it's in everyone's long-term interest to make this change sooner than later. Fortunately, it's usually not hard to migrate an existing matcher to the new API. Here's what you need to do: If you wrote your matcher like this: ``` // Old matcher definition that doesn't work with the latest // Google Mock. using ::testing::MatcherInterface; ... class MyWonderfulMatcher : public MatcherInterface { public: ... virtual bool Matches(MyType value) const { // Returns true if value matches. return value.GetFoo() > 5; } ... }; ``` you'll need to change it to: ``` // New matcher definition that works with the latest Google Mock. using ::testing::MatcherInterface; using ::testing::MatchResultListener; ... class MyWonderfulMatcher : public MatcherInterface { public: ... virtual bool MatchAndExplain(MyType value, MatchResultListener* listener) const { // Returns true if value matches. return value.GetFoo() > 5; } ... }; ``` (i.e. rename `Matches()` to `MatchAndExplain()` and give it a second argument of type `MatchResultListener*`.) If you were also using `ExplainMatchResultTo()` to improve the matcher message: ``` // Old matcher definition that doesn't work with the lastest // Google Mock. using ::testing::MatcherInterface; ... class MyWonderfulMatcher : public MatcherInterface { public: ... virtual bool Matches(MyType value) const { // Returns true if value matches. return value.GetFoo() > 5; } virtual void ExplainMatchResultTo(MyType value, ::std::ostream* os) const { // Prints some helpful information to os to help // a user understand why value matches (or doesn't match). *os << "the Foo property is " << value.GetFoo(); } ... }; ``` you should move the logic of `ExplainMatchResultTo()` into `MatchAndExplain()`, using the `MatchResultListener` argument where the `::std::ostream` was used: ``` // New matcher definition that works with the latest Google Mock. using ::testing::MatcherInterface; using ::testing::MatchResultListener; ... class MyWonderfulMatcher : public MatcherInterface { public: ... virtual bool MatchAndExplain(MyType value, MatchResultListener* listener) const { // Returns true if value matches. *listener << "the Foo property is " << value.GetFoo(); return value.GetFoo() > 5; } ... }; ``` If your matcher is defined using `MakePolymorphicMatcher()`: ``` // Old matcher definition that doesn't work with the latest // Google Mock. using ::testing::MakePolymorphicMatcher; ... class MyGreatMatcher { public: ... bool Matches(MyType value) const { // Returns true if value matches. return value.GetBar() < 42; } ... }; ... MakePolymorphicMatcher(MyGreatMatcher()) ... ``` you should rename the `Matches()` method to `MatchAndExplain()` and add a `MatchResultListener*` argument (the same as what you need to do for matchers defined by implementing `MatcherInterface`): ``` // New matcher definition that works with the latest Google Mock. using ::testing::MakePolymorphicMatcher; using ::testing::MatchResultListener; ... class MyGreatMatcher { public: ... bool MatchAndExplain(MyType value, MatchResultListener* listener) const { // Returns true if value matches. return value.GetBar() < 42; } ... }; ... MakePolymorphicMatcher(MyGreatMatcher()) ... ``` If your polymorphic matcher uses `ExplainMatchResultTo()` for better failure messages: ``` // Old matcher definition that doesn't work with the latest // Google Mock. using ::testing::MakePolymorphicMatcher; ... class MyGreatMatcher { public: ... bool Matches(MyType value) const { // Returns true if value matches. return value.GetBar() < 42; } ... }; void ExplainMatchResultTo(const MyGreatMatcher& matcher, MyType value, ::std::ostream* os) { // Prints some helpful information to os to help // a user understand why value matches (or doesn't match). *os << "the Bar property is " << value.GetBar(); } ... MakePolymorphicMatcher(MyGreatMatcher()) ... ``` you'll need to move the logic inside `ExplainMatchResultTo()` to `MatchAndExplain()`: ``` // New matcher definition that works with the latest Google Mock. using ::testing::MakePolymorphicMatcher; using ::testing::MatchResultListener; ... class MyGreatMatcher { public: ... bool MatchAndExplain(MyType value, MatchResultListener* listener) const { // Returns true if value matches. *listener << "the Bar property is " << value.GetBar(); return value.GetBar() < 42; } ... }; ... MakePolymorphicMatcher(MyGreatMatcher()) ... ``` For more information, you can read these [two](CookBook.md#writing-new-monomorphic-matchers) [recipes](CookBook.md#writing-new-polymorphic-matchers) from the cookbook. As always, you are welcome to post questions on `googlemock@googlegroups.com` if you need any help. ## When using Google Mock, do I have to use Google Test as the testing framework? I have my favorite testing framework and don't want to switch. ## Google Mock works out of the box with Google Test. However, it's easy to configure it to work with any testing framework of your choice. [Here](ForDummies.md#using-google-mock-with-any-testing-framework) is how. ## How am I supposed to make sense of these horrible template errors? ## If you are confused by the compiler errors gcc threw at you, try consulting the _Google Mock Doctor_ tool first. What it does is to scan stdin for gcc error messages, and spit out diagnoses on the problems (we call them diseases) your code has. To "install", run command: ``` alias gmd='/scripts/gmock_doctor.py' ``` To use it, do: ``` 2>&1 | gmd ``` For example: ``` make my_test 2>&1 | gmd ``` Or you can run `gmd` and copy-n-paste gcc's error messages to it. ## Can I mock a variadic function? ## You cannot mock a variadic function (i.e. a function taking ellipsis (`...`) arguments) directly in Google Mock. The problem is that in general, there is _no way_ for a mock object to know how many arguments are passed to the variadic method, and what the arguments' types are. Only the _author of the base class_ knows the protocol, and we cannot look into his head. Therefore, to mock such a function, the _user_ must teach the mock object how to figure out the number of arguments and their types. One way to do it is to provide overloaded versions of the function. Ellipsis arguments are inherited from C and not really a C++ feature. They are unsafe to use and don't work with arguments that have constructors or destructors. Therefore we recommend to avoid them in C++ as much as possible. ## MSVC gives me warning C4301 or C4373 when I define a mock method with a const parameter. Why? ## If you compile this using Microsoft Visual C++ 2005 SP1: ``` class Foo { ... virtual void Bar(const int i) = 0; }; class MockFoo : public Foo { ... MOCK_METHOD1(Bar, void(const int i)); }; ``` You may get the following warning: ``` warning C4301: 'MockFoo::Bar': overriding virtual function only differs from 'Foo::Bar' by const/volatile qualifier ``` This is a MSVC bug. The same code compiles fine with gcc ,for example. If you use Visual C++ 2008 SP1, you would get the warning: ``` warning C4373: 'MockFoo::Bar': virtual function overrides 'Foo::Bar', previous versions of the compiler did not override when parameters only differed by const/volatile qualifiers ``` In C++, if you _declare_ a function with a `const` parameter, the `const` modifier is _ignored_. Therefore, the `Foo` base class above is equivalent to: ``` class Foo { ... virtual void Bar(int i) = 0; // int or const int? Makes no difference. }; ``` In fact, you can _declare_ Bar() with an `int` parameter, and _define_ it with a `const int` parameter. The compiler will still match them up. Since making a parameter `const` is meaningless in the method _declaration_, we recommend to remove it in both `Foo` and `MockFoo`. That should workaround the VC bug. Note that we are talking about the _top-level_ `const` modifier here. If the function parameter is passed by pointer or reference, declaring the _pointee_ or _referee_ as `const` is still meaningful. For example, the following two declarations are _not_ equivalent: ``` void Bar(int* p); // Neither p nor *p is const. void Bar(const int* p); // p is not const, but *p is. ``` ## I have a huge mock class, and Microsoft Visual C++ runs out of memory when compiling it. What can I do? ## We've noticed that when the `/clr` compiler flag is used, Visual C++ uses 5~6 times as much memory when compiling a mock class. We suggest to avoid `/clr` when compiling native C++ mocks. ## I can't figure out why Google Mock thinks my expectations are not satisfied. What should I do? ## You might want to run your test with `--gmock_verbose=info`. This flag lets Google Mock print a trace of every mock function call it receives. By studying the trace, you'll gain insights on why the expectations you set are not met. ## How can I assert that a function is NEVER called? ## ``` EXPECT_CALL(foo, Bar(_)) .Times(0); ``` ## I have a failed test where Google Mock tells me TWICE that a particular expectation is not satisfied. Isn't this redundant? ## When Google Mock detects a failure, it prints relevant information (the mock function arguments, the state of relevant expectations, and etc) to help the user debug. If another failure is detected, Google Mock will do the same, including printing the state of relevant expectations. Sometimes an expectation's state didn't change between two failures, and you'll see the same description of the state twice. They are however _not_ redundant, as they refer to _different points in time_. The fact they are the same _is_ interesting information. ## I get a heap check failure when using a mock object, but using a real object is fine. What can be wrong? ## Does the class (hopefully a pure interface) you are mocking have a virtual destructor? Whenever you derive from a base class, make sure its destructor is virtual. Otherwise Bad Things will happen. Consider the following code: ``` class Base { public: // Not virtual, but should be. ~Base() { ... } ... }; class Derived : public Base { public: ... private: std::string value_; }; ... Base* p = new Derived; ... delete p; // Surprise! ~Base() will be called, but ~Derived() will not // - value_ is leaked. ``` By changing `~Base()` to virtual, `~Derived()` will be correctly called when `delete p` is executed, and the heap checker will be happy. ## The "newer expectations override older ones" rule makes writing expectations awkward. Why does Google Mock do that? ## When people complain about this, often they are referring to code like: ``` // foo.Bar() should be called twice, return 1 the first time, and return // 2 the second time. However, I have to write the expectations in the // reverse order. This sucks big time!!! EXPECT_CALL(foo, Bar()) .WillOnce(Return(2)) .RetiresOnSaturation(); EXPECT_CALL(foo, Bar()) .WillOnce(Return(1)) .RetiresOnSaturation(); ``` The problem is that they didn't pick the **best** way to express the test's intent. By default, expectations don't have to be matched in _any_ particular order. If you want them to match in a certain order, you need to be explicit. This is Google Mock's (and jMock's) fundamental philosophy: it's easy to accidentally over-specify your tests, and we want to make it harder to do so. There are two better ways to write the test spec. You could either put the expectations in sequence: ``` // foo.Bar() should be called twice, return 1 the first time, and return // 2 the second time. Using a sequence, we can write the expectations // in their natural order. { InSequence s; EXPECT_CALL(foo, Bar()) .WillOnce(Return(1)) .RetiresOnSaturation(); EXPECT_CALL(foo, Bar()) .WillOnce(Return(2)) .RetiresOnSaturation(); } ``` or you can put the sequence of actions in the same expectation: ``` // foo.Bar() should be called twice, return 1 the first time, and return // 2 the second time. EXPECT_CALL(foo, Bar()) .WillOnce(Return(1)) .WillOnce(Return(2)) .RetiresOnSaturation(); ``` Back to the original questions: why does Google Mock search the expectations (and `ON_CALL`s) from back to front? Because this allows a user to set up a mock's behavior for the common case early (e.g. in the mock's constructor or the test fixture's set-up phase) and customize it with more specific rules later. If Google Mock searches from front to back, this very useful pattern won't be possible. ## Google Mock prints a warning when a function without EXPECT\_CALL is called, even if I have set its behavior using ON\_CALL. Would it be reasonable not to show the warning in this case? ## When choosing between being neat and being safe, we lean toward the latter. So the answer is that we think it's better to show the warning. Often people write `ON_CALL`s in the mock object's constructor or `SetUp()`, as the default behavior rarely changes from test to test. Then in the test body they set the expectations, which are often different for each test. Having an `ON_CALL` in the set-up part of a test doesn't mean that the calls are expected. If there's no `EXPECT_CALL` and the method is called, it's possibly an error. If we quietly let the call go through without notifying the user, bugs may creep in unnoticed. If, however, you are sure that the calls are OK, you can write ``` EXPECT_CALL(foo, Bar(_)) .WillRepeatedly(...); ``` instead of ``` ON_CALL(foo, Bar(_)) .WillByDefault(...); ``` This tells Google Mock that you do expect the calls and no warning should be printed. Also, you can control the verbosity using the `--gmock_verbose` flag. If you find the output too noisy when debugging, just choose a less verbose level. ## How can I delete the mock function's argument in an action? ## If you find yourself needing to perform some action that's not supported by Google Mock directly, remember that you can define your own actions using [MakeAction()](CookBook.md#writing-new-actions) or [MakePolymorphicAction()](CookBook.md#writing_new_polymorphic_actions), or you can write a stub function and invoke it using [Invoke()](CookBook.md#using-functions_methods_functors). ## MOCK\_METHODn()'s second argument looks funny. Why don't you use the MOCK\_METHODn(Method, return\_type, arg\_1, ..., arg\_n) syntax? ## What?! I think it's beautiful. :-) While which syntax looks more natural is a subjective matter to some extent, Google Mock's syntax was chosen for several practical advantages it has. Try to mock a function that takes a map as an argument: ``` virtual int GetSize(const map& m); ``` Using the proposed syntax, it would be: ``` MOCK_METHOD1(GetSize, int, const map& m); ``` Guess what? You'll get a compiler error as the compiler thinks that `const map& m` are **two**, not one, arguments. To work around this you can use `typedef` to give the map type a name, but that gets in the way of your work. Google Mock's syntax avoids this problem as the function's argument types are protected inside a pair of parentheses: ``` // This compiles fine. MOCK_METHOD1(GetSize, int(const map& m)); ``` You still need a `typedef` if the return type contains an unprotected comma, but that's much rarer. Other advantages include: 1. `MOCK_METHOD1(Foo, int, bool)` can leave a reader wonder whether the method returns `int` or `bool`, while there won't be such confusion using Google Mock's syntax. 1. The way Google Mock describes a function type is nothing new, although many people may not be familiar with it. The same syntax was used in C, and the `function` library in `tr1` uses this syntax extensively. Since `tr1` will become a part of the new version of STL, we feel very comfortable to be consistent with it. 1. The function type syntax is also used in other parts of Google Mock's API (e.g. the action interface) in order to make the implementation tractable. A user needs to learn it anyway in order to utilize Google Mock's more advanced features. We'd as well stick to the same syntax in `MOCK_METHOD*`! ## My code calls a static/global function. Can I mock it? ## You can, but you need to make some changes. In general, if you find yourself needing to mock a static function, it's a sign that your modules are too tightly coupled (and less flexible, less reusable, less testable, etc). You are probably better off defining a small interface and call the function through that interface, which then can be easily mocked. It's a bit of work initially, but usually pays for itself quickly. This Google Testing Blog [post](http://googletesting.blogspot.com/2008/06/defeat-static-cling.html) says it excellently. Check it out. ## My mock object needs to do complex stuff. It's a lot of pain to specify the actions. Google Mock sucks! ## I know it's not a question, but you get an answer for free any way. :-) With Google Mock, you can create mocks in C++ easily. And people might be tempted to use them everywhere. Sometimes they work great, and sometimes you may find them, well, a pain to use. So, what's wrong in the latter case? When you write a test without using mocks, you exercise the code and assert that it returns the correct value or that the system is in an expected state. This is sometimes called "state-based testing". Mocks are great for what some call "interaction-based" testing: instead of checking the system state at the very end, mock objects verify that they are invoked the right way and report an error as soon as it arises, giving you a handle on the precise context in which the error was triggered. This is often more effective and economical to do than state-based testing. If you are doing state-based testing and using a test double just to simulate the real object, you are probably better off using a fake. Using a mock in this case causes pain, as it's not a strong point for mocks to perform complex actions. If you experience this and think that mocks suck, you are just not using the right tool for your problem. Or, you might be trying to solve the wrong problem. :-) ## I got a warning "Uninteresting function call encountered - default action taken.." Should I panic? ## By all means, NO! It's just an FYI. What it means is that you have a mock function, you haven't set any expectations on it (by Google Mock's rule this means that you are not interested in calls to this function and therefore it can be called any number of times), and it is called. That's OK - you didn't say it's not OK to call the function! What if you actually meant to disallow this function to be called, but forgot to write `EXPECT_CALL(foo, Bar()).Times(0)`? While one can argue that it's the user's fault, Google Mock tries to be nice and prints you a note. So, when you see the message and believe that there shouldn't be any uninteresting calls, you should investigate what's going on. To make your life easier, Google Mock prints the function name and arguments when an uninteresting call is encountered. ## I want to define a custom action. Should I use Invoke() or implement the action interface? ## Either way is fine - you want to choose the one that's more convenient for your circumstance. Usually, if your action is for a particular function type, defining it using `Invoke()` should be easier; if your action can be used in functions of different types (e.g. if you are defining `Return(value)`), `MakePolymorphicAction()` is easiest. Sometimes you want precise control on what types of functions the action can be used in, and implementing `ActionInterface` is the way to go here. See the implementation of `Return()` in `include/gmock/gmock-actions.h` for an example. ## I'm using the set-argument-pointee action, and the compiler complains about "conflicting return type specified". What does it mean? ## You got this error as Google Mock has no idea what value it should return when the mock method is called. `SetArgPointee()` says what the side effect is, but doesn't say what the return value should be. You need `DoAll()` to chain a `SetArgPointee()` with a `Return()`. See this [recipe](CookBook.md#mocking_side_effects) for more details and an example. ## My question is not in your FAQ! ## If you cannot find the answer to your question in this FAQ, there are some other resources you can use: 1. read other [documentation](Documentation.md), 1. search the mailing list [archive](http://groups.google.com/group/googlemock/topics), 1. ask it on [googlemock@googlegroups.com](mailto:googlemock@googlegroups.com) and someone will answer it (to prevent spam, we require you to join the [discussion group](http://groups.google.com/group/googlemock) before you can post.). Please note that creating an issue in the [issue tracker](https://github.com/google/googletest/issues) is _not_ a good way to get your answer, as it is monitored infrequently by a very small number of people. When asking a question, it's helpful to provide as much of the following information as possible (people cannot help you if there's not enough information in your question): * the version (or the revision number if you check out from SVN directly) of Google Mock you use (Google Mock is under active development, so it's possible that your problem has been solved in a later version), * your operating system, * the name and version of your compiler, * the complete command line flags you give to your compiler, * the complete compiler error messages (if the question is about compilation), * the _actual_ code (ideally, a minimal but complete program) that has the problem you encounter. nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/docs/KnownIssues.md000066400000000000000000000027701455373415500264100ustar00rootroot00000000000000As any non-trivial software system, Google Mock has some known limitations and problems. We are working on improving it, and welcome your help! The follow is a list of issues we know about. ## README contains outdated information on Google Mock's compatibility with other testing frameworks ## The `README` file in release 1.1.0 still says that Google Mock only works with Google Test. Actually, you can configure Google Mock to work with any testing framework you choose. ## Tests failing on machines using Power PC CPUs (e.g. some Macs) ## `gmock_output_test` and `gmock-printers_test` are known to fail with Power PC CPUs. This is due to portability issues with these tests, and is not an indication of problems in Google Mock itself. You can safely ignore them. ## Failed to resolve libgtest.so.0 in tests when built against installed Google Test ## This only applies if you manually built and installed Google Test, and then built a Google Mock against it (either explicitly, or because gtest-config was in your path post-install). In this situation, Libtool has a known issue with certain systems' ldconfig setup: http://article.gmane.org/gmane.comp.sysutils.automake.general/9025 This requires a manual run of "sudo ldconfig" after the "sudo make install" for Google Test before any binaries which link against it can be executed. This isn't a bug in our install, but we should at least have documented it or hacked a work-around into our install. We should have one of these solutions in our next release.nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/docs/v1_5/000077500000000000000000000000001455373415500243425ustar00rootroot00000000000000nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/docs/v1_5/CheatSheet.md000066400000000000000000000562421455373415500267120ustar00rootroot00000000000000 # Defining a Mock Class # ## Mocking a Normal Class ## Given ``` class Foo { ... virtual ~Foo(); virtual int GetSize() const = 0; virtual string Describe(const char* name) = 0; virtual string Describe(int type) = 0; virtual bool Process(Bar elem, int count) = 0; }; ``` (note that `~Foo()` **must** be virtual) we can define its mock as ``` #include class MockFoo : public Foo { MOCK_CONST_METHOD0(GetSize, int()); MOCK_METHOD1(Describe, string(const char* name)); MOCK_METHOD1(Describe, string(int type)); MOCK_METHOD2(Process, bool(Bar elem, int count)); }; ``` To create a "nice" mock object which ignores all uninteresting calls, or a "strict" mock object, which treats them as failures: ``` NiceMock nice_foo; // The type is a subclass of MockFoo. StrictMock strict_foo; // The type is a subclass of MockFoo. ``` ## Mocking a Class Template ## To mock ``` template class StackInterface { public: ... virtual ~StackInterface(); virtual int GetSize() const = 0; virtual void Push(const Elem& x) = 0; }; ``` (note that `~StackInterface()` **must** be virtual) just append `_T` to the `MOCK_*` macros: ``` template class MockStack : public StackInterface { public: ... MOCK_CONST_METHOD0_T(GetSize, int()); MOCK_METHOD1_T(Push, void(const Elem& x)); }; ``` ## Specifying Calling Conventions for Mock Functions ## If your mock function doesn't use the default calling convention, you can specify it by appending `_WITH_CALLTYPE` to any of the macros described in the previous two sections and supplying the calling convention as the first argument to the macro. For example, ``` MOCK_METHOD_1_WITH_CALLTYPE(STDMETHODCALLTYPE, Foo, bool(int n)); MOCK_CONST_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, Bar, int(double x, double y)); ``` where `STDMETHODCALLTYPE` is defined by `` on Windows. # Using Mocks in Tests # The typical flow is: 1. Import the Google Mock names you need to use. All Google Mock names are in the `testing` namespace unless they are macros or otherwise noted. 1. Create the mock objects. 1. Optionally, set the default actions of the mock objects. 1. Set your expectations on the mock objects (How will they be called? What wil they do?). 1. Exercise code that uses the mock objects; if necessary, check the result using [Google Test](http://code.google.com/p/googletest/) assertions. 1. When a mock objects is destructed, Google Mock automatically verifies that all expectations on it have been satisfied. Here is an example: ``` using ::testing::Return; // #1 TEST(BarTest, DoesThis) { MockFoo foo; // #2 ON_CALL(foo, GetSize()) // #3 .WillByDefault(Return(1)); // ... other default actions ... EXPECT_CALL(foo, Describe(5)) // #4 .Times(3) .WillRepeatedly(Return("Category 5")); // ... other expectations ... EXPECT_EQ("good", MyProductionFunction(&foo)); // #5 } // #6 ``` # Setting Default Actions # Google Mock has a **built-in default action** for any function that returns `void`, `bool`, a numeric value, or a pointer. To customize the default action for functions with return type `T` globally: ``` using ::testing::DefaultValue; DefaultValue::Set(value); // Sets the default value to be returned. // ... use the mocks ... DefaultValue::Clear(); // Resets the default value. ``` To customize the default action for a particular method, use `ON_CALL()`: ``` ON_CALL(mock_object, method(matchers)) .With(multi_argument_matcher) ? .WillByDefault(action); ``` # Setting Expectations # `EXPECT_CALL()` sets **expectations** on a mock method (How will it be called? What will it do?): ``` EXPECT_CALL(mock_object, method(matchers)) .With(multi_argument_matcher) ? .Times(cardinality) ? .InSequence(sequences) * .After(expectations) * .WillOnce(action) * .WillRepeatedly(action) ? .RetiresOnSaturation(); ? ``` If `Times()` is omitted, the cardinality is assumed to be: * `Times(1)` when there is neither `WillOnce()` nor `WillRepeatedly()`; * `Times(n)` when there are `n WillOnce()`s but no `WillRepeatedly()`, where `n` >= 1; or * `Times(AtLeast(n))` when there are `n WillOnce()`s and a `WillRepeatedly()`, where `n` >= 0. A method with no `EXPECT_CALL()` is free to be invoked _any number of times_, and the default action will be taken each time. # Matchers # A **matcher** matches a _single_ argument. You can use it inside `ON_CALL()` or `EXPECT_CALL()`, or use it to validate a value directly: | `EXPECT_THAT(value, matcher)` | Asserts that `value` matches `matcher`. | |:------------------------------|:----------------------------------------| | `ASSERT_THAT(value, matcher)` | The same as `EXPECT_THAT(value, matcher)`, except that it generates a **fatal** failure. | Built-in matchers (where `argument` is the function argument) are divided into several categories: ## Wildcard ## |`_`|`argument` can be any value of the correct type.| |:--|:-----------------------------------------------| |`A()` or `An()`|`argument` can be any value of type `type`. | ## Generic Comparison ## |`Eq(value)` or `value`|`argument == value`| |:---------------------|:------------------| |`Ge(value)` |`argument >= value`| |`Gt(value)` |`argument > value` | |`Le(value)` |`argument <= value`| |`Lt(value)` |`argument < value` | |`Ne(value)` |`argument != value`| |`IsNull()` |`argument` is a `NULL` pointer (raw or smart).| |`NotNull()` |`argument` is a non-null pointer (raw or smart).| |`Ref(variable)` |`argument` is a reference to `variable`.| |`TypedEq(value)`|`argument` has type `type` and is equal to `value`. You may need to use this instead of `Eq(value)` when the mock function is overloaded.| Except `Ref()`, these matchers make a _copy_ of `value` in case it's modified or destructed later. If the compiler complains that `value` doesn't have a public copy constructor, try wrap it in `ByRef()`, e.g. `Eq(ByRef(non_copyable_value))`. If you do that, make sure `non_copyable_value` is not changed afterwards, or the meaning of your matcher will be changed. ## Floating-Point Matchers ## |`DoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as unequal.| |:-------------------|:----------------------------------------------------------------------------------------------| |`FloatEq(a_float)` |`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as unequal. | |`NanSensitiveDoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as equal. | |`NanSensitiveFloatEq(a_float)`|`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as equal. | The above matchers use ULP-based comparison (the same as used in [Google Test](http://code.google.com/p/googletest/)). They automatically pick a reasonable error bound based on the absolute value of the expected value. `DoubleEq()` and `FloatEq()` conform to the IEEE standard, which requires comparing two NaNs for equality to return false. The `NanSensitive*` version instead treats two NaNs as equal, which is often what a user wants. ## String Matchers ## The `argument` can be either a C string or a C++ string object: |`ContainsRegex(string)`|`argument` matches the given regular expression.| |:----------------------|:-----------------------------------------------| |`EndsWith(suffix)` |`argument` ends with string `suffix`. | |`HasSubstr(string)` |`argument` contains `string` as a sub-string. | |`MatchesRegex(string)` |`argument` matches the given regular expression with the match starting at the first character and ending at the last character.| |`StartsWith(prefix)` |`argument` starts with string `prefix`. | |`StrCaseEq(string)` |`argument` is equal to `string`, ignoring case. | |`StrCaseNe(string)` |`argument` is not equal to `string`, ignoring case.| |`StrEq(string)` |`argument` is equal to `string`. | |`StrNe(string)` |`argument` is not equal to `string`. | `StrCaseEq()`, `StrCaseNe()`, `StrEq()`, and `StrNe()` work for wide strings as well. ## Container Matchers ## Most STL-style containers support `==`, so you can use `Eq(expected_container)` or simply `expected_container` to match a container exactly. If you want to write the elements in-line, match them more flexibly, or get more informative messages, you can use: | `Contains(e)` | `argument` contains an element that matches `e`, which can be either a value or a matcher. | |:--------------|:-------------------------------------------------------------------------------------------| |`ElementsAre(e0, e1, ..., en)`|`argument` has `n + 1` elements, where the i-th element matches `ei`, which can be a value or a matcher. 0 to 10 arguments are allowed.| |`ElementsAreArray(array)` or `ElementsAreArray(array, count)`|The same as `ElementsAre()` except that the expected element values/matchers come from a C-style array.| | `ContainerEq(container)` | The same as `Eq(container)` except that the failure message also includes which elements are in one container but not the other. | These matchers can also match: 1. a native array passed by reference (e.g. in `Foo(const int (&a)[5])`), and 1. an array passed as a pointer and a count (e.g. in `Bar(const T* buffer, int len)` -- see [Multi-argument Matchers](#Multiargument_Matchers.md)). where the array may be multi-dimensional (i.e. its elements can be arrays). ## Member Matchers ## |`Field(&class::field, m)`|`argument.field` (or `argument->field` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.| |:------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------| |`Key(e)` |`argument.first` matches `e`, which can be either a value or a matcher. E.g. `Contains(Key(Le(5)))` can verify that a `map` contains a key `<= 5`.| |`Pair(m1, m2)` |`argument` is an `std::pair` whose `first` field matches `m1` and `second` field matches `m2`. | |`Property(&class::property, m)`|`argument.property()` (or `argument->property()` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.| ## Matching the Result of a Function or Functor ## |`ResultOf(f, m)`|`f(argument)` matches matcher `m`, where `f` is a function or functor.| |:---------------|:---------------------------------------------------------------------| ## Pointer Matchers ## |`Pointee(m)`|`argument` (either a smart pointer or a raw pointer) points to a value that matches matcher `m`.| |:-----------|:-----------------------------------------------------------------------------------------------| ## Multiargument Matchers ## These are matchers on tuple types. They can be used in `.With()`. The following can be used on functions with two
arguments
`x` and `y`: |`Eq()`|`x == y`| |:-----|:-------| |`Ge()`|`x >= y`| |`Gt()`|`x > y` | |`Le()`|`x <= y`| |`Lt()`|`x < y` | |`Ne()`|`x != y`| You can use the following selectors to pick a subset of the arguments (or reorder them) to participate in the matching: |`AllArgs(m)`|Equivalent to `m`. Useful as syntactic sugar in `.With(AllArgs(m))`.| |:-----------|:-------------------------------------------------------------------| |`Args(m)`|The `k` selected (using 0-based indices) arguments match `m`, e.g. `Args<1, 2>(Contains(5))`.| ## Composite Matchers ## You can make a matcher from one or more other matchers: |`AllOf(m1, m2, ..., mn)`|`argument` matches all of the matchers `m1` to `mn`.| |:-----------------------|:---------------------------------------------------| |`AnyOf(m1, m2, ..., mn)`|`argument` matches at least one of the matchers `m1` to `mn`.| |`Not(m)` |`argument` doesn't match matcher `m`. | ## Adapters for Matchers ## |`MatcherCast(m)`|casts matcher `m` to type `Matcher`.| |:------------------|:--------------------------------------| |`SafeMatcherCast(m)`| [safely casts](V1_5_CookBook#Casting_Matchers.md) matcher `m` to type `Matcher`. | |`Truly(predicate)` |`predicate(argument)` returns something considered by C++ to be true, where `predicate` is a function or functor.| ## Matchers as Predicates ## |`Matches(m)`|a unary functor that returns `true` if the argument matches `m`.| |:-----------|:---------------------------------------------------------------| |`ExplainMatchResult(m, value, result_listener)`|returns `true` if `value` matches `m`, explaining the result to `result_listener`.| |`Value(x, m)`|returns `true` if the value of `x` matches `m`. | ## Defining Matchers ## | `MATCHER(IsEven, "") { return (arg % 2) == 0; }` | Defines a matcher `IsEven()` to match an even number. | |:-------------------------------------------------|:------------------------------------------------------| | `MATCHER_P(IsDivisibleBy, n, "") { *result_listener << "where the remainder is " << (arg % n); return (arg % n) == 0; }` | Defines a macher `IsDivisibleBy(n)` to match a number divisible by `n`. | | `MATCHER_P2(IsBetween, a, b, "is between %(a)s and %(b)s") { return a <= arg && arg <= b; }` | Defines a matcher `IsBetween(a, b)` to match a value in the range [`a`, `b`]. | **Notes:** 1. The `MATCHER*` macros cannot be used inside a function or class. 1. The matcher body must be _purely functional_ (i.e. it cannot have any side effect, and the result must not depend on anything other than the value being matched and the matcher parameters). 1. You can use `PrintToString(x)` to convert a value `x` of any type to a string. ## Matchers as Test Assertions ## |`ASSERT_THAT(expression, m)`|Generates a [fatal failure](http://code.google.com/p/googletest/wiki/GoogleTestPrimer#Assertions) if the value of `expression` doesn't match matcher `m`.| |:---------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------| |`EXPECT_THAT(expression, m)`|Generates a non-fatal failure if the value of `expression` doesn't match matcher `m`. | # Actions # **Actions** specify what a mock function should do when invoked. ## Returning a Value ## |`Return()`|Return from a `void` mock function.| |:---------|:----------------------------------| |`Return(value)`|Return `value`. | |`ReturnArg()`|Return the `N`-th (0-based) argument.| |`ReturnNew(a1, ..., ak)`|Return `new T(a1, ..., ak)`; a different object is created each time.| |`ReturnNull()`|Return a null pointer. | |`ReturnRef(variable)`|Return a reference to `variable`. | ## Side Effects ## |`Assign(&variable, value)`|Assign `value` to variable.| |:-------------------------|:--------------------------| | `DeleteArg()` | Delete the `N`-th (0-based) argument, which must be a pointer. | | `SaveArg(pointer)` | Save the `N`-th (0-based) argument to `*pointer`. | | `SetArgReferee(value)` | Assign value to the variable referenced by the `N`-th (0-based) argument. | |`SetArgumentPointee(value)`|Assign `value` to the variable pointed by the `N`-th (0-based) argument.| |`SetArrayArgument(first, last)`|Copies the elements in source range [`first`, `last`) to the array pointed to by the `N`-th (0-based) argument, which can be either a pointer or an iterator. The action does not take ownership of the elements in the source range.| |`SetErrnoAndReturn(error, value)`|Set `errno` to `error` and return `value`.| |`Throw(exception)` |Throws the given exception, which can be any copyable value. Available since v1.1.0.| ## Using a Function or a Functor as an Action ## |`Invoke(f)`|Invoke `f` with the arguments passed to the mock function, where `f` can be a global/static function or a functor.| |:----------|:-----------------------------------------------------------------------------------------------------------------| |`Invoke(object_pointer, &class::method)`|Invoke the {method on the object with the arguments passed to the mock function. | |`InvokeWithoutArgs(f)`|Invoke `f`, which can be a global/static function or a functor. `f` must take no arguments. | |`InvokeWithoutArgs(object_pointer, &class::method)`|Invoke the method on the object, which takes no arguments. | |`InvokeArgument(arg1, arg2, ..., argk)`|Invoke the mock function's `N`-th (0-based) argument, which must be a function or a functor, with the `k` arguments.| The return value of the invoked function is used as the return value of the action. When defining a function or functor to be used with `Invoke*()`, you can declare any unused parameters as `Unused`: ``` double Distance(Unused, double x, double y) { return sqrt(x*x + y*y); } ... EXPECT_CALL(mock, Foo("Hi", _, _)).WillOnce(Invoke(Distance)); ``` In `InvokeArgument(...)`, if an argument needs to be passed by reference, wrap it inside `ByRef()`. For example, ``` InvokeArgument<2>(5, string("Hi"), ByRef(foo)) ``` calls the mock function's #2 argument, passing to it `5` and `string("Hi")` by value, and `foo` by reference. ## Default Action ## |`DoDefault()`|Do the default action (specified by `ON_CALL()` or the built-in one).| |:------------|:--------------------------------------------------------------------| **Note:** due to technical reasons, `DoDefault()` cannot be used inside a composite action - trying to do so will result in a run-time error. ## Composite Actions ## |`DoAll(a1, a2, ..., an)`|Do all actions `a1` to `an` and return the result of `an` in each invocation. The first `n - 1` sub-actions must return void. | |:-----------------------|:-----------------------------------------------------------------------------------------------------------------------------| |`IgnoreResult(a)` |Perform action `a` and ignore its result. `a` must not return void. | |`WithArg(a)` |Pass the `N`-th (0-based) argument of the mock function to action `a` and perform it. | |`WithArgs(a)`|Pass the selected (0-based) arguments of the mock function to action `a` and perform it. | |`WithoutArgs(a)` |Perform action `a` without any arguments. | ## Defining Actions ## | `ACTION(Sum) { return arg0 + arg1; }` | Defines an action `Sum()` to return the sum of the mock function's argument #0 and #1. | |:--------------------------------------|:---------------------------------------------------------------------------------------| | `ACTION_P(Plus, n) { return arg0 + n; }` | Defines an action `Plus(n)` to return the sum of the mock function's argument #0 and `n`. | | `ACTION_Pk(Foo, p1, ..., pk) { statements; }` | Defines a parameterized action `Foo(p1, ..., pk)` to execute the given `statements`. | The `ACTION*` macros cannot be used inside a function or class. # Cardinalities # These are used in `Times()` to specify how many times a mock function will be called: |`AnyNumber()`|The function can be called any number of times.| |:------------|:----------------------------------------------| |`AtLeast(n)` |The call is expected at least `n` times. | |`AtMost(n)` |The call is expected at most `n` times. | |`Between(m, n)`|The call is expected between `m` and `n` (inclusive) times.| |`Exactly(n) or n`|The call is expected exactly `n` times. In particular, the call should never happen when `n` is 0.| # Expectation Order # By default, the expectations can be matched in _any_ order. If some or all expectations must be matched in a given order, there are two ways to specify it. They can be used either independently or together. ## The After Clause ## ``` using ::testing::Expectation; ... Expectation init_x = EXPECT_CALL(foo, InitX()); Expectation init_y = EXPECT_CALL(foo, InitY()); EXPECT_CALL(foo, Bar()) .After(init_x, init_y); ``` says that `Bar()` can be called only after both `InitX()` and `InitY()` have been called. If you don't know how many pre-requisites an expectation has when you write it, you can use an `ExpectationSet` to collect them: ``` using ::testing::ExpectationSet; ... ExpectationSet all_inits; for (int i = 0; i < element_count; i++) { all_inits += EXPECT_CALL(foo, InitElement(i)); } EXPECT_CALL(foo, Bar()) .After(all_inits); ``` says that `Bar()` can be called only after all elements have been initialized (but we don't care about which elements get initialized before the others). Modifying an `ExpectationSet` after using it in an `.After()` doesn't affect the meaning of the `.After()`. ## Sequences ## When you have a long chain of sequential expectations, it's easier to specify the order using **sequences**, which don't require you to given each expectation in the chain a different name. All expected
calls
in the same sequence must occur in the order they are specified. ``` using ::testing::Sequence; Sequence s1, s2; ... EXPECT_CALL(foo, Reset()) .InSequence(s1, s2) .WillOnce(Return(true)); EXPECT_CALL(foo, GetSize()) .InSequence(s1) .WillOnce(Return(1)); EXPECT_CALL(foo, Describe(A())) .InSequence(s2) .WillOnce(Return("dummy")); ``` says that `Reset()` must be called before _both_ `GetSize()` _and_ `Describe()`, and the latter two can occur in any order. To put many expectations in a sequence conveniently: ``` using ::testing::InSequence; { InSequence dummy; EXPECT_CALL(...)...; EXPECT_CALL(...)...; ... EXPECT_CALL(...)...; } ``` says that all expected calls in the scope of `dummy` must occur in strict order. The name `dummy` is irrelevant.) # Verifying and Resetting a Mock # Google Mock will verify the expectations on a mock object when it is destructed, or you can do it earlier: ``` using ::testing::Mock; ... // Verifies and removes the expectations on mock_obj; // returns true iff successful. Mock::VerifyAndClearExpectations(&mock_obj); ... // Verifies and removes the expectations on mock_obj; // also removes the default actions set by ON_CALL(); // returns true iff successful. Mock::VerifyAndClear(&mock_obj); ``` You can also tell Google Mock that a mock object can be leaked and doesn't need to be verified: ``` Mock::AllowLeak(&mock_obj); ``` # Mock Classes # Google Mock defines a convenient mock class template ``` class MockFunction { public: MOCK_METHODn(Call, R(A1, ..., An)); }; ``` See this [recipe](V1_5_CookBook#Using_Check_Points.md) for one application of it. # Flags # | `--gmock_catch_leaked_mocks=0` | Don't report leaked mock objects as failures. | |:-------------------------------|:----------------------------------------------| | `--gmock_verbose=LEVEL` | Sets the default verbosity level (`info`, `warning`, or `error`) of Google Mock messages. |nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/docs/v1_5/CookBook.md000066400000000000000000003257021455373415500264030ustar00rootroot00000000000000 You can find recipes for using Google Mock here. If you haven't yet, please read the [ForDummies](V1_5_ForDummies.md) document first to make sure you understand the basics. **Note:** Google Mock lives in the `testing` name space. For readability, it is recommended to write `using ::testing::Foo;` once in your file before using the name `Foo` defined by Google Mock. We omit such `using` statements in this page for brevity, but you should do it in your own code. # Creating Mock Classes # ## Mocking Private or Protected Methods ## You must always put a mock method definition (`MOCK_METHOD*`) in a `public:` section of the mock class, regardless of the method being mocked being `public`, `protected`, or `private` in the base class. This allows `ON_CALL` and `EXPECT_CALL` to reference the mock function from outside of the mock class. (Yes, C++ allows a subclass to change the access level of a virtual function in the base class.) Example: ``` class Foo { public: ... virtual bool Transform(Gadget* g) = 0; protected: virtual void Resume(); private: virtual int GetTimeOut(); }; class MockFoo : public Foo { public: ... MOCK_METHOD1(Transform, bool(Gadget* g)); // The following must be in the public section, even though the // methods are protected or private in the base class. MOCK_METHOD0(Resume, void()); MOCK_METHOD0(GetTimeOut, int()); }; ``` ## Mocking Overloaded Methods ## You can mock overloaded functions as usual. No special attention is required: ``` class Foo { ... // Must be virtual as we'll inherit from Foo. virtual ~Foo(); // Overloaded on the types and/or numbers of arguments. virtual int Add(Element x); virtual int Add(int times, Element x); // Overloaded on the const-ness of this object. virtual Bar& GetBar(); virtual const Bar& GetBar() const; }; class MockFoo : public Foo { ... MOCK_METHOD1(Add, int(Element x)); MOCK_METHOD2(Add, int(int times, Element x); MOCK_METHOD0(GetBar, Bar&()); MOCK_CONST_METHOD0(GetBar, const Bar&()); }; ``` **Note:** if you don't mock all versions of the overloaded method, the compiler will give you a warning about some methods in the base class being hidden. To fix that, use `using` to bring them in scope: ``` class MockFoo : public Foo { ... using Foo::Add; MOCK_METHOD1(Add, int(Element x)); // We don't want to mock int Add(int times, Element x); ... }; ``` ## Mocking Class Templates ## To mock a class template, append `_T` to the `MOCK_*` macros: ``` template class StackInterface { ... // Must be virtual as we'll inherit from StackInterface. virtual ~StackInterface(); virtual int GetSize() const = 0; virtual void Push(const Elem& x) = 0; }; template class MockStack : public StackInterface { ... MOCK_CONST_METHOD0_T(GetSize, int()); MOCK_METHOD1_T(Push, void(const Elem& x)); }; ``` ## Mocking Nonvirtual Methods ## Google Mock can mock non-virtual functions to be used in what we call _hi-perf dependency injection_. In this case, instead of sharing a common base class with the real class, your mock class will be _unrelated_ to the real class, but contain methods with the same signatures. The syntax for mocking non-virtual methods is the _same_ as mocking virtual methods: ``` // A simple packet stream class. None of its members is virtual. class ConcretePacketStream { public: void AppendPacket(Packet* new_packet); const Packet* GetPacket(size_t packet_number) const; size_t NumberOfPackets() const; ... }; // A mock packet stream class. It inherits from no other, but defines // GetPacket() and NumberOfPackets(). class MockPacketStream { public: MOCK_CONST_METHOD1(GetPacket, const Packet*(size_t packet_number)); MOCK_CONST_METHOD0(NumberOfPackets, size_t()); ... }; ``` Note that the mock class doesn't define `AppendPacket()`, unlike the real class. That's fine as long as the test doesn't need to call it. Next, you need a way to say that you want to use `ConcretePacketStream` in production code, and use `MockPacketStream` in tests. Since the functions are not virtual and the two classes are unrelated, you must specify your choice at _compile time_ (as opposed to run time). One way to do it is to templatize your code that needs to use a packet stream. More specifically, you will give your code a template type argument for the type of the packet stream. In production, you will instantiate your template with `ConcretePacketStream` as the type argument. In tests, you will instantiate the same template with `MockPacketStream`. For example, you may write: ``` template void CreateConnection(PacketStream* stream) { ... } template class PacketReader { public: void ReadPackets(PacketStream* stream, size_t packet_num); }; ``` Then you can use `CreateConnection()` and `PacketReader` in production code, and use `CreateConnection()` and `PacketReader` in tests. ``` MockPacketStream mock_stream; EXPECT_CALL(mock_stream, ...)...; .. set more expectations on mock_stream ... PacketReader reader(&mock_stream); ... exercise reader ... ``` ## Mocking Free Functions ## It's possible to use Google Mock to mock a free function (i.e. a C-style function or a static method). You just need to rewrite your code to use an interface (abstract class). Instead of calling a free function (say, `OpenFile`) directly, introduce an interface for it and have a concrete subclass that calls the free function: ``` class FileInterface { public: ... virtual bool Open(const char* path, const char* mode) = 0; }; class File : public FileInterface { public: ... virtual bool Open(const char* path, const char* mode) { return OpenFile(path, mode); } }; ``` Your code should talk to `FileInterface` to open a file. Now it's easy to mock out the function. This may seem much hassle, but in practice you often have multiple related functions that you can put in the same interface, so the per-function syntactic overhead will be much lower. If you are concerned about the performance overhead incurred by virtual functions, and profiling confirms your concern, you can combine this with the recipe for [mocking non-virtual methods](#Mocking_Nonvirtual_Methods.md). ## Nice Mocks and Strict Mocks ## If a mock method has no `EXPECT_CALL` spec but is called, Google Mock will print a warning about the "uninteresting call". The rationale is: * New methods may be added to an interface after a test is written. We shouldn't fail a test just because a method it doesn't know about is called. * However, this may also mean there's a bug in the test, so Google Mock shouldn't be silent either. If the user believes these calls are harmless, he can add an `EXPECT_CALL()` to suppress the warning. However, sometimes you may want to suppress all "uninteresting call" warnings, while sometimes you may want the opposite, i.e. to treat all of them as errors. Google Mock lets you make the decision on a per-mock-object basis. Suppose your test uses a mock class `MockFoo`: ``` TEST(...) { MockFoo mock_foo; EXPECT_CALL(mock_foo, DoThis()); ... code that uses mock_foo ... } ``` If a method of `mock_foo` other than `DoThis()` is called, it will be reported by Google Mock as a warning. However, if you rewrite your test to use `NiceMock` instead, the warning will be gone, resulting in a cleaner test output: ``` using ::testing::NiceMock; TEST(...) { NiceMock mock_foo; EXPECT_CALL(mock_foo, DoThis()); ... code that uses mock_foo ... } ``` `NiceMock` is a subclass of `MockFoo`, so it can be used wherever `MockFoo` is accepted. It also works if `MockFoo`'s constructor takes some arguments, as `NiceMock` "inherits" `MockFoo`'s constructors: ``` using ::testing::NiceMock; TEST(...) { NiceMock mock_foo(5, "hi"); // Calls MockFoo(5, "hi"). EXPECT_CALL(mock_foo, DoThis()); ... code that uses mock_foo ... } ``` The usage of `StrictMock` is similar, except that it makes all uninteresting calls failures: ``` using ::testing::StrictMock; TEST(...) { StrictMock mock_foo; EXPECT_CALL(mock_foo, DoThis()); ... code that uses mock_foo ... // The test will fail if a method of mock_foo other than DoThis() // is called. } ``` There are some caveats though (I don't like them just as much as the next guy, but sadly they are side effects of C++'s limitations): 1. `NiceMock` and `StrictMock` only work for mock methods defined using the `MOCK_METHOD*` family of macros **directly** in the `MockFoo` class. If a mock method is defined in a **base class** of `MockFoo`, the "nice" or "strict" modifier may not affect it, depending on the compiler. In particular, nesting `NiceMock` and `StrictMock` (e.g. `NiceMock >`) is **not** supported. 1. The constructors of the base mock (`MockFoo`) cannot have arguments passed by non-const reference, which happens to be banned by the [Google C++ style guide](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml). 1. During the constructor or destructor of `MockFoo`, the mock object is _not_ nice or strict. This may cause surprises if the constructor or destructor calls a mock method on `this` object. (This behavior, however, is consistent with C++'s general rule: if a constructor or destructor calls a virtual method of `this` object, that method is treated as non-virtual. In other words, to the base class's constructor or destructor, `this` object behaves like an instance of the base class, not the derived class. This rule is required for safety. Otherwise a base constructor may use members of a derived class before they are initialized, or a base destructor may use members of a derived class after they have been destroyed.) Finally, you should be **very cautious** when using this feature, as the decision you make applies to **all** future changes to the mock class. If an important change is made in the interface you are mocking (and thus in the mock class), it could break your tests (if you use `StrictMock`) or let bugs pass through without a warning (if you use `NiceMock`). Therefore, try to specify the mock's behavior using explicit `EXPECT_CALL` first, and only turn to `NiceMock` or `StrictMock` as the last resort. ## Simplifying the Interface without Breaking Existing Code ## Sometimes a method has a long list of arguments that is mostly uninteresting. For example, ``` class LogSink { public: ... virtual void send(LogSeverity severity, const char* full_filename, const char* base_filename, int line, const struct tm* tm_time, const char* message, size_t message_len) = 0; }; ``` This method's argument list is lengthy and hard to work with (let's say that the `message` argument is not even 0-terminated). If we mock it as is, using the mock will be awkward. If, however, we try to simplify this interface, we'll need to fix all clients depending on it, which is often infeasible. The trick is to re-dispatch the method in the mock class: ``` class ScopedMockLog : public LogSink { public: ... virtual void send(LogSeverity severity, const char* full_filename, const char* base_filename, int line, const tm* tm_time, const char* message, size_t message_len) { // We are only interested in the log severity, full file name, and // log message. Log(severity, full_filename, std::string(message, message_len)); } // Implements the mock method: // // void Log(LogSeverity severity, // const string& file_path, // const string& message); MOCK_METHOD3(Log, void(LogSeverity severity, const string& file_path, const string& message)); }; ``` By defining a new mock method with a trimmed argument list, we make the mock class much more user-friendly. ## Alternative to Mocking Concrete Classes ## Often you may find yourself using classes that don't implement interfaces. In order to test your code that uses such a class (let's call it `Concrete`), you may be tempted to make the methods of `Concrete` virtual and then mock it. Try not to do that. Making a non-virtual function virtual is a big decision. It creates an extension point where subclasses can tweak your class' behavior. This weakens your control on the class because now it's harder to maintain the class' invariants. You should make a function virtual only when there is a valid reason for a subclass to override it. Mocking concrete classes directly is problematic as it creates a tight coupling between the class and the tests - any small change in the class may invalidate your tests and make test maintenance a pain. To avoid such problems, many programmers have been practicing "coding to interfaces": instead of talking to the `Concrete` class, your code would define an interface and talk to it. Then you implement that interface as an adaptor on top of `Concrete`. In tests, you can easily mock that interface to observe how your code is doing. This technique incurs some overhead: * You pay the cost of virtual function calls (usually not a problem). * There is more abstraction for the programmers to learn. However, it can also bring significant benefits in addition to better testability: * `Concrete`'s API may not fit your problem domain very well, as you may not be the only client it tries to serve. By designing your own interface, you have a chance to tailor it to your need - you may add higher-level functionalities, rename stuff, etc instead of just trimming the class. This allows you to write your code (user of the interface) in a more natural way, which means it will be more readable, more maintainable, and you'll be more productive. * If `Concrete`'s implementation ever has to change, you don't have to rewrite everywhere it is used. Instead, you can absorb the change in your implementation of the interface, and your other code and tests will be insulated from this change. Some people worry that if everyone is practicing this technique, they will end up writing lots of redundant code. This concern is totally understandable. However, there are two reasons why it may not be the case: * Different projects may need to use `Concrete` in different ways, so the best interfaces for them will be different. Therefore, each of them will have its own domain-specific interface on top of `Concrete`, and they will not be the same code. * If enough projects want to use the same interface, they can always share it, just like they have been sharing `Concrete`. You can check in the interface and the adaptor somewhere near `Concrete` (perhaps in a `contrib` sub-directory) and let many projects use it. You need to weigh the pros and cons carefully for your particular problem, but I'd like to assure you that the Java community has been practicing this for a long time and it's a proven effective technique applicable in a wide variety of situations. :-) ## Delegating Calls to a Fake ## Some times you have a non-trivial fake implementation of an interface. For example: ``` class Foo { public: virtual ~Foo() {} virtual char DoThis(int n) = 0; virtual void DoThat(const char* s, int* p) = 0; }; class FakeFoo : public Foo { public: virtual char DoThis(int n) { return (n > 0) ? '+' : (n < 0) ? '-' : '0'; } virtual void DoThat(const char* s, int* p) { *p = strlen(s); } }; ``` Now you want to mock this interface such that you can set expectations on it. However, you also want to use `FakeFoo` for the default behavior, as duplicating it in the mock object is, well, a lot of work. When you define the mock class using Google Mock, you can have it delegate its default action to a fake class you already have, using this pattern: ``` using ::testing::_; using ::testing::Invoke; class MockFoo : public Foo { public: // Normal mock method definitions using Google Mock. MOCK_METHOD1(DoThis, char(int n)); MOCK_METHOD2(DoThat, void(const char* s, int* p)); // Delegates the default actions of the methods to a FakeFoo object. // This must be called *before* the custom ON_CALL() statements. void DelegateToFake() { ON_CALL(*this, DoThis(_)) .WillByDefault(Invoke(&fake_, &FakeFoo::DoThis)); ON_CALL(*this, DoThat(_, _)) .WillByDefault(Invoke(&fake_, &FakeFoo::DoThat)); } private: FakeFoo fake_; // Keeps an instance of the fake in the mock. }; ``` With that, you can use `MockFoo` in your tests as usual. Just remember that if you don't explicitly set an action in an `ON_CALL()` or `EXPECT_CALL()`, the fake will be called upon to do it: ``` using ::testing::_; TEST(AbcTest, Xyz) { MockFoo foo; foo.DelegateToFake(); // Enables the fake for delegation. // Put your ON_CALL(foo, ...)s here, if any. // No action specified, meaning to use the default action. EXPECT_CALL(foo, DoThis(5)); EXPECT_CALL(foo, DoThat(_, _)); int n = 0; EXPECT_EQ('+', foo.DoThis(5)); // FakeFoo::DoThis() is invoked. foo.DoThat("Hi", &n); // FakeFoo::DoThat() is invoked. EXPECT_EQ(2, n); } ``` **Some tips:** * If you want, you can still override the default action by providing your own `ON_CALL()` or using `.WillOnce()` / `.WillRepeatedly()` in `EXPECT_CALL()`. * In `DelegateToFake()`, you only need to delegate the methods whose fake implementation you intend to use. * The general technique discussed here works for overloaded methods, but you'll need to tell the compiler which version you mean. To disambiguate a mock function (the one you specify inside the parentheses of `ON_CALL()`), see the "Selecting Between Overloaded Functions" section on this page; to disambiguate a fake function (the one you place inside `Invoke()`), use a `static_cast` to specify the function's type. * Having to mix a mock and a fake is often a sign of something gone wrong. Perhaps you haven't got used to the interaction-based way of testing yet. Or perhaps your interface is taking on too many roles and should be split up. Therefore, **don't abuse this**. We would only recommend to do it as an intermediate step when you are refactoring your code. Regarding the tip on mixing a mock and a fake, here's an example on why it may be a bad sign: Suppose you have a class `System` for low-level system operations. In particular, it does file and I/O operations. And suppose you want to test how your code uses `System` to do I/O, and you just want the file operations to work normally. If you mock out the entire `System` class, you'll have to provide a fake implementation for the file operation part, which suggests that `System` is taking on too many roles. Instead, you can define a `FileOps` interface and an `IOOps` interface and split `System`'s functionalities into the two. Then you can mock `IOOps` without mocking `FileOps`. ## Delegating Calls to a Real Object ## When using testing doubles (mocks, fakes, stubs, and etc), sometimes their behaviors will differ from those of the real objects. This difference could be either intentional (as in simulating an error such that you can test the error handling code) or unintentional. If your mocks have different behaviors than the real objects by mistake, you could end up with code that passes the tests but fails in production. You can use the _delegating-to-real_ technique to ensure that your mock has the same behavior as the real object while retaining the ability to validate calls. This technique is very similar to the delegating-to-fake technique, the difference being that we use a real object instead of a fake. Here's an example: ``` using ::testing::_; using ::testing::AtLeast; using ::testing::Invoke; class MockFoo : public Foo { public: MockFoo() { // By default, all calls are delegated to the real object. ON_CALL(*this, DoThis()) .WillByDefault(Invoke(&real_, &Foo::DoThis)); ON_CALL(*this, DoThat(_)) .WillByDefault(Invoke(&real_, &Foo::DoThat)); ... } MOCK_METHOD0(DoThis, ...); MOCK_METHOD1(DoThat, ...); ... private: Foo real_; }; ... MockFoo mock; EXPECT_CALL(mock, DoThis()) .Times(3); EXPECT_CALL(mock, DoThat("Hi")) .Times(AtLeast(1)); ... use mock in test ... ``` With this, Google Mock will verify that your code made the right calls (with the right arguments, in the right order, called the right number of times, etc), and a real object will answer the calls (so the behavior will be the same as in production). This gives you the best of both worlds. ## Delegating Calls to a Parent Class ## Ideally, you should code to interfaces, whose methods are all pure virtual. In reality, sometimes you do need to mock a virtual method that is not pure (i.e, it already has an implementation). For example: ``` class Foo { public: virtual ~Foo(); virtual void Pure(int n) = 0; virtual int Concrete(const char* str) { ... } }; class MockFoo : public Foo { public: // Mocking a pure method. MOCK_METHOD1(Pure, void(int n)); // Mocking a concrete method. Foo::Concrete() is shadowed. MOCK_METHOD1(Concrete, int(const char* str)); }; ``` Sometimes you may want to call `Foo::Concrete()` instead of `MockFoo::Concrete()`. Perhaps you want to do it as part of a stub action, or perhaps your test doesn't need to mock `Concrete()` at all (but it would be oh-so painful to have to define a new mock class whenever you don't need to mock one of its methods). The trick is to leave a back door in your mock class for accessing the real methods in the base class: ``` class MockFoo : public Foo { public: // Mocking a pure method. MOCK_METHOD1(Pure, void(int n)); // Mocking a concrete method. Foo::Concrete() is shadowed. MOCK_METHOD1(Concrete, int(const char* str)); // Use this to call Concrete() defined in Foo. int FooConcrete(const char* str) { return Foo::Concrete(str); } }; ``` Now, you can call `Foo::Concrete()` inside an action by: ``` using ::testing::_; using ::testing::Invoke; ... EXPECT_CALL(foo, Concrete(_)) .WillOnce(Invoke(&foo, &MockFoo::FooConcrete)); ``` or tell the mock object that you don't want to mock `Concrete()`: ``` using ::testing::Invoke; ... ON_CALL(foo, Concrete(_)) .WillByDefault(Invoke(&foo, &MockFoo::FooConcrete)); ``` (Why don't we just write `Invoke(&foo, &Foo::Concrete)`? If you do that, `MockFoo::Concrete()` will be called (and cause an infinite recursion) since `Foo::Concrete()` is virtual. That's just how C++ works.) # Using Matchers # ## Matching Argument Values Exactly ## You can specify exactly which arguments a mock method is expecting: ``` using ::testing::Return; ... EXPECT_CALL(foo, DoThis(5)) .WillOnce(Return('a')); EXPECT_CALL(foo, DoThat("Hello", bar)); ``` ## Using Simple Matchers ## You can use matchers to match arguments that have a certain property: ``` using ::testing::Ge; using ::testing::NotNull; using ::testing::Return; ... EXPECT_CALL(foo, DoThis(Ge(5))) // The argument must be >= 5. .WillOnce(Return('a')); EXPECT_CALL(foo, DoThat("Hello", NotNull())); // The second argument must not be NULL. ``` A frequently used matcher is `_`, which matches anything: ``` using ::testing::_; using ::testing::NotNull; ... EXPECT_CALL(foo, DoThat(_, NotNull())); ``` ## Combining Matchers ## You can build complex matchers from existing ones using `AllOf()`, `AnyOf()`, and `Not()`: ``` using ::testing::AllOf; using ::testing::Gt; using ::testing::HasSubstr; using ::testing::Ne; using ::testing::Not; ... // The argument must be > 5 and != 10. EXPECT_CALL(foo, DoThis(AllOf(Gt(5), Ne(10)))); // The first argument must not contain sub-string "blah". EXPECT_CALL(foo, DoThat(Not(HasSubstr("blah")), NULL)); ``` ## Casting Matchers ## Google Mock matchers are statically typed, meaning that the compiler can catch your mistake if you use a matcher of the wrong type (for example, if you use `Eq(5)` to match a `string` argument). Good for you! Sometimes, however, you know what you're doing and want the compiler to give you some slack. One example is that you have a matcher for `long` and the argument you want to match is `int`. While the two types aren't exactly the same, there is nothing really wrong with using a `Matcher` to match an `int` - after all, we can first convert the `int` argument to a `long` before giving it to the matcher. To support this need, Google Mock gives you the `SafeMatcherCast(m)` function. It casts a matcher `m` to type `Matcher`. To ensure safety, Google Mock checks that (let `U` be the type `m` accepts): 1. Type `T` can be implicitly cast to type `U`; 1. When both `T` and `U` are built-in arithmetic types (`bool`, integers, and floating-point numbers), the conversion from `T` to `U` is not lossy (in other words, any value representable by `T` can also be represented by `U`); and 1. When `U` is a reference, `T` must also be a reference (as the underlying matcher may be interested in the address of the `U` value). The code won't compile if any of these conditions isn't met. Here's one example: ``` using ::testing::SafeMatcherCast; // A base class and a child class. class Base { ... }; class Derived : public Base { ... }; class MockFoo : public Foo { public: MOCK_METHOD1(DoThis, void(Derived* derived)); }; ... MockFoo foo; // m is a Matcher we got from somewhere. EXPECT_CALL(foo, DoThis(SafeMatcherCast(m))); ``` If you find `SafeMatcherCast(m)` too limiting, you can use a similar function `MatcherCast(m)`. The difference is that `MatcherCast` works as long as you can `static_cast` type `T` to type `U`. `MatcherCast` essentially lets you bypass C++'s type system (`static_cast` isn't always safe as it could throw away information, for example), so be careful not to misuse/abuse it. ## Selecting Between Overloaded Functions ## If you expect an overloaded function to be called, the compiler may need some help on which overloaded version it is. To disambiguate functions overloaded on the const-ness of this object, use the `Const()` argument wrapper. ``` using ::testing::ReturnRef; class MockFoo : public Foo { ... MOCK_METHOD0(GetBar, Bar&()); MOCK_CONST_METHOD0(GetBar, const Bar&()); }; ... MockFoo foo; Bar bar1, bar2; EXPECT_CALL(foo, GetBar()) // The non-const GetBar(). .WillOnce(ReturnRef(bar1)); EXPECT_CALL(Const(foo), GetBar()) // The const GetBar(). .WillOnce(ReturnRef(bar2)); ``` (`Const()` is defined by Google Mock and returns a `const` reference to its argument.) To disambiguate overloaded functions with the same number of arguments but different argument types, you may need to specify the exact type of a matcher, either by wrapping your matcher in `Matcher()`, or using a matcher whose type is fixed (`TypedEq`, `An()`, etc): ``` using ::testing::An; using ::testing::Lt; using ::testing::Matcher; using ::testing::TypedEq; class MockPrinter : public Printer { public: MOCK_METHOD1(Print, void(int n)); MOCK_METHOD1(Print, void(char c)); }; TEST(PrinterTest, Print) { MockPrinter printer; EXPECT_CALL(printer, Print(An())); // void Print(int); EXPECT_CALL(printer, Print(Matcher(Lt(5)))); // void Print(int); EXPECT_CALL(printer, Print(TypedEq('a'))); // void Print(char); printer.Print(3); printer.Print(6); printer.Print('a'); } ``` ## Performing Different Actions Based on the Arguments ## When a mock method is called, the _last_ matching expectation that's still active will be selected (think "newer overrides older"). So, you can make a method do different things depending on its argument values like this: ``` using ::testing::_; using ::testing::Lt; using ::testing::Return; ... // The default case. EXPECT_CALL(foo, DoThis(_)) .WillRepeatedly(Return('b')); // The more specific case. EXPECT_CALL(foo, DoThis(Lt(5))) .WillRepeatedly(Return('a')); ``` Now, if `foo.DoThis()` is called with a value less than 5, `'a'` will be returned; otherwise `'b'` will be returned. ## Matching Multiple Arguments as a Whole ## Sometimes it's not enough to match the arguments individually. For example, we may want to say that the first argument must be less than the second argument. The `With()` clause allows us to match all arguments of a mock function as a whole. For example, ``` using ::testing::_; using ::testing::Lt; using ::testing::Ne; ... EXPECT_CALL(foo, InRange(Ne(0), _)) .With(Lt()); ``` says that the first argument of `InRange()` must not be 0, and must be less than the second argument. The expression inside `With()` must be a matcher of type `Matcher >`, where `A1`, ..., `An` are the types of the function arguments. You can also write `AllArgs(m)` instead of `m` inside `.With()`. The two forms are equivalent, but `.With(AllArgs(Lt()))` is more readable than `.With(Lt())`. You can use `Args(m)` to match the `n` selected arguments against `m`. For example, ``` using ::testing::_; using ::testing::AllOf; using ::testing::Args; using ::testing::Lt; ... EXPECT_CALL(foo, Blah(_, _, _)) .With(AllOf(Args<0, 1>(Lt()), Args<1, 2>(Lt()))); ``` says that `Blah()` will be called with arguments `x`, `y`, and `z` where `x < y < z`. As a convenience and example, Google Mock provides some matchers for 2-tuples, including the `Lt()` matcher above. See the [CheatSheet](V1_5_CheatSheet.md) for the complete list. ## Using Matchers as Predicates ## Have you noticed that a matcher is just a fancy predicate that also knows how to describe itself? Many existing algorithms take predicates as arguments (e.g. those defined in STL's `` header), and it would be a shame if Google Mock matchers are not allowed to participate. Luckily, you can use a matcher where a unary predicate functor is expected by wrapping it inside the `Matches()` function. For example, ``` #include #include std::vector v; ... // How many elements in v are >= 10? const int count = count_if(v.begin(), v.end(), Matches(Ge(10))); ``` Since you can build complex matchers from simpler ones easily using Google Mock, this gives you a way to conveniently construct composite predicates (doing the same using STL's `` header is just painful). For example, here's a predicate that's satisfied by any number that is >= 0, <= 100, and != 50: ``` Matches(AllOf(Ge(0), Le(100), Ne(50))) ``` ## Using Matchers in Google Test Assertions ## Since matchers are basically predicates that also know how to describe themselves, there is a way to take advantage of them in [Google Test](http://code.google.com/p/googletest/) assertions. It's called `ASSERT_THAT` and `EXPECT_THAT`: ``` ASSERT_THAT(value, matcher); // Asserts that value matches matcher. EXPECT_THAT(value, matcher); // The non-fatal version. ``` For example, in a Google Test test you can write: ``` #include using ::testing::AllOf; using ::testing::Ge; using ::testing::Le; using ::testing::MatchesRegex; using ::testing::StartsWith; ... EXPECT_THAT(Foo(), StartsWith("Hello")); EXPECT_THAT(Bar(), MatchesRegex("Line \\d+")); ASSERT_THAT(Baz(), AllOf(Ge(5), Le(10))); ``` which (as you can probably guess) executes `Foo()`, `Bar()`, and `Baz()`, and verifies that: * `Foo()` returns a string that starts with `"Hello"`. * `Bar()` returns a string that matches regular expression `"Line \\d+"`. * `Baz()` returns a number in the range [5, 10]. The nice thing about these macros is that _they read like English_. They generate informative messages too. For example, if the first `EXPECT_THAT()` above fails, the message will be something like: ``` Value of: Foo() Actual: "Hi, world!" Expected: starts with "Hello" ``` **Credit:** The idea of `(ASSERT|EXPECT)_THAT` was stolen from the [Hamcrest](http://code.google.com/p/hamcrest/) project, which adds `assertThat()` to JUnit. ## Using Predicates as Matchers ## Google Mock provides a built-in set of matchers. In case you find them lacking, you can use an arbitray unary predicate function or functor as a matcher - as long as the predicate accepts a value of the type you want. You do this by wrapping the predicate inside the `Truly()` function, for example: ``` using ::testing::Truly; int IsEven(int n) { return (n % 2) == 0 ? 1 : 0; } ... // Bar() must be called with an even number. EXPECT_CALL(foo, Bar(Truly(IsEven))); ``` Note that the predicate function / functor doesn't have to return `bool`. It works as long as the return value can be used as the condition in statement `if (condition) ...`. ## Matching Arguments that Are Not Copyable ## When you do an `EXPECT_CALL(mock_obj, Foo(bar))`, Google Mock saves away a copy of `bar`. When `Foo()` is called later, Google Mock compares the argument to `Foo()` with the saved copy of `bar`. This way, you don't need to worry about `bar` being modified or destroyed after the `EXPECT_CALL()` is executed. The same is true when you use matchers like `Eq(bar)`, `Le(bar)`, and so on. But what if `bar` cannot be copied (i.e. has no copy constructor)? You could define your own matcher function and use it with `Truly()`, as the previous couple of recipes have shown. Or, you may be able to get away from it if you can guarantee that `bar` won't be changed after the `EXPECT_CALL()` is executed. Just tell Google Mock that it should save a reference to `bar`, instead of a copy of it. Here's how: ``` using ::testing::Eq; using ::testing::ByRef; using ::testing::Lt; ... // Expects that Foo()'s argument == bar. EXPECT_CALL(mock_obj, Foo(Eq(ByRef(bar)))); // Expects that Foo()'s argument < bar. EXPECT_CALL(mock_obj, Foo(Lt(ByRef(bar)))); ``` Remember: if you do this, don't change `bar` after the `EXPECT_CALL()`, or the result is undefined. ## Validating a Member of an Object ## Often a mock function takes a reference to object as an argument. When matching the argument, you may not want to compare the entire object against a fixed object, as that may be over-specification. Instead, you may need to validate a certain member variable or the result of a certain getter method of the object. You can do this with `Field()` and `Property()`. More specifically, ``` Field(&Foo::bar, m) ``` is a matcher that matches a `Foo` object whose `bar` member variable satisfies matcher `m`. ``` Property(&Foo::baz, m) ``` is a matcher that matches a `Foo` object whose `baz()` method returns a value that satisfies matcher `m`. For example: > | `Field(&Foo::number, Ge(3))` | Matches `x` where `x.number >= 3`. | |:-----------------------------|:-----------------------------------| > | `Property(&Foo::name, StartsWith("John "))` | Matches `x` where `x.name()` starts with `"John "`. | Note that in `Property(&Foo::baz, ...)`, method `baz()` must take no argument and be declared as `const`. BTW, `Field()` and `Property()` can also match plain pointers to objects. For instance, ``` Field(&Foo::number, Ge(3)) ``` matches a plain pointer `p` where `p->number >= 3`. If `p` is `NULL`, the match will always fail regardless of the inner matcher. What if you want to validate more than one members at the same time? Remember that there is `AllOf()`. ## Validating the Value Pointed to by a Pointer Argument ## C++ functions often take pointers as arguments. You can use matchers like `NULL`, `NotNull()`, and other comparison matchers to match a pointer, but what if you want to make sure the value _pointed to_ by the pointer, instead of the pointer itself, has a certain property? Well, you can use the `Pointee(m)` matcher. `Pointee(m)` matches a pointer iff `m` matches the value the pointer points to. For example: ``` using ::testing::Ge; using ::testing::Pointee; ... EXPECT_CALL(foo, Bar(Pointee(Ge(3)))); ``` expects `foo.Bar()` to be called with a pointer that points to a value greater than or equal to 3. One nice thing about `Pointee()` is that it treats a `NULL` pointer as a match failure, so you can write `Pointee(m)` instead of ``` AllOf(NotNull(), Pointee(m)) ``` without worrying that a `NULL` pointer will crash your test. Also, did we tell you that `Pointee()` works with both raw pointers **and** smart pointers (`linked_ptr`, `shared_ptr`, `scoped_ptr`, and etc)? What if you have a pointer to pointer? You guessed it - you can use nested `Pointee()` to probe deeper inside the value. For example, `Pointee(Pointee(Lt(3)))` matches a pointer that points to a pointer that points to a number less than 3 (what a mouthful...). ## Testing a Certain Property of an Object ## Sometimes you want to specify that an object argument has a certain property, but there is no existing matcher that does this. If you want good error messages, you should define a matcher. If you want to do it quick and dirty, you could get away with writing an ordinary function. Let's say you have a mock function that takes an object of type `Foo`, which has an `int bar()` method and an `int baz()` method, and you want to constrain that the argument's `bar()` value plus its `baz()` value is a given number. Here's how you can define a matcher to do it: ``` using ::testing::MatcherInterface; using ::testing::MatchResultListener; class BarPlusBazEqMatcher : public MatcherInterface { public: explicit BarPlusBazEqMatcher(int expected_sum) : expected_sum_(expected_sum) {} virtual bool MatchAndExplain(const Foo& foo, MatchResultListener* listener) const { return (foo.bar() + foo.baz()) == expected_sum_; } virtual void DescribeTo(::std::ostream* os) const { *os << "bar() + baz() equals " << expected_sum_; } virtual void DescribeNegationTo(::std::ostream* os) const { *os << "bar() + baz() does not equal " << expected_sum_; } private: const int expected_sum_; }; inline Matcher BarPlusBazEq(int expected_sum) { return MakeMatcher(new BarPlusBazEqMatcher(expected_sum)); } ... EXPECT_CALL(..., DoThis(BarPlusBazEq(5)))...; ``` ## Matching Containers ## Sometimes an STL container (e.g. list, vector, map, ...) is passed to a mock function and you may want to validate it. Since most STL containers support the `==` operator, you can write `Eq(expected_container)` or simply `expected_container` to match a container exactly. Sometimes, though, you may want to be more flexible (for example, the first element must be an exact match, but the second element can be any positive number, and so on). Also, containers used in tests often have a small number of elements, and having to define the expected container out-of-line is a bit of a hassle. You can use the `ElementsAre()` matcher in such cases: ``` using ::testing::_; using ::testing::ElementsAre; using ::testing::Gt; ... MOCK_METHOD1(Foo, void(const vector& numbers)); ... EXPECT_CALL(mock, Foo(ElementsAre(1, Gt(0), _, 5))); ``` The above matcher says that the container must have 4 elements, which must be 1, greater than 0, anything, and 5 respectively. `ElementsAre()` is overloaded to take 0 to 10 arguments. If more are needed, you can place them in a C-style array and use `ElementsAreArray()` instead: ``` using ::testing::ElementsAreArray; ... // ElementsAreArray accepts an array of element values. const int expected_vector1[] = { 1, 5, 2, 4, ... }; EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector1))); // Or, an array of element matchers. Matcher expected_vector2 = { 1, Gt(2), _, 3, ... }; EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector2))); ``` In case the array needs to be dynamically created (and therefore the array size cannot be inferred by the compiler), you can give `ElementsAreArray()` an additional argument to specify the array size: ``` using ::testing::ElementsAreArray; ... int* const expected_vector3 = new int[count]; ... fill expected_vector3 with values ... EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector3, count))); ``` **Tips:** * `ElementAre*()` works with _any_ container that implements the STL iterator concept (i.e. it has a `const_iterator` type and supports `begin()/end()`) and supports `size()`, not just the ones defined in STL. It will even work with container types yet to be written - as long as they follows the above pattern. * You can use nested `ElementAre*()` to match nested (multi-dimensional) containers. * If the container is passed by pointer instead of by reference, just write `Pointee(ElementsAre*(...))`. * The order of elements _matters_ for `ElementsAre*()`. Therefore don't use it with containers whose element order is undefined (e.g. `hash_map`). ## Sharing Matchers ## Under the hood, a Google Mock matcher object consists of a pointer to a ref-counted implementation object. Copying matchers is allowed and very efficient, as only the pointer is copied. When the last matcher that references the implementation object dies, the implementation object will be deleted. Therefore, if you have some complex matcher that you want to use again and again, there is no need to build it everytime. Just assign it to a matcher variable and use that variable repeatedly! For example, ``` Matcher in_range = AllOf(Gt(5), Le(10)); ... use in_range as a matcher in multiple EXPECT_CALLs ... ``` # Setting Expectations # ## Ignoring Uninteresting Calls ## If you are not interested in how a mock method is called, just don't say anything about it. In this case, if the method is ever called, Google Mock will perform its default action to allow the test program to continue. If you are not happy with the default action taken by Google Mock, you can override it using `DefaultValue::Set()` (described later in this document) or `ON_CALL()`. Please note that once you expressed interest in a particular mock method (via `EXPECT_CALL()`), all invocations to it must match some expectation. If this function is called but the arguments don't match any `EXPECT_CALL()` statement, it will be an error. ## Disallowing Unexpected Calls ## If a mock method shouldn't be called at all, explicitly say so: ``` using ::testing::_; ... EXPECT_CALL(foo, Bar(_)) .Times(0); ``` If some calls to the method are allowed, but the rest are not, just list all the expected calls: ``` using ::testing::AnyNumber; using ::testing::Gt; ... EXPECT_CALL(foo, Bar(5)); EXPECT_CALL(foo, Bar(Gt(10))) .Times(AnyNumber()); ``` A call to `foo.Bar()` that doesn't match any of the `EXPECT_CALL()` statements will be an error. ## Expecting Ordered Calls ## Although an `EXPECT_CALL()` statement defined earlier takes precedence when Google Mock tries to match a function call with an expectation, by default calls don't have to happen in the order `EXPECT_CALL()` statements are written. For example, if the arguments match the matchers in the third `EXPECT_CALL()`, but not those in the first two, then the third expectation will be used. If you would rather have all calls occur in the order of the expectations, put the `EXPECT_CALL()` statements in a block where you define a variable of type `InSequence`: ``` using ::testing::_; using ::testing::InSequence; { InSequence s; EXPECT_CALL(foo, DoThis(5)); EXPECT_CALL(bar, DoThat(_)) .Times(2); EXPECT_CALL(foo, DoThis(6)); } ``` In this example, we expect a call to `foo.DoThis(5)`, followed by two calls to `bar.DoThat()` where the argument can be anything, which are in turn followed by a call to `foo.DoThis(6)`. If a call occurred out-of-order, Google Mock will report an error. ## Expecting Partially Ordered Calls ## Sometimes requiring everything to occur in a predetermined order can lead to brittle tests. For example, we may care about `A` occurring before both `B` and `C`, but aren't interested in the relative order of `B` and `C`. In this case, the test should reflect our real intent, instead of being overly constraining. Google Mock allows you to impose an arbitrary DAG (directed acyclic graph) on the calls. One way to express the DAG is to use the [After](V1_5_CheatSheet#The_After_Clause.md) clause of `EXPECT_CALL`. Another way is via the `InSequence()` clause (not the same as the `InSequence` class), which we borrowed from jMock 2. It's less flexible than `After()`, but more convenient when you have long chains of sequential calls, as it doesn't require you to come up with different names for the expectations in the chains. Here's how it works: If we view `EXPECT_CALL()` statements as nodes in a graph, and add an edge from node A to node B wherever A must occur before B, we can get a DAG. We use the term "sequence" to mean a directed path in this DAG. Now, if we decompose the DAG into sequences, we just need to know which sequences each `EXPECT_CALL()` belongs to in order to be able to reconstruct the orginal DAG. So, to specify the partial order on the expectations we need to do two things: first to define some `Sequence` objects, and then for each `EXPECT_CALL()` say which `Sequence` objects it is part of. Expectations in the same sequence must occur in the order they are written. For example, ``` using ::testing::Sequence; Sequence s1, s2; EXPECT_CALL(foo, A()) .InSequence(s1, s2); EXPECT_CALL(bar, B()) .InSequence(s1); EXPECT_CALL(bar, C()) .InSequence(s2); EXPECT_CALL(foo, D()) .InSequence(s2); ``` specifies the following DAG (where `s1` is `A -> B`, and `s2` is `A -> C -> D`): ``` +---> B | A ---| | +---> C ---> D ``` This means that A must occur before B and C, and C must occur before D. There's no restriction about the order other than these. ## Controlling When an Expectation Retires ## When a mock method is called, Google Mock only consider expectations that are still active. An expectation is active when created, and becomes inactive (aka _retires_) when a call that has to occur later has occurred. For example, in ``` using ::testing::_; using ::testing::Sequence; Sequence s1, s2; EXPECT_CALL(log, Log(WARNING, _, "File too large.")) // #1 .Times(AnyNumber()) .InSequence(s1, s2); EXPECT_CALL(log, Log(WARNING, _, "Data set is empty.")) // #2 .InSequence(s1); EXPECT_CALL(log, Log(WARNING, _, "User not found.")) // #3 .InSequence(s2); ``` as soon as either #2 or #3 is matched, #1 will retire. If a warning `"File too large."` is logged after this, it will be an error. Note that an expectation doesn't retire automatically when it's saturated. For example, ``` using ::testing::_; ... EXPECT_CALL(log, Log(WARNING, _, _)); // #1 EXPECT_CALL(log, Log(WARNING, _, "File too large.")); // #2 ``` says that there will be exactly one warning with the message `"File too large."`. If the second warning contains this message too, #2 will match again and result in an upper-bound-violated error. If this is not what you want, you can ask an expectation to retire as soon as it becomes saturated: ``` using ::testing::_; ... EXPECT_CALL(log, Log(WARNING, _, _)); // #1 EXPECT_CALL(log, Log(WARNING, _, "File too large.")) // #2 .RetiresOnSaturation(); ``` Here #2 can be used only once, so if you have two warnings with the message `"File too large."`, the first will match #2 and the second will match #1 - there will be no error. # Using Actions # ## Returning References from Mock Methods ## If a mock function's return type is a reference, you need to use `ReturnRef()` instead of `Return()` to return a result: ``` using ::testing::ReturnRef; class MockFoo : public Foo { public: MOCK_METHOD0(GetBar, Bar&()); }; ... MockFoo foo; Bar bar; EXPECT_CALL(foo, GetBar()) .WillOnce(ReturnRef(bar)); ``` ## Combining Actions ## Want to do more than one thing when a function is called? That's fine. `DoAll()` allow you to do sequence of actions every time. Only the return value of the last action in the sequence will be used. ``` using ::testing::DoAll; class MockFoo : public Foo { public: MOCK_METHOD1(Bar, bool(int n)); }; ... EXPECT_CALL(foo, Bar(_)) .WillOnce(DoAll(action_1, action_2, ... action_n)); ``` ## Mocking Side Effects ## Sometimes a method exhibits its effect not via returning a value but via side effects. For example, it may change some global state or modify an output argument. To mock side effects, in general you can define your own action by implementing `::testing::ActionInterface`. If all you need to do is to change an output argument, the built-in `SetArgumentPointee()` action is convenient: ``` using ::testing::SetArgumentPointee; class MockMutator : public Mutator { public: MOCK_METHOD2(Mutate, void(bool mutate, int* value)); ... }; ... MockMutator mutator; EXPECT_CALL(mutator, Mutate(true, _)) .WillOnce(SetArgumentPointee<1>(5)); ``` In this example, when `mutator.Mutate()` is called, we will assign 5 to the `int` variable pointed to by argument #1 (0-based). `SetArgumentPointee()` conveniently makes an internal copy of the value you pass to it, removing the need to keep the value in scope and alive. The implication however is that the value must have a copy constructor and assignment operator. If the mock method also needs to return a value as well, you can chain `SetArgumentPointee()` with `Return()` using `DoAll()`: ``` using ::testing::_; using ::testing::Return; using ::testing::SetArgumentPointee; class MockMutator : public Mutator { public: ... MOCK_METHOD1(MutateInt, bool(int* value)); }; ... MockMutator mutator; EXPECT_CALL(mutator, MutateInt(_)) .WillOnce(DoAll(SetArgumentPointee<0>(5), Return(true))); ``` If the output argument is an array, use the `SetArrayArgument(first, last)` action instead. It copies the elements in source range `[first, last)` to the array pointed to by the `N`-th (0-based) argument: ``` using ::testing::NotNull; using ::testing::SetArrayArgument; class MockArrayMutator : public ArrayMutator { public: MOCK_METHOD2(Mutate, void(int* values, int num_values)); ... }; ... MockArrayMutator mutator; int values[5] = { 1, 2, 3, 4, 5 }; EXPECT_CALL(mutator, Mutate(NotNull(), 5)) .WillOnce(SetArrayArgument<0>(values, values + 5)); ``` This also works when the argument is an output iterator: ``` using ::testing::_; using ::testing::SeArrayArgument; class MockRolodex : public Rolodex { public: MOCK_METHOD1(GetNames, void(std::back_insert_iterator >)); ... }; ... MockRolodex rolodex; vector names; names.push_back("George"); names.push_back("John"); names.push_back("Thomas"); EXPECT_CALL(rolodex, GetNames(_)) .WillOnce(SetArrayArgument<0>(names.begin(), names.end())); ``` ## Changing a Mock Object's Behavior Based on the State ## If you expect a call to change the behavior of a mock object, you can use `::testing::InSequence` to specify different behaviors before and after the call: ``` using ::testing::InSequence; using ::testing::Return; ... { InSequence seq; EXPECT_CALL(my_mock, IsDirty()) .WillRepeatedly(Return(true)); EXPECT_CALL(my_mock, Flush()); EXPECT_CALL(my_mock, IsDirty()) .WillRepeatedly(Return(false)); } my_mock.FlushIfDirty(); ``` This makes `my_mock.IsDirty()` return `true` before `my_mock.Flush()` is called and return `false` afterwards. If the behavior change is more complex, you can store the effects in a variable and make a mock method get its return value from that variable: ``` using ::testing::_; using ::testing::SaveArg; using ::testing::Return; ACTION_P(ReturnPointee, p) { return *p; } ... int previous_value = 0; EXPECT_CALL(my_mock, GetPrevValue()) .WillRepeatedly(ReturnPointee(&previous_value)); EXPECT_CALL(my_mock, UpdateValue(_)) .WillRepeatedly(SaveArg<0>(&previous_value)); my_mock.DoSomethingToUpdateValue(); ``` Here `my_mock.GetPrevValue()` will always return the argument of the last `UpdateValue()` call. ## Setting the Default Value for a Return Type ## If a mock method's return type is a built-in C++ type or pointer, by default it will return 0 when invoked. You only need to specify an action if this default value doesn't work for you. Sometimes, you may want to change this default value, or you may want to specify a default value for types Google Mock doesn't know about. You can do this using the `::testing::DefaultValue` class template: ``` class MockFoo : public Foo { public: MOCK_METHOD0(CalculateBar, Bar()); }; ... Bar default_bar; // Sets the default return value for type Bar. DefaultValue::Set(default_bar); MockFoo foo; // We don't need to specify an action here, as the default // return value works for us. EXPECT_CALL(foo, CalculateBar()); foo.CalculateBar(); // This should return default_bar. // Unsets the default return value. DefaultValue::Clear(); ``` Please note that changing the default value for a type can make you tests hard to understand. We recommend you to use this feature judiciously. For example, you may want to make sure the `Set()` and `Clear()` calls are right next to the code that uses your mock. ## Setting the Default Actions for a Mock Method ## You've learned how to change the default value of a given type. However, this may be too coarse for your purpose: perhaps you have two mock methods with the same return type and you want them to have different behaviors. The `ON_CALL()` macro allows you to customize your mock's behavior at the method level: ``` using ::testing::_; using ::testing::AnyNumber; using ::testing::Gt; using ::testing::Return; ... ON_CALL(foo, Sign(_)) .WillByDefault(Return(-1)); ON_CALL(foo, Sign(0)) .WillByDefault(Return(0)); ON_CALL(foo, Sign(Gt(0))) .WillByDefault(Return(1)); EXPECT_CALL(foo, Sign(_)) .Times(AnyNumber()); foo.Sign(5); // This should return 1. foo.Sign(-9); // This should return -1. foo.Sign(0); // This should return 0. ``` As you may have guessed, when there are more than one `ON_CALL()` statements, the news order take precedence over the older ones. In other words, the **last** one that matches the function arguments will be used. This matching order allows you to set up the common behavior in a mock object's constructor or the test fixture's set-up phase and specialize the mock's behavior later. ## Using Functions/Methods/Functors as Actions ## If the built-in actions don't suit you, you can easily use an existing function, method, or functor as an action: ``` using ::testing::_; using ::testing::Invoke; class MockFoo : public Foo { public: MOCK_METHOD2(Sum, int(int x, int y)); MOCK_METHOD1(ComplexJob, bool(int x)); }; int CalculateSum(int x, int y) { return x + y; } class Helper { public: bool ComplexJob(int x); }; ... MockFoo foo; Helper helper; EXPECT_CALL(foo, Sum(_, _)) .WillOnce(Invoke(CalculateSum)); EXPECT_CALL(foo, ComplexJob(_)) .WillOnce(Invoke(&helper, &Helper::ComplexJob)); foo.Sum(5, 6); // Invokes CalculateSum(5, 6). foo.ComplexJob(10); // Invokes helper.ComplexJob(10); ``` The only requirement is that the type of the function, etc must be _compatible_ with the signature of the mock function, meaning that the latter's arguments can be implicitly converted to the corresponding arguments of the former, and the former's return type can be implicitly converted to that of the latter. So, you can invoke something whose type is _not_ exactly the same as the mock function, as long as it's safe to do so - nice, huh? ## Invoking a Function/Method/Functor Without Arguments ## `Invoke()` is very useful for doing actions that are more complex. It passes the mock function's arguments to the function or functor being invoked such that the callee has the full context of the call to work with. If the invoked function is not interested in some or all of the arguments, it can simply ignore them. Yet, a common pattern is that a test author wants to invoke a function without the arguments of the mock function. `Invoke()` allows her to do that using a wrapper function that throws away the arguments before invoking an underlining nullary function. Needless to say, this can be tedious and obscures the intent of the test. `InvokeWithoutArgs()` solves this problem. It's like `Invoke()` except that it doesn't pass the mock function's arguments to the callee. Here's an example: ``` using ::testing::_; using ::testing::InvokeWithoutArgs; class MockFoo : public Foo { public: MOCK_METHOD1(ComplexJob, bool(int n)); }; bool Job1() { ... } ... MockFoo foo; EXPECT_CALL(foo, ComplexJob(_)) .WillOnce(InvokeWithoutArgs(Job1)); foo.ComplexJob(10); // Invokes Job1(). ``` ## Invoking an Argument of the Mock Function ## Sometimes a mock function will receive a function pointer or a functor (in other words, a "callable") as an argument, e.g. ``` class MockFoo : public Foo { public: MOCK_METHOD2(DoThis, bool(int n, bool (*fp)(int))); }; ``` and you may want to invoke this callable argument: ``` using ::testing::_; ... MockFoo foo; EXPECT_CALL(foo, DoThis(_, _)) .WillOnce(...); // Will execute (*fp)(5), where fp is the // second argument DoThis() receives. ``` Arghh, you need to refer to a mock function argument but C++ has no lambda (yet), so you have to define your own action. :-( Or do you really? Well, Google Mock has an action to solve _exactly_ this problem: ``` InvokeArgument(arg_1, arg_2, ..., arg_m) ``` will invoke the `N`-th (0-based) argument the mock function receives, with `arg_1`, `arg_2`, ..., and `arg_m`. No matter if the argument is a function pointer or a functor, Google Mock handles them both. With that, you could write: ``` using ::testing::_; using ::testing::InvokeArgument; ... EXPECT_CALL(foo, DoThis(_, _)) .WillOnce(InvokeArgument<1>(5)); // Will execute (*fp)(5), where fp is the // second argument DoThis() receives. ``` What if the callable takes an argument by reference? No problem - just wrap it inside `ByRef()`: ``` ... MOCK_METHOD1(Bar, bool(bool (*fp)(int, const Helper&))); ... using ::testing::_; using ::testing::ByRef; using ::testing::InvokeArgument; ... MockFoo foo; Helper helper; ... EXPECT_CALL(foo, Bar(_)) .WillOnce(InvokeArgument<0>(5, ByRef(helper))); // ByRef(helper) guarantees that a reference to helper, not a copy of it, // will be passed to the callable. ``` What if the callable takes an argument by reference and we do **not** wrap the argument in `ByRef()`? Then `InvokeArgument()` will _make a copy_ of the argument, and pass a _reference to the copy_, instead of a reference to the original value, to the callable. This is especially handy when the argument is a temporary value: ``` ... MOCK_METHOD1(DoThat, bool(bool (*f)(const double& x, const string& s))); ... using ::testing::_; using ::testing::InvokeArgument; ... MockFoo foo; ... EXPECT_CALL(foo, DoThat(_)) .WillOnce(InvokeArgument<0>(5.0, string("Hi"))); // Will execute (*f)(5.0, string("Hi")), where f is the function pointer // DoThat() receives. Note that the values 5.0 and string("Hi") are // temporary and dead once the EXPECT_CALL() statement finishes. Yet // it's fine to perform this action later, since a copy of the values // are kept inside the InvokeArgument action. ``` ## Ignoring an Action's Result ## Sometimes you have an action that returns _something_, but you need an action that returns `void` (perhaps you want to use it in a mock function that returns `void`, or perhaps it needs to be used in `DoAll()` and it's not the last in the list). `IgnoreResult()` lets you do that. For example: ``` using ::testing::_; using ::testing::Invoke; using ::testing::Return; int Process(const MyData& data); string DoSomething(); class MockFoo : public Foo { public: MOCK_METHOD1(Abc, void(const MyData& data)); MOCK_METHOD0(Xyz, bool()); }; ... MockFoo foo; EXPECT_CALL(foo, Abc(_)) // .WillOnce(Invoke(Process)); // The above line won't compile as Process() returns int but Abc() needs // to return void. .WillOnce(IgnoreResult(Invoke(Process))); EXPECT_CALL(foo, Xyz()) .WillOnce(DoAll(IgnoreResult(Invoke(DoSomething)), // Ignores the string DoSomething() returns. Return(true))); ``` Note that you **cannot** use `IgnoreResult()` on an action that already returns `void`. Doing so will lead to ugly compiler errors. ## Selecting an Action's Arguments ## Say you have a mock function `Foo()` that takes seven arguments, and you have a custom action that you want to invoke when `Foo()` is called. Trouble is, the custom action only wants three arguments: ``` using ::testing::_; using ::testing::Invoke; ... MOCK_METHOD7(Foo, bool(bool visible, const string& name, int x, int y, const map, double>& weight, double min_weight, double max_wight)); ... bool IsVisibleInQuadrant1(bool visible, int x, int y) { return visible && x >= 0 && y >= 0; } ... EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) .WillOnce(Invoke(IsVisibleInQuadrant1)); // Uh, won't compile. :-( ``` To please the compiler God, you can to define an "adaptor" that has the same signature as `Foo()` and calls the custom action with the right arguments: ``` using ::testing::_; using ::testing::Invoke; bool MyIsVisibleInQuadrant1(bool visible, const string& name, int x, int y, const map, double>& weight, double min_weight, double max_wight) { return IsVisibleInQuadrant1(visible, x, y); } ... EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) .WillOnce(Invoke(MyIsVisibleInQuadrant1)); // Now it works. ``` But isn't this awkward? Google Mock provides a generic _action adaptor_, so you can spend your time minding more important business than writing your own adaptors. Here's the syntax: ``` WithArgs(action) ``` creates an action that passes the arguments of the mock function at the given indices (0-based) to the inner `action` and performs it. Using `WithArgs`, our original example can be written as: ``` using ::testing::_; using ::testing::Invoke; using ::testing::WithArgs; ... EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) .WillOnce(WithArgs<0, 2, 3>(Invoke(IsVisibleInQuadrant1))); // No need to define your own adaptor. ``` For better readability, Google Mock also gives you: * `WithoutArgs(action)` when the inner `action` takes _no_ argument, and * `WithArg(action)` (no `s` after `Arg`) when the inner `action` takes _one_ argument. As you may have realized, `InvokeWithoutArgs(...)` is just syntactic sugar for `WithoutArgs(Inovke(...))`. Here are more tips: * The inner action used in `WithArgs` and friends does not have to be `Invoke()` -- it can be anything. * You can repeat an argument in the argument list if necessary, e.g. `WithArgs<2, 3, 3, 5>(...)`. * You can change the order of the arguments, e.g. `WithArgs<3, 2, 1>(...)`. * The types of the selected arguments do _not_ have to match the signature of the inner action exactly. It works as long as they can be implicitly converted to the corresponding arguments of the inner action. For example, if the 4-th argument of the mock function is an `int` and `my_action` takes a `double`, `WithArg<4>(my_action)` will work. ## Ignoring Arguments in Action Functions ## The selecting-an-action's-arguments recipe showed us one way to make a mock function and an action with incompatible argument lists fit together. The downside is that wrapping the action in `WithArgs<...>()` can get tedious for people writing the tests. If you are defining a function, method, or functor to be used with `Invoke*()`, and you are not interested in some of its arguments, an alternative to `WithArgs` is to declare the uninteresting arguments as `Unused`. This makes the definition less cluttered and less fragile in case the types of the uninteresting arguments change. It could also increase the chance the action function can be reused. For example, given ``` MOCK_METHOD3(Foo, double(const string& label, double x, double y)); MOCK_METHOD3(Bar, double(int index, double x, double y)); ``` instead of ``` using ::testing::_; using ::testing::Invoke; double DistanceToOriginWithLabel(const string& label, double x, double y) { return sqrt(x*x + y*y); } double DistanceToOriginWithIndex(int index, double x, double y) { return sqrt(x*x + y*y); } ... EXEPCT_CALL(mock, Foo("abc", _, _)) .WillOnce(Invoke(DistanceToOriginWithLabel)); EXEPCT_CALL(mock, Bar(5, _, _)) .WillOnce(Invoke(DistanceToOriginWithIndex)); ``` you could write ``` using ::testing::_; using ::testing::Invoke; using ::testing::Unused; double DistanceToOrigin(Unused, double x, double y) { return sqrt(x*x + y*y); } ... EXEPCT_CALL(mock, Foo("abc", _, _)) .WillOnce(Invoke(DistanceToOrigin)); EXEPCT_CALL(mock, Bar(5, _, _)) .WillOnce(Invoke(DistanceToOrigin)); ``` ## Sharing Actions ## Just like matchers, a Google Mock action object consists of a pointer to a ref-counted implementation object. Therefore copying actions is also allowed and very efficient. When the last action that references the implementation object dies, the implementation object will be deleted. If you have some complex action that you want to use again and again, you may not have to build it from scratch everytime. If the action doesn't have an internal state (i.e. if it always does the same thing no matter how many times it has been called), you can assign it to an action variable and use that variable repeatedly. For example: ``` Action set_flag = DoAll(SetArgumentPointee<0>(5), Return(true)); ... use set_flag in .WillOnce() and .WillRepeatedly() ... ``` However, if the action has its own state, you may be surprised if you share the action object. Suppose you have an action factory `IncrementCounter(init)` which creates an action that increments and returns a counter whose initial value is `init`, using two actions created from the same expression and using a shared action will exihibit different behaviors. Example: ``` EXPECT_CALL(foo, DoThis()) .WillRepeatedly(IncrementCounter(0)); EXPECT_CALL(foo, DoThat()) .WillRepeatedly(IncrementCounter(0)); foo.DoThis(); // Returns 1. foo.DoThis(); // Returns 2. foo.DoThat(); // Returns 1 - Blah() uses a different // counter than Bar()'s. ``` versus ``` Action increment = IncrementCounter(0); EXPECT_CALL(foo, DoThis()) .WillRepeatedly(increment); EXPECT_CALL(foo, DoThat()) .WillRepeatedly(increment); foo.DoThis(); // Returns 1. foo.DoThis(); // Returns 2. foo.DoThat(); // Returns 3 - the counter is shared. ``` # Misc Recipes on Using Google Mock # ## Forcing a Verification ## When it's being destoyed, your friendly mock object will automatically verify that all expectations on it have been satisfied, and will generate [Google Test](http://code.google.com/p/googletest/) failures if not. This is convenient as it leaves you with one less thing to worry about. That is, unless you are not sure if your mock object will be destoyed. How could it be that your mock object won't eventually be destroyed? Well, it might be created on the heap and owned by the code you are testing. Suppose there's a bug in that code and it doesn't delete the mock object properly - you could end up with a passing test when there's actually a bug. Using a heap checker is a good idea and can alleviate the concern, but its implementation may not be 100% reliable. So, sometimes you do want to _force_ Google Mock to verify a mock object before it is (hopefully) destructed. You can do this with `Mock::VerifyAndClearExpectations(&mock_object)`: ``` TEST(MyServerTest, ProcessesRequest) { using ::testing::Mock; MockFoo* const foo = new MockFoo; EXPECT_CALL(*foo, ...)...; // ... other expectations ... // server now owns foo. MyServer server(foo); server.ProcessRequest(...); // In case that server's destructor will forget to delete foo, // this will verify the expectations anyway. Mock::VerifyAndClearExpectations(foo); } // server is destroyed when it goes out of scope here. ``` **Tip:** The `Mock::VerifyAndClearExpectations()` function returns a `bool` to indicate whether the verification was successful (`true` for yes), so you can wrap that function call inside a `ASSERT_TRUE()` if there is no point going further when the verification has failed. ## Using Check Points ## Sometimes you may want to "reset" a mock object at various check points in your test: at each check point, you verify that all existing expectations on the mock object have been satisfied, and then you set some new expectations on it as if it's newly created. This allows you to work with a mock object in "phases" whose sizes are each manageable. One such scenario is that in your test's `SetUp()` function, you may want to put the object you are testing into a certain state, with the help from a mock object. Once in the desired state, you want to clear all expectations on the mock, such that in the `TEST_F` body you can set fresh expectations on it. As you may have figured out, the `Mock::VerifyAndClearExpectations()` function we saw in the previous recipe can help you here. Or, if you are using `ON_CALL()` to set default actions on the mock object and want to clear the default actions as well, use `Mock::VerifyAndClear(&mock_object)` instead. This function does what `Mock::VerifyAndClearExpectations(&mock_object)` does and returns the same `bool`, **plus** it clears the `ON_CALL()` statements on `mock_object` too. Another trick you can use to achieve the same effect is to put the expectations in sequences and insert calls to a dummy "check-point" function at specific places. Then you can verify that the mock function calls do happen at the right time. For example, if you are exercising code: ``` Foo(1); Foo(2); Foo(3); ``` and want to verify that `Foo(1)` and `Foo(3)` both invoke `mock.Bar("a")`, but `Foo(2)` doesn't invoke anything. You can write: ``` using ::testing::MockFunction; TEST(FooTest, InvokesBarCorrectly) { MyMock mock; // Class MockFunction has exactly one mock method. It is named // Call() and has type F. MockFunction check; { InSequence s; EXPECT_CALL(mock, Bar("a")); EXPECT_CALL(check, Call("1")); EXPECT_CALL(check, Call("2")); EXPECT_CALL(mock, Bar("a")); } Foo(1); check.Call("1"); Foo(2); check.Call("2"); Foo(3); } ``` The expectation spec says that the first `Bar("a")` must happen before check point "1", the second `Bar("a")` must happen after check point "2", and nothing should happen between the two check points. The explicit check points make it easy to tell which `Bar("a")` is called by which call to `Foo()`. ## Mocking Destructors ## Sometimes you want to make sure a mock object is destructed at the right time, e.g. after `bar->A()` is called but before `bar->B()` is called. We already know that you can specify constraints on the order of mock function calls, so all we need to do is to mock the destructor of the mock function. This sounds simple, except for one problem: a destructor is a special function with special syntax and special semantics, and the `MOCK_METHOD0` macro doesn't work for it: ``` MOCK_METHOD0(~MockFoo, void()); // Won't compile! ``` The good news is that you can use a simple pattern to achieve the same effect. First, add a mock function `Die()` to your mock class and call it in the destructor, like this: ``` class MockFoo : public Foo { ... // Add the following two lines to the mock class. MOCK_METHOD0(Die, void()); virtual ~MockFoo() { Die(); } }; ``` (If the name `Die()` clashes with an existing symbol, choose another name.) Now, we have translated the problem of testing when a `MockFoo` object dies to testing when its `Die()` method is called: ``` MockFoo* foo = new MockFoo; MockBar* bar = new MockBar; ... { InSequence s; // Expects *foo to die after bar->A() and before bar->B(). EXPECT_CALL(*bar, A()); EXPECT_CALL(*foo, Die()); EXPECT_CALL(*bar, B()); } ``` And that's that. ## Using Google Mock and Threads ## **IMPORTANT NOTE:** What we describe in this recipe is **NOT** true yet, as Google Mock is not currently thread-safe. However, all we need to make it thread-safe is to implement some synchronization operations in `` - and then the information below will become true. In a **unit** test, it's best if you could isolate and test a piece of code in a single-threaded context. That avoids race conditions and dead locks, and makes debugging your test much easier. Yet many programs are multi-threaded, and sometimes to test something we need to pound on it from more than one thread. Google Mock works for this purpose too. Remember the steps for using a mock: 1. Create a mock object `foo`. 1. Set its default actions and expectations using `ON_CALL()` and `EXPECT_CALL()`. 1. The code under test calls methods of `foo`. 1. Optionally, verify and reset the mock. 1. Destroy the mock yourself, or let the code under test destroy it. The destructor will automatically verify it. If you follow the following simple rules, your mocks and threads can live happily togeter: * Execute your _test code_ (as opposed to the code being tested) in _one_ thread. This makes your test easy to follow. * Obviously, you can do step #1 without locking. * When doing step #2 and #5, make sure no other thread is accessing `foo`. Obvious too, huh? * #3 and #4 can be done either in one thread or in multiple threads - anyway you want. Google Mock takes care of the locking, so you don't have to do any - unless required by your test logic. If you violate the rules (for example, if you set expectations on a mock while another thread is calling its methods), you get undefined behavior. That's not fun, so don't do it. Google Mock guarantees that the action for a mock function is done in the same thread that called the mock function. For example, in ``` EXPECT_CALL(mock, Foo(1)) .WillOnce(action1); EXPECT_CALL(mock, Foo(2)) .WillOnce(action2); ``` if `Foo(1)` is called in thread 1 and `Foo(2)` is called in thread 2, Google Mock will execute `action1` in thread 1 and `action2` in thread 2. Google Mock does _not_ impose a sequence on actions performed in different threads (doing so may create deadlocks as the actions may need to cooperate). This means that the execution of `action1` and `action2` in the above example _may_ interleave. If this is a problem, you should add proper synchronization logic to `action1` and `action2` to make the test thread-safe. Also, remember that `DefaultValue` is a global resource that potentially affects _all_ living mock objects in your program. Naturally, you won't want to mess with it from multiple threads or when there still are mocks in action. ## Controlling How Much Information Google Mock Prints ## When Google Mock sees something that has the potential of being an error (e.g. a mock function with no expectation is called, a.k.a. an uninteresting call, which is allowed but perhaps you forgot to explicitly ban the call), it prints some warning messages, including the arguments of the function and the return value. Hopefully this will remind you to take a look and see if there is indeed a problem. Sometimes you are confident that your tests are correct and may not appreciate such friendly messages. Some other times, you are debugging your tests or learning about the behavior of the code you are testing, and wish you could observe every mock call that happens (including argument values and the return value). Clearly, one size doesn't fit all. You can control how much Google Mock tells you using the `--gmock_verbose=LEVEL` command-line flag, where `LEVEL` is a string with three possible values: * `info`: Google Mock will print all informational messages, warnings, and errors (most verbose). At this setting, Google Mock will also log any calls to the `ON_CALL/EXPECT_CALL` macros. * `warning`: Google Mock will print both warnings and errors (less verbose). This is the default. * `error`: Google Mock will print errors only (least verbose). Alternatively, you can adjust the value of that flag from within your tests like so: ``` ::testing::FLAGS_gmock_verbose = "error"; ``` Now, judiciously use the right flag to enable Google Mock serve you better! ## Running Tests in Emacs ## If you build and run your tests in Emacs, the source file locations of Google Mock and [Google Test](http://code.google.com/p/googletest/) errors will be highlighted. Just press `` on one of them and you'll be taken to the offending line. Or, you can just type `C-x `` to jump to the next error. To make it even easier, you can add the following lines to your `~/.emacs` file: ``` (global-set-key "\M-m" 'compile) ; m is for make (global-set-key [M-down] 'next-error) (global-set-key [M-up] '(lambda () (interactive) (next-error -1))) ``` Then you can type `M-m` to start a build, or `M-up`/`M-down` to move back and forth between errors. ## Fusing Google Mock Source Files ## Google Mock's implementation consists of dozens of files (excluding its own tests). Sometimes you may want them to be packaged up in fewer files instead, such that you can easily copy them to a new machine and start hacking there. For this we provide an experimental Python script `fuse_gmock_files.py` in the `scripts/` directory (starting with release 1.2.0). Assuming you have Python 2.4 or above installed on your machine, just go to that directory and run ``` python fuse_gmock_files.py OUTPUT_DIR ``` and you should see an `OUTPUT_DIR` directory being created with files `gtest/gtest.h`, `gmock/gmock.h`, and `gmock-gtest-all.cc` in it. These three files contain everything you need to use Google Mock (and Google Test). Just copy them to anywhere you want and you are ready to write tests and use mocks. You can use the [scrpts/test/Makefile](http://code.google.com/p/googlemock/source/browse/trunk/scripts/test/Makefile) file as an example on how to compile your tests against them. # Extending Google Mock # ## Writing New Matchers Quickly ## The `MATCHER*` family of macros can be used to define custom matchers easily. The syntax: ``` MATCHER(name, "description string") { statements; } ``` will define a matcher with the given name that executes the statements, which must return a `bool` to indicate if the match succeeds. Inside the statements, you can refer to the value being matched by `arg`, and refer to its type by `arg_type`. The description string documents what the matcher does, and is used to generate the failure message when the match fails. Since a `MATCHER()` is usually defined in a header file shared by multiple C++ source files, we require the description to be a C-string _literal_ to avoid possible side effects. It can be empty (`""`), in which case Google Mock will use the sequence of words in the matcher name as the description. For example: ``` MATCHER(IsDivisibleBy7, "") { return (arg % 7) == 0; } ``` allows you to write ``` // Expects mock_foo.Bar(n) to be called where n is divisible by 7. EXPECT_CALL(mock_foo, Bar(IsDivisibleBy7())); ``` or, ``` // Verifies that the value of some_expression is divisible by 7. EXPECT_THAT(some_expression, IsDivisibleBy7()); ``` If the above assertion fails, it will print something like: ``` Value of: some_expression Expected: is divisible by 7 Actual: 27 ``` where the description `"is divisible by 7"` is automatically calculated from the matcher name `IsDivisibleBy7`. Optionally, you can stream additional information to a hidden argument named `result_listener` to explain the match result. For example, a better definition of `IsDivisibleBy7` is: ``` MATCHER(IsDivisibleBy7, "") { if ((arg % 7) == 0) return true; *result_listener << "the remainder is " << (arg % 7); return false; } ``` With this definition, the above assertion will give a better message: ``` Value of: some_expression Expected: is divisible by 7 Actual: 27 (the remainder is 6) ``` You should let `MatchAndExplain()` print _any additional information_ that can help a user understand the match result. Note that it should explain why the match succeeds in case of a success (unless it's obvious) - this is useful when the matcher is used inside `Not()`. There is no need to print the argument value itself, as Google Mock already prints it for you. **Notes:** 1. The type of the value being matched (`arg_type`) is determined by the context in which you use the matcher and is supplied to you by the compiler, so you don't need to worry about declaring it (nor can you). This allows the matcher to be polymorphic. For example, `IsDivisibleBy7()` can be used to match any type where the value of `(arg % 7) == 0` can be implicitly converted to a `bool`. In the `Bar(IsDivisibleBy7())` example above, if method `Bar()` takes an `int`, `arg_type` will be `int`; if it takes an `unsigned long`, `arg_type` will be `unsigned long`; and so on. 1. Google Mock doesn't guarantee when or how many times a matcher will be invoked. Therefore the matcher logic must be _purely functional_ (i.e. it cannot have any side effect, and the result must not depend on anything other than the value being matched and the matcher parameters). This requirement must be satisfied no matter how you define the matcher (e.g. using one of the methods described in the following recipes). In particular, a matcher can never call a mock function, as that will affect the state of the mock object and Google Mock. ## Writing New Parameterized Matchers Quickly ## Sometimes you'll want to define a matcher that has parameters. For that you can use the macro: ``` MATCHER_P(name, param_name, "description string") { statements; } ``` For example: ``` MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; } ``` will allow you to write: ``` EXPECT_THAT(Blah("a"), HasAbsoluteValue(n)); ``` which may lead to this message (assuming `n` is 10): ``` Value of: Blah("a") Expected: has absolute value 10 Actual: -9 ``` Note that both the matcher description and its parameter are printed, making the message human-friendly. In the matcher definition body, you can write `foo_type` to reference the type of a parameter named `foo`. For example, in the body of `MATCHER_P(HasAbsoluteValue, value)` above, you can write `value_type` to refer to the type of `value`. Google Mock also provides `MATCHER_P2`, `MATCHER_P3`, ..., up to `MATCHER_P10` to support multi-parameter matchers: ``` MATCHER_Pk(name, param_1, ..., param_k, "description string") { statements; } ``` Please note that the custom description string is for a particular **instance** of the matcher, where the parameters have been bound to actual values. Therefore usually you'll want the parameter values to be part of the description. Google Mock lets you do that using Python-style interpolations. The following syntaxes are supported currently: | `%%` | a single `%` character | |:-----|:-----------------------| | `%(*)s` | all parameters of the matcher printed as a tuple | | `%(foo)s` | value of the matcher parameter named `foo` | For example, ``` MATCHER_P2(InClosedRange, low, hi, "is in range [%(low)s, %(hi)s]") { return low <= arg && arg <= hi; } ... EXPECT_THAT(3, InClosedRange(4, 6)); ``` would generate a failure that contains the message: ``` Expected: is in range [4, 6] ``` If you specify `""` as the description, the failure message will contain the sequence of words in the matcher name followed by the parameter values printed as a tuple. For example, ``` MATCHER_P2(InClosedRange, low, hi, "") { ... } ... EXPECT_THAT(3, InClosedRange(4, 6)); ``` would generate a failure that contains the text: ``` Expected: in closed range (4, 6) ``` For the purpose of typing, you can view ``` MATCHER_Pk(Foo, p1, ..., pk, "description string") { ... } ``` as shorthand for ``` template FooMatcherPk Foo(p1_type p1, ..., pk_type pk) { ... } ``` When you write `Foo(v1, ..., vk)`, the compiler infers the types of the parameters `v1`, ..., and `vk` for you. If you are not happy with the result of the type inference, you can specify the types by explicitly instantiating the template, as in `Foo(5, false)`. As said earlier, you don't get to (or need to) specify `arg_type` as that's determined by the context in which the matcher is used. You can assign the result of expression `Foo(p1, ..., pk)` to a variable of type `FooMatcherPk`. This can be useful when composing matchers. Matchers that don't have a parameter or have only one parameter have special types: you can assign `Foo()` to a `FooMatcher`-typed variable, and assign `Foo(p)` to a `FooMatcherP`-typed variable. While you can instantiate a matcher template with reference types, passing the parameters by pointer usually makes your code more readable. If, however, you still want to pass a parameter by reference, be aware that in the failure message generated by the matcher you will see the value of the referenced object but not its address. You can overload matchers with different numbers of parameters: ``` MATCHER_P(Blah, a, "description string 1") { ... } MATCHER_P2(Blah, a, b, "description string 2") { ... } ``` While it's tempting to always use the `MATCHER*` macros when defining a new matcher, you should also consider implementing `MatcherInterface` or using `MakePolymorphicMatcher()` instead (see the recipes that follow), especially if you need to use the matcher a lot. While these approaches require more work, they give you more control on the types of the value being matched and the matcher parameters, which in general leads to better compiler error messages that pay off in the long run. They also allow overloading matchers based on parameter types (as opposed to just based on the number of parameters). ## Writing New Monomorphic Matchers ## A matcher of argument type `T` implements `::testing::MatcherInterface` and does two things: it tests whether a value of type `T` matches the matcher, and can describe what kind of values it matches. The latter ability is used for generating readable error messages when expectations are violated. The interface looks like this: ``` class MatchResultListener { public: ... // Streams x to the underlying ostream; does nothing if the ostream // is NULL. template MatchResultListener& operator<<(const T& x); // Returns the underlying ostream. ::std::ostream* stream(); }; template class MatcherInterface { public: virtual ~MatcherInterface(); // Returns true iff the matcher matches x; also explains the match // result to 'listener'. virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0; // Describes this matcher to an ostream. virtual void DescribeTo(::std::ostream* os) const = 0; // Describes the negation of this matcher to an ostream. virtual void DescribeNegationTo(::std::ostream* os) const; }; ``` If you need a custom matcher but `Truly()` is not a good option (for example, you may not be happy with the way `Truly(predicate)` describes itself, or you may want your matcher to be polymorphic as `Eq(value)` is), you can define a matcher to do whatever you want in two steps: first implement the matcher interface, and then define a factory function to create a matcher instance. The second step is not strictly needed but it makes the syntax of using the matcher nicer. For example, you can define a matcher to test whether an `int` is divisible by 7 and then use it like this: ``` using ::testing::MakeMatcher; using ::testing::Matcher; using ::testing::MatcherInterface; using ::testing::MatchResultListener; class DivisibleBy7Matcher : public MatcherInterface { public: virtual bool MatchAndExplain(int n, MatchResultListener* listener) const { return (n % 7) == 0; } virtual void DescribeTo(::std::ostream* os) const { *os << "is divisible by 7"; } virtual void DescribeNegationTo(::std::ostream* os) const { *os << "is not divisible by 7"; } }; inline Matcher DivisibleBy7() { return MakeMatcher(new DivisibleBy7Matcher); } ... EXPECT_CALL(foo, Bar(DivisibleBy7())); ``` You may improve the matcher message by streaming additional information to the `listener` argument in `MatchAndExplain()`: ``` class DivisibleBy7Matcher : public MatcherInterface { public: virtual bool MatchAndExplain(int n, MatchResultListener* listener) const { const int remainder = n % 7; if (remainder != 0) { *listener << "the remainder is " << remainder; } return remainder == 0; } ... }; ``` Then, `EXPECT_THAT(x, DivisibleBy7());` may general a message like this: ``` Value of: x Expected: is divisible by 7 Actual: 23 (the remainder is 2) ``` ## Writing New Polymorphic Matchers ## You've learned how to write your own matchers in the previous recipe. Just one problem: a matcher created using `MakeMatcher()` only works for one particular type of arguments. If you want a _polymorphic_ matcher that works with arguments of several types (for instance, `Eq(x)` can be used to match a `value` as long as `value` == `x` compiles -- `value` and `x` don't have to share the same type), you can learn the trick from `` but it's a bit involved. Fortunately, most of the time you can define a polymorphic matcher easily with the help of `MakePolymorphicMatcher()`. Here's how you can define `NotNull()` as an example: ``` using ::testing::MakePolymorphicMatcher; using ::testing::MatchResultListener; using ::testing::NotNull; using ::testing::PolymorphicMatcher; class NotNullMatcher { public: // To implement a polymorphic matcher, first define a COPYABLE class // that has three members MatchAndExplain(), DescribeTo(), and // DescribeNegationTo(), like the following. // In this example, we want to use NotNull() with any pointer, so // MatchAndExplain() accepts a pointer of any type as its first argument. // In general, you can define MatchAndExplain() as an ordinary method or // a method template, or even overload it. template bool MatchAndExplain(T* p, MatchResultListener* /* listener */) const { return p != NULL; } // Describes the property of a value matching this matcher. void DescribeTo(::std::ostream* os) const { *os << "is not NULL"; } // Describes the property of a value NOT matching this matcher. void DescribeNegationTo(::std::ostream* os) const { *os << "is NULL"; } }; // To construct a polymorphic matcher, pass an instance of the class // to MakePolymorphicMatcher(). Note the return type. inline PolymorphicMatcher NotNull() { return MakePolymorphicMatcher(NotNullMatcher()); } ... EXPECT_CALL(foo, Bar(NotNull())); // The argument must be a non-NULL pointer. ``` **Note:** Your polymorphic matcher class does **not** need to inherit from `MatcherInterface` or any other class, and its methods do **not** need to be virtual. Like in a monomorphic matcher, you may explain the match result by streaming additional information to the `listener` argument in `MatchAndExplain()`. ## Writing New Cardinalities ## A cardinality is used in `Times()` to tell Google Mock how many times you expect a call to occur. It doesn't have to be exact. For example, you can say `AtLeast(5)` or `Between(2, 4)`. If the built-in set of cardinalities doesn't suit you, you are free to define your own by implementing the following interface (in namespace `testing`): ``` class CardinalityInterface { public: virtual ~CardinalityInterface(); // Returns true iff call_count calls will satisfy this cardinality. virtual bool IsSatisfiedByCallCount(int call_count) const = 0; // Returns true iff call_count calls will saturate this cardinality. virtual bool IsSaturatedByCallCount(int call_count) const = 0; // Describes self to an ostream. virtual void DescribeTo(::std::ostream* os) const = 0; }; ``` For example, to specify that a call must occur even number of times, you can write ``` using ::testing::Cardinality; using ::testing::CardinalityInterface; using ::testing::MakeCardinality; class EvenNumberCardinality : public CardinalityInterface { public: virtual bool IsSatisfiedByCallCount(int call_count) const { return (call_count % 2) == 0; } virtual bool IsSaturatedByCallCount(int call_count) const { return false; } virtual void DescribeTo(::std::ostream* os) const { *os << "called even number of times"; } }; Cardinality EvenNumber() { return MakeCardinality(new EvenNumberCardinality); } ... EXPECT_CALL(foo, Bar(3)) .Times(EvenNumber()); ``` ## Writing New Actions Quickly ## If the built-in actions don't work for you, and you find it inconvenient to use `Invoke()`, you can use a macro from the `ACTION*` family to quickly define a new action that can be used in your code as if it's a built-in action. By writing ``` ACTION(name) { statements; } ``` in a namespace scope (i.e. not inside a class or function), you will define an action with the given name that executes the statements. The value returned by `statements` will be used as the return value of the action. Inside the statements, you can refer to the K-th (0-based) argument of the mock function as `argK`. For example: ``` ACTION(IncrementArg1) { return ++(*arg1); } ``` allows you to write ``` ... WillOnce(IncrementArg1()); ``` Note that you don't need to specify the types of the mock function arguments. Rest assured that your code is type-safe though: you'll get a compiler error if `*arg1` doesn't support the `++` operator, or if the type of `++(*arg1)` isn't compatible with the mock function's return type. Another example: ``` ACTION(Foo) { (*arg2)(5); Blah(); *arg1 = 0; return arg0; } ``` defines an action `Foo()` that invokes argument #2 (a function pointer) with 5, calls function `Blah()`, sets the value pointed to by argument #1 to 0, and returns argument #0. For more convenience and flexibility, you can also use the following pre-defined symbols in the body of `ACTION`: | `argK_type` | The type of the K-th (0-based) argument of the mock function | |:------------|:-------------------------------------------------------------| | `args` | All arguments of the mock function as a tuple | | `args_type` | The type of all arguments of the mock function as a tuple | | `return_type` | The return type of the mock function | | `function_type` | The type of the mock function | For example, when using an `ACTION` as a stub action for mock function: ``` int DoSomething(bool flag, int* ptr); ``` we have: | **Pre-defined Symbol** | **Is Bound To** | |:-----------------------|:----------------| | `arg0` | the value of `flag` | | `arg0_type` | the type `bool` | | `arg1` | the value of `ptr` | | `arg1_type` | the type `int*` | | `args` | the tuple `(flag, ptr)` | | `args_type` | the type `std::tr1::tuple` | | `return_type` | the type `int` | | `function_type` | the type `int(bool, int*)` | ## Writing New Parameterized Actions Quickly ## Sometimes you'll want to parameterize an action you define. For that we have another macro ``` ACTION_P(name, param) { statements; } ``` For example, ``` ACTION_P(Add, n) { return arg0 + n; } ``` will allow you to write ``` // Returns argument #0 + 5. ... WillOnce(Add(5)); ``` For convenience, we use the term _arguments_ for the values used to invoke the mock function, and the term _parameters_ for the values used to instantiate an action. Note that you don't need to provide the type of the parameter either. Suppose the parameter is named `param`, you can also use the Google-Mock-defined symbol `param_type` to refer to the type of the parameter as inferred by the compiler. For example, in the body of `ACTION_P(Add, n)` above, you can write `n_type` for the type of `n`. Google Mock also provides `ACTION_P2`, `ACTION_P3`, and etc to support multi-parameter actions. For example, ``` ACTION_P2(ReturnDistanceTo, x, y) { double dx = arg0 - x; double dy = arg1 - y; return sqrt(dx*dx + dy*dy); } ``` lets you write ``` ... WillOnce(ReturnDistanceTo(5.0, 26.5)); ``` You can view `ACTION` as a degenerated parameterized action where the number of parameters is 0. You can also easily define actions overloaded on the number of parameters: ``` ACTION_P(Plus, a) { ... } ACTION_P2(Plus, a, b) { ... } ``` ## Restricting the Type of an Argument or Parameter in an ACTION ## For maximum brevity and reusability, the `ACTION*` macros don't ask you to provide the types of the mock function arguments and the action parameters. Instead, we let the compiler infer the types for us. Sometimes, however, we may want to be more explicit about the types. There are several tricks to do that. For example: ``` ACTION(Foo) { // Makes sure arg0 can be converted to int. int n = arg0; ... use n instead of arg0 here ... } ACTION_P(Bar, param) { // Makes sure the type of arg1 is const char*. ::testing::StaticAssertTypeEq(); // Makes sure param can be converted to bool. bool flag = param; } ``` where `StaticAssertTypeEq` is a compile-time assertion in Google Test that verifies two types are the same. ## Writing New Action Templates Quickly ## Sometimes you want to give an action explicit template parameters that cannot be inferred from its value parameters. `ACTION_TEMPLATE()` supports that and can be viewed as an extension to `ACTION()` and `ACTION_P*()`. The syntax: ``` ACTION_TEMPLATE(ActionName, HAS_m_TEMPLATE_PARAMS(kind1, name1, ..., kind_m, name_m), AND_n_VALUE_PARAMS(p1, ..., p_n)) { statements; } ``` defines an action template that takes _m_ explicit template parameters and _n_ value parameters, where _m_ is between 1 and 10, and _n_ is between 0 and 10. `name_i` is the name of the i-th template parameter, and `kind_i` specifies whether it's a `typename`, an integral constant, or a template. `p_i` is the name of the i-th value parameter. Example: ``` // DuplicateArg(output) converts the k-th argument of the mock // function to type T and copies it to *output. ACTION_TEMPLATE(DuplicateArg, // Note the comma between int and k: HAS_2_TEMPLATE_PARAMS(int, k, typename, T), AND_1_VALUE_PARAMS(output)) { *output = T(std::tr1::get(args)); } ``` To create an instance of an action template, write: ``` ActionName(v1, ..., v_n) ``` where the `t`s are the template arguments and the `v`s are the value arguments. The value argument types are inferred by the compiler. For example: ``` using ::testing::_; ... int n; EXPECT_CALL(mock, Foo(_, _)) .WillOnce(DuplicateArg<1, unsigned char>(&n)); ``` If you want to explicitly specify the value argument types, you can provide additional template arguments: ``` ActionName(v1, ..., v_n) ``` where `u_i` is the desired type of `v_i`. `ACTION_TEMPLATE` and `ACTION`/`ACTION_P*` can be overloaded on the number of value parameters, but not on the number of template parameters. Without the restriction, the meaning of the following is unclear: ``` OverloadedAction(x); ``` Are we using a single-template-parameter action where `bool` refers to the type of `x`, or a two-template-parameter action where the compiler is asked to infer the type of `x`? ## Using the ACTION Object's Type ## If you are writing a function that returns an `ACTION` object, you'll need to know its type. The type depends on the macro used to define the action and the parameter types. The rule is relatively simple: | **Given Definition** | **Expression** | **Has Type** | |:---------------------|:---------------|:-------------| | `ACTION(Foo)` | `Foo()` | `FooAction` | | `ACTION_TEMPLATE(Foo, HAS_m_TEMPLATE_PARAMS(...), AND_0_VALUE_PARAMS())` | `Foo()` | `FooAction` | | `ACTION_P(Bar, param)` | `Bar(int_value)` | `BarActionP` | | `ACTION_TEMPLATE(Bar, HAS_m_TEMPLATE_PARAMS(...), AND_1_VALUE_PARAMS(p1))` | `Bar(int_value)` | `FooActionP` | | `ACTION_P2(Baz, p1, p2)` | `Baz(bool_value, int_value)` | `BazActionP2` | | `ACTION_TEMPLATE(Baz, HAS_m_TEMPLATE_PARAMS(...), AND_2_VALUE_PARAMS(p1, p2))` | `Baz(bool_value, int_value)` | `FooActionP2` | | ... | ... | ... | Note that we have to pick different suffixes (`Action`, `ActionP`, `ActionP2`, and etc) for actions with different numbers of value parameters, or the action definitions cannot be overloaded on the number of them. ## Writing New Monomorphic Actions ## While the `ACTION*` macros are very convenient, sometimes they are inappropriate. For example, despite the tricks shown in the previous recipes, they don't let you directly specify the types of the mock function arguments and the action parameters, which in general leads to unoptimized compiler error messages that can baffle unfamiliar users. They also don't allow overloading actions based on parameter types without jumping through some hoops. An alternative to the `ACTION*` macros is to implement `::testing::ActionInterface`, where `F` is the type of the mock function in which the action will be used. For example: ``` template class ActionInterface { public: virtual ~ActionInterface(); // Performs the action. Result is the return type of function type // F, and ArgumentTuple is the tuple of arguments of F. // // For example, if F is int(bool, const string&), then Result would // be int, and ArgumentTuple would be tr1::tuple. virtual Result Perform(const ArgumentTuple& args) = 0; }; using ::testing::_; using ::testing::Action; using ::testing::ActionInterface; using ::testing::MakeAction; typedef int IncrementMethod(int*); class IncrementArgumentAction : public ActionInterface { public: virtual int Perform(const tr1::tuple& args) { int* p = tr1::get<0>(args); // Grabs the first argument. return *p++; } }; Action IncrementArgument() { return MakeAction(new IncrementArgumentAction); } ... EXPECT_CALL(foo, Baz(_)) .WillOnce(IncrementArgument()); int n = 5; foo.Baz(&n); // Should return 5 and change n to 6. ``` ## Writing New Polymorphic Actions ## The previous recipe showed you how to define your own action. This is all good, except that you need to know the type of the function in which the action will be used. Sometimes that can be a problem. For example, if you want to use the action in functions with _different_ types (e.g. like `Return()` and `SetArgumentPointee()`). If an action can be used in several types of mock functions, we say it's _polymorphic_. The `MakePolymorphicAction()` function template makes it easy to define such an action: ``` namespace testing { template PolymorphicAction MakePolymorphicAction(const Impl& impl); } // namespace testing ``` As an example, let's define an action that returns the second argument in the mock function's argument list. The first step is to define an implementation class: ``` class ReturnSecondArgumentAction { public: template Result Perform(const ArgumentTuple& args) const { // To get the i-th (0-based) argument, use tr1::get(args). return tr1::get<1>(args); } }; ``` This implementation class does _not_ need to inherit from any particular class. What matters is that it must have a `Perform()` method template. This method template takes the mock function's arguments as a tuple in a **single** argument, and returns the result of the action. It can be either `const` or not, but must be invokable with exactly one template argument, which is the result type. In other words, you must be able to call `Perform(args)` where `R` is the mock function's return type and `args` is its arguments in a tuple. Next, we use `MakePolymorphicAction()` to turn an instance of the implementation class into the polymorphic action we need. It will be convenient to have a wrapper for this: ``` using ::testing::MakePolymorphicAction; using ::testing::PolymorphicAction; PolymorphicAction ReturnSecondArgument() { return MakePolymorphicAction(ReturnSecondArgumentAction()); } ``` Now, you can use this polymorphic action the same way you use the built-in ones: ``` using ::testing::_; class MockFoo : public Foo { public: MOCK_METHOD2(DoThis, int(bool flag, int n)); MOCK_METHOD3(DoThat, string(int x, const char* str1, const char* str2)); }; ... MockFoo foo; EXPECT_CALL(foo, DoThis(_, _)) .WillOnce(ReturnSecondArgument()); EXPECT_CALL(foo, DoThat(_, _, _)) .WillOnce(ReturnSecondArgument()); ... foo.DoThis(true, 5); // Will return 5. foo.DoThat(1, "Hi", "Bye"); // Will return "Hi". ``` ## Teaching Google Mock How to Print Your Values ## When an uninteresting or unexpected call occurs, Google Mock prints the argument values to help you debug. The `EXPECT_THAT` and `ASSERT_THAT` assertions also print the value being validated when the test fails. Google Mock does this using the user-extensible value printer defined in ``. This printer knows how to print the built-in C++ types, native arrays, STL containers, and any type that supports the `<<` operator. For other types, it prints the raw bytes in the value and hope you the user can figure it out. Did I say that the printer is `extensible`? That means you can teach it to do a better job at printing your particular type than to dump the bytes. To do that, you just need to define `<<` for your type: ``` #include namespace foo { class Foo { ... }; // It's important that the << operator is defined in the SAME // namespace that defines Foo. C++'s look-up rules rely on that. ::std::ostream& operator<<(::std::ostream& os, const Foo& foo) { return os << foo.DebugString(); // Whatever needed to print foo to os. } } // namespace foo ``` Sometimes, this might not be an option. For example, your team may consider it dangerous or bad style to have a `<<` operator for `Foo`, or `Foo` may already have a `<<` operator that doesn't do what you want (and you cannot change it). Don't despair though - Google Mock gives you a second chance to get it right. Namely, you can define a `PrintTo()` function like this: ``` #include namespace foo { class Foo { ... }; // It's important that PrintTo() is defined in the SAME // namespace that defines Foo. C++'s look-up rules rely on that. void PrintTo(const Foo& foo, ::std::ostream* os) { *os << foo.DebugString(); // Whatever needed to print foo to os. } } // namespace foo ``` What if you have both `<<` and `PrintTo()`? In this case, the latter will override the former when Google Mock is concerned. This allows you to customize how the value should appear in Google Mock's output without affecting code that relies on the behavior of its `<<` operator. **Note:** When printing a pointer of type `T*`, Google Mock calls `PrintTo(T*, std::ostream* os)` instead of `operator<<(std::ostream&, T*)`. Therefore the only way to affect how a pointer is printed by Google Mock is to define `PrintTo()` for it. Also note that `T*` and `const T*` are different types, so you may need to define `PrintTo()` for both. Why does Google Mock treat pointers specially? There are several reasons: * We cannot use `operator<<` to print a `signed char*` or `unsigned char*`, since it will print the pointer as a NUL-terminated C string, which likely will cause an access violation. * We want `NULL` pointers to be printed as `"NULL"`, but `operator<<` prints it as `"0"`, `"nullptr"`, or something else, depending on the compiler. * With some compilers, printing a `NULL` `char*` using `operator<<` will segfault. * `operator<<` prints a function pointer as a `bool` (hence it always prints `"1"`), which is not very useful.nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/docs/v1_5/Documentation.md000066400000000000000000000014151455373415500274760ustar00rootroot00000000000000This page lists all documentation wiki pages for Google Mock **version 1.5.0** -- **if you use a different version of Google Mock, please read the documentation for that specific version instead.** * [ForDummies](V1_5_ForDummies.md) -- start here if you are new to Google Mock. * [CheatSheet](V1_5_CheatSheet.md) -- a quick reference. * [CookBook](V1_5_CookBook.md) -- recipes for doing various tasks using Google Mock. * [FrequentlyAskedQuestions](V1_5_FrequentlyAskedQuestions.md) -- check here before asking a question on the mailing list. To contribute code to Google Mock, read: * DevGuide -- read this _before_ writing your first patch. * [Pump Manual](http://code.google.com/p/googletest/wiki/PumpManual) -- how we generate some of Google Mock's source files.nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/docs/v1_5/ForDummies.md000066400000000000000000000722351455373415500267470ustar00rootroot00000000000000 (**Note:** If you get compiler errors that you don't understand, be sure to consult [Google Mock Doctor](V1_5_FrequentlyAskedQuestions#How_am_I_supposed_to_make_sense_of_these_horrible_template_error.md).) # What Is Google C++ Mocking Framework? # When you write a prototype or test, often it's not feasible or wise to rely on real objects entirely. A **mock object** implements the same interface as a real object (so it can be used as one), but lets you specify at run time how it will be used and what it should do (which methods will be called? in which order? how many times? with what arguments? what will they return? etc). **Note:** It is easy to confuse the term _fake objects_ with mock objects. Fakes and mocks actually mean very different things in the Test-Driven Development (TDD) community: * **Fake** objects have working implementations, but usually take some shortcut (perhaps to make the operations less expensive), which makes them not suitable for production. An in-memory file system would be an example of a fake. * **Mocks** are objects pre-programmed with _expectations_, which form a specification of the calls they are expected to receive. If all this seems too abstract for you, don't worry - the most important thing to remember is that a mock allows you to check the _interaction_ between itself and code that uses it. The difference between fakes and mocks will become much clearer once you start to use mocks. **Google C++ Mocking Framework** (or **Google Mock** for short) is a library (sometimes we also call it a "framework" to make it sound cool) for creating mock classes and using them. It does to C++ what [jMock](http://www.jmock.org/) and [EasyMock](http://www.easymock.org/) do to Java. Using Google Mock involves three basic steps: 1. Use some simple macros to describe the interface you want to mock, and they will expand to the implementation of your mock class; 1. Create some mock objects and specify its expectations and behavior using an intuitive syntax; 1. Exercise code that uses the mock objects. Google Mock will catch any violation of the expectations as soon as it arises. # Why Google Mock? # While mock objects help you remove unnecessary dependencies in tests and make them fast and reliable, using mocks manually in C++ is _hard_: * Someone has to implement the mocks. The job is usually tedious and error-prone. No wonder people go great distance to avoid it. * The quality of those manually written mocks is a bit, uh, unpredictable. You may see some really polished ones, but you may also see some that were hacked up in a hurry and have all sorts of ad hoc restrictions. * The knowledge you gained from using one mock doesn't transfer to the next. In contrast, Java and Python programmers have some fine mock frameworks, which automate the creation of mocks. As a result, mocking is a proven effective technique and widely adopted practice in those communities. Having the right tool absolutely makes the difference. Google Mock was built to help C++ programmers. It was inspired by [jMock](http://www.jmock.org/) and [EasyMock](http://www.easymock.org/), but designed with C++'s specifics in mind. It is your friend if any of the following problems is bothering you: * You are stuck with a sub-optimal design and wish you had done more prototyping before it was too late, but prototyping in C++ is by no means "rapid". * Your tests are slow as they depend on too many libraries or use expensive resources (e.g. a database). * Your tests are brittle as some resources they use are unreliable (e.g. the network). * You want to test how your code handles a failure (e.g. a file checksum error), but it's not easy to cause one. * You need to make sure that your module interacts with other modules in the right way, but it's hard to observe the interaction; therefore you resort to observing the side effects at the end of the action, which is awkward at best. * You want to "mock out" your dependencies, except that they don't have mock implementations yet; and, frankly, you aren't thrilled by some of those hand-written mocks. We encourage you to use Google Mock as: * a _design_ tool, for it lets you experiment with your interface design early and often. More iterations lead to better designs! * a _testing_ tool to cut your tests' outbound dependencies and probe the interaction between your module and its collaborators. # Getting Started # Using Google Mock is easy! Inside your C++ source file, just `#include` `` and ``, and you are ready to go. # A Case for Mock Turtles # Let's look at an example. Suppose you are developing a graphics program that relies on a LOGO-like API for drawing. How would you test that it does the right thing? Well, you can run it and compare the screen with a golden screen snapshot, but let's admit it: tests like this are expensive to run and fragile (What if you just upgraded to a shiny new graphics card that has better anti-aliasing? Suddenly you have to update all your golden images.). It would be too painful if all your tests are like this. Fortunately, you learned about Dependency Injection and know the right thing to do: instead of having your application talk to the drawing API directly, wrap the API in an interface (say, `Turtle`) and code to that interface: ``` class Turtle { ... virtual ~Turtle() {} virtual void PenUp() = 0; virtual void PenDown() = 0; virtual void Forward(int distance) = 0; virtual void Turn(int degrees) = 0; virtual void GoTo(int x, int y) = 0; virtual int GetX() const = 0; virtual int GetY() const = 0; }; ``` (Note that the destructor of `Turtle` **must** be virtual, as is the case for **all** classes you intend to inherit from - otherwise the destructor of the derived class will not be called when you delete an object through a base pointer, and you'll get corrupted program states like memory leaks.) You can control whether the turtle's movement will leave a trace using `PenUp()` and `PenDown()`, and control its movement using `Forward()`, `Turn()`, and `GoTo()`. Finally, `GetX()` and `GetY()` tell you the current position of the turtle. Your program will normally use a real implementation of this interface. In tests, you can use a mock implementation instead. This allows you to easily check what drawing primitives your program is calling, with what arguments, and in which order. Tests written this way are much more robust (they won't break because your new machine does anti-aliasing differently), easier to read and maintain (the intent of a test is expressed in the code, not in some binary images), and run _much, much faster_. # Writing the Mock Class # If you are lucky, the mocks you need to use have already been implemented by some nice people. If, however, you find yourself in the position to write a mock class, relax - Google Mock turns this task into a fun game! (Well, almost.) ## How to Define It ## Using the `Turtle` interface as example, here are the simple steps you need to follow: 1. Derive a class `MockTurtle` from `Turtle`. 1. Take a virtual function of `Turtle`. Count how many arguments it has. 1. In the `public:` section of the child class, write `MOCK_METHODn();` (or `MOCK_CONST_METHODn();` if you are mocking a `const` method), where `n` is the number of the arguments; if you counted wrong, shame on you, and a compiler error will tell you so. 1. Now comes the fun part: you take the function signature, cut-and-paste the _function name_ as the _first_ argument to the macro, and leave what's left as the _second_ argument (in case you're curious, this is the _type of the function_). 1. Repeat until all virtual functions you want to mock are done. After the process, you should have something like: ``` #include // Brings in Google Mock. class MockTurtle : public Turtle { public: ... MOCK_METHOD0(PenUp, void()); MOCK_METHOD0(PenDown, void()); MOCK_METHOD1(Forward, void(int distance)); MOCK_METHOD1(Turn, void(int degrees)); MOCK_METHOD2(GoTo, void(int x, int y)); MOCK_CONST_METHOD0(GetX, int()); MOCK_CONST_METHOD0(GetY, int()); }; ``` You don't need to define these mock methods somewhere else - the `MOCK_METHOD*` macros will generate the definitions for you. It's that simple! Once you get the hang of it, you can pump out mock classes faster than your source-control system can handle your check-ins. **Tip:** If even this is too much work for you, you'll find the `gmock_gen.py` tool in Google Mock's `scripts/generator/` directory (courtesy of the [cppclean](http://code.google.com/p/cppclean/) project) useful. This command-line tool requires that you have Python 2.4 installed. You give it a C++ file and the name of an abstract class defined in it, and it will print the definition of the mock class for you. Due to the complexity of the C++ language, this script may not always work, but it can be quite handy when it does. For more details, read the [user documentation](http://code.google.com/p/googlemock/source/browse/trunk/scripts/generator/README). ## Where to Put It ## When you define a mock class, you need to decide where to put its definition. Some people put it in a `*_test.cc`. This is fine when the interface being mocked (say, `Foo`) is owned by the same person or team. Otherwise, when the owner of `Foo` changes it, your test could break. (You can't really expect `Foo`'s maintainer to fix every test that uses `Foo`, can you?) So, the rule of thumb is: if you need to mock `Foo` and it's owned by others, define the mock class in `Foo`'s package (better, in a `testing` sub-package such that you can clearly separate production code and testing utilities), and put it in a `mock_foo.h`. Then everyone can reference `mock_foo.h` from their tests. If `Foo` ever changes, there is only one copy of `MockFoo` to change, and only tests that depend on the changed methods need to be fixed. Another way to do it: you can introduce a thin layer `FooAdaptor` on top of `Foo` and code to this new interface. Since you own `FooAdaptor`, you can absorb changes in `Foo` much more easily. While this is more work initially, carefully choosing the adaptor interface can make your code easier to write and more readable (a net win in the long run), as you can choose `FooAdaptor` to fit your specific domain much better than `Foo` does. # Using Mocks in Tests # Once you have a mock class, using it is easy. The typical work flow is: 1. Import the Google Mock names from the `testing` namespace such that you can use them unqualified (You only have to do it once per file. Remember that namespaces are a good idea and good for your health.). 1. Create some mock objects. 1. Specify your expectations on them (How many times will a method be called? With what arguments? What should it do? etc.). 1. Exercise some code that uses the mocks; optionally, check the result using Google Test assertions. If a mock method is called more than expected or with wrong arguments, you'll get an error immediately. 1. When a mock is destructed, Google Mock will automatically check whether all expectations on it have been satisfied. Here's an example: ``` #include "path/to/mock-turtle.h" #include #include using ::testing::AtLeast; // #1 TEST(PainterTest, CanDrawSomething) { MockTurtle turtle; // #2 EXPECT_CALL(turtle, PenDown()) // #3 .Times(AtLeast(1)); Painter painter(&turtle); // #4 EXPECT_TRUE(painter.DrawCircle(0, 0, 10)); } // #5 int main(int argc, char** argv) { // The following line must be executed to initialize Google Mock // (and Google Test) before running the tests. ::testing::InitGoogleMock(&argc, argv); return RUN_ALL_TESTS(); } ``` As you might have guessed, this test checks that `PenDown()` is called at least once. If the `painter` object didn't call this method, your test will fail with a message like this: ``` path/to/my_test.cc:119: Failure Actual function call count doesn't match this expectation: Actually: never called; Expected: called at least once. ``` **Tip 1:** If you run the test from an Emacs buffer, you can hit `` on the line number displayed in the error message to jump right to the failed expectation. **Tip 2:** If your mock objects are never deleted, the final verification won't happen. Therefore it's a good idea to use a heap leak checker in your tests when you allocate mocks on the heap. **Important note:** Google Mock requires expectations to be set **before** the mock functions are called, otherwise the behavior is **undefined**. In particular, you mustn't interleave `EXPECT_CALL()`s and calls to the mock functions. This means `EXPECT_CALL()` should be read as expecting that a call will occur _in the future_, not that a call has occurred. Why does Google Mock work like that? Well, specifying the expectation beforehand allows Google Mock to report a violation as soon as it arises, when the context (stack trace, etc) is still available. This makes debugging much easier. Admittedly, this test is contrived and doesn't do much. You can easily achieve the same effect without using Google Mock. However, as we shall reveal soon, Google Mock allows you to do _much more_ with the mocks. ## Using Google Mock with Any Testing Framework ## If you want to use something other than Google Test (e.g. [CppUnit](http://apps.sourceforge.net/mediawiki/cppunit/index.php?title=Main_Page) or [CxxTest](http://cxxtest.tigris.org/)) as your testing framework, just change the `main()` function in the previous section to: ``` int main(int argc, char** argv) { // The following line causes Google Mock to throw an exception on failure, // which will be interpreted by your testing framework as a test failure. ::testing::GTEST_FLAG(throw_on_failure) = true; ::testing::InitGoogleMock(&argc, argv); ... whatever your testing framework requires ... } ``` This approach has a catch: it makes Google Mock throw an exception from a mock object's destructor sometimes. With some compilers, this sometimes causes the test program to crash. You'll still be able to notice that the test has failed, but it's not a graceful failure. A better solution is to use Google Test's [event listener API](http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide#Extending_Google_Test_by_Handling_Test_Events) to report a test failure to your testing framework properly. You'll need to implement the `OnTestPartResult()` method of the event listener interface, but it should be straightforward. If this turns out to be too much work, we suggest that you stick with Google Test, which works with Google Mock seamlessly (in fact, it is technically part of Google Mock.). If there is a reason that you cannot use Google Test, please let us know. # Setting Expectations # The key to using a mock object successfully is to set the _right expectations_ on it. If you set the expectations too strict, your test will fail as the result of unrelated changes. If you set them too loose, bugs can slip through. You want to do it just right such that your test can catch exactly the kind of bugs you intend it to catch. Google Mock provides the necessary means for you to do it "just right." ## General Syntax ## In Google Mock we use the `EXPECT_CALL()` macro to set an expectation on a mock method. The general syntax is: ``` EXPECT_CALL(mock_object, method(matchers)) .Times(cardinality) .WillOnce(action) .WillRepeatedly(action); ``` The macro has two arguments: first the mock object, and then the method and its arguments. Note that the two are separated by a comma (`,`), not a period (`.`). (Why using a comma? The answer is that it was necessary for technical reasons.) The macro can be followed by some optional _clauses_ that provide more information about the expectation. We'll discuss how each clause works in the coming sections. This syntax is designed to make an expectation read like English. For example, you can probably guess that ``` using ::testing::Return;... EXPECT_CALL(turtle, GetX()) .Times(5) .WillOnce(Return(100)) .WillOnce(Return(150)) .WillRepeatedly(Return(200)); ``` says that the `turtle` object's `GetX()` method will be called five times, it will return 100 the first time, 150 the second time, and then 200 every time. Some people like to call this style of syntax a Domain-Specific Language (DSL). **Note:** Why do we use a macro to do this? It serves two purposes: first it makes expectations easily identifiable (either by `grep` or by a human reader), and second it allows Google Mock to include the source file location of a failed expectation in messages, making debugging easier. ## Matchers: What Arguments Do We Expect? ## When a mock function takes arguments, we must specify what arguments we are expecting; for example: ``` // Expects the turtle to move forward by 100 units. EXPECT_CALL(turtle, Forward(100)); ``` Sometimes you may not want to be too specific (Remember that talk about tests being too rigid? Over specification leads to brittle tests and obscures the intent of tests. Therefore we encourage you to specify only what's necessary - no more, no less.). If you care to check that `Forward()` will be called but aren't interested in its actual argument, write `_` as the argument, which means "anything goes": ``` using ::testing::_; ... // Expects the turtle to move forward. EXPECT_CALL(turtle, Forward(_)); ``` `_` is an instance of what we call **matchers**. A matcher is like a predicate and can test whether an argument is what we'd expect. You can use a matcher inside `EXPECT_CALL()` wherever a function argument is expected. A list of built-in matchers can be found in the [CheatSheet](V1_5_CheatSheet.md). For example, here's the `Ge` (greater than or equal) matcher: ``` using ::testing::Ge;... EXPECT_CALL(turtle, Forward(Ge(100))); ``` This checks that the turtle will be told to go forward by at least 100 units. ## Cardinalities: How Many Times Will It Be Called? ## The first clause we can specify following an `EXPECT_CALL()` is `Times()`. We call its argument a **cardinality** as it tells _how many times_ the call should occur. It allows us to repeat an expectation many times without actually writing it as many times. More importantly, a cardinality can be "fuzzy", just like a matcher can be. This allows a user to express the intent of a test exactly. An interesting special case is when we say `Times(0)`. You may have guessed - it means that the function shouldn't be called with the given arguments at all, and Google Mock will report a Google Test failure whenever the function is (wrongfully) called. We've seen `AtLeast(n)` as an example of fuzzy cardinalities earlier. For the list of built-in cardinalities you can use, see the [CheatSheet](V1_5_CheatSheet.md). The `Times()` clause can be omitted. **If you omit `Times()`, Google Mock will infer the cardinality for you.** The rules are easy to remember: * If **neither** `WillOnce()` **nor** `WillRepeatedly()` is in the `EXPECT_CALL()`, the inferred cardinality is `Times(1)`. * If there are `n WillOnce()`'s but **no** `WillRepeatedly()`, where `n` >= 1, the cardinality is `Times(n)`. * If there are `n WillOnce()`'s and **one** `WillRepeatedly()`, where `n` >= 0, the cardinality is `Times(AtLeast(n))`. **Quick quiz:** what do you think will happen if a function is expected to be called twice but actually called four times? ## Actions: What Should It Do? ## Remember that a mock object doesn't really have a working implementation? We as users have to tell it what to do when a method is invoked. This is easy in Google Mock. First, if the return type of a mock function is a built-in type or a pointer, the function has a **default action** (a `void` function will just return, a `bool` function will return `false`, and other functions will return 0). If you don't say anything, this behavior will be used. Second, if a mock function doesn't have a default action, or the default action doesn't suit you, you can specify the action to be taken each time the expectation matches using a series of `WillOnce()` clauses followed by an optional `WillRepeatedly()`. For example, ``` using ::testing::Return;... EXPECT_CALL(turtle, GetX()) .WillOnce(Return(100)) .WillOnce(Return(200)) .WillOnce(Return(300)); ``` This says that `turtle.GetX()` will be called _exactly three times_ (Google Mock inferred this from how many `WillOnce()` clauses we've written, since we didn't explicitly write `Times()`), and will return 100, 200, and 300 respectively. ``` using ::testing::Return;... EXPECT_CALL(turtle, GetY()) .WillOnce(Return(100)) .WillOnce(Return(200)) .WillRepeatedly(Return(300)); ``` says that `turtle.GetY()` will be called _at least twice_ (Google Mock knows this as we've written two `WillOnce()` clauses and a `WillRepeatedly()` while having no explicit `Times()`), will return 100 the first time, 200 the second time, and 300 from the third time on. Of course, if you explicitly write a `Times()`, Google Mock will not try to infer the cardinality itself. What if the number you specified is larger than there are `WillOnce()` clauses? Well, after all `WillOnce()`s are used up, Google Mock will do the _default_ action for the function every time (unless, of course, you have a `WillRepeatedly()`.). What can we do inside `WillOnce()` besides `Return()`? You can return a reference using `ReturnRef(variable)`, or invoke a pre-defined function, among [others](V1_5_CheatSheet#Actions.md). **Important note:** The `EXPECT_CALL()` statement evaluates the action clause only once, even though the action may be performed many times. Therefore you must be careful about side effects. The following may not do what you want: ``` int n = 100; EXPECT_CALL(turtle, GetX()) .Times(4) .WillOnce(Return(n++)); ``` Instead of returning 100, 101, 102, ..., consecutively, this mock function will always return 100 as `n++` is only evaluated once. Similarly, `Return(new Foo)` will create a new `Foo` object when the `EXPECT_CALL()` is executed, and will return the same pointer every time. If you want the side effect to happen every time, you need to define a custom action, which we'll teach in the [CookBook](V1_5_CookBook.md). Time for another quiz! What do you think the following means? ``` using ::testing::Return;... EXPECT_CALL(turtle, GetY()) .Times(4) .WillOnce(Return(100)); ``` Obviously `turtle.GetY()` is expected to be called four times. But if you think it will return 100 every time, think twice! Remember that one `WillOnce()` clause will be consumed each time the function is invoked and the default action will be taken afterwards. So the right answer is that `turtle.GetY()` will return 100 the first time, but **return 0 from the second time on**, as returning 0 is the default action for `int` functions. ## Using Multiple Expectations ## So far we've only shown examples where you have a single expectation. More realistically, you're going to specify expectations on multiple mock methods, which may be from multiple mock objects. By default, when a mock method is invoked, Google Mock will search the expectations in the **reverse order** they are defined, and stop when an active expectation that matches the arguments is found (you can think of it as "newer rules override older ones."). If the matching expectation cannot take any more calls, you will get an upper-bound-violated failure. Here's an example: ``` using ::testing::_;... EXPECT_CALL(turtle, Forward(_)); // #1 EXPECT_CALL(turtle, Forward(10)) // #2 .Times(2); ``` If `Forward(10)` is called three times in a row, the third time it will be an error, as the last matching expectation (#2) has been saturated. If, however, the third `Forward(10)` call is replaced by `Forward(20)`, then it would be OK, as now #1 will be the matching expectation. **Side note:** Why does Google Mock search for a match in the _reverse_ order of the expectations? The reason is that this allows a user to set up the default expectations in a mock object's constructor or the test fixture's set-up phase and then customize the mock by writing more specific expectations in the test body. So, if you have two expectations on the same method, you want to put the one with more specific matchers **after** the other, or the more specific rule would be shadowed by the more general one that comes after it. ## Ordered vs Unordered Calls ## By default, an expectation can match a call even though an earlier expectation hasn't been satisfied. In other words, the calls don't have to occur in the order the expectations are specified. Sometimes, you may want all the expected calls to occur in a strict order. To say this in Google Mock is easy: ``` using ::testing::InSequence;... TEST(FooTest, DrawsLineSegment) { ... { InSequence dummy; EXPECT_CALL(turtle, PenDown()); EXPECT_CALL(turtle, Forward(100)); EXPECT_CALL(turtle, PenUp()); } Foo(); } ``` By creating an object of type `InSequence`, all expectations in its scope are put into a _sequence_ and have to occur _sequentially_. Since we are just relying on the constructor and destructor of this object to do the actual work, its name is really irrelevant. In this example, we test that `Foo()` calls the three expected functions in the order as written. If a call is made out-of-order, it will be an error. (What if you care about the relative order of some of the calls, but not all of them? Can you specify an arbitrary partial order? The answer is ... yes! If you are impatient, the details can be found in the [CookBook](V1_5_CookBook.md).) ## All Expectations Are Sticky (Unless Said Otherwise) ## Now let's do a quick quiz to see how well you can use this mock stuff already. How would you test that the turtle is asked to go to the origin _exactly twice_ (you want to ignore any other instructions it receives)? After you've come up with your answer, take a look at ours and compare notes (solve it yourself first - don't cheat!): ``` using ::testing::_;... EXPECT_CALL(turtle, GoTo(_, _)) // #1 .Times(AnyNumber()); EXPECT_CALL(turtle, GoTo(0, 0)) // #2 .Times(2); ``` Suppose `turtle.GoTo(0, 0)` is called three times. In the third time, Google Mock will see that the arguments match expectation #2 (remember that we always pick the last matching expectation). Now, since we said that there should be only two such calls, Google Mock will report an error immediately. This is basically what we've told you in the "Using Multiple Expectations" section above. This example shows that **expectations in Google Mock are "sticky" by default**, in the sense that they remain active even after we have reached their invocation upper bounds. This is an important rule to remember, as it affects the meaning of the spec, and is **different** to how it's done in many other mocking frameworks (Why'd we do that? Because we think our rule makes the common cases easier to express and understand.). Simple? Let's see if you've really understood it: what does the following code say? ``` using ::testing::Return; ... for (int i = n; i > 0; i--) { EXPECT_CALL(turtle, GetX()) .WillOnce(Return(10*i)); } ``` If you think it says that `turtle.GetX()` will be called `n` times and will return 10, 20, 30, ..., consecutively, think twice! The problem is that, as we said, expectations are sticky. So, the second time `turtle.GetX()` is called, the last (latest) `EXPECT_CALL()` statement will match, and will immediately lead to an "upper bound exceeded" error - this piece of code is not very useful! One correct way of saying that `turtle.GetX()` will return 10, 20, 30, ..., is to explicitly say that the expectations are _not_ sticky. In other words, they should _retire_ as soon as they are saturated: ``` using ::testing::Return; ... for (int i = n; i > 0; i--) { EXPECT_CALL(turtle, GetX()) .WillOnce(Return(10*i)) .RetiresOnSaturation(); } ``` And, there's a better way to do it: in this case, we expect the calls to occur in a specific order, and we line up the actions to match the order. Since the order is important here, we should make it explicit using a sequence: ``` using ::testing::InSequence; using ::testing::Return; ... { InSequence s; for (int i = 1; i <= n; i++) { EXPECT_CALL(turtle, GetX()) .WillOnce(Return(10*i)) .RetiresOnSaturation(); } } ``` By the way, the other situation where an expectation may _not_ be sticky is when it's in a sequence - as soon as another expectation that comes after it in the sequence has been used, it automatically retires (and will never be used to match any call). ## Uninteresting Calls ## A mock object may have many methods, and not all of them are that interesting. For example, in some tests we may not care about how many times `GetX()` and `GetY()` get called. In Google Mock, if you are not interested in a method, just don't say anything about it. If a call to this method occurs, you'll see a warning in the test output, but it won't be a failure. # What Now? # Congratulations! You've learned enough about Google Mock to start using it. Now, you might want to join the [googlemock](http://groups.google.com/group/googlemock) discussion group and actually write some tests using Google Mock - it will be fun. Hey, it may even be addictive - you've been warned. Then, if you feel like increasing your mock quotient, you should move on to the [CookBook](V1_5_CookBook.md). You can learn many advanced features of Google Mock there -- and advance your level of enjoyment and testing bliss.nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/docs/v1_5/FrequentlyAskedQuestions.md000066400000000000000000000552001455373415500317070ustar00rootroot00000000000000 Please send your questions to the [googlemock](http://groups.google.com/group/googlemock) discussion group. If you need help with compiler errors, make sure you have tried [Google Mock Doctor](#How_am_I_supposed_to_make_sense_of_these_horrible_template_error.md) first. ## I wrote some matchers. After I upgraded to a new version of Google Mock, they no longer compile. What's going on? ## After version 1.4.0 of Google Mock was released, we had an idea on how to make it easier to write matchers that can generate informative messages efficiently. We experimented with this idea and liked what we saw. Therefore we decided to implement it. Unfortunately, this means that if you have defined your own matchers by implementing `MatcherInterface` or using `MakePolymorphicMatcher()`, your definitions will no longer compile. Matchers defined using the `MATCHER*` family of macros are not affected. Sorry for the hassle if your matchers are affected. We believe it's in everyone's long-term interest to make this change sooner than later. Fortunately, it's usually not hard to migrate an existing matcher to the new API. Here's what you need to do: If you wrote your matcher like this: ``` // Old matcher definition that doesn't work with the latest // Google Mock. using ::testing::MatcherInterface; ... class MyWonderfulMatcher : public MatcherInterface { public: ... virtual bool Matches(MyType value) const { // Returns true if value matches. return value.GetFoo() > 5; } ... }; ``` you'll need to change it to: ``` // New matcher definition that works with the latest Google Mock. using ::testing::MatcherInterface; using ::testing::MatchResultListener; ... class MyWonderfulMatcher : public MatcherInterface { public: ... virtual bool MatchAndExplain(MyType value, MatchResultListener* listener) const { // Returns true if value matches. return value.GetFoo() > 5; } ... }; ``` (i.e. rename `Matches()` to `MatchAndExplain()` and give it a second argument of type `MatchResultListener*`.) If you were also using `ExplainMatchResultTo()` to improve the matcher message: ``` // Old matcher definition that doesn't work with the lastest // Google Mock. using ::testing::MatcherInterface; ... class MyWonderfulMatcher : public MatcherInterface { public: ... virtual bool Matches(MyType value) const { // Returns true if value matches. return value.GetFoo() > 5; } virtual void ExplainMatchResultTo(MyType value, ::std::ostream* os) const { // Prints some helpful information to os to help // a user understand why value matches (or doesn't match). *os << "the Foo property is " << value.GetFoo(); } ... }; ``` you should move the logic of `ExplainMatchResultTo()` into `MatchAndExplain()`, using the `MatchResultListener` argument where the `::std::ostream` was used: ``` // New matcher definition that works with the latest Google Mock. using ::testing::MatcherInterface; using ::testing::MatchResultListener; ... class MyWonderfulMatcher : public MatcherInterface { public: ... virtual bool MatchAndExplain(MyType value, MatchResultListener* listener) const { // Returns true if value matches. *listener << "the Foo property is " << value.GetFoo(); return value.GetFoo() > 5; } ... }; ``` If your matcher is defined using `MakePolymorphicMatcher()`: ``` // Old matcher definition that doesn't work with the latest // Google Mock. using ::testing::MakePolymorphicMatcher; ... class MyGreatMatcher { public: ... bool Matches(MyType value) const { // Returns true if value matches. return value.GetBar() < 42; } ... }; ... MakePolymorphicMatcher(MyGreatMatcher()) ... ``` you should rename the `Matches()` method to `MatchAndExplain()` and add a `MatchResultListener*` argument (the same as what you need to do for matchers defined by implementing `MatcherInterface`): ``` // New matcher definition that works with the latest Google Mock. using ::testing::MakePolymorphicMatcher; using ::testing::MatchResultListener; ... class MyGreatMatcher { public: ... bool MatchAndExplain(MyType value, MatchResultListener* listener) const { // Returns true if value matches. return value.GetBar() < 42; } ... }; ... MakePolymorphicMatcher(MyGreatMatcher()) ... ``` If your polymorphic matcher uses `ExplainMatchResultTo()` for better failure messages: ``` // Old matcher definition that doesn't work with the latest // Google Mock. using ::testing::MakePolymorphicMatcher; ... class MyGreatMatcher { public: ... bool Matches(MyType value) const { // Returns true if value matches. return value.GetBar() < 42; } ... }; void ExplainMatchResultTo(const MyGreatMatcher& matcher, MyType value, ::std::ostream* os) { // Prints some helpful information to os to help // a user understand why value matches (or doesn't match). *os << "the Bar property is " << value.GetBar(); } ... MakePolymorphicMatcher(MyGreatMatcher()) ... ``` you'll need to move the logic inside `ExplainMatchResultTo()` to `MatchAndExplain()`: ``` // New matcher definition that works with the latest Google Mock. using ::testing::MakePolymorphicMatcher; using ::testing::MatchResultListener; ... class MyGreatMatcher { public: ... bool MatchAndExplain(MyType value, MatchResultListener* listener) const { // Returns true if value matches. *listener << "the Bar property is " << value.GetBar(); return value.GetBar() < 42; } ... }; ... MakePolymorphicMatcher(MyGreatMatcher()) ... ``` For more information, you can read these [two](V1_5_CookBook#Writing_New_Monomorphic_Matchers.md) [recipes](V1_5_CookBook#Writing_New_Polymorphic_Matchers.md) from the cookbook. As always, you are welcome to post questions on `googlemock@googlegroups.com` if you need any help. ## When using Google Mock, do I have to use Google Test as the testing framework? I have my favorite testing framework and don't want to switch. ## Google Mock works out of the box with Google Test. However, it's easy to configure it to work with any testing framework of your choice. [Here](V1_5_ForDummies#Using_Google_Mock_with_Any_Testing_Framework.md) is how. ## How am I supposed to make sense of these horrible template errors? ## If you are confused by the compiler errors gcc threw at you, try consulting the _Google Mock Doctor_ tool first. What it does is to scan stdin for gcc error messages, and spit out diagnoses on the problems (we call them diseases) your code has. To "install", run command: ``` alias gmd='/scripts/gmock_doctor.py' ``` To use it, do: ``` 2>&1 | gmd ``` For example: ``` make my_test 2>&1 | gmd ``` Or you can run `gmd` and copy-n-paste gcc's error messages to it. ## Can I mock a variadic function? ## You cannot mock a variadic function (i.e. a function taking ellipsis (`...`) arguments) directly in Google Mock. The problem is that in general, there is _no way_ for a mock object to know how many arguments are passed to the variadic method, and what the arguments' types are. Only the _author of the base class_ knows the protocol, and we cannot look into his head. Therefore, to mock such a function, the _user_ must teach the mock object how to figure out the number of arguments and their types. One way to do it is to provide overloaded versions of the function. Ellipsis arguments are inherited from C and not really a C++ feature. They are unsafe to use and don't work with arguments that have constructors or destructors. Therefore we recommend to avoid them in C++ as much as possible. ## MSVC gives me warning C4301 or C4373 when I define a mock method with a const parameter. Why? ## If you compile this using Microsoft Visual C++ 2005 SP1: ``` class Foo { ... virtual void Bar(const int i) = 0; }; class MockFoo : public Foo { ... MOCK_METHOD1(Bar, void(const int i)); }; ``` You may get the following warning: ``` warning C4301: 'MockFoo::Bar': overriding virtual function only differs from 'Foo::Bar' by const/volatile qualifier ``` This is a MSVC bug. The same code compiles fine with gcc ,for example. If you use Visual C++ 2008 SP1, you would get the warning: ``` warning C4373: 'MockFoo::Bar': virtual function overrides 'Foo::Bar', previous versions of the compiler did not override when parameters only differed by const/volatile qualifiers ``` In C++, if you _declare_ a function with a `const` parameter, the `const` modifier is _ignored_. Therefore, the `Foo` base class above is equivalent to: ``` class Foo { ... virtual void Bar(int i) = 0; // int or const int? Makes no difference. }; ``` In fact, you can _declare_ Bar() with an `int` parameter, and _define_ it with a `const int` parameter. The compiler will still match them up. Since making a parameter `const` is meaningless in the method _declaration_, we recommend to remove it in both `Foo` and `MockFoo`. That should workaround the VC bug. Note that we are talking about the _top-level_ `const` modifier here. If the function parameter is passed by pointer or reference, declaring the _pointee_ or _referee_ as `const` is still meaningful. For example, the following two declarations are _not_ equivalent: ``` void Bar(int* p); // Neither p nor *p is const. void Bar(const int* p); // p is not const, but *p is. ``` ## I have a huge mock class, and Microsoft Visual C++ runs out of memory when compiling it. What can I do? ## We've noticed that when the `/clr` compiler flag is used, Visual C++ uses 5~6 times as much memory when compiling a mock class. We suggest to avoid `/clr` when compiling native C++ mocks. ## I can't figure out why Google Mock thinks my expectations are not satisfied. What should I do? ## You might want to run your test with `--gmock_verbose=info`. This flag lets Google Mock print a trace of every mock function call it receives. By studying the trace, you'll gain insights on why the expectations you set are not met. ## How can I assert that a function is NEVER called? ## ``` EXPECT_CALL(foo, Bar(_)) .Times(0); ``` ## I have a failed test where Google Mock tells me TWICE that a particular expectation is not satisfied. Isn't this redundant? ## When Google Mock detects a failure, it prints relevant information (the mock function arguments, the state of relevant expectations, and etc) to help the user debug. If another failure is detected, Google Mock will do the same, including printing the state of relevant expectations. Sometimes an expectation's state didn't change between two failures, and you'll see the same description of the state twice. They are however _not_ redundant, as they refer to _different points in time_. The fact they are the same _is_ interesting information. ## I get a heap check failure when using a mock object, but using a real object is fine. What can be wrong? ## Does the class (hopefully a pure interface) you are mocking have a virtual destructor? Whenever you derive from a base class, make sure its destructor is virtual. Otherwise Bad Things will happen. Consider the following code: ``` class Base { public: // Not virtual, but should be. ~Base() { ... } ... }; class Derived : public Base { public: ... private: std::string value_; }; ... Base* p = new Derived; ... delete p; // Surprise! ~Base() will be called, but ~Derived() will not // - value_ is leaked. ``` By changing `~Base()` to virtual, `~Derived()` will be correctly called when `delete p` is executed, and the heap checker will be happy. ## The "newer expectations override older ones" rule makes writing expectations awkward. Why does Google Mock do that? ## When people complain about this, often they are referring to code like: ``` // foo.Bar() should be called twice, return 1 the first time, and return // 2 the second time. However, I have to write the expectations in the // reverse order. This sucks big time!!! EXPECT_CALL(foo, Bar()) .WillOnce(Return(2)) .RetiresOnSaturation(); EXPECT_CALL(foo, Bar()) .WillOnce(Return(1)) .RetiresOnSaturation(); ``` The problem is that they didn't pick the **best** way to express the test's intent. By default, expectations don't have to be matched in _any_ particular order. If you want them to match in a certain order, you need to be explicit. This is Google Mock's (and jMock's) fundamental philosophy: it's easy to accidentally over-specify your tests, and we want to make it harder to do so. There are two better ways to write the test spec. You could either put the expectations in sequence: ``` // foo.Bar() should be called twice, return 1 the first time, and return // 2 the second time. Using a sequence, we can write the expectations // in their natural order. { InSequence s; EXPECT_CALL(foo, Bar()) .WillOnce(Return(1)) .RetiresOnSaturation(); EXPECT_CALL(foo, Bar()) .WillOnce(Return(2)) .RetiresOnSaturation(); } ``` or you can put the sequence of actions in the same expectation: ``` // foo.Bar() should be called twice, return 1 the first time, and return // 2 the second time. EXPECT_CALL(foo, Bar()) .WillOnce(Return(1)) .WillOnce(Return(2)) .RetiresOnSaturation(); ``` Back to the original questions: why does Google Mock search the expectations (and `ON_CALL`s) from back to front? Because this allows a user to set up a mock's behavior for the common case early (e.g. in the mock's constructor or the test fixture's set-up phase) and customize it with more specific rules later. If Google Mock searches from front to back, this very useful pattern won't be possible. ## Google Mock prints a warning when a function without EXPECT\_CALL is called, even if I have set its behavior using ON\_CALL. Would it be reasonable not to show the warning in this case? ## When choosing between being neat and being safe, we lean toward the latter. So the answer is that we think it's better to show the warning. Often people write `ON_CALL`s in the mock object's constructor or `SetUp()`, as the default behavior rarely changes from test to test. Then in the test body they set the expectations, which are often different for each test. Having an `ON_CALL` in the set-up part of a test doesn't mean that the calls are expected. If there's no `EXPECT_CALL` and the method is called, it's possibly an error. If we quietly let the call go through without notifying the user, bugs may creep in unnoticed. If, however, you are sure that the calls are OK, you can write ``` EXPECT_CALL(foo, Bar(_)) .WillRepeatedly(...); ``` instead of ``` ON_CALL(foo, Bar(_)) .WillByDefault(...); ``` This tells Google Mock that you do expect the calls and no warning should be printed. Also, you can control the verbosity using the `--gmock_verbose` flag. If you find the output too noisy when debugging, just choose a less verbose level. ## How can I delete the mock function's argument in an action? ## If you find yourself needing to perform some action that's not supported by Google Mock directly, remember that you can define your own actions using [MakeAction()](V1_5_CookBook#Writing_New_Actions.md) or [MakePolymorphicAction()](V1_5_CookBook#Writing_New_Polymorphic_Actions.md), or you can write a stub function and invoke it using [Invoke()](V1_5_CookBook#Using_Functions_Methods_Functors.md). ## MOCK\_METHODn()'s second argument looks funny. Why don't you use the MOCK\_METHODn(Method, return\_type, arg\_1, ..., arg\_n) syntax? ## What?! I think it's beautiful. :-) While which syntax looks more natural is a subjective matter to some extent, Google Mock's syntax was chosen for several practical advantages it has. Try to mock a function that takes a map as an argument: ``` virtual int GetSize(const map& m); ``` Using the proposed syntax, it would be: ``` MOCK_METHOD1(GetSize, int, const map& m); ``` Guess what? You'll get a compiler error as the compiler thinks that `const map& m` are **two**, not one, arguments. To work around this you can use `typedef` to give the map type a name, but that gets in the way of your work. Google Mock's syntax avoids this problem as the function's argument types are protected inside a pair of parentheses: ``` // This compiles fine. MOCK_METHOD1(GetSize, int(const map& m)); ``` You still need a `typedef` if the return type contains an unprotected comma, but that's much rarer. Other advantages include: 1. `MOCK_METHOD1(Foo, int, bool)` can leave a reader wonder whether the method returns `int` or `bool`, while there won't be such confusion using Google Mock's syntax. 1. The way Google Mock describes a function type is nothing new, although many people may not be familiar with it. The same syntax was used in C, and the `function` library in `tr1` uses this syntax extensively. Since `tr1` will become a part of the new version of STL, we feel very comfortable to be consistent with it. 1. The function type syntax is also used in other parts of Google Mock's API (e.g. the action interface) in order to make the implementation tractable. A user needs to learn it anyway in order to utilize Google Mock's more advanced features. We'd as well stick to the same syntax in `MOCK_METHOD*`! ## My code calls a static/global function. Can I mock it? ## You can, but you need to make some changes. In general, if you find yourself needing to mock a static function, it's a sign that your modules are too tightly coupled (and less flexible, less reusable, less testable, etc). You are probably better off defining a small interface and call the function through that interface, which then can be easily mocked. It's a bit of work initially, but usually pays for itself quickly. This Google Testing Blog [post](http://googletesting.blogspot.com/2008/06/defeat-static-cling.html) says it excellently. Check it out. ## My mock object needs to do complex stuff. It's a lot of pain to specify the actions. Google Mock sucks! ## I know it's not a question, but you get an answer for free any way. :-) With Google Mock, you can create mocks in C++ easily. And people might be tempted to use them everywhere. Sometimes they work great, and sometimes you may find them, well, a pain to use. So, what's wrong in the latter case? When you write a test without using mocks, you exercise the code and assert that it returns the correct value or that the system is in an expected state. This is sometimes called "state-based testing". Mocks are great for what some call "interaction-based" testing: instead of checking the system state at the very end, mock objects verify that they are invoked the right way and report an error as soon as it arises, giving you a handle on the precise context in which the error was triggered. This is often more effective and economical to do than state-based testing. If you are doing state-based testing and using a test double just to simulate the real object, you are probably better off using a fake. Using a mock in this case causes pain, as it's not a strong point for mocks to perform complex actions. If you experience this and think that mocks suck, you are just not using the right tool for your problem. Or, you might be trying to solve the wrong problem. :-) ## I got a warning "Uninteresting function call encountered - default action taken.." Should I panic? ## By all means, NO! It's just an FYI. What it means is that you have a mock function, you haven't set any expectations on it (by Google Mock's rule this means that you are not interested in calls to this function and therefore it can be called any number of times), and it is called. That's OK - you didn't say it's not OK to call the function! What if you actually meant to disallow this function to be called, but forgot to write `EXPECT_CALL(foo, Bar()).Times(0)`? While one can argue that it's the user's fault, Google Mock tries to be nice and prints you a note. So, when you see the message and believe that there shouldn't be any uninteresting calls, you should investigate what's going on. To make your life easier, Google Mock prints the function name and arguments when an uninteresting call is encountered. ## I want to define a custom action. Should I use Invoke() or implement the action interface? ## Either way is fine - you want to choose the one that's more convenient for your circumstance. Usually, if your action is for a particular function type, defining it using `Invoke()` should be easier; if your action can be used in functions of different types (e.g. if you are defining `Return(value)`), `MakePolymorphicAction()` is easiest. Sometimes you want precise control on what types of functions the action can be used in, and implementing `ActionInterface` is the way to go here. See the implementation of `Return()` in `include/gmock/gmock-actions.h` for an example. ## I'm using the set-argument-pointee action, and the compiler complains about "conflicting return type specified". What does it mean? ## You got this error as Google Mock has no idea what value it should return when the mock method is called. `SetArgumentPointee()` says what the side effect is, but doesn't say what the return value should be. You need `DoAll()` to chain a `SetArgumentPointee()` with a `Return()`. See this [recipe](V1_5_CookBook#Mocking_Side_Effects.md) for more details and an example. ## My question is not in your FAQ! ## If you cannot find the answer to your question in this FAQ, there are some other resources you can use: 1. read other [wiki pages](http://code.google.com/p/googlemock/w/list), 1. search the mailing list [archive](http://groups.google.com/group/googlemock/topics), 1. ask it on [googlemock@googlegroups.com](mailto:googlemock@googlegroups.com) and someone will answer it (to prevent spam, we require you to join the [discussion group](http://groups.google.com/group/googlemock) before you can post.). Please note that creating an issue in the [issue tracker](http://code.google.com/p/googlemock/issues/list) is _not_ a good way to get your answer, as it is monitored infrequently by a very small number of people. When asking a question, it's helpful to provide as much of the following information as possible (people cannot help you if there's not enough information in your question): * the version (or the revision number if you check out from SVN directly) of Google Mock you use (Google Mock is under active development, so it's possible that your problem has been solved in a later version), * your operating system, * the name and version of your compiler, * the complete command line flags you give to your compiler, * the complete compiler error messages (if the question is about compilation), * the _actual_ code (ideally, a minimal but complete program) that has the problem you encounter.nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/docs/v1_6/000077500000000000000000000000001455373415500243435ustar00rootroot00000000000000nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/docs/v1_6/CheatSheet.md000066400000000000000000000611771455373415500267160ustar00rootroot00000000000000 # Defining a Mock Class # ## Mocking a Normal Class ## Given ``` class Foo { ... virtual ~Foo(); virtual int GetSize() const = 0; virtual string Describe(const char* name) = 0; virtual string Describe(int type) = 0; virtual bool Process(Bar elem, int count) = 0; }; ``` (note that `~Foo()` **must** be virtual) we can define its mock as ``` #include "gmock/gmock.h" class MockFoo : public Foo { MOCK_CONST_METHOD0(GetSize, int()); MOCK_METHOD1(Describe, string(const char* name)); MOCK_METHOD1(Describe, string(int type)); MOCK_METHOD2(Process, bool(Bar elem, int count)); }; ``` To create a "nice" mock object which ignores all uninteresting calls, or a "strict" mock object, which treats them as failures: ``` NiceMock nice_foo; // The type is a subclass of MockFoo. StrictMock strict_foo; // The type is a subclass of MockFoo. ``` ## Mocking a Class Template ## To mock ``` template class StackInterface { public: ... virtual ~StackInterface(); virtual int GetSize() const = 0; virtual void Push(const Elem& x) = 0; }; ``` (note that `~StackInterface()` **must** be virtual) just append `_T` to the `MOCK_*` macros: ``` template class MockStack : public StackInterface { public: ... MOCK_CONST_METHOD0_T(GetSize, int()); MOCK_METHOD1_T(Push, void(const Elem& x)); }; ``` ## Specifying Calling Conventions for Mock Functions ## If your mock function doesn't use the default calling convention, you can specify it by appending `_WITH_CALLTYPE` to any of the macros described in the previous two sections and supplying the calling convention as the first argument to the macro. For example, ``` MOCK_METHOD_1_WITH_CALLTYPE(STDMETHODCALLTYPE, Foo, bool(int n)); MOCK_CONST_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, Bar, int(double x, double y)); ``` where `STDMETHODCALLTYPE` is defined by `` on Windows. # Using Mocks in Tests # The typical flow is: 1. Import the Google Mock names you need to use. All Google Mock names are in the `testing` namespace unless they are macros or otherwise noted. 1. Create the mock objects. 1. Optionally, set the default actions of the mock objects. 1. Set your expectations on the mock objects (How will they be called? What wil they do?). 1. Exercise code that uses the mock objects; if necessary, check the result using [Google Test](http://code.google.com/p/googletest/) assertions. 1. When a mock objects is destructed, Google Mock automatically verifies that all expectations on it have been satisfied. Here is an example: ``` using ::testing::Return; // #1 TEST(BarTest, DoesThis) { MockFoo foo; // #2 ON_CALL(foo, GetSize()) // #3 .WillByDefault(Return(1)); // ... other default actions ... EXPECT_CALL(foo, Describe(5)) // #4 .Times(3) .WillRepeatedly(Return("Category 5")); // ... other expectations ... EXPECT_EQ("good", MyProductionFunction(&foo)); // #5 } // #6 ``` # Setting Default Actions # Google Mock has a **built-in default action** for any function that returns `void`, `bool`, a numeric value, or a pointer. To customize the default action for functions with return type `T` globally: ``` using ::testing::DefaultValue; DefaultValue::Set(value); // Sets the default value to be returned. // ... use the mocks ... DefaultValue::Clear(); // Resets the default value. ``` To customize the default action for a particular method, use `ON_CALL()`: ``` ON_CALL(mock_object, method(matchers)) .With(multi_argument_matcher) ? .WillByDefault(action); ``` # Setting Expectations # `EXPECT_CALL()` sets **expectations** on a mock method (How will it be called? What will it do?): ``` EXPECT_CALL(mock_object, method(matchers)) .With(multi_argument_matcher) ? .Times(cardinality) ? .InSequence(sequences) * .After(expectations) * .WillOnce(action) * .WillRepeatedly(action) ? .RetiresOnSaturation(); ? ``` If `Times()` is omitted, the cardinality is assumed to be: * `Times(1)` when there is neither `WillOnce()` nor `WillRepeatedly()`; * `Times(n)` when there are `n WillOnce()`s but no `WillRepeatedly()`, where `n` >= 1; or * `Times(AtLeast(n))` when there are `n WillOnce()`s and a `WillRepeatedly()`, where `n` >= 0. A method with no `EXPECT_CALL()` is free to be invoked _any number of times_, and the default action will be taken each time. # Matchers # A **matcher** matches a _single_ argument. You can use it inside `ON_CALL()` or `EXPECT_CALL()`, or use it to validate a value directly: | `EXPECT_THAT(value, matcher)` | Asserts that `value` matches `matcher`. | |:------------------------------|:----------------------------------------| | `ASSERT_THAT(value, matcher)` | The same as `EXPECT_THAT(value, matcher)`, except that it generates a **fatal** failure. | Built-in matchers (where `argument` is the function argument) are divided into several categories: ## Wildcard ## |`_`|`argument` can be any value of the correct type.| |:--|:-----------------------------------------------| |`A()` or `An()`|`argument` can be any value of type `type`. | ## Generic Comparison ## |`Eq(value)` or `value`|`argument == value`| |:---------------------|:------------------| |`Ge(value)` |`argument >= value`| |`Gt(value)` |`argument > value` | |`Le(value)` |`argument <= value`| |`Lt(value)` |`argument < value` | |`Ne(value)` |`argument != value`| |`IsNull()` |`argument` is a `NULL` pointer (raw or smart).| |`NotNull()` |`argument` is a non-null pointer (raw or smart).| |`Ref(variable)` |`argument` is a reference to `variable`.| |`TypedEq(value)`|`argument` has type `type` and is equal to `value`. You may need to use this instead of `Eq(value)` when the mock function is overloaded.| Except `Ref()`, these matchers make a _copy_ of `value` in case it's modified or destructed later. If the compiler complains that `value` doesn't have a public copy constructor, try wrap it in `ByRef()`, e.g. `Eq(ByRef(non_copyable_value))`. If you do that, make sure `non_copyable_value` is not changed afterwards, or the meaning of your matcher will be changed. ## Floating-Point Matchers ## |`DoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as unequal.| |:-------------------|:----------------------------------------------------------------------------------------------| |`FloatEq(a_float)` |`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as unequal. | |`NanSensitiveDoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as equal. | |`NanSensitiveFloatEq(a_float)`|`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as equal. | These matchers use ULP-based comparison (the same as used in [Google Test](http://code.google.com/p/googletest/)). They automatically pick a reasonable error bound based on the absolute value of the expected value. `DoubleEq()` and `FloatEq()` conform to the IEEE standard, which requires comparing two NaNs for equality to return false. The `NanSensitive*` version instead treats two NaNs as equal, which is often what a user wants. ## String Matchers ## The `argument` can be either a C string or a C++ string object: |`ContainsRegex(string)`|`argument` matches the given regular expression.| |:----------------------|:-----------------------------------------------| |`EndsWith(suffix)` |`argument` ends with string `suffix`. | |`HasSubstr(string)` |`argument` contains `string` as a sub-string. | |`MatchesRegex(string)` |`argument` matches the given regular expression with the match starting at the first character and ending at the last character.| |`StartsWith(prefix)` |`argument` starts with string `prefix`. | |`StrCaseEq(string)` |`argument` is equal to `string`, ignoring case. | |`StrCaseNe(string)` |`argument` is not equal to `string`, ignoring case.| |`StrEq(string)` |`argument` is equal to `string`. | |`StrNe(string)` |`argument` is not equal to `string`. | `ContainsRegex()` and `MatchesRegex()` use the regular expression syntax defined [here](http://code.google.com/p/googletest/wiki/V1_6_AdvancedGuide#Regular_Expression_Syntax). `StrCaseEq()`, `StrCaseNe()`, `StrEq()`, and `StrNe()` work for wide strings as well. ## Container Matchers ## Most STL-style containers support `==`, so you can use `Eq(expected_container)` or simply `expected_container` to match a container exactly. If you want to write the elements in-line, match them more flexibly, or get more informative messages, you can use: | `Contains(e)` | `argument` contains an element that matches `e`, which can be either a value or a matcher. | |:--------------|:-------------------------------------------------------------------------------------------| | `Each(e)` | `argument` is a container where _every_ element matches `e`, which can be either a value or a matcher. | | `ElementsAre(e0, e1, ..., en)` | `argument` has `n + 1` elements, where the i-th element matches `ei`, which can be a value or a matcher. 0 to 10 arguments are allowed. | | `ElementsAreArray(array)` or `ElementsAreArray(array, count)` | The same as `ElementsAre()` except that the expected element values/matchers come from a C-style array. | | `ContainerEq(container)` | The same as `Eq(container)` except that the failure message also includes which elements are in one container but not the other. | | `Pointwise(m, container)` | `argument` contains the same number of elements as in `container`, and for all i, (the i-th element in `argument`, the i-th element in `container`) match `m`, which is a matcher on 2-tuples. E.g. `Pointwise(Le(), upper_bounds)` verifies that each element in `argument` doesn't exceed the corresponding element in `upper_bounds`. | These matchers can also match: 1. a native array passed by reference (e.g. in `Foo(const int (&a)[5])`), and 1. an array passed as a pointer and a count (e.g. in `Bar(const T* buffer, int len)` -- see [Multi-argument Matchers](#Multiargument_Matchers.md)). where the array may be multi-dimensional (i.e. its elements can be arrays). ## Member Matchers ## |`Field(&class::field, m)`|`argument.field` (or `argument->field` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.| |:------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------| |`Key(e)` |`argument.first` matches `e`, which can be either a value or a matcher. E.g. `Contains(Key(Le(5)))` can verify that a `map` contains a key `<= 5`.| |`Pair(m1, m2)` |`argument` is an `std::pair` whose `first` field matches `m1` and `second` field matches `m2`. | |`Property(&class::property, m)`|`argument.property()` (or `argument->property()` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.| ## Matching the Result of a Function or Functor ## |`ResultOf(f, m)`|`f(argument)` matches matcher `m`, where `f` is a function or functor.| |:---------------|:---------------------------------------------------------------------| ## Pointer Matchers ## |`Pointee(m)`|`argument` (either a smart pointer or a raw pointer) points to a value that matches matcher `m`.| |:-----------|:-----------------------------------------------------------------------------------------------| ## Multiargument Matchers ## Technically, all matchers match a _single_ value. A "multi-argument" matcher is just one that matches a _tuple_. The following matchers can be used to match a tuple `(x, y)`: |`Eq()`|`x == y`| |:-----|:-------| |`Ge()`|`x >= y`| |`Gt()`|`x > y` | |`Le()`|`x <= y`| |`Lt()`|`x < y` | |`Ne()`|`x != y`| You can use the following selectors to pick a subset of the arguments (or reorder them) to participate in the matching: |`AllArgs(m)`|Equivalent to `m`. Useful as syntactic sugar in `.With(AllArgs(m))`.| |:-----------|:-------------------------------------------------------------------| |`Args(m)`|The tuple of the `k` selected (using 0-based indices) arguments matches `m`, e.g. `Args<1, 2>(Eq())`.| ## Composite Matchers ## You can make a matcher from one or more other matchers: |`AllOf(m1, m2, ..., mn)`|`argument` matches all of the matchers `m1` to `mn`.| |:-----------------------|:---------------------------------------------------| |`AnyOf(m1, m2, ..., mn)`|`argument` matches at least one of the matchers `m1` to `mn`.| |`Not(m)` |`argument` doesn't match matcher `m`. | ## Adapters for Matchers ## |`MatcherCast(m)`|casts matcher `m` to type `Matcher`.| |:------------------|:--------------------------------------| |`SafeMatcherCast(m)`| [safely casts](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Casting_Matchers) matcher `m` to type `Matcher`. | |`Truly(predicate)` |`predicate(argument)` returns something considered by C++ to be true, where `predicate` is a function or functor.| ## Matchers as Predicates ## |`Matches(m)(value)`|evaluates to `true` if `value` matches `m`. You can use `Matches(m)` alone as a unary functor.| |:------------------|:---------------------------------------------------------------------------------------------| |`ExplainMatchResult(m, value, result_listener)`|evaluates to `true` if `value` matches `m`, explaining the result to `result_listener`. | |`Value(value, m)` |evaluates to `true` if `value` matches `m`. | ## Defining Matchers ## | `MATCHER(IsEven, "") { return (arg % 2) == 0; }` | Defines a matcher `IsEven()` to match an even number. | |:-------------------------------------------------|:------------------------------------------------------| | `MATCHER_P(IsDivisibleBy, n, "") { *result_listener << "where the remainder is " << (arg % n); return (arg % n) == 0; }` | Defines a macher `IsDivisibleBy(n)` to match a number divisible by `n`. | | `MATCHER_P2(IsBetween, a, b, std::string(negation ? "isn't" : "is") + " between " + PrintToString(a) + " and " + PrintToString(b)) { return a <= arg && arg <= b; }` | Defines a matcher `IsBetween(a, b)` to match a value in the range [`a`, `b`]. | **Notes:** 1. The `MATCHER*` macros cannot be used inside a function or class. 1. The matcher body must be _purely functional_ (i.e. it cannot have any side effect, and the result must not depend on anything other than the value being matched and the matcher parameters). 1. You can use `PrintToString(x)` to convert a value `x` of any type to a string. ## Matchers as Test Assertions ## |`ASSERT_THAT(expression, m)`|Generates a [fatal failure](http://code.google.com/p/googletest/wiki/V1_6_Primer#Assertions) if the value of `expression` doesn't match matcher `m`.| |:---------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------| |`EXPECT_THAT(expression, m)`|Generates a non-fatal failure if the value of `expression` doesn't match matcher `m`. | # Actions # **Actions** specify what a mock function should do when invoked. ## Returning a Value ## |`Return()`|Return from a `void` mock function.| |:---------|:----------------------------------| |`Return(value)`|Return `value`. If the type of `value` is different to the mock function's return type, `value` is converted to the latter type at the time the expectation is set, not when the action is executed.| |`ReturnArg()`|Return the `N`-th (0-based) argument.| |`ReturnNew(a1, ..., ak)`|Return `new T(a1, ..., ak)`; a different object is created each time.| |`ReturnNull()`|Return a null pointer. | |`ReturnPointee(ptr)`|Return the value pointed to by `ptr`.| |`ReturnRef(variable)`|Return a reference to `variable`. | |`ReturnRefOfCopy(value)`|Return a reference to a copy of `value`; the copy lives as long as the action.| ## Side Effects ## |`Assign(&variable, value)`|Assign `value` to variable.| |:-------------------------|:--------------------------| | `DeleteArg()` | Delete the `N`-th (0-based) argument, which must be a pointer. | | `SaveArg(pointer)` | Save the `N`-th (0-based) argument to `*pointer`. | | `SaveArgPointee(pointer)` | Save the value pointed to by the `N`-th (0-based) argument to `*pointer`. | | `SetArgReferee(value)` | Assign value to the variable referenced by the `N`-th (0-based) argument. | |`SetArgPointee(value)` |Assign `value` to the variable pointed by the `N`-th (0-based) argument.| |`SetArgumentPointee(value)`|Same as `SetArgPointee(value)`. Deprecated. Will be removed in v1.7.0.| |`SetArrayArgument(first, last)`|Copies the elements in source range [`first`, `last`) to the array pointed to by the `N`-th (0-based) argument, which can be either a pointer or an iterator. The action does not take ownership of the elements in the source range.| |`SetErrnoAndReturn(error, value)`|Set `errno` to `error` and return `value`.| |`Throw(exception)` |Throws the given exception, which can be any copyable value. Available since v1.1.0.| ## Using a Function or a Functor as an Action ## |`Invoke(f)`|Invoke `f` with the arguments passed to the mock function, where `f` can be a global/static function or a functor.| |:----------|:-----------------------------------------------------------------------------------------------------------------| |`Invoke(object_pointer, &class::method)`|Invoke the {method on the object with the arguments passed to the mock function. | |`InvokeWithoutArgs(f)`|Invoke `f`, which can be a global/static function or a functor. `f` must take no arguments. | |`InvokeWithoutArgs(object_pointer, &class::method)`|Invoke the method on the object, which takes no arguments. | |`InvokeArgument(arg1, arg2, ..., argk)`|Invoke the mock function's `N`-th (0-based) argument, which must be a function or a functor, with the `k` arguments.| The return value of the invoked function is used as the return value of the action. When defining a function or functor to be used with `Invoke*()`, you can declare any unused parameters as `Unused`: ``` double Distance(Unused, double x, double y) { return sqrt(x*x + y*y); } ... EXPECT_CALL(mock, Foo("Hi", _, _)).WillOnce(Invoke(Distance)); ``` In `InvokeArgument(...)`, if an argument needs to be passed by reference, wrap it inside `ByRef()`. For example, ``` InvokeArgument<2>(5, string("Hi"), ByRef(foo)) ``` calls the mock function's #2 argument, passing to it `5` and `string("Hi")` by value, and `foo` by reference. ## Default Action ## |`DoDefault()`|Do the default action (specified by `ON_CALL()` or the built-in one).| |:------------|:--------------------------------------------------------------------| **Note:** due to technical reasons, `DoDefault()` cannot be used inside a composite action - trying to do so will result in a run-time error. ## Composite Actions ## |`DoAll(a1, a2, ..., an)`|Do all actions `a1` to `an` and return the result of `an` in each invocation. The first `n - 1` sub-actions must return void. | |:-----------------------|:-----------------------------------------------------------------------------------------------------------------------------| |`IgnoreResult(a)` |Perform action `a` and ignore its result. `a` must not return void. | |`WithArg(a)` |Pass the `N`-th (0-based) argument of the mock function to action `a` and perform it. | |`WithArgs(a)`|Pass the selected (0-based) arguments of the mock function to action `a` and perform it. | |`WithoutArgs(a)` |Perform action `a` without any arguments. | ## Defining Actions ## | `ACTION(Sum) { return arg0 + arg1; }` | Defines an action `Sum()` to return the sum of the mock function's argument #0 and #1. | |:--------------------------------------|:---------------------------------------------------------------------------------------| | `ACTION_P(Plus, n) { return arg0 + n; }` | Defines an action `Plus(n)` to return the sum of the mock function's argument #0 and `n`. | | `ACTION_Pk(Foo, p1, ..., pk) { statements; }` | Defines a parameterized action `Foo(p1, ..., pk)` to execute the given `statements`. | The `ACTION*` macros cannot be used inside a function or class. # Cardinalities # These are used in `Times()` to specify how many times a mock function will be called: |`AnyNumber()`|The function can be called any number of times.| |:------------|:----------------------------------------------| |`AtLeast(n)` |The call is expected at least `n` times. | |`AtMost(n)` |The call is expected at most `n` times. | |`Between(m, n)`|The call is expected between `m` and `n` (inclusive) times.| |`Exactly(n) or n`|The call is expected exactly `n` times. In particular, the call should never happen when `n` is 0.| # Expectation Order # By default, the expectations can be matched in _any_ order. If some or all expectations must be matched in a given order, there are two ways to specify it. They can be used either independently or together. ## The After Clause ## ``` using ::testing::Expectation; ... Expectation init_x = EXPECT_CALL(foo, InitX()); Expectation init_y = EXPECT_CALL(foo, InitY()); EXPECT_CALL(foo, Bar()) .After(init_x, init_y); ``` says that `Bar()` can be called only after both `InitX()` and `InitY()` have been called. If you don't know how many pre-requisites an expectation has when you write it, you can use an `ExpectationSet` to collect them: ``` using ::testing::ExpectationSet; ... ExpectationSet all_inits; for (int i = 0; i < element_count; i++) { all_inits += EXPECT_CALL(foo, InitElement(i)); } EXPECT_CALL(foo, Bar()) .After(all_inits); ``` says that `Bar()` can be called only after all elements have been initialized (but we don't care about which elements get initialized before the others). Modifying an `ExpectationSet` after using it in an `.After()` doesn't affect the meaning of the `.After()`. ## Sequences ## When you have a long chain of sequential expectations, it's easier to specify the order using **sequences**, which don't require you to given each expectation in the chain a different name. All expected
calls
in the same sequence must occur in the order they are specified. ``` using ::testing::Sequence; Sequence s1, s2; ... EXPECT_CALL(foo, Reset()) .InSequence(s1, s2) .WillOnce(Return(true)); EXPECT_CALL(foo, GetSize()) .InSequence(s1) .WillOnce(Return(1)); EXPECT_CALL(foo, Describe(A())) .InSequence(s2) .WillOnce(Return("dummy")); ``` says that `Reset()` must be called before _both_ `GetSize()` _and_ `Describe()`, and the latter two can occur in any order. To put many expectations in a sequence conveniently: ``` using ::testing::InSequence; { InSequence dummy; EXPECT_CALL(...)...; EXPECT_CALL(...)...; ... EXPECT_CALL(...)...; } ``` says that all expected calls in the scope of `dummy` must occur in strict order. The name `dummy` is irrelevant.) # Verifying and Resetting a Mock # Google Mock will verify the expectations on a mock object when it is destructed, or you can do it earlier: ``` using ::testing::Mock; ... // Verifies and removes the expectations on mock_obj; // returns true iff successful. Mock::VerifyAndClearExpectations(&mock_obj); ... // Verifies and removes the expectations on mock_obj; // also removes the default actions set by ON_CALL(); // returns true iff successful. Mock::VerifyAndClear(&mock_obj); ``` You can also tell Google Mock that a mock object can be leaked and doesn't need to be verified: ``` Mock::AllowLeak(&mock_obj); ``` # Mock Classes # Google Mock defines a convenient mock class template ``` class MockFunction { public: MOCK_METHODn(Call, R(A1, ..., An)); }; ``` See this [recipe](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Using_Check_Points) for one application of it. # Flags # | `--gmock_catch_leaked_mocks=0` | Don't report leaked mock objects as failures. | |:-------------------------------|:----------------------------------------------| | `--gmock_verbose=LEVEL` | Sets the default verbosity level (`info`, `warning`, or `error`) of Google Mock messages. |nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/docs/v1_6/CookBook.md000066400000000000000000003327641455373415500264120ustar00rootroot00000000000000 You can find recipes for using Google Mock here. If you haven't yet, please read the [ForDummies](V1_6_ForDummies.md) document first to make sure you understand the basics. **Note:** Google Mock lives in the `testing` name space. For readability, it is recommended to write `using ::testing::Foo;` once in your file before using the name `Foo` defined by Google Mock. We omit such `using` statements in this page for brevity, but you should do it in your own code. # Creating Mock Classes # ## Mocking Private or Protected Methods ## You must always put a mock method definition (`MOCK_METHOD*`) in a `public:` section of the mock class, regardless of the method being mocked being `public`, `protected`, or `private` in the base class. This allows `ON_CALL` and `EXPECT_CALL` to reference the mock function from outside of the mock class. (Yes, C++ allows a subclass to change the access level of a virtual function in the base class.) Example: ``` class Foo { public: ... virtual bool Transform(Gadget* g) = 0; protected: virtual void Resume(); private: virtual int GetTimeOut(); }; class MockFoo : public Foo { public: ... MOCK_METHOD1(Transform, bool(Gadget* g)); // The following must be in the public section, even though the // methods are protected or private in the base class. MOCK_METHOD0(Resume, void()); MOCK_METHOD0(GetTimeOut, int()); }; ``` ## Mocking Overloaded Methods ## You can mock overloaded functions as usual. No special attention is required: ``` class Foo { ... // Must be virtual as we'll inherit from Foo. virtual ~Foo(); // Overloaded on the types and/or numbers of arguments. virtual int Add(Element x); virtual int Add(int times, Element x); // Overloaded on the const-ness of this object. virtual Bar& GetBar(); virtual const Bar& GetBar() const; }; class MockFoo : public Foo { ... MOCK_METHOD1(Add, int(Element x)); MOCK_METHOD2(Add, int(int times, Element x); MOCK_METHOD0(GetBar, Bar&()); MOCK_CONST_METHOD0(GetBar, const Bar&()); }; ``` **Note:** if you don't mock all versions of the overloaded method, the compiler will give you a warning about some methods in the base class being hidden. To fix that, use `using` to bring them in scope: ``` class MockFoo : public Foo { ... using Foo::Add; MOCK_METHOD1(Add, int(Element x)); // We don't want to mock int Add(int times, Element x); ... }; ``` ## Mocking Class Templates ## To mock a class template, append `_T` to the `MOCK_*` macros: ``` template class StackInterface { ... // Must be virtual as we'll inherit from StackInterface. virtual ~StackInterface(); virtual int GetSize() const = 0; virtual void Push(const Elem& x) = 0; }; template class MockStack : public StackInterface { ... MOCK_CONST_METHOD0_T(GetSize, int()); MOCK_METHOD1_T(Push, void(const Elem& x)); }; ``` ## Mocking Nonvirtual Methods ## Google Mock can mock non-virtual functions to be used in what we call _hi-perf dependency injection_. In this case, instead of sharing a common base class with the real class, your mock class will be _unrelated_ to the real class, but contain methods with the same signatures. The syntax for mocking non-virtual methods is the _same_ as mocking virtual methods: ``` // A simple packet stream class. None of its members is virtual. class ConcretePacketStream { public: void AppendPacket(Packet* new_packet); const Packet* GetPacket(size_t packet_number) const; size_t NumberOfPackets() const; ... }; // A mock packet stream class. It inherits from no other, but defines // GetPacket() and NumberOfPackets(). class MockPacketStream { public: MOCK_CONST_METHOD1(GetPacket, const Packet*(size_t packet_number)); MOCK_CONST_METHOD0(NumberOfPackets, size_t()); ... }; ``` Note that the mock class doesn't define `AppendPacket()`, unlike the real class. That's fine as long as the test doesn't need to call it. Next, you need a way to say that you want to use `ConcretePacketStream` in production code, and use `MockPacketStream` in tests. Since the functions are not virtual and the two classes are unrelated, you must specify your choice at _compile time_ (as opposed to run time). One way to do it is to templatize your code that needs to use a packet stream. More specifically, you will give your code a template type argument for the type of the packet stream. In production, you will instantiate your template with `ConcretePacketStream` as the type argument. In tests, you will instantiate the same template with `MockPacketStream`. For example, you may write: ``` template void CreateConnection(PacketStream* stream) { ... } template class PacketReader { public: void ReadPackets(PacketStream* stream, size_t packet_num); }; ``` Then you can use `CreateConnection()` and `PacketReader` in production code, and use `CreateConnection()` and `PacketReader` in tests. ``` MockPacketStream mock_stream; EXPECT_CALL(mock_stream, ...)...; .. set more expectations on mock_stream ... PacketReader reader(&mock_stream); ... exercise reader ... ``` ## Mocking Free Functions ## It's possible to use Google Mock to mock a free function (i.e. a C-style function or a static method). You just need to rewrite your code to use an interface (abstract class). Instead of calling a free function (say, `OpenFile`) directly, introduce an interface for it and have a concrete subclass that calls the free function: ``` class FileInterface { public: ... virtual bool Open(const char* path, const char* mode) = 0; }; class File : public FileInterface { public: ... virtual bool Open(const char* path, const char* mode) { return OpenFile(path, mode); } }; ``` Your code should talk to `FileInterface` to open a file. Now it's easy to mock out the function. This may seem much hassle, but in practice you often have multiple related functions that you can put in the same interface, so the per-function syntactic overhead will be much lower. If you are concerned about the performance overhead incurred by virtual functions, and profiling confirms your concern, you can combine this with the recipe for [mocking non-virtual methods](#Mocking_Nonvirtual_Methods.md). ## Nice Mocks and Strict Mocks ## If a mock method has no `EXPECT_CALL` spec but is called, Google Mock will print a warning about the "uninteresting call". The rationale is: * New methods may be added to an interface after a test is written. We shouldn't fail a test just because a method it doesn't know about is called. * However, this may also mean there's a bug in the test, so Google Mock shouldn't be silent either. If the user believes these calls are harmless, he can add an `EXPECT_CALL()` to suppress the warning. However, sometimes you may want to suppress all "uninteresting call" warnings, while sometimes you may want the opposite, i.e. to treat all of them as errors. Google Mock lets you make the decision on a per-mock-object basis. Suppose your test uses a mock class `MockFoo`: ``` TEST(...) { MockFoo mock_foo; EXPECT_CALL(mock_foo, DoThis()); ... code that uses mock_foo ... } ``` If a method of `mock_foo` other than `DoThis()` is called, it will be reported by Google Mock as a warning. However, if you rewrite your test to use `NiceMock` instead, the warning will be gone, resulting in a cleaner test output: ``` using ::testing::NiceMock; TEST(...) { NiceMock mock_foo; EXPECT_CALL(mock_foo, DoThis()); ... code that uses mock_foo ... } ``` `NiceMock` is a subclass of `MockFoo`, so it can be used wherever `MockFoo` is accepted. It also works if `MockFoo`'s constructor takes some arguments, as `NiceMock` "inherits" `MockFoo`'s constructors: ``` using ::testing::NiceMock; TEST(...) { NiceMock mock_foo(5, "hi"); // Calls MockFoo(5, "hi"). EXPECT_CALL(mock_foo, DoThis()); ... code that uses mock_foo ... } ``` The usage of `StrictMock` is similar, except that it makes all uninteresting calls failures: ``` using ::testing::StrictMock; TEST(...) { StrictMock mock_foo; EXPECT_CALL(mock_foo, DoThis()); ... code that uses mock_foo ... // The test will fail if a method of mock_foo other than DoThis() // is called. } ``` There are some caveats though (I don't like them just as much as the next guy, but sadly they are side effects of C++'s limitations): 1. `NiceMock` and `StrictMock` only work for mock methods defined using the `MOCK_METHOD*` family of macros **directly** in the `MockFoo` class. If a mock method is defined in a **base class** of `MockFoo`, the "nice" or "strict" modifier may not affect it, depending on the compiler. In particular, nesting `NiceMock` and `StrictMock` (e.g. `NiceMock >`) is **not** supported. 1. The constructors of the base mock (`MockFoo`) cannot have arguments passed by non-const reference, which happens to be banned by the [Google C++ style guide](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml). 1. During the constructor or destructor of `MockFoo`, the mock object is _not_ nice or strict. This may cause surprises if the constructor or destructor calls a mock method on `this` object. (This behavior, however, is consistent with C++'s general rule: if a constructor or destructor calls a virtual method of `this` object, that method is treated as non-virtual. In other words, to the base class's constructor or destructor, `this` object behaves like an instance of the base class, not the derived class. This rule is required for safety. Otherwise a base constructor may use members of a derived class before they are initialized, or a base destructor may use members of a derived class after they have been destroyed.) Finally, you should be **very cautious** when using this feature, as the decision you make applies to **all** future changes to the mock class. If an important change is made in the interface you are mocking (and thus in the mock class), it could break your tests (if you use `StrictMock`) or let bugs pass through without a warning (if you use `NiceMock`). Therefore, try to specify the mock's behavior using explicit `EXPECT_CALL` first, and only turn to `NiceMock` or `StrictMock` as the last resort. ## Simplifying the Interface without Breaking Existing Code ## Sometimes a method has a long list of arguments that is mostly uninteresting. For example, ``` class LogSink { public: ... virtual void send(LogSeverity severity, const char* full_filename, const char* base_filename, int line, const struct tm* tm_time, const char* message, size_t message_len) = 0; }; ``` This method's argument list is lengthy and hard to work with (let's say that the `message` argument is not even 0-terminated). If we mock it as is, using the mock will be awkward. If, however, we try to simplify this interface, we'll need to fix all clients depending on it, which is often infeasible. The trick is to re-dispatch the method in the mock class: ``` class ScopedMockLog : public LogSink { public: ... virtual void send(LogSeverity severity, const char* full_filename, const char* base_filename, int line, const tm* tm_time, const char* message, size_t message_len) { // We are only interested in the log severity, full file name, and // log message. Log(severity, full_filename, std::string(message, message_len)); } // Implements the mock method: // // void Log(LogSeverity severity, // const string& file_path, // const string& message); MOCK_METHOD3(Log, void(LogSeverity severity, const string& file_path, const string& message)); }; ``` By defining a new mock method with a trimmed argument list, we make the mock class much more user-friendly. ## Alternative to Mocking Concrete Classes ## Often you may find yourself using classes that don't implement interfaces. In order to test your code that uses such a class (let's call it `Concrete`), you may be tempted to make the methods of `Concrete` virtual and then mock it. Try not to do that. Making a non-virtual function virtual is a big decision. It creates an extension point where subclasses can tweak your class' behavior. This weakens your control on the class because now it's harder to maintain the class' invariants. You should make a function virtual only when there is a valid reason for a subclass to override it. Mocking concrete classes directly is problematic as it creates a tight coupling between the class and the tests - any small change in the class may invalidate your tests and make test maintenance a pain. To avoid such problems, many programmers have been practicing "coding to interfaces": instead of talking to the `Concrete` class, your code would define an interface and talk to it. Then you implement that interface as an adaptor on top of `Concrete`. In tests, you can easily mock that interface to observe how your code is doing. This technique incurs some overhead: * You pay the cost of virtual function calls (usually not a problem). * There is more abstraction for the programmers to learn. However, it can also bring significant benefits in addition to better testability: * `Concrete`'s API may not fit your problem domain very well, as you may not be the only client it tries to serve. By designing your own interface, you have a chance to tailor it to your need - you may add higher-level functionalities, rename stuff, etc instead of just trimming the class. This allows you to write your code (user of the interface) in a more natural way, which means it will be more readable, more maintainable, and you'll be more productive. * If `Concrete`'s implementation ever has to change, you don't have to rewrite everywhere it is used. Instead, you can absorb the change in your implementation of the interface, and your other code and tests will be insulated from this change. Some people worry that if everyone is practicing this technique, they will end up writing lots of redundant code. This concern is totally understandable. However, there are two reasons why it may not be the case: * Different projects may need to use `Concrete` in different ways, so the best interfaces for them will be different. Therefore, each of them will have its own domain-specific interface on top of `Concrete`, and they will not be the same code. * If enough projects want to use the same interface, they can always share it, just like they have been sharing `Concrete`. You can check in the interface and the adaptor somewhere near `Concrete` (perhaps in a `contrib` sub-directory) and let many projects use it. You need to weigh the pros and cons carefully for your particular problem, but I'd like to assure you that the Java community has been practicing this for a long time and it's a proven effective technique applicable in a wide variety of situations. :-) ## Delegating Calls to a Fake ## Some times you have a non-trivial fake implementation of an interface. For example: ``` class Foo { public: virtual ~Foo() {} virtual char DoThis(int n) = 0; virtual void DoThat(const char* s, int* p) = 0; }; class FakeFoo : public Foo { public: virtual char DoThis(int n) { return (n > 0) ? '+' : (n < 0) ? '-' : '0'; } virtual void DoThat(const char* s, int* p) { *p = strlen(s); } }; ``` Now you want to mock this interface such that you can set expectations on it. However, you also want to use `FakeFoo` for the default behavior, as duplicating it in the mock object is, well, a lot of work. When you define the mock class using Google Mock, you can have it delegate its default action to a fake class you already have, using this pattern: ``` using ::testing::_; using ::testing::Invoke; class MockFoo : public Foo { public: // Normal mock method definitions using Google Mock. MOCK_METHOD1(DoThis, char(int n)); MOCK_METHOD2(DoThat, void(const char* s, int* p)); // Delegates the default actions of the methods to a FakeFoo object. // This must be called *before* the custom ON_CALL() statements. void DelegateToFake() { ON_CALL(*this, DoThis(_)) .WillByDefault(Invoke(&fake_, &FakeFoo::DoThis)); ON_CALL(*this, DoThat(_, _)) .WillByDefault(Invoke(&fake_, &FakeFoo::DoThat)); } private: FakeFoo fake_; // Keeps an instance of the fake in the mock. }; ``` With that, you can use `MockFoo` in your tests as usual. Just remember that if you don't explicitly set an action in an `ON_CALL()` or `EXPECT_CALL()`, the fake will be called upon to do it: ``` using ::testing::_; TEST(AbcTest, Xyz) { MockFoo foo; foo.DelegateToFake(); // Enables the fake for delegation. // Put your ON_CALL(foo, ...)s here, if any. // No action specified, meaning to use the default action. EXPECT_CALL(foo, DoThis(5)); EXPECT_CALL(foo, DoThat(_, _)); int n = 0; EXPECT_EQ('+', foo.DoThis(5)); // FakeFoo::DoThis() is invoked. foo.DoThat("Hi", &n); // FakeFoo::DoThat() is invoked. EXPECT_EQ(2, n); } ``` **Some tips:** * If you want, you can still override the default action by providing your own `ON_CALL()` or using `.WillOnce()` / `.WillRepeatedly()` in `EXPECT_CALL()`. * In `DelegateToFake()`, you only need to delegate the methods whose fake implementation you intend to use. * The general technique discussed here works for overloaded methods, but you'll need to tell the compiler which version you mean. To disambiguate a mock function (the one you specify inside the parentheses of `ON_CALL()`), see the "Selecting Between Overloaded Functions" section on this page; to disambiguate a fake function (the one you place inside `Invoke()`), use a `static_cast` to specify the function's type. * Having to mix a mock and a fake is often a sign of something gone wrong. Perhaps you haven't got used to the interaction-based way of testing yet. Or perhaps your interface is taking on too many roles and should be split up. Therefore, **don't abuse this**. We would only recommend to do it as an intermediate step when you are refactoring your code. Regarding the tip on mixing a mock and a fake, here's an example on why it may be a bad sign: Suppose you have a class `System` for low-level system operations. In particular, it does file and I/O operations. And suppose you want to test how your code uses `System` to do I/O, and you just want the file operations to work normally. If you mock out the entire `System` class, you'll have to provide a fake implementation for the file operation part, which suggests that `System` is taking on too many roles. Instead, you can define a `FileOps` interface and an `IOOps` interface and split `System`'s functionalities into the two. Then you can mock `IOOps` without mocking `FileOps`. ## Delegating Calls to a Real Object ## When using testing doubles (mocks, fakes, stubs, and etc), sometimes their behaviors will differ from those of the real objects. This difference could be either intentional (as in simulating an error such that you can test the error handling code) or unintentional. If your mocks have different behaviors than the real objects by mistake, you could end up with code that passes the tests but fails in production. You can use the _delegating-to-real_ technique to ensure that your mock has the same behavior as the real object while retaining the ability to validate calls. This technique is very similar to the delegating-to-fake technique, the difference being that we use a real object instead of a fake. Here's an example: ``` using ::testing::_; using ::testing::AtLeast; using ::testing::Invoke; class MockFoo : public Foo { public: MockFoo() { // By default, all calls are delegated to the real object. ON_CALL(*this, DoThis()) .WillByDefault(Invoke(&real_, &Foo::DoThis)); ON_CALL(*this, DoThat(_)) .WillByDefault(Invoke(&real_, &Foo::DoThat)); ... } MOCK_METHOD0(DoThis, ...); MOCK_METHOD1(DoThat, ...); ... private: Foo real_; }; ... MockFoo mock; EXPECT_CALL(mock, DoThis()) .Times(3); EXPECT_CALL(mock, DoThat("Hi")) .Times(AtLeast(1)); ... use mock in test ... ``` With this, Google Mock will verify that your code made the right calls (with the right arguments, in the right order, called the right number of times, etc), and a real object will answer the calls (so the behavior will be the same as in production). This gives you the best of both worlds. ## Delegating Calls to a Parent Class ## Ideally, you should code to interfaces, whose methods are all pure virtual. In reality, sometimes you do need to mock a virtual method that is not pure (i.e, it already has an implementation). For example: ``` class Foo { public: virtual ~Foo(); virtual void Pure(int n) = 0; virtual int Concrete(const char* str) { ... } }; class MockFoo : public Foo { public: // Mocking a pure method. MOCK_METHOD1(Pure, void(int n)); // Mocking a concrete method. Foo::Concrete() is shadowed. MOCK_METHOD1(Concrete, int(const char* str)); }; ``` Sometimes you may want to call `Foo::Concrete()` instead of `MockFoo::Concrete()`. Perhaps you want to do it as part of a stub action, or perhaps your test doesn't need to mock `Concrete()` at all (but it would be oh-so painful to have to define a new mock class whenever you don't need to mock one of its methods). The trick is to leave a back door in your mock class for accessing the real methods in the base class: ``` class MockFoo : public Foo { public: // Mocking a pure method. MOCK_METHOD1(Pure, void(int n)); // Mocking a concrete method. Foo::Concrete() is shadowed. MOCK_METHOD1(Concrete, int(const char* str)); // Use this to call Concrete() defined in Foo. int FooConcrete(const char* str) { return Foo::Concrete(str); } }; ``` Now, you can call `Foo::Concrete()` inside an action by: ``` using ::testing::_; using ::testing::Invoke; ... EXPECT_CALL(foo, Concrete(_)) .WillOnce(Invoke(&foo, &MockFoo::FooConcrete)); ``` or tell the mock object that you don't want to mock `Concrete()`: ``` using ::testing::Invoke; ... ON_CALL(foo, Concrete(_)) .WillByDefault(Invoke(&foo, &MockFoo::FooConcrete)); ``` (Why don't we just write `Invoke(&foo, &Foo::Concrete)`? If you do that, `MockFoo::Concrete()` will be called (and cause an infinite recursion) since `Foo::Concrete()` is virtual. That's just how C++ works.) # Using Matchers # ## Matching Argument Values Exactly ## You can specify exactly which arguments a mock method is expecting: ``` using ::testing::Return; ... EXPECT_CALL(foo, DoThis(5)) .WillOnce(Return('a')); EXPECT_CALL(foo, DoThat("Hello", bar)); ``` ## Using Simple Matchers ## You can use matchers to match arguments that have a certain property: ``` using ::testing::Ge; using ::testing::NotNull; using ::testing::Return; ... EXPECT_CALL(foo, DoThis(Ge(5))) // The argument must be >= 5. .WillOnce(Return('a')); EXPECT_CALL(foo, DoThat("Hello", NotNull())); // The second argument must not be NULL. ``` A frequently used matcher is `_`, which matches anything: ``` using ::testing::_; using ::testing::NotNull; ... EXPECT_CALL(foo, DoThat(_, NotNull())); ``` ## Combining Matchers ## You can build complex matchers from existing ones using `AllOf()`, `AnyOf()`, and `Not()`: ``` using ::testing::AllOf; using ::testing::Gt; using ::testing::HasSubstr; using ::testing::Ne; using ::testing::Not; ... // The argument must be > 5 and != 10. EXPECT_CALL(foo, DoThis(AllOf(Gt(5), Ne(10)))); // The first argument must not contain sub-string "blah". EXPECT_CALL(foo, DoThat(Not(HasSubstr("blah")), NULL)); ``` ## Casting Matchers ## Google Mock matchers are statically typed, meaning that the compiler can catch your mistake if you use a matcher of the wrong type (for example, if you use `Eq(5)` to match a `string` argument). Good for you! Sometimes, however, you know what you're doing and want the compiler to give you some slack. One example is that you have a matcher for `long` and the argument you want to match is `int`. While the two types aren't exactly the same, there is nothing really wrong with using a `Matcher` to match an `int` - after all, we can first convert the `int` argument to a `long` before giving it to the matcher. To support this need, Google Mock gives you the `SafeMatcherCast(m)` function. It casts a matcher `m` to type `Matcher`. To ensure safety, Google Mock checks that (let `U` be the type `m` accepts): 1. Type `T` can be implicitly cast to type `U`; 1. When both `T` and `U` are built-in arithmetic types (`bool`, integers, and floating-point numbers), the conversion from `T` to `U` is not lossy (in other words, any value representable by `T` can also be represented by `U`); and 1. When `U` is a reference, `T` must also be a reference (as the underlying matcher may be interested in the address of the `U` value). The code won't compile if any of these conditions isn't met. Here's one example: ``` using ::testing::SafeMatcherCast; // A base class and a child class. class Base { ... }; class Derived : public Base { ... }; class MockFoo : public Foo { public: MOCK_METHOD1(DoThis, void(Derived* derived)); }; ... MockFoo foo; // m is a Matcher we got from somewhere. EXPECT_CALL(foo, DoThis(SafeMatcherCast(m))); ``` If you find `SafeMatcherCast(m)` too limiting, you can use a similar function `MatcherCast(m)`. The difference is that `MatcherCast` works as long as you can `static_cast` type `T` to type `U`. `MatcherCast` essentially lets you bypass C++'s type system (`static_cast` isn't always safe as it could throw away information, for example), so be careful not to misuse/abuse it. ## Selecting Between Overloaded Functions ## If you expect an overloaded function to be called, the compiler may need some help on which overloaded version it is. To disambiguate functions overloaded on the const-ness of this object, use the `Const()` argument wrapper. ``` using ::testing::ReturnRef; class MockFoo : public Foo { ... MOCK_METHOD0(GetBar, Bar&()); MOCK_CONST_METHOD0(GetBar, const Bar&()); }; ... MockFoo foo; Bar bar1, bar2; EXPECT_CALL(foo, GetBar()) // The non-const GetBar(). .WillOnce(ReturnRef(bar1)); EXPECT_CALL(Const(foo), GetBar()) // The const GetBar(). .WillOnce(ReturnRef(bar2)); ``` (`Const()` is defined by Google Mock and returns a `const` reference to its argument.) To disambiguate overloaded functions with the same number of arguments but different argument types, you may need to specify the exact type of a matcher, either by wrapping your matcher in `Matcher()`, or using a matcher whose type is fixed (`TypedEq`, `An()`, etc): ``` using ::testing::An; using ::testing::Lt; using ::testing::Matcher; using ::testing::TypedEq; class MockPrinter : public Printer { public: MOCK_METHOD1(Print, void(int n)); MOCK_METHOD1(Print, void(char c)); }; TEST(PrinterTest, Print) { MockPrinter printer; EXPECT_CALL(printer, Print(An())); // void Print(int); EXPECT_CALL(printer, Print(Matcher(Lt(5)))); // void Print(int); EXPECT_CALL(printer, Print(TypedEq('a'))); // void Print(char); printer.Print(3); printer.Print(6); printer.Print('a'); } ``` ## Performing Different Actions Based on the Arguments ## When a mock method is called, the _last_ matching expectation that's still active will be selected (think "newer overrides older"). So, you can make a method do different things depending on its argument values like this: ``` using ::testing::_; using ::testing::Lt; using ::testing::Return; ... // The default case. EXPECT_CALL(foo, DoThis(_)) .WillRepeatedly(Return('b')); // The more specific case. EXPECT_CALL(foo, DoThis(Lt(5))) .WillRepeatedly(Return('a')); ``` Now, if `foo.DoThis()` is called with a value less than 5, `'a'` will be returned; otherwise `'b'` will be returned. ## Matching Multiple Arguments as a Whole ## Sometimes it's not enough to match the arguments individually. For example, we may want to say that the first argument must be less than the second argument. The `With()` clause allows us to match all arguments of a mock function as a whole. For example, ``` using ::testing::_; using ::testing::Lt; using ::testing::Ne; ... EXPECT_CALL(foo, InRange(Ne(0), _)) .With(Lt()); ``` says that the first argument of `InRange()` must not be 0, and must be less than the second argument. The expression inside `With()` must be a matcher of type `Matcher >`, where `A1`, ..., `An` are the types of the function arguments. You can also write `AllArgs(m)` instead of `m` inside `.With()`. The two forms are equivalent, but `.With(AllArgs(Lt()))` is more readable than `.With(Lt())`. You can use `Args(m)` to match the `n` selected arguments (as a tuple) against `m`. For example, ``` using ::testing::_; using ::testing::AllOf; using ::testing::Args; using ::testing::Lt; ... EXPECT_CALL(foo, Blah(_, _, _)) .With(AllOf(Args<0, 1>(Lt()), Args<1, 2>(Lt()))); ``` says that `Blah()` will be called with arguments `x`, `y`, and `z` where `x < y < z`. As a convenience and example, Google Mock provides some matchers for 2-tuples, including the `Lt()` matcher above. See the [CheatSheet](V1_6_CheatSheet.md) for the complete list. Note that if you want to pass the arguments to a predicate of your own (e.g. `.With(Args<0, 1>(Truly(&MyPredicate)))`), that predicate MUST be written to take a `tr1::tuple` as its argument; Google Mock will pass the `n` selected arguments as _one_ single tuple to the predicate. ## Using Matchers as Predicates ## Have you noticed that a matcher is just a fancy predicate that also knows how to describe itself? Many existing algorithms take predicates as arguments (e.g. those defined in STL's `` header), and it would be a shame if Google Mock matchers are not allowed to participate. Luckily, you can use a matcher where a unary predicate functor is expected by wrapping it inside the `Matches()` function. For example, ``` #include #include std::vector v; ... // How many elements in v are >= 10? const int count = count_if(v.begin(), v.end(), Matches(Ge(10))); ``` Since you can build complex matchers from simpler ones easily using Google Mock, this gives you a way to conveniently construct composite predicates (doing the same using STL's `` header is just painful). For example, here's a predicate that's satisfied by any number that is >= 0, <= 100, and != 50: ``` Matches(AllOf(Ge(0), Le(100), Ne(50))) ``` ## Using Matchers in Google Test Assertions ## Since matchers are basically predicates that also know how to describe themselves, there is a way to take advantage of them in [Google Test](http://code.google.com/p/googletest/) assertions. It's called `ASSERT_THAT` and `EXPECT_THAT`: ``` ASSERT_THAT(value, matcher); // Asserts that value matches matcher. EXPECT_THAT(value, matcher); // The non-fatal version. ``` For example, in a Google Test test you can write: ``` #include "gmock/gmock.h" using ::testing::AllOf; using ::testing::Ge; using ::testing::Le; using ::testing::MatchesRegex; using ::testing::StartsWith; ... EXPECT_THAT(Foo(), StartsWith("Hello")); EXPECT_THAT(Bar(), MatchesRegex("Line \\d+")); ASSERT_THAT(Baz(), AllOf(Ge(5), Le(10))); ``` which (as you can probably guess) executes `Foo()`, `Bar()`, and `Baz()`, and verifies that: * `Foo()` returns a string that starts with `"Hello"`. * `Bar()` returns a string that matches regular expression `"Line \\d+"`. * `Baz()` returns a number in the range [5, 10]. The nice thing about these macros is that _they read like English_. They generate informative messages too. For example, if the first `EXPECT_THAT()` above fails, the message will be something like: ``` Value of: Foo() Actual: "Hi, world!" Expected: starts with "Hello" ``` **Credit:** The idea of `(ASSERT|EXPECT)_THAT` was stolen from the [Hamcrest](http://code.google.com/p/hamcrest/) project, which adds `assertThat()` to JUnit. ## Using Predicates as Matchers ## Google Mock provides a built-in set of matchers. In case you find them lacking, you can use an arbitray unary predicate function or functor as a matcher - as long as the predicate accepts a value of the type you want. You do this by wrapping the predicate inside the `Truly()` function, for example: ``` using ::testing::Truly; int IsEven(int n) { return (n % 2) == 0 ? 1 : 0; } ... // Bar() must be called with an even number. EXPECT_CALL(foo, Bar(Truly(IsEven))); ``` Note that the predicate function / functor doesn't have to return `bool`. It works as long as the return value can be used as the condition in statement `if (condition) ...`. ## Matching Arguments that Are Not Copyable ## When you do an `EXPECT_CALL(mock_obj, Foo(bar))`, Google Mock saves away a copy of `bar`. When `Foo()` is called later, Google Mock compares the argument to `Foo()` with the saved copy of `bar`. This way, you don't need to worry about `bar` being modified or destroyed after the `EXPECT_CALL()` is executed. The same is true when you use matchers like `Eq(bar)`, `Le(bar)`, and so on. But what if `bar` cannot be copied (i.e. has no copy constructor)? You could define your own matcher function and use it with `Truly()`, as the previous couple of recipes have shown. Or, you may be able to get away from it if you can guarantee that `bar` won't be changed after the `EXPECT_CALL()` is executed. Just tell Google Mock that it should save a reference to `bar`, instead of a copy of it. Here's how: ``` using ::testing::Eq; using ::testing::ByRef; using ::testing::Lt; ... // Expects that Foo()'s argument == bar. EXPECT_CALL(mock_obj, Foo(Eq(ByRef(bar)))); // Expects that Foo()'s argument < bar. EXPECT_CALL(mock_obj, Foo(Lt(ByRef(bar)))); ``` Remember: if you do this, don't change `bar` after the `EXPECT_CALL()`, or the result is undefined. ## Validating a Member of an Object ## Often a mock function takes a reference to object as an argument. When matching the argument, you may not want to compare the entire object against a fixed object, as that may be over-specification. Instead, you may need to validate a certain member variable or the result of a certain getter method of the object. You can do this with `Field()` and `Property()`. More specifically, ``` Field(&Foo::bar, m) ``` is a matcher that matches a `Foo` object whose `bar` member variable satisfies matcher `m`. ``` Property(&Foo::baz, m) ``` is a matcher that matches a `Foo` object whose `baz()` method returns a value that satisfies matcher `m`. For example: > | `Field(&Foo::number, Ge(3))` | Matches `x` where `x.number >= 3`. | |:-----------------------------|:-----------------------------------| > | `Property(&Foo::name, StartsWith("John "))` | Matches `x` where `x.name()` starts with `"John "`. | Note that in `Property(&Foo::baz, ...)`, method `baz()` must take no argument and be declared as `const`. BTW, `Field()` and `Property()` can also match plain pointers to objects. For instance, ``` Field(&Foo::number, Ge(3)) ``` matches a plain pointer `p` where `p->number >= 3`. If `p` is `NULL`, the match will always fail regardless of the inner matcher. What if you want to validate more than one members at the same time? Remember that there is `AllOf()`. ## Validating the Value Pointed to by a Pointer Argument ## C++ functions often take pointers as arguments. You can use matchers like `NULL`, `NotNull()`, and other comparison matchers to match a pointer, but what if you want to make sure the value _pointed to_ by the pointer, instead of the pointer itself, has a certain property? Well, you can use the `Pointee(m)` matcher. `Pointee(m)` matches a pointer iff `m` matches the value the pointer points to. For example: ``` using ::testing::Ge; using ::testing::Pointee; ... EXPECT_CALL(foo, Bar(Pointee(Ge(3)))); ``` expects `foo.Bar()` to be called with a pointer that points to a value greater than or equal to 3. One nice thing about `Pointee()` is that it treats a `NULL` pointer as a match failure, so you can write `Pointee(m)` instead of ``` AllOf(NotNull(), Pointee(m)) ``` without worrying that a `NULL` pointer will crash your test. Also, did we tell you that `Pointee()` works with both raw pointers **and** smart pointers (`linked_ptr`, `shared_ptr`, `scoped_ptr`, and etc)? What if you have a pointer to pointer? You guessed it - you can use nested `Pointee()` to probe deeper inside the value. For example, `Pointee(Pointee(Lt(3)))` matches a pointer that points to a pointer that points to a number less than 3 (what a mouthful...). ## Testing a Certain Property of an Object ## Sometimes you want to specify that an object argument has a certain property, but there is no existing matcher that does this. If you want good error messages, you should define a matcher. If you want to do it quick and dirty, you could get away with writing an ordinary function. Let's say you have a mock function that takes an object of type `Foo`, which has an `int bar()` method and an `int baz()` method, and you want to constrain that the argument's `bar()` value plus its `baz()` value is a given number. Here's how you can define a matcher to do it: ``` using ::testing::MatcherInterface; using ::testing::MatchResultListener; class BarPlusBazEqMatcher : public MatcherInterface { public: explicit BarPlusBazEqMatcher(int expected_sum) : expected_sum_(expected_sum) {} virtual bool MatchAndExplain(const Foo& foo, MatchResultListener* listener) const { return (foo.bar() + foo.baz()) == expected_sum_; } virtual void DescribeTo(::std::ostream* os) const { *os << "bar() + baz() equals " << expected_sum_; } virtual void DescribeNegationTo(::std::ostream* os) const { *os << "bar() + baz() does not equal " << expected_sum_; } private: const int expected_sum_; }; inline Matcher BarPlusBazEq(int expected_sum) { return MakeMatcher(new BarPlusBazEqMatcher(expected_sum)); } ... EXPECT_CALL(..., DoThis(BarPlusBazEq(5)))...; ``` ## Matching Containers ## Sometimes an STL container (e.g. list, vector, map, ...) is passed to a mock function and you may want to validate it. Since most STL containers support the `==` operator, you can write `Eq(expected_container)` or simply `expected_container` to match a container exactly. Sometimes, though, you may want to be more flexible (for example, the first element must be an exact match, but the second element can be any positive number, and so on). Also, containers used in tests often have a small number of elements, and having to define the expected container out-of-line is a bit of a hassle. You can use the `ElementsAre()` matcher in such cases: ``` using ::testing::_; using ::testing::ElementsAre; using ::testing::Gt; ... MOCK_METHOD1(Foo, void(const vector& numbers)); ... EXPECT_CALL(mock, Foo(ElementsAre(1, Gt(0), _, 5))); ``` The above matcher says that the container must have 4 elements, which must be 1, greater than 0, anything, and 5 respectively. `ElementsAre()` is overloaded to take 0 to 10 arguments. If more are needed, you can place them in a C-style array and use `ElementsAreArray()` instead: ``` using ::testing::ElementsAreArray; ... // ElementsAreArray accepts an array of element values. const int expected_vector1[] = { 1, 5, 2, 4, ... }; EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector1))); // Or, an array of element matchers. Matcher expected_vector2 = { 1, Gt(2), _, 3, ... }; EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector2))); ``` In case the array needs to be dynamically created (and therefore the array size cannot be inferred by the compiler), you can give `ElementsAreArray()` an additional argument to specify the array size: ``` using ::testing::ElementsAreArray; ... int* const expected_vector3 = new int[count]; ... fill expected_vector3 with values ... EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector3, count))); ``` **Tips:** * `ElementAre*()` works with _any_ container that implements the STL iterator concept (i.e. it has a `const_iterator` type and supports `begin()/end()`) and supports `size()`, not just the ones defined in STL. It will even work with container types yet to be written - as long as they follows the above pattern. * You can use nested `ElementAre*()` to match nested (multi-dimensional) containers. * If the container is passed by pointer instead of by reference, just write `Pointee(ElementsAre*(...))`. * The order of elements _matters_ for `ElementsAre*()`. Therefore don't use it with containers whose element order is undefined (e.g. `hash_map`). ## Sharing Matchers ## Under the hood, a Google Mock matcher object consists of a pointer to a ref-counted implementation object. Copying matchers is allowed and very efficient, as only the pointer is copied. When the last matcher that references the implementation object dies, the implementation object will be deleted. Therefore, if you have some complex matcher that you want to use again and again, there is no need to build it everytime. Just assign it to a matcher variable and use that variable repeatedly! For example, ``` Matcher in_range = AllOf(Gt(5), Le(10)); ... use in_range as a matcher in multiple EXPECT_CALLs ... ``` # Setting Expectations # ## Ignoring Uninteresting Calls ## If you are not interested in how a mock method is called, just don't say anything about it. In this case, if the method is ever called, Google Mock will perform its default action to allow the test program to continue. If you are not happy with the default action taken by Google Mock, you can override it using `DefaultValue::Set()` (described later in this document) or `ON_CALL()`. Please note that once you expressed interest in a particular mock method (via `EXPECT_CALL()`), all invocations to it must match some expectation. If this function is called but the arguments don't match any `EXPECT_CALL()` statement, it will be an error. ## Disallowing Unexpected Calls ## If a mock method shouldn't be called at all, explicitly say so: ``` using ::testing::_; ... EXPECT_CALL(foo, Bar(_)) .Times(0); ``` If some calls to the method are allowed, but the rest are not, just list all the expected calls: ``` using ::testing::AnyNumber; using ::testing::Gt; ... EXPECT_CALL(foo, Bar(5)); EXPECT_CALL(foo, Bar(Gt(10))) .Times(AnyNumber()); ``` A call to `foo.Bar()` that doesn't match any of the `EXPECT_CALL()` statements will be an error. ## Expecting Ordered Calls ## Although an `EXPECT_CALL()` statement defined earlier takes precedence when Google Mock tries to match a function call with an expectation, by default calls don't have to happen in the order `EXPECT_CALL()` statements are written. For example, if the arguments match the matchers in the third `EXPECT_CALL()`, but not those in the first two, then the third expectation will be used. If you would rather have all calls occur in the order of the expectations, put the `EXPECT_CALL()` statements in a block where you define a variable of type `InSequence`: ``` using ::testing::_; using ::testing::InSequence; { InSequence s; EXPECT_CALL(foo, DoThis(5)); EXPECT_CALL(bar, DoThat(_)) .Times(2); EXPECT_CALL(foo, DoThis(6)); } ``` In this example, we expect a call to `foo.DoThis(5)`, followed by two calls to `bar.DoThat()` where the argument can be anything, which are in turn followed by a call to `foo.DoThis(6)`. If a call occurred out-of-order, Google Mock will report an error. ## Expecting Partially Ordered Calls ## Sometimes requiring everything to occur in a predetermined order can lead to brittle tests. For example, we may care about `A` occurring before both `B` and `C`, but aren't interested in the relative order of `B` and `C`. In this case, the test should reflect our real intent, instead of being overly constraining. Google Mock allows you to impose an arbitrary DAG (directed acyclic graph) on the calls. One way to express the DAG is to use the [After](http://code.google.com/p/googlemock/wiki/V1_6_CheatSheet#The_After_Clause) clause of `EXPECT_CALL`. Another way is via the `InSequence()` clause (not the same as the `InSequence` class), which we borrowed from jMock 2. It's less flexible than `After()`, but more convenient when you have long chains of sequential calls, as it doesn't require you to come up with different names for the expectations in the chains. Here's how it works: If we view `EXPECT_CALL()` statements as nodes in a graph, and add an edge from node A to node B wherever A must occur before B, we can get a DAG. We use the term "sequence" to mean a directed path in this DAG. Now, if we decompose the DAG into sequences, we just need to know which sequences each `EXPECT_CALL()` belongs to in order to be able to reconstruct the orginal DAG. So, to specify the partial order on the expectations we need to do two things: first to define some `Sequence` objects, and then for each `EXPECT_CALL()` say which `Sequence` objects it is part of. Expectations in the same sequence must occur in the order they are written. For example, ``` using ::testing::Sequence; Sequence s1, s2; EXPECT_CALL(foo, A()) .InSequence(s1, s2); EXPECT_CALL(bar, B()) .InSequence(s1); EXPECT_CALL(bar, C()) .InSequence(s2); EXPECT_CALL(foo, D()) .InSequence(s2); ``` specifies the following DAG (where `s1` is `A -> B`, and `s2` is `A -> C -> D`): ``` +---> B | A ---| | +---> C ---> D ``` This means that A must occur before B and C, and C must occur before D. There's no restriction about the order other than these. ## Controlling When an Expectation Retires ## When a mock method is called, Google Mock only consider expectations that are still active. An expectation is active when created, and becomes inactive (aka _retires_) when a call that has to occur later has occurred. For example, in ``` using ::testing::_; using ::testing::Sequence; Sequence s1, s2; EXPECT_CALL(log, Log(WARNING, _, "File too large.")) // #1 .Times(AnyNumber()) .InSequence(s1, s2); EXPECT_CALL(log, Log(WARNING, _, "Data set is empty.")) // #2 .InSequence(s1); EXPECT_CALL(log, Log(WARNING, _, "User not found.")) // #3 .InSequence(s2); ``` as soon as either #2 or #3 is matched, #1 will retire. If a warning `"File too large."` is logged after this, it will be an error. Note that an expectation doesn't retire automatically when it's saturated. For example, ``` using ::testing::_; ... EXPECT_CALL(log, Log(WARNING, _, _)); // #1 EXPECT_CALL(log, Log(WARNING, _, "File too large.")); // #2 ``` says that there will be exactly one warning with the message `"File too large."`. If the second warning contains this message too, #2 will match again and result in an upper-bound-violated error. If this is not what you want, you can ask an expectation to retire as soon as it becomes saturated: ``` using ::testing::_; ... EXPECT_CALL(log, Log(WARNING, _, _)); // #1 EXPECT_CALL(log, Log(WARNING, _, "File too large.")) // #2 .RetiresOnSaturation(); ``` Here #2 can be used only once, so if you have two warnings with the message `"File too large."`, the first will match #2 and the second will match #1 - there will be no error. # Using Actions # ## Returning References from Mock Methods ## If a mock function's return type is a reference, you need to use `ReturnRef()` instead of `Return()` to return a result: ``` using ::testing::ReturnRef; class MockFoo : public Foo { public: MOCK_METHOD0(GetBar, Bar&()); }; ... MockFoo foo; Bar bar; EXPECT_CALL(foo, GetBar()) .WillOnce(ReturnRef(bar)); ``` ## Returning Live Values from Mock Methods ## The `Return(x)` action saves a copy of `x` when the action is _created_, and always returns the same value whenever it's executed. Sometimes you may want to instead return the _live_ value of `x` (i.e. its value at the time when the action is _executed_.). If the mock function's return type is a reference, you can do it using `ReturnRef(x)`, as shown in the previous recipe ("Returning References from Mock Methods"). However, Google Mock doesn't let you use `ReturnRef()` in a mock function whose return type is not a reference, as doing that usually indicates a user error. So, what shall you do? You may be tempted to try `ByRef()`: ``` using testing::ByRef; using testing::Return; class MockFoo : public Foo { public: MOCK_METHOD0(GetValue, int()); }; ... int x = 0; MockFoo foo; EXPECT_CALL(foo, GetValue()) .WillRepeatedly(Return(ByRef(x))); x = 42; EXPECT_EQ(42, foo.GetValue()); ``` Unfortunately, it doesn't work here. The above code will fail with error: ``` Value of: foo.GetValue() Actual: 0 Expected: 42 ``` The reason is that `Return(value)` converts `value` to the actual return type of the mock function at the time when the action is _created_, not when it is _executed_. (This behavior was chosen for the action to be safe when `value` is a proxy object that references some temporary objects.) As a result, `ByRef(x)` is converted to an `int` value (instead of a `const int&`) when the expectation is set, and `Return(ByRef(x))` will always return 0. `ReturnPointee(pointer)` was provided to solve this problem specifically. It returns the value pointed to by `pointer` at the time the action is _executed_: ``` using testing::ReturnPointee; ... int x = 0; MockFoo foo; EXPECT_CALL(foo, GetValue()) .WillRepeatedly(ReturnPointee(&x)); // Note the & here. x = 42; EXPECT_EQ(42, foo.GetValue()); // This will succeed now. ``` ## Combining Actions ## Want to do more than one thing when a function is called? That's fine. `DoAll()` allow you to do sequence of actions every time. Only the return value of the last action in the sequence will be used. ``` using ::testing::DoAll; class MockFoo : public Foo { public: MOCK_METHOD1(Bar, bool(int n)); }; ... EXPECT_CALL(foo, Bar(_)) .WillOnce(DoAll(action_1, action_2, ... action_n)); ``` ## Mocking Side Effects ## Sometimes a method exhibits its effect not via returning a value but via side effects. For example, it may change some global state or modify an output argument. To mock side effects, in general you can define your own action by implementing `::testing::ActionInterface`. If all you need to do is to change an output argument, the built-in `SetArgPointee()` action is convenient: ``` using ::testing::SetArgPointee; class MockMutator : public Mutator { public: MOCK_METHOD2(Mutate, void(bool mutate, int* value)); ... }; ... MockMutator mutator; EXPECT_CALL(mutator, Mutate(true, _)) .WillOnce(SetArgPointee<1>(5)); ``` In this example, when `mutator.Mutate()` is called, we will assign 5 to the `int` variable pointed to by argument #1 (0-based). `SetArgPointee()` conveniently makes an internal copy of the value you pass to it, removing the need to keep the value in scope and alive. The implication however is that the value must have a copy constructor and assignment operator. If the mock method also needs to return a value as well, you can chain `SetArgPointee()` with `Return()` using `DoAll()`: ``` using ::testing::_; using ::testing::Return; using ::testing::SetArgPointee; class MockMutator : public Mutator { public: ... MOCK_METHOD1(MutateInt, bool(int* value)); }; ... MockMutator mutator; EXPECT_CALL(mutator, MutateInt(_)) .WillOnce(DoAll(SetArgPointee<0>(5), Return(true))); ``` If the output argument is an array, use the `SetArrayArgument(first, last)` action instead. It copies the elements in source range `[first, last)` to the array pointed to by the `N`-th (0-based) argument: ``` using ::testing::NotNull; using ::testing::SetArrayArgument; class MockArrayMutator : public ArrayMutator { public: MOCK_METHOD2(Mutate, void(int* values, int num_values)); ... }; ... MockArrayMutator mutator; int values[5] = { 1, 2, 3, 4, 5 }; EXPECT_CALL(mutator, Mutate(NotNull(), 5)) .WillOnce(SetArrayArgument<0>(values, values + 5)); ``` This also works when the argument is an output iterator: ``` using ::testing::_; using ::testing::SeArrayArgument; class MockRolodex : public Rolodex { public: MOCK_METHOD1(GetNames, void(std::back_insert_iterator >)); ... }; ... MockRolodex rolodex; vector names; names.push_back("George"); names.push_back("John"); names.push_back("Thomas"); EXPECT_CALL(rolodex, GetNames(_)) .WillOnce(SetArrayArgument<0>(names.begin(), names.end())); ``` ## Changing a Mock Object's Behavior Based on the State ## If you expect a call to change the behavior of a mock object, you can use `::testing::InSequence` to specify different behaviors before and after the call: ``` using ::testing::InSequence; using ::testing::Return; ... { InSequence seq; EXPECT_CALL(my_mock, IsDirty()) .WillRepeatedly(Return(true)); EXPECT_CALL(my_mock, Flush()); EXPECT_CALL(my_mock, IsDirty()) .WillRepeatedly(Return(false)); } my_mock.FlushIfDirty(); ``` This makes `my_mock.IsDirty()` return `true` before `my_mock.Flush()` is called and return `false` afterwards. If the behavior change is more complex, you can store the effects in a variable and make a mock method get its return value from that variable: ``` using ::testing::_; using ::testing::SaveArg; using ::testing::Return; ACTION_P(ReturnPointee, p) { return *p; } ... int previous_value = 0; EXPECT_CALL(my_mock, GetPrevValue()) .WillRepeatedly(ReturnPointee(&previous_value)); EXPECT_CALL(my_mock, UpdateValue(_)) .WillRepeatedly(SaveArg<0>(&previous_value)); my_mock.DoSomethingToUpdateValue(); ``` Here `my_mock.GetPrevValue()` will always return the argument of the last `UpdateValue()` call. ## Setting the Default Value for a Return Type ## If a mock method's return type is a built-in C++ type or pointer, by default it will return 0 when invoked. You only need to specify an action if this default value doesn't work for you. Sometimes, you may want to change this default value, or you may want to specify a default value for types Google Mock doesn't know about. You can do this using the `::testing::DefaultValue` class template: ``` class MockFoo : public Foo { public: MOCK_METHOD0(CalculateBar, Bar()); }; ... Bar default_bar; // Sets the default return value for type Bar. DefaultValue::Set(default_bar); MockFoo foo; // We don't need to specify an action here, as the default // return value works for us. EXPECT_CALL(foo, CalculateBar()); foo.CalculateBar(); // This should return default_bar. // Unsets the default return value. DefaultValue::Clear(); ``` Please note that changing the default value for a type can make you tests hard to understand. We recommend you to use this feature judiciously. For example, you may want to make sure the `Set()` and `Clear()` calls are right next to the code that uses your mock. ## Setting the Default Actions for a Mock Method ## You've learned how to change the default value of a given type. However, this may be too coarse for your purpose: perhaps you have two mock methods with the same return type and you want them to have different behaviors. The `ON_CALL()` macro allows you to customize your mock's behavior at the method level: ``` using ::testing::_; using ::testing::AnyNumber; using ::testing::Gt; using ::testing::Return; ... ON_CALL(foo, Sign(_)) .WillByDefault(Return(-1)); ON_CALL(foo, Sign(0)) .WillByDefault(Return(0)); ON_CALL(foo, Sign(Gt(0))) .WillByDefault(Return(1)); EXPECT_CALL(foo, Sign(_)) .Times(AnyNumber()); foo.Sign(5); // This should return 1. foo.Sign(-9); // This should return -1. foo.Sign(0); // This should return 0. ``` As you may have guessed, when there are more than one `ON_CALL()` statements, the news order take precedence over the older ones. In other words, the **last** one that matches the function arguments will be used. This matching order allows you to set up the common behavior in a mock object's constructor or the test fixture's set-up phase and specialize the mock's behavior later. ## Using Functions/Methods/Functors as Actions ## If the built-in actions don't suit you, you can easily use an existing function, method, or functor as an action: ``` using ::testing::_; using ::testing::Invoke; class MockFoo : public Foo { public: MOCK_METHOD2(Sum, int(int x, int y)); MOCK_METHOD1(ComplexJob, bool(int x)); }; int CalculateSum(int x, int y) { return x + y; } class Helper { public: bool ComplexJob(int x); }; ... MockFoo foo; Helper helper; EXPECT_CALL(foo, Sum(_, _)) .WillOnce(Invoke(CalculateSum)); EXPECT_CALL(foo, ComplexJob(_)) .WillOnce(Invoke(&helper, &Helper::ComplexJob)); foo.Sum(5, 6); // Invokes CalculateSum(5, 6). foo.ComplexJob(10); // Invokes helper.ComplexJob(10); ``` The only requirement is that the type of the function, etc must be _compatible_ with the signature of the mock function, meaning that the latter's arguments can be implicitly converted to the corresponding arguments of the former, and the former's return type can be implicitly converted to that of the latter. So, you can invoke something whose type is _not_ exactly the same as the mock function, as long as it's safe to do so - nice, huh? ## Invoking a Function/Method/Functor Without Arguments ## `Invoke()` is very useful for doing actions that are more complex. It passes the mock function's arguments to the function or functor being invoked such that the callee has the full context of the call to work with. If the invoked function is not interested in some or all of the arguments, it can simply ignore them. Yet, a common pattern is that a test author wants to invoke a function without the arguments of the mock function. `Invoke()` allows her to do that using a wrapper function that throws away the arguments before invoking an underlining nullary function. Needless to say, this can be tedious and obscures the intent of the test. `InvokeWithoutArgs()` solves this problem. It's like `Invoke()` except that it doesn't pass the mock function's arguments to the callee. Here's an example: ``` using ::testing::_; using ::testing::InvokeWithoutArgs; class MockFoo : public Foo { public: MOCK_METHOD1(ComplexJob, bool(int n)); }; bool Job1() { ... } ... MockFoo foo; EXPECT_CALL(foo, ComplexJob(_)) .WillOnce(InvokeWithoutArgs(Job1)); foo.ComplexJob(10); // Invokes Job1(). ``` ## Invoking an Argument of the Mock Function ## Sometimes a mock function will receive a function pointer or a functor (in other words, a "callable") as an argument, e.g. ``` class MockFoo : public Foo { public: MOCK_METHOD2(DoThis, bool(int n, bool (*fp)(int))); }; ``` and you may want to invoke this callable argument: ``` using ::testing::_; ... MockFoo foo; EXPECT_CALL(foo, DoThis(_, _)) .WillOnce(...); // Will execute (*fp)(5), where fp is the // second argument DoThis() receives. ``` Arghh, you need to refer to a mock function argument but C++ has no lambda (yet), so you have to define your own action. :-( Or do you really? Well, Google Mock has an action to solve _exactly_ this problem: ``` InvokeArgument(arg_1, arg_2, ..., arg_m) ``` will invoke the `N`-th (0-based) argument the mock function receives, with `arg_1`, `arg_2`, ..., and `arg_m`. No matter if the argument is a function pointer or a functor, Google Mock handles them both. With that, you could write: ``` using ::testing::_; using ::testing::InvokeArgument; ... EXPECT_CALL(foo, DoThis(_, _)) .WillOnce(InvokeArgument<1>(5)); // Will execute (*fp)(5), where fp is the // second argument DoThis() receives. ``` What if the callable takes an argument by reference? No problem - just wrap it inside `ByRef()`: ``` ... MOCK_METHOD1(Bar, bool(bool (*fp)(int, const Helper&))); ... using ::testing::_; using ::testing::ByRef; using ::testing::InvokeArgument; ... MockFoo foo; Helper helper; ... EXPECT_CALL(foo, Bar(_)) .WillOnce(InvokeArgument<0>(5, ByRef(helper))); // ByRef(helper) guarantees that a reference to helper, not a copy of it, // will be passed to the callable. ``` What if the callable takes an argument by reference and we do **not** wrap the argument in `ByRef()`? Then `InvokeArgument()` will _make a copy_ of the argument, and pass a _reference to the copy_, instead of a reference to the original value, to the callable. This is especially handy when the argument is a temporary value: ``` ... MOCK_METHOD1(DoThat, bool(bool (*f)(const double& x, const string& s))); ... using ::testing::_; using ::testing::InvokeArgument; ... MockFoo foo; ... EXPECT_CALL(foo, DoThat(_)) .WillOnce(InvokeArgument<0>(5.0, string("Hi"))); // Will execute (*f)(5.0, string("Hi")), where f is the function pointer // DoThat() receives. Note that the values 5.0 and string("Hi") are // temporary and dead once the EXPECT_CALL() statement finishes. Yet // it's fine to perform this action later, since a copy of the values // are kept inside the InvokeArgument action. ``` ## Ignoring an Action's Result ## Sometimes you have an action that returns _something_, but you need an action that returns `void` (perhaps you want to use it in a mock function that returns `void`, or perhaps it needs to be used in `DoAll()` and it's not the last in the list). `IgnoreResult()` lets you do that. For example: ``` using ::testing::_; using ::testing::Invoke; using ::testing::Return; int Process(const MyData& data); string DoSomething(); class MockFoo : public Foo { public: MOCK_METHOD1(Abc, void(const MyData& data)); MOCK_METHOD0(Xyz, bool()); }; ... MockFoo foo; EXPECT_CALL(foo, Abc(_)) // .WillOnce(Invoke(Process)); // The above line won't compile as Process() returns int but Abc() needs // to return void. .WillOnce(IgnoreResult(Invoke(Process))); EXPECT_CALL(foo, Xyz()) .WillOnce(DoAll(IgnoreResult(Invoke(DoSomething)), // Ignores the string DoSomething() returns. Return(true))); ``` Note that you **cannot** use `IgnoreResult()` on an action that already returns `void`. Doing so will lead to ugly compiler errors. ## Selecting an Action's Arguments ## Say you have a mock function `Foo()` that takes seven arguments, and you have a custom action that you want to invoke when `Foo()` is called. Trouble is, the custom action only wants three arguments: ``` using ::testing::_; using ::testing::Invoke; ... MOCK_METHOD7(Foo, bool(bool visible, const string& name, int x, int y, const map, double>& weight, double min_weight, double max_wight)); ... bool IsVisibleInQuadrant1(bool visible, int x, int y) { return visible && x >= 0 && y >= 0; } ... EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) .WillOnce(Invoke(IsVisibleInQuadrant1)); // Uh, won't compile. :-( ``` To please the compiler God, you can to define an "adaptor" that has the same signature as `Foo()` and calls the custom action with the right arguments: ``` using ::testing::_; using ::testing::Invoke; bool MyIsVisibleInQuadrant1(bool visible, const string& name, int x, int y, const map, double>& weight, double min_weight, double max_wight) { return IsVisibleInQuadrant1(visible, x, y); } ... EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) .WillOnce(Invoke(MyIsVisibleInQuadrant1)); // Now it works. ``` But isn't this awkward? Google Mock provides a generic _action adaptor_, so you can spend your time minding more important business than writing your own adaptors. Here's the syntax: ``` WithArgs(action) ``` creates an action that passes the arguments of the mock function at the given indices (0-based) to the inner `action` and performs it. Using `WithArgs`, our original example can be written as: ``` using ::testing::_; using ::testing::Invoke; using ::testing::WithArgs; ... EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) .WillOnce(WithArgs<0, 2, 3>(Invoke(IsVisibleInQuadrant1))); // No need to define your own adaptor. ``` For better readability, Google Mock also gives you: * `WithoutArgs(action)` when the inner `action` takes _no_ argument, and * `WithArg(action)` (no `s` after `Arg`) when the inner `action` takes _one_ argument. As you may have realized, `InvokeWithoutArgs(...)` is just syntactic sugar for `WithoutArgs(Inovke(...))`. Here are more tips: * The inner action used in `WithArgs` and friends does not have to be `Invoke()` -- it can be anything. * You can repeat an argument in the argument list if necessary, e.g. `WithArgs<2, 3, 3, 5>(...)`. * You can change the order of the arguments, e.g. `WithArgs<3, 2, 1>(...)`. * The types of the selected arguments do _not_ have to match the signature of the inner action exactly. It works as long as they can be implicitly converted to the corresponding arguments of the inner action. For example, if the 4-th argument of the mock function is an `int` and `my_action` takes a `double`, `WithArg<4>(my_action)` will work. ## Ignoring Arguments in Action Functions ## The selecting-an-action's-arguments recipe showed us one way to make a mock function and an action with incompatible argument lists fit together. The downside is that wrapping the action in `WithArgs<...>()` can get tedious for people writing the tests. If you are defining a function, method, or functor to be used with `Invoke*()`, and you are not interested in some of its arguments, an alternative to `WithArgs` is to declare the uninteresting arguments as `Unused`. This makes the definition less cluttered and less fragile in case the types of the uninteresting arguments change. It could also increase the chance the action function can be reused. For example, given ``` MOCK_METHOD3(Foo, double(const string& label, double x, double y)); MOCK_METHOD3(Bar, double(int index, double x, double y)); ``` instead of ``` using ::testing::_; using ::testing::Invoke; double DistanceToOriginWithLabel(const string& label, double x, double y) { return sqrt(x*x + y*y); } double DistanceToOriginWithIndex(int index, double x, double y) { return sqrt(x*x + y*y); } ... EXEPCT_CALL(mock, Foo("abc", _, _)) .WillOnce(Invoke(DistanceToOriginWithLabel)); EXEPCT_CALL(mock, Bar(5, _, _)) .WillOnce(Invoke(DistanceToOriginWithIndex)); ``` you could write ``` using ::testing::_; using ::testing::Invoke; using ::testing::Unused; double DistanceToOrigin(Unused, double x, double y) { return sqrt(x*x + y*y); } ... EXEPCT_CALL(mock, Foo("abc", _, _)) .WillOnce(Invoke(DistanceToOrigin)); EXEPCT_CALL(mock, Bar(5, _, _)) .WillOnce(Invoke(DistanceToOrigin)); ``` ## Sharing Actions ## Just like matchers, a Google Mock action object consists of a pointer to a ref-counted implementation object. Therefore copying actions is also allowed and very efficient. When the last action that references the implementation object dies, the implementation object will be deleted. If you have some complex action that you want to use again and again, you may not have to build it from scratch everytime. If the action doesn't have an internal state (i.e. if it always does the same thing no matter how many times it has been called), you can assign it to an action variable and use that variable repeatedly. For example: ``` Action set_flag = DoAll(SetArgPointee<0>(5), Return(true)); ... use set_flag in .WillOnce() and .WillRepeatedly() ... ``` However, if the action has its own state, you may be surprised if you share the action object. Suppose you have an action factory `IncrementCounter(init)` which creates an action that increments and returns a counter whose initial value is `init`, using two actions created from the same expression and using a shared action will exihibit different behaviors. Example: ``` EXPECT_CALL(foo, DoThis()) .WillRepeatedly(IncrementCounter(0)); EXPECT_CALL(foo, DoThat()) .WillRepeatedly(IncrementCounter(0)); foo.DoThis(); // Returns 1. foo.DoThis(); // Returns 2. foo.DoThat(); // Returns 1 - Blah() uses a different // counter than Bar()'s. ``` versus ``` Action increment = IncrementCounter(0); EXPECT_CALL(foo, DoThis()) .WillRepeatedly(increment); EXPECT_CALL(foo, DoThat()) .WillRepeatedly(increment); foo.DoThis(); // Returns 1. foo.DoThis(); // Returns 2. foo.DoThat(); // Returns 3 - the counter is shared. ``` # Misc Recipes on Using Google Mock # ## Making the Compilation Faster ## Believe it or not, the _vast majority_ of the time spent on compiling a mock class is in generating its constructor and destructor, as they perform non-trivial tasks (e.g. verification of the expectations). What's more, mock methods with different signatures have different types and thus their constructors/destructors need to be generated by the compiler separately. As a result, if you mock many different types of methods, compiling your mock class can get really slow. If you are experiencing slow compilation, you can move the definition of your mock class' constructor and destructor out of the class body and into a `.cpp` file. This way, even if you `#include` your mock class in N files, the compiler only needs to generate its constructor and destructor once, resulting in a much faster compilation. Let's illustrate the idea using an example. Here's the definition of a mock class before applying this recipe: ``` // File mock_foo.h. ... class MockFoo : public Foo { public: // Since we don't declare the constructor or the destructor, // the compiler will generate them in every translation unit // where this mock class is used. MOCK_METHOD0(DoThis, int()); MOCK_METHOD1(DoThat, bool(const char* str)); ... more mock methods ... }; ``` After the change, it would look like: ``` // File mock_foo.h. ... class MockFoo : public Foo { public: // The constructor and destructor are declared, but not defined, here. MockFoo(); virtual ~MockFoo(); MOCK_METHOD0(DoThis, int()); MOCK_METHOD1(DoThat, bool(const char* str)); ... more mock methods ... }; ``` and ``` // File mock_foo.cpp. #include "path/to/mock_foo.h" // The definitions may appear trivial, but the functions actually do a // lot of things through the constructors/destructors of the member // variables used to implement the mock methods. MockFoo::MockFoo() {} MockFoo::~MockFoo() {} ``` ## Forcing a Verification ## When it's being destoyed, your friendly mock object will automatically verify that all expectations on it have been satisfied, and will generate [Google Test](http://code.google.com/p/googletest/) failures if not. This is convenient as it leaves you with one less thing to worry about. That is, unless you are not sure if your mock object will be destoyed. How could it be that your mock object won't eventually be destroyed? Well, it might be created on the heap and owned by the code you are testing. Suppose there's a bug in that code and it doesn't delete the mock object properly - you could end up with a passing test when there's actually a bug. Using a heap checker is a good idea and can alleviate the concern, but its implementation may not be 100% reliable. So, sometimes you do want to _force_ Google Mock to verify a mock object before it is (hopefully) destructed. You can do this with `Mock::VerifyAndClearExpectations(&mock_object)`: ``` TEST(MyServerTest, ProcessesRequest) { using ::testing::Mock; MockFoo* const foo = new MockFoo; EXPECT_CALL(*foo, ...)...; // ... other expectations ... // server now owns foo. MyServer server(foo); server.ProcessRequest(...); // In case that server's destructor will forget to delete foo, // this will verify the expectations anyway. Mock::VerifyAndClearExpectations(foo); } // server is destroyed when it goes out of scope here. ``` **Tip:** The `Mock::VerifyAndClearExpectations()` function returns a `bool` to indicate whether the verification was successful (`true` for yes), so you can wrap that function call inside a `ASSERT_TRUE()` if there is no point going further when the verification has failed. ## Using Check Points ## Sometimes you may want to "reset" a mock object at various check points in your test: at each check point, you verify that all existing expectations on the mock object have been satisfied, and then you set some new expectations on it as if it's newly created. This allows you to work with a mock object in "phases" whose sizes are each manageable. One such scenario is that in your test's `SetUp()` function, you may want to put the object you are testing into a certain state, with the help from a mock object. Once in the desired state, you want to clear all expectations on the mock, such that in the `TEST_F` body you can set fresh expectations on it. As you may have figured out, the `Mock::VerifyAndClearExpectations()` function we saw in the previous recipe can help you here. Or, if you are using `ON_CALL()` to set default actions on the mock object and want to clear the default actions as well, use `Mock::VerifyAndClear(&mock_object)` instead. This function does what `Mock::VerifyAndClearExpectations(&mock_object)` does and returns the same `bool`, **plus** it clears the `ON_CALL()` statements on `mock_object` too. Another trick you can use to achieve the same effect is to put the expectations in sequences and insert calls to a dummy "check-point" function at specific places. Then you can verify that the mock function calls do happen at the right time. For example, if you are exercising code: ``` Foo(1); Foo(2); Foo(3); ``` and want to verify that `Foo(1)` and `Foo(3)` both invoke `mock.Bar("a")`, but `Foo(2)` doesn't invoke anything. You can write: ``` using ::testing::MockFunction; TEST(FooTest, InvokesBarCorrectly) { MyMock mock; // Class MockFunction has exactly one mock method. It is named // Call() and has type F. MockFunction check; { InSequence s; EXPECT_CALL(mock, Bar("a")); EXPECT_CALL(check, Call("1")); EXPECT_CALL(check, Call("2")); EXPECT_CALL(mock, Bar("a")); } Foo(1); check.Call("1"); Foo(2); check.Call("2"); Foo(3); } ``` The expectation spec says that the first `Bar("a")` must happen before check point "1", the second `Bar("a")` must happen after check point "2", and nothing should happen between the two check points. The explicit check points make it easy to tell which `Bar("a")` is called by which call to `Foo()`. ## Mocking Destructors ## Sometimes you want to make sure a mock object is destructed at the right time, e.g. after `bar->A()` is called but before `bar->B()` is called. We already know that you can specify constraints on the order of mock function calls, so all we need to do is to mock the destructor of the mock function. This sounds simple, except for one problem: a destructor is a special function with special syntax and special semantics, and the `MOCK_METHOD0` macro doesn't work for it: ``` MOCK_METHOD0(~MockFoo, void()); // Won't compile! ``` The good news is that you can use a simple pattern to achieve the same effect. First, add a mock function `Die()` to your mock class and call it in the destructor, like this: ``` class MockFoo : public Foo { ... // Add the following two lines to the mock class. MOCK_METHOD0(Die, void()); virtual ~MockFoo() { Die(); } }; ``` (If the name `Die()` clashes with an existing symbol, choose another name.) Now, we have translated the problem of testing when a `MockFoo` object dies to testing when its `Die()` method is called: ``` MockFoo* foo = new MockFoo; MockBar* bar = new MockBar; ... { InSequence s; // Expects *foo to die after bar->A() and before bar->B(). EXPECT_CALL(*bar, A()); EXPECT_CALL(*foo, Die()); EXPECT_CALL(*bar, B()); } ``` And that's that. ## Using Google Mock and Threads ## **IMPORTANT NOTE:** What we describe in this recipe is **ONLY** true on platforms where Google Mock is thread-safe. Currently these are only platforms that support the pthreads library (this includes Linux and Mac). To make it thread-safe on other platforms we only need to implement some synchronization operations in `"gtest/internal/gtest-port.h"`. In a **unit** test, it's best if you could isolate and test a piece of code in a single-threaded context. That avoids race conditions and dead locks, and makes debugging your test much easier. Yet many programs are multi-threaded, and sometimes to test something we need to pound on it from more than one thread. Google Mock works for this purpose too. Remember the steps for using a mock: 1. Create a mock object `foo`. 1. Set its default actions and expectations using `ON_CALL()` and `EXPECT_CALL()`. 1. The code under test calls methods of `foo`. 1. Optionally, verify and reset the mock. 1. Destroy the mock yourself, or let the code under test destroy it. The destructor will automatically verify it. If you follow the following simple rules, your mocks and threads can live happily togeter: * Execute your _test code_ (as opposed to the code being tested) in _one_ thread. This makes your test easy to follow. * Obviously, you can do step #1 without locking. * When doing step #2 and #5, make sure no other thread is accessing `foo`. Obvious too, huh? * #3 and #4 can be done either in one thread or in multiple threads - anyway you want. Google Mock takes care of the locking, so you don't have to do any - unless required by your test logic. If you violate the rules (for example, if you set expectations on a mock while another thread is calling its methods), you get undefined behavior. That's not fun, so don't do it. Google Mock guarantees that the action for a mock function is done in the same thread that called the mock function. For example, in ``` EXPECT_CALL(mock, Foo(1)) .WillOnce(action1); EXPECT_CALL(mock, Foo(2)) .WillOnce(action2); ``` if `Foo(1)` is called in thread 1 and `Foo(2)` is called in thread 2, Google Mock will execute `action1` in thread 1 and `action2` in thread 2. Google Mock does _not_ impose a sequence on actions performed in different threads (doing so may create deadlocks as the actions may need to cooperate). This means that the execution of `action1` and `action2` in the above example _may_ interleave. If this is a problem, you should add proper synchronization logic to `action1` and `action2` to make the test thread-safe. Also, remember that `DefaultValue` is a global resource that potentially affects _all_ living mock objects in your program. Naturally, you won't want to mess with it from multiple threads or when there still are mocks in action. ## Controlling How Much Information Google Mock Prints ## When Google Mock sees something that has the potential of being an error (e.g. a mock function with no expectation is called, a.k.a. an uninteresting call, which is allowed but perhaps you forgot to explicitly ban the call), it prints some warning messages, including the arguments of the function and the return value. Hopefully this will remind you to take a look and see if there is indeed a problem. Sometimes you are confident that your tests are correct and may not appreciate such friendly messages. Some other times, you are debugging your tests or learning about the behavior of the code you are testing, and wish you could observe every mock call that happens (including argument values and the return value). Clearly, one size doesn't fit all. You can control how much Google Mock tells you using the `--gmock_verbose=LEVEL` command-line flag, where `LEVEL` is a string with three possible values: * `info`: Google Mock will print all informational messages, warnings, and errors (most verbose). At this setting, Google Mock will also log any calls to the `ON_CALL/EXPECT_CALL` macros. * `warning`: Google Mock will print both warnings and errors (less verbose). This is the default. * `error`: Google Mock will print errors only (least verbose). Alternatively, you can adjust the value of that flag from within your tests like so: ``` ::testing::FLAGS_gmock_verbose = "error"; ``` Now, judiciously use the right flag to enable Google Mock serve you better! ## Running Tests in Emacs ## If you build and run your tests in Emacs, the source file locations of Google Mock and [Google Test](http://code.google.com/p/googletest/) errors will be highlighted. Just press `` on one of them and you'll be taken to the offending line. Or, you can just type `C-x `` to jump to the next error. To make it even easier, you can add the following lines to your `~/.emacs` file: ``` (global-set-key "\M-m" 'compile) ; m is for make (global-set-key [M-down] 'next-error) (global-set-key [M-up] '(lambda () (interactive) (next-error -1))) ``` Then you can type `M-m` to start a build, or `M-up`/`M-down` to move back and forth between errors. ## Fusing Google Mock Source Files ## Google Mock's implementation consists of dozens of files (excluding its own tests). Sometimes you may want them to be packaged up in fewer files instead, such that you can easily copy them to a new machine and start hacking there. For this we provide an experimental Python script `fuse_gmock_files.py` in the `scripts/` directory (starting with release 1.2.0). Assuming you have Python 2.4 or above installed on your machine, just go to that directory and run ``` python fuse_gmock_files.py OUTPUT_DIR ``` and you should see an `OUTPUT_DIR` directory being created with files `gtest/gtest.h`, `gmock/gmock.h`, and `gmock-gtest-all.cc` in it. These three files contain everything you need to use Google Mock (and Google Test). Just copy them to anywhere you want and you are ready to write tests and use mocks. You can use the [scrpts/test/Makefile](http://code.google.com/p/googlemock/source/browse/trunk/scripts/test/Makefile) file as an example on how to compile your tests against them. # Extending Google Mock # ## Writing New Matchers Quickly ## The `MATCHER*` family of macros can be used to define custom matchers easily. The syntax: ``` MATCHER(name, description_string_expression) { statements; } ``` will define a matcher with the given name that executes the statements, which must return a `bool` to indicate if the match succeeds. Inside the statements, you can refer to the value being matched by `arg`, and refer to its type by `arg_type`. The description string is a `string`-typed expression that documents what the matcher does, and is used to generate the failure message when the match fails. It can (and should) reference the special `bool` variable `negation`, and should evaluate to the description of the matcher when `negation` is `false`, or that of the matcher's negation when `negation` is `true`. For convenience, we allow the description string to be empty (`""`), in which case Google Mock will use the sequence of words in the matcher name as the description. For example: ``` MATCHER(IsDivisibleBy7, "") { return (arg % 7) == 0; } ``` allows you to write ``` // Expects mock_foo.Bar(n) to be called where n is divisible by 7. EXPECT_CALL(mock_foo, Bar(IsDivisibleBy7())); ``` or, ``` using ::testing::Not; ... EXPECT_THAT(some_expression, IsDivisibleBy7()); EXPECT_THAT(some_other_expression, Not(IsDivisibleBy7())); ``` If the above assertions fail, they will print something like: ``` Value of: some_expression Expected: is divisible by 7 Actual: 27 ... Value of: some_other_expression Expected: not (is divisible by 7) Actual: 21 ``` where the descriptions `"is divisible by 7"` and `"not (is divisible by 7)"` are automatically calculated from the matcher name `IsDivisibleBy7`. As you may have noticed, the auto-generated descriptions (especially those for the negation) may not be so great. You can always override them with a string expression of your own: ``` MATCHER(IsDivisibleBy7, std::string(negation ? "isn't" : "is") + " divisible by 7") { return (arg % 7) == 0; } ``` Optionally, you can stream additional information to a hidden argument named `result_listener` to explain the match result. For example, a better definition of `IsDivisibleBy7` is: ``` MATCHER(IsDivisibleBy7, "") { if ((arg % 7) == 0) return true; *result_listener << "the remainder is " << (arg % 7); return false; } ``` With this definition, the above assertion will give a better message: ``` Value of: some_expression Expected: is divisible by 7 Actual: 27 (the remainder is 6) ``` You should let `MatchAndExplain()` print _any additional information_ that can help a user understand the match result. Note that it should explain why the match succeeds in case of a success (unless it's obvious) - this is useful when the matcher is used inside `Not()`. There is no need to print the argument value itself, as Google Mock already prints it for you. **Notes:** 1. The type of the value being matched (`arg_type`) is determined by the context in which you use the matcher and is supplied to you by the compiler, so you don't need to worry about declaring it (nor can you). This allows the matcher to be polymorphic. For example, `IsDivisibleBy7()` can be used to match any type where the value of `(arg % 7) == 0` can be implicitly converted to a `bool`. In the `Bar(IsDivisibleBy7())` example above, if method `Bar()` takes an `int`, `arg_type` will be `int`; if it takes an `unsigned long`, `arg_type` will be `unsigned long`; and so on. 1. Google Mock doesn't guarantee when or how many times a matcher will be invoked. Therefore the matcher logic must be _purely functional_ (i.e. it cannot have any side effect, and the result must not depend on anything other than the value being matched and the matcher parameters). This requirement must be satisfied no matter how you define the matcher (e.g. using one of the methods described in the following recipes). In particular, a matcher can never call a mock function, as that will affect the state of the mock object and Google Mock. ## Writing New Parameterized Matchers Quickly ## Sometimes you'll want to define a matcher that has parameters. For that you can use the macro: ``` MATCHER_P(name, param_name, description_string) { statements; } ``` where the description string can be either `""` or a string expression that references `negation` and `param_name`. For example: ``` MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; } ``` will allow you to write: ``` EXPECT_THAT(Blah("a"), HasAbsoluteValue(n)); ``` which may lead to this message (assuming `n` is 10): ``` Value of: Blah("a") Expected: has absolute value 10 Actual: -9 ``` Note that both the matcher description and its parameter are printed, making the message human-friendly. In the matcher definition body, you can write `foo_type` to reference the type of a parameter named `foo`. For example, in the body of `MATCHER_P(HasAbsoluteValue, value)` above, you can write `value_type` to refer to the type of `value`. Google Mock also provides `MATCHER_P2`, `MATCHER_P3`, ..., up to `MATCHER_P10` to support multi-parameter matchers: ``` MATCHER_Pk(name, param_1, ..., param_k, description_string) { statements; } ``` Please note that the custom description string is for a particular **instance** of the matcher, where the parameters have been bound to actual values. Therefore usually you'll want the parameter values to be part of the description. Google Mock lets you do that by referencing the matcher parameters in the description string expression. For example, ``` using ::testing::PrintToString; MATCHER_P2(InClosedRange, low, hi, std::string(negation ? "isn't" : "is") + " in range [" + PrintToString(low) + ", " + PrintToString(hi) + "]") { return low <= arg && arg <= hi; } ... EXPECT_THAT(3, InClosedRange(4, 6)); ``` would generate a failure that contains the message: ``` Expected: is in range [4, 6] ``` If you specify `""` as the description, the failure message will contain the sequence of words in the matcher name followed by the parameter values printed as a tuple. For example, ``` MATCHER_P2(InClosedRange, low, hi, "") { ... } ... EXPECT_THAT(3, InClosedRange(4, 6)); ``` would generate a failure that contains the text: ``` Expected: in closed range (4, 6) ``` For the purpose of typing, you can view ``` MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... } ``` as shorthand for ``` template FooMatcherPk Foo(p1_type p1, ..., pk_type pk) { ... } ``` When you write `Foo(v1, ..., vk)`, the compiler infers the types of the parameters `v1`, ..., and `vk` for you. If you are not happy with the result of the type inference, you can specify the types by explicitly instantiating the template, as in `Foo(5, false)`. As said earlier, you don't get to (or need to) specify `arg_type` as that's determined by the context in which the matcher is used. You can assign the result of expression `Foo(p1, ..., pk)` to a variable of type `FooMatcherPk`. This can be useful when composing matchers. Matchers that don't have a parameter or have only one parameter have special types: you can assign `Foo()` to a `FooMatcher`-typed variable, and assign `Foo(p)` to a `FooMatcherP`-typed variable. While you can instantiate a matcher template with reference types, passing the parameters by pointer usually makes your code more readable. If, however, you still want to pass a parameter by reference, be aware that in the failure message generated by the matcher you will see the value of the referenced object but not its address. You can overload matchers with different numbers of parameters: ``` MATCHER_P(Blah, a, description_string_1) { ... } MATCHER_P2(Blah, a, b, description_string_2) { ... } ``` While it's tempting to always use the `MATCHER*` macros when defining a new matcher, you should also consider implementing `MatcherInterface` or using `MakePolymorphicMatcher()` instead (see the recipes that follow), especially if you need to use the matcher a lot. While these approaches require more work, they give you more control on the types of the value being matched and the matcher parameters, which in general leads to better compiler error messages that pay off in the long run. They also allow overloading matchers based on parameter types (as opposed to just based on the number of parameters). ## Writing New Monomorphic Matchers ## A matcher of argument type `T` implements `::testing::MatcherInterface` and does two things: it tests whether a value of type `T` matches the matcher, and can describe what kind of values it matches. The latter ability is used for generating readable error messages when expectations are violated. The interface looks like this: ``` class MatchResultListener { public: ... // Streams x to the underlying ostream; does nothing if the ostream // is NULL. template MatchResultListener& operator<<(const T& x); // Returns the underlying ostream. ::std::ostream* stream(); }; template class MatcherInterface { public: virtual ~MatcherInterface(); // Returns true iff the matcher matches x; also explains the match // result to 'listener'. virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0; // Describes this matcher to an ostream. virtual void DescribeTo(::std::ostream* os) const = 0; // Describes the negation of this matcher to an ostream. virtual void DescribeNegationTo(::std::ostream* os) const; }; ``` If you need a custom matcher but `Truly()` is not a good option (for example, you may not be happy with the way `Truly(predicate)` describes itself, or you may want your matcher to be polymorphic as `Eq(value)` is), you can define a matcher to do whatever you want in two steps: first implement the matcher interface, and then define a factory function to create a matcher instance. The second step is not strictly needed but it makes the syntax of using the matcher nicer. For example, you can define a matcher to test whether an `int` is divisible by 7 and then use it like this: ``` using ::testing::MakeMatcher; using ::testing::Matcher; using ::testing::MatcherInterface; using ::testing::MatchResultListener; class DivisibleBy7Matcher : public MatcherInterface { public: virtual bool MatchAndExplain(int n, MatchResultListener* listener) const { return (n % 7) == 0; } virtual void DescribeTo(::std::ostream* os) const { *os << "is divisible by 7"; } virtual void DescribeNegationTo(::std::ostream* os) const { *os << "is not divisible by 7"; } }; inline Matcher DivisibleBy7() { return MakeMatcher(new DivisibleBy7Matcher); } ... EXPECT_CALL(foo, Bar(DivisibleBy7())); ``` You may improve the matcher message by streaming additional information to the `listener` argument in `MatchAndExplain()`: ``` class DivisibleBy7Matcher : public MatcherInterface { public: virtual bool MatchAndExplain(int n, MatchResultListener* listener) const { const int remainder = n % 7; if (remainder != 0) { *listener << "the remainder is " << remainder; } return remainder == 0; } ... }; ``` Then, `EXPECT_THAT(x, DivisibleBy7());` may general a message like this: ``` Value of: x Expected: is divisible by 7 Actual: 23 (the remainder is 2) ``` ## Writing New Polymorphic Matchers ## You've learned how to write your own matchers in the previous recipe. Just one problem: a matcher created using `MakeMatcher()` only works for one particular type of arguments. If you want a _polymorphic_ matcher that works with arguments of several types (for instance, `Eq(x)` can be used to match a `value` as long as `value` == `x` compiles -- `value` and `x` don't have to share the same type), you can learn the trick from `"gmock/gmock-matchers.h"` but it's a bit involved. Fortunately, most of the time you can define a polymorphic matcher easily with the help of `MakePolymorphicMatcher()`. Here's how you can define `NotNull()` as an example: ``` using ::testing::MakePolymorphicMatcher; using ::testing::MatchResultListener; using ::testing::NotNull; using ::testing::PolymorphicMatcher; class NotNullMatcher { public: // To implement a polymorphic matcher, first define a COPYABLE class // that has three members MatchAndExplain(), DescribeTo(), and // DescribeNegationTo(), like the following. // In this example, we want to use NotNull() with any pointer, so // MatchAndExplain() accepts a pointer of any type as its first argument. // In general, you can define MatchAndExplain() as an ordinary method or // a method template, or even overload it. template bool MatchAndExplain(T* p, MatchResultListener* /* listener */) const { return p != NULL; } // Describes the property of a value matching this matcher. void DescribeTo(::std::ostream* os) const { *os << "is not NULL"; } // Describes the property of a value NOT matching this matcher. void DescribeNegationTo(::std::ostream* os) const { *os << "is NULL"; } }; // To construct a polymorphic matcher, pass an instance of the class // to MakePolymorphicMatcher(). Note the return type. inline PolymorphicMatcher NotNull() { return MakePolymorphicMatcher(NotNullMatcher()); } ... EXPECT_CALL(foo, Bar(NotNull())); // The argument must be a non-NULL pointer. ``` **Note:** Your polymorphic matcher class does **not** need to inherit from `MatcherInterface` or any other class, and its methods do **not** need to be virtual. Like in a monomorphic matcher, you may explain the match result by streaming additional information to the `listener` argument in `MatchAndExplain()`. ## Writing New Cardinalities ## A cardinality is used in `Times()` to tell Google Mock how many times you expect a call to occur. It doesn't have to be exact. For example, you can say `AtLeast(5)` or `Between(2, 4)`. If the built-in set of cardinalities doesn't suit you, you are free to define your own by implementing the following interface (in namespace `testing`): ``` class CardinalityInterface { public: virtual ~CardinalityInterface(); // Returns true iff call_count calls will satisfy this cardinality. virtual bool IsSatisfiedByCallCount(int call_count) const = 0; // Returns true iff call_count calls will saturate this cardinality. virtual bool IsSaturatedByCallCount(int call_count) const = 0; // Describes self to an ostream. virtual void DescribeTo(::std::ostream* os) const = 0; }; ``` For example, to specify that a call must occur even number of times, you can write ``` using ::testing::Cardinality; using ::testing::CardinalityInterface; using ::testing::MakeCardinality; class EvenNumberCardinality : public CardinalityInterface { public: virtual bool IsSatisfiedByCallCount(int call_count) const { return (call_count % 2) == 0; } virtual bool IsSaturatedByCallCount(int call_count) const { return false; } virtual void DescribeTo(::std::ostream* os) const { *os << "called even number of times"; } }; Cardinality EvenNumber() { return MakeCardinality(new EvenNumberCardinality); } ... EXPECT_CALL(foo, Bar(3)) .Times(EvenNumber()); ``` ## Writing New Actions Quickly ## If the built-in actions don't work for you, and you find it inconvenient to use `Invoke()`, you can use a macro from the `ACTION*` family to quickly define a new action that can be used in your code as if it's a built-in action. By writing ``` ACTION(name) { statements; } ``` in a namespace scope (i.e. not inside a class or function), you will define an action with the given name that executes the statements. The value returned by `statements` will be used as the return value of the action. Inside the statements, you can refer to the K-th (0-based) argument of the mock function as `argK`. For example: ``` ACTION(IncrementArg1) { return ++(*arg1); } ``` allows you to write ``` ... WillOnce(IncrementArg1()); ``` Note that you don't need to specify the types of the mock function arguments. Rest assured that your code is type-safe though: you'll get a compiler error if `*arg1` doesn't support the `++` operator, or if the type of `++(*arg1)` isn't compatible with the mock function's return type. Another example: ``` ACTION(Foo) { (*arg2)(5); Blah(); *arg1 = 0; return arg0; } ``` defines an action `Foo()` that invokes argument #2 (a function pointer) with 5, calls function `Blah()`, sets the value pointed to by argument #1 to 0, and returns argument #0. For more convenience and flexibility, you can also use the following pre-defined symbols in the body of `ACTION`: | `argK_type` | The type of the K-th (0-based) argument of the mock function | |:------------|:-------------------------------------------------------------| | `args` | All arguments of the mock function as a tuple | | `args_type` | The type of all arguments of the mock function as a tuple | | `return_type` | The return type of the mock function | | `function_type` | The type of the mock function | For example, when using an `ACTION` as a stub action for mock function: ``` int DoSomething(bool flag, int* ptr); ``` we have: | **Pre-defined Symbol** | **Is Bound To** | |:-----------------------|:----------------| | `arg0` | the value of `flag` | | `arg0_type` | the type `bool` | | `arg1` | the value of `ptr` | | `arg1_type` | the type `int*` | | `args` | the tuple `(flag, ptr)` | | `args_type` | the type `std::tr1::tuple` | | `return_type` | the type `int` | | `function_type` | the type `int(bool, int*)` | ## Writing New Parameterized Actions Quickly ## Sometimes you'll want to parameterize an action you define. For that we have another macro ``` ACTION_P(name, param) { statements; } ``` For example, ``` ACTION_P(Add, n) { return arg0 + n; } ``` will allow you to write ``` // Returns argument #0 + 5. ... WillOnce(Add(5)); ``` For convenience, we use the term _arguments_ for the values used to invoke the mock function, and the term _parameters_ for the values used to instantiate an action. Note that you don't need to provide the type of the parameter either. Suppose the parameter is named `param`, you can also use the Google-Mock-defined symbol `param_type` to refer to the type of the parameter as inferred by the compiler. For example, in the body of `ACTION_P(Add, n)` above, you can write `n_type` for the type of `n`. Google Mock also provides `ACTION_P2`, `ACTION_P3`, and etc to support multi-parameter actions. For example, ``` ACTION_P2(ReturnDistanceTo, x, y) { double dx = arg0 - x; double dy = arg1 - y; return sqrt(dx*dx + dy*dy); } ``` lets you write ``` ... WillOnce(ReturnDistanceTo(5.0, 26.5)); ``` You can view `ACTION` as a degenerated parameterized action where the number of parameters is 0. You can also easily define actions overloaded on the number of parameters: ``` ACTION_P(Plus, a) { ... } ACTION_P2(Plus, a, b) { ... } ``` ## Restricting the Type of an Argument or Parameter in an ACTION ## For maximum brevity and reusability, the `ACTION*` macros don't ask you to provide the types of the mock function arguments and the action parameters. Instead, we let the compiler infer the types for us. Sometimes, however, we may want to be more explicit about the types. There are several tricks to do that. For example: ``` ACTION(Foo) { // Makes sure arg0 can be converted to int. int n = arg0; ... use n instead of arg0 here ... } ACTION_P(Bar, param) { // Makes sure the type of arg1 is const char*. ::testing::StaticAssertTypeEq(); // Makes sure param can be converted to bool. bool flag = param; } ``` where `StaticAssertTypeEq` is a compile-time assertion in Google Test that verifies two types are the same. ## Writing New Action Templates Quickly ## Sometimes you want to give an action explicit template parameters that cannot be inferred from its value parameters. `ACTION_TEMPLATE()` supports that and can be viewed as an extension to `ACTION()` and `ACTION_P*()`. The syntax: ``` ACTION_TEMPLATE(ActionName, HAS_m_TEMPLATE_PARAMS(kind1, name1, ..., kind_m, name_m), AND_n_VALUE_PARAMS(p1, ..., p_n)) { statements; } ``` defines an action template that takes _m_ explicit template parameters and _n_ value parameters, where _m_ is between 1 and 10, and _n_ is between 0 and 10. `name_i` is the name of the i-th template parameter, and `kind_i` specifies whether it's a `typename`, an integral constant, or a template. `p_i` is the name of the i-th value parameter. Example: ``` // DuplicateArg(output) converts the k-th argument of the mock // function to type T and copies it to *output. ACTION_TEMPLATE(DuplicateArg, // Note the comma between int and k: HAS_2_TEMPLATE_PARAMS(int, k, typename, T), AND_1_VALUE_PARAMS(output)) { *output = T(std::tr1::get(args)); } ``` To create an instance of an action template, write: ``` ActionName(v1, ..., v_n) ``` where the `t`s are the template arguments and the `v`s are the value arguments. The value argument types are inferred by the compiler. For example: ``` using ::testing::_; ... int n; EXPECT_CALL(mock, Foo(_, _)) .WillOnce(DuplicateArg<1, unsigned char>(&n)); ``` If you want to explicitly specify the value argument types, you can provide additional template arguments: ``` ActionName(v1, ..., v_n) ``` where `u_i` is the desired type of `v_i`. `ACTION_TEMPLATE` and `ACTION`/`ACTION_P*` can be overloaded on the number of value parameters, but not on the number of template parameters. Without the restriction, the meaning of the following is unclear: ``` OverloadedAction(x); ``` Are we using a single-template-parameter action where `bool` refers to the type of `x`, or a two-template-parameter action where the compiler is asked to infer the type of `x`? ## Using the ACTION Object's Type ## If you are writing a function that returns an `ACTION` object, you'll need to know its type. The type depends on the macro used to define the action and the parameter types. The rule is relatively simple: | **Given Definition** | **Expression** | **Has Type** | |:---------------------|:---------------|:-------------| | `ACTION(Foo)` | `Foo()` | `FooAction` | | `ACTION_TEMPLATE(Foo, HAS_m_TEMPLATE_PARAMS(...), AND_0_VALUE_PARAMS())` | `Foo()` | `FooAction` | | `ACTION_P(Bar, param)` | `Bar(int_value)` | `BarActionP` | | `ACTION_TEMPLATE(Bar, HAS_m_TEMPLATE_PARAMS(...), AND_1_VALUE_PARAMS(p1))` | `Bar(int_value)` | `FooActionP` | | `ACTION_P2(Baz, p1, p2)` | `Baz(bool_value, int_value)` | `BazActionP2` | | `ACTION_TEMPLATE(Baz, HAS_m_TEMPLATE_PARAMS(...), AND_2_VALUE_PARAMS(p1, p2))` | `Baz(bool_value, int_value)` | `FooActionP2` | | ... | ... | ... | Note that we have to pick different suffixes (`Action`, `ActionP`, `ActionP2`, and etc) for actions with different numbers of value parameters, or the action definitions cannot be overloaded on the number of them. ## Writing New Monomorphic Actions ## While the `ACTION*` macros are very convenient, sometimes they are inappropriate. For example, despite the tricks shown in the previous recipes, they don't let you directly specify the types of the mock function arguments and the action parameters, which in general leads to unoptimized compiler error messages that can baffle unfamiliar users. They also don't allow overloading actions based on parameter types without jumping through some hoops. An alternative to the `ACTION*` macros is to implement `::testing::ActionInterface`, where `F` is the type of the mock function in which the action will be used. For example: ``` template class ActionInterface { public: virtual ~ActionInterface(); // Performs the action. Result is the return type of function type // F, and ArgumentTuple is the tuple of arguments of F. // // For example, if F is int(bool, const string&), then Result would // be int, and ArgumentTuple would be tr1::tuple. virtual Result Perform(const ArgumentTuple& args) = 0; }; using ::testing::_; using ::testing::Action; using ::testing::ActionInterface; using ::testing::MakeAction; typedef int IncrementMethod(int*); class IncrementArgumentAction : public ActionInterface { public: virtual int Perform(const tr1::tuple& args) { int* p = tr1::get<0>(args); // Grabs the first argument. return *p++; } }; Action IncrementArgument() { return MakeAction(new IncrementArgumentAction); } ... EXPECT_CALL(foo, Baz(_)) .WillOnce(IncrementArgument()); int n = 5; foo.Baz(&n); // Should return 5 and change n to 6. ``` ## Writing New Polymorphic Actions ## The previous recipe showed you how to define your own action. This is all good, except that you need to know the type of the function in which the action will be used. Sometimes that can be a problem. For example, if you want to use the action in functions with _different_ types (e.g. like `Return()` and `SetArgPointee()`). If an action can be used in several types of mock functions, we say it's _polymorphic_. The `MakePolymorphicAction()` function template makes it easy to define such an action: ``` namespace testing { template PolymorphicAction MakePolymorphicAction(const Impl& impl); } // namespace testing ``` As an example, let's define an action that returns the second argument in the mock function's argument list. The first step is to define an implementation class: ``` class ReturnSecondArgumentAction { public: template Result Perform(const ArgumentTuple& args) const { // To get the i-th (0-based) argument, use tr1::get(args). return tr1::get<1>(args); } }; ``` This implementation class does _not_ need to inherit from any particular class. What matters is that it must have a `Perform()` method template. This method template takes the mock function's arguments as a tuple in a **single** argument, and returns the result of the action. It can be either `const` or not, but must be invokable with exactly one template argument, which is the result type. In other words, you must be able to call `Perform(args)` where `R` is the mock function's return type and `args` is its arguments in a tuple. Next, we use `MakePolymorphicAction()` to turn an instance of the implementation class into the polymorphic action we need. It will be convenient to have a wrapper for this: ``` using ::testing::MakePolymorphicAction; using ::testing::PolymorphicAction; PolymorphicAction ReturnSecondArgument() { return MakePolymorphicAction(ReturnSecondArgumentAction()); } ``` Now, you can use this polymorphic action the same way you use the built-in ones: ``` using ::testing::_; class MockFoo : public Foo { public: MOCK_METHOD2(DoThis, int(bool flag, int n)); MOCK_METHOD3(DoThat, string(int x, const char* str1, const char* str2)); }; ... MockFoo foo; EXPECT_CALL(foo, DoThis(_, _)) .WillOnce(ReturnSecondArgument()); EXPECT_CALL(foo, DoThat(_, _, _)) .WillOnce(ReturnSecondArgument()); ... foo.DoThis(true, 5); // Will return 5. foo.DoThat(1, "Hi", "Bye"); // Will return "Hi". ``` ## Teaching Google Mock How to Print Your Values ## When an uninteresting or unexpected call occurs, Google Mock prints the argument values and the stack trace to help you debug. Assertion macros like `EXPECT_THAT` and `EXPECT_EQ` also print the values in question when the assertion fails. Google Mock and Google Test do this using Google Test's user-extensible value printer. This printer knows how to print built-in C++ types, native arrays, STL containers, and any type that supports the `<<` operator. For other types, it prints the raw bytes in the value and hopes that you the user can figure it out. [Google Test's advanced guide](http://code.google.com/p/googletest/wiki/V1_6_AdvancedGuide#Teaching_Google_Test_How_to_Print_Your_Values) explains how to extend the printer to do a better job at printing your particular type than to dump the bytes.nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/docs/v1_6/Documentation.md000066400000000000000000000014251455373415500275000ustar00rootroot00000000000000This page lists all documentation wiki pages for Google Mock **1.6** - **if you use a released version of Google Mock, please read the documentation for that specific version instead.** * [ForDummies](V1_6_ForDummies.md) -- start here if you are new to Google Mock. * [CheatSheet](V1_6_CheatSheet.md) -- a quick reference. * [CookBook](V1_6_CookBook.md) -- recipes for doing various tasks using Google Mock. * [FrequentlyAskedQuestions](V1_6_FrequentlyAskedQuestions.md) -- check here before asking a question on the mailing list. To contribute code to Google Mock, read: * [DevGuide](DevGuide.md) -- read this _before_ writing your first patch. * [Pump Manual](http://code.google.com/p/googletest/wiki/V1_6_PumpManual) -- how we generate some of Google Mock's source files.nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/docs/v1_6/ForDummies.md000066400000000000000000000726341455373415500267530ustar00rootroot00000000000000 (**Note:** If you get compiler errors that you don't understand, be sure to consult [Google Mock Doctor](http://code.google.com/p/googlemock/wiki/V1_6_FrequentlyAskedQuestions#How_am_I_supposed_to_make_sense_of_these_horrible_template_error).) # What Is Google C++ Mocking Framework? # When you write a prototype or test, often it's not feasible or wise to rely on real objects entirely. A **mock object** implements the same interface as a real object (so it can be used as one), but lets you specify at run time how it will be used and what it should do (which methods will be called? in which order? how many times? with what arguments? what will they return? etc). **Note:** It is easy to confuse the term _fake objects_ with mock objects. Fakes and mocks actually mean very different things in the Test-Driven Development (TDD) community: * **Fake** objects have working implementations, but usually take some shortcut (perhaps to make the operations less expensive), which makes them not suitable for production. An in-memory file system would be an example of a fake. * **Mocks** are objects pre-programmed with _expectations_, which form a specification of the calls they are expected to receive. If all this seems too abstract for you, don't worry - the most important thing to remember is that a mock allows you to check the _interaction_ between itself and code that uses it. The difference between fakes and mocks will become much clearer once you start to use mocks. **Google C++ Mocking Framework** (or **Google Mock** for short) is a library (sometimes we also call it a "framework" to make it sound cool) for creating mock classes and using them. It does to C++ what [jMock](http://www.jmock.org/) and [EasyMock](http://www.easymock.org/) do to Java. Using Google Mock involves three basic steps: 1. Use some simple macros to describe the interface you want to mock, and they will expand to the implementation of your mock class; 1. Create some mock objects and specify its expectations and behavior using an intuitive syntax; 1. Exercise code that uses the mock objects. Google Mock will catch any violation of the expectations as soon as it arises. # Why Google Mock? # While mock objects help you remove unnecessary dependencies in tests and make them fast and reliable, using mocks manually in C++ is _hard_: * Someone has to implement the mocks. The job is usually tedious and error-prone. No wonder people go great distance to avoid it. * The quality of those manually written mocks is a bit, uh, unpredictable. You may see some really polished ones, but you may also see some that were hacked up in a hurry and have all sorts of ad hoc restrictions. * The knowledge you gained from using one mock doesn't transfer to the next. In contrast, Java and Python programmers have some fine mock frameworks, which automate the creation of mocks. As a result, mocking is a proven effective technique and widely adopted practice in those communities. Having the right tool absolutely makes the difference. Google Mock was built to help C++ programmers. It was inspired by [jMock](http://www.jmock.org/) and [EasyMock](http://www.easymock.org/), but designed with C++'s specifics in mind. It is your friend if any of the following problems is bothering you: * You are stuck with a sub-optimal design and wish you had done more prototyping before it was too late, but prototyping in C++ is by no means "rapid". * Your tests are slow as they depend on too many libraries or use expensive resources (e.g. a database). * Your tests are brittle as some resources they use are unreliable (e.g. the network). * You want to test how your code handles a failure (e.g. a file checksum error), but it's not easy to cause one. * You need to make sure that your module interacts with other modules in the right way, but it's hard to observe the interaction; therefore you resort to observing the side effects at the end of the action, which is awkward at best. * You want to "mock out" your dependencies, except that they don't have mock implementations yet; and, frankly, you aren't thrilled by some of those hand-written mocks. We encourage you to use Google Mock as: * a _design_ tool, for it lets you experiment with your interface design early and often. More iterations lead to better designs! * a _testing_ tool to cut your tests' outbound dependencies and probe the interaction between your module and its collaborators. # Getting Started # Using Google Mock is easy! Inside your C++ source file, just `#include` `"gtest/gtest.h"` and `"gmock/gmock.h"`, and you are ready to go. # A Case for Mock Turtles # Let's look at an example. Suppose you are developing a graphics program that relies on a LOGO-like API for drawing. How would you test that it does the right thing? Well, you can run it and compare the screen with a golden screen snapshot, but let's admit it: tests like this are expensive to run and fragile (What if you just upgraded to a shiny new graphics card that has better anti-aliasing? Suddenly you have to update all your golden images.). It would be too painful if all your tests are like this. Fortunately, you learned about Dependency Injection and know the right thing to do: instead of having your application talk to the drawing API directly, wrap the API in an interface (say, `Turtle`) and code to that interface: ``` class Turtle { ... virtual ~Turtle() {} virtual void PenUp() = 0; virtual void PenDown() = 0; virtual void Forward(int distance) = 0; virtual void Turn(int degrees) = 0; virtual void GoTo(int x, int y) = 0; virtual int GetX() const = 0; virtual int GetY() const = 0; }; ``` (Note that the destructor of `Turtle` **must** be virtual, as is the case for **all** classes you intend to inherit from - otherwise the destructor of the derived class will not be called when you delete an object through a base pointer, and you'll get corrupted program states like memory leaks.) You can control whether the turtle's movement will leave a trace using `PenUp()` and `PenDown()`, and control its movement using `Forward()`, `Turn()`, and `GoTo()`. Finally, `GetX()` and `GetY()` tell you the current position of the turtle. Your program will normally use a real implementation of this interface. In tests, you can use a mock implementation instead. This allows you to easily check what drawing primitives your program is calling, with what arguments, and in which order. Tests written this way are much more robust (they won't break because your new machine does anti-aliasing differently), easier to read and maintain (the intent of a test is expressed in the code, not in some binary images), and run _much, much faster_. # Writing the Mock Class # If you are lucky, the mocks you need to use have already been implemented by some nice people. If, however, you find yourself in the position to write a mock class, relax - Google Mock turns this task into a fun game! (Well, almost.) ## How to Define It ## Using the `Turtle` interface as example, here are the simple steps you need to follow: 1. Derive a class `MockTurtle` from `Turtle`. 1. Take a _virtual_ function of `Turtle` (while it's possible to [mock non-virtual methods using templates](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Mocking_Nonvirtual_Methods), it's much more involved). Count how many arguments it has. 1. In the `public:` section of the child class, write `MOCK_METHODn();` (or `MOCK_CONST_METHODn();` if you are mocking a `const` method), where `n` is the number of the arguments; if you counted wrong, shame on you, and a compiler error will tell you so. 1. Now comes the fun part: you take the function signature, cut-and-paste the _function name_ as the _first_ argument to the macro, and leave what's left as the _second_ argument (in case you're curious, this is the _type of the function_). 1. Repeat until all virtual functions you want to mock are done. After the process, you should have something like: ``` #include "gmock/gmock.h" // Brings in Google Mock. class MockTurtle : public Turtle { public: ... MOCK_METHOD0(PenUp, void()); MOCK_METHOD0(PenDown, void()); MOCK_METHOD1(Forward, void(int distance)); MOCK_METHOD1(Turn, void(int degrees)); MOCK_METHOD2(GoTo, void(int x, int y)); MOCK_CONST_METHOD0(GetX, int()); MOCK_CONST_METHOD0(GetY, int()); }; ``` You don't need to define these mock methods somewhere else - the `MOCK_METHOD*` macros will generate the definitions for you. It's that simple! Once you get the hang of it, you can pump out mock classes faster than your source-control system can handle your check-ins. **Tip:** If even this is too much work for you, you'll find the `gmock_gen.py` tool in Google Mock's `scripts/generator/` directory (courtesy of the [cppclean](http://code.google.com/p/cppclean/) project) useful. This command-line tool requires that you have Python 2.4 installed. You give it a C++ file and the name of an abstract class defined in it, and it will print the definition of the mock class for you. Due to the complexity of the C++ language, this script may not always work, but it can be quite handy when it does. For more details, read the [user documentation](http://code.google.com/p/googlemock/source/browse/trunk/scripts/generator/README). ## Where to Put It ## When you define a mock class, you need to decide where to put its definition. Some people put it in a `*_test.cc`. This is fine when the interface being mocked (say, `Foo`) is owned by the same person or team. Otherwise, when the owner of `Foo` changes it, your test could break. (You can't really expect `Foo`'s maintainer to fix every test that uses `Foo`, can you?) So, the rule of thumb is: if you need to mock `Foo` and it's owned by others, define the mock class in `Foo`'s package (better, in a `testing` sub-package such that you can clearly separate production code and testing utilities), and put it in a `mock_foo.h`. Then everyone can reference `mock_foo.h` from their tests. If `Foo` ever changes, there is only one copy of `MockFoo` to change, and only tests that depend on the changed methods need to be fixed. Another way to do it: you can introduce a thin layer `FooAdaptor` on top of `Foo` and code to this new interface. Since you own `FooAdaptor`, you can absorb changes in `Foo` much more easily. While this is more work initially, carefully choosing the adaptor interface can make your code easier to write and more readable (a net win in the long run), as you can choose `FooAdaptor` to fit your specific domain much better than `Foo` does. # Using Mocks in Tests # Once you have a mock class, using it is easy. The typical work flow is: 1. Import the Google Mock names from the `testing` namespace such that you can use them unqualified (You only have to do it once per file. Remember that namespaces are a good idea and good for your health.). 1. Create some mock objects. 1. Specify your expectations on them (How many times will a method be called? With what arguments? What should it do? etc.). 1. Exercise some code that uses the mocks; optionally, check the result using Google Test assertions. If a mock method is called more than expected or with wrong arguments, you'll get an error immediately. 1. When a mock is destructed, Google Mock will automatically check whether all expectations on it have been satisfied. Here's an example: ``` #include "path/to/mock-turtle.h" #include "gmock/gmock.h" #include "gtest/gtest.h" using ::testing::AtLeast; // #1 TEST(PainterTest, CanDrawSomething) { MockTurtle turtle; // #2 EXPECT_CALL(turtle, PenDown()) // #3 .Times(AtLeast(1)); Painter painter(&turtle); // #4 EXPECT_TRUE(painter.DrawCircle(0, 0, 10)); } // #5 int main(int argc, char** argv) { // The following line must be executed to initialize Google Mock // (and Google Test) before running the tests. ::testing::InitGoogleMock(&argc, argv); return RUN_ALL_TESTS(); } ``` As you might have guessed, this test checks that `PenDown()` is called at least once. If the `painter` object didn't call this method, your test will fail with a message like this: ``` path/to/my_test.cc:119: Failure Actual function call count doesn't match this expectation: Actually: never called; Expected: called at least once. ``` **Tip 1:** If you run the test from an Emacs buffer, you can hit `` on the line number displayed in the error message to jump right to the failed expectation. **Tip 2:** If your mock objects are never deleted, the final verification won't happen. Therefore it's a good idea to use a heap leak checker in your tests when you allocate mocks on the heap. **Important note:** Google Mock requires expectations to be set **before** the mock functions are called, otherwise the behavior is **undefined**. In particular, you mustn't interleave `EXPECT_CALL()`s and calls to the mock functions. This means `EXPECT_CALL()` should be read as expecting that a call will occur _in the future_, not that a call has occurred. Why does Google Mock work like that? Well, specifying the expectation beforehand allows Google Mock to report a violation as soon as it arises, when the context (stack trace, etc) is still available. This makes debugging much easier. Admittedly, this test is contrived and doesn't do much. You can easily achieve the same effect without using Google Mock. However, as we shall reveal soon, Google Mock allows you to do _much more_ with the mocks. ## Using Google Mock with Any Testing Framework ## If you want to use something other than Google Test (e.g. [CppUnit](http://apps.sourceforge.net/mediawiki/cppunit/index.php?title=Main_Page) or [CxxTest](http://cxxtest.tigris.org/)) as your testing framework, just change the `main()` function in the previous section to: ``` int main(int argc, char** argv) { // The following line causes Google Mock to throw an exception on failure, // which will be interpreted by your testing framework as a test failure. ::testing::GTEST_FLAG(throw_on_failure) = true; ::testing::InitGoogleMock(&argc, argv); ... whatever your testing framework requires ... } ``` This approach has a catch: it makes Google Mock throw an exception from a mock object's destructor sometimes. With some compilers, this sometimes causes the test program to crash. You'll still be able to notice that the test has failed, but it's not a graceful failure. A better solution is to use Google Test's [event listener API](http://code.google.com/p/googletest/wiki/V1_6_AdvancedGuide#Extending_Google_Test_by_Handling_Test_Events) to report a test failure to your testing framework properly. You'll need to implement the `OnTestPartResult()` method of the event listener interface, but it should be straightforward. If this turns out to be too much work, we suggest that you stick with Google Test, which works with Google Mock seamlessly (in fact, it is technically part of Google Mock.). If there is a reason that you cannot use Google Test, please let us know. # Setting Expectations # The key to using a mock object successfully is to set the _right expectations_ on it. If you set the expectations too strict, your test will fail as the result of unrelated changes. If you set them too loose, bugs can slip through. You want to do it just right such that your test can catch exactly the kind of bugs you intend it to catch. Google Mock provides the necessary means for you to do it "just right." ## General Syntax ## In Google Mock we use the `EXPECT_CALL()` macro to set an expectation on a mock method. The general syntax is: ``` EXPECT_CALL(mock_object, method(matchers)) .Times(cardinality) .WillOnce(action) .WillRepeatedly(action); ``` The macro has two arguments: first the mock object, and then the method and its arguments. Note that the two are separated by a comma (`,`), not a period (`.`). (Why using a comma? The answer is that it was necessary for technical reasons.) The macro can be followed by some optional _clauses_ that provide more information about the expectation. We'll discuss how each clause works in the coming sections. This syntax is designed to make an expectation read like English. For example, you can probably guess that ``` using ::testing::Return;... EXPECT_CALL(turtle, GetX()) .Times(5) .WillOnce(Return(100)) .WillOnce(Return(150)) .WillRepeatedly(Return(200)); ``` says that the `turtle` object's `GetX()` method will be called five times, it will return 100 the first time, 150 the second time, and then 200 every time. Some people like to call this style of syntax a Domain-Specific Language (DSL). **Note:** Why do we use a macro to do this? It serves two purposes: first it makes expectations easily identifiable (either by `grep` or by a human reader), and second it allows Google Mock to include the source file location of a failed expectation in messages, making debugging easier. ## Matchers: What Arguments Do We Expect? ## When a mock function takes arguments, we must specify what arguments we are expecting; for example: ``` // Expects the turtle to move forward by 100 units. EXPECT_CALL(turtle, Forward(100)); ``` Sometimes you may not want to be too specific (Remember that talk about tests being too rigid? Over specification leads to brittle tests and obscures the intent of tests. Therefore we encourage you to specify only what's necessary - no more, no less.). If you care to check that `Forward()` will be called but aren't interested in its actual argument, write `_` as the argument, which means "anything goes": ``` using ::testing::_; ... // Expects the turtle to move forward. EXPECT_CALL(turtle, Forward(_)); ``` `_` is an instance of what we call **matchers**. A matcher is like a predicate and can test whether an argument is what we'd expect. You can use a matcher inside `EXPECT_CALL()` wherever a function argument is expected. A list of built-in matchers can be found in the [CheatSheet](V1_6_CheatSheet.md). For example, here's the `Ge` (greater than or equal) matcher: ``` using ::testing::Ge;... EXPECT_CALL(turtle, Forward(Ge(100))); ``` This checks that the turtle will be told to go forward by at least 100 units. ## Cardinalities: How Many Times Will It Be Called? ## The first clause we can specify following an `EXPECT_CALL()` is `Times()`. We call its argument a **cardinality** as it tells _how many times_ the call should occur. It allows us to repeat an expectation many times without actually writing it as many times. More importantly, a cardinality can be "fuzzy", just like a matcher can be. This allows a user to express the intent of a test exactly. An interesting special case is when we say `Times(0)`. You may have guessed - it means that the function shouldn't be called with the given arguments at all, and Google Mock will report a Google Test failure whenever the function is (wrongfully) called. We've seen `AtLeast(n)` as an example of fuzzy cardinalities earlier. For the list of built-in cardinalities you can use, see the [CheatSheet](V1_6_CheatSheet.md). The `Times()` clause can be omitted. **If you omit `Times()`, Google Mock will infer the cardinality for you.** The rules are easy to remember: * If **neither** `WillOnce()` **nor** `WillRepeatedly()` is in the `EXPECT_CALL()`, the inferred cardinality is `Times(1)`. * If there are `n WillOnce()`'s but **no** `WillRepeatedly()`, where `n` >= 1, the cardinality is `Times(n)`. * If there are `n WillOnce()`'s and **one** `WillRepeatedly()`, where `n` >= 0, the cardinality is `Times(AtLeast(n))`. **Quick quiz:** what do you think will happen if a function is expected to be called twice but actually called four times? ## Actions: What Should It Do? ## Remember that a mock object doesn't really have a working implementation? We as users have to tell it what to do when a method is invoked. This is easy in Google Mock. First, if the return type of a mock function is a built-in type or a pointer, the function has a **default action** (a `void` function will just return, a `bool` function will return `false`, and other functions will return 0). If you don't say anything, this behavior will be used. Second, if a mock function doesn't have a default action, or the default action doesn't suit you, you can specify the action to be taken each time the expectation matches using a series of `WillOnce()` clauses followed by an optional `WillRepeatedly()`. For example, ``` using ::testing::Return;... EXPECT_CALL(turtle, GetX()) .WillOnce(Return(100)) .WillOnce(Return(200)) .WillOnce(Return(300)); ``` This says that `turtle.GetX()` will be called _exactly three times_ (Google Mock inferred this from how many `WillOnce()` clauses we've written, since we didn't explicitly write `Times()`), and will return 100, 200, and 300 respectively. ``` using ::testing::Return;... EXPECT_CALL(turtle, GetY()) .WillOnce(Return(100)) .WillOnce(Return(200)) .WillRepeatedly(Return(300)); ``` says that `turtle.GetY()` will be called _at least twice_ (Google Mock knows this as we've written two `WillOnce()` clauses and a `WillRepeatedly()` while having no explicit `Times()`), will return 100 the first time, 200 the second time, and 300 from the third time on. Of course, if you explicitly write a `Times()`, Google Mock will not try to infer the cardinality itself. What if the number you specified is larger than there are `WillOnce()` clauses? Well, after all `WillOnce()`s are used up, Google Mock will do the _default_ action for the function every time (unless, of course, you have a `WillRepeatedly()`.). What can we do inside `WillOnce()` besides `Return()`? You can return a reference using `ReturnRef(variable)`, or invoke a pre-defined function, among [others](http://code.google.com/p/googlemock/wiki/V1_6_CheatSheet#Actions). **Important note:** The `EXPECT_CALL()` statement evaluates the action clause only once, even though the action may be performed many times. Therefore you must be careful about side effects. The following may not do what you want: ``` int n = 100; EXPECT_CALL(turtle, GetX()) .Times(4) .WillRepeatedly(Return(n++)); ``` Instead of returning 100, 101, 102, ..., consecutively, this mock function will always return 100 as `n++` is only evaluated once. Similarly, `Return(new Foo)` will create a new `Foo` object when the `EXPECT_CALL()` is executed, and will return the same pointer every time. If you want the side effect to happen every time, you need to define a custom action, which we'll teach in the [CookBook](V1_6_CookBook.md). Time for another quiz! What do you think the following means? ``` using ::testing::Return;... EXPECT_CALL(turtle, GetY()) .Times(4) .WillOnce(Return(100)); ``` Obviously `turtle.GetY()` is expected to be called four times. But if you think it will return 100 every time, think twice! Remember that one `WillOnce()` clause will be consumed each time the function is invoked and the default action will be taken afterwards. So the right answer is that `turtle.GetY()` will return 100 the first time, but **return 0 from the second time on**, as returning 0 is the default action for `int` functions. ## Using Multiple Expectations ## So far we've only shown examples where you have a single expectation. More realistically, you're going to specify expectations on multiple mock methods, which may be from multiple mock objects. By default, when a mock method is invoked, Google Mock will search the expectations in the **reverse order** they are defined, and stop when an active expectation that matches the arguments is found (you can think of it as "newer rules override older ones."). If the matching expectation cannot take any more calls, you will get an upper-bound-violated failure. Here's an example: ``` using ::testing::_;... EXPECT_CALL(turtle, Forward(_)); // #1 EXPECT_CALL(turtle, Forward(10)) // #2 .Times(2); ``` If `Forward(10)` is called three times in a row, the third time it will be an error, as the last matching expectation (#2) has been saturated. If, however, the third `Forward(10)` call is replaced by `Forward(20)`, then it would be OK, as now #1 will be the matching expectation. **Side note:** Why does Google Mock search for a match in the _reverse_ order of the expectations? The reason is that this allows a user to set up the default expectations in a mock object's constructor or the test fixture's set-up phase and then customize the mock by writing more specific expectations in the test body. So, if you have two expectations on the same method, you want to put the one with more specific matchers **after** the other, or the more specific rule would be shadowed by the more general one that comes after it. ## Ordered vs Unordered Calls ## By default, an expectation can match a call even though an earlier expectation hasn't been satisfied. In other words, the calls don't have to occur in the order the expectations are specified. Sometimes, you may want all the expected calls to occur in a strict order. To say this in Google Mock is easy: ``` using ::testing::InSequence;... TEST(FooTest, DrawsLineSegment) { ... { InSequence dummy; EXPECT_CALL(turtle, PenDown()); EXPECT_CALL(turtle, Forward(100)); EXPECT_CALL(turtle, PenUp()); } Foo(); } ``` By creating an object of type `InSequence`, all expectations in its scope are put into a _sequence_ and have to occur _sequentially_. Since we are just relying on the constructor and destructor of this object to do the actual work, its name is really irrelevant. In this example, we test that `Foo()` calls the three expected functions in the order as written. If a call is made out-of-order, it will be an error. (What if you care about the relative order of some of the calls, but not all of them? Can you specify an arbitrary partial order? The answer is ... yes! If you are impatient, the details can be found in the [CookBook](V1_6_CookBook.md).) ## All Expectations Are Sticky (Unless Said Otherwise) ## Now let's do a quick quiz to see how well you can use this mock stuff already. How would you test that the turtle is asked to go to the origin _exactly twice_ (you want to ignore any other instructions it receives)? After you've come up with your answer, take a look at ours and compare notes (solve it yourself first - don't cheat!): ``` using ::testing::_;... EXPECT_CALL(turtle, GoTo(_, _)) // #1 .Times(AnyNumber()); EXPECT_CALL(turtle, GoTo(0, 0)) // #2 .Times(2); ``` Suppose `turtle.GoTo(0, 0)` is called three times. In the third time, Google Mock will see that the arguments match expectation #2 (remember that we always pick the last matching expectation). Now, since we said that there should be only two such calls, Google Mock will report an error immediately. This is basically what we've told you in the "Using Multiple Expectations" section above. This example shows that **expectations in Google Mock are "sticky" by default**, in the sense that they remain active even after we have reached their invocation upper bounds. This is an important rule to remember, as it affects the meaning of the spec, and is **different** to how it's done in many other mocking frameworks (Why'd we do that? Because we think our rule makes the common cases easier to express and understand.). Simple? Let's see if you've really understood it: what does the following code say? ``` using ::testing::Return; ... for (int i = n; i > 0; i--) { EXPECT_CALL(turtle, GetX()) .WillOnce(Return(10*i)); } ``` If you think it says that `turtle.GetX()` will be called `n` times and will return 10, 20, 30, ..., consecutively, think twice! The problem is that, as we said, expectations are sticky. So, the second time `turtle.GetX()` is called, the last (latest) `EXPECT_CALL()` statement will match, and will immediately lead to an "upper bound exceeded" error - this piece of code is not very useful! One correct way of saying that `turtle.GetX()` will return 10, 20, 30, ..., is to explicitly say that the expectations are _not_ sticky. In other words, they should _retire_ as soon as they are saturated: ``` using ::testing::Return; ... for (int i = n; i > 0; i--) { EXPECT_CALL(turtle, GetX()) .WillOnce(Return(10*i)) .RetiresOnSaturation(); } ``` And, there's a better way to do it: in this case, we expect the calls to occur in a specific order, and we line up the actions to match the order. Since the order is important here, we should make it explicit using a sequence: ``` using ::testing::InSequence; using ::testing::Return; ... { InSequence s; for (int i = 1; i <= n; i++) { EXPECT_CALL(turtle, GetX()) .WillOnce(Return(10*i)) .RetiresOnSaturation(); } } ``` By the way, the other situation where an expectation may _not_ be sticky is when it's in a sequence - as soon as another expectation that comes after it in the sequence has been used, it automatically retires (and will never be used to match any call). ## Uninteresting Calls ## A mock object may have many methods, and not all of them are that interesting. For example, in some tests we may not care about how many times `GetX()` and `GetY()` get called. In Google Mock, if you are not interested in a method, just don't say anything about it. If a call to this method occurs, you'll see a warning in the test output, but it won't be a failure. # What Now? # Congratulations! You've learned enough about Google Mock to start using it. Now, you might want to join the [googlemock](http://groups.google.com/group/googlemock) discussion group and actually write some tests using Google Mock - it will be fun. Hey, it may even be addictive - you've been warned. Then, if you feel like increasing your mock quotient, you should move on to the [CookBook](V1_6_CookBook.md). You can learn many advanced features of Google Mock there -- and advance your level of enjoyment and testing bliss.nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/docs/v1_6/FrequentlyAskedQuestions.md000066400000000000000000000563041455373415500317160ustar00rootroot00000000000000 Please send your questions to the [googlemock](http://groups.google.com/group/googlemock) discussion group. If you need help with compiler errors, make sure you have tried [Google Mock Doctor](#How_am_I_supposed_to_make_sense_of_these_horrible_template_error.md) first. ## When I call a method on my mock object, the method for the real object is invoked instead. What's the problem? ## In order for a method to be mocked, it must be _virtual_, unless you use the [high-perf dependency injection technique](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Mocking_Nonvirtual_Methods). ## I wrote some matchers. After I upgraded to a new version of Google Mock, they no longer compile. What's going on? ## After version 1.4.0 of Google Mock was released, we had an idea on how to make it easier to write matchers that can generate informative messages efficiently. We experimented with this idea and liked what we saw. Therefore we decided to implement it. Unfortunately, this means that if you have defined your own matchers by implementing `MatcherInterface` or using `MakePolymorphicMatcher()`, your definitions will no longer compile. Matchers defined using the `MATCHER*` family of macros are not affected. Sorry for the hassle if your matchers are affected. We believe it's in everyone's long-term interest to make this change sooner than later. Fortunately, it's usually not hard to migrate an existing matcher to the new API. Here's what you need to do: If you wrote your matcher like this: ``` // Old matcher definition that doesn't work with the latest // Google Mock. using ::testing::MatcherInterface; ... class MyWonderfulMatcher : public MatcherInterface { public: ... virtual bool Matches(MyType value) const { // Returns true if value matches. return value.GetFoo() > 5; } ... }; ``` you'll need to change it to: ``` // New matcher definition that works with the latest Google Mock. using ::testing::MatcherInterface; using ::testing::MatchResultListener; ... class MyWonderfulMatcher : public MatcherInterface { public: ... virtual bool MatchAndExplain(MyType value, MatchResultListener* listener) const { // Returns true if value matches. return value.GetFoo() > 5; } ... }; ``` (i.e. rename `Matches()` to `MatchAndExplain()` and give it a second argument of type `MatchResultListener*`.) If you were also using `ExplainMatchResultTo()` to improve the matcher message: ``` // Old matcher definition that doesn't work with the lastest // Google Mock. using ::testing::MatcherInterface; ... class MyWonderfulMatcher : public MatcherInterface { public: ... virtual bool Matches(MyType value) const { // Returns true if value matches. return value.GetFoo() > 5; } virtual void ExplainMatchResultTo(MyType value, ::std::ostream* os) const { // Prints some helpful information to os to help // a user understand why value matches (or doesn't match). *os << "the Foo property is " << value.GetFoo(); } ... }; ``` you should move the logic of `ExplainMatchResultTo()` into `MatchAndExplain()`, using the `MatchResultListener` argument where the `::std::ostream` was used: ``` // New matcher definition that works with the latest Google Mock. using ::testing::MatcherInterface; using ::testing::MatchResultListener; ... class MyWonderfulMatcher : public MatcherInterface { public: ... virtual bool MatchAndExplain(MyType value, MatchResultListener* listener) const { // Returns true if value matches. *listener << "the Foo property is " << value.GetFoo(); return value.GetFoo() > 5; } ... }; ``` If your matcher is defined using `MakePolymorphicMatcher()`: ``` // Old matcher definition that doesn't work with the latest // Google Mock. using ::testing::MakePolymorphicMatcher; ... class MyGreatMatcher { public: ... bool Matches(MyType value) const { // Returns true if value matches. return value.GetBar() < 42; } ... }; ... MakePolymorphicMatcher(MyGreatMatcher()) ... ``` you should rename the `Matches()` method to `MatchAndExplain()` and add a `MatchResultListener*` argument (the same as what you need to do for matchers defined by implementing `MatcherInterface`): ``` // New matcher definition that works with the latest Google Mock. using ::testing::MakePolymorphicMatcher; using ::testing::MatchResultListener; ... class MyGreatMatcher { public: ... bool MatchAndExplain(MyType value, MatchResultListener* listener) const { // Returns true if value matches. return value.GetBar() < 42; } ... }; ... MakePolymorphicMatcher(MyGreatMatcher()) ... ``` If your polymorphic matcher uses `ExplainMatchResultTo()` for better failure messages: ``` // Old matcher definition that doesn't work with the latest // Google Mock. using ::testing::MakePolymorphicMatcher; ... class MyGreatMatcher { public: ... bool Matches(MyType value) const { // Returns true if value matches. return value.GetBar() < 42; } ... }; void ExplainMatchResultTo(const MyGreatMatcher& matcher, MyType value, ::std::ostream* os) { // Prints some helpful information to os to help // a user understand why value matches (or doesn't match). *os << "the Bar property is " << value.GetBar(); } ... MakePolymorphicMatcher(MyGreatMatcher()) ... ``` you'll need to move the logic inside `ExplainMatchResultTo()` to `MatchAndExplain()`: ``` // New matcher definition that works with the latest Google Mock. using ::testing::MakePolymorphicMatcher; using ::testing::MatchResultListener; ... class MyGreatMatcher { public: ... bool MatchAndExplain(MyType value, MatchResultListener* listener) const { // Returns true if value matches. *listener << "the Bar property is " << value.GetBar(); return value.GetBar() < 42; } ... }; ... MakePolymorphicMatcher(MyGreatMatcher()) ... ``` For more information, you can read these [two](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Writing_New_Monomorphic_Matchers) [recipes](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Writing_New_Polymorphic_Matchers) from the cookbook. As always, you are welcome to post questions on `googlemock@googlegroups.com` if you need any help. ## When using Google Mock, do I have to use Google Test as the testing framework? I have my favorite testing framework and don't want to switch. ## Google Mock works out of the box with Google Test. However, it's easy to configure it to work with any testing framework of your choice. [Here](http://code.google.com/p/googlemock/wiki/V1_6_ForDummies#Using_Google_Mock_with_Any_Testing_Framework) is how. ## How am I supposed to make sense of these horrible template errors? ## If you are confused by the compiler errors gcc threw at you, try consulting the _Google Mock Doctor_ tool first. What it does is to scan stdin for gcc error messages, and spit out diagnoses on the problems (we call them diseases) your code has. To "install", run command: ``` alias gmd='/scripts/gmock_doctor.py' ``` To use it, do: ``` 2>&1 | gmd ``` For example: ``` make my_test 2>&1 | gmd ``` Or you can run `gmd` and copy-n-paste gcc's error messages to it. ## Can I mock a variadic function? ## You cannot mock a variadic function (i.e. a function taking ellipsis (`...`) arguments) directly in Google Mock. The problem is that in general, there is _no way_ for a mock object to know how many arguments are passed to the variadic method, and what the arguments' types are. Only the _author of the base class_ knows the protocol, and we cannot look into his head. Therefore, to mock such a function, the _user_ must teach the mock object how to figure out the number of arguments and their types. One way to do it is to provide overloaded versions of the function. Ellipsis arguments are inherited from C and not really a C++ feature. They are unsafe to use and don't work with arguments that have constructors or destructors. Therefore we recommend to avoid them in C++ as much as possible. ## MSVC gives me warning C4301 or C4373 when I define a mock method with a const parameter. Why? ## If you compile this using Microsoft Visual C++ 2005 SP1: ``` class Foo { ... virtual void Bar(const int i) = 0; }; class MockFoo : public Foo { ... MOCK_METHOD1(Bar, void(const int i)); }; ``` You may get the following warning: ``` warning C4301: 'MockFoo::Bar': overriding virtual function only differs from 'Foo::Bar' by const/volatile qualifier ``` This is a MSVC bug. The same code compiles fine with gcc ,for example. If you use Visual C++ 2008 SP1, you would get the warning: ``` warning C4373: 'MockFoo::Bar': virtual function overrides 'Foo::Bar', previous versions of the compiler did not override when parameters only differed by const/volatile qualifiers ``` In C++, if you _declare_ a function with a `const` parameter, the `const` modifier is _ignored_. Therefore, the `Foo` base class above is equivalent to: ``` class Foo { ... virtual void Bar(int i) = 0; // int or const int? Makes no difference. }; ``` In fact, you can _declare_ Bar() with an `int` parameter, and _define_ it with a `const int` parameter. The compiler will still match them up. Since making a parameter `const` is meaningless in the method _declaration_, we recommend to remove it in both `Foo` and `MockFoo`. That should workaround the VC bug. Note that we are talking about the _top-level_ `const` modifier here. If the function parameter is passed by pointer or reference, declaring the _pointee_ or _referee_ as `const` is still meaningful. For example, the following two declarations are _not_ equivalent: ``` void Bar(int* p); // Neither p nor *p is const. void Bar(const int* p); // p is not const, but *p is. ``` ## I have a huge mock class, and Microsoft Visual C++ runs out of memory when compiling it. What can I do? ## We've noticed that when the `/clr` compiler flag is used, Visual C++ uses 5~6 times as much memory when compiling a mock class. We suggest to avoid `/clr` when compiling native C++ mocks. ## I can't figure out why Google Mock thinks my expectations are not satisfied. What should I do? ## You might want to run your test with `--gmock_verbose=info`. This flag lets Google Mock print a trace of every mock function call it receives. By studying the trace, you'll gain insights on why the expectations you set are not met. ## How can I assert that a function is NEVER called? ## ``` EXPECT_CALL(foo, Bar(_)) .Times(0); ``` ## I have a failed test where Google Mock tells me TWICE that a particular expectation is not satisfied. Isn't this redundant? ## When Google Mock detects a failure, it prints relevant information (the mock function arguments, the state of relevant expectations, and etc) to help the user debug. If another failure is detected, Google Mock will do the same, including printing the state of relevant expectations. Sometimes an expectation's state didn't change between two failures, and you'll see the same description of the state twice. They are however _not_ redundant, as they refer to _different points in time_. The fact they are the same _is_ interesting information. ## I get a heap check failure when using a mock object, but using a real object is fine. What can be wrong? ## Does the class (hopefully a pure interface) you are mocking have a virtual destructor? Whenever you derive from a base class, make sure its destructor is virtual. Otherwise Bad Things will happen. Consider the following code: ``` class Base { public: // Not virtual, but should be. ~Base() { ... } ... }; class Derived : public Base { public: ... private: std::string value_; }; ... Base* p = new Derived; ... delete p; // Surprise! ~Base() will be called, but ~Derived() will not // - value_ is leaked. ``` By changing `~Base()` to virtual, `~Derived()` will be correctly called when `delete p` is executed, and the heap checker will be happy. ## The "newer expectations override older ones" rule makes writing expectations awkward. Why does Google Mock do that? ## When people complain about this, often they are referring to code like: ``` // foo.Bar() should be called twice, return 1 the first time, and return // 2 the second time. However, I have to write the expectations in the // reverse order. This sucks big time!!! EXPECT_CALL(foo, Bar()) .WillOnce(Return(2)) .RetiresOnSaturation(); EXPECT_CALL(foo, Bar()) .WillOnce(Return(1)) .RetiresOnSaturation(); ``` The problem is that they didn't pick the **best** way to express the test's intent. By default, expectations don't have to be matched in _any_ particular order. If you want them to match in a certain order, you need to be explicit. This is Google Mock's (and jMock's) fundamental philosophy: it's easy to accidentally over-specify your tests, and we want to make it harder to do so. There are two better ways to write the test spec. You could either put the expectations in sequence: ``` // foo.Bar() should be called twice, return 1 the first time, and return // 2 the second time. Using a sequence, we can write the expectations // in their natural order. { InSequence s; EXPECT_CALL(foo, Bar()) .WillOnce(Return(1)) .RetiresOnSaturation(); EXPECT_CALL(foo, Bar()) .WillOnce(Return(2)) .RetiresOnSaturation(); } ``` or you can put the sequence of actions in the same expectation: ``` // foo.Bar() should be called twice, return 1 the first time, and return // 2 the second time. EXPECT_CALL(foo, Bar()) .WillOnce(Return(1)) .WillOnce(Return(2)) .RetiresOnSaturation(); ``` Back to the original questions: why does Google Mock search the expectations (and `ON_CALL`s) from back to front? Because this allows a user to set up a mock's behavior for the common case early (e.g. in the mock's constructor or the test fixture's set-up phase) and customize it with more specific rules later. If Google Mock searches from front to back, this very useful pattern won't be possible. ## Google Mock prints a warning when a function without EXPECT\_CALL is called, even if I have set its behavior using ON\_CALL. Would it be reasonable not to show the warning in this case? ## When choosing between being neat and being safe, we lean toward the latter. So the answer is that we think it's better to show the warning. Often people write `ON_CALL`s in the mock object's constructor or `SetUp()`, as the default behavior rarely changes from test to test. Then in the test body they set the expectations, which are often different for each test. Having an `ON_CALL` in the set-up part of a test doesn't mean that the calls are expected. If there's no `EXPECT_CALL` and the method is called, it's possibly an error. If we quietly let the call go through without notifying the user, bugs may creep in unnoticed. If, however, you are sure that the calls are OK, you can write ``` EXPECT_CALL(foo, Bar(_)) .WillRepeatedly(...); ``` instead of ``` ON_CALL(foo, Bar(_)) .WillByDefault(...); ``` This tells Google Mock that you do expect the calls and no warning should be printed. Also, you can control the verbosity using the `--gmock_verbose` flag. If you find the output too noisy when debugging, just choose a less verbose level. ## How can I delete the mock function's argument in an action? ## If you find yourself needing to perform some action that's not supported by Google Mock directly, remember that you can define your own actions using [MakeAction()](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Writing_New_Actions) or [MakePolymorphicAction()](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Writing_New_Polymorphic_Actions), or you can write a stub function and invoke it using [Invoke()](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Using_Functions_Methods_Functors). ## MOCK\_METHODn()'s second argument looks funny. Why don't you use the MOCK\_METHODn(Method, return\_type, arg\_1, ..., arg\_n) syntax? ## What?! I think it's beautiful. :-) While which syntax looks more natural is a subjective matter to some extent, Google Mock's syntax was chosen for several practical advantages it has. Try to mock a function that takes a map as an argument: ``` virtual int GetSize(const map& m); ``` Using the proposed syntax, it would be: ``` MOCK_METHOD1(GetSize, int, const map& m); ``` Guess what? You'll get a compiler error as the compiler thinks that `const map& m` are **two**, not one, arguments. To work around this you can use `typedef` to give the map type a name, but that gets in the way of your work. Google Mock's syntax avoids this problem as the function's argument types are protected inside a pair of parentheses: ``` // This compiles fine. MOCK_METHOD1(GetSize, int(const map& m)); ``` You still need a `typedef` if the return type contains an unprotected comma, but that's much rarer. Other advantages include: 1. `MOCK_METHOD1(Foo, int, bool)` can leave a reader wonder whether the method returns `int` or `bool`, while there won't be such confusion using Google Mock's syntax. 1. The way Google Mock describes a function type is nothing new, although many people may not be familiar with it. The same syntax was used in C, and the `function` library in `tr1` uses this syntax extensively. Since `tr1` will become a part of the new version of STL, we feel very comfortable to be consistent with it. 1. The function type syntax is also used in other parts of Google Mock's API (e.g. the action interface) in order to make the implementation tractable. A user needs to learn it anyway in order to utilize Google Mock's more advanced features. We'd as well stick to the same syntax in `MOCK_METHOD*`! ## My code calls a static/global function. Can I mock it? ## You can, but you need to make some changes. In general, if you find yourself needing to mock a static function, it's a sign that your modules are too tightly coupled (and less flexible, less reusable, less testable, etc). You are probably better off defining a small interface and call the function through that interface, which then can be easily mocked. It's a bit of work initially, but usually pays for itself quickly. This Google Testing Blog [post](http://googletesting.blogspot.com/2008/06/defeat-static-cling.html) says it excellently. Check it out. ## My mock object needs to do complex stuff. It's a lot of pain to specify the actions. Google Mock sucks! ## I know it's not a question, but you get an answer for free any way. :-) With Google Mock, you can create mocks in C++ easily. And people might be tempted to use them everywhere. Sometimes they work great, and sometimes you may find them, well, a pain to use. So, what's wrong in the latter case? When you write a test without using mocks, you exercise the code and assert that it returns the correct value or that the system is in an expected state. This is sometimes called "state-based testing". Mocks are great for what some call "interaction-based" testing: instead of checking the system state at the very end, mock objects verify that they are invoked the right way and report an error as soon as it arises, giving you a handle on the precise context in which the error was triggered. This is often more effective and economical to do than state-based testing. If you are doing state-based testing and using a test double just to simulate the real object, you are probably better off using a fake. Using a mock in this case causes pain, as it's not a strong point for mocks to perform complex actions. If you experience this and think that mocks suck, you are just not using the right tool for your problem. Or, you might be trying to solve the wrong problem. :-) ## I got a warning "Uninteresting function call encountered - default action taken.." Should I panic? ## By all means, NO! It's just an FYI. What it means is that you have a mock function, you haven't set any expectations on it (by Google Mock's rule this means that you are not interested in calls to this function and therefore it can be called any number of times), and it is called. That's OK - you didn't say it's not OK to call the function! What if you actually meant to disallow this function to be called, but forgot to write `EXPECT_CALL(foo, Bar()).Times(0)`? While one can argue that it's the user's fault, Google Mock tries to be nice and prints you a note. So, when you see the message and believe that there shouldn't be any uninteresting calls, you should investigate what's going on. To make your life easier, Google Mock prints the function name and arguments when an uninteresting call is encountered. ## I want to define a custom action. Should I use Invoke() or implement the action interface? ## Either way is fine - you want to choose the one that's more convenient for your circumstance. Usually, if your action is for a particular function type, defining it using `Invoke()` should be easier; if your action can be used in functions of different types (e.g. if you are defining `Return(value)`), `MakePolymorphicAction()` is easiest. Sometimes you want precise control on what types of functions the action can be used in, and implementing `ActionInterface` is the way to go here. See the implementation of `Return()` in `include/gmock/gmock-actions.h` for an example. ## I'm using the set-argument-pointee action, and the compiler complains about "conflicting return type specified". What does it mean? ## You got this error as Google Mock has no idea what value it should return when the mock method is called. `SetArgPointee()` says what the side effect is, but doesn't say what the return value should be. You need `DoAll()` to chain a `SetArgPointee()` with a `Return()`. See this [recipe](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Mocking_Side_Effects) for more details and an example. ## My question is not in your FAQ! ## If you cannot find the answer to your question in this FAQ, there are some other resources you can use: 1. read other [wiki pages](http://code.google.com/p/googlemock/w/list), 1. search the mailing list [archive](http://groups.google.com/group/googlemock/topics), 1. ask it on [googlemock@googlegroups.com](mailto:googlemock@googlegroups.com) and someone will answer it (to prevent spam, we require you to join the [discussion group](http://groups.google.com/group/googlemock) before you can post.). Please note that creating an issue in the [issue tracker](http://code.google.com/p/googlemock/issues/list) is _not_ a good way to get your answer, as it is monitored infrequently by a very small number of people. When asking a question, it's helpful to provide as much of the following information as possible (people cannot help you if there's not enough information in your question): * the version (or the revision number if you check out from SVN directly) of Google Mock you use (Google Mock is under active development, so it's possible that your problem has been solved in a later version), * your operating system, * the name and version of your compiler, * the complete command line flags you give to your compiler, * the complete compiler error messages (if the question is about compilation), * the _actual_ code (ideally, a minimal but complete program) that has the problem you encounter.nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/docs/v1_7/000077500000000000000000000000001455373415500243445ustar00rootroot00000000000000nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/docs/v1_7/CheatSheet.md000066400000000000000000000665621455373415500267220ustar00rootroot00000000000000 # Defining a Mock Class # ## Mocking a Normal Class ## Given ``` class Foo { ... virtual ~Foo(); virtual int GetSize() const = 0; virtual string Describe(const char* name) = 0; virtual string Describe(int type) = 0; virtual bool Process(Bar elem, int count) = 0; }; ``` (note that `~Foo()` **must** be virtual) we can define its mock as ``` #include "gmock/gmock.h" class MockFoo : public Foo { MOCK_CONST_METHOD0(GetSize, int()); MOCK_METHOD1(Describe, string(const char* name)); MOCK_METHOD1(Describe, string(int type)); MOCK_METHOD2(Process, bool(Bar elem, int count)); }; ``` To create a "nice" mock object which ignores all uninteresting calls, or a "strict" mock object, which treats them as failures: ``` NiceMock nice_foo; // The type is a subclass of MockFoo. StrictMock strict_foo; // The type is a subclass of MockFoo. ``` ## Mocking a Class Template ## To mock ``` template class StackInterface { public: ... virtual ~StackInterface(); virtual int GetSize() const = 0; virtual void Push(const Elem& x) = 0; }; ``` (note that `~StackInterface()` **must** be virtual) just append `_T` to the `MOCK_*` macros: ``` template class MockStack : public StackInterface { public: ... MOCK_CONST_METHOD0_T(GetSize, int()); MOCK_METHOD1_T(Push, void(const Elem& x)); }; ``` ## Specifying Calling Conventions for Mock Functions ## If your mock function doesn't use the default calling convention, you can specify it by appending `_WITH_CALLTYPE` to any of the macros described in the previous two sections and supplying the calling convention as the first argument to the macro. For example, ``` MOCK_METHOD_1_WITH_CALLTYPE(STDMETHODCALLTYPE, Foo, bool(int n)); MOCK_CONST_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, Bar, int(double x, double y)); ``` where `STDMETHODCALLTYPE` is defined by `` on Windows. # Using Mocks in Tests # The typical flow is: 1. Import the Google Mock names you need to use. All Google Mock names are in the `testing` namespace unless they are macros or otherwise noted. 1. Create the mock objects. 1. Optionally, set the default actions of the mock objects. 1. Set your expectations on the mock objects (How will they be called? What wil they do?). 1. Exercise code that uses the mock objects; if necessary, check the result using [Google Test](http://code.google.com/p/googletest/) assertions. 1. When a mock objects is destructed, Google Mock automatically verifies that all expectations on it have been satisfied. Here is an example: ``` using ::testing::Return; // #1 TEST(BarTest, DoesThis) { MockFoo foo; // #2 ON_CALL(foo, GetSize()) // #3 .WillByDefault(Return(1)); // ... other default actions ... EXPECT_CALL(foo, Describe(5)) // #4 .Times(3) .WillRepeatedly(Return("Category 5")); // ... other expectations ... EXPECT_EQ("good", MyProductionFunction(&foo)); // #5 } // #6 ``` # Setting Default Actions # Google Mock has a **built-in default action** for any function that returns `void`, `bool`, a numeric value, or a pointer. To customize the default action for functions with return type `T` globally: ``` using ::testing::DefaultValue; DefaultValue::Set(value); // Sets the default value to be returned. // ... use the mocks ... DefaultValue::Clear(); // Resets the default value. ``` To customize the default action for a particular method, use `ON_CALL()`: ``` ON_CALL(mock_object, method(matchers)) .With(multi_argument_matcher) ? .WillByDefault(action); ``` # Setting Expectations # `EXPECT_CALL()` sets **expectations** on a mock method (How will it be called? What will it do?): ``` EXPECT_CALL(mock_object, method(matchers)) .With(multi_argument_matcher) ? .Times(cardinality) ? .InSequence(sequences) * .After(expectations) * .WillOnce(action) * .WillRepeatedly(action) ? .RetiresOnSaturation(); ? ``` If `Times()` is omitted, the cardinality is assumed to be: * `Times(1)` when there is neither `WillOnce()` nor `WillRepeatedly()`; * `Times(n)` when there are `n WillOnce()`s but no `WillRepeatedly()`, where `n` >= 1; or * `Times(AtLeast(n))` when there are `n WillOnce()`s and a `WillRepeatedly()`, where `n` >= 0. A method with no `EXPECT_CALL()` is free to be invoked _any number of times_, and the default action will be taken each time. # Matchers # A **matcher** matches a _single_ argument. You can use it inside `ON_CALL()` or `EXPECT_CALL()`, or use it to validate a value directly: | `EXPECT_THAT(value, matcher)` | Asserts that `value` matches `matcher`. | |:------------------------------|:----------------------------------------| | `ASSERT_THAT(value, matcher)` | The same as `EXPECT_THAT(value, matcher)`, except that it generates a **fatal** failure. | Built-in matchers (where `argument` is the function argument) are divided into several categories: ## Wildcard ## |`_`|`argument` can be any value of the correct type.| |:--|:-----------------------------------------------| |`A()` or `An()`|`argument` can be any value of type `type`. | ## Generic Comparison ## |`Eq(value)` or `value`|`argument == value`| |:---------------------|:------------------| |`Ge(value)` |`argument >= value`| |`Gt(value)` |`argument > value` | |`Le(value)` |`argument <= value`| |`Lt(value)` |`argument < value` | |`Ne(value)` |`argument != value`| |`IsNull()` |`argument` is a `NULL` pointer (raw or smart).| |`NotNull()` |`argument` is a non-null pointer (raw or smart).| |`Ref(variable)` |`argument` is a reference to `variable`.| |`TypedEq(value)`|`argument` has type `type` and is equal to `value`. You may need to use this instead of `Eq(value)` when the mock function is overloaded.| Except `Ref()`, these matchers make a _copy_ of `value` in case it's modified or destructed later. If the compiler complains that `value` doesn't have a public copy constructor, try wrap it in `ByRef()`, e.g. `Eq(ByRef(non_copyable_value))`. If you do that, make sure `non_copyable_value` is not changed afterwards, or the meaning of your matcher will be changed. ## Floating-Point Matchers ## |`DoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as unequal.| |:-------------------|:----------------------------------------------------------------------------------------------| |`FloatEq(a_float)` |`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as unequal. | |`NanSensitiveDoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as equal. | |`NanSensitiveFloatEq(a_float)`|`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as equal. | The above matchers use ULP-based comparison (the same as used in [Google Test](http://code.google.com/p/googletest/)). They automatically pick a reasonable error bound based on the absolute value of the expected value. `DoubleEq()` and `FloatEq()` conform to the IEEE standard, which requires comparing two NaNs for equality to return false. The `NanSensitive*` version instead treats two NaNs as equal, which is often what a user wants. |`DoubleNear(a_double, max_abs_error)`|`argument` is a `double` value close to `a_double` (absolute error <= `max_abs_error`), treating two NaNs as unequal.| |:------------------------------------|:--------------------------------------------------------------------------------------------------------------------| |`FloatNear(a_float, max_abs_error)` |`argument` is a `float` value close to `a_float` (absolute error <= `max_abs_error`), treating two NaNs as unequal. | |`NanSensitiveDoubleNear(a_double, max_abs_error)`|`argument` is a `double` value close to `a_double` (absolute error <= `max_abs_error`), treating two NaNs as equal. | |`NanSensitiveFloatNear(a_float, max_abs_error)`|`argument` is a `float` value close to `a_float` (absolute error <= `max_abs_error`), treating two NaNs as equal. | ## String Matchers ## The `argument` can be either a C string or a C++ string object: |`ContainsRegex(string)`|`argument` matches the given regular expression.| |:----------------------|:-----------------------------------------------| |`EndsWith(suffix)` |`argument` ends with string `suffix`. | |`HasSubstr(string)` |`argument` contains `string` as a sub-string. | |`MatchesRegex(string)` |`argument` matches the given regular expression with the match starting at the first character and ending at the last character.| |`StartsWith(prefix)` |`argument` starts with string `prefix`. | |`StrCaseEq(string)` |`argument` is equal to `string`, ignoring case. | |`StrCaseNe(string)` |`argument` is not equal to `string`, ignoring case.| |`StrEq(string)` |`argument` is equal to `string`. | |`StrNe(string)` |`argument` is not equal to `string`. | `ContainsRegex()` and `MatchesRegex()` use the regular expression syntax defined [here](http://code.google.com/p/googletest/wiki/AdvancedGuide#Regular_Expression_Syntax). `StrCaseEq()`, `StrCaseNe()`, `StrEq()`, and `StrNe()` work for wide strings as well. ## Container Matchers ## Most STL-style containers support `==`, so you can use `Eq(expected_container)` or simply `expected_container` to match a container exactly. If you want to write the elements in-line, match them more flexibly, or get more informative messages, you can use: | `ContainerEq(container)` | The same as `Eq(container)` except that the failure message also includes which elements are in one container but not the other. | |:-------------------------|:---------------------------------------------------------------------------------------------------------------------------------| | `Contains(e)` | `argument` contains an element that matches `e`, which can be either a value or a matcher. | | `Each(e)` | `argument` is a container where _every_ element matches `e`, which can be either a value or a matcher. | | `ElementsAre(e0, e1, ..., en)` | `argument` has `n + 1` elements, where the i-th element matches `ei`, which can be a value or a matcher. 0 to 10 arguments are allowed. | | `ElementsAreArray({ e0, e1, ..., en })`, `ElementsAreArray(array)`, or `ElementsAreArray(array, count)` | The same as `ElementsAre()` except that the expected element values/matchers come from an initializer list, vector, or C-style array. | | `IsEmpty()` | `argument` is an empty container (`container.empty()`). | | `Pointwise(m, container)` | `argument` contains the same number of elements as in `container`, and for all i, (the i-th element in `argument`, the i-th element in `container`) match `m`, which is a matcher on 2-tuples. E.g. `Pointwise(Le(), upper_bounds)` verifies that each element in `argument` doesn't exceed the corresponding element in `upper_bounds`. See more detail below. | | `SizeIs(m)` | `argument` is a container whose size matches `m`. E.g. `SizeIs(2)` or `SizeIs(Lt(2))`. | | `UnorderedElementsAre(e0, e1, ..., en)` | `argument` has `n + 1` elements, and under some permutation each element matches an `ei` (for a different `i`), which can be a value or a matcher. 0 to 10 arguments are allowed. | | `UnorderedElementsAreArray({ e0, e1, ..., en })`, `UnorderedElementsAreArray(array)`, or `UnorderedElementsAreArray(array, count)` | The same as `UnorderedElementsAre()` except that the expected element values/matchers come from an initializer list, vector, or C-style array. | | `WhenSorted(m)` | When `argument` is sorted using the `<` operator, it matches container matcher `m`. E.g. `WhenSorted(UnorderedElementsAre(1, 2, 3))` verifies that `argument` contains elements `1`, `2`, and `3`, ignoring order. | | `WhenSortedBy(comparator, m)` | The same as `WhenSorted(m)`, except that the given comparator instead of `<` is used to sort `argument`. E.g. `WhenSortedBy(std::greater(), ElementsAre(3, 2, 1))`. | Notes: * These matchers can also match: 1. a native array passed by reference (e.g. in `Foo(const int (&a)[5])`), and 1. an array passed as a pointer and a count (e.g. in `Bar(const T* buffer, int len)` -- see [Multi-argument Matchers](#Multiargument_Matchers.md)). * The array being matched may be multi-dimensional (i.e. its elements can be arrays). * `m` in `Pointwise(m, ...)` should be a matcher for `std::tr1::tuple` where `T` and `U` are the element type of the actual container and the expected container, respectively. For example, to compare two `Foo` containers where `Foo` doesn't support `operator==` but has an `Equals()` method, one might write: ``` using ::std::tr1::get; MATCHER(FooEq, "") { return get<0>(arg).Equals(get<1>(arg)); } ... EXPECT_THAT(actual_foos, Pointwise(FooEq(), expected_foos)); ``` ## Member Matchers ## |`Field(&class::field, m)`|`argument.field` (or `argument->field` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.| |:------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------| |`Key(e)` |`argument.first` matches `e`, which can be either a value or a matcher. E.g. `Contains(Key(Le(5)))` can verify that a `map` contains a key `<= 5`.| |`Pair(m1, m2)` |`argument` is an `std::pair` whose `first` field matches `m1` and `second` field matches `m2`. | |`Property(&class::property, m)`|`argument.property()` (or `argument->property()` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.| ## Matching the Result of a Function or Functor ## |`ResultOf(f, m)`|`f(argument)` matches matcher `m`, where `f` is a function or functor.| |:---------------|:---------------------------------------------------------------------| ## Pointer Matchers ## |`Pointee(m)`|`argument` (either a smart pointer or a raw pointer) points to a value that matches matcher `m`.| |:-----------|:-----------------------------------------------------------------------------------------------| ## Multiargument Matchers ## Technically, all matchers match a _single_ value. A "multi-argument" matcher is just one that matches a _tuple_. The following matchers can be used to match a tuple `(x, y)`: |`Eq()`|`x == y`| |:-----|:-------| |`Ge()`|`x >= y`| |`Gt()`|`x > y` | |`Le()`|`x <= y`| |`Lt()`|`x < y` | |`Ne()`|`x != y`| You can use the following selectors to pick a subset of the arguments (or reorder them) to participate in the matching: |`AllArgs(m)`|Equivalent to `m`. Useful as syntactic sugar in `.With(AllArgs(m))`.| |:-----------|:-------------------------------------------------------------------| |`Args(m)`|The tuple of the `k` selected (using 0-based indices) arguments matches `m`, e.g. `Args<1, 2>(Eq())`.| ## Composite Matchers ## You can make a matcher from one or more other matchers: |`AllOf(m1, m2, ..., mn)`|`argument` matches all of the matchers `m1` to `mn`.| |:-----------------------|:---------------------------------------------------| |`AnyOf(m1, m2, ..., mn)`|`argument` matches at least one of the matchers `m1` to `mn`.| |`Not(m)` |`argument` doesn't match matcher `m`. | ## Adapters for Matchers ## |`MatcherCast(m)`|casts matcher `m` to type `Matcher`.| |:------------------|:--------------------------------------| |`SafeMatcherCast(m)`| [safely casts](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Casting_Matchers) matcher `m` to type `Matcher`. | |`Truly(predicate)` |`predicate(argument)` returns something considered by C++ to be true, where `predicate` is a function or functor.| ## Matchers as Predicates ## |`Matches(m)(value)`|evaluates to `true` if `value` matches `m`. You can use `Matches(m)` alone as a unary functor.| |:------------------|:---------------------------------------------------------------------------------------------| |`ExplainMatchResult(m, value, result_listener)`|evaluates to `true` if `value` matches `m`, explaining the result to `result_listener`. | |`Value(value, m)` |evaluates to `true` if `value` matches `m`. | ## Defining Matchers ## | `MATCHER(IsEven, "") { return (arg % 2) == 0; }` | Defines a matcher `IsEven()` to match an even number. | |:-------------------------------------------------|:------------------------------------------------------| | `MATCHER_P(IsDivisibleBy, n, "") { *result_listener << "where the remainder is " << (arg % n); return (arg % n) == 0; }` | Defines a macher `IsDivisibleBy(n)` to match a number divisible by `n`. | | `MATCHER_P2(IsBetween, a, b, std::string(negation ? "isn't" : "is") + " between " + PrintToString(a) + " and " + PrintToString(b)) { return a <= arg && arg <= b; }` | Defines a matcher `IsBetween(a, b)` to match a value in the range [`a`, `b`]. | **Notes:** 1. The `MATCHER*` macros cannot be used inside a function or class. 1. The matcher body must be _purely functional_ (i.e. it cannot have any side effect, and the result must not depend on anything other than the value being matched and the matcher parameters). 1. You can use `PrintToString(x)` to convert a value `x` of any type to a string. ## Matchers as Test Assertions ## |`ASSERT_THAT(expression, m)`|Generates a [fatal failure](http://code.google.com/p/googletest/wiki/Primer#Assertions) if the value of `expression` doesn't match matcher `m`.| |:---------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------| |`EXPECT_THAT(expression, m)`|Generates a non-fatal failure if the value of `expression` doesn't match matcher `m`. | # Actions # **Actions** specify what a mock function should do when invoked. ## Returning a Value ## |`Return()`|Return from a `void` mock function.| |:---------|:----------------------------------| |`Return(value)`|Return `value`. If the type of `value` is different to the mock function's return type, `value` is converted to the latter type at the time the expectation is set, not when the action is executed.| |`ReturnArg()`|Return the `N`-th (0-based) argument.| |`ReturnNew(a1, ..., ak)`|Return `new T(a1, ..., ak)`; a different object is created each time.| |`ReturnNull()`|Return a null pointer. | |`ReturnPointee(ptr)`|Return the value pointed to by `ptr`.| |`ReturnRef(variable)`|Return a reference to `variable`. | |`ReturnRefOfCopy(value)`|Return a reference to a copy of `value`; the copy lives as long as the action.| ## Side Effects ## |`Assign(&variable, value)`|Assign `value` to variable.| |:-------------------------|:--------------------------| | `DeleteArg()` | Delete the `N`-th (0-based) argument, which must be a pointer. | | `SaveArg(pointer)` | Save the `N`-th (0-based) argument to `*pointer`. | | `SaveArgPointee(pointer)` | Save the value pointed to by the `N`-th (0-based) argument to `*pointer`. | | `SetArgReferee(value)` | Assign value to the variable referenced by the `N`-th (0-based) argument. | |`SetArgPointee(value)` |Assign `value` to the variable pointed by the `N`-th (0-based) argument.| |`SetArgumentPointee(value)`|Same as `SetArgPointee(value)`. Deprecated. Will be removed in v1.7.0.| |`SetArrayArgument(first, last)`|Copies the elements in source range [`first`, `last`) to the array pointed to by the `N`-th (0-based) argument, which can be either a pointer or an iterator. The action does not take ownership of the elements in the source range.| |`SetErrnoAndReturn(error, value)`|Set `errno` to `error` and return `value`.| |`Throw(exception)` |Throws the given exception, which can be any copyable value. Available since v1.1.0.| ## Using a Function or a Functor as an Action ## |`Invoke(f)`|Invoke `f` with the arguments passed to the mock function, where `f` can be a global/static function or a functor.| |:----------|:-----------------------------------------------------------------------------------------------------------------| |`Invoke(object_pointer, &class::method)`|Invoke the {method on the object with the arguments passed to the mock function. | |`InvokeWithoutArgs(f)`|Invoke `f`, which can be a global/static function or a functor. `f` must take no arguments. | |`InvokeWithoutArgs(object_pointer, &class::method)`|Invoke the method on the object, which takes no arguments. | |`InvokeArgument(arg1, arg2, ..., argk)`|Invoke the mock function's `N`-th (0-based) argument, which must be a function or a functor, with the `k` arguments.| The return value of the invoked function is used as the return value of the action. When defining a function or functor to be used with `Invoke*()`, you can declare any unused parameters as `Unused`: ``` double Distance(Unused, double x, double y) { return sqrt(x*x + y*y); } ... EXPECT_CALL(mock, Foo("Hi", _, _)).WillOnce(Invoke(Distance)); ``` In `InvokeArgument(...)`, if an argument needs to be passed by reference, wrap it inside `ByRef()`. For example, ``` InvokeArgument<2>(5, string("Hi"), ByRef(foo)) ``` calls the mock function's #2 argument, passing to it `5` and `string("Hi")` by value, and `foo` by reference. ## Default Action ## |`DoDefault()`|Do the default action (specified by `ON_CALL()` or the built-in one).| |:------------|:--------------------------------------------------------------------| **Note:** due to technical reasons, `DoDefault()` cannot be used inside a composite action - trying to do so will result in a run-time error. ## Composite Actions ## |`DoAll(a1, a2, ..., an)`|Do all actions `a1` to `an` and return the result of `an` in each invocation. The first `n - 1` sub-actions must return void. | |:-----------------------|:-----------------------------------------------------------------------------------------------------------------------------| |`IgnoreResult(a)` |Perform action `a` and ignore its result. `a` must not return void. | |`WithArg(a)` |Pass the `N`-th (0-based) argument of the mock function to action `a` and perform it. | |`WithArgs(a)`|Pass the selected (0-based) arguments of the mock function to action `a` and perform it. | |`WithoutArgs(a)` |Perform action `a` without any arguments. | ## Defining Actions ## | `ACTION(Sum) { return arg0 + arg1; }` | Defines an action `Sum()` to return the sum of the mock function's argument #0 and #1. | |:--------------------------------------|:---------------------------------------------------------------------------------------| | `ACTION_P(Plus, n) { return arg0 + n; }` | Defines an action `Plus(n)` to return the sum of the mock function's argument #0 and `n`. | | `ACTION_Pk(Foo, p1, ..., pk) { statements; }` | Defines a parameterized action `Foo(p1, ..., pk)` to execute the given `statements`. | The `ACTION*` macros cannot be used inside a function or class. # Cardinalities # These are used in `Times()` to specify how many times a mock function will be called: |`AnyNumber()`|The function can be called any number of times.| |:------------|:----------------------------------------------| |`AtLeast(n)` |The call is expected at least `n` times. | |`AtMost(n)` |The call is expected at most `n` times. | |`Between(m, n)`|The call is expected between `m` and `n` (inclusive) times.| |`Exactly(n) or n`|The call is expected exactly `n` times. In particular, the call should never happen when `n` is 0.| # Expectation Order # By default, the expectations can be matched in _any_ order. If some or all expectations must be matched in a given order, there are two ways to specify it. They can be used either independently or together. ## The After Clause ## ``` using ::testing::Expectation; ... Expectation init_x = EXPECT_CALL(foo, InitX()); Expectation init_y = EXPECT_CALL(foo, InitY()); EXPECT_CALL(foo, Bar()) .After(init_x, init_y); ``` says that `Bar()` can be called only after both `InitX()` and `InitY()` have been called. If you don't know how many pre-requisites an expectation has when you write it, you can use an `ExpectationSet` to collect them: ``` using ::testing::ExpectationSet; ... ExpectationSet all_inits; for (int i = 0; i < element_count; i++) { all_inits += EXPECT_CALL(foo, InitElement(i)); } EXPECT_CALL(foo, Bar()) .After(all_inits); ``` says that `Bar()` can be called only after all elements have been initialized (but we don't care about which elements get initialized before the others). Modifying an `ExpectationSet` after using it in an `.After()` doesn't affect the meaning of the `.After()`. ## Sequences ## When you have a long chain of sequential expectations, it's easier to specify the order using **sequences**, which don't require you to given each expectation in the chain a different name. All expected
calls
in the same sequence must occur in the order they are specified. ``` using ::testing::Sequence; Sequence s1, s2; ... EXPECT_CALL(foo, Reset()) .InSequence(s1, s2) .WillOnce(Return(true)); EXPECT_CALL(foo, GetSize()) .InSequence(s1) .WillOnce(Return(1)); EXPECT_CALL(foo, Describe(A())) .InSequence(s2) .WillOnce(Return("dummy")); ``` says that `Reset()` must be called before _both_ `GetSize()` _and_ `Describe()`, and the latter two can occur in any order. To put many expectations in a sequence conveniently: ``` using ::testing::InSequence; { InSequence dummy; EXPECT_CALL(...)...; EXPECT_CALL(...)...; ... EXPECT_CALL(...)...; } ``` says that all expected calls in the scope of `dummy` must occur in strict order. The name `dummy` is irrelevant.) # Verifying and Resetting a Mock # Google Mock will verify the expectations on a mock object when it is destructed, or you can do it earlier: ``` using ::testing::Mock; ... // Verifies and removes the expectations on mock_obj; // returns true iff successful. Mock::VerifyAndClearExpectations(&mock_obj); ... // Verifies and removes the expectations on mock_obj; // also removes the default actions set by ON_CALL(); // returns true iff successful. Mock::VerifyAndClear(&mock_obj); ``` You can also tell Google Mock that a mock object can be leaked and doesn't need to be verified: ``` Mock::AllowLeak(&mock_obj); ``` # Mock Classes # Google Mock defines a convenient mock class template ``` class MockFunction { public: MOCK_METHODn(Call, R(A1, ..., An)); }; ``` See this [recipe](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Using_Check_Points) for one application of it. # Flags # | `--gmock_catch_leaked_mocks=0` | Don't report leaked mock objects as failures. | |:-------------------------------|:----------------------------------------------| | `--gmock_verbose=LEVEL` | Sets the default verbosity level (`info`, `warning`, or `error`) of Google Mock messages. |nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/docs/v1_7/CookBook.md000066400000000000000000003463461455373415500264140ustar00rootroot00000000000000 You can find recipes for using Google Mock here. If you haven't yet, please read the [ForDummies](V1_7_ForDummies.md) document first to make sure you understand the basics. **Note:** Google Mock lives in the `testing` name space. For readability, it is recommended to write `using ::testing::Foo;` once in your file before using the name `Foo` defined by Google Mock. We omit such `using` statements in this page for brevity, but you should do it in your own code. # Creating Mock Classes # ## Mocking Private or Protected Methods ## You must always put a mock method definition (`MOCK_METHOD*`) in a `public:` section of the mock class, regardless of the method being mocked being `public`, `protected`, or `private` in the base class. This allows `ON_CALL` and `EXPECT_CALL` to reference the mock function from outside of the mock class. (Yes, C++ allows a subclass to change the access level of a virtual function in the base class.) Example: ``` class Foo { public: ... virtual bool Transform(Gadget* g) = 0; protected: virtual void Resume(); private: virtual int GetTimeOut(); }; class MockFoo : public Foo { public: ... MOCK_METHOD1(Transform, bool(Gadget* g)); // The following must be in the public section, even though the // methods are protected or private in the base class. MOCK_METHOD0(Resume, void()); MOCK_METHOD0(GetTimeOut, int()); }; ``` ## Mocking Overloaded Methods ## You can mock overloaded functions as usual. No special attention is required: ``` class Foo { ... // Must be virtual as we'll inherit from Foo. virtual ~Foo(); // Overloaded on the types and/or numbers of arguments. virtual int Add(Element x); virtual int Add(int times, Element x); // Overloaded on the const-ness of this object. virtual Bar& GetBar(); virtual const Bar& GetBar() const; }; class MockFoo : public Foo { ... MOCK_METHOD1(Add, int(Element x)); MOCK_METHOD2(Add, int(int times, Element x); MOCK_METHOD0(GetBar, Bar&()); MOCK_CONST_METHOD0(GetBar, const Bar&()); }; ``` **Note:** if you don't mock all versions of the overloaded method, the compiler will give you a warning about some methods in the base class being hidden. To fix that, use `using` to bring them in scope: ``` class MockFoo : public Foo { ... using Foo::Add; MOCK_METHOD1(Add, int(Element x)); // We don't want to mock int Add(int times, Element x); ... }; ``` ## Mocking Class Templates ## To mock a class template, append `_T` to the `MOCK_*` macros: ``` template class StackInterface { ... // Must be virtual as we'll inherit from StackInterface. virtual ~StackInterface(); virtual int GetSize() const = 0; virtual void Push(const Elem& x) = 0; }; template class MockStack : public StackInterface { ... MOCK_CONST_METHOD0_T(GetSize, int()); MOCK_METHOD1_T(Push, void(const Elem& x)); }; ``` ## Mocking Nonvirtual Methods ## Google Mock can mock non-virtual functions to be used in what we call _hi-perf dependency injection_. In this case, instead of sharing a common base class with the real class, your mock class will be _unrelated_ to the real class, but contain methods with the same signatures. The syntax for mocking non-virtual methods is the _same_ as mocking virtual methods: ``` // A simple packet stream class. None of its members is virtual. class ConcretePacketStream { public: void AppendPacket(Packet* new_packet); const Packet* GetPacket(size_t packet_number) const; size_t NumberOfPackets() const; ... }; // A mock packet stream class. It inherits from no other, but defines // GetPacket() and NumberOfPackets(). class MockPacketStream { public: MOCK_CONST_METHOD1(GetPacket, const Packet*(size_t packet_number)); MOCK_CONST_METHOD0(NumberOfPackets, size_t()); ... }; ``` Note that the mock class doesn't define `AppendPacket()`, unlike the real class. That's fine as long as the test doesn't need to call it. Next, you need a way to say that you want to use `ConcretePacketStream` in production code, and use `MockPacketStream` in tests. Since the functions are not virtual and the two classes are unrelated, you must specify your choice at _compile time_ (as opposed to run time). One way to do it is to templatize your code that needs to use a packet stream. More specifically, you will give your code a template type argument for the type of the packet stream. In production, you will instantiate your template with `ConcretePacketStream` as the type argument. In tests, you will instantiate the same template with `MockPacketStream`. For example, you may write: ``` template void CreateConnection(PacketStream* stream) { ... } template class PacketReader { public: void ReadPackets(PacketStream* stream, size_t packet_num); }; ``` Then you can use `CreateConnection()` and `PacketReader` in production code, and use `CreateConnection()` and `PacketReader` in tests. ``` MockPacketStream mock_stream; EXPECT_CALL(mock_stream, ...)...; .. set more expectations on mock_stream ... PacketReader reader(&mock_stream); ... exercise reader ... ``` ## Mocking Free Functions ## It's possible to use Google Mock to mock a free function (i.e. a C-style function or a static method). You just need to rewrite your code to use an interface (abstract class). Instead of calling a free function (say, `OpenFile`) directly, introduce an interface for it and have a concrete subclass that calls the free function: ``` class FileInterface { public: ... virtual bool Open(const char* path, const char* mode) = 0; }; class File : public FileInterface { public: ... virtual bool Open(const char* path, const char* mode) { return OpenFile(path, mode); } }; ``` Your code should talk to `FileInterface` to open a file. Now it's easy to mock out the function. This may seem much hassle, but in practice you often have multiple related functions that you can put in the same interface, so the per-function syntactic overhead will be much lower. If you are concerned about the performance overhead incurred by virtual functions, and profiling confirms your concern, you can combine this with the recipe for [mocking non-virtual methods](#Mocking_Nonvirtual_Methods.md). ## The Nice, the Strict, and the Naggy ## If a mock method has no `EXPECT_CALL` spec but is called, Google Mock will print a warning about the "uninteresting call". The rationale is: * New methods may be added to an interface after a test is written. We shouldn't fail a test just because a method it doesn't know about is called. * However, this may also mean there's a bug in the test, so Google Mock shouldn't be silent either. If the user believes these calls are harmless, he can add an `EXPECT_CALL()` to suppress the warning. However, sometimes you may want to suppress all "uninteresting call" warnings, while sometimes you may want the opposite, i.e. to treat all of them as errors. Google Mock lets you make the decision on a per-mock-object basis. Suppose your test uses a mock class `MockFoo`: ``` TEST(...) { MockFoo mock_foo; EXPECT_CALL(mock_foo, DoThis()); ... code that uses mock_foo ... } ``` If a method of `mock_foo` other than `DoThis()` is called, it will be reported by Google Mock as a warning. However, if you rewrite your test to use `NiceMock` instead, the warning will be gone, resulting in a cleaner test output: ``` using ::testing::NiceMock; TEST(...) { NiceMock mock_foo; EXPECT_CALL(mock_foo, DoThis()); ... code that uses mock_foo ... } ``` `NiceMock` is a subclass of `MockFoo`, so it can be used wherever `MockFoo` is accepted. It also works if `MockFoo`'s constructor takes some arguments, as `NiceMock` "inherits" `MockFoo`'s constructors: ``` using ::testing::NiceMock; TEST(...) { NiceMock mock_foo(5, "hi"); // Calls MockFoo(5, "hi"). EXPECT_CALL(mock_foo, DoThis()); ... code that uses mock_foo ... } ``` The usage of `StrictMock` is similar, except that it makes all uninteresting calls failures: ``` using ::testing::StrictMock; TEST(...) { StrictMock mock_foo; EXPECT_CALL(mock_foo, DoThis()); ... code that uses mock_foo ... // The test will fail if a method of mock_foo other than DoThis() // is called. } ``` There are some caveats though (I don't like them just as much as the next guy, but sadly they are side effects of C++'s limitations): 1. `NiceMock` and `StrictMock` only work for mock methods defined using the `MOCK_METHOD*` family of macros **directly** in the `MockFoo` class. If a mock method is defined in a **base class** of `MockFoo`, the "nice" or "strict" modifier may not affect it, depending on the compiler. In particular, nesting `NiceMock` and `StrictMock` (e.g. `NiceMock >`) is **not** supported. 1. The constructors of the base mock (`MockFoo`) cannot have arguments passed by non-const reference, which happens to be banned by the [Google C++ style guide](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml). 1. During the constructor or destructor of `MockFoo`, the mock object is _not_ nice or strict. This may cause surprises if the constructor or destructor calls a mock method on `this` object. (This behavior, however, is consistent with C++'s general rule: if a constructor or destructor calls a virtual method of `this` object, that method is treated as non-virtual. In other words, to the base class's constructor or destructor, `this` object behaves like an instance of the base class, not the derived class. This rule is required for safety. Otherwise a base constructor may use members of a derived class before they are initialized, or a base destructor may use members of a derived class after they have been destroyed.) Finally, you should be **very cautious** about when to use naggy or strict mocks, as they tend to make tests more brittle and harder to maintain. When you refactor your code without changing its externally visible behavior, ideally you should't need to update any tests. If your code interacts with a naggy mock, however, you may start to get spammed with warnings as the result of your change. Worse, if your code interacts with a strict mock, your tests may start to fail and you'll be forced to fix them. Our general recommendation is to use nice mocks (not yet the default) most of the time, use naggy mocks (the current default) when developing or debugging tests, and use strict mocks only as the last resort. ## Simplifying the Interface without Breaking Existing Code ## Sometimes a method has a long list of arguments that is mostly uninteresting. For example, ``` class LogSink { public: ... virtual void send(LogSeverity severity, const char* full_filename, const char* base_filename, int line, const struct tm* tm_time, const char* message, size_t message_len) = 0; }; ``` This method's argument list is lengthy and hard to work with (let's say that the `message` argument is not even 0-terminated). If we mock it as is, using the mock will be awkward. If, however, we try to simplify this interface, we'll need to fix all clients depending on it, which is often infeasible. The trick is to re-dispatch the method in the mock class: ``` class ScopedMockLog : public LogSink { public: ... virtual void send(LogSeverity severity, const char* full_filename, const char* base_filename, int line, const tm* tm_time, const char* message, size_t message_len) { // We are only interested in the log severity, full file name, and // log message. Log(severity, full_filename, std::string(message, message_len)); } // Implements the mock method: // // void Log(LogSeverity severity, // const string& file_path, // const string& message); MOCK_METHOD3(Log, void(LogSeverity severity, const string& file_path, const string& message)); }; ``` By defining a new mock method with a trimmed argument list, we make the mock class much more user-friendly. ## Alternative to Mocking Concrete Classes ## Often you may find yourself using classes that don't implement interfaces. In order to test your code that uses such a class (let's call it `Concrete`), you may be tempted to make the methods of `Concrete` virtual and then mock it. Try not to do that. Making a non-virtual function virtual is a big decision. It creates an extension point where subclasses can tweak your class' behavior. This weakens your control on the class because now it's harder to maintain the class' invariants. You should make a function virtual only when there is a valid reason for a subclass to override it. Mocking concrete classes directly is problematic as it creates a tight coupling between the class and the tests - any small change in the class may invalidate your tests and make test maintenance a pain. To avoid such problems, many programmers have been practicing "coding to interfaces": instead of talking to the `Concrete` class, your code would define an interface and talk to it. Then you implement that interface as an adaptor on top of `Concrete`. In tests, you can easily mock that interface to observe how your code is doing. This technique incurs some overhead: * You pay the cost of virtual function calls (usually not a problem). * There is more abstraction for the programmers to learn. However, it can also bring significant benefits in addition to better testability: * `Concrete`'s API may not fit your problem domain very well, as you may not be the only client it tries to serve. By designing your own interface, you have a chance to tailor it to your need - you may add higher-level functionalities, rename stuff, etc instead of just trimming the class. This allows you to write your code (user of the interface) in a more natural way, which means it will be more readable, more maintainable, and you'll be more productive. * If `Concrete`'s implementation ever has to change, you don't have to rewrite everywhere it is used. Instead, you can absorb the change in your implementation of the interface, and your other code and tests will be insulated from this change. Some people worry that if everyone is practicing this technique, they will end up writing lots of redundant code. This concern is totally understandable. However, there are two reasons why it may not be the case: * Different projects may need to use `Concrete` in different ways, so the best interfaces for them will be different. Therefore, each of them will have its own domain-specific interface on top of `Concrete`, and they will not be the same code. * If enough projects want to use the same interface, they can always share it, just like they have been sharing `Concrete`. You can check in the interface and the adaptor somewhere near `Concrete` (perhaps in a `contrib` sub-directory) and let many projects use it. You need to weigh the pros and cons carefully for your particular problem, but I'd like to assure you that the Java community has been practicing this for a long time and it's a proven effective technique applicable in a wide variety of situations. :-) ## Delegating Calls to a Fake ## Some times you have a non-trivial fake implementation of an interface. For example: ``` class Foo { public: virtual ~Foo() {} virtual char DoThis(int n) = 0; virtual void DoThat(const char* s, int* p) = 0; }; class FakeFoo : public Foo { public: virtual char DoThis(int n) { return (n > 0) ? '+' : (n < 0) ? '-' : '0'; } virtual void DoThat(const char* s, int* p) { *p = strlen(s); } }; ``` Now you want to mock this interface such that you can set expectations on it. However, you also want to use `FakeFoo` for the default behavior, as duplicating it in the mock object is, well, a lot of work. When you define the mock class using Google Mock, you can have it delegate its default action to a fake class you already have, using this pattern: ``` using ::testing::_; using ::testing::Invoke; class MockFoo : public Foo { public: // Normal mock method definitions using Google Mock. MOCK_METHOD1(DoThis, char(int n)); MOCK_METHOD2(DoThat, void(const char* s, int* p)); // Delegates the default actions of the methods to a FakeFoo object. // This must be called *before* the custom ON_CALL() statements. void DelegateToFake() { ON_CALL(*this, DoThis(_)) .WillByDefault(Invoke(&fake_, &FakeFoo::DoThis)); ON_CALL(*this, DoThat(_, _)) .WillByDefault(Invoke(&fake_, &FakeFoo::DoThat)); } private: FakeFoo fake_; // Keeps an instance of the fake in the mock. }; ``` With that, you can use `MockFoo` in your tests as usual. Just remember that if you don't explicitly set an action in an `ON_CALL()` or `EXPECT_CALL()`, the fake will be called upon to do it: ``` using ::testing::_; TEST(AbcTest, Xyz) { MockFoo foo; foo.DelegateToFake(); // Enables the fake for delegation. // Put your ON_CALL(foo, ...)s here, if any. // No action specified, meaning to use the default action. EXPECT_CALL(foo, DoThis(5)); EXPECT_CALL(foo, DoThat(_, _)); int n = 0; EXPECT_EQ('+', foo.DoThis(5)); // FakeFoo::DoThis() is invoked. foo.DoThat("Hi", &n); // FakeFoo::DoThat() is invoked. EXPECT_EQ(2, n); } ``` **Some tips:** * If you want, you can still override the default action by providing your own `ON_CALL()` or using `.WillOnce()` / `.WillRepeatedly()` in `EXPECT_CALL()`. * In `DelegateToFake()`, you only need to delegate the methods whose fake implementation you intend to use. * The general technique discussed here works for overloaded methods, but you'll need to tell the compiler which version you mean. To disambiguate a mock function (the one you specify inside the parentheses of `ON_CALL()`), see the "Selecting Between Overloaded Functions" section on this page; to disambiguate a fake function (the one you place inside `Invoke()`), use a `static_cast` to specify the function's type. For instance, if class `Foo` has methods `char DoThis(int n)` and `bool DoThis(double x) const`, and you want to invoke the latter, you need to write `Invoke(&fake_, static_cast(&FakeFoo::DoThis))` instead of `Invoke(&fake_, &FakeFoo::DoThis)` (The strange-looking thing inside the angled brackets of `static_cast` is the type of a function pointer to the second `DoThis()` method.). * Having to mix a mock and a fake is often a sign of something gone wrong. Perhaps you haven't got used to the interaction-based way of testing yet. Or perhaps your interface is taking on too many roles and should be split up. Therefore, **don't abuse this**. We would only recommend to do it as an intermediate step when you are refactoring your code. Regarding the tip on mixing a mock and a fake, here's an example on why it may be a bad sign: Suppose you have a class `System` for low-level system operations. In particular, it does file and I/O operations. And suppose you want to test how your code uses `System` to do I/O, and you just want the file operations to work normally. If you mock out the entire `System` class, you'll have to provide a fake implementation for the file operation part, which suggests that `System` is taking on too many roles. Instead, you can define a `FileOps` interface and an `IOOps` interface and split `System`'s functionalities into the two. Then you can mock `IOOps` without mocking `FileOps`. ## Delegating Calls to a Real Object ## When using testing doubles (mocks, fakes, stubs, and etc), sometimes their behaviors will differ from those of the real objects. This difference could be either intentional (as in simulating an error such that you can test the error handling code) or unintentional. If your mocks have different behaviors than the real objects by mistake, you could end up with code that passes the tests but fails in production. You can use the _delegating-to-real_ technique to ensure that your mock has the same behavior as the real object while retaining the ability to validate calls. This technique is very similar to the delegating-to-fake technique, the difference being that we use a real object instead of a fake. Here's an example: ``` using ::testing::_; using ::testing::AtLeast; using ::testing::Invoke; class MockFoo : public Foo { public: MockFoo() { // By default, all calls are delegated to the real object. ON_CALL(*this, DoThis()) .WillByDefault(Invoke(&real_, &Foo::DoThis)); ON_CALL(*this, DoThat(_)) .WillByDefault(Invoke(&real_, &Foo::DoThat)); ... } MOCK_METHOD0(DoThis, ...); MOCK_METHOD1(DoThat, ...); ... private: Foo real_; }; ... MockFoo mock; EXPECT_CALL(mock, DoThis()) .Times(3); EXPECT_CALL(mock, DoThat("Hi")) .Times(AtLeast(1)); ... use mock in test ... ``` With this, Google Mock will verify that your code made the right calls (with the right arguments, in the right order, called the right number of times, etc), and a real object will answer the calls (so the behavior will be the same as in production). This gives you the best of both worlds. ## Delegating Calls to a Parent Class ## Ideally, you should code to interfaces, whose methods are all pure virtual. In reality, sometimes you do need to mock a virtual method that is not pure (i.e, it already has an implementation). For example: ``` class Foo { public: virtual ~Foo(); virtual void Pure(int n) = 0; virtual int Concrete(const char* str) { ... } }; class MockFoo : public Foo { public: // Mocking a pure method. MOCK_METHOD1(Pure, void(int n)); // Mocking a concrete method. Foo::Concrete() is shadowed. MOCK_METHOD1(Concrete, int(const char* str)); }; ``` Sometimes you may want to call `Foo::Concrete()` instead of `MockFoo::Concrete()`. Perhaps you want to do it as part of a stub action, or perhaps your test doesn't need to mock `Concrete()` at all (but it would be oh-so painful to have to define a new mock class whenever you don't need to mock one of its methods). The trick is to leave a back door in your mock class for accessing the real methods in the base class: ``` class MockFoo : public Foo { public: // Mocking a pure method. MOCK_METHOD1(Pure, void(int n)); // Mocking a concrete method. Foo::Concrete() is shadowed. MOCK_METHOD1(Concrete, int(const char* str)); // Use this to call Concrete() defined in Foo. int FooConcrete(const char* str) { return Foo::Concrete(str); } }; ``` Now, you can call `Foo::Concrete()` inside an action by: ``` using ::testing::_; using ::testing::Invoke; ... EXPECT_CALL(foo, Concrete(_)) .WillOnce(Invoke(&foo, &MockFoo::FooConcrete)); ``` or tell the mock object that you don't want to mock `Concrete()`: ``` using ::testing::Invoke; ... ON_CALL(foo, Concrete(_)) .WillByDefault(Invoke(&foo, &MockFoo::FooConcrete)); ``` (Why don't we just write `Invoke(&foo, &Foo::Concrete)`? If you do that, `MockFoo::Concrete()` will be called (and cause an infinite recursion) since `Foo::Concrete()` is virtual. That's just how C++ works.) # Using Matchers # ## Matching Argument Values Exactly ## You can specify exactly which arguments a mock method is expecting: ``` using ::testing::Return; ... EXPECT_CALL(foo, DoThis(5)) .WillOnce(Return('a')); EXPECT_CALL(foo, DoThat("Hello", bar)); ``` ## Using Simple Matchers ## You can use matchers to match arguments that have a certain property: ``` using ::testing::Ge; using ::testing::NotNull; using ::testing::Return; ... EXPECT_CALL(foo, DoThis(Ge(5))) // The argument must be >= 5. .WillOnce(Return('a')); EXPECT_CALL(foo, DoThat("Hello", NotNull())); // The second argument must not be NULL. ``` A frequently used matcher is `_`, which matches anything: ``` using ::testing::_; using ::testing::NotNull; ... EXPECT_CALL(foo, DoThat(_, NotNull())); ``` ## Combining Matchers ## You can build complex matchers from existing ones using `AllOf()`, `AnyOf()`, and `Not()`: ``` using ::testing::AllOf; using ::testing::Gt; using ::testing::HasSubstr; using ::testing::Ne; using ::testing::Not; ... // The argument must be > 5 and != 10. EXPECT_CALL(foo, DoThis(AllOf(Gt(5), Ne(10)))); // The first argument must not contain sub-string "blah". EXPECT_CALL(foo, DoThat(Not(HasSubstr("blah")), NULL)); ``` ## Casting Matchers ## Google Mock matchers are statically typed, meaning that the compiler can catch your mistake if you use a matcher of the wrong type (for example, if you use `Eq(5)` to match a `string` argument). Good for you! Sometimes, however, you know what you're doing and want the compiler to give you some slack. One example is that you have a matcher for `long` and the argument you want to match is `int`. While the two types aren't exactly the same, there is nothing really wrong with using a `Matcher` to match an `int` - after all, we can first convert the `int` argument to a `long` before giving it to the matcher. To support this need, Google Mock gives you the `SafeMatcherCast(m)` function. It casts a matcher `m` to type `Matcher`. To ensure safety, Google Mock checks that (let `U` be the type `m` accepts): 1. Type `T` can be implicitly cast to type `U`; 1. When both `T` and `U` are built-in arithmetic types (`bool`, integers, and floating-point numbers), the conversion from `T` to `U` is not lossy (in other words, any value representable by `T` can also be represented by `U`); and 1. When `U` is a reference, `T` must also be a reference (as the underlying matcher may be interested in the address of the `U` value). The code won't compile if any of these conditions isn't met. Here's one example: ``` using ::testing::SafeMatcherCast; // A base class and a child class. class Base { ... }; class Derived : public Base { ... }; class MockFoo : public Foo { public: MOCK_METHOD1(DoThis, void(Derived* derived)); }; ... MockFoo foo; // m is a Matcher we got from somewhere. EXPECT_CALL(foo, DoThis(SafeMatcherCast(m))); ``` If you find `SafeMatcherCast(m)` too limiting, you can use a similar function `MatcherCast(m)`. The difference is that `MatcherCast` works as long as you can `static_cast` type `T` to type `U`. `MatcherCast` essentially lets you bypass C++'s type system (`static_cast` isn't always safe as it could throw away information, for example), so be careful not to misuse/abuse it. ## Selecting Between Overloaded Functions ## If you expect an overloaded function to be called, the compiler may need some help on which overloaded version it is. To disambiguate functions overloaded on the const-ness of this object, use the `Const()` argument wrapper. ``` using ::testing::ReturnRef; class MockFoo : public Foo { ... MOCK_METHOD0(GetBar, Bar&()); MOCK_CONST_METHOD0(GetBar, const Bar&()); }; ... MockFoo foo; Bar bar1, bar2; EXPECT_CALL(foo, GetBar()) // The non-const GetBar(). .WillOnce(ReturnRef(bar1)); EXPECT_CALL(Const(foo), GetBar()) // The const GetBar(). .WillOnce(ReturnRef(bar2)); ``` (`Const()` is defined by Google Mock and returns a `const` reference to its argument.) To disambiguate overloaded functions with the same number of arguments but different argument types, you may need to specify the exact type of a matcher, either by wrapping your matcher in `Matcher()`, or using a matcher whose type is fixed (`TypedEq`, `An()`, etc): ``` using ::testing::An; using ::testing::Lt; using ::testing::Matcher; using ::testing::TypedEq; class MockPrinter : public Printer { public: MOCK_METHOD1(Print, void(int n)); MOCK_METHOD1(Print, void(char c)); }; TEST(PrinterTest, Print) { MockPrinter printer; EXPECT_CALL(printer, Print(An())); // void Print(int); EXPECT_CALL(printer, Print(Matcher(Lt(5)))); // void Print(int); EXPECT_CALL(printer, Print(TypedEq('a'))); // void Print(char); printer.Print(3); printer.Print(6); printer.Print('a'); } ``` ## Performing Different Actions Based on the Arguments ## When a mock method is called, the _last_ matching expectation that's still active will be selected (think "newer overrides older"). So, you can make a method do different things depending on its argument values like this: ``` using ::testing::_; using ::testing::Lt; using ::testing::Return; ... // The default case. EXPECT_CALL(foo, DoThis(_)) .WillRepeatedly(Return('b')); // The more specific case. EXPECT_CALL(foo, DoThis(Lt(5))) .WillRepeatedly(Return('a')); ``` Now, if `foo.DoThis()` is called with a value less than 5, `'a'` will be returned; otherwise `'b'` will be returned. ## Matching Multiple Arguments as a Whole ## Sometimes it's not enough to match the arguments individually. For example, we may want to say that the first argument must be less than the second argument. The `With()` clause allows us to match all arguments of a mock function as a whole. For example, ``` using ::testing::_; using ::testing::Lt; using ::testing::Ne; ... EXPECT_CALL(foo, InRange(Ne(0), _)) .With(Lt()); ``` says that the first argument of `InRange()` must not be 0, and must be less than the second argument. The expression inside `With()` must be a matcher of type `Matcher >`, where `A1`, ..., `An` are the types of the function arguments. You can also write `AllArgs(m)` instead of `m` inside `.With()`. The two forms are equivalent, but `.With(AllArgs(Lt()))` is more readable than `.With(Lt())`. You can use `Args(m)` to match the `n` selected arguments (as a tuple) against `m`. For example, ``` using ::testing::_; using ::testing::AllOf; using ::testing::Args; using ::testing::Lt; ... EXPECT_CALL(foo, Blah(_, _, _)) .With(AllOf(Args<0, 1>(Lt()), Args<1, 2>(Lt()))); ``` says that `Blah()` will be called with arguments `x`, `y`, and `z` where `x < y < z`. As a convenience and example, Google Mock provides some matchers for 2-tuples, including the `Lt()` matcher above. See the [CheatSheet](V1_7_CheatSheet.md) for the complete list. Note that if you want to pass the arguments to a predicate of your own (e.g. `.With(Args<0, 1>(Truly(&MyPredicate)))`), that predicate MUST be written to take a `tr1::tuple` as its argument; Google Mock will pass the `n` selected arguments as _one_ single tuple to the predicate. ## Using Matchers as Predicates ## Have you noticed that a matcher is just a fancy predicate that also knows how to describe itself? Many existing algorithms take predicates as arguments (e.g. those defined in STL's `` header), and it would be a shame if Google Mock matchers are not allowed to participate. Luckily, you can use a matcher where a unary predicate functor is expected by wrapping it inside the `Matches()` function. For example, ``` #include #include std::vector v; ... // How many elements in v are >= 10? const int count = count_if(v.begin(), v.end(), Matches(Ge(10))); ``` Since you can build complex matchers from simpler ones easily using Google Mock, this gives you a way to conveniently construct composite predicates (doing the same using STL's `` header is just painful). For example, here's a predicate that's satisfied by any number that is >= 0, <= 100, and != 50: ``` Matches(AllOf(Ge(0), Le(100), Ne(50))) ``` ## Using Matchers in Google Test Assertions ## Since matchers are basically predicates that also know how to describe themselves, there is a way to take advantage of them in [Google Test](http://code.google.com/p/googletest/) assertions. It's called `ASSERT_THAT` and `EXPECT_THAT`: ``` ASSERT_THAT(value, matcher); // Asserts that value matches matcher. EXPECT_THAT(value, matcher); // The non-fatal version. ``` For example, in a Google Test test you can write: ``` #include "gmock/gmock.h" using ::testing::AllOf; using ::testing::Ge; using ::testing::Le; using ::testing::MatchesRegex; using ::testing::StartsWith; ... EXPECT_THAT(Foo(), StartsWith("Hello")); EXPECT_THAT(Bar(), MatchesRegex("Line \\d+")); ASSERT_THAT(Baz(), AllOf(Ge(5), Le(10))); ``` which (as you can probably guess) executes `Foo()`, `Bar()`, and `Baz()`, and verifies that: * `Foo()` returns a string that starts with `"Hello"`. * `Bar()` returns a string that matches regular expression `"Line \\d+"`. * `Baz()` returns a number in the range [5, 10]. The nice thing about these macros is that _they read like English_. They generate informative messages too. For example, if the first `EXPECT_THAT()` above fails, the message will be something like: ``` Value of: Foo() Actual: "Hi, world!" Expected: starts with "Hello" ``` **Credit:** The idea of `(ASSERT|EXPECT)_THAT` was stolen from the [Hamcrest](http://code.google.com/p/hamcrest/) project, which adds `assertThat()` to JUnit. ## Using Predicates as Matchers ## Google Mock provides a built-in set of matchers. In case you find them lacking, you can use an arbitray unary predicate function or functor as a matcher - as long as the predicate accepts a value of the type you want. You do this by wrapping the predicate inside the `Truly()` function, for example: ``` using ::testing::Truly; int IsEven(int n) { return (n % 2) == 0 ? 1 : 0; } ... // Bar() must be called with an even number. EXPECT_CALL(foo, Bar(Truly(IsEven))); ``` Note that the predicate function / functor doesn't have to return `bool`. It works as long as the return value can be used as the condition in statement `if (condition) ...`. ## Matching Arguments that Are Not Copyable ## When you do an `EXPECT_CALL(mock_obj, Foo(bar))`, Google Mock saves away a copy of `bar`. When `Foo()` is called later, Google Mock compares the argument to `Foo()` with the saved copy of `bar`. This way, you don't need to worry about `bar` being modified or destroyed after the `EXPECT_CALL()` is executed. The same is true when you use matchers like `Eq(bar)`, `Le(bar)`, and so on. But what if `bar` cannot be copied (i.e. has no copy constructor)? You could define your own matcher function and use it with `Truly()`, as the previous couple of recipes have shown. Or, you may be able to get away from it if you can guarantee that `bar` won't be changed after the `EXPECT_CALL()` is executed. Just tell Google Mock that it should save a reference to `bar`, instead of a copy of it. Here's how: ``` using ::testing::Eq; using ::testing::ByRef; using ::testing::Lt; ... // Expects that Foo()'s argument == bar. EXPECT_CALL(mock_obj, Foo(Eq(ByRef(bar)))); // Expects that Foo()'s argument < bar. EXPECT_CALL(mock_obj, Foo(Lt(ByRef(bar)))); ``` Remember: if you do this, don't change `bar` after the `EXPECT_CALL()`, or the result is undefined. ## Validating a Member of an Object ## Often a mock function takes a reference to object as an argument. When matching the argument, you may not want to compare the entire object against a fixed object, as that may be over-specification. Instead, you may need to validate a certain member variable or the result of a certain getter method of the object. You can do this with `Field()` and `Property()`. More specifically, ``` Field(&Foo::bar, m) ``` is a matcher that matches a `Foo` object whose `bar` member variable satisfies matcher `m`. ``` Property(&Foo::baz, m) ``` is a matcher that matches a `Foo` object whose `baz()` method returns a value that satisfies matcher `m`. For example: > | `Field(&Foo::number, Ge(3))` | Matches `x` where `x.number >= 3`. | |:-----------------------------|:-----------------------------------| > | `Property(&Foo::name, StartsWith("John "))` | Matches `x` where `x.name()` starts with `"John "`. | Note that in `Property(&Foo::baz, ...)`, method `baz()` must take no argument and be declared as `const`. BTW, `Field()` and `Property()` can also match plain pointers to objects. For instance, ``` Field(&Foo::number, Ge(3)) ``` matches a plain pointer `p` where `p->number >= 3`. If `p` is `NULL`, the match will always fail regardless of the inner matcher. What if you want to validate more than one members at the same time? Remember that there is `AllOf()`. ## Validating the Value Pointed to by a Pointer Argument ## C++ functions often take pointers as arguments. You can use matchers like `IsNull()`, `NotNull()`, and other comparison matchers to match a pointer, but what if you want to make sure the value _pointed to_ by the pointer, instead of the pointer itself, has a certain property? Well, you can use the `Pointee(m)` matcher. `Pointee(m)` matches a pointer iff `m` matches the value the pointer points to. For example: ``` using ::testing::Ge; using ::testing::Pointee; ... EXPECT_CALL(foo, Bar(Pointee(Ge(3)))); ``` expects `foo.Bar()` to be called with a pointer that points to a value greater than or equal to 3. One nice thing about `Pointee()` is that it treats a `NULL` pointer as a match failure, so you can write `Pointee(m)` instead of ``` AllOf(NotNull(), Pointee(m)) ``` without worrying that a `NULL` pointer will crash your test. Also, did we tell you that `Pointee()` works with both raw pointers **and** smart pointers (`linked_ptr`, `shared_ptr`, `scoped_ptr`, and etc)? What if you have a pointer to pointer? You guessed it - you can use nested `Pointee()` to probe deeper inside the value. For example, `Pointee(Pointee(Lt(3)))` matches a pointer that points to a pointer that points to a number less than 3 (what a mouthful...). ## Testing a Certain Property of an Object ## Sometimes you want to specify that an object argument has a certain property, but there is no existing matcher that does this. If you want good error messages, you should define a matcher. If you want to do it quick and dirty, you could get away with writing an ordinary function. Let's say you have a mock function that takes an object of type `Foo`, which has an `int bar()` method and an `int baz()` method, and you want to constrain that the argument's `bar()` value plus its `baz()` value is a given number. Here's how you can define a matcher to do it: ``` using ::testing::MatcherInterface; using ::testing::MatchResultListener; class BarPlusBazEqMatcher : public MatcherInterface { public: explicit BarPlusBazEqMatcher(int expected_sum) : expected_sum_(expected_sum) {} virtual bool MatchAndExplain(const Foo& foo, MatchResultListener* listener) const { return (foo.bar() + foo.baz()) == expected_sum_; } virtual void DescribeTo(::std::ostream* os) const { *os << "bar() + baz() equals " << expected_sum_; } virtual void DescribeNegationTo(::std::ostream* os) const { *os << "bar() + baz() does not equal " << expected_sum_; } private: const int expected_sum_; }; inline Matcher BarPlusBazEq(int expected_sum) { return MakeMatcher(new BarPlusBazEqMatcher(expected_sum)); } ... EXPECT_CALL(..., DoThis(BarPlusBazEq(5)))...; ``` ## Matching Containers ## Sometimes an STL container (e.g. list, vector, map, ...) is passed to a mock function and you may want to validate it. Since most STL containers support the `==` operator, you can write `Eq(expected_container)` or simply `expected_container` to match a container exactly. Sometimes, though, you may want to be more flexible (for example, the first element must be an exact match, but the second element can be any positive number, and so on). Also, containers used in tests often have a small number of elements, and having to define the expected container out-of-line is a bit of a hassle. You can use the `ElementsAre()` or `UnorderedElementsAre()` matcher in such cases: ``` using ::testing::_; using ::testing::ElementsAre; using ::testing::Gt; ... MOCK_METHOD1(Foo, void(const vector& numbers)); ... EXPECT_CALL(mock, Foo(ElementsAre(1, Gt(0), _, 5))); ``` The above matcher says that the container must have 4 elements, which must be 1, greater than 0, anything, and 5 respectively. If you instead write: ``` using ::testing::_; using ::testing::Gt; using ::testing::UnorderedElementsAre; ... MOCK_METHOD1(Foo, void(const vector& numbers)); ... EXPECT_CALL(mock, Foo(UnorderedElementsAre(1, Gt(0), _, 5))); ``` It means that the container must have 4 elements, which under some permutation must be 1, greater than 0, anything, and 5 respectively. `ElementsAre()` and `UnorderedElementsAre()` are overloaded to take 0 to 10 arguments. If more are needed, you can place them in a C-style array and use `ElementsAreArray()` or `UnorderedElementsAreArray()` instead: ``` using ::testing::ElementsAreArray; ... // ElementsAreArray accepts an array of element values. const int expected_vector1[] = { 1, 5, 2, 4, ... }; EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector1))); // Or, an array of element matchers. Matcher expected_vector2 = { 1, Gt(2), _, 3, ... }; EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector2))); ``` In case the array needs to be dynamically created (and therefore the array size cannot be inferred by the compiler), you can give `ElementsAreArray()` an additional argument to specify the array size: ``` using ::testing::ElementsAreArray; ... int* const expected_vector3 = new int[count]; ... fill expected_vector3 with values ... EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector3, count))); ``` **Tips:** * `ElementsAre*()` can be used to match _any_ container that implements the STL iterator pattern (i.e. it has a `const_iterator` type and supports `begin()/end()`), not just the ones defined in STL. It will even work with container types yet to be written - as long as they follows the above pattern. * You can use nested `ElementsAre*()` to match nested (multi-dimensional) containers. * If the container is passed by pointer instead of by reference, just write `Pointee(ElementsAre*(...))`. * The order of elements _matters_ for `ElementsAre*()`. Therefore don't use it with containers whose element order is undefined (e.g. `hash_map`). ## Sharing Matchers ## Under the hood, a Google Mock matcher object consists of a pointer to a ref-counted implementation object. Copying matchers is allowed and very efficient, as only the pointer is copied. When the last matcher that references the implementation object dies, the implementation object will be deleted. Therefore, if you have some complex matcher that you want to use again and again, there is no need to build it everytime. Just assign it to a matcher variable and use that variable repeatedly! For example, ``` Matcher in_range = AllOf(Gt(5), Le(10)); ... use in_range as a matcher in multiple EXPECT_CALLs ... ``` # Setting Expectations # ## Knowing When to Expect ## `ON_CALL` is likely the single most under-utilized construct in Google Mock. There are basically two constructs for defining the behavior of a mock object: `ON_CALL` and `EXPECT_CALL`. The difference? `ON_CALL` defines what happens when a mock method is called, but _doesn't imply any expectation on the method being called._ `EXPECT_CALL` not only defines the behavior, but also sets an expectation that _the method will be called with the given arguments, for the given number of times_ (and _in the given order_ when you specify the order too). Since `EXPECT_CALL` does more, isn't it better than `ON_CALL`? Not really. Every `EXPECT_CALL` adds a constraint on the behavior of the code under test. Having more constraints than necessary is _baaad_ - even worse than not having enough constraints. This may be counter-intuitive. How could tests that verify more be worse than tests that verify less? Isn't verification the whole point of tests? The answer, lies in _what_ a test should verify. **A good test verifies the contract of the code.** If a test over-specifies, it doesn't leave enough freedom to the implementation. As a result, changing the implementation without breaking the contract (e.g. refactoring and optimization), which should be perfectly fine to do, can break such tests. Then you have to spend time fixing them, only to see them broken again the next time the implementation is changed. Keep in mind that one doesn't have to verify more than one property in one test. In fact, **it's a good style to verify only one thing in one test.** If you do that, a bug will likely break only one or two tests instead of dozens (which case would you rather debug?). If you are also in the habit of giving tests descriptive names that tell what they verify, you can often easily guess what's wrong just from the test log itself. So use `ON_CALL` by default, and only use `EXPECT_CALL` when you actually intend to verify that the call is made. For example, you may have a bunch of `ON_CALL`s in your test fixture to set the common mock behavior shared by all tests in the same group, and write (scarcely) different `EXPECT_CALL`s in different `TEST_F`s to verify different aspects of the code's behavior. Compared with the style where each `TEST` has many `EXPECT_CALL`s, this leads to tests that are more resilient to implementational changes (and thus less likely to require maintenance) and makes the intent of the tests more obvious (so they are easier to maintain when you do need to maintain them). ## Ignoring Uninteresting Calls ## If you are not interested in how a mock method is called, just don't say anything about it. In this case, if the method is ever called, Google Mock will perform its default action to allow the test program to continue. If you are not happy with the default action taken by Google Mock, you can override it using `DefaultValue::Set()` (described later in this document) or `ON_CALL()`. Please note that once you expressed interest in a particular mock method (via `EXPECT_CALL()`), all invocations to it must match some expectation. If this function is called but the arguments don't match any `EXPECT_CALL()` statement, it will be an error. ## Disallowing Unexpected Calls ## If a mock method shouldn't be called at all, explicitly say so: ``` using ::testing::_; ... EXPECT_CALL(foo, Bar(_)) .Times(0); ``` If some calls to the method are allowed, but the rest are not, just list all the expected calls: ``` using ::testing::AnyNumber; using ::testing::Gt; ... EXPECT_CALL(foo, Bar(5)); EXPECT_CALL(foo, Bar(Gt(10))) .Times(AnyNumber()); ``` A call to `foo.Bar()` that doesn't match any of the `EXPECT_CALL()` statements will be an error. ## Expecting Ordered Calls ## Although an `EXPECT_CALL()` statement defined earlier takes precedence when Google Mock tries to match a function call with an expectation, by default calls don't have to happen in the order `EXPECT_CALL()` statements are written. For example, if the arguments match the matchers in the third `EXPECT_CALL()`, but not those in the first two, then the third expectation will be used. If you would rather have all calls occur in the order of the expectations, put the `EXPECT_CALL()` statements in a block where you define a variable of type `InSequence`: ``` using ::testing::_; using ::testing::InSequence; { InSequence s; EXPECT_CALL(foo, DoThis(5)); EXPECT_CALL(bar, DoThat(_)) .Times(2); EXPECT_CALL(foo, DoThis(6)); } ``` In this example, we expect a call to `foo.DoThis(5)`, followed by two calls to `bar.DoThat()` where the argument can be anything, which are in turn followed by a call to `foo.DoThis(6)`. If a call occurred out-of-order, Google Mock will report an error. ## Expecting Partially Ordered Calls ## Sometimes requiring everything to occur in a predetermined order can lead to brittle tests. For example, we may care about `A` occurring before both `B` and `C`, but aren't interested in the relative order of `B` and `C`. In this case, the test should reflect our real intent, instead of being overly constraining. Google Mock allows you to impose an arbitrary DAG (directed acyclic graph) on the calls. One way to express the DAG is to use the [After](http://code.google.com/p/googlemock/wiki/V1_7_CheatSheet#The_After_Clause) clause of `EXPECT_CALL`. Another way is via the `InSequence()` clause (not the same as the `InSequence` class), which we borrowed from jMock 2. It's less flexible than `After()`, but more convenient when you have long chains of sequential calls, as it doesn't require you to come up with different names for the expectations in the chains. Here's how it works: If we view `EXPECT_CALL()` statements as nodes in a graph, and add an edge from node A to node B wherever A must occur before B, we can get a DAG. We use the term "sequence" to mean a directed path in this DAG. Now, if we decompose the DAG into sequences, we just need to know which sequences each `EXPECT_CALL()` belongs to in order to be able to reconstruct the orginal DAG. So, to specify the partial order on the expectations we need to do two things: first to define some `Sequence` objects, and then for each `EXPECT_CALL()` say which `Sequence` objects it is part of. Expectations in the same sequence must occur in the order they are written. For example, ``` using ::testing::Sequence; Sequence s1, s2; EXPECT_CALL(foo, A()) .InSequence(s1, s2); EXPECT_CALL(bar, B()) .InSequence(s1); EXPECT_CALL(bar, C()) .InSequence(s2); EXPECT_CALL(foo, D()) .InSequence(s2); ``` specifies the following DAG (where `s1` is `A -> B`, and `s2` is `A -> C -> D`): ``` +---> B | A ---| | +---> C ---> D ``` This means that A must occur before B and C, and C must occur before D. There's no restriction about the order other than these. ## Controlling When an Expectation Retires ## When a mock method is called, Google Mock only consider expectations that are still active. An expectation is active when created, and becomes inactive (aka _retires_) when a call that has to occur later has occurred. For example, in ``` using ::testing::_; using ::testing::Sequence; Sequence s1, s2; EXPECT_CALL(log, Log(WARNING, _, "File too large.")) // #1 .Times(AnyNumber()) .InSequence(s1, s2); EXPECT_CALL(log, Log(WARNING, _, "Data set is empty.")) // #2 .InSequence(s1); EXPECT_CALL(log, Log(WARNING, _, "User not found.")) // #3 .InSequence(s2); ``` as soon as either #2 or #3 is matched, #1 will retire. If a warning `"File too large."` is logged after this, it will be an error. Note that an expectation doesn't retire automatically when it's saturated. For example, ``` using ::testing::_; ... EXPECT_CALL(log, Log(WARNING, _, _)); // #1 EXPECT_CALL(log, Log(WARNING, _, "File too large.")); // #2 ``` says that there will be exactly one warning with the message `"File too large."`. If the second warning contains this message too, #2 will match again and result in an upper-bound-violated error. If this is not what you want, you can ask an expectation to retire as soon as it becomes saturated: ``` using ::testing::_; ... EXPECT_CALL(log, Log(WARNING, _, _)); // #1 EXPECT_CALL(log, Log(WARNING, _, "File too large.")) // #2 .RetiresOnSaturation(); ``` Here #2 can be used only once, so if you have two warnings with the message `"File too large."`, the first will match #2 and the second will match #1 - there will be no error. # Using Actions # ## Returning References from Mock Methods ## If a mock function's return type is a reference, you need to use `ReturnRef()` instead of `Return()` to return a result: ``` using ::testing::ReturnRef; class MockFoo : public Foo { public: MOCK_METHOD0(GetBar, Bar&()); }; ... MockFoo foo; Bar bar; EXPECT_CALL(foo, GetBar()) .WillOnce(ReturnRef(bar)); ``` ## Returning Live Values from Mock Methods ## The `Return(x)` action saves a copy of `x` when the action is _created_, and always returns the same value whenever it's executed. Sometimes you may want to instead return the _live_ value of `x` (i.e. its value at the time when the action is _executed_.). If the mock function's return type is a reference, you can do it using `ReturnRef(x)`, as shown in the previous recipe ("Returning References from Mock Methods"). However, Google Mock doesn't let you use `ReturnRef()` in a mock function whose return type is not a reference, as doing that usually indicates a user error. So, what shall you do? You may be tempted to try `ByRef()`: ``` using testing::ByRef; using testing::Return; class MockFoo : public Foo { public: MOCK_METHOD0(GetValue, int()); }; ... int x = 0; MockFoo foo; EXPECT_CALL(foo, GetValue()) .WillRepeatedly(Return(ByRef(x))); x = 42; EXPECT_EQ(42, foo.GetValue()); ``` Unfortunately, it doesn't work here. The above code will fail with error: ``` Value of: foo.GetValue() Actual: 0 Expected: 42 ``` The reason is that `Return(value)` converts `value` to the actual return type of the mock function at the time when the action is _created_, not when it is _executed_. (This behavior was chosen for the action to be safe when `value` is a proxy object that references some temporary objects.) As a result, `ByRef(x)` is converted to an `int` value (instead of a `const int&`) when the expectation is set, and `Return(ByRef(x))` will always return 0. `ReturnPointee(pointer)` was provided to solve this problem specifically. It returns the value pointed to by `pointer` at the time the action is _executed_: ``` using testing::ReturnPointee; ... int x = 0; MockFoo foo; EXPECT_CALL(foo, GetValue()) .WillRepeatedly(ReturnPointee(&x)); // Note the & here. x = 42; EXPECT_EQ(42, foo.GetValue()); // This will succeed now. ``` ## Combining Actions ## Want to do more than one thing when a function is called? That's fine. `DoAll()` allow you to do sequence of actions every time. Only the return value of the last action in the sequence will be used. ``` using ::testing::DoAll; class MockFoo : public Foo { public: MOCK_METHOD1(Bar, bool(int n)); }; ... EXPECT_CALL(foo, Bar(_)) .WillOnce(DoAll(action_1, action_2, ... action_n)); ``` ## Mocking Side Effects ## Sometimes a method exhibits its effect not via returning a value but via side effects. For example, it may change some global state or modify an output argument. To mock side effects, in general you can define your own action by implementing `::testing::ActionInterface`. If all you need to do is to change an output argument, the built-in `SetArgPointee()` action is convenient: ``` using ::testing::SetArgPointee; class MockMutator : public Mutator { public: MOCK_METHOD2(Mutate, void(bool mutate, int* value)); ... }; ... MockMutator mutator; EXPECT_CALL(mutator, Mutate(true, _)) .WillOnce(SetArgPointee<1>(5)); ``` In this example, when `mutator.Mutate()` is called, we will assign 5 to the `int` variable pointed to by argument #1 (0-based). `SetArgPointee()` conveniently makes an internal copy of the value you pass to it, removing the need to keep the value in scope and alive. The implication however is that the value must have a copy constructor and assignment operator. If the mock method also needs to return a value as well, you can chain `SetArgPointee()` with `Return()` using `DoAll()`: ``` using ::testing::_; using ::testing::Return; using ::testing::SetArgPointee; class MockMutator : public Mutator { public: ... MOCK_METHOD1(MutateInt, bool(int* value)); }; ... MockMutator mutator; EXPECT_CALL(mutator, MutateInt(_)) .WillOnce(DoAll(SetArgPointee<0>(5), Return(true))); ``` If the output argument is an array, use the `SetArrayArgument(first, last)` action instead. It copies the elements in source range `[first, last)` to the array pointed to by the `N`-th (0-based) argument: ``` using ::testing::NotNull; using ::testing::SetArrayArgument; class MockArrayMutator : public ArrayMutator { public: MOCK_METHOD2(Mutate, void(int* values, int num_values)); ... }; ... MockArrayMutator mutator; int values[5] = { 1, 2, 3, 4, 5 }; EXPECT_CALL(mutator, Mutate(NotNull(), 5)) .WillOnce(SetArrayArgument<0>(values, values + 5)); ``` This also works when the argument is an output iterator: ``` using ::testing::_; using ::testing::SeArrayArgument; class MockRolodex : public Rolodex { public: MOCK_METHOD1(GetNames, void(std::back_insert_iterator >)); ... }; ... MockRolodex rolodex; vector names; names.push_back("George"); names.push_back("John"); names.push_back("Thomas"); EXPECT_CALL(rolodex, GetNames(_)) .WillOnce(SetArrayArgument<0>(names.begin(), names.end())); ``` ## Changing a Mock Object's Behavior Based on the State ## If you expect a call to change the behavior of a mock object, you can use `::testing::InSequence` to specify different behaviors before and after the call: ``` using ::testing::InSequence; using ::testing::Return; ... { InSequence seq; EXPECT_CALL(my_mock, IsDirty()) .WillRepeatedly(Return(true)); EXPECT_CALL(my_mock, Flush()); EXPECT_CALL(my_mock, IsDirty()) .WillRepeatedly(Return(false)); } my_mock.FlushIfDirty(); ``` This makes `my_mock.IsDirty()` return `true` before `my_mock.Flush()` is called and return `false` afterwards. If the behavior change is more complex, you can store the effects in a variable and make a mock method get its return value from that variable: ``` using ::testing::_; using ::testing::SaveArg; using ::testing::Return; ACTION_P(ReturnPointee, p) { return *p; } ... int previous_value = 0; EXPECT_CALL(my_mock, GetPrevValue()) .WillRepeatedly(ReturnPointee(&previous_value)); EXPECT_CALL(my_mock, UpdateValue(_)) .WillRepeatedly(SaveArg<0>(&previous_value)); my_mock.DoSomethingToUpdateValue(); ``` Here `my_mock.GetPrevValue()` will always return the argument of the last `UpdateValue()` call. ## Setting the Default Value for a Return Type ## If a mock method's return type is a built-in C++ type or pointer, by default it will return 0 when invoked. You only need to specify an action if this default value doesn't work for you. Sometimes, you may want to change this default value, or you may want to specify a default value for types Google Mock doesn't know about. You can do this using the `::testing::DefaultValue` class template: ``` class MockFoo : public Foo { public: MOCK_METHOD0(CalculateBar, Bar()); }; ... Bar default_bar; // Sets the default return value for type Bar. DefaultValue::Set(default_bar); MockFoo foo; // We don't need to specify an action here, as the default // return value works for us. EXPECT_CALL(foo, CalculateBar()); foo.CalculateBar(); // This should return default_bar. // Unsets the default return value. DefaultValue::Clear(); ``` Please note that changing the default value for a type can make you tests hard to understand. We recommend you to use this feature judiciously. For example, you may want to make sure the `Set()` and `Clear()` calls are right next to the code that uses your mock. ## Setting the Default Actions for a Mock Method ## You've learned how to change the default value of a given type. However, this may be too coarse for your purpose: perhaps you have two mock methods with the same return type and you want them to have different behaviors. The `ON_CALL()` macro allows you to customize your mock's behavior at the method level: ``` using ::testing::_; using ::testing::AnyNumber; using ::testing::Gt; using ::testing::Return; ... ON_CALL(foo, Sign(_)) .WillByDefault(Return(-1)); ON_CALL(foo, Sign(0)) .WillByDefault(Return(0)); ON_CALL(foo, Sign(Gt(0))) .WillByDefault(Return(1)); EXPECT_CALL(foo, Sign(_)) .Times(AnyNumber()); foo.Sign(5); // This should return 1. foo.Sign(-9); // This should return -1. foo.Sign(0); // This should return 0. ``` As you may have guessed, when there are more than one `ON_CALL()` statements, the news order take precedence over the older ones. In other words, the **last** one that matches the function arguments will be used. This matching order allows you to set up the common behavior in a mock object's constructor or the test fixture's set-up phase and specialize the mock's behavior later. ## Using Functions/Methods/Functors as Actions ## If the built-in actions don't suit you, you can easily use an existing function, method, or functor as an action: ``` using ::testing::_; using ::testing::Invoke; class MockFoo : public Foo { public: MOCK_METHOD2(Sum, int(int x, int y)); MOCK_METHOD1(ComplexJob, bool(int x)); }; int CalculateSum(int x, int y) { return x + y; } class Helper { public: bool ComplexJob(int x); }; ... MockFoo foo; Helper helper; EXPECT_CALL(foo, Sum(_, _)) .WillOnce(Invoke(CalculateSum)); EXPECT_CALL(foo, ComplexJob(_)) .WillOnce(Invoke(&helper, &Helper::ComplexJob)); foo.Sum(5, 6); // Invokes CalculateSum(5, 6). foo.ComplexJob(10); // Invokes helper.ComplexJob(10); ``` The only requirement is that the type of the function, etc must be _compatible_ with the signature of the mock function, meaning that the latter's arguments can be implicitly converted to the corresponding arguments of the former, and the former's return type can be implicitly converted to that of the latter. So, you can invoke something whose type is _not_ exactly the same as the mock function, as long as it's safe to do so - nice, huh? ## Invoking a Function/Method/Functor Without Arguments ## `Invoke()` is very useful for doing actions that are more complex. It passes the mock function's arguments to the function or functor being invoked such that the callee has the full context of the call to work with. If the invoked function is not interested in some or all of the arguments, it can simply ignore them. Yet, a common pattern is that a test author wants to invoke a function without the arguments of the mock function. `Invoke()` allows her to do that using a wrapper function that throws away the arguments before invoking an underlining nullary function. Needless to say, this can be tedious and obscures the intent of the test. `InvokeWithoutArgs()` solves this problem. It's like `Invoke()` except that it doesn't pass the mock function's arguments to the callee. Here's an example: ``` using ::testing::_; using ::testing::InvokeWithoutArgs; class MockFoo : public Foo { public: MOCK_METHOD1(ComplexJob, bool(int n)); }; bool Job1() { ... } ... MockFoo foo; EXPECT_CALL(foo, ComplexJob(_)) .WillOnce(InvokeWithoutArgs(Job1)); foo.ComplexJob(10); // Invokes Job1(). ``` ## Invoking an Argument of the Mock Function ## Sometimes a mock function will receive a function pointer or a functor (in other words, a "callable") as an argument, e.g. ``` class MockFoo : public Foo { public: MOCK_METHOD2(DoThis, bool(int n, bool (*fp)(int))); }; ``` and you may want to invoke this callable argument: ``` using ::testing::_; ... MockFoo foo; EXPECT_CALL(foo, DoThis(_, _)) .WillOnce(...); // Will execute (*fp)(5), where fp is the // second argument DoThis() receives. ``` Arghh, you need to refer to a mock function argument but C++ has no lambda (yet), so you have to define your own action. :-( Or do you really? Well, Google Mock has an action to solve _exactly_ this problem: ``` InvokeArgument(arg_1, arg_2, ..., arg_m) ``` will invoke the `N`-th (0-based) argument the mock function receives, with `arg_1`, `arg_2`, ..., and `arg_m`. No matter if the argument is a function pointer or a functor, Google Mock handles them both. With that, you could write: ``` using ::testing::_; using ::testing::InvokeArgument; ... EXPECT_CALL(foo, DoThis(_, _)) .WillOnce(InvokeArgument<1>(5)); // Will execute (*fp)(5), where fp is the // second argument DoThis() receives. ``` What if the callable takes an argument by reference? No problem - just wrap it inside `ByRef()`: ``` ... MOCK_METHOD1(Bar, bool(bool (*fp)(int, const Helper&))); ... using ::testing::_; using ::testing::ByRef; using ::testing::InvokeArgument; ... MockFoo foo; Helper helper; ... EXPECT_CALL(foo, Bar(_)) .WillOnce(InvokeArgument<0>(5, ByRef(helper))); // ByRef(helper) guarantees that a reference to helper, not a copy of it, // will be passed to the callable. ``` What if the callable takes an argument by reference and we do **not** wrap the argument in `ByRef()`? Then `InvokeArgument()` will _make a copy_ of the argument, and pass a _reference to the copy_, instead of a reference to the original value, to the callable. This is especially handy when the argument is a temporary value: ``` ... MOCK_METHOD1(DoThat, bool(bool (*f)(const double& x, const string& s))); ... using ::testing::_; using ::testing::InvokeArgument; ... MockFoo foo; ... EXPECT_CALL(foo, DoThat(_)) .WillOnce(InvokeArgument<0>(5.0, string("Hi"))); // Will execute (*f)(5.0, string("Hi")), where f is the function pointer // DoThat() receives. Note that the values 5.0 and string("Hi") are // temporary and dead once the EXPECT_CALL() statement finishes. Yet // it's fine to perform this action later, since a copy of the values // are kept inside the InvokeArgument action. ``` ## Ignoring an Action's Result ## Sometimes you have an action that returns _something_, but you need an action that returns `void` (perhaps you want to use it in a mock function that returns `void`, or perhaps it needs to be used in `DoAll()` and it's not the last in the list). `IgnoreResult()` lets you do that. For example: ``` using ::testing::_; using ::testing::Invoke; using ::testing::Return; int Process(const MyData& data); string DoSomething(); class MockFoo : public Foo { public: MOCK_METHOD1(Abc, void(const MyData& data)); MOCK_METHOD0(Xyz, bool()); }; ... MockFoo foo; EXPECT_CALL(foo, Abc(_)) // .WillOnce(Invoke(Process)); // The above line won't compile as Process() returns int but Abc() needs // to return void. .WillOnce(IgnoreResult(Invoke(Process))); EXPECT_CALL(foo, Xyz()) .WillOnce(DoAll(IgnoreResult(Invoke(DoSomething)), // Ignores the string DoSomething() returns. Return(true))); ``` Note that you **cannot** use `IgnoreResult()` on an action that already returns `void`. Doing so will lead to ugly compiler errors. ## Selecting an Action's Arguments ## Say you have a mock function `Foo()` that takes seven arguments, and you have a custom action that you want to invoke when `Foo()` is called. Trouble is, the custom action only wants three arguments: ``` using ::testing::_; using ::testing::Invoke; ... MOCK_METHOD7(Foo, bool(bool visible, const string& name, int x, int y, const map, double>& weight, double min_weight, double max_wight)); ... bool IsVisibleInQuadrant1(bool visible, int x, int y) { return visible && x >= 0 && y >= 0; } ... EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) .WillOnce(Invoke(IsVisibleInQuadrant1)); // Uh, won't compile. :-( ``` To please the compiler God, you can to define an "adaptor" that has the same signature as `Foo()` and calls the custom action with the right arguments: ``` using ::testing::_; using ::testing::Invoke; bool MyIsVisibleInQuadrant1(bool visible, const string& name, int x, int y, const map, double>& weight, double min_weight, double max_wight) { return IsVisibleInQuadrant1(visible, x, y); } ... EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) .WillOnce(Invoke(MyIsVisibleInQuadrant1)); // Now it works. ``` But isn't this awkward? Google Mock provides a generic _action adaptor_, so you can spend your time minding more important business than writing your own adaptors. Here's the syntax: ``` WithArgs(action) ``` creates an action that passes the arguments of the mock function at the given indices (0-based) to the inner `action` and performs it. Using `WithArgs`, our original example can be written as: ``` using ::testing::_; using ::testing::Invoke; using ::testing::WithArgs; ... EXPECT_CALL(mock, Foo(_, _, _, _, _, _, _)) .WillOnce(WithArgs<0, 2, 3>(Invoke(IsVisibleInQuadrant1))); // No need to define your own adaptor. ``` For better readability, Google Mock also gives you: * `WithoutArgs(action)` when the inner `action` takes _no_ argument, and * `WithArg(action)` (no `s` after `Arg`) when the inner `action` takes _one_ argument. As you may have realized, `InvokeWithoutArgs(...)` is just syntactic sugar for `WithoutArgs(Inovke(...))`. Here are more tips: * The inner action used in `WithArgs` and friends does not have to be `Invoke()` -- it can be anything. * You can repeat an argument in the argument list if necessary, e.g. `WithArgs<2, 3, 3, 5>(...)`. * You can change the order of the arguments, e.g. `WithArgs<3, 2, 1>(...)`. * The types of the selected arguments do _not_ have to match the signature of the inner action exactly. It works as long as they can be implicitly converted to the corresponding arguments of the inner action. For example, if the 4-th argument of the mock function is an `int` and `my_action` takes a `double`, `WithArg<4>(my_action)` will work. ## Ignoring Arguments in Action Functions ## The selecting-an-action's-arguments recipe showed us one way to make a mock function and an action with incompatible argument lists fit together. The downside is that wrapping the action in `WithArgs<...>()` can get tedious for people writing the tests. If you are defining a function, method, or functor to be used with `Invoke*()`, and you are not interested in some of its arguments, an alternative to `WithArgs` is to declare the uninteresting arguments as `Unused`. This makes the definition less cluttered and less fragile in case the types of the uninteresting arguments change. It could also increase the chance the action function can be reused. For example, given ``` MOCK_METHOD3(Foo, double(const string& label, double x, double y)); MOCK_METHOD3(Bar, double(int index, double x, double y)); ``` instead of ``` using ::testing::_; using ::testing::Invoke; double DistanceToOriginWithLabel(const string& label, double x, double y) { return sqrt(x*x + y*y); } double DistanceToOriginWithIndex(int index, double x, double y) { return sqrt(x*x + y*y); } ... EXEPCT_CALL(mock, Foo("abc", _, _)) .WillOnce(Invoke(DistanceToOriginWithLabel)); EXEPCT_CALL(mock, Bar(5, _, _)) .WillOnce(Invoke(DistanceToOriginWithIndex)); ``` you could write ``` using ::testing::_; using ::testing::Invoke; using ::testing::Unused; double DistanceToOrigin(Unused, double x, double y) { return sqrt(x*x + y*y); } ... EXEPCT_CALL(mock, Foo("abc", _, _)) .WillOnce(Invoke(DistanceToOrigin)); EXEPCT_CALL(mock, Bar(5, _, _)) .WillOnce(Invoke(DistanceToOrigin)); ``` ## Sharing Actions ## Just like matchers, a Google Mock action object consists of a pointer to a ref-counted implementation object. Therefore copying actions is also allowed and very efficient. When the last action that references the implementation object dies, the implementation object will be deleted. If you have some complex action that you want to use again and again, you may not have to build it from scratch everytime. If the action doesn't have an internal state (i.e. if it always does the same thing no matter how many times it has been called), you can assign it to an action variable and use that variable repeatedly. For example: ``` Action set_flag = DoAll(SetArgPointee<0>(5), Return(true)); ... use set_flag in .WillOnce() and .WillRepeatedly() ... ``` However, if the action has its own state, you may be surprised if you share the action object. Suppose you have an action factory `IncrementCounter(init)` which creates an action that increments and returns a counter whose initial value is `init`, using two actions created from the same expression and using a shared action will exihibit different behaviors. Example: ``` EXPECT_CALL(foo, DoThis()) .WillRepeatedly(IncrementCounter(0)); EXPECT_CALL(foo, DoThat()) .WillRepeatedly(IncrementCounter(0)); foo.DoThis(); // Returns 1. foo.DoThis(); // Returns 2. foo.DoThat(); // Returns 1 - Blah() uses a different // counter than Bar()'s. ``` versus ``` Action increment = IncrementCounter(0); EXPECT_CALL(foo, DoThis()) .WillRepeatedly(increment); EXPECT_CALL(foo, DoThat()) .WillRepeatedly(increment); foo.DoThis(); // Returns 1. foo.DoThis(); // Returns 2. foo.DoThat(); // Returns 3 - the counter is shared. ``` # Misc Recipes on Using Google Mock # ## Making the Compilation Faster ## Believe it or not, the _vast majority_ of the time spent on compiling a mock class is in generating its constructor and destructor, as they perform non-trivial tasks (e.g. verification of the expectations). What's more, mock methods with different signatures have different types and thus their constructors/destructors need to be generated by the compiler separately. As a result, if you mock many different types of methods, compiling your mock class can get really slow. If you are experiencing slow compilation, you can move the definition of your mock class' constructor and destructor out of the class body and into a `.cpp` file. This way, even if you `#include` your mock class in N files, the compiler only needs to generate its constructor and destructor once, resulting in a much faster compilation. Let's illustrate the idea using an example. Here's the definition of a mock class before applying this recipe: ``` // File mock_foo.h. ... class MockFoo : public Foo { public: // Since we don't declare the constructor or the destructor, // the compiler will generate them in every translation unit // where this mock class is used. MOCK_METHOD0(DoThis, int()); MOCK_METHOD1(DoThat, bool(const char* str)); ... more mock methods ... }; ``` After the change, it would look like: ``` // File mock_foo.h. ... class MockFoo : public Foo { public: // The constructor and destructor are declared, but not defined, here. MockFoo(); virtual ~MockFoo(); MOCK_METHOD0(DoThis, int()); MOCK_METHOD1(DoThat, bool(const char* str)); ... more mock methods ... }; ``` and ``` // File mock_foo.cpp. #include "path/to/mock_foo.h" // The definitions may appear trivial, but the functions actually do a // lot of things through the constructors/destructors of the member // variables used to implement the mock methods. MockFoo::MockFoo() {} MockFoo::~MockFoo() {} ``` ## Forcing a Verification ## When it's being destoyed, your friendly mock object will automatically verify that all expectations on it have been satisfied, and will generate [Google Test](http://code.google.com/p/googletest/) failures if not. This is convenient as it leaves you with one less thing to worry about. That is, unless you are not sure if your mock object will be destoyed. How could it be that your mock object won't eventually be destroyed? Well, it might be created on the heap and owned by the code you are testing. Suppose there's a bug in that code and it doesn't delete the mock object properly - you could end up with a passing test when there's actually a bug. Using a heap checker is a good idea and can alleviate the concern, but its implementation may not be 100% reliable. So, sometimes you do want to _force_ Google Mock to verify a mock object before it is (hopefully) destructed. You can do this with `Mock::VerifyAndClearExpectations(&mock_object)`: ``` TEST(MyServerTest, ProcessesRequest) { using ::testing::Mock; MockFoo* const foo = new MockFoo; EXPECT_CALL(*foo, ...)...; // ... other expectations ... // server now owns foo. MyServer server(foo); server.ProcessRequest(...); // In case that server's destructor will forget to delete foo, // this will verify the expectations anyway. Mock::VerifyAndClearExpectations(foo); } // server is destroyed when it goes out of scope here. ``` **Tip:** The `Mock::VerifyAndClearExpectations()` function returns a `bool` to indicate whether the verification was successful (`true` for yes), so you can wrap that function call inside a `ASSERT_TRUE()` if there is no point going further when the verification has failed. ## Using Check Points ## Sometimes you may want to "reset" a mock object at various check points in your test: at each check point, you verify that all existing expectations on the mock object have been satisfied, and then you set some new expectations on it as if it's newly created. This allows you to work with a mock object in "phases" whose sizes are each manageable. One such scenario is that in your test's `SetUp()` function, you may want to put the object you are testing into a certain state, with the help from a mock object. Once in the desired state, you want to clear all expectations on the mock, such that in the `TEST_F` body you can set fresh expectations on it. As you may have figured out, the `Mock::VerifyAndClearExpectations()` function we saw in the previous recipe can help you here. Or, if you are using `ON_CALL()` to set default actions on the mock object and want to clear the default actions as well, use `Mock::VerifyAndClear(&mock_object)` instead. This function does what `Mock::VerifyAndClearExpectations(&mock_object)` does and returns the same `bool`, **plus** it clears the `ON_CALL()` statements on `mock_object` too. Another trick you can use to achieve the same effect is to put the expectations in sequences and insert calls to a dummy "check-point" function at specific places. Then you can verify that the mock function calls do happen at the right time. For example, if you are exercising code: ``` Foo(1); Foo(2); Foo(3); ``` and want to verify that `Foo(1)` and `Foo(3)` both invoke `mock.Bar("a")`, but `Foo(2)` doesn't invoke anything. You can write: ``` using ::testing::MockFunction; TEST(FooTest, InvokesBarCorrectly) { MyMock mock; // Class MockFunction has exactly one mock method. It is named // Call() and has type F. MockFunction check; { InSequence s; EXPECT_CALL(mock, Bar("a")); EXPECT_CALL(check, Call("1")); EXPECT_CALL(check, Call("2")); EXPECT_CALL(mock, Bar("a")); } Foo(1); check.Call("1"); Foo(2); check.Call("2"); Foo(3); } ``` The expectation spec says that the first `Bar("a")` must happen before check point "1", the second `Bar("a")` must happen after check point "2", and nothing should happen between the two check points. The explicit check points make it easy to tell which `Bar("a")` is called by which call to `Foo()`. ## Mocking Destructors ## Sometimes you want to make sure a mock object is destructed at the right time, e.g. after `bar->A()` is called but before `bar->B()` is called. We already know that you can specify constraints on the order of mock function calls, so all we need to do is to mock the destructor of the mock function. This sounds simple, except for one problem: a destructor is a special function with special syntax and special semantics, and the `MOCK_METHOD0` macro doesn't work for it: ``` MOCK_METHOD0(~MockFoo, void()); // Won't compile! ``` The good news is that you can use a simple pattern to achieve the same effect. First, add a mock function `Die()` to your mock class and call it in the destructor, like this: ``` class MockFoo : public Foo { ... // Add the following two lines to the mock class. MOCK_METHOD0(Die, void()); virtual ~MockFoo() { Die(); } }; ``` (If the name `Die()` clashes with an existing symbol, choose another name.) Now, we have translated the problem of testing when a `MockFoo` object dies to testing when its `Die()` method is called: ``` MockFoo* foo = new MockFoo; MockBar* bar = new MockBar; ... { InSequence s; // Expects *foo to die after bar->A() and before bar->B(). EXPECT_CALL(*bar, A()); EXPECT_CALL(*foo, Die()); EXPECT_CALL(*bar, B()); } ``` And that's that. ## Using Google Mock and Threads ## **IMPORTANT NOTE:** What we describe in this recipe is **ONLY** true on platforms where Google Mock is thread-safe. Currently these are only platforms that support the pthreads library (this includes Linux and Mac). To make it thread-safe on other platforms we only need to implement some synchronization operations in `"gtest/internal/gtest-port.h"`. In a **unit** test, it's best if you could isolate and test a piece of code in a single-threaded context. That avoids race conditions and dead locks, and makes debugging your test much easier. Yet many programs are multi-threaded, and sometimes to test something we need to pound on it from more than one thread. Google Mock works for this purpose too. Remember the steps for using a mock: 1. Create a mock object `foo`. 1. Set its default actions and expectations using `ON_CALL()` and `EXPECT_CALL()`. 1. The code under test calls methods of `foo`. 1. Optionally, verify and reset the mock. 1. Destroy the mock yourself, or let the code under test destroy it. The destructor will automatically verify it. If you follow the following simple rules, your mocks and threads can live happily togeter: * Execute your _test code_ (as opposed to the code being tested) in _one_ thread. This makes your test easy to follow. * Obviously, you can do step #1 without locking. * When doing step #2 and #5, make sure no other thread is accessing `foo`. Obvious too, huh? * #3 and #4 can be done either in one thread or in multiple threads - anyway you want. Google Mock takes care of the locking, so you don't have to do any - unless required by your test logic. If you violate the rules (for example, if you set expectations on a mock while another thread is calling its methods), you get undefined behavior. That's not fun, so don't do it. Google Mock guarantees that the action for a mock function is done in the same thread that called the mock function. For example, in ``` EXPECT_CALL(mock, Foo(1)) .WillOnce(action1); EXPECT_CALL(mock, Foo(2)) .WillOnce(action2); ``` if `Foo(1)` is called in thread 1 and `Foo(2)` is called in thread 2, Google Mock will execute `action1` in thread 1 and `action2` in thread 2. Google Mock does _not_ impose a sequence on actions performed in different threads (doing so may create deadlocks as the actions may need to cooperate). This means that the execution of `action1` and `action2` in the above example _may_ interleave. If this is a problem, you should add proper synchronization logic to `action1` and `action2` to make the test thread-safe. Also, remember that `DefaultValue` is a global resource that potentially affects _all_ living mock objects in your program. Naturally, you won't want to mess with it from multiple threads or when there still are mocks in action. ## Controlling How Much Information Google Mock Prints ## When Google Mock sees something that has the potential of being an error (e.g. a mock function with no expectation is called, a.k.a. an uninteresting call, which is allowed but perhaps you forgot to explicitly ban the call), it prints some warning messages, including the arguments of the function and the return value. Hopefully this will remind you to take a look and see if there is indeed a problem. Sometimes you are confident that your tests are correct and may not appreciate such friendly messages. Some other times, you are debugging your tests or learning about the behavior of the code you are testing, and wish you could observe every mock call that happens (including argument values and the return value). Clearly, one size doesn't fit all. You can control how much Google Mock tells you using the `--gmock_verbose=LEVEL` command-line flag, where `LEVEL` is a string with three possible values: * `info`: Google Mock will print all informational messages, warnings, and errors (most verbose). At this setting, Google Mock will also log any calls to the `ON_CALL/EXPECT_CALL` macros. * `warning`: Google Mock will print both warnings and errors (less verbose). This is the default. * `error`: Google Mock will print errors only (least verbose). Alternatively, you can adjust the value of that flag from within your tests like so: ``` ::testing::FLAGS_gmock_verbose = "error"; ``` Now, judiciously use the right flag to enable Google Mock serve you better! ## Gaining Super Vision into Mock Calls ## You have a test using Google Mock. It fails: Google Mock tells you that some expectations aren't satisfied. However, you aren't sure why: Is there a typo somewhere in the matchers? Did you mess up the order of the `EXPECT_CALL`s? Or is the code under test doing something wrong? How can you find out the cause? Won't it be nice if you have X-ray vision and can actually see the trace of all `EXPECT_CALL`s and mock method calls as they are made? For each call, would you like to see its actual argument values and which `EXPECT_CALL` Google Mock thinks it matches? You can unlock this power by running your test with the `--gmock_verbose=info` flag. For example, given the test program: ``` using testing::_; using testing::HasSubstr; using testing::Return; class MockFoo { public: MOCK_METHOD2(F, void(const string& x, const string& y)); }; TEST(Foo, Bar) { MockFoo mock; EXPECT_CALL(mock, F(_, _)).WillRepeatedly(Return()); EXPECT_CALL(mock, F("a", "b")); EXPECT_CALL(mock, F("c", HasSubstr("d"))); mock.F("a", "good"); mock.F("a", "b"); } ``` if you run it with `--gmock_verbose=info`, you will see this output: ``` [ RUN ] Foo.Bar foo_test.cc:14: EXPECT_CALL(mock, F(_, _)) invoked foo_test.cc:15: EXPECT_CALL(mock, F("a", "b")) invoked foo_test.cc:16: EXPECT_CALL(mock, F("c", HasSubstr("d"))) invoked foo_test.cc:14: Mock function call matches EXPECT_CALL(mock, F(_, _))... Function call: F(@0x7fff7c8dad40"a", @0x7fff7c8dad10"good") foo_test.cc:15: Mock function call matches EXPECT_CALL(mock, F("a", "b"))... Function call: F(@0x7fff7c8dada0"a", @0x7fff7c8dad70"b") foo_test.cc:16: Failure Actual function call count doesn't match EXPECT_CALL(mock, F("c", HasSubstr("d")))... Expected: to be called once Actual: never called - unsatisfied and active [ FAILED ] Foo.Bar ``` Suppose the bug is that the `"c"` in the third `EXPECT_CALL` is a typo and should actually be `"a"`. With the above message, you should see that the actual `F("a", "good")` call is matched by the first `EXPECT_CALL`, not the third as you thought. From that it should be obvious that the third `EXPECT_CALL` is written wrong. Case solved. ## Running Tests in Emacs ## If you build and run your tests in Emacs, the source file locations of Google Mock and [Google Test](http://code.google.com/p/googletest/) errors will be highlighted. Just press `` on one of them and you'll be taken to the offending line. Or, you can just type `C-x `` to jump to the next error. To make it even easier, you can add the following lines to your `~/.emacs` file: ``` (global-set-key "\M-m" 'compile) ; m is for make (global-set-key [M-down] 'next-error) (global-set-key [M-up] '(lambda () (interactive) (next-error -1))) ``` Then you can type `M-m` to start a build, or `M-up`/`M-down` to move back and forth between errors. ## Fusing Google Mock Source Files ## Google Mock's implementation consists of dozens of files (excluding its own tests). Sometimes you may want them to be packaged up in fewer files instead, such that you can easily copy them to a new machine and start hacking there. For this we provide an experimental Python script `fuse_gmock_files.py` in the `scripts/` directory (starting with release 1.2.0). Assuming you have Python 2.4 or above installed on your machine, just go to that directory and run ``` python fuse_gmock_files.py OUTPUT_DIR ``` and you should see an `OUTPUT_DIR` directory being created with files `gtest/gtest.h`, `gmock/gmock.h`, and `gmock-gtest-all.cc` in it. These three files contain everything you need to use Google Mock (and Google Test). Just copy them to anywhere you want and you are ready to write tests and use mocks. You can use the [scrpts/test/Makefile](http://code.google.com/p/googlemock/source/browse/trunk/scripts/test/Makefile) file as an example on how to compile your tests against them. # Extending Google Mock # ## Writing New Matchers Quickly ## The `MATCHER*` family of macros can be used to define custom matchers easily. The syntax: ``` MATCHER(name, description_string_expression) { statements; } ``` will define a matcher with the given name that executes the statements, which must return a `bool` to indicate if the match succeeds. Inside the statements, you can refer to the value being matched by `arg`, and refer to its type by `arg_type`. The description string is a `string`-typed expression that documents what the matcher does, and is used to generate the failure message when the match fails. It can (and should) reference the special `bool` variable `negation`, and should evaluate to the description of the matcher when `negation` is `false`, or that of the matcher's negation when `negation` is `true`. For convenience, we allow the description string to be empty (`""`), in which case Google Mock will use the sequence of words in the matcher name as the description. For example: ``` MATCHER(IsDivisibleBy7, "") { return (arg % 7) == 0; } ``` allows you to write ``` // Expects mock_foo.Bar(n) to be called where n is divisible by 7. EXPECT_CALL(mock_foo, Bar(IsDivisibleBy7())); ``` or, ``` using ::testing::Not; ... EXPECT_THAT(some_expression, IsDivisibleBy7()); EXPECT_THAT(some_other_expression, Not(IsDivisibleBy7())); ``` If the above assertions fail, they will print something like: ``` Value of: some_expression Expected: is divisible by 7 Actual: 27 ... Value of: some_other_expression Expected: not (is divisible by 7) Actual: 21 ``` where the descriptions `"is divisible by 7"` and `"not (is divisible by 7)"` are automatically calculated from the matcher name `IsDivisibleBy7`. As you may have noticed, the auto-generated descriptions (especially those for the negation) may not be so great. You can always override them with a string expression of your own: ``` MATCHER(IsDivisibleBy7, std::string(negation ? "isn't" : "is") + " divisible by 7") { return (arg % 7) == 0; } ``` Optionally, you can stream additional information to a hidden argument named `result_listener` to explain the match result. For example, a better definition of `IsDivisibleBy7` is: ``` MATCHER(IsDivisibleBy7, "") { if ((arg % 7) == 0) return true; *result_listener << "the remainder is " << (arg % 7); return false; } ``` With this definition, the above assertion will give a better message: ``` Value of: some_expression Expected: is divisible by 7 Actual: 27 (the remainder is 6) ``` You should let `MatchAndExplain()` print _any additional information_ that can help a user understand the match result. Note that it should explain why the match succeeds in case of a success (unless it's obvious) - this is useful when the matcher is used inside `Not()`. There is no need to print the argument value itself, as Google Mock already prints it for you. **Notes:** 1. The type of the value being matched (`arg_type`) is determined by the context in which you use the matcher and is supplied to you by the compiler, so you don't need to worry about declaring it (nor can you). This allows the matcher to be polymorphic. For example, `IsDivisibleBy7()` can be used to match any type where the value of `(arg % 7) == 0` can be implicitly converted to a `bool`. In the `Bar(IsDivisibleBy7())` example above, if method `Bar()` takes an `int`, `arg_type` will be `int`; if it takes an `unsigned long`, `arg_type` will be `unsigned long`; and so on. 1. Google Mock doesn't guarantee when or how many times a matcher will be invoked. Therefore the matcher logic must be _purely functional_ (i.e. it cannot have any side effect, and the result must not depend on anything other than the value being matched and the matcher parameters). This requirement must be satisfied no matter how you define the matcher (e.g. using one of the methods described in the following recipes). In particular, a matcher can never call a mock function, as that will affect the state of the mock object and Google Mock. ## Writing New Parameterized Matchers Quickly ## Sometimes you'll want to define a matcher that has parameters. For that you can use the macro: ``` MATCHER_P(name, param_name, description_string) { statements; } ``` where the description string can be either `""` or a string expression that references `negation` and `param_name`. For example: ``` MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; } ``` will allow you to write: ``` EXPECT_THAT(Blah("a"), HasAbsoluteValue(n)); ``` which may lead to this message (assuming `n` is 10): ``` Value of: Blah("a") Expected: has absolute value 10 Actual: -9 ``` Note that both the matcher description and its parameter are printed, making the message human-friendly. In the matcher definition body, you can write `foo_type` to reference the type of a parameter named `foo`. For example, in the body of `MATCHER_P(HasAbsoluteValue, value)` above, you can write `value_type` to refer to the type of `value`. Google Mock also provides `MATCHER_P2`, `MATCHER_P3`, ..., up to `MATCHER_P10` to support multi-parameter matchers: ``` MATCHER_Pk(name, param_1, ..., param_k, description_string) { statements; } ``` Please note that the custom description string is for a particular **instance** of the matcher, where the parameters have been bound to actual values. Therefore usually you'll want the parameter values to be part of the description. Google Mock lets you do that by referencing the matcher parameters in the description string expression. For example, ``` using ::testing::PrintToString; MATCHER_P2(InClosedRange, low, hi, std::string(negation ? "isn't" : "is") + " in range [" + PrintToString(low) + ", " + PrintToString(hi) + "]") { return low <= arg && arg <= hi; } ... EXPECT_THAT(3, InClosedRange(4, 6)); ``` would generate a failure that contains the message: ``` Expected: is in range [4, 6] ``` If you specify `""` as the description, the failure message will contain the sequence of words in the matcher name followed by the parameter values printed as a tuple. For example, ``` MATCHER_P2(InClosedRange, low, hi, "") { ... } ... EXPECT_THAT(3, InClosedRange(4, 6)); ``` would generate a failure that contains the text: ``` Expected: in closed range (4, 6) ``` For the purpose of typing, you can view ``` MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... } ``` as shorthand for ``` template FooMatcherPk Foo(p1_type p1, ..., pk_type pk) { ... } ``` When you write `Foo(v1, ..., vk)`, the compiler infers the types of the parameters `v1`, ..., and `vk` for you. If you are not happy with the result of the type inference, you can specify the types by explicitly instantiating the template, as in `Foo(5, false)`. As said earlier, you don't get to (or need to) specify `arg_type` as that's determined by the context in which the matcher is used. You can assign the result of expression `Foo(p1, ..., pk)` to a variable of type `FooMatcherPk`. This can be useful when composing matchers. Matchers that don't have a parameter or have only one parameter have special types: you can assign `Foo()` to a `FooMatcher`-typed variable, and assign `Foo(p)` to a `FooMatcherP`-typed variable. While you can instantiate a matcher template with reference types, passing the parameters by pointer usually makes your code more readable. If, however, you still want to pass a parameter by reference, be aware that in the failure message generated by the matcher you will see the value of the referenced object but not its address. You can overload matchers with different numbers of parameters: ``` MATCHER_P(Blah, a, description_string_1) { ... } MATCHER_P2(Blah, a, b, description_string_2) { ... } ``` While it's tempting to always use the `MATCHER*` macros when defining a new matcher, you should also consider implementing `MatcherInterface` or using `MakePolymorphicMatcher()` instead (see the recipes that follow), especially if you need to use the matcher a lot. While these approaches require more work, they give you more control on the types of the value being matched and the matcher parameters, which in general leads to better compiler error messages that pay off in the long run. They also allow overloading matchers based on parameter types (as opposed to just based on the number of parameters). ## Writing New Monomorphic Matchers ## A matcher of argument type `T` implements `::testing::MatcherInterface` and does two things: it tests whether a value of type `T` matches the matcher, and can describe what kind of values it matches. The latter ability is used for generating readable error messages when expectations are violated. The interface looks like this: ``` class MatchResultListener { public: ... // Streams x to the underlying ostream; does nothing if the ostream // is NULL. template MatchResultListener& operator<<(const T& x); // Returns the underlying ostream. ::std::ostream* stream(); }; template class MatcherInterface { public: virtual ~MatcherInterface(); // Returns true iff the matcher matches x; also explains the match // result to 'listener'. virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0; // Describes this matcher to an ostream. virtual void DescribeTo(::std::ostream* os) const = 0; // Describes the negation of this matcher to an ostream. virtual void DescribeNegationTo(::std::ostream* os) const; }; ``` If you need a custom matcher but `Truly()` is not a good option (for example, you may not be happy with the way `Truly(predicate)` describes itself, or you may want your matcher to be polymorphic as `Eq(value)` is), you can define a matcher to do whatever you want in two steps: first implement the matcher interface, and then define a factory function to create a matcher instance. The second step is not strictly needed but it makes the syntax of using the matcher nicer. For example, you can define a matcher to test whether an `int` is divisible by 7 and then use it like this: ``` using ::testing::MakeMatcher; using ::testing::Matcher; using ::testing::MatcherInterface; using ::testing::MatchResultListener; class DivisibleBy7Matcher : public MatcherInterface { public: virtual bool MatchAndExplain(int n, MatchResultListener* listener) const { return (n % 7) == 0; } virtual void DescribeTo(::std::ostream* os) const { *os << "is divisible by 7"; } virtual void DescribeNegationTo(::std::ostream* os) const { *os << "is not divisible by 7"; } }; inline Matcher DivisibleBy7() { return MakeMatcher(new DivisibleBy7Matcher); } ... EXPECT_CALL(foo, Bar(DivisibleBy7())); ``` You may improve the matcher message by streaming additional information to the `listener` argument in `MatchAndExplain()`: ``` class DivisibleBy7Matcher : public MatcherInterface { public: virtual bool MatchAndExplain(int n, MatchResultListener* listener) const { const int remainder = n % 7; if (remainder != 0) { *listener << "the remainder is " << remainder; } return remainder == 0; } ... }; ``` Then, `EXPECT_THAT(x, DivisibleBy7());` may general a message like this: ``` Value of: x Expected: is divisible by 7 Actual: 23 (the remainder is 2) ``` ## Writing New Polymorphic Matchers ## You've learned how to write your own matchers in the previous recipe. Just one problem: a matcher created using `MakeMatcher()` only works for one particular type of arguments. If you want a _polymorphic_ matcher that works with arguments of several types (for instance, `Eq(x)` can be used to match a `value` as long as `value` == `x` compiles -- `value` and `x` don't have to share the same type), you can learn the trick from `"gmock/gmock-matchers.h"` but it's a bit involved. Fortunately, most of the time you can define a polymorphic matcher easily with the help of `MakePolymorphicMatcher()`. Here's how you can define `NotNull()` as an example: ``` using ::testing::MakePolymorphicMatcher; using ::testing::MatchResultListener; using ::testing::NotNull; using ::testing::PolymorphicMatcher; class NotNullMatcher { public: // To implement a polymorphic matcher, first define a COPYABLE class // that has three members MatchAndExplain(), DescribeTo(), and // DescribeNegationTo(), like the following. // In this example, we want to use NotNull() with any pointer, so // MatchAndExplain() accepts a pointer of any type as its first argument. // In general, you can define MatchAndExplain() as an ordinary method or // a method template, or even overload it. template bool MatchAndExplain(T* p, MatchResultListener* /* listener */) const { return p != NULL; } // Describes the property of a value matching this matcher. void DescribeTo(::std::ostream* os) const { *os << "is not NULL"; } // Describes the property of a value NOT matching this matcher. void DescribeNegationTo(::std::ostream* os) const { *os << "is NULL"; } }; // To construct a polymorphic matcher, pass an instance of the class // to MakePolymorphicMatcher(). Note the return type. inline PolymorphicMatcher NotNull() { return MakePolymorphicMatcher(NotNullMatcher()); } ... EXPECT_CALL(foo, Bar(NotNull())); // The argument must be a non-NULL pointer. ``` **Note:** Your polymorphic matcher class does **not** need to inherit from `MatcherInterface` or any other class, and its methods do **not** need to be virtual. Like in a monomorphic matcher, you may explain the match result by streaming additional information to the `listener` argument in `MatchAndExplain()`. ## Writing New Cardinalities ## A cardinality is used in `Times()` to tell Google Mock how many times you expect a call to occur. It doesn't have to be exact. For example, you can say `AtLeast(5)` or `Between(2, 4)`. If the built-in set of cardinalities doesn't suit you, you are free to define your own by implementing the following interface (in namespace `testing`): ``` class CardinalityInterface { public: virtual ~CardinalityInterface(); // Returns true iff call_count calls will satisfy this cardinality. virtual bool IsSatisfiedByCallCount(int call_count) const = 0; // Returns true iff call_count calls will saturate this cardinality. virtual bool IsSaturatedByCallCount(int call_count) const = 0; // Describes self to an ostream. virtual void DescribeTo(::std::ostream* os) const = 0; }; ``` For example, to specify that a call must occur even number of times, you can write ``` using ::testing::Cardinality; using ::testing::CardinalityInterface; using ::testing::MakeCardinality; class EvenNumberCardinality : public CardinalityInterface { public: virtual bool IsSatisfiedByCallCount(int call_count) const { return (call_count % 2) == 0; } virtual bool IsSaturatedByCallCount(int call_count) const { return false; } virtual void DescribeTo(::std::ostream* os) const { *os << "called even number of times"; } }; Cardinality EvenNumber() { return MakeCardinality(new EvenNumberCardinality); } ... EXPECT_CALL(foo, Bar(3)) .Times(EvenNumber()); ``` ## Writing New Actions Quickly ## If the built-in actions don't work for you, and you find it inconvenient to use `Invoke()`, you can use a macro from the `ACTION*` family to quickly define a new action that can be used in your code as if it's a built-in action. By writing ``` ACTION(name) { statements; } ``` in a namespace scope (i.e. not inside a class or function), you will define an action with the given name that executes the statements. The value returned by `statements` will be used as the return value of the action. Inside the statements, you can refer to the K-th (0-based) argument of the mock function as `argK`. For example: ``` ACTION(IncrementArg1) { return ++(*arg1); } ``` allows you to write ``` ... WillOnce(IncrementArg1()); ``` Note that you don't need to specify the types of the mock function arguments. Rest assured that your code is type-safe though: you'll get a compiler error if `*arg1` doesn't support the `++` operator, or if the type of `++(*arg1)` isn't compatible with the mock function's return type. Another example: ``` ACTION(Foo) { (*arg2)(5); Blah(); *arg1 = 0; return arg0; } ``` defines an action `Foo()` that invokes argument #2 (a function pointer) with 5, calls function `Blah()`, sets the value pointed to by argument #1 to 0, and returns argument #0. For more convenience and flexibility, you can also use the following pre-defined symbols in the body of `ACTION`: | `argK_type` | The type of the K-th (0-based) argument of the mock function | |:------------|:-------------------------------------------------------------| | `args` | All arguments of the mock function as a tuple | | `args_type` | The type of all arguments of the mock function as a tuple | | `return_type` | The return type of the mock function | | `function_type` | The type of the mock function | For example, when using an `ACTION` as a stub action for mock function: ``` int DoSomething(bool flag, int* ptr); ``` we have: | **Pre-defined Symbol** | **Is Bound To** | |:-----------------------|:----------------| | `arg0` | the value of `flag` | | `arg0_type` | the type `bool` | | `arg1` | the value of `ptr` | | `arg1_type` | the type `int*` | | `args` | the tuple `(flag, ptr)` | | `args_type` | the type `std::tr1::tuple` | | `return_type` | the type `int` | | `function_type` | the type `int(bool, int*)` | ## Writing New Parameterized Actions Quickly ## Sometimes you'll want to parameterize an action you define. For that we have another macro ``` ACTION_P(name, param) { statements; } ``` For example, ``` ACTION_P(Add, n) { return arg0 + n; } ``` will allow you to write ``` // Returns argument #0 + 5. ... WillOnce(Add(5)); ``` For convenience, we use the term _arguments_ for the values used to invoke the mock function, and the term _parameters_ for the values used to instantiate an action. Note that you don't need to provide the type of the parameter either. Suppose the parameter is named `param`, you can also use the Google-Mock-defined symbol `param_type` to refer to the type of the parameter as inferred by the compiler. For example, in the body of `ACTION_P(Add, n)` above, you can write `n_type` for the type of `n`. Google Mock also provides `ACTION_P2`, `ACTION_P3`, and etc to support multi-parameter actions. For example, ``` ACTION_P2(ReturnDistanceTo, x, y) { double dx = arg0 - x; double dy = arg1 - y; return sqrt(dx*dx + dy*dy); } ``` lets you write ``` ... WillOnce(ReturnDistanceTo(5.0, 26.5)); ``` You can view `ACTION` as a degenerated parameterized action where the number of parameters is 0. You can also easily define actions overloaded on the number of parameters: ``` ACTION_P(Plus, a) { ... } ACTION_P2(Plus, a, b) { ... } ``` ## Restricting the Type of an Argument or Parameter in an ACTION ## For maximum brevity and reusability, the `ACTION*` macros don't ask you to provide the types of the mock function arguments and the action parameters. Instead, we let the compiler infer the types for us. Sometimes, however, we may want to be more explicit about the types. There are several tricks to do that. For example: ``` ACTION(Foo) { // Makes sure arg0 can be converted to int. int n = arg0; ... use n instead of arg0 here ... } ACTION_P(Bar, param) { // Makes sure the type of arg1 is const char*. ::testing::StaticAssertTypeEq(); // Makes sure param can be converted to bool. bool flag = param; } ``` where `StaticAssertTypeEq` is a compile-time assertion in Google Test that verifies two types are the same. ## Writing New Action Templates Quickly ## Sometimes you want to give an action explicit template parameters that cannot be inferred from its value parameters. `ACTION_TEMPLATE()` supports that and can be viewed as an extension to `ACTION()` and `ACTION_P*()`. The syntax: ``` ACTION_TEMPLATE(ActionName, HAS_m_TEMPLATE_PARAMS(kind1, name1, ..., kind_m, name_m), AND_n_VALUE_PARAMS(p1, ..., p_n)) { statements; } ``` defines an action template that takes _m_ explicit template parameters and _n_ value parameters, where _m_ is between 1 and 10, and _n_ is between 0 and 10. `name_i` is the name of the i-th template parameter, and `kind_i` specifies whether it's a `typename`, an integral constant, or a template. `p_i` is the name of the i-th value parameter. Example: ``` // DuplicateArg(output) converts the k-th argument of the mock // function to type T and copies it to *output. ACTION_TEMPLATE(DuplicateArg, // Note the comma between int and k: HAS_2_TEMPLATE_PARAMS(int, k, typename, T), AND_1_VALUE_PARAMS(output)) { *output = T(std::tr1::get(args)); } ``` To create an instance of an action template, write: ``` ActionName(v1, ..., v_n) ``` where the `t`s are the template arguments and the `v`s are the value arguments. The value argument types are inferred by the compiler. For example: ``` using ::testing::_; ... int n; EXPECT_CALL(mock, Foo(_, _)) .WillOnce(DuplicateArg<1, unsigned char>(&n)); ``` If you want to explicitly specify the value argument types, you can provide additional template arguments: ``` ActionName(v1, ..., v_n) ``` where `u_i` is the desired type of `v_i`. `ACTION_TEMPLATE` and `ACTION`/`ACTION_P*` can be overloaded on the number of value parameters, but not on the number of template parameters. Without the restriction, the meaning of the following is unclear: ``` OverloadedAction(x); ``` Are we using a single-template-parameter action where `bool` refers to the type of `x`, or a two-template-parameter action where the compiler is asked to infer the type of `x`? ## Using the ACTION Object's Type ## If you are writing a function that returns an `ACTION` object, you'll need to know its type. The type depends on the macro used to define the action and the parameter types. The rule is relatively simple: | **Given Definition** | **Expression** | **Has Type** | |:---------------------|:---------------|:-------------| | `ACTION(Foo)` | `Foo()` | `FooAction` | | `ACTION_TEMPLATE(Foo, HAS_m_TEMPLATE_PARAMS(...), AND_0_VALUE_PARAMS())` | `Foo()` | `FooAction` | | `ACTION_P(Bar, param)` | `Bar(int_value)` | `BarActionP` | | `ACTION_TEMPLATE(Bar, HAS_m_TEMPLATE_PARAMS(...), AND_1_VALUE_PARAMS(p1))` | `Bar(int_value)` | `FooActionP` | | `ACTION_P2(Baz, p1, p2)` | `Baz(bool_value, int_value)` | `BazActionP2` | | `ACTION_TEMPLATE(Baz, HAS_m_TEMPLATE_PARAMS(...), AND_2_VALUE_PARAMS(p1, p2))` | `Baz(bool_value, int_value)` | `FooActionP2` | | ... | ... | ... | Note that we have to pick different suffixes (`Action`, `ActionP`, `ActionP2`, and etc) for actions with different numbers of value parameters, or the action definitions cannot be overloaded on the number of them. ## Writing New Monomorphic Actions ## While the `ACTION*` macros are very convenient, sometimes they are inappropriate. For example, despite the tricks shown in the previous recipes, they don't let you directly specify the types of the mock function arguments and the action parameters, which in general leads to unoptimized compiler error messages that can baffle unfamiliar users. They also don't allow overloading actions based on parameter types without jumping through some hoops. An alternative to the `ACTION*` macros is to implement `::testing::ActionInterface`, where `F` is the type of the mock function in which the action will be used. For example: ``` template class ActionInterface { public: virtual ~ActionInterface(); // Performs the action. Result is the return type of function type // F, and ArgumentTuple is the tuple of arguments of F. // // For example, if F is int(bool, const string&), then Result would // be int, and ArgumentTuple would be tr1::tuple. virtual Result Perform(const ArgumentTuple& args) = 0; }; using ::testing::_; using ::testing::Action; using ::testing::ActionInterface; using ::testing::MakeAction; typedef int IncrementMethod(int*); class IncrementArgumentAction : public ActionInterface { public: virtual int Perform(const tr1::tuple& args) { int* p = tr1::get<0>(args); // Grabs the first argument. return *p++; } }; Action IncrementArgument() { return MakeAction(new IncrementArgumentAction); } ... EXPECT_CALL(foo, Baz(_)) .WillOnce(IncrementArgument()); int n = 5; foo.Baz(&n); // Should return 5 and change n to 6. ``` ## Writing New Polymorphic Actions ## The previous recipe showed you how to define your own action. This is all good, except that you need to know the type of the function in which the action will be used. Sometimes that can be a problem. For example, if you want to use the action in functions with _different_ types (e.g. like `Return()` and `SetArgPointee()`). If an action can be used in several types of mock functions, we say it's _polymorphic_. The `MakePolymorphicAction()` function template makes it easy to define such an action: ``` namespace testing { template PolymorphicAction MakePolymorphicAction(const Impl& impl); } // namespace testing ``` As an example, let's define an action that returns the second argument in the mock function's argument list. The first step is to define an implementation class: ``` class ReturnSecondArgumentAction { public: template Result Perform(const ArgumentTuple& args) const { // To get the i-th (0-based) argument, use tr1::get(args). return tr1::get<1>(args); } }; ``` This implementation class does _not_ need to inherit from any particular class. What matters is that it must have a `Perform()` method template. This method template takes the mock function's arguments as a tuple in a **single** argument, and returns the result of the action. It can be either `const` or not, but must be invokable with exactly one template argument, which is the result type. In other words, you must be able to call `Perform(args)` where `R` is the mock function's return type and `args` is its arguments in a tuple. Next, we use `MakePolymorphicAction()` to turn an instance of the implementation class into the polymorphic action we need. It will be convenient to have a wrapper for this: ``` using ::testing::MakePolymorphicAction; using ::testing::PolymorphicAction; PolymorphicAction ReturnSecondArgument() { return MakePolymorphicAction(ReturnSecondArgumentAction()); } ``` Now, you can use this polymorphic action the same way you use the built-in ones: ``` using ::testing::_; class MockFoo : public Foo { public: MOCK_METHOD2(DoThis, int(bool flag, int n)); MOCK_METHOD3(DoThat, string(int x, const char* str1, const char* str2)); }; ... MockFoo foo; EXPECT_CALL(foo, DoThis(_, _)) .WillOnce(ReturnSecondArgument()); EXPECT_CALL(foo, DoThat(_, _, _)) .WillOnce(ReturnSecondArgument()); ... foo.DoThis(true, 5); // Will return 5. foo.DoThat(1, "Hi", "Bye"); // Will return "Hi". ``` ## Teaching Google Mock How to Print Your Values ## When an uninteresting or unexpected call occurs, Google Mock prints the argument values and the stack trace to help you debug. Assertion macros like `EXPECT_THAT` and `EXPECT_EQ` also print the values in question when the assertion fails. Google Mock and Google Test do this using Google Test's user-extensible value printer. This printer knows how to print built-in C++ types, native arrays, STL containers, and any type that supports the `<<` operator. For other types, it prints the raw bytes in the value and hopes that you the user can figure it out. [Google Test's advanced guide](http://code.google.com/p/googletest/wiki/AdvancedGuide#Teaching_Google_Test_How_to_Print_Your_Values) explains how to extend the printer to do a better job at printing your particular type than to dump the bytes.nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/docs/v1_7/Documentation.md000066400000000000000000000014441455373415500275020ustar00rootroot00000000000000This page lists all documentation wiki pages for Google Mock **(the SVN trunk version)** - **if you use a released version of Google Mock, please read the documentation for that specific version instead.** * [ForDummies](V1_7_ForDummies.md) -- start here if you are new to Google Mock. * [CheatSheet](V1_7_CheatSheet.md) -- a quick reference. * [CookBook](V1_7_CookBook.md) -- recipes for doing various tasks using Google Mock. * [FrequentlyAskedQuestions](V1_7_FrequentlyAskedQuestions.md) -- check here before asking a question on the mailing list. To contribute code to Google Mock, read: * [DevGuide](DevGuide.md) -- read this _before_ writing your first patch. * [Pump Manual](http://code.google.com/p/googletest/wiki/PumpManual) -- how we generate some of Google Mock's source files.nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/docs/v1_7/ForDummies.md000066400000000000000000000726711455373415500267550ustar00rootroot00000000000000 (**Note:** If you get compiler errors that you don't understand, be sure to consult [Google Mock Doctor](http://code.google.com/p/googlemock/wiki/V1_7_FrequentlyAskedQuestions#How_am_I_supposed_to_make_sense_of_these_horrible_template_error).) # What Is Google C++ Mocking Framework? # When you write a prototype or test, often it's not feasible or wise to rely on real objects entirely. A **mock object** implements the same interface as a real object (so it can be used as one), but lets you specify at run time how it will be used and what it should do (which methods will be called? in which order? how many times? with what arguments? what will they return? etc). **Note:** It is easy to confuse the term _fake objects_ with mock objects. Fakes and mocks actually mean very different things in the Test-Driven Development (TDD) community: * **Fake** objects have working implementations, but usually take some shortcut (perhaps to make the operations less expensive), which makes them not suitable for production. An in-memory file system would be an example of a fake. * **Mocks** are objects pre-programmed with _expectations_, which form a specification of the calls they are expected to receive. If all this seems too abstract for you, don't worry - the most important thing to remember is that a mock allows you to check the _interaction_ between itself and code that uses it. The difference between fakes and mocks will become much clearer once you start to use mocks. **Google C++ Mocking Framework** (or **Google Mock** for short) is a library (sometimes we also call it a "framework" to make it sound cool) for creating mock classes and using them. It does to C++ what [jMock](http://www.jmock.org/) and [EasyMock](http://www.easymock.org/) do to Java. Using Google Mock involves three basic steps: 1. Use some simple macros to describe the interface you want to mock, and they will expand to the implementation of your mock class; 1. Create some mock objects and specify its expectations and behavior using an intuitive syntax; 1. Exercise code that uses the mock objects. Google Mock will catch any violation of the expectations as soon as it arises. # Why Google Mock? # While mock objects help you remove unnecessary dependencies in tests and make them fast and reliable, using mocks manually in C++ is _hard_: * Someone has to implement the mocks. The job is usually tedious and error-prone. No wonder people go great distance to avoid it. * The quality of those manually written mocks is a bit, uh, unpredictable. You may see some really polished ones, but you may also see some that were hacked up in a hurry and have all sorts of ad hoc restrictions. * The knowledge you gained from using one mock doesn't transfer to the next. In contrast, Java and Python programmers have some fine mock frameworks, which automate the creation of mocks. As a result, mocking is a proven effective technique and widely adopted practice in those communities. Having the right tool absolutely makes the difference. Google Mock was built to help C++ programmers. It was inspired by [jMock](http://www.jmock.org/) and [EasyMock](http://www.easymock.org/), but designed with C++'s specifics in mind. It is your friend if any of the following problems is bothering you: * You are stuck with a sub-optimal design and wish you had done more prototyping before it was too late, but prototyping in C++ is by no means "rapid". * Your tests are slow as they depend on too many libraries or use expensive resources (e.g. a database). * Your tests are brittle as some resources they use are unreliable (e.g. the network). * You want to test how your code handles a failure (e.g. a file checksum error), but it's not easy to cause one. * You need to make sure that your module interacts with other modules in the right way, but it's hard to observe the interaction; therefore you resort to observing the side effects at the end of the action, which is awkward at best. * You want to "mock out" your dependencies, except that they don't have mock implementations yet; and, frankly, you aren't thrilled by some of those hand-written mocks. We encourage you to use Google Mock as: * a _design_ tool, for it lets you experiment with your interface design early and often. More iterations lead to better designs! * a _testing_ tool to cut your tests' outbound dependencies and probe the interaction between your module and its collaborators. # Getting Started # Using Google Mock is easy! Inside your C++ source file, just `#include` `"gtest/gtest.h"` and `"gmock/gmock.h"`, and you are ready to go. # A Case for Mock Turtles # Let's look at an example. Suppose you are developing a graphics program that relies on a LOGO-like API for drawing. How would you test that it does the right thing? Well, you can run it and compare the screen with a golden screen snapshot, but let's admit it: tests like this are expensive to run and fragile (What if you just upgraded to a shiny new graphics card that has better anti-aliasing? Suddenly you have to update all your golden images.). It would be too painful if all your tests are like this. Fortunately, you learned about Dependency Injection and know the right thing to do: instead of having your application talk to the drawing API directly, wrap the API in an interface (say, `Turtle`) and code to that interface: ``` class Turtle { ... virtual ~Turtle() {} virtual void PenUp() = 0; virtual void PenDown() = 0; virtual void Forward(int distance) = 0; virtual void Turn(int degrees) = 0; virtual void GoTo(int x, int y) = 0; virtual int GetX() const = 0; virtual int GetY() const = 0; }; ``` (Note that the destructor of `Turtle` **must** be virtual, as is the case for **all** classes you intend to inherit from - otherwise the destructor of the derived class will not be called when you delete an object through a base pointer, and you'll get corrupted program states like memory leaks.) You can control whether the turtle's movement will leave a trace using `PenUp()` and `PenDown()`, and control its movement using `Forward()`, `Turn()`, and `GoTo()`. Finally, `GetX()` and `GetY()` tell you the current position of the turtle. Your program will normally use a real implementation of this interface. In tests, you can use a mock implementation instead. This allows you to easily check what drawing primitives your program is calling, with what arguments, and in which order. Tests written this way are much more robust (they won't break because your new machine does anti-aliasing differently), easier to read and maintain (the intent of a test is expressed in the code, not in some binary images), and run _much, much faster_. # Writing the Mock Class # If you are lucky, the mocks you need to use have already been implemented by some nice people. If, however, you find yourself in the position to write a mock class, relax - Google Mock turns this task into a fun game! (Well, almost.) ## How to Define It ## Using the `Turtle` interface as example, here are the simple steps you need to follow: 1. Derive a class `MockTurtle` from `Turtle`. 1. Take a _virtual_ function of `Turtle` (while it's possible to [mock non-virtual methods using templates](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Mocking_Nonvirtual_Methods), it's much more involved). Count how many arguments it has. 1. In the `public:` section of the child class, write `MOCK_METHODn();` (or `MOCK_CONST_METHODn();` if you are mocking a `const` method), where `n` is the number of the arguments; if you counted wrong, shame on you, and a compiler error will tell you so. 1. Now comes the fun part: you take the function signature, cut-and-paste the _function name_ as the _first_ argument to the macro, and leave what's left as the _second_ argument (in case you're curious, this is the _type of the function_). 1. Repeat until all virtual functions you want to mock are done. After the process, you should have something like: ``` #include "gmock/gmock.h" // Brings in Google Mock. class MockTurtle : public Turtle { public: ... MOCK_METHOD0(PenUp, void()); MOCK_METHOD0(PenDown, void()); MOCK_METHOD1(Forward, void(int distance)); MOCK_METHOD1(Turn, void(int degrees)); MOCK_METHOD2(GoTo, void(int x, int y)); MOCK_CONST_METHOD0(GetX, int()); MOCK_CONST_METHOD0(GetY, int()); }; ``` You don't need to define these mock methods somewhere else - the `MOCK_METHOD*` macros will generate the definitions for you. It's that simple! Once you get the hang of it, you can pump out mock classes faster than your source-control system can handle your check-ins. **Tip:** If even this is too much work for you, you'll find the `gmock_gen.py` tool in Google Mock's `scripts/generator/` directory (courtesy of the [cppclean](http://code.google.com/p/cppclean/) project) useful. This command-line tool requires that you have Python 2.4 installed. You give it a C++ file and the name of an abstract class defined in it, and it will print the definition of the mock class for you. Due to the complexity of the C++ language, this script may not always work, but it can be quite handy when it does. For more details, read the [user documentation](http://code.google.com/p/googlemock/source/browse/trunk/scripts/generator/README). ## Where to Put It ## When you define a mock class, you need to decide where to put its definition. Some people put it in a `*_test.cc`. This is fine when the interface being mocked (say, `Foo`) is owned by the same person or team. Otherwise, when the owner of `Foo` changes it, your test could break. (You can't really expect `Foo`'s maintainer to fix every test that uses `Foo`, can you?) So, the rule of thumb is: if you need to mock `Foo` and it's owned by others, define the mock class in `Foo`'s package (better, in a `testing` sub-package such that you can clearly separate production code and testing utilities), and put it in a `mock_foo.h`. Then everyone can reference `mock_foo.h` from their tests. If `Foo` ever changes, there is only one copy of `MockFoo` to change, and only tests that depend on the changed methods need to be fixed. Another way to do it: you can introduce a thin layer `FooAdaptor` on top of `Foo` and code to this new interface. Since you own `FooAdaptor`, you can absorb changes in `Foo` much more easily. While this is more work initially, carefully choosing the adaptor interface can make your code easier to write and more readable (a net win in the long run), as you can choose `FooAdaptor` to fit your specific domain much better than `Foo` does. # Using Mocks in Tests # Once you have a mock class, using it is easy. The typical work flow is: 1. Import the Google Mock names from the `testing` namespace such that you can use them unqualified (You only have to do it once per file. Remember that namespaces are a good idea and good for your health.). 1. Create some mock objects. 1. Specify your expectations on them (How many times will a method be called? With what arguments? What should it do? etc.). 1. Exercise some code that uses the mocks; optionally, check the result using Google Test assertions. If a mock method is called more than expected or with wrong arguments, you'll get an error immediately. 1. When a mock is destructed, Google Mock will automatically check whether all expectations on it have been satisfied. Here's an example: ``` #include "path/to/mock-turtle.h" #include "gmock/gmock.h" #include "gtest/gtest.h" using ::testing::AtLeast; // #1 TEST(PainterTest, CanDrawSomething) { MockTurtle turtle; // #2 EXPECT_CALL(turtle, PenDown()) // #3 .Times(AtLeast(1)); Painter painter(&turtle); // #4 EXPECT_TRUE(painter.DrawCircle(0, 0, 10)); } // #5 int main(int argc, char** argv) { // The following line must be executed to initialize Google Mock // (and Google Test) before running the tests. ::testing::InitGoogleMock(&argc, argv); return RUN_ALL_TESTS(); } ``` As you might have guessed, this test checks that `PenDown()` is called at least once. If the `painter` object didn't call this method, your test will fail with a message like this: ``` path/to/my_test.cc:119: Failure Actual function call count doesn't match this expectation: Actually: never called; Expected: called at least once. ``` **Tip 1:** If you run the test from an Emacs buffer, you can hit `` on the line number displayed in the error message to jump right to the failed expectation. **Tip 2:** If your mock objects are never deleted, the final verification won't happen. Therefore it's a good idea to use a heap leak checker in your tests when you allocate mocks on the heap. **Important note:** Google Mock requires expectations to be set **before** the mock functions are called, otherwise the behavior is **undefined**. In particular, you mustn't interleave `EXPECT_CALL()`s and calls to the mock functions. This means `EXPECT_CALL()` should be read as expecting that a call will occur _in the future_, not that a call has occurred. Why does Google Mock work like that? Well, specifying the expectation beforehand allows Google Mock to report a violation as soon as it arises, when the context (stack trace, etc) is still available. This makes debugging much easier. Admittedly, this test is contrived and doesn't do much. You can easily achieve the same effect without using Google Mock. However, as we shall reveal soon, Google Mock allows you to do _much more_ with the mocks. ## Using Google Mock with Any Testing Framework ## If you want to use something other than Google Test (e.g. [CppUnit](http://apps.sourceforge.net/mediawiki/cppunit/index.php?title=Main_Page) or [CxxTest](http://cxxtest.tigris.org/)) as your testing framework, just change the `main()` function in the previous section to: ``` int main(int argc, char** argv) { // The following line causes Google Mock to throw an exception on failure, // which will be interpreted by your testing framework as a test failure. ::testing::GTEST_FLAG(throw_on_failure) = true; ::testing::InitGoogleMock(&argc, argv); ... whatever your testing framework requires ... } ``` This approach has a catch: it makes Google Mock throw an exception from a mock object's destructor sometimes. With some compilers, this sometimes causes the test program to crash. You'll still be able to notice that the test has failed, but it's not a graceful failure. A better solution is to use Google Test's [event listener API](http://code.google.com/p/googletest/wiki/AdvancedGuide#Extending_Google_Test_by_Handling_Test_Events) to report a test failure to your testing framework properly. You'll need to implement the `OnTestPartResult()` method of the event listener interface, but it should be straightforward. If this turns out to be too much work, we suggest that you stick with Google Test, which works with Google Mock seamlessly (in fact, it is technically part of Google Mock.). If there is a reason that you cannot use Google Test, please let us know. # Setting Expectations # The key to using a mock object successfully is to set the _right expectations_ on it. If you set the expectations too strict, your test will fail as the result of unrelated changes. If you set them too loose, bugs can slip through. You want to do it just right such that your test can catch exactly the kind of bugs you intend it to catch. Google Mock provides the necessary means for you to do it "just right." ## General Syntax ## In Google Mock we use the `EXPECT_CALL()` macro to set an expectation on a mock method. The general syntax is: ``` EXPECT_CALL(mock_object, method(matchers)) .Times(cardinality) .WillOnce(action) .WillRepeatedly(action); ``` The macro has two arguments: first the mock object, and then the method and its arguments. Note that the two are separated by a comma (`,`), not a period (`.`). (Why using a comma? The answer is that it was necessary for technical reasons.) The macro can be followed by some optional _clauses_ that provide more information about the expectation. We'll discuss how each clause works in the coming sections. This syntax is designed to make an expectation read like English. For example, you can probably guess that ``` using ::testing::Return;... EXPECT_CALL(turtle, GetX()) .Times(5) .WillOnce(Return(100)) .WillOnce(Return(150)) .WillRepeatedly(Return(200)); ``` says that the `turtle` object's `GetX()` method will be called five times, it will return 100 the first time, 150 the second time, and then 200 every time. Some people like to call this style of syntax a Domain-Specific Language (DSL). **Note:** Why do we use a macro to do this? It serves two purposes: first it makes expectations easily identifiable (either by `grep` or by a human reader), and second it allows Google Mock to include the source file location of a failed expectation in messages, making debugging easier. ## Matchers: What Arguments Do We Expect? ## When a mock function takes arguments, we must specify what arguments we are expecting; for example: ``` // Expects the turtle to move forward by 100 units. EXPECT_CALL(turtle, Forward(100)); ``` Sometimes you may not want to be too specific (Remember that talk about tests being too rigid? Over specification leads to brittle tests and obscures the intent of tests. Therefore we encourage you to specify only what's necessary - no more, no less.). If you care to check that `Forward()` will be called but aren't interested in its actual argument, write `_` as the argument, which means "anything goes": ``` using ::testing::_; ... // Expects the turtle to move forward. EXPECT_CALL(turtle, Forward(_)); ``` `_` is an instance of what we call **matchers**. A matcher is like a predicate and can test whether an argument is what we'd expect. You can use a matcher inside `EXPECT_CALL()` wherever a function argument is expected. A list of built-in matchers can be found in the [CheatSheet](V1_7_CheatSheet.md). For example, here's the `Ge` (greater than or equal) matcher: ``` using ::testing::Ge;... EXPECT_CALL(turtle, Forward(Ge(100))); ``` This checks that the turtle will be told to go forward by at least 100 units. ## Cardinalities: How Many Times Will It Be Called? ## The first clause we can specify following an `EXPECT_CALL()` is `Times()`. We call its argument a **cardinality** as it tells _how many times_ the call should occur. It allows us to repeat an expectation many times without actually writing it as many times. More importantly, a cardinality can be "fuzzy", just like a matcher can be. This allows a user to express the intent of a test exactly. An interesting special case is when we say `Times(0)`. You may have guessed - it means that the function shouldn't be called with the given arguments at all, and Google Mock will report a Google Test failure whenever the function is (wrongfully) called. We've seen `AtLeast(n)` as an example of fuzzy cardinalities earlier. For the list of built-in cardinalities you can use, see the [CheatSheet](V1_7_CheatSheet.md). The `Times()` clause can be omitted. **If you omit `Times()`, Google Mock will infer the cardinality for you.** The rules are easy to remember: * If **neither** `WillOnce()` **nor** `WillRepeatedly()` is in the `EXPECT_CALL()`, the inferred cardinality is `Times(1)`. * If there are `n WillOnce()`'s but **no** `WillRepeatedly()`, where `n` >= 1, the cardinality is `Times(n)`. * If there are `n WillOnce()`'s and **one** `WillRepeatedly()`, where `n` >= 0, the cardinality is `Times(AtLeast(n))`. **Quick quiz:** what do you think will happen if a function is expected to be called twice but actually called four times? ## Actions: What Should It Do? ## Remember that a mock object doesn't really have a working implementation? We as users have to tell it what to do when a method is invoked. This is easy in Google Mock. First, if the return type of a mock function is a built-in type or a pointer, the function has a **default action** (a `void` function will just return, a `bool` function will return `false`, and other functions will return 0). If you don't say anything, this behavior will be used. Second, if a mock function doesn't have a default action, or the default action doesn't suit you, you can specify the action to be taken each time the expectation matches using a series of `WillOnce()` clauses followed by an optional `WillRepeatedly()`. For example, ``` using ::testing::Return;... EXPECT_CALL(turtle, GetX()) .WillOnce(Return(100)) .WillOnce(Return(200)) .WillOnce(Return(300)); ``` This says that `turtle.GetX()` will be called _exactly three times_ (Google Mock inferred this from how many `WillOnce()` clauses we've written, since we didn't explicitly write `Times()`), and will return 100, 200, and 300 respectively. ``` using ::testing::Return;... EXPECT_CALL(turtle, GetY()) .WillOnce(Return(100)) .WillOnce(Return(200)) .WillRepeatedly(Return(300)); ``` says that `turtle.GetY()` will be called _at least twice_ (Google Mock knows this as we've written two `WillOnce()` clauses and a `WillRepeatedly()` while having no explicit `Times()`), will return 100 the first time, 200 the second time, and 300 from the third time on. Of course, if you explicitly write a `Times()`, Google Mock will not try to infer the cardinality itself. What if the number you specified is larger than there are `WillOnce()` clauses? Well, after all `WillOnce()`s are used up, Google Mock will do the _default_ action for the function every time (unless, of course, you have a `WillRepeatedly()`.). What can we do inside `WillOnce()` besides `Return()`? You can return a reference using `ReturnRef(variable)`, or invoke a pre-defined function, among [others](http://code.google.com/p/googlemock/wiki/V1_7_CheatSheet#Actions). **Important note:** The `EXPECT_CALL()` statement evaluates the action clause only once, even though the action may be performed many times. Therefore you must be careful about side effects. The following may not do what you want: ``` int n = 100; EXPECT_CALL(turtle, GetX()) .Times(4) .WillRepeatedly(Return(n++)); ``` Instead of returning 100, 101, 102, ..., consecutively, this mock function will always return 100 as `n++` is only evaluated once. Similarly, `Return(new Foo)` will create a new `Foo` object when the `EXPECT_CALL()` is executed, and will return the same pointer every time. If you want the side effect to happen every time, you need to define a custom action, which we'll teach in the [CookBook](V1_7_CookBook.md). Time for another quiz! What do you think the following means? ``` using ::testing::Return;... EXPECT_CALL(turtle, GetY()) .Times(4) .WillOnce(Return(100)); ``` Obviously `turtle.GetY()` is expected to be called four times. But if you think it will return 100 every time, think twice! Remember that one `WillOnce()` clause will be consumed each time the function is invoked and the default action will be taken afterwards. So the right answer is that `turtle.GetY()` will return 100 the first time, but **return 0 from the second time on**, as returning 0 is the default action for `int` functions. ## Using Multiple Expectations ## So far we've only shown examples where you have a single expectation. More realistically, you're going to specify expectations on multiple mock methods, which may be from multiple mock objects. By default, when a mock method is invoked, Google Mock will search the expectations in the **reverse order** they are defined, and stop when an active expectation that matches the arguments is found (you can think of it as "newer rules override older ones."). If the matching expectation cannot take any more calls, you will get an upper-bound-violated failure. Here's an example: ``` using ::testing::_;... EXPECT_CALL(turtle, Forward(_)); // #1 EXPECT_CALL(turtle, Forward(10)) // #2 .Times(2); ``` If `Forward(10)` is called three times in a row, the third time it will be an error, as the last matching expectation (#2) has been saturated. If, however, the third `Forward(10)` call is replaced by `Forward(20)`, then it would be OK, as now #1 will be the matching expectation. **Side note:** Why does Google Mock search for a match in the _reverse_ order of the expectations? The reason is that this allows a user to set up the default expectations in a mock object's constructor or the test fixture's set-up phase and then customize the mock by writing more specific expectations in the test body. So, if you have two expectations on the same method, you want to put the one with more specific matchers **after** the other, or the more specific rule would be shadowed by the more general one that comes after it. ## Ordered vs Unordered Calls ## By default, an expectation can match a call even though an earlier expectation hasn't been satisfied. In other words, the calls don't have to occur in the order the expectations are specified. Sometimes, you may want all the expected calls to occur in a strict order. To say this in Google Mock is easy: ``` using ::testing::InSequence;... TEST(FooTest, DrawsLineSegment) { ... { InSequence dummy; EXPECT_CALL(turtle, PenDown()); EXPECT_CALL(turtle, Forward(100)); EXPECT_CALL(turtle, PenUp()); } Foo(); } ``` By creating an object of type `InSequence`, all expectations in its scope are put into a _sequence_ and have to occur _sequentially_. Since we are just relying on the constructor and destructor of this object to do the actual work, its name is really irrelevant. In this example, we test that `Foo()` calls the three expected functions in the order as written. If a call is made out-of-order, it will be an error. (What if you care about the relative order of some of the calls, but not all of them? Can you specify an arbitrary partial order? The answer is ... yes! If you are impatient, the details can be found in the [CookBook](V1_7_CookBook#Expecting_Partially_Ordered_Calls.md).) ## All Expectations Are Sticky (Unless Said Otherwise) ## Now let's do a quick quiz to see how well you can use this mock stuff already. How would you test that the turtle is asked to go to the origin _exactly twice_ (you want to ignore any other instructions it receives)? After you've come up with your answer, take a look at ours and compare notes (solve it yourself first - don't cheat!): ``` using ::testing::_;... EXPECT_CALL(turtle, GoTo(_, _)) // #1 .Times(AnyNumber()); EXPECT_CALL(turtle, GoTo(0, 0)) // #2 .Times(2); ``` Suppose `turtle.GoTo(0, 0)` is called three times. In the third time, Google Mock will see that the arguments match expectation #2 (remember that we always pick the last matching expectation). Now, since we said that there should be only two such calls, Google Mock will report an error immediately. This is basically what we've told you in the "Using Multiple Expectations" section above. This example shows that **expectations in Google Mock are "sticky" by default**, in the sense that they remain active even after we have reached their invocation upper bounds. This is an important rule to remember, as it affects the meaning of the spec, and is **different** to how it's done in many other mocking frameworks (Why'd we do that? Because we think our rule makes the common cases easier to express and understand.). Simple? Let's see if you've really understood it: what does the following code say? ``` using ::testing::Return; ... for (int i = n; i > 0; i--) { EXPECT_CALL(turtle, GetX()) .WillOnce(Return(10*i)); } ``` If you think it says that `turtle.GetX()` will be called `n` times and will return 10, 20, 30, ..., consecutively, think twice! The problem is that, as we said, expectations are sticky. So, the second time `turtle.GetX()` is called, the last (latest) `EXPECT_CALL()` statement will match, and will immediately lead to an "upper bound exceeded" error - this piece of code is not very useful! One correct way of saying that `turtle.GetX()` will return 10, 20, 30, ..., is to explicitly say that the expectations are _not_ sticky. In other words, they should _retire_ as soon as they are saturated: ``` using ::testing::Return; ... for (int i = n; i > 0; i--) { EXPECT_CALL(turtle, GetX()) .WillOnce(Return(10*i)) .RetiresOnSaturation(); } ``` And, there's a better way to do it: in this case, we expect the calls to occur in a specific order, and we line up the actions to match the order. Since the order is important here, we should make it explicit using a sequence: ``` using ::testing::InSequence; using ::testing::Return; ... { InSequence s; for (int i = 1; i <= n; i++) { EXPECT_CALL(turtle, GetX()) .WillOnce(Return(10*i)) .RetiresOnSaturation(); } } ``` By the way, the other situation where an expectation may _not_ be sticky is when it's in a sequence - as soon as another expectation that comes after it in the sequence has been used, it automatically retires (and will never be used to match any call). ## Uninteresting Calls ## A mock object may have many methods, and not all of them are that interesting. For example, in some tests we may not care about how many times `GetX()` and `GetY()` get called. In Google Mock, if you are not interested in a method, just don't say anything about it. If a call to this method occurs, you'll see a warning in the test output, but it won't be a failure. # What Now? # Congratulations! You've learned enough about Google Mock to start using it. Now, you might want to join the [googlemock](http://groups.google.com/group/googlemock) discussion group and actually write some tests using Google Mock - it will be fun. Hey, it may even be addictive - you've been warned. Then, if you feel like increasing your mock quotient, you should move on to the [CookBook](V1_7_CookBook.md). You can learn many advanced features of Google Mock there -- and advance your level of enjoyment and testing bliss.nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/docs/v1_7/FrequentlyAskedQuestions.md000066400000000000000000000563041455373415500317170ustar00rootroot00000000000000 Please send your questions to the [googlemock](http://groups.google.com/group/googlemock) discussion group. If you need help with compiler errors, make sure you have tried [Google Mock Doctor](#How_am_I_supposed_to_make_sense_of_these_horrible_template_error.md) first. ## When I call a method on my mock object, the method for the real object is invoked instead. What's the problem? ## In order for a method to be mocked, it must be _virtual_, unless you use the [high-perf dependency injection technique](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Mocking_Nonvirtual_Methods). ## I wrote some matchers. After I upgraded to a new version of Google Mock, they no longer compile. What's going on? ## After version 1.4.0 of Google Mock was released, we had an idea on how to make it easier to write matchers that can generate informative messages efficiently. We experimented with this idea and liked what we saw. Therefore we decided to implement it. Unfortunately, this means that if you have defined your own matchers by implementing `MatcherInterface` or using `MakePolymorphicMatcher()`, your definitions will no longer compile. Matchers defined using the `MATCHER*` family of macros are not affected. Sorry for the hassle if your matchers are affected. We believe it's in everyone's long-term interest to make this change sooner than later. Fortunately, it's usually not hard to migrate an existing matcher to the new API. Here's what you need to do: If you wrote your matcher like this: ``` // Old matcher definition that doesn't work with the latest // Google Mock. using ::testing::MatcherInterface; ... class MyWonderfulMatcher : public MatcherInterface { public: ... virtual bool Matches(MyType value) const { // Returns true if value matches. return value.GetFoo() > 5; } ... }; ``` you'll need to change it to: ``` // New matcher definition that works with the latest Google Mock. using ::testing::MatcherInterface; using ::testing::MatchResultListener; ... class MyWonderfulMatcher : public MatcherInterface { public: ... virtual bool MatchAndExplain(MyType value, MatchResultListener* listener) const { // Returns true if value matches. return value.GetFoo() > 5; } ... }; ``` (i.e. rename `Matches()` to `MatchAndExplain()` and give it a second argument of type `MatchResultListener*`.) If you were also using `ExplainMatchResultTo()` to improve the matcher message: ``` // Old matcher definition that doesn't work with the lastest // Google Mock. using ::testing::MatcherInterface; ... class MyWonderfulMatcher : public MatcherInterface { public: ... virtual bool Matches(MyType value) const { // Returns true if value matches. return value.GetFoo() > 5; } virtual void ExplainMatchResultTo(MyType value, ::std::ostream* os) const { // Prints some helpful information to os to help // a user understand why value matches (or doesn't match). *os << "the Foo property is " << value.GetFoo(); } ... }; ``` you should move the logic of `ExplainMatchResultTo()` into `MatchAndExplain()`, using the `MatchResultListener` argument where the `::std::ostream` was used: ``` // New matcher definition that works with the latest Google Mock. using ::testing::MatcherInterface; using ::testing::MatchResultListener; ... class MyWonderfulMatcher : public MatcherInterface { public: ... virtual bool MatchAndExplain(MyType value, MatchResultListener* listener) const { // Returns true if value matches. *listener << "the Foo property is " << value.GetFoo(); return value.GetFoo() > 5; } ... }; ``` If your matcher is defined using `MakePolymorphicMatcher()`: ``` // Old matcher definition that doesn't work with the latest // Google Mock. using ::testing::MakePolymorphicMatcher; ... class MyGreatMatcher { public: ... bool Matches(MyType value) const { // Returns true if value matches. return value.GetBar() < 42; } ... }; ... MakePolymorphicMatcher(MyGreatMatcher()) ... ``` you should rename the `Matches()` method to `MatchAndExplain()` and add a `MatchResultListener*` argument (the same as what you need to do for matchers defined by implementing `MatcherInterface`): ``` // New matcher definition that works with the latest Google Mock. using ::testing::MakePolymorphicMatcher; using ::testing::MatchResultListener; ... class MyGreatMatcher { public: ... bool MatchAndExplain(MyType value, MatchResultListener* listener) const { // Returns true if value matches. return value.GetBar() < 42; } ... }; ... MakePolymorphicMatcher(MyGreatMatcher()) ... ``` If your polymorphic matcher uses `ExplainMatchResultTo()` for better failure messages: ``` // Old matcher definition that doesn't work with the latest // Google Mock. using ::testing::MakePolymorphicMatcher; ... class MyGreatMatcher { public: ... bool Matches(MyType value) const { // Returns true if value matches. return value.GetBar() < 42; } ... }; void ExplainMatchResultTo(const MyGreatMatcher& matcher, MyType value, ::std::ostream* os) { // Prints some helpful information to os to help // a user understand why value matches (or doesn't match). *os << "the Bar property is " << value.GetBar(); } ... MakePolymorphicMatcher(MyGreatMatcher()) ... ``` you'll need to move the logic inside `ExplainMatchResultTo()` to `MatchAndExplain()`: ``` // New matcher definition that works with the latest Google Mock. using ::testing::MakePolymorphicMatcher; using ::testing::MatchResultListener; ... class MyGreatMatcher { public: ... bool MatchAndExplain(MyType value, MatchResultListener* listener) const { // Returns true if value matches. *listener << "the Bar property is " << value.GetBar(); return value.GetBar() < 42; } ... }; ... MakePolymorphicMatcher(MyGreatMatcher()) ... ``` For more information, you can read these [two](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Writing_New_Monomorphic_Matchers) [recipes](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Writing_New_Polymorphic_Matchers) from the cookbook. As always, you are welcome to post questions on `googlemock@googlegroups.com` if you need any help. ## When using Google Mock, do I have to use Google Test as the testing framework? I have my favorite testing framework and don't want to switch. ## Google Mock works out of the box with Google Test. However, it's easy to configure it to work with any testing framework of your choice. [Here](http://code.google.com/p/googlemock/wiki/V1_7_ForDummies#Using_Google_Mock_with_Any_Testing_Framework) is how. ## How am I supposed to make sense of these horrible template errors? ## If you are confused by the compiler errors gcc threw at you, try consulting the _Google Mock Doctor_ tool first. What it does is to scan stdin for gcc error messages, and spit out diagnoses on the problems (we call them diseases) your code has. To "install", run command: ``` alias gmd='/scripts/gmock_doctor.py' ``` To use it, do: ``` 2>&1 | gmd ``` For example: ``` make my_test 2>&1 | gmd ``` Or you can run `gmd` and copy-n-paste gcc's error messages to it. ## Can I mock a variadic function? ## You cannot mock a variadic function (i.e. a function taking ellipsis (`...`) arguments) directly in Google Mock. The problem is that in general, there is _no way_ for a mock object to know how many arguments are passed to the variadic method, and what the arguments' types are. Only the _author of the base class_ knows the protocol, and we cannot look into his head. Therefore, to mock such a function, the _user_ must teach the mock object how to figure out the number of arguments and their types. One way to do it is to provide overloaded versions of the function. Ellipsis arguments are inherited from C and not really a C++ feature. They are unsafe to use and don't work with arguments that have constructors or destructors. Therefore we recommend to avoid them in C++ as much as possible. ## MSVC gives me warning C4301 or C4373 when I define a mock method with a const parameter. Why? ## If you compile this using Microsoft Visual C++ 2005 SP1: ``` class Foo { ... virtual void Bar(const int i) = 0; }; class MockFoo : public Foo { ... MOCK_METHOD1(Bar, void(const int i)); }; ``` You may get the following warning: ``` warning C4301: 'MockFoo::Bar': overriding virtual function only differs from 'Foo::Bar' by const/volatile qualifier ``` This is a MSVC bug. The same code compiles fine with gcc ,for example. If you use Visual C++ 2008 SP1, you would get the warning: ``` warning C4373: 'MockFoo::Bar': virtual function overrides 'Foo::Bar', previous versions of the compiler did not override when parameters only differed by const/volatile qualifiers ``` In C++, if you _declare_ a function with a `const` parameter, the `const` modifier is _ignored_. Therefore, the `Foo` base class above is equivalent to: ``` class Foo { ... virtual void Bar(int i) = 0; // int or const int? Makes no difference. }; ``` In fact, you can _declare_ Bar() with an `int` parameter, and _define_ it with a `const int` parameter. The compiler will still match them up. Since making a parameter `const` is meaningless in the method _declaration_, we recommend to remove it in both `Foo` and `MockFoo`. That should workaround the VC bug. Note that we are talking about the _top-level_ `const` modifier here. If the function parameter is passed by pointer or reference, declaring the _pointee_ or _referee_ as `const` is still meaningful. For example, the following two declarations are _not_ equivalent: ``` void Bar(int* p); // Neither p nor *p is const. void Bar(const int* p); // p is not const, but *p is. ``` ## I have a huge mock class, and Microsoft Visual C++ runs out of memory when compiling it. What can I do? ## We've noticed that when the `/clr` compiler flag is used, Visual C++ uses 5~6 times as much memory when compiling a mock class. We suggest to avoid `/clr` when compiling native C++ mocks. ## I can't figure out why Google Mock thinks my expectations are not satisfied. What should I do? ## You might want to run your test with `--gmock_verbose=info`. This flag lets Google Mock print a trace of every mock function call it receives. By studying the trace, you'll gain insights on why the expectations you set are not met. ## How can I assert that a function is NEVER called? ## ``` EXPECT_CALL(foo, Bar(_)) .Times(0); ``` ## I have a failed test where Google Mock tells me TWICE that a particular expectation is not satisfied. Isn't this redundant? ## When Google Mock detects a failure, it prints relevant information (the mock function arguments, the state of relevant expectations, and etc) to help the user debug. If another failure is detected, Google Mock will do the same, including printing the state of relevant expectations. Sometimes an expectation's state didn't change between two failures, and you'll see the same description of the state twice. They are however _not_ redundant, as they refer to _different points in time_. The fact they are the same _is_ interesting information. ## I get a heap check failure when using a mock object, but using a real object is fine. What can be wrong? ## Does the class (hopefully a pure interface) you are mocking have a virtual destructor? Whenever you derive from a base class, make sure its destructor is virtual. Otherwise Bad Things will happen. Consider the following code: ``` class Base { public: // Not virtual, but should be. ~Base() { ... } ... }; class Derived : public Base { public: ... private: std::string value_; }; ... Base* p = new Derived; ... delete p; // Surprise! ~Base() will be called, but ~Derived() will not // - value_ is leaked. ``` By changing `~Base()` to virtual, `~Derived()` will be correctly called when `delete p` is executed, and the heap checker will be happy. ## The "newer expectations override older ones" rule makes writing expectations awkward. Why does Google Mock do that? ## When people complain about this, often they are referring to code like: ``` // foo.Bar() should be called twice, return 1 the first time, and return // 2 the second time. However, I have to write the expectations in the // reverse order. This sucks big time!!! EXPECT_CALL(foo, Bar()) .WillOnce(Return(2)) .RetiresOnSaturation(); EXPECT_CALL(foo, Bar()) .WillOnce(Return(1)) .RetiresOnSaturation(); ``` The problem is that they didn't pick the **best** way to express the test's intent. By default, expectations don't have to be matched in _any_ particular order. If you want them to match in a certain order, you need to be explicit. This is Google Mock's (and jMock's) fundamental philosophy: it's easy to accidentally over-specify your tests, and we want to make it harder to do so. There are two better ways to write the test spec. You could either put the expectations in sequence: ``` // foo.Bar() should be called twice, return 1 the first time, and return // 2 the second time. Using a sequence, we can write the expectations // in their natural order. { InSequence s; EXPECT_CALL(foo, Bar()) .WillOnce(Return(1)) .RetiresOnSaturation(); EXPECT_CALL(foo, Bar()) .WillOnce(Return(2)) .RetiresOnSaturation(); } ``` or you can put the sequence of actions in the same expectation: ``` // foo.Bar() should be called twice, return 1 the first time, and return // 2 the second time. EXPECT_CALL(foo, Bar()) .WillOnce(Return(1)) .WillOnce(Return(2)) .RetiresOnSaturation(); ``` Back to the original questions: why does Google Mock search the expectations (and `ON_CALL`s) from back to front? Because this allows a user to set up a mock's behavior for the common case early (e.g. in the mock's constructor or the test fixture's set-up phase) and customize it with more specific rules later. If Google Mock searches from front to back, this very useful pattern won't be possible. ## Google Mock prints a warning when a function without EXPECT\_CALL is called, even if I have set its behavior using ON\_CALL. Would it be reasonable not to show the warning in this case? ## When choosing between being neat and being safe, we lean toward the latter. So the answer is that we think it's better to show the warning. Often people write `ON_CALL`s in the mock object's constructor or `SetUp()`, as the default behavior rarely changes from test to test. Then in the test body they set the expectations, which are often different for each test. Having an `ON_CALL` in the set-up part of a test doesn't mean that the calls are expected. If there's no `EXPECT_CALL` and the method is called, it's possibly an error. If we quietly let the call go through without notifying the user, bugs may creep in unnoticed. If, however, you are sure that the calls are OK, you can write ``` EXPECT_CALL(foo, Bar(_)) .WillRepeatedly(...); ``` instead of ``` ON_CALL(foo, Bar(_)) .WillByDefault(...); ``` This tells Google Mock that you do expect the calls and no warning should be printed. Also, you can control the verbosity using the `--gmock_verbose` flag. If you find the output too noisy when debugging, just choose a less verbose level. ## How can I delete the mock function's argument in an action? ## If you find yourself needing to perform some action that's not supported by Google Mock directly, remember that you can define your own actions using [MakeAction()](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Writing_New_Actions) or [MakePolymorphicAction()](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Writing_New_Polymorphic_Actions), or you can write a stub function and invoke it using [Invoke()](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Using_Functions_Methods_Functors). ## MOCK\_METHODn()'s second argument looks funny. Why don't you use the MOCK\_METHODn(Method, return\_type, arg\_1, ..., arg\_n) syntax? ## What?! I think it's beautiful. :-) While which syntax looks more natural is a subjective matter to some extent, Google Mock's syntax was chosen for several practical advantages it has. Try to mock a function that takes a map as an argument: ``` virtual int GetSize(const map& m); ``` Using the proposed syntax, it would be: ``` MOCK_METHOD1(GetSize, int, const map& m); ``` Guess what? You'll get a compiler error as the compiler thinks that `const map& m` are **two**, not one, arguments. To work around this you can use `typedef` to give the map type a name, but that gets in the way of your work. Google Mock's syntax avoids this problem as the function's argument types are protected inside a pair of parentheses: ``` // This compiles fine. MOCK_METHOD1(GetSize, int(const map& m)); ``` You still need a `typedef` if the return type contains an unprotected comma, but that's much rarer. Other advantages include: 1. `MOCK_METHOD1(Foo, int, bool)` can leave a reader wonder whether the method returns `int` or `bool`, while there won't be such confusion using Google Mock's syntax. 1. The way Google Mock describes a function type is nothing new, although many people may not be familiar with it. The same syntax was used in C, and the `function` library in `tr1` uses this syntax extensively. Since `tr1` will become a part of the new version of STL, we feel very comfortable to be consistent with it. 1. The function type syntax is also used in other parts of Google Mock's API (e.g. the action interface) in order to make the implementation tractable. A user needs to learn it anyway in order to utilize Google Mock's more advanced features. We'd as well stick to the same syntax in `MOCK_METHOD*`! ## My code calls a static/global function. Can I mock it? ## You can, but you need to make some changes. In general, if you find yourself needing to mock a static function, it's a sign that your modules are too tightly coupled (and less flexible, less reusable, less testable, etc). You are probably better off defining a small interface and call the function through that interface, which then can be easily mocked. It's a bit of work initially, but usually pays for itself quickly. This Google Testing Blog [post](http://googletesting.blogspot.com/2008/06/defeat-static-cling.html) says it excellently. Check it out. ## My mock object needs to do complex stuff. It's a lot of pain to specify the actions. Google Mock sucks! ## I know it's not a question, but you get an answer for free any way. :-) With Google Mock, you can create mocks in C++ easily. And people might be tempted to use them everywhere. Sometimes they work great, and sometimes you may find them, well, a pain to use. So, what's wrong in the latter case? When you write a test without using mocks, you exercise the code and assert that it returns the correct value or that the system is in an expected state. This is sometimes called "state-based testing". Mocks are great for what some call "interaction-based" testing: instead of checking the system state at the very end, mock objects verify that they are invoked the right way and report an error as soon as it arises, giving you a handle on the precise context in which the error was triggered. This is often more effective and economical to do than state-based testing. If you are doing state-based testing and using a test double just to simulate the real object, you are probably better off using a fake. Using a mock in this case causes pain, as it's not a strong point for mocks to perform complex actions. If you experience this and think that mocks suck, you are just not using the right tool for your problem. Or, you might be trying to solve the wrong problem. :-) ## I got a warning "Uninteresting function call encountered - default action taken.." Should I panic? ## By all means, NO! It's just an FYI. What it means is that you have a mock function, you haven't set any expectations on it (by Google Mock's rule this means that you are not interested in calls to this function and therefore it can be called any number of times), and it is called. That's OK - you didn't say it's not OK to call the function! What if you actually meant to disallow this function to be called, but forgot to write `EXPECT_CALL(foo, Bar()).Times(0)`? While one can argue that it's the user's fault, Google Mock tries to be nice and prints you a note. So, when you see the message and believe that there shouldn't be any uninteresting calls, you should investigate what's going on. To make your life easier, Google Mock prints the function name and arguments when an uninteresting call is encountered. ## I want to define a custom action. Should I use Invoke() or implement the action interface? ## Either way is fine - you want to choose the one that's more convenient for your circumstance. Usually, if your action is for a particular function type, defining it using `Invoke()` should be easier; if your action can be used in functions of different types (e.g. if you are defining `Return(value)`), `MakePolymorphicAction()` is easiest. Sometimes you want precise control on what types of functions the action can be used in, and implementing `ActionInterface` is the way to go here. See the implementation of `Return()` in `include/gmock/gmock-actions.h` for an example. ## I'm using the set-argument-pointee action, and the compiler complains about "conflicting return type specified". What does it mean? ## You got this error as Google Mock has no idea what value it should return when the mock method is called. `SetArgPointee()` says what the side effect is, but doesn't say what the return value should be. You need `DoAll()` to chain a `SetArgPointee()` with a `Return()`. See this [recipe](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Mocking_Side_Effects) for more details and an example. ## My question is not in your FAQ! ## If you cannot find the answer to your question in this FAQ, there are some other resources you can use: 1. read other [wiki pages](http://code.google.com/p/googlemock/w/list), 1. search the mailing list [archive](http://groups.google.com/group/googlemock/topics), 1. ask it on [googlemock@googlegroups.com](mailto:googlemock@googlegroups.com) and someone will answer it (to prevent spam, we require you to join the [discussion group](http://groups.google.com/group/googlemock) before you can post.). Please note that creating an issue in the [issue tracker](http://code.google.com/p/googlemock/issues/list) is _not_ a good way to get your answer, as it is monitored infrequently by a very small number of people. When asking a question, it's helpful to provide as much of the following information as possible (people cannot help you if there's not enough information in your question): * the version (or the revision number if you check out from SVN directly) of Google Mock you use (Google Mock is under active development, so it's possible that your problem has been solved in a later version), * your operating system, * the name and version of your compiler, * the complete command line flags you give to your compiler, * the complete compiler error messages (if the question is about compilation), * the _actual_ code (ideally, a minimal but complete program) that has the problem you encounter.nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/include/000077500000000000000000000000001455373415500242635ustar00rootroot00000000000000nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/include/gmock/000077500000000000000000000000001455373415500253635ustar00rootroot00000000000000nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/include/gmock/gmock-actions.h000066400000000000000000001204131455373415500302730ustar00rootroot00000000000000// Copyright 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // Google Mock - a framework for writing C++ mock classes. // // This file implements some commonly used actions. #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_ #ifndef _WIN32_WCE # include #endif #include #include #include "gmock/internal/gmock-internal-utils.h" #include "gmock/internal/gmock-port.h" #if GTEST_HAS_STD_TYPE_TRAITS_ // Defined by gtest-port.h via gmock-port.h. #include #endif namespace testing { // To implement an action Foo, define: // 1. a class FooAction that implements the ActionInterface interface, and // 2. a factory function that creates an Action object from a // const FooAction*. // // The two-level delegation design follows that of Matcher, providing // consistency for extension developers. It also eases ownership // management as Action objects can now be copied like plain values. namespace internal { template class ActionAdaptor; // BuiltInDefaultValueGetter::Get() returns a // default-constructed T value. BuiltInDefaultValueGetter::Get() crashes with an error. // // This primary template is used when kDefaultConstructible is true. template struct BuiltInDefaultValueGetter { static T Get() { return T(); } }; template struct BuiltInDefaultValueGetter { static T Get() { Assert(false, __FILE__, __LINE__, "Default action undefined for the function return type."); return internal::Invalid(); // The above statement will never be reached, but is required in // order for this function to compile. } }; // BuiltInDefaultValue::Get() returns the "built-in" default value // for type T, which is NULL when T is a raw pointer type, 0 when T is // a numeric type, false when T is bool, or "" when T is string or // std::string. In addition, in C++11 and above, it turns a // default-constructed T value if T is default constructible. For any // other type T, the built-in default T value is undefined, and the // function will abort the process. template class BuiltInDefaultValue { public: #if GTEST_HAS_STD_TYPE_TRAITS_ // This function returns true iff type T has a built-in default value. static bool Exists() { return ::std::is_default_constructible::value; } static T Get() { return BuiltInDefaultValueGetter< T, ::std::is_default_constructible::value>::Get(); } #else // GTEST_HAS_STD_TYPE_TRAITS_ // This function returns true iff type T has a built-in default value. static bool Exists() { return false; } static T Get() { return BuiltInDefaultValueGetter::Get(); } #endif // GTEST_HAS_STD_TYPE_TRAITS_ }; // This partial specialization says that we use the same built-in // default value for T and const T. template class BuiltInDefaultValue { public: static bool Exists() { return BuiltInDefaultValue::Exists(); } static T Get() { return BuiltInDefaultValue::Get(); } }; // This partial specialization defines the default values for pointer // types. template class BuiltInDefaultValue { public: static bool Exists() { return true; } static T* Get() { return NULL; } }; // The following specializations define the default values for // specific types we care about. #define GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(type, value) \ template <> \ class BuiltInDefaultValue { \ public: \ static bool Exists() { return true; } \ static type Get() { return value; } \ } GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(void, ); // NOLINT #if GTEST_HAS_GLOBAL_STRING GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(::string, ""); #endif // GTEST_HAS_GLOBAL_STRING GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(::std::string, ""); GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(bool, false); GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned char, '\0'); GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed char, '\0'); GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(char, '\0'); // There's no need for a default action for signed wchar_t, as that // type is the same as wchar_t for gcc, and invalid for MSVC. // // There's also no need for a default action for unsigned wchar_t, as // that type is the same as unsigned int for gcc, and invalid for // MSVC. #if GMOCK_WCHAR_T_IS_NATIVE_ GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(wchar_t, 0U); // NOLINT #endif GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned short, 0U); // NOLINT GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed short, 0); // NOLINT GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned int, 0U); GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed int, 0); GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned long, 0UL); // NOLINT GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed long, 0L); // NOLINT GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(UInt64, 0); GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(Int64, 0); GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(float, 0); GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(double, 0); #undef GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_ } // namespace internal // When an unexpected function call is encountered, Google Mock will // let it return a default value if the user has specified one for its // return type, or if the return type has a built-in default value; // otherwise Google Mock won't know what value to return and will have // to abort the process. // // The DefaultValue class allows a user to specify the // default value for a type T that is both copyable and publicly // destructible (i.e. anything that can be used as a function return // type). The usage is: // // // Sets the default value for type T to be foo. // DefaultValue::Set(foo); template class DefaultValue { public: // Sets the default value for type T; requires T to be // copy-constructable and have a public destructor. static void Set(T x) { delete producer_; producer_ = new FixedValueProducer(x); } // Provides a factory function to be called to generate the default value. // This method can be used even if T is only move-constructible, but it is not // limited to that case. typedef T (*FactoryFunction)(); static void SetFactory(FactoryFunction factory) { delete producer_; producer_ = new FactoryValueProducer(factory); } // Unsets the default value for type T. static void Clear() { delete producer_; producer_ = NULL; } // Returns true iff the user has set the default value for type T. static bool IsSet() { return producer_ != NULL; } // Returns true if T has a default return value set by the user or there // exists a built-in default value. static bool Exists() { return IsSet() || internal::BuiltInDefaultValue::Exists(); } // Returns the default value for type T if the user has set one; // otherwise returns the built-in default value. Requires that Exists() // is true, which ensures that the return value is well-defined. static T Get() { return producer_ == NULL ? internal::BuiltInDefaultValue::Get() : producer_->Produce(); } private: class ValueProducer { public: virtual ~ValueProducer() {} virtual T Produce() = 0; }; class FixedValueProducer : public ValueProducer { public: explicit FixedValueProducer(T value) : value_(value) {} virtual T Produce() { return value_; } private: const T value_; GTEST_DISALLOW_COPY_AND_ASSIGN_(FixedValueProducer); }; class FactoryValueProducer : public ValueProducer { public: explicit FactoryValueProducer(FactoryFunction factory) : factory_(factory) {} virtual T Produce() { return factory_(); } private: const FactoryFunction factory_; GTEST_DISALLOW_COPY_AND_ASSIGN_(FactoryValueProducer); }; static ValueProducer* producer_; }; // This partial specialization allows a user to set default values for // reference types. template class DefaultValue { public: // Sets the default value for type T&. static void Set(T& x) { // NOLINT address_ = &x; } // Unsets the default value for type T&. static void Clear() { address_ = NULL; } // Returns true iff the user has set the default value for type T&. static bool IsSet() { return address_ != NULL; } // Returns true if T has a default return value set by the user or there // exists a built-in default value. static bool Exists() { return IsSet() || internal::BuiltInDefaultValue::Exists(); } // Returns the default value for type T& if the user has set one; // otherwise returns the built-in default value if there is one; // otherwise aborts the process. static T& Get() { return address_ == NULL ? internal::BuiltInDefaultValue::Get() : *address_; } private: static T* address_; }; // This specialization allows DefaultValue::Get() to // compile. template <> class DefaultValue { public: static bool Exists() { return true; } static void Get() {} }; // Points to the user-set default value for type T. template typename DefaultValue::ValueProducer* DefaultValue::producer_ = NULL; // Points to the user-set default value for type T&. template T* DefaultValue::address_ = NULL; // Implement this interface to define an action for function type F. template class ActionInterface { public: typedef typename internal::Function::Result Result; typedef typename internal::Function::ArgumentTuple ArgumentTuple; ActionInterface() {} virtual ~ActionInterface() {} // Performs the action. This method is not const, as in general an // action can have side effects and be stateful. For example, a // get-the-next-element-from-the-collection action will need to // remember the current element. virtual Result Perform(const ArgumentTuple& args) = 0; private: GTEST_DISALLOW_COPY_AND_ASSIGN_(ActionInterface); }; // An Action is a copyable and IMMUTABLE (except by assignment) // object that represents an action to be taken when a mock function // of type F is called. The implementation of Action is just a // linked_ptr to const ActionInterface, so copying is fairly cheap. // Don't inherit from Action! // // You can view an object implementing ActionInterface as a // concrete action (including its current state), and an Action // object as a handle to it. template class Action { public: typedef typename internal::Function::Result Result; typedef typename internal::Function::ArgumentTuple ArgumentTuple; // Constructs a null Action. Needed for storing Action objects in // STL containers. Action() : impl_(NULL) {} // Constructs an Action from its implementation. A NULL impl is // used to represent the "do-default" action. explicit Action(ActionInterface* impl) : impl_(impl) {} // Copy constructor. Action(const Action& action) : impl_(action.impl_) {} // This constructor allows us to turn an Action object into an // Action, as long as F's arguments can be implicitly converted // to Func's and Func's return type can be implicitly converted to // F's. template explicit Action(const Action& action); // Returns true iff this is the DoDefault() action. bool IsDoDefault() const { return impl_.get() == NULL; } // Performs the action. Note that this method is const even though // the corresponding method in ActionInterface is not. The reason // is that a const Action means that it cannot be re-bound to // another concrete action, not that the concrete action it binds to // cannot change state. (Think of the difference between a const // pointer and a pointer to const.) Result Perform(const ArgumentTuple& args) const { internal::Assert( !IsDoDefault(), __FILE__, __LINE__, "You are using DoDefault() inside a composite action like " "DoAll() or WithArgs(). This is not supported for technical " "reasons. Please instead spell out the default action, or " "assign the default action to an Action variable and use " "the variable in various places."); return impl_->Perform(args); } private: template friend class internal::ActionAdaptor; internal::linked_ptr > impl_; }; // The PolymorphicAction class template makes it easy to implement a // polymorphic action (i.e. an action that can be used in mock // functions of than one type, e.g. Return()). // // To define a polymorphic action, a user first provides a COPYABLE // implementation class that has a Perform() method template: // // class FooAction { // public: // template // Result Perform(const ArgumentTuple& args) const { // // Processes the arguments and returns a result, using // // tr1::get(args) to get the N-th (0-based) argument in the tuple. // } // ... // }; // // Then the user creates the polymorphic action using // MakePolymorphicAction(object) where object has type FooAction. See // the definition of Return(void) and SetArgumentPointee(value) for // complete examples. template class PolymorphicAction { public: explicit PolymorphicAction(const Impl& impl) : impl_(impl) {} template operator Action() const { return Action(new MonomorphicImpl(impl_)); } private: template class MonomorphicImpl : public ActionInterface { public: typedef typename internal::Function::Result Result; typedef typename internal::Function::ArgumentTuple ArgumentTuple; explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {} virtual Result Perform(const ArgumentTuple& args) { return impl_.template Perform(args); } private: Impl impl_; GTEST_DISALLOW_ASSIGN_(MonomorphicImpl); }; Impl impl_; GTEST_DISALLOW_ASSIGN_(PolymorphicAction); }; // Creates an Action from its implementation and returns it. The // created Action object owns the implementation. template Action MakeAction(ActionInterface* impl) { return Action(impl); } // Creates a polymorphic action from its implementation. This is // easier to use than the PolymorphicAction constructor as it // doesn't require you to explicitly write the template argument, e.g. // // MakePolymorphicAction(foo); // vs // PolymorphicAction(foo); template inline PolymorphicAction MakePolymorphicAction(const Impl& impl) { return PolymorphicAction(impl); } namespace internal { // Allows an Action object to pose as an Action, as long as F2 // and F1 are compatible. template class ActionAdaptor : public ActionInterface { public: typedef typename internal::Function::Result Result; typedef typename internal::Function::ArgumentTuple ArgumentTuple; explicit ActionAdaptor(const Action& from) : impl_(from.impl_) {} virtual Result Perform(const ArgumentTuple& args) { return impl_->Perform(args); } private: const internal::linked_ptr > impl_; GTEST_DISALLOW_ASSIGN_(ActionAdaptor); }; // Helper struct to specialize ReturnAction to execute a move instead of a copy // on return. Useful for move-only types, but could be used on any type. template struct ByMoveWrapper { explicit ByMoveWrapper(T value) : payload(internal::move(value)) {} T payload; }; // Implements the polymorphic Return(x) action, which can be used in // any function that returns the type of x, regardless of the argument // types. // // Note: The value passed into Return must be converted into // Function::Result when this action is cast to Action rather than // when that action is performed. This is important in scenarios like // // MOCK_METHOD1(Method, T(U)); // ... // { // Foo foo; // X x(&foo); // EXPECT_CALL(mock, Method(_)).WillOnce(Return(x)); // } // // In the example above the variable x holds reference to foo which leaves // scope and gets destroyed. If copying X just copies a reference to foo, // that copy will be left with a hanging reference. If conversion to T // makes a copy of foo, the above code is safe. To support that scenario, we // need to make sure that the type conversion happens inside the EXPECT_CALL // statement, and conversion of the result of Return to Action is a // good place for that. // template class ReturnAction { public: // Constructs a ReturnAction object from the value to be returned. // 'value' is passed by value instead of by const reference in order // to allow Return("string literal") to compile. explicit ReturnAction(R value) : value_(new R(internal::move(value))) {} // This template type conversion operator allows Return(x) to be // used in ANY function that returns x's type. template operator Action() const { // Assert statement belongs here because this is the best place to verify // conditions on F. It produces the clearest error messages // in most compilers. // Impl really belongs in this scope as a local class but can't // because MSVC produces duplicate symbols in different translation units // in this case. Until MS fixes that bug we put Impl into the class scope // and put the typedef both here (for use in assert statement) and // in the Impl class. But both definitions must be the same. typedef typename Function::Result Result; GTEST_COMPILE_ASSERT_( !is_reference::value, use_ReturnRef_instead_of_Return_to_return_a_reference); return Action(new Impl(value_)); } private: // Implements the Return(x) action for a particular function type F. template class Impl : public ActionInterface { public: typedef typename Function::Result Result; typedef typename Function::ArgumentTuple ArgumentTuple; // The implicit cast is necessary when Result has more than one // single-argument constructor (e.g. Result is std::vector) and R // has a type conversion operator template. In that case, value_(value) // won't compile as the compiler doesn't known which constructor of // Result to call. ImplicitCast_ forces the compiler to convert R to // Result without considering explicit constructors, thus resolving the // ambiguity. value_ is then initialized using its copy constructor. explicit Impl(const linked_ptr& value) : value_before_cast_(*value), value_(ImplicitCast_(value_before_cast_)) {} virtual Result Perform(const ArgumentTuple&) { return value_; } private: GTEST_COMPILE_ASSERT_(!is_reference::value, Result_cannot_be_a_reference_type); // We save the value before casting just in case it is being cast to a // wrapper type. R value_before_cast_; Result value_; GTEST_DISALLOW_COPY_AND_ASSIGN_(Impl); }; // Partially specialize for ByMoveWrapper. This version of ReturnAction will // move its contents instead. template class Impl, F> : public ActionInterface { public: typedef typename Function::Result Result; typedef typename Function::ArgumentTuple ArgumentTuple; explicit Impl(const linked_ptr& wrapper) : performed_(false), wrapper_(wrapper) {} virtual Result Perform(const ArgumentTuple&) { GTEST_CHECK_(!performed_) << "A ByMove() action should only be performed once."; performed_ = true; return internal::move(wrapper_->payload); } private: bool performed_; const linked_ptr wrapper_; GTEST_DISALLOW_ASSIGN_(Impl); }; const linked_ptr value_; GTEST_DISALLOW_ASSIGN_(ReturnAction); }; // Implements the ReturnNull() action. class ReturnNullAction { public: // Allows ReturnNull() to be used in any pointer-returning function. In C++11 // this is enforced by returning nullptr, and in non-C++11 by asserting a // pointer type on compile time. template static Result Perform(const ArgumentTuple&) { #if GTEST_LANG_CXX11 return nullptr; #else GTEST_COMPILE_ASSERT_(internal::is_pointer::value, ReturnNull_can_be_used_to_return_a_pointer_only); return NULL; #endif // GTEST_LANG_CXX11 } }; // Implements the Return() action. class ReturnVoidAction { public: // Allows Return() to be used in any void-returning function. template static void Perform(const ArgumentTuple&) { CompileAssertTypesEqual(); } }; // Implements the polymorphic ReturnRef(x) action, which can be used // in any function that returns a reference to the type of x, // regardless of the argument types. template class ReturnRefAction { public: // Constructs a ReturnRefAction object from the reference to be returned. explicit ReturnRefAction(T& ref) : ref_(ref) {} // NOLINT // This template type conversion operator allows ReturnRef(x) to be // used in ANY function that returns a reference to x's type. template operator Action() const { typedef typename Function::Result Result; // Asserts that the function return type is a reference. This // catches the user error of using ReturnRef(x) when Return(x) // should be used, and generates some helpful error message. GTEST_COMPILE_ASSERT_(internal::is_reference::value, use_Return_instead_of_ReturnRef_to_return_a_value); return Action(new Impl(ref_)); } private: // Implements the ReturnRef(x) action for a particular function type F. template class Impl : public ActionInterface { public: typedef typename Function::Result Result; typedef typename Function::ArgumentTuple ArgumentTuple; explicit Impl(T& ref) : ref_(ref) {} // NOLINT virtual Result Perform(const ArgumentTuple&) { return ref_; } private: T& ref_; GTEST_DISALLOW_ASSIGN_(Impl); }; T& ref_; GTEST_DISALLOW_ASSIGN_(ReturnRefAction); }; // Implements the polymorphic ReturnRefOfCopy(x) action, which can be // used in any function that returns a reference to the type of x, // regardless of the argument types. template class ReturnRefOfCopyAction { public: // Constructs a ReturnRefOfCopyAction object from the reference to // be returned. explicit ReturnRefOfCopyAction(const T& value) : value_(value) {} // NOLINT // This template type conversion operator allows ReturnRefOfCopy(x) to be // used in ANY function that returns a reference to x's type. template operator Action() const { typedef typename Function::Result Result; // Asserts that the function return type is a reference. This // catches the user error of using ReturnRefOfCopy(x) when Return(x) // should be used, and generates some helpful error message. GTEST_COMPILE_ASSERT_( internal::is_reference::value, use_Return_instead_of_ReturnRefOfCopy_to_return_a_value); return Action(new Impl(value_)); } private: // Implements the ReturnRefOfCopy(x) action for a particular function type F. template class Impl : public ActionInterface { public: typedef typename Function::Result Result; typedef typename Function::ArgumentTuple ArgumentTuple; explicit Impl(const T& value) : value_(value) {} // NOLINT virtual Result Perform(const ArgumentTuple&) { return value_; } private: T value_; GTEST_DISALLOW_ASSIGN_(Impl); }; const T value_; GTEST_DISALLOW_ASSIGN_(ReturnRefOfCopyAction); }; // Implements the polymorphic DoDefault() action. class DoDefaultAction { public: // This template type conversion operator allows DoDefault() to be // used in any function. template operator Action() const { return Action(NULL); } }; // Implements the Assign action to set a given pointer referent to a // particular value. template class AssignAction { public: AssignAction(T1* ptr, T2 value) : ptr_(ptr), value_(value) {} template void Perform(const ArgumentTuple& /* args */) const { *ptr_ = value_; } private: T1* const ptr_; const T2 value_; GTEST_DISALLOW_ASSIGN_(AssignAction); }; #if !GTEST_OS_WINDOWS_MOBILE // Implements the SetErrnoAndReturn action to simulate return from // various system calls and libc functions. template class SetErrnoAndReturnAction { public: SetErrnoAndReturnAction(int errno_value, T result) : errno_(errno_value), result_(result) {} template Result Perform(const ArgumentTuple& /* args */) const { errno = errno_; return result_; } private: const int errno_; const T result_; GTEST_DISALLOW_ASSIGN_(SetErrnoAndReturnAction); }; #endif // !GTEST_OS_WINDOWS_MOBILE // Implements the SetArgumentPointee(x) action for any function // whose N-th argument (0-based) is a pointer to x's type. The // template parameter kIsProto is true iff type A is ProtocolMessage, // proto2::Message, or a sub-class of those. template class SetArgumentPointeeAction { public: // Constructs an action that sets the variable pointed to by the // N-th function argument to 'value'. explicit SetArgumentPointeeAction(const A& value) : value_(value) {} template void Perform(const ArgumentTuple& args) const { CompileAssertTypesEqual(); *::testing::get(args) = value_; } private: const A value_; GTEST_DISALLOW_ASSIGN_(SetArgumentPointeeAction); }; template class SetArgumentPointeeAction { public: // Constructs an action that sets the variable pointed to by the // N-th function argument to 'proto'. Both ProtocolMessage and // proto2::Message have the CopyFrom() method, so the same // implementation works for both. explicit SetArgumentPointeeAction(const Proto& proto) : proto_(new Proto) { proto_->CopyFrom(proto); } template void Perform(const ArgumentTuple& args) const { CompileAssertTypesEqual(); ::testing::get(args)->CopyFrom(*proto_); } private: const internal::linked_ptr proto_; GTEST_DISALLOW_ASSIGN_(SetArgumentPointeeAction); }; // Implements the InvokeWithoutArgs(f) action. The template argument // FunctionImpl is the implementation type of f, which can be either a // function pointer or a functor. InvokeWithoutArgs(f) can be used as an // Action as long as f's type is compatible with F (i.e. f can be // assigned to a tr1::function). template class InvokeWithoutArgsAction { public: // The c'tor makes a copy of function_impl (either a function // pointer or a functor). explicit InvokeWithoutArgsAction(FunctionImpl function_impl) : function_impl_(function_impl) {} // Allows InvokeWithoutArgs(f) to be used as any action whose type is // compatible with f. template Result Perform(const ArgumentTuple&) { return function_impl_(); } private: FunctionImpl function_impl_; GTEST_DISALLOW_ASSIGN_(InvokeWithoutArgsAction); }; // Implements the InvokeWithoutArgs(object_ptr, &Class::Method) action. template class InvokeMethodWithoutArgsAction { public: InvokeMethodWithoutArgsAction(Class* obj_ptr, MethodPtr method_ptr) : obj_ptr_(obj_ptr), method_ptr_(method_ptr) {} template Result Perform(const ArgumentTuple&) const { return (obj_ptr_->*method_ptr_)(); } private: Class* const obj_ptr_; const MethodPtr method_ptr_; GTEST_DISALLOW_ASSIGN_(InvokeMethodWithoutArgsAction); }; // Implements the IgnoreResult(action) action. template class IgnoreResultAction { public: explicit IgnoreResultAction(const A& action) : action_(action) {} template operator Action() const { // Assert statement belongs here because this is the best place to verify // conditions on F. It produces the clearest error messages // in most compilers. // Impl really belongs in this scope as a local class but can't // because MSVC produces duplicate symbols in different translation units // in this case. Until MS fixes that bug we put Impl into the class scope // and put the typedef both here (for use in assert statement) and // in the Impl class. But both definitions must be the same. typedef typename internal::Function::Result Result; // Asserts at compile time that F returns void. CompileAssertTypesEqual(); return Action(new Impl(action_)); } private: template class Impl : public ActionInterface { public: typedef typename internal::Function::Result Result; typedef typename internal::Function::ArgumentTuple ArgumentTuple; explicit Impl(const A& action) : action_(action) {} virtual void Perform(const ArgumentTuple& args) { // Performs the action and ignores its result. action_.Perform(args); } private: // Type OriginalFunction is the same as F except that its return // type is IgnoredValue. typedef typename internal::Function::MakeResultIgnoredValue OriginalFunction; const Action action_; GTEST_DISALLOW_ASSIGN_(Impl); }; const A action_; GTEST_DISALLOW_ASSIGN_(IgnoreResultAction); }; // A ReferenceWrapper object represents a reference to type T, // which can be either const or not. It can be explicitly converted // from, and implicitly converted to, a T&. Unlike a reference, // ReferenceWrapper can be copied and can survive template type // inference. This is used to support by-reference arguments in the // InvokeArgument(...) action. The idea was from "reference // wrappers" in tr1, which we don't have in our source tree yet. template class ReferenceWrapper { public: // Constructs a ReferenceWrapper object from a T&. explicit ReferenceWrapper(T& l_value) : pointer_(&l_value) {} // NOLINT // Allows a ReferenceWrapper object to be implicitly converted to // a T&. operator T&() const { return *pointer_; } private: T* pointer_; }; // Allows the expression ByRef(x) to be printed as a reference to x. template void PrintTo(const ReferenceWrapper& ref, ::std::ostream* os) { T& value = ref; UniversalPrinter::Print(value, os); } // Does two actions sequentially. Used for implementing the DoAll(a1, // a2, ...) action. template class DoBothAction { public: DoBothAction(Action1 action1, Action2 action2) : action1_(action1), action2_(action2) {} // This template type conversion operator allows DoAll(a1, ..., a_n) // to be used in ANY function of compatible type. template operator Action() const { return Action(new Impl(action1_, action2_)); } private: // Implements the DoAll(...) action for a particular function type F. template class Impl : public ActionInterface { public: typedef typename Function::Result Result; typedef typename Function::ArgumentTuple ArgumentTuple; typedef typename Function::MakeResultVoid VoidResult; Impl(const Action& action1, const Action& action2) : action1_(action1), action2_(action2) {} virtual Result Perform(const ArgumentTuple& args) { action1_.Perform(args); return action2_.Perform(args); } private: const Action action1_; const Action action2_; GTEST_DISALLOW_ASSIGN_(Impl); }; Action1 action1_; Action2 action2_; GTEST_DISALLOW_ASSIGN_(DoBothAction); }; } // namespace internal // An Unused object can be implicitly constructed from ANY value. // This is handy when defining actions that ignore some or all of the // mock function arguments. For example, given // // MOCK_METHOD3(Foo, double(const string& label, double x, double y)); // MOCK_METHOD3(Bar, double(int index, double x, double y)); // // instead of // // double DistanceToOriginWithLabel(const string& label, double x, double y) { // return sqrt(x*x + y*y); // } // double DistanceToOriginWithIndex(int index, double x, double y) { // return sqrt(x*x + y*y); // } // ... // EXEPCT_CALL(mock, Foo("abc", _, _)) // .WillOnce(Invoke(DistanceToOriginWithLabel)); // EXEPCT_CALL(mock, Bar(5, _, _)) // .WillOnce(Invoke(DistanceToOriginWithIndex)); // // you could write // // // We can declare any uninteresting argument as Unused. // double DistanceToOrigin(Unused, double x, double y) { // return sqrt(x*x + y*y); // } // ... // EXEPCT_CALL(mock, Foo("abc", _, _)).WillOnce(Invoke(DistanceToOrigin)); // EXEPCT_CALL(mock, Bar(5, _, _)).WillOnce(Invoke(DistanceToOrigin)); typedef internal::IgnoredValue Unused; // This constructor allows us to turn an Action object into an // Action, as long as To's arguments can be implicitly converted // to From's and From's return type cann be implicitly converted to // To's. template template Action::Action(const Action& from) : impl_(new internal::ActionAdaptor(from)) {} // Creates an action that returns 'value'. 'value' is passed by value // instead of const reference - otherwise Return("string literal") // will trigger a compiler error about using array as initializer. template internal::ReturnAction Return(R value) { return internal::ReturnAction(internal::move(value)); } // Creates an action that returns NULL. inline PolymorphicAction ReturnNull() { return MakePolymorphicAction(internal::ReturnNullAction()); } // Creates an action that returns from a void function. inline PolymorphicAction Return() { return MakePolymorphicAction(internal::ReturnVoidAction()); } // Creates an action that returns the reference to a variable. template inline internal::ReturnRefAction ReturnRef(R& x) { // NOLINT return internal::ReturnRefAction(x); } // Creates an action that returns the reference to a copy of the // argument. The copy is created when the action is constructed and // lives as long as the action. template inline internal::ReturnRefOfCopyAction ReturnRefOfCopy(const R& x) { return internal::ReturnRefOfCopyAction(x); } // Modifies the parent action (a Return() action) to perform a move of the // argument instead of a copy. // Return(ByMove()) actions can only be executed once and will assert this // invariant. template internal::ByMoveWrapper ByMove(R x) { return internal::ByMoveWrapper(internal::move(x)); } // Creates an action that does the default action for the give mock function. inline internal::DoDefaultAction DoDefault() { return internal::DoDefaultAction(); } // Creates an action that sets the variable pointed by the N-th // (0-based) function argument to 'value'. template PolymorphicAction< internal::SetArgumentPointeeAction< N, T, internal::IsAProtocolMessage::value> > SetArgPointee(const T& x) { return MakePolymorphicAction(internal::SetArgumentPointeeAction< N, T, internal::IsAProtocolMessage::value>(x)); } #if !((GTEST_GCC_VER_ && GTEST_GCC_VER_ < 40000) || GTEST_OS_SYMBIAN) // This overload allows SetArgPointee() to accept a string literal. // GCC prior to the version 4.0 and Symbian C++ compiler cannot distinguish // this overload from the templated version and emit a compile error. template PolymorphicAction< internal::SetArgumentPointeeAction > SetArgPointee(const char* p) { return MakePolymorphicAction(internal::SetArgumentPointeeAction< N, const char*, false>(p)); } template PolymorphicAction< internal::SetArgumentPointeeAction > SetArgPointee(const wchar_t* p) { return MakePolymorphicAction(internal::SetArgumentPointeeAction< N, const wchar_t*, false>(p)); } #endif // The following version is DEPRECATED. template PolymorphicAction< internal::SetArgumentPointeeAction< N, T, internal::IsAProtocolMessage::value> > SetArgumentPointee(const T& x) { return MakePolymorphicAction(internal::SetArgumentPointeeAction< N, T, internal::IsAProtocolMessage::value>(x)); } // Creates an action that sets a pointer referent to a given value. template PolymorphicAction > Assign(T1* ptr, T2 val) { return MakePolymorphicAction(internal::AssignAction(ptr, val)); } #if !GTEST_OS_WINDOWS_MOBILE // Creates an action that sets errno and returns the appropriate error. template PolymorphicAction > SetErrnoAndReturn(int errval, T result) { return MakePolymorphicAction( internal::SetErrnoAndReturnAction(errval, result)); } #endif // !GTEST_OS_WINDOWS_MOBILE // Various overloads for InvokeWithoutArgs(). // Creates an action that invokes 'function_impl' with no argument. template PolymorphicAction > InvokeWithoutArgs(FunctionImpl function_impl) { return MakePolymorphicAction( internal::InvokeWithoutArgsAction(function_impl)); } // Creates an action that invokes the given method on the given object // with no argument. template PolymorphicAction > InvokeWithoutArgs(Class* obj_ptr, MethodPtr method_ptr) { return MakePolymorphicAction( internal::InvokeMethodWithoutArgsAction( obj_ptr, method_ptr)); } // Creates an action that performs an_action and throws away its // result. In other words, it changes the return type of an_action to // void. an_action MUST NOT return void, or the code won't compile. template inline internal::IgnoreResultAction IgnoreResult(const A& an_action) { return internal::IgnoreResultAction(an_action); } // Creates a reference wrapper for the given L-value. If necessary, // you can explicitly specify the type of the reference. For example, // suppose 'derived' is an object of type Derived, ByRef(derived) // would wrap a Derived&. If you want to wrap a const Base& instead, // where Base is a base class of Derived, just write: // // ByRef(derived) template inline internal::ReferenceWrapper ByRef(T& l_value) { // NOLINT return internal::ReferenceWrapper(l_value); } } // namespace testing #endif // GMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_ nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/include/gmock/gmock-cardinalities.h000066400000000000000000000132741455373415500314540ustar00rootroot00000000000000// Copyright 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // Google Mock - a framework for writing C++ mock classes. // // This file implements some commonly used cardinalities. More // cardinalities can be defined by the user implementing the // CardinalityInterface interface if necessary. #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_ #include #include // NOLINT #include "gmock/internal/gmock-port.h" #include "gtest/gtest.h" namespace testing { // To implement a cardinality Foo, define: // 1. a class FooCardinality that implements the // CardinalityInterface interface, and // 2. a factory function that creates a Cardinality object from a // const FooCardinality*. // // The two-level delegation design follows that of Matcher, providing // consistency for extension developers. It also eases ownership // management as Cardinality objects can now be copied like plain values. // The implementation of a cardinality. class CardinalityInterface { public: virtual ~CardinalityInterface() {} // Conservative estimate on the lower/upper bound of the number of // calls allowed. virtual int ConservativeLowerBound() const { return 0; } virtual int ConservativeUpperBound() const { return INT_MAX; } // Returns true iff call_count calls will satisfy this cardinality. virtual bool IsSatisfiedByCallCount(int call_count) const = 0; // Returns true iff call_count calls will saturate this cardinality. virtual bool IsSaturatedByCallCount(int call_count) const = 0; // Describes self to an ostream. virtual void DescribeTo(::std::ostream* os) const = 0; }; // A Cardinality is a copyable and IMMUTABLE (except by assignment) // object that specifies how many times a mock function is expected to // be called. The implementation of Cardinality is just a linked_ptr // to const CardinalityInterface, so copying is fairly cheap. // Don't inherit from Cardinality! class GTEST_API_ Cardinality { public: // Constructs a null cardinality. Needed for storing Cardinality // objects in STL containers. Cardinality() {} // Constructs a Cardinality from its implementation. explicit Cardinality(const CardinalityInterface* impl) : impl_(impl) {} // Conservative estimate on the lower/upper bound of the number of // calls allowed. int ConservativeLowerBound() const { return impl_->ConservativeLowerBound(); } int ConservativeUpperBound() const { return impl_->ConservativeUpperBound(); } // Returns true iff call_count calls will satisfy this cardinality. bool IsSatisfiedByCallCount(int call_count) const { return impl_->IsSatisfiedByCallCount(call_count); } // Returns true iff call_count calls will saturate this cardinality. bool IsSaturatedByCallCount(int call_count) const { return impl_->IsSaturatedByCallCount(call_count); } // Returns true iff call_count calls will over-saturate this // cardinality, i.e. exceed the maximum number of allowed calls. bool IsOverSaturatedByCallCount(int call_count) const { return impl_->IsSaturatedByCallCount(call_count) && !impl_->IsSatisfiedByCallCount(call_count); } // Describes self to an ostream void DescribeTo(::std::ostream* os) const { impl_->DescribeTo(os); } // Describes the given actual call count to an ostream. static void DescribeActualCallCountTo(int actual_call_count, ::std::ostream* os); private: internal::linked_ptr impl_; }; // Creates a cardinality that allows at least n calls. GTEST_API_ Cardinality AtLeast(int n); // Creates a cardinality that allows at most n calls. GTEST_API_ Cardinality AtMost(int n); // Creates a cardinality that allows any number of calls. GTEST_API_ Cardinality AnyNumber(); // Creates a cardinality that allows between min and max calls. GTEST_API_ Cardinality Between(int min, int max); // Creates a cardinality that allows exactly n calls. GTEST_API_ Cardinality Exactly(int n); // Creates a cardinality from its implementation. inline Cardinality MakeCardinality(const CardinalityInterface* c) { return Cardinality(c); } } // namespace testing #endif // GMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_ nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/include/gmock/gmock-generated-actions.h000066400000000000000000003134641455373415500322410ustar00rootroot00000000000000// This file was GENERATED by a script. DO NOT EDIT BY HAND!!! // Copyright 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // Google Mock - a framework for writing C++ mock classes. // // This file implements some commonly used variadic actions. #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ #include "gmock/gmock-actions.h" #include "gmock/internal/gmock-port.h" namespace testing { namespace internal { // InvokeHelper knows how to unpack an N-tuple and invoke an N-ary // function or method with the unpacked values, where F is a function // type that takes N arguments. template class InvokeHelper; template class InvokeHelper > { public: template static R Invoke(Function function, const ::testing::tuple<>&) { return function(); } template static R InvokeMethod(Class* obj_ptr, MethodPtr method_ptr, const ::testing::tuple<>&) { return (obj_ptr->*method_ptr)(); } }; template class InvokeHelper > { public: template static R Invoke(Function function, const ::testing::tuple& args) { return function(get<0>(args)); } template static R InvokeMethod(Class* obj_ptr, MethodPtr method_ptr, const ::testing::tuple& args) { return (obj_ptr->*method_ptr)(get<0>(args)); } }; template class InvokeHelper > { public: template static R Invoke(Function function, const ::testing::tuple& args) { return function(get<0>(args), get<1>(args)); } template static R InvokeMethod(Class* obj_ptr, MethodPtr method_ptr, const ::testing::tuple& args) { return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args)); } }; template class InvokeHelper > { public: template static R Invoke(Function function, const ::testing::tuple& args) { return function(get<0>(args), get<1>(args), get<2>(args)); } template static R InvokeMethod(Class* obj_ptr, MethodPtr method_ptr, const ::testing::tuple& args) { return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), get<2>(args)); } }; template class InvokeHelper > { public: template static R Invoke(Function function, const ::testing::tuple& args) { return function(get<0>(args), get<1>(args), get<2>(args), get<3>(args)); } template static R InvokeMethod(Class* obj_ptr, MethodPtr method_ptr, const ::testing::tuple& args) { return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), get<2>(args), get<3>(args)); } }; template class InvokeHelper > { public: template static R Invoke(Function function, const ::testing::tuple& args) { return function(get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args)); } template static R InvokeMethod(Class* obj_ptr, MethodPtr method_ptr, const ::testing::tuple& args) { return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args)); } }; template class InvokeHelper > { public: template static R Invoke(Function function, const ::testing::tuple& args) { return function(get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args), get<5>(args)); } template static R InvokeMethod(Class* obj_ptr, MethodPtr method_ptr, const ::testing::tuple& args) { return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args), get<5>(args)); } }; template class InvokeHelper > { public: template static R Invoke(Function function, const ::testing::tuple& args) { return function(get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args), get<5>(args), get<6>(args)); } template static R InvokeMethod(Class* obj_ptr, MethodPtr method_ptr, const ::testing::tuple& args) { return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args), get<5>(args), get<6>(args)); } }; template class InvokeHelper > { public: template static R Invoke(Function function, const ::testing::tuple& args) { return function(get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args), get<5>(args), get<6>(args), get<7>(args)); } template static R InvokeMethod(Class* obj_ptr, MethodPtr method_ptr, const ::testing::tuple& args) { return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args), get<5>(args), get<6>(args), get<7>(args)); } }; template class InvokeHelper > { public: template static R Invoke(Function function, const ::testing::tuple& args) { return function(get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args), get<5>(args), get<6>(args), get<7>(args), get<8>(args)); } template static R InvokeMethod(Class* obj_ptr, MethodPtr method_ptr, const ::testing::tuple& args) { return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args), get<5>(args), get<6>(args), get<7>(args), get<8>(args)); } }; template class InvokeHelper > { public: template static R Invoke(Function function, const ::testing::tuple& args) { return function(get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args), get<5>(args), get<6>(args), get<7>(args), get<8>(args), get<9>(args)); } template static R InvokeMethod(Class* obj_ptr, MethodPtr method_ptr, const ::testing::tuple& args) { return (obj_ptr->*method_ptr)(get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args), get<5>(args), get<6>(args), get<7>(args), get<8>(args), get<9>(args)); } }; // An INTERNAL macro for extracting the type of a tuple field. It's // subject to change without notice - DO NOT USE IN USER CODE! #define GMOCK_FIELD_(Tuple, N) \ typename ::testing::tuple_element::type // SelectArgs::type is the // type of an n-ary function whose i-th (1-based) argument type is the // k{i}-th (0-based) field of ArgumentTuple, which must be a tuple // type, and whose return type is Result. For example, // SelectArgs, 0, 3>::type // is int(bool, long). // // SelectArgs::Select(args) // returns the selected fields (k1, k2, ..., k_n) of args as a tuple. // For example, // SelectArgs, 2, 0>::Select( // ::testing::make_tuple(true, 'a', 2.5)) // returns tuple (2.5, true). // // The numbers in list k1, k2, ..., k_n must be >= 0, where n can be // in the range [0, 10]. Duplicates are allowed and they don't have // to be in an ascending or descending order. template class SelectArgs { public: typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3), GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5), GMOCK_FIELD_(ArgumentTuple, k6), GMOCK_FIELD_(ArgumentTuple, k7), GMOCK_FIELD_(ArgumentTuple, k8), GMOCK_FIELD_(ArgumentTuple, k9), GMOCK_FIELD_(ArgumentTuple, k10)); typedef typename Function::ArgumentTuple SelectedArgs; static SelectedArgs Select(const ArgumentTuple& args) { return SelectedArgs(get(args), get(args), get(args), get(args), get(args), get(args), get(args), get(args), get(args), get(args)); } }; template class SelectArgs { public: typedef Result type(); typedef typename Function::ArgumentTuple SelectedArgs; static SelectedArgs Select(const ArgumentTuple& /* args */) { return SelectedArgs(); } }; template class SelectArgs { public: typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1)); typedef typename Function::ArgumentTuple SelectedArgs; static SelectedArgs Select(const ArgumentTuple& args) { return SelectedArgs(get(args)); } }; template class SelectArgs { public: typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), GMOCK_FIELD_(ArgumentTuple, k2)); typedef typename Function::ArgumentTuple SelectedArgs; static SelectedArgs Select(const ArgumentTuple& args) { return SelectedArgs(get(args), get(args)); } }; template class SelectArgs { public: typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3)); typedef typename Function::ArgumentTuple SelectedArgs; static SelectedArgs Select(const ArgumentTuple& args) { return SelectedArgs(get(args), get(args), get(args)); } }; template class SelectArgs { public: typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3), GMOCK_FIELD_(ArgumentTuple, k4)); typedef typename Function::ArgumentTuple SelectedArgs; static SelectedArgs Select(const ArgumentTuple& args) { return SelectedArgs(get(args), get(args), get(args), get(args)); } }; template class SelectArgs { public: typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3), GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5)); typedef typename Function::ArgumentTuple SelectedArgs; static SelectedArgs Select(const ArgumentTuple& args) { return SelectedArgs(get(args), get(args), get(args), get(args), get(args)); } }; template class SelectArgs { public: typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3), GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5), GMOCK_FIELD_(ArgumentTuple, k6)); typedef typename Function::ArgumentTuple SelectedArgs; static SelectedArgs Select(const ArgumentTuple& args) { return SelectedArgs(get(args), get(args), get(args), get(args), get(args), get(args)); } }; template class SelectArgs { public: typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3), GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5), GMOCK_FIELD_(ArgumentTuple, k6), GMOCK_FIELD_(ArgumentTuple, k7)); typedef typename Function::ArgumentTuple SelectedArgs; static SelectedArgs Select(const ArgumentTuple& args) { return SelectedArgs(get(args), get(args), get(args), get(args), get(args), get(args), get(args)); } }; template class SelectArgs { public: typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3), GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5), GMOCK_FIELD_(ArgumentTuple, k6), GMOCK_FIELD_(ArgumentTuple, k7), GMOCK_FIELD_(ArgumentTuple, k8)); typedef typename Function::ArgumentTuple SelectedArgs; static SelectedArgs Select(const ArgumentTuple& args) { return SelectedArgs(get(args), get(args), get(args), get(args), get(args), get(args), get(args), get(args)); } }; template class SelectArgs { public: typedef Result type(GMOCK_FIELD_(ArgumentTuple, k1), GMOCK_FIELD_(ArgumentTuple, k2), GMOCK_FIELD_(ArgumentTuple, k3), GMOCK_FIELD_(ArgumentTuple, k4), GMOCK_FIELD_(ArgumentTuple, k5), GMOCK_FIELD_(ArgumentTuple, k6), GMOCK_FIELD_(ArgumentTuple, k7), GMOCK_FIELD_(ArgumentTuple, k8), GMOCK_FIELD_(ArgumentTuple, k9)); typedef typename Function::ArgumentTuple SelectedArgs; static SelectedArgs Select(const ArgumentTuple& args) { return SelectedArgs(get(args), get(args), get(args), get(args), get(args), get(args), get(args), get(args), get(args)); } }; #undef GMOCK_FIELD_ // Implements the WithArgs action. template class WithArgsAction { public: explicit WithArgsAction(const InnerAction& action) : action_(action) {} template operator Action() const { return MakeAction(new Impl(action_)); } private: template class Impl : public ActionInterface { public: typedef typename Function::Result Result; typedef typename Function::ArgumentTuple ArgumentTuple; explicit Impl(const InnerAction& action) : action_(action) {} virtual Result Perform(const ArgumentTuple& args) { return action_.Perform(SelectArgs::Select(args)); } private: typedef typename SelectArgs::type InnerFunctionType; Action action_; }; const InnerAction action_; GTEST_DISALLOW_ASSIGN_(WithArgsAction); }; // A macro from the ACTION* family (defined later in this file) // defines an action that can be used in a mock function. Typically, // these actions only care about a subset of the arguments of the mock // function. For example, if such an action only uses the second // argument, it can be used in any mock function that takes >= 2 // arguments where the type of the second argument is compatible. // // Therefore, the action implementation must be prepared to take more // arguments than it needs. The ExcessiveArg type is used to // represent those excessive arguments. In order to keep the compiler // error messages tractable, we define it in the testing namespace // instead of testing::internal. However, this is an INTERNAL TYPE // and subject to change without notice, so a user MUST NOT USE THIS // TYPE DIRECTLY. struct ExcessiveArg {}; // A helper class needed for implementing the ACTION* macros. template class ActionHelper { public: static Result Perform(Impl* impl, const ::testing::tuple<>& args) { return impl->template gmock_PerformImpl<>(args, ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg()); } template static Result Perform(Impl* impl, const ::testing::tuple& args) { return impl->template gmock_PerformImpl(args, get<0>(args), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg()); } template static Result Perform(Impl* impl, const ::testing::tuple& args) { return impl->template gmock_PerformImpl(args, get<0>(args), get<1>(args), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg()); } template static Result Perform(Impl* impl, const ::testing::tuple& args) { return impl->template gmock_PerformImpl(args, get<0>(args), get<1>(args), get<2>(args), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg()); } template static Result Perform(Impl* impl, const ::testing::tuple& args) { return impl->template gmock_PerformImpl(args, get<0>(args), get<1>(args), get<2>(args), get<3>(args), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg()); } template static Result Perform(Impl* impl, const ::testing::tuple& args) { return impl->template gmock_PerformImpl(args, get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg()); } template static Result Perform(Impl* impl, const ::testing::tuple& args) { return impl->template gmock_PerformImpl(args, get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args), get<5>(args), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg()); } template static Result Perform(Impl* impl, const ::testing::tuple& args) { return impl->template gmock_PerformImpl(args, get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args), get<5>(args), get<6>(args), ExcessiveArg(), ExcessiveArg(), ExcessiveArg()); } template static Result Perform(Impl* impl, const ::testing::tuple& args) { return impl->template gmock_PerformImpl(args, get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args), get<5>(args), get<6>(args), get<7>(args), ExcessiveArg(), ExcessiveArg()); } template static Result Perform(Impl* impl, const ::testing::tuple& args) { return impl->template gmock_PerformImpl(args, get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args), get<5>(args), get<6>(args), get<7>(args), get<8>(args), ExcessiveArg()); } template static Result Perform(Impl* impl, const ::testing::tuple& args) { return impl->template gmock_PerformImpl(args, get<0>(args), get<1>(args), get<2>(args), get<3>(args), get<4>(args), get<5>(args), get<6>(args), get<7>(args), get<8>(args), get<9>(args)); } }; } // namespace internal // Various overloads for Invoke(). // WithArgs(an_action) creates an action that passes // the selected arguments of the mock function to an_action and // performs it. It serves as an adaptor between actions with // different argument lists. C++ doesn't support default arguments for // function templates, so we have to overload it. template inline internal::WithArgsAction WithArgs(const InnerAction& action) { return internal::WithArgsAction(action); } template inline internal::WithArgsAction WithArgs(const InnerAction& action) { return internal::WithArgsAction(action); } template inline internal::WithArgsAction WithArgs(const InnerAction& action) { return internal::WithArgsAction(action); } template inline internal::WithArgsAction WithArgs(const InnerAction& action) { return internal::WithArgsAction(action); } template inline internal::WithArgsAction WithArgs(const InnerAction& action) { return internal::WithArgsAction(action); } template inline internal::WithArgsAction WithArgs(const InnerAction& action) { return internal::WithArgsAction(action); } template inline internal::WithArgsAction WithArgs(const InnerAction& action) { return internal::WithArgsAction(action); } template inline internal::WithArgsAction WithArgs(const InnerAction& action) { return internal::WithArgsAction(action); } template inline internal::WithArgsAction WithArgs(const InnerAction& action) { return internal::WithArgsAction(action); } template inline internal::WithArgsAction WithArgs(const InnerAction& action) { return internal::WithArgsAction(action); } // Creates an action that does actions a1, a2, ..., sequentially in // each invocation. template inline internal::DoBothAction DoAll(Action1 a1, Action2 a2) { return internal::DoBothAction(a1, a2); } template inline internal::DoBothAction > DoAll(Action1 a1, Action2 a2, Action3 a3) { return DoAll(a1, DoAll(a2, a3)); } template inline internal::DoBothAction > > DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4) { return DoAll(a1, DoAll(a2, a3, a4)); } template inline internal::DoBothAction > > > DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5) { return DoAll(a1, DoAll(a2, a3, a4, a5)); } template inline internal::DoBothAction > > > > DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6) { return DoAll(a1, DoAll(a2, a3, a4, a5, a6)); } template inline internal::DoBothAction > > > > > DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, Action7 a7) { return DoAll(a1, DoAll(a2, a3, a4, a5, a6, a7)); } template inline internal::DoBothAction > > > > > > DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, Action7 a7, Action8 a8) { return DoAll(a1, DoAll(a2, a3, a4, a5, a6, a7, a8)); } template inline internal::DoBothAction > > > > > > > DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, Action7 a7, Action8 a8, Action9 a9) { return DoAll(a1, DoAll(a2, a3, a4, a5, a6, a7, a8, a9)); } template inline internal::DoBothAction > > > > > > > > DoAll(Action1 a1, Action2 a2, Action3 a3, Action4 a4, Action5 a5, Action6 a6, Action7 a7, Action8 a8, Action9 a9, Action10 a10) { return DoAll(a1, DoAll(a2, a3, a4, a5, a6, a7, a8, a9, a10)); } } // namespace testing // The ACTION* family of macros can be used in a namespace scope to // define custom actions easily. The syntax: // // ACTION(name) { statements; } // // will define an action with the given name that executes the // statements. The value returned by the statements will be used as // the return value of the action. Inside the statements, you can // refer to the K-th (0-based) argument of the mock function by // 'argK', and refer to its type by 'argK_type'. For example: // // ACTION(IncrementArg1) { // arg1_type temp = arg1; // return ++(*temp); // } // // allows you to write // // ...WillOnce(IncrementArg1()); // // You can also refer to the entire argument tuple and its type by // 'args' and 'args_type', and refer to the mock function type and its // return type by 'function_type' and 'return_type'. // // Note that you don't need to specify the types of the mock function // arguments. However rest assured that your code is still type-safe: // you'll get a compiler error if *arg1 doesn't support the ++ // operator, or if the type of ++(*arg1) isn't compatible with the // mock function's return type, for example. // // Sometimes you'll want to parameterize the action. For that you can use // another macro: // // ACTION_P(name, param_name) { statements; } // // For example: // // ACTION_P(Add, n) { return arg0 + n; } // // will allow you to write: // // ...WillOnce(Add(5)); // // Note that you don't need to provide the type of the parameter // either. If you need to reference the type of a parameter named // 'foo', you can write 'foo_type'. For example, in the body of // ACTION_P(Add, n) above, you can write 'n_type' to refer to the type // of 'n'. // // We also provide ACTION_P2, ACTION_P3, ..., up to ACTION_P10 to support // multi-parameter actions. // // For the purpose of typing, you can view // // ACTION_Pk(Foo, p1, ..., pk) { ... } // // as shorthand for // // template // FooActionPk Foo(p1_type p1, ..., pk_type pk) { ... } // // In particular, you can provide the template type arguments // explicitly when invoking Foo(), as in Foo(5, false); // although usually you can rely on the compiler to infer the types // for you automatically. You can assign the result of expression // Foo(p1, ..., pk) to a variable of type FooActionPk. This can be useful when composing actions. // // You can also overload actions with different numbers of parameters: // // ACTION_P(Plus, a) { ... } // ACTION_P2(Plus, a, b) { ... } // // While it's tempting to always use the ACTION* macros when defining // a new action, you should also consider implementing ActionInterface // or using MakePolymorphicAction() instead, especially if you need to // use the action a lot. While these approaches require more work, // they give you more control on the types of the mock function // arguments and the action parameters, which in general leads to // better compiler error messages that pay off in the long run. They // also allow overloading actions based on parameter types (as opposed // to just based on the number of parameters). // // CAVEAT: // // ACTION*() can only be used in a namespace scope. The reason is // that C++ doesn't yet allow function-local types to be used to // instantiate templates. The up-coming C++0x standard will fix this. // Once that's done, we'll consider supporting using ACTION*() inside // a function. // // MORE INFORMATION: // // To learn more about using these macros, please search for 'ACTION' // on http://code.google.com/p/googlemock/wiki/CookBook. // An internal macro needed for implementing ACTION*(). #define GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_\ const args_type& args GTEST_ATTRIBUTE_UNUSED_, \ arg0_type arg0 GTEST_ATTRIBUTE_UNUSED_, \ arg1_type arg1 GTEST_ATTRIBUTE_UNUSED_, \ arg2_type arg2 GTEST_ATTRIBUTE_UNUSED_, \ arg3_type arg3 GTEST_ATTRIBUTE_UNUSED_, \ arg4_type arg4 GTEST_ATTRIBUTE_UNUSED_, \ arg5_type arg5 GTEST_ATTRIBUTE_UNUSED_, \ arg6_type arg6 GTEST_ATTRIBUTE_UNUSED_, \ arg7_type arg7 GTEST_ATTRIBUTE_UNUSED_, \ arg8_type arg8 GTEST_ATTRIBUTE_UNUSED_, \ arg9_type arg9 GTEST_ATTRIBUTE_UNUSED_ // Sometimes you want to give an action explicit template parameters // that cannot be inferred from its value parameters. ACTION() and // ACTION_P*() don't support that. ACTION_TEMPLATE() remedies that // and can be viewed as an extension to ACTION() and ACTION_P*(). // // The syntax: // // ACTION_TEMPLATE(ActionName, // HAS_m_TEMPLATE_PARAMS(kind1, name1, ..., kind_m, name_m), // AND_n_VALUE_PARAMS(p1, ..., p_n)) { statements; } // // defines an action template that takes m explicit template // parameters and n value parameters. name_i is the name of the i-th // template parameter, and kind_i specifies whether it's a typename, // an integral constant, or a template. p_i is the name of the i-th // value parameter. // // Example: // // // DuplicateArg(output) converts the k-th argument of the mock // // function to type T and copies it to *output. // ACTION_TEMPLATE(DuplicateArg, // HAS_2_TEMPLATE_PARAMS(int, k, typename, T), // AND_1_VALUE_PARAMS(output)) { // *output = T(::testing::get(args)); // } // ... // int n; // EXPECT_CALL(mock, Foo(_, _)) // .WillOnce(DuplicateArg<1, unsigned char>(&n)); // // To create an instance of an action template, write: // // ActionName(v1, ..., v_n) // // where the ts are the template arguments and the vs are the value // arguments. The value argument types are inferred by the compiler. // If you want to explicitly specify the value argument types, you can // provide additional template arguments: // // ActionName(v1, ..., v_n) // // where u_i is the desired type of v_i. // // ACTION_TEMPLATE and ACTION/ACTION_P* can be overloaded on the // number of value parameters, but not on the number of template // parameters. Without the restriction, the meaning of the following // is unclear: // // OverloadedAction(x); // // Are we using a single-template-parameter action where 'bool' refers // to the type of x, or are we using a two-template-parameter action // where the compiler is asked to infer the type of x? // // Implementation notes: // // GMOCK_INTERNAL_*_HAS_m_TEMPLATE_PARAMS and // GMOCK_INTERNAL_*_AND_n_VALUE_PARAMS are internal macros for // implementing ACTION_TEMPLATE. The main trick we use is to create // new macro invocations when expanding a macro. For example, we have // // #define ACTION_TEMPLATE(name, template_params, value_params) // ... GMOCK_INTERNAL_DECL_##template_params ... // // which causes ACTION_TEMPLATE(..., HAS_1_TEMPLATE_PARAMS(typename, T), ...) // to expand to // // ... GMOCK_INTERNAL_DECL_HAS_1_TEMPLATE_PARAMS(typename, T) ... // // Since GMOCK_INTERNAL_DECL_HAS_1_TEMPLATE_PARAMS is a macro, the // preprocessor will continue to expand it to // // ... typename T ... // // This technique conforms to the C++ standard and is portable. It // allows us to implement action templates using O(N) code, where N is // the maximum number of template/value parameters supported. Without // using it, we'd have to devote O(N^2) amount of code to implement all // combinations of m and n. // Declares the template parameters. #define GMOCK_INTERNAL_DECL_HAS_1_TEMPLATE_PARAMS(kind0, name0) kind0 name0 #define GMOCK_INTERNAL_DECL_HAS_2_TEMPLATE_PARAMS(kind0, name0, kind1, \ name1) kind0 name0, kind1 name1 #define GMOCK_INTERNAL_DECL_HAS_3_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ kind2, name2) kind0 name0, kind1 name1, kind2 name2 #define GMOCK_INTERNAL_DECL_HAS_4_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ kind2, name2, kind3, name3) kind0 name0, kind1 name1, kind2 name2, \ kind3 name3 #define GMOCK_INTERNAL_DECL_HAS_5_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ kind2, name2, kind3, name3, kind4, name4) kind0 name0, kind1 name1, \ kind2 name2, kind3 name3, kind4 name4 #define GMOCK_INTERNAL_DECL_HAS_6_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ kind2, name2, kind3, name3, kind4, name4, kind5, name5) kind0 name0, \ kind1 name1, kind2 name2, kind3 name3, kind4 name4, kind5 name5 #define GMOCK_INTERNAL_DECL_HAS_7_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, \ name6) kind0 name0, kind1 name1, kind2 name2, kind3 name3, kind4 name4, \ kind5 name5, kind6 name6 #define GMOCK_INTERNAL_DECL_HAS_8_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, name6, \ kind7, name7) kind0 name0, kind1 name1, kind2 name2, kind3 name3, \ kind4 name4, kind5 name5, kind6 name6, kind7 name7 #define GMOCK_INTERNAL_DECL_HAS_9_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, name6, \ kind7, name7, kind8, name8) kind0 name0, kind1 name1, kind2 name2, \ kind3 name3, kind4 name4, kind5 name5, kind6 name6, kind7 name7, \ kind8 name8 #define GMOCK_INTERNAL_DECL_HAS_10_TEMPLATE_PARAMS(kind0, name0, kind1, \ name1, kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, \ name6, kind7, name7, kind8, name8, kind9, name9) kind0 name0, \ kind1 name1, kind2 name2, kind3 name3, kind4 name4, kind5 name5, \ kind6 name6, kind7 name7, kind8 name8, kind9 name9 // Lists the template parameters. #define GMOCK_INTERNAL_LIST_HAS_1_TEMPLATE_PARAMS(kind0, name0) name0 #define GMOCK_INTERNAL_LIST_HAS_2_TEMPLATE_PARAMS(kind0, name0, kind1, \ name1) name0, name1 #define GMOCK_INTERNAL_LIST_HAS_3_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ kind2, name2) name0, name1, name2 #define GMOCK_INTERNAL_LIST_HAS_4_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ kind2, name2, kind3, name3) name0, name1, name2, name3 #define GMOCK_INTERNAL_LIST_HAS_5_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ kind2, name2, kind3, name3, kind4, name4) name0, name1, name2, name3, \ name4 #define GMOCK_INTERNAL_LIST_HAS_6_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ kind2, name2, kind3, name3, kind4, name4, kind5, name5) name0, name1, \ name2, name3, name4, name5 #define GMOCK_INTERNAL_LIST_HAS_7_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, \ name6) name0, name1, name2, name3, name4, name5, name6 #define GMOCK_INTERNAL_LIST_HAS_8_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, name6, \ kind7, name7) name0, name1, name2, name3, name4, name5, name6, name7 #define GMOCK_INTERNAL_LIST_HAS_9_TEMPLATE_PARAMS(kind0, name0, kind1, name1, \ kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, name6, \ kind7, name7, kind8, name8) name0, name1, name2, name3, name4, name5, \ name6, name7, name8 #define GMOCK_INTERNAL_LIST_HAS_10_TEMPLATE_PARAMS(kind0, name0, kind1, \ name1, kind2, name2, kind3, name3, kind4, name4, kind5, name5, kind6, \ name6, kind7, name7, kind8, name8, kind9, name9) name0, name1, name2, \ name3, name4, name5, name6, name7, name8, name9 // Declares the types of value parameters. #define GMOCK_INTERNAL_DECL_TYPE_AND_0_VALUE_PARAMS() #define GMOCK_INTERNAL_DECL_TYPE_AND_1_VALUE_PARAMS(p0) , typename p0##_type #define GMOCK_INTERNAL_DECL_TYPE_AND_2_VALUE_PARAMS(p0, p1) , \ typename p0##_type, typename p1##_type #define GMOCK_INTERNAL_DECL_TYPE_AND_3_VALUE_PARAMS(p0, p1, p2) , \ typename p0##_type, typename p1##_type, typename p2##_type #define GMOCK_INTERNAL_DECL_TYPE_AND_4_VALUE_PARAMS(p0, p1, p2, p3) , \ typename p0##_type, typename p1##_type, typename p2##_type, \ typename p3##_type #define GMOCK_INTERNAL_DECL_TYPE_AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4) , \ typename p0##_type, typename p1##_type, typename p2##_type, \ typename p3##_type, typename p4##_type #define GMOCK_INTERNAL_DECL_TYPE_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5) , \ typename p0##_type, typename p1##_type, typename p2##_type, \ typename p3##_type, typename p4##_type, typename p5##_type #define GMOCK_INTERNAL_DECL_TYPE_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ p6) , typename p0##_type, typename p1##_type, typename p2##_type, \ typename p3##_type, typename p4##_type, typename p5##_type, \ typename p6##_type #define GMOCK_INTERNAL_DECL_TYPE_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ p6, p7) , typename p0##_type, typename p1##_type, typename p2##_type, \ typename p3##_type, typename p4##_type, typename p5##_type, \ typename p6##_type, typename p7##_type #define GMOCK_INTERNAL_DECL_TYPE_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ p6, p7, p8) , typename p0##_type, typename p1##_type, typename p2##_type, \ typename p3##_type, typename p4##_type, typename p5##_type, \ typename p6##_type, typename p7##_type, typename p8##_type #define GMOCK_INTERNAL_DECL_TYPE_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ p6, p7, p8, p9) , typename p0##_type, typename p1##_type, \ typename p2##_type, typename p3##_type, typename p4##_type, \ typename p5##_type, typename p6##_type, typename p7##_type, \ typename p8##_type, typename p9##_type // Initializes the value parameters. #define GMOCK_INTERNAL_INIT_AND_0_VALUE_PARAMS()\ () #define GMOCK_INTERNAL_INIT_AND_1_VALUE_PARAMS(p0)\ (p0##_type gmock_p0) : p0(gmock_p0) #define GMOCK_INTERNAL_INIT_AND_2_VALUE_PARAMS(p0, p1)\ (p0##_type gmock_p0, p1##_type gmock_p1) : p0(gmock_p0), p1(gmock_p1) #define GMOCK_INTERNAL_INIT_AND_3_VALUE_PARAMS(p0, p1, p2)\ (p0##_type gmock_p0, p1##_type gmock_p1, \ p2##_type gmock_p2) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2) #define GMOCK_INTERNAL_INIT_AND_4_VALUE_PARAMS(p0, p1, p2, p3)\ (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ p3##_type gmock_p3) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ p3(gmock_p3) #define GMOCK_INTERNAL_INIT_AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4)\ (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ p3##_type gmock_p3, p4##_type gmock_p4) : p0(gmock_p0), p1(gmock_p1), \ p2(gmock_p2), p3(gmock_p3), p4(gmock_p4) #define GMOCK_INTERNAL_INIT_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5)\ (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ p3##_type gmock_p3, p4##_type gmock_p4, \ p5##_type gmock_p5) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ p3(gmock_p3), p4(gmock_p4), p5(gmock_p5) #define GMOCK_INTERNAL_INIT_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6)\ (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ p6##_type gmock_p6) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6) #define GMOCK_INTERNAL_INIT_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7)\ (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ p6##_type gmock_p6, p7##_type gmock_p7) : p0(gmock_p0), p1(gmock_p1), \ p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ p7(gmock_p7) #define GMOCK_INTERNAL_INIT_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ p7, p8)\ (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ p6##_type gmock_p6, p7##_type gmock_p7, \ p8##_type gmock_p8) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \ p8(gmock_p8) #define GMOCK_INTERNAL_INIT_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ p7, p8, p9)\ (p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ p6##_type gmock_p6, p7##_type gmock_p7, p8##_type gmock_p8, \ p9##_type gmock_p9) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \ p8(gmock_p8), p9(gmock_p9) // Declares the fields for storing the value parameters. #define GMOCK_INTERNAL_DEFN_AND_0_VALUE_PARAMS() #define GMOCK_INTERNAL_DEFN_AND_1_VALUE_PARAMS(p0) p0##_type p0; #define GMOCK_INTERNAL_DEFN_AND_2_VALUE_PARAMS(p0, p1) p0##_type p0; \ p1##_type p1; #define GMOCK_INTERNAL_DEFN_AND_3_VALUE_PARAMS(p0, p1, p2) p0##_type p0; \ p1##_type p1; p2##_type p2; #define GMOCK_INTERNAL_DEFN_AND_4_VALUE_PARAMS(p0, p1, p2, p3) p0##_type p0; \ p1##_type p1; p2##_type p2; p3##_type p3; #define GMOCK_INTERNAL_DEFN_AND_5_VALUE_PARAMS(p0, p1, p2, p3, \ p4) p0##_type p0; p1##_type p1; p2##_type p2; p3##_type p3; p4##_type p4; #define GMOCK_INTERNAL_DEFN_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, \ p5) p0##_type p0; p1##_type p1; p2##_type p2; p3##_type p3; p4##_type p4; \ p5##_type p5; #define GMOCK_INTERNAL_DEFN_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ p6) p0##_type p0; p1##_type p1; p2##_type p2; p3##_type p3; p4##_type p4; \ p5##_type p5; p6##_type p6; #define GMOCK_INTERNAL_DEFN_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ p7) p0##_type p0; p1##_type p1; p2##_type p2; p3##_type p3; p4##_type p4; \ p5##_type p5; p6##_type p6; p7##_type p7; #define GMOCK_INTERNAL_DEFN_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ p7, p8) p0##_type p0; p1##_type p1; p2##_type p2; p3##_type p3; \ p4##_type p4; p5##_type p5; p6##_type p6; p7##_type p7; p8##_type p8; #define GMOCK_INTERNAL_DEFN_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ p7, p8, p9) p0##_type p0; p1##_type p1; p2##_type p2; p3##_type p3; \ p4##_type p4; p5##_type p5; p6##_type p6; p7##_type p7; p8##_type p8; \ p9##_type p9; // Lists the value parameters. #define GMOCK_INTERNAL_LIST_AND_0_VALUE_PARAMS() #define GMOCK_INTERNAL_LIST_AND_1_VALUE_PARAMS(p0) p0 #define GMOCK_INTERNAL_LIST_AND_2_VALUE_PARAMS(p0, p1) p0, p1 #define GMOCK_INTERNAL_LIST_AND_3_VALUE_PARAMS(p0, p1, p2) p0, p1, p2 #define GMOCK_INTERNAL_LIST_AND_4_VALUE_PARAMS(p0, p1, p2, p3) p0, p1, p2, p3 #define GMOCK_INTERNAL_LIST_AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4) p0, p1, \ p2, p3, p4 #define GMOCK_INTERNAL_LIST_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5) p0, \ p1, p2, p3, p4, p5 #define GMOCK_INTERNAL_LIST_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ p6) p0, p1, p2, p3, p4, p5, p6 #define GMOCK_INTERNAL_LIST_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ p7) p0, p1, p2, p3, p4, p5, p6, p7 #define GMOCK_INTERNAL_LIST_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ p7, p8) p0, p1, p2, p3, p4, p5, p6, p7, p8 #define GMOCK_INTERNAL_LIST_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ p7, p8, p9) p0, p1, p2, p3, p4, p5, p6, p7, p8, p9 // Lists the value parameter types. #define GMOCK_INTERNAL_LIST_TYPE_AND_0_VALUE_PARAMS() #define GMOCK_INTERNAL_LIST_TYPE_AND_1_VALUE_PARAMS(p0) , p0##_type #define GMOCK_INTERNAL_LIST_TYPE_AND_2_VALUE_PARAMS(p0, p1) , p0##_type, \ p1##_type #define GMOCK_INTERNAL_LIST_TYPE_AND_3_VALUE_PARAMS(p0, p1, p2) , p0##_type, \ p1##_type, p2##_type #define GMOCK_INTERNAL_LIST_TYPE_AND_4_VALUE_PARAMS(p0, p1, p2, p3) , \ p0##_type, p1##_type, p2##_type, p3##_type #define GMOCK_INTERNAL_LIST_TYPE_AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4) , \ p0##_type, p1##_type, p2##_type, p3##_type, p4##_type #define GMOCK_INTERNAL_LIST_TYPE_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5) , \ p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, p5##_type #define GMOCK_INTERNAL_LIST_TYPE_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ p6) , p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, p5##_type, \ p6##_type #define GMOCK_INTERNAL_LIST_TYPE_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ p6, p7) , p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \ p5##_type, p6##_type, p7##_type #define GMOCK_INTERNAL_LIST_TYPE_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ p6, p7, p8) , p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \ p5##_type, p6##_type, p7##_type, p8##_type #define GMOCK_INTERNAL_LIST_TYPE_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ p6, p7, p8, p9) , p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \ p5##_type, p6##_type, p7##_type, p8##_type, p9##_type // Declares the value parameters. #define GMOCK_INTERNAL_DECL_AND_0_VALUE_PARAMS() #define GMOCK_INTERNAL_DECL_AND_1_VALUE_PARAMS(p0) p0##_type p0 #define GMOCK_INTERNAL_DECL_AND_2_VALUE_PARAMS(p0, p1) p0##_type p0, \ p1##_type p1 #define GMOCK_INTERNAL_DECL_AND_3_VALUE_PARAMS(p0, p1, p2) p0##_type p0, \ p1##_type p1, p2##_type p2 #define GMOCK_INTERNAL_DECL_AND_4_VALUE_PARAMS(p0, p1, p2, p3) p0##_type p0, \ p1##_type p1, p2##_type p2, p3##_type p3 #define GMOCK_INTERNAL_DECL_AND_5_VALUE_PARAMS(p0, p1, p2, p3, \ p4) p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4 #define GMOCK_INTERNAL_DECL_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, \ p5) p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4, \ p5##_type p5 #define GMOCK_INTERNAL_DECL_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, \ p6) p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4, \ p5##_type p5, p6##_type p6 #define GMOCK_INTERNAL_DECL_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ p7) p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4, \ p5##_type p5, p6##_type p6, p7##_type p7 #define GMOCK_INTERNAL_DECL_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ p7, p8) p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, p8##_type p8 #define GMOCK_INTERNAL_DECL_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ p7, p8, p9) p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, p8##_type p8, \ p9##_type p9 // The suffix of the class template implementing the action template. #define GMOCK_INTERNAL_COUNT_AND_0_VALUE_PARAMS() #define GMOCK_INTERNAL_COUNT_AND_1_VALUE_PARAMS(p0) P #define GMOCK_INTERNAL_COUNT_AND_2_VALUE_PARAMS(p0, p1) P2 #define GMOCK_INTERNAL_COUNT_AND_3_VALUE_PARAMS(p0, p1, p2) P3 #define GMOCK_INTERNAL_COUNT_AND_4_VALUE_PARAMS(p0, p1, p2, p3) P4 #define GMOCK_INTERNAL_COUNT_AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4) P5 #define GMOCK_INTERNAL_COUNT_AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5) P6 #define GMOCK_INTERNAL_COUNT_AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6) P7 #define GMOCK_INTERNAL_COUNT_AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ p7) P8 #define GMOCK_INTERNAL_COUNT_AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ p7, p8) P9 #define GMOCK_INTERNAL_COUNT_AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, \ p7, p8, p9) P10 // The name of the class template implementing the action template. #define GMOCK_ACTION_CLASS_(name, value_params)\ GTEST_CONCAT_TOKEN_(name##Action, GMOCK_INTERNAL_COUNT_##value_params) #define ACTION_TEMPLATE(name, template_params, value_params)\ template \ class GMOCK_ACTION_CLASS_(name, value_params) {\ public:\ explicit GMOCK_ACTION_CLASS_(name, value_params)\ GMOCK_INTERNAL_INIT_##value_params {}\ template \ class gmock_Impl : public ::testing::ActionInterface {\ public:\ typedef F function_type;\ typedef typename ::testing::internal::Function::Result return_type;\ typedef typename ::testing::internal::Function::ArgumentTuple\ args_type;\ explicit gmock_Impl GMOCK_INTERNAL_INIT_##value_params {}\ virtual return_type Perform(const args_type& args) {\ return ::testing::internal::ActionHelper::\ Perform(this, args);\ }\ template \ return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ arg9_type arg9) const;\ GMOCK_INTERNAL_DEFN_##value_params\ private:\ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template operator ::testing::Action() const {\ return ::testing::Action(\ new gmock_Impl(GMOCK_INTERNAL_LIST_##value_params));\ }\ GMOCK_INTERNAL_DEFN_##value_params\ private:\ GTEST_DISALLOW_ASSIGN_(GMOCK_ACTION_CLASS_(name, value_params));\ };\ template \ inline GMOCK_ACTION_CLASS_(name, value_params)<\ GMOCK_INTERNAL_LIST_##template_params\ GMOCK_INTERNAL_LIST_TYPE_##value_params> name(\ GMOCK_INTERNAL_DECL_##value_params) {\ return GMOCK_ACTION_CLASS_(name, value_params)<\ GMOCK_INTERNAL_LIST_##template_params\ GMOCK_INTERNAL_LIST_TYPE_##value_params>(\ GMOCK_INTERNAL_LIST_##value_params);\ }\ template \ template \ template \ typename ::testing::internal::Function::Result\ GMOCK_ACTION_CLASS_(name, value_params)<\ GMOCK_INTERNAL_LIST_##template_params\ GMOCK_INTERNAL_LIST_TYPE_##value_params>::gmock_Impl::\ gmock_PerformImpl(\ GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const #define ACTION(name)\ class name##Action {\ public:\ name##Action() {}\ template \ class gmock_Impl : public ::testing::ActionInterface {\ public:\ typedef F function_type;\ typedef typename ::testing::internal::Function::Result return_type;\ typedef typename ::testing::internal::Function::ArgumentTuple\ args_type;\ gmock_Impl() {}\ virtual return_type Perform(const args_type& args) {\ return ::testing::internal::ActionHelper::\ Perform(this, args);\ }\ template \ return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ arg9_type arg9) const;\ private:\ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template operator ::testing::Action() const {\ return ::testing::Action(new gmock_Impl());\ }\ private:\ GTEST_DISALLOW_ASSIGN_(name##Action);\ };\ inline name##Action name() {\ return name##Action();\ }\ template \ template \ typename ::testing::internal::Function::Result\ name##Action::gmock_Impl::gmock_PerformImpl(\ GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const #define ACTION_P(name, p0)\ template \ class name##ActionP {\ public:\ explicit name##ActionP(p0##_type gmock_p0) : p0(gmock_p0) {}\ template \ class gmock_Impl : public ::testing::ActionInterface {\ public:\ typedef F function_type;\ typedef typename ::testing::internal::Function::Result return_type;\ typedef typename ::testing::internal::Function::ArgumentTuple\ args_type;\ explicit gmock_Impl(p0##_type gmock_p0) : p0(gmock_p0) {}\ virtual return_type Perform(const args_type& args) {\ return ::testing::internal::ActionHelper::\ Perform(this, args);\ }\ template \ return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ arg9_type arg9) const;\ p0##_type p0;\ private:\ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template operator ::testing::Action() const {\ return ::testing::Action(new gmock_Impl(p0));\ }\ p0##_type p0;\ private:\ GTEST_DISALLOW_ASSIGN_(name##ActionP);\ };\ template \ inline name##ActionP name(p0##_type p0) {\ return name##ActionP(p0);\ }\ template \ template \ template \ typename ::testing::internal::Function::Result\ name##ActionP::gmock_Impl::gmock_PerformImpl(\ GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const #define ACTION_P2(name, p0, p1)\ template \ class name##ActionP2 {\ public:\ name##ActionP2(p0##_type gmock_p0, p1##_type gmock_p1) : p0(gmock_p0), \ p1(gmock_p1) {}\ template \ class gmock_Impl : public ::testing::ActionInterface {\ public:\ typedef F function_type;\ typedef typename ::testing::internal::Function::Result return_type;\ typedef typename ::testing::internal::Function::ArgumentTuple\ args_type;\ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1) : p0(gmock_p0), \ p1(gmock_p1) {}\ virtual return_type Perform(const args_type& args) {\ return ::testing::internal::ActionHelper::\ Perform(this, args);\ }\ template \ return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ arg9_type arg9) const;\ p0##_type p0;\ p1##_type p1;\ private:\ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template operator ::testing::Action() const {\ return ::testing::Action(new gmock_Impl(p0, p1));\ }\ p0##_type p0;\ p1##_type p1;\ private:\ GTEST_DISALLOW_ASSIGN_(name##ActionP2);\ };\ template \ inline name##ActionP2 name(p0##_type p0, \ p1##_type p1) {\ return name##ActionP2(p0, p1);\ }\ template \ template \ template \ typename ::testing::internal::Function::Result\ name##ActionP2::gmock_Impl::gmock_PerformImpl(\ GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const #define ACTION_P3(name, p0, p1, p2)\ template \ class name##ActionP3 {\ public:\ name##ActionP3(p0##_type gmock_p0, p1##_type gmock_p1, \ p2##_type gmock_p2) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2) {}\ template \ class gmock_Impl : public ::testing::ActionInterface {\ public:\ typedef F function_type;\ typedef typename ::testing::internal::Function::Result return_type;\ typedef typename ::testing::internal::Function::ArgumentTuple\ args_type;\ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, \ p2##_type gmock_p2) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2) {}\ virtual return_type Perform(const args_type& args) {\ return ::testing::internal::ActionHelper::\ Perform(this, args);\ }\ template \ return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ arg9_type arg9) const;\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ private:\ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template operator ::testing::Action() const {\ return ::testing::Action(new gmock_Impl(p0, p1, p2));\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ private:\ GTEST_DISALLOW_ASSIGN_(name##ActionP3);\ };\ template \ inline name##ActionP3 name(p0##_type p0, \ p1##_type p1, p2##_type p2) {\ return name##ActionP3(p0, p1, p2);\ }\ template \ template \ template \ typename ::testing::internal::Function::Result\ name##ActionP3::gmock_Impl::gmock_PerformImpl(\ GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const #define ACTION_P4(name, p0, p1, p2, p3)\ template \ class name##ActionP4 {\ public:\ name##ActionP4(p0##_type gmock_p0, p1##_type gmock_p1, \ p2##_type gmock_p2, p3##_type gmock_p3) : p0(gmock_p0), p1(gmock_p1), \ p2(gmock_p2), p3(gmock_p3) {}\ template \ class gmock_Impl : public ::testing::ActionInterface {\ public:\ typedef F function_type;\ typedef typename ::testing::internal::Function::Result return_type;\ typedef typename ::testing::internal::Function::ArgumentTuple\ args_type;\ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ p3##_type gmock_p3) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ p3(gmock_p3) {}\ virtual return_type Perform(const args_type& args) {\ return ::testing::internal::ActionHelper::\ Perform(this, args);\ }\ template \ return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ arg9_type arg9) const;\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ private:\ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template operator ::testing::Action() const {\ return ::testing::Action(new gmock_Impl(p0, p1, p2, p3));\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ private:\ GTEST_DISALLOW_ASSIGN_(name##ActionP4);\ };\ template \ inline name##ActionP4 name(p0##_type p0, p1##_type p1, p2##_type p2, \ p3##_type p3) {\ return name##ActionP4(p0, p1, \ p2, p3);\ }\ template \ template \ template \ typename ::testing::internal::Function::Result\ name##ActionP4::gmock_Impl::gmock_PerformImpl(\ GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const #define ACTION_P5(name, p0, p1, p2, p3, p4)\ template \ class name##ActionP5 {\ public:\ name##ActionP5(p0##_type gmock_p0, p1##_type gmock_p1, \ p2##_type gmock_p2, p3##_type gmock_p3, \ p4##_type gmock_p4) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ p3(gmock_p3), p4(gmock_p4) {}\ template \ class gmock_Impl : public ::testing::ActionInterface {\ public:\ typedef F function_type;\ typedef typename ::testing::internal::Function::Result return_type;\ typedef typename ::testing::internal::Function::ArgumentTuple\ args_type;\ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ p3##_type gmock_p3, p4##_type gmock_p4) : p0(gmock_p0), \ p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), p4(gmock_p4) {}\ virtual return_type Perform(const args_type& args) {\ return ::testing::internal::ActionHelper::\ Perform(this, args);\ }\ template \ return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ arg9_type arg9) const;\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ p4##_type p4;\ private:\ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template operator ::testing::Action() const {\ return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4));\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ p4##_type p4;\ private:\ GTEST_DISALLOW_ASSIGN_(name##ActionP5);\ };\ template \ inline name##ActionP5 name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ p4##_type p4) {\ return name##ActionP5(p0, p1, p2, p3, p4);\ }\ template \ template \ template \ typename ::testing::internal::Function::Result\ name##ActionP5::gmock_Impl::gmock_PerformImpl(\ GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const #define ACTION_P6(name, p0, p1, p2, p3, p4, p5)\ template \ class name##ActionP6 {\ public:\ name##ActionP6(p0##_type gmock_p0, p1##_type gmock_p1, \ p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ p5##_type gmock_p5) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ p3(gmock_p3), p4(gmock_p4), p5(gmock_p5) {}\ template \ class gmock_Impl : public ::testing::ActionInterface {\ public:\ typedef F function_type;\ typedef typename ::testing::internal::Function::Result return_type;\ typedef typename ::testing::internal::Function::ArgumentTuple\ args_type;\ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ p3##_type gmock_p3, p4##_type gmock_p4, \ p5##_type gmock_p5) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ p3(gmock_p3), p4(gmock_p4), p5(gmock_p5) {}\ virtual return_type Perform(const args_type& args) {\ return ::testing::internal::ActionHelper::\ Perform(this, args);\ }\ template \ return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ arg9_type arg9) const;\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ p4##_type p4;\ p5##_type p5;\ private:\ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template operator ::testing::Action() const {\ return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5));\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ p4##_type p4;\ p5##_type p5;\ private:\ GTEST_DISALLOW_ASSIGN_(name##ActionP6);\ };\ template \ inline name##ActionP6 name(p0##_type p0, p1##_type p1, p2##_type p2, \ p3##_type p3, p4##_type p4, p5##_type p5) {\ return name##ActionP6(p0, p1, p2, p3, p4, p5);\ }\ template \ template \ template \ typename ::testing::internal::Function::Result\ name##ActionP6::gmock_Impl::gmock_PerformImpl(\ GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const #define ACTION_P7(name, p0, p1, p2, p3, p4, p5, p6)\ template \ class name##ActionP7 {\ public:\ name##ActionP7(p0##_type gmock_p0, p1##_type gmock_p1, \ p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ p5##_type gmock_p5, p6##_type gmock_p6) : p0(gmock_p0), p1(gmock_p1), \ p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), \ p6(gmock_p6) {}\ template \ class gmock_Impl : public ::testing::ActionInterface {\ public:\ typedef F function_type;\ typedef typename ::testing::internal::Function::Result return_type;\ typedef typename ::testing::internal::Function::ArgumentTuple\ args_type;\ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ p6##_type gmock_p6) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6) {}\ virtual return_type Perform(const args_type& args) {\ return ::testing::internal::ActionHelper::\ Perform(this, args);\ }\ template \ return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ arg9_type arg9) const;\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ p4##_type p4;\ p5##_type p5;\ p6##_type p6;\ private:\ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template operator ::testing::Action() const {\ return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5, \ p6));\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ p4##_type p4;\ p5##_type p5;\ p6##_type p6;\ private:\ GTEST_DISALLOW_ASSIGN_(name##ActionP7);\ };\ template \ inline name##ActionP7 name(p0##_type p0, p1##_type p1, \ p2##_type p2, p3##_type p3, p4##_type p4, p5##_type p5, \ p6##_type p6) {\ return name##ActionP7(p0, p1, p2, p3, p4, p5, p6);\ }\ template \ template \ template \ typename ::testing::internal::Function::Result\ name##ActionP7::gmock_Impl::gmock_PerformImpl(\ GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const #define ACTION_P8(name, p0, p1, p2, p3, p4, p5, p6, p7)\ template \ class name##ActionP8 {\ public:\ name##ActionP8(p0##_type gmock_p0, p1##_type gmock_p1, \ p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ p5##_type gmock_p5, p6##_type gmock_p6, \ p7##_type gmock_p7) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ p7(gmock_p7) {}\ template \ class gmock_Impl : public ::testing::ActionInterface {\ public:\ typedef F function_type;\ typedef typename ::testing::internal::Function::Result return_type;\ typedef typename ::testing::internal::Function::ArgumentTuple\ args_type;\ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ p6##_type gmock_p6, p7##_type gmock_p7) : p0(gmock_p0), \ p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), \ p5(gmock_p5), p6(gmock_p6), p7(gmock_p7) {}\ virtual return_type Perform(const args_type& args) {\ return ::testing::internal::ActionHelper::\ Perform(this, args);\ }\ template \ return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ arg9_type arg9) const;\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ p4##_type p4;\ p5##_type p5;\ p6##_type p6;\ p7##_type p7;\ private:\ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template operator ::testing::Action() const {\ return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5, \ p6, p7));\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ p4##_type p4;\ p5##_type p5;\ p6##_type p6;\ p7##_type p7;\ private:\ GTEST_DISALLOW_ASSIGN_(name##ActionP8);\ };\ template \ inline name##ActionP8 name(p0##_type p0, \ p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4, p5##_type p5, \ p6##_type p6, p7##_type p7) {\ return name##ActionP8(p0, p1, p2, p3, p4, p5, \ p6, p7);\ }\ template \ template \ template \ typename ::testing::internal::Function::Result\ name##ActionP8::gmock_Impl::gmock_PerformImpl(\ GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const #define ACTION_P9(name, p0, p1, p2, p3, p4, p5, p6, p7, p8)\ template \ class name##ActionP9 {\ public:\ name##ActionP9(p0##_type gmock_p0, p1##_type gmock_p1, \ p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ p5##_type gmock_p5, p6##_type gmock_p6, p7##_type gmock_p7, \ p8##_type gmock_p8) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \ p8(gmock_p8) {}\ template \ class gmock_Impl : public ::testing::ActionInterface {\ public:\ typedef F function_type;\ typedef typename ::testing::internal::Function::Result return_type;\ typedef typename ::testing::internal::Function::ArgumentTuple\ args_type;\ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ p6##_type gmock_p6, p7##_type gmock_p7, \ p8##_type gmock_p8) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ p7(gmock_p7), p8(gmock_p8) {}\ virtual return_type Perform(const args_type& args) {\ return ::testing::internal::ActionHelper::\ Perform(this, args);\ }\ template \ return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ arg9_type arg9) const;\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ p4##_type p4;\ p5##_type p5;\ p6##_type p6;\ p7##_type p7;\ p8##_type p8;\ private:\ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template operator ::testing::Action() const {\ return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5, \ p6, p7, p8));\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ p4##_type p4;\ p5##_type p5;\ p6##_type p6;\ p7##_type p7;\ p8##_type p8;\ private:\ GTEST_DISALLOW_ASSIGN_(name##ActionP9);\ };\ template \ inline name##ActionP9 name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, \ p8##_type p8) {\ return name##ActionP9(p0, p1, p2, \ p3, p4, p5, p6, p7, p8);\ }\ template \ template \ template \ typename ::testing::internal::Function::Result\ name##ActionP9::gmock_Impl::gmock_PerformImpl(\ GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const #define ACTION_P10(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)\ template \ class name##ActionP10 {\ public:\ name##ActionP10(p0##_type gmock_p0, p1##_type gmock_p1, \ p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ p5##_type gmock_p5, p6##_type gmock_p6, p7##_type gmock_p7, \ p8##_type gmock_p8, p9##_type gmock_p9) : p0(gmock_p0), p1(gmock_p1), \ p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ p7(gmock_p7), p8(gmock_p8), p9(gmock_p9) {}\ template \ class gmock_Impl : public ::testing::ActionInterface {\ public:\ typedef F function_type;\ typedef typename ::testing::internal::Function::Result return_type;\ typedef typename ::testing::internal::Function::ArgumentTuple\ args_type;\ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ p6##_type gmock_p6, p7##_type gmock_p7, p8##_type gmock_p8, \ p9##_type gmock_p9) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ p7(gmock_p7), p8(gmock_p8), p9(gmock_p9) {}\ virtual return_type Perform(const args_type& args) {\ return ::testing::internal::ActionHelper::\ Perform(this, args);\ }\ template \ return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \ arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \ arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \ arg9_type arg9) const;\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ p4##_type p4;\ p5##_type p5;\ p6##_type p6;\ p7##_type p7;\ p8##_type p8;\ p9##_type p9;\ private:\ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template operator ::testing::Action() const {\ return ::testing::Action(new gmock_Impl(p0, p1, p2, p3, p4, p5, \ p6, p7, p8, p9));\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ p4##_type p4;\ p5##_type p5;\ p6##_type p6;\ p7##_type p7;\ p8##_type p8;\ p9##_type p9;\ private:\ GTEST_DISALLOW_ASSIGN_(name##ActionP10);\ };\ template \ inline name##ActionP10 name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, p8##_type p8, \ p9##_type p9) {\ return name##ActionP10(p0, \ p1, p2, p3, p4, p5, p6, p7, p8, p9);\ }\ template \ template \ template \ typename ::testing::internal::Function::Result\ name##ActionP10::gmock_Impl::gmock_PerformImpl(\ GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const namespace testing { // The ACTION*() macros trigger warning C4100 (unreferenced formal // parameter) in MSVC with -W4. Unfortunately they cannot be fixed in // the macro definition, as the warnings are generated when the macro // is expanded and macro expansion cannot contain #pragma. Therefore // we suppress them here. #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable:4100) #endif // Various overloads for InvokeArgument(). // // The InvokeArgument(a1, a2, ..., a_k) action invokes the N-th // (0-based) argument, which must be a k-ary callable, of the mock // function, with arguments a1, a2, ..., a_k. // // Notes: // // 1. The arguments are passed by value by default. If you need to // pass an argument by reference, wrap it inside ByRef(). For // example, // // InvokeArgument<1>(5, string("Hello"), ByRef(foo)) // // passes 5 and string("Hello") by value, and passes foo by // reference. // // 2. If the callable takes an argument by reference but ByRef() is // not used, it will receive the reference to a copy of the value, // instead of the original value. For example, when the 0-th // argument of the mock function takes a const string&, the action // // InvokeArgument<0>(string("Hello")) // // makes a copy of the temporary string("Hello") object and passes a // reference of the copy, instead of the original temporary object, // to the callable. This makes it easy for a user to define an // InvokeArgument action from temporary values and have it performed // later. namespace internal { namespace invoke_argument { // Appears in InvokeArgumentAdl's argument list to help avoid // accidental calls to user functions of the same name. struct AdlTag {}; // InvokeArgumentAdl - a helper for InvokeArgument. // The basic overloads are provided here for generic functors. // Overloads for other custom-callables are provided in the // internal/custom/callback-actions.h header. template R InvokeArgumentAdl(AdlTag, F f) { return f(); } template R InvokeArgumentAdl(AdlTag, F f, A1 a1) { return f(a1); } template R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2) { return f(a1, a2); } template R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3) { return f(a1, a2, a3); } template R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4) { return f(a1, a2, a3, a4); } template R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) { return f(a1, a2, a3, a4, a5); } template R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) { return f(a1, a2, a3, a4, a5, a6); } template R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) { return f(a1, a2, a3, a4, a5, a6, a7); } template R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) { return f(a1, a2, a3, a4, a5, a6, a7, a8); } template R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) { return f(a1, a2, a3, a4, a5, a6, a7, a8, a9); } template R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) { return f(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); } } // namespace invoke_argument } // namespace internal ACTION_TEMPLATE(InvokeArgument, HAS_1_TEMPLATE_PARAMS(int, k), AND_0_VALUE_PARAMS()) { using internal::invoke_argument::InvokeArgumentAdl; return InvokeArgumentAdl( internal::invoke_argument::AdlTag(), ::testing::get(args)); } ACTION_TEMPLATE(InvokeArgument, HAS_1_TEMPLATE_PARAMS(int, k), AND_1_VALUE_PARAMS(p0)) { using internal::invoke_argument::InvokeArgumentAdl; return InvokeArgumentAdl( internal::invoke_argument::AdlTag(), ::testing::get(args), p0); } ACTION_TEMPLATE(InvokeArgument, HAS_1_TEMPLATE_PARAMS(int, k), AND_2_VALUE_PARAMS(p0, p1)) { using internal::invoke_argument::InvokeArgumentAdl; return InvokeArgumentAdl( internal::invoke_argument::AdlTag(), ::testing::get(args), p0, p1); } ACTION_TEMPLATE(InvokeArgument, HAS_1_TEMPLATE_PARAMS(int, k), AND_3_VALUE_PARAMS(p0, p1, p2)) { using internal::invoke_argument::InvokeArgumentAdl; return InvokeArgumentAdl( internal::invoke_argument::AdlTag(), ::testing::get(args), p0, p1, p2); } ACTION_TEMPLATE(InvokeArgument, HAS_1_TEMPLATE_PARAMS(int, k), AND_4_VALUE_PARAMS(p0, p1, p2, p3)) { using internal::invoke_argument::InvokeArgumentAdl; return InvokeArgumentAdl( internal::invoke_argument::AdlTag(), ::testing::get(args), p0, p1, p2, p3); } ACTION_TEMPLATE(InvokeArgument, HAS_1_TEMPLATE_PARAMS(int, k), AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4)) { using internal::invoke_argument::InvokeArgumentAdl; return InvokeArgumentAdl( internal::invoke_argument::AdlTag(), ::testing::get(args), p0, p1, p2, p3, p4); } ACTION_TEMPLATE(InvokeArgument, HAS_1_TEMPLATE_PARAMS(int, k), AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5)) { using internal::invoke_argument::InvokeArgumentAdl; return InvokeArgumentAdl( internal::invoke_argument::AdlTag(), ::testing::get(args), p0, p1, p2, p3, p4, p5); } ACTION_TEMPLATE(InvokeArgument, HAS_1_TEMPLATE_PARAMS(int, k), AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6)) { using internal::invoke_argument::InvokeArgumentAdl; return InvokeArgumentAdl( internal::invoke_argument::AdlTag(), ::testing::get(args), p0, p1, p2, p3, p4, p5, p6); } ACTION_TEMPLATE(InvokeArgument, HAS_1_TEMPLATE_PARAMS(int, k), AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7)) { using internal::invoke_argument::InvokeArgumentAdl; return InvokeArgumentAdl( internal::invoke_argument::AdlTag(), ::testing::get(args), p0, p1, p2, p3, p4, p5, p6, p7); } ACTION_TEMPLATE(InvokeArgument, HAS_1_TEMPLATE_PARAMS(int, k), AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7, p8)) { using internal::invoke_argument::InvokeArgumentAdl; return InvokeArgumentAdl( internal::invoke_argument::AdlTag(), ::testing::get(args), p0, p1, p2, p3, p4, p5, p6, p7, p8); } ACTION_TEMPLATE(InvokeArgument, HAS_1_TEMPLATE_PARAMS(int, k), AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)) { using internal::invoke_argument::InvokeArgumentAdl; return InvokeArgumentAdl( internal::invoke_argument::AdlTag(), ::testing::get(args), p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); } // Various overloads for ReturnNew(). // // The ReturnNew(a1, a2, ..., a_k) action returns a pointer to a new // instance of type T, constructed on the heap with constructor arguments // a1, a2, ..., and a_k. The caller assumes ownership of the returned value. ACTION_TEMPLATE(ReturnNew, HAS_1_TEMPLATE_PARAMS(typename, T), AND_0_VALUE_PARAMS()) { return new T(); } ACTION_TEMPLATE(ReturnNew, HAS_1_TEMPLATE_PARAMS(typename, T), AND_1_VALUE_PARAMS(p0)) { return new T(p0); } ACTION_TEMPLATE(ReturnNew, HAS_1_TEMPLATE_PARAMS(typename, T), AND_2_VALUE_PARAMS(p0, p1)) { return new T(p0, p1); } ACTION_TEMPLATE(ReturnNew, HAS_1_TEMPLATE_PARAMS(typename, T), AND_3_VALUE_PARAMS(p0, p1, p2)) { return new T(p0, p1, p2); } ACTION_TEMPLATE(ReturnNew, HAS_1_TEMPLATE_PARAMS(typename, T), AND_4_VALUE_PARAMS(p0, p1, p2, p3)) { return new T(p0, p1, p2, p3); } ACTION_TEMPLATE(ReturnNew, HAS_1_TEMPLATE_PARAMS(typename, T), AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4)) { return new T(p0, p1, p2, p3, p4); } ACTION_TEMPLATE(ReturnNew, HAS_1_TEMPLATE_PARAMS(typename, T), AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5)) { return new T(p0, p1, p2, p3, p4, p5); } ACTION_TEMPLATE(ReturnNew, HAS_1_TEMPLATE_PARAMS(typename, T), AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6)) { return new T(p0, p1, p2, p3, p4, p5, p6); } ACTION_TEMPLATE(ReturnNew, HAS_1_TEMPLATE_PARAMS(typename, T), AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7)) { return new T(p0, p1, p2, p3, p4, p5, p6, p7); } ACTION_TEMPLATE(ReturnNew, HAS_1_TEMPLATE_PARAMS(typename, T), AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7, p8)) { return new T(p0, p1, p2, p3, p4, p5, p6, p7, p8); } ACTION_TEMPLATE(ReturnNew, HAS_1_TEMPLATE_PARAMS(typename, T), AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)) { return new T(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); } #ifdef _MSC_VER # pragma warning(pop) #endif } // namespace testing // Include any custom actions added by the local installation. // We must include this header at the end to make sure it can use the // declarations from this file. #include "gmock/internal/custom/gmock-generated-actions.h" #endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/include/gmock/gmock-generated-actions.h.pump000066400000000000000000000634411455373415500332160ustar00rootroot00000000000000$$ -*- mode: c++; -*- $$ This is a Pump source file. Please use Pump to convert it to $$ gmock-generated-actions.h. $$ $var n = 10 $$ The maximum arity we support. $$}} This meta comment fixes auto-indentation in editors. // Copyright 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // Google Mock - a framework for writing C++ mock classes. // // This file implements some commonly used variadic actions. #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ #include "gmock/gmock-actions.h" #include "gmock/internal/gmock-port.h" namespace testing { namespace internal { // InvokeHelper knows how to unpack an N-tuple and invoke an N-ary // function or method with the unpacked values, where F is a function // type that takes N arguments. template class InvokeHelper; $range i 0..n $for i [[ $range j 1..i $var types = [[$for j [[, typename A$j]]]] $var as = [[$for j, [[A$j]]]] $var args = [[$if i==0 [[]] $else [[ args]]]] $var gets = [[$for j, [[get<$(j - 1)>(args)]]]] template class InvokeHelper > { public: template static R Invoke(Function function, const ::testing::tuple<$as>&$args) { return function($gets); } template static R InvokeMethod(Class* obj_ptr, MethodPtr method_ptr, const ::testing::tuple<$as>&$args) { return (obj_ptr->*method_ptr)($gets); } }; ]] // An INTERNAL macro for extracting the type of a tuple field. It's // subject to change without notice - DO NOT USE IN USER CODE! #define GMOCK_FIELD_(Tuple, N) \ typename ::testing::tuple_element::type $range i 1..n // SelectArgs::type is the // type of an n-ary function whose i-th (1-based) argument type is the // k{i}-th (0-based) field of ArgumentTuple, which must be a tuple // type, and whose return type is Result. For example, // SelectArgs, 0, 3>::type // is int(bool, long). // // SelectArgs::Select(args) // returns the selected fields (k1, k2, ..., k_n) of args as a tuple. // For example, // SelectArgs, 2, 0>::Select( // ::testing::make_tuple(true, 'a', 2.5)) // returns tuple (2.5, true). // // The numbers in list k1, k2, ..., k_n must be >= 0, where n can be // in the range [0, $n]. Duplicates are allowed and they don't have // to be in an ascending or descending order. template class SelectArgs { public: typedef Result type($for i, [[GMOCK_FIELD_(ArgumentTuple, k$i)]]); typedef typename Function::ArgumentTuple SelectedArgs; static SelectedArgs Select(const ArgumentTuple& args) { return SelectedArgs($for i, [[get(args)]]); } }; $for i [[ $range j 1..n $range j1 1..i-1 template class SelectArgs { public: typedef Result type($for j1, [[GMOCK_FIELD_(ArgumentTuple, k$j1)]]); typedef typename Function::ArgumentTuple SelectedArgs; static SelectedArgs Select(const ArgumentTuple& [[]] $if i == 1 [[/* args */]] $else [[args]]) { return SelectedArgs($for j1, [[get(args)]]); } }; ]] #undef GMOCK_FIELD_ $var ks = [[$for i, [[k$i]]]] // Implements the WithArgs action. template class WithArgsAction { public: explicit WithArgsAction(const InnerAction& action) : action_(action) {} template operator Action() const { return MakeAction(new Impl(action_)); } private: template class Impl : public ActionInterface { public: typedef typename Function::Result Result; typedef typename Function::ArgumentTuple ArgumentTuple; explicit Impl(const InnerAction& action) : action_(action) {} virtual Result Perform(const ArgumentTuple& args) { return action_.Perform(SelectArgs::Select(args)); } private: typedef typename SelectArgs::type InnerFunctionType; Action action_; }; const InnerAction action_; GTEST_DISALLOW_ASSIGN_(WithArgsAction); }; // A macro from the ACTION* family (defined later in this file) // defines an action that can be used in a mock function. Typically, // these actions only care about a subset of the arguments of the mock // function. For example, if such an action only uses the second // argument, it can be used in any mock function that takes >= 2 // arguments where the type of the second argument is compatible. // // Therefore, the action implementation must be prepared to take more // arguments than it needs. The ExcessiveArg type is used to // represent those excessive arguments. In order to keep the compiler // error messages tractable, we define it in the testing namespace // instead of testing::internal. However, this is an INTERNAL TYPE // and subject to change without notice, so a user MUST NOT USE THIS // TYPE DIRECTLY. struct ExcessiveArg {}; // A helper class needed for implementing the ACTION* macros. template class ActionHelper { public: $range i 0..n $for i [[ $var template = [[$if i==0 [[]] $else [[ $range j 0..i-1 template <$for j, [[typename A$j]]> ]]]] $range j 0..i-1 $var As = [[$for j, [[A$j]]]] $var as = [[$for j, [[get<$j>(args)]]]] $range k 1..n-i $var eas = [[$for k, [[ExcessiveArg()]]]] $var arg_list = [[$if (i==0) | (i==n) [[$as$eas]] $else [[$as, $eas]]]] $template static Result Perform(Impl* impl, const ::testing::tuple<$As>& args) { return impl->template gmock_PerformImpl<$As>(args, $arg_list); } ]] }; } // namespace internal // Various overloads for Invoke(). // WithArgs(an_action) creates an action that passes // the selected arguments of the mock function to an_action and // performs it. It serves as an adaptor between actions with // different argument lists. C++ doesn't support default arguments for // function templates, so we have to overload it. $range i 1..n $for i [[ $range j 1..i template <$for j [[int k$j, ]]typename InnerAction> inline internal::WithArgsAction WithArgs(const InnerAction& action) { return internal::WithArgsAction(action); } ]] // Creates an action that does actions a1, a2, ..., sequentially in // each invocation. $range i 2..n $for i [[ $range j 2..i $var types = [[$for j, [[typename Action$j]]]] $var Aas = [[$for j [[, Action$j a$j]]]] template $range k 1..i-1 inline $for k [[internal::DoBothAction]] DoAll(Action1 a1$Aas) { $if i==2 [[ return internal::DoBothAction(a1, a2); ]] $else [[ $range j2 2..i return DoAll(a1, DoAll($for j2, [[a$j2]])); ]] } ]] } // namespace testing // The ACTION* family of macros can be used in a namespace scope to // define custom actions easily. The syntax: // // ACTION(name) { statements; } // // will define an action with the given name that executes the // statements. The value returned by the statements will be used as // the return value of the action. Inside the statements, you can // refer to the K-th (0-based) argument of the mock function by // 'argK', and refer to its type by 'argK_type'. For example: // // ACTION(IncrementArg1) { // arg1_type temp = arg1; // return ++(*temp); // } // // allows you to write // // ...WillOnce(IncrementArg1()); // // You can also refer to the entire argument tuple and its type by // 'args' and 'args_type', and refer to the mock function type and its // return type by 'function_type' and 'return_type'. // // Note that you don't need to specify the types of the mock function // arguments. However rest assured that your code is still type-safe: // you'll get a compiler error if *arg1 doesn't support the ++ // operator, or if the type of ++(*arg1) isn't compatible with the // mock function's return type, for example. // // Sometimes you'll want to parameterize the action. For that you can use // another macro: // // ACTION_P(name, param_name) { statements; } // // For example: // // ACTION_P(Add, n) { return arg0 + n; } // // will allow you to write: // // ...WillOnce(Add(5)); // // Note that you don't need to provide the type of the parameter // either. If you need to reference the type of a parameter named // 'foo', you can write 'foo_type'. For example, in the body of // ACTION_P(Add, n) above, you can write 'n_type' to refer to the type // of 'n'. // // We also provide ACTION_P2, ACTION_P3, ..., up to ACTION_P$n to support // multi-parameter actions. // // For the purpose of typing, you can view // // ACTION_Pk(Foo, p1, ..., pk) { ... } // // as shorthand for // // template // FooActionPk Foo(p1_type p1, ..., pk_type pk) { ... } // // In particular, you can provide the template type arguments // explicitly when invoking Foo(), as in Foo(5, false); // although usually you can rely on the compiler to infer the types // for you automatically. You can assign the result of expression // Foo(p1, ..., pk) to a variable of type FooActionPk. This can be useful when composing actions. // // You can also overload actions with different numbers of parameters: // // ACTION_P(Plus, a) { ... } // ACTION_P2(Plus, a, b) { ... } // // While it's tempting to always use the ACTION* macros when defining // a new action, you should also consider implementing ActionInterface // or using MakePolymorphicAction() instead, especially if you need to // use the action a lot. While these approaches require more work, // they give you more control on the types of the mock function // arguments and the action parameters, which in general leads to // better compiler error messages that pay off in the long run. They // also allow overloading actions based on parameter types (as opposed // to just based on the number of parameters). // // CAVEAT: // // ACTION*() can only be used in a namespace scope. The reason is // that C++ doesn't yet allow function-local types to be used to // instantiate templates. The up-coming C++0x standard will fix this. // Once that's done, we'll consider supporting using ACTION*() inside // a function. // // MORE INFORMATION: // // To learn more about using these macros, please search for 'ACTION' // on http://code.google.com/p/googlemock/wiki/CookBook. $range i 0..n $range k 0..n-1 // An internal macro needed for implementing ACTION*(). #define GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_\ const args_type& args GTEST_ATTRIBUTE_UNUSED_ $for k [[, \ arg$k[[]]_type arg$k GTEST_ATTRIBUTE_UNUSED_]] // Sometimes you want to give an action explicit template parameters // that cannot be inferred from its value parameters. ACTION() and // ACTION_P*() don't support that. ACTION_TEMPLATE() remedies that // and can be viewed as an extension to ACTION() and ACTION_P*(). // // The syntax: // // ACTION_TEMPLATE(ActionName, // HAS_m_TEMPLATE_PARAMS(kind1, name1, ..., kind_m, name_m), // AND_n_VALUE_PARAMS(p1, ..., p_n)) { statements; } // // defines an action template that takes m explicit template // parameters and n value parameters. name_i is the name of the i-th // template parameter, and kind_i specifies whether it's a typename, // an integral constant, or a template. p_i is the name of the i-th // value parameter. // // Example: // // // DuplicateArg(output) converts the k-th argument of the mock // // function to type T and copies it to *output. // ACTION_TEMPLATE(DuplicateArg, // HAS_2_TEMPLATE_PARAMS(int, k, typename, T), // AND_1_VALUE_PARAMS(output)) { // *output = T(::testing::get(args)); // } // ... // int n; // EXPECT_CALL(mock, Foo(_, _)) // .WillOnce(DuplicateArg<1, unsigned char>(&n)); // // To create an instance of an action template, write: // // ActionName(v1, ..., v_n) // // where the ts are the template arguments and the vs are the value // arguments. The value argument types are inferred by the compiler. // If you want to explicitly specify the value argument types, you can // provide additional template arguments: // // ActionName(v1, ..., v_n) // // where u_i is the desired type of v_i. // // ACTION_TEMPLATE and ACTION/ACTION_P* can be overloaded on the // number of value parameters, but not on the number of template // parameters. Without the restriction, the meaning of the following // is unclear: // // OverloadedAction(x); // // Are we using a single-template-parameter action where 'bool' refers // to the type of x, or are we using a two-template-parameter action // where the compiler is asked to infer the type of x? // // Implementation notes: // // GMOCK_INTERNAL_*_HAS_m_TEMPLATE_PARAMS and // GMOCK_INTERNAL_*_AND_n_VALUE_PARAMS are internal macros for // implementing ACTION_TEMPLATE. The main trick we use is to create // new macro invocations when expanding a macro. For example, we have // // #define ACTION_TEMPLATE(name, template_params, value_params) // ... GMOCK_INTERNAL_DECL_##template_params ... // // which causes ACTION_TEMPLATE(..., HAS_1_TEMPLATE_PARAMS(typename, T), ...) // to expand to // // ... GMOCK_INTERNAL_DECL_HAS_1_TEMPLATE_PARAMS(typename, T) ... // // Since GMOCK_INTERNAL_DECL_HAS_1_TEMPLATE_PARAMS is a macro, the // preprocessor will continue to expand it to // // ... typename T ... // // This technique conforms to the C++ standard and is portable. It // allows us to implement action templates using O(N) code, where N is // the maximum number of template/value parameters supported. Without // using it, we'd have to devote O(N^2) amount of code to implement all // combinations of m and n. // Declares the template parameters. $range j 1..n $for j [[ $range m 0..j-1 #define GMOCK_INTERNAL_DECL_HAS_$j[[]] _TEMPLATE_PARAMS($for m, [[kind$m, name$m]]) $for m, [[kind$m name$m]] ]] // Lists the template parameters. $for j [[ $range m 0..j-1 #define GMOCK_INTERNAL_LIST_HAS_$j[[]] _TEMPLATE_PARAMS($for m, [[kind$m, name$m]]) $for m, [[name$m]] ]] // Declares the types of value parameters. $for i [[ $range j 0..i-1 #define GMOCK_INTERNAL_DECL_TYPE_AND_$i[[]] _VALUE_PARAMS($for j, [[p$j]]) $for j [[, typename p$j##_type]] ]] // Initializes the value parameters. $for i [[ $range j 0..i-1 #define GMOCK_INTERNAL_INIT_AND_$i[[]]_VALUE_PARAMS($for j, [[p$j]])\ ($for j, [[p$j##_type gmock_p$j]])$if i>0 [[ : ]]$for j, [[p$j(gmock_p$j)]] ]] // Declares the fields for storing the value parameters. $for i [[ $range j 0..i-1 #define GMOCK_INTERNAL_DEFN_AND_$i[[]] _VALUE_PARAMS($for j, [[p$j]]) $for j [[p$j##_type p$j; ]] ]] // Lists the value parameters. $for i [[ $range j 0..i-1 #define GMOCK_INTERNAL_LIST_AND_$i[[]] _VALUE_PARAMS($for j, [[p$j]]) $for j, [[p$j]] ]] // Lists the value parameter types. $for i [[ $range j 0..i-1 #define GMOCK_INTERNAL_LIST_TYPE_AND_$i[[]] _VALUE_PARAMS($for j, [[p$j]]) $for j [[, p$j##_type]] ]] // Declares the value parameters. $for i [[ $range j 0..i-1 #define GMOCK_INTERNAL_DECL_AND_$i[[]]_VALUE_PARAMS($for j, [[p$j]]) [[]] $for j, [[p$j##_type p$j]] ]] // The suffix of the class template implementing the action template. $for i [[ $range j 0..i-1 #define GMOCK_INTERNAL_COUNT_AND_$i[[]]_VALUE_PARAMS($for j, [[p$j]]) [[]] $if i==1 [[P]] $elif i>=2 [[P$i]] ]] // The name of the class template implementing the action template. #define GMOCK_ACTION_CLASS_(name, value_params)\ GTEST_CONCAT_TOKEN_(name##Action, GMOCK_INTERNAL_COUNT_##value_params) $range k 0..n-1 #define ACTION_TEMPLATE(name, template_params, value_params)\ template \ class GMOCK_ACTION_CLASS_(name, value_params) {\ public:\ explicit GMOCK_ACTION_CLASS_(name, value_params)\ GMOCK_INTERNAL_INIT_##value_params {}\ template \ class gmock_Impl : public ::testing::ActionInterface {\ public:\ typedef F function_type;\ typedef typename ::testing::internal::Function::Result return_type;\ typedef typename ::testing::internal::Function::ArgumentTuple\ args_type;\ explicit gmock_Impl GMOCK_INTERNAL_INIT_##value_params {}\ virtual return_type Perform(const args_type& args) {\ return ::testing::internal::ActionHelper::\ Perform(this, args);\ }\ template <$for k, [[typename arg$k[[]]_type]]>\ return_type gmock_PerformImpl(const args_type& args[[]] $for k [[, arg$k[[]]_type arg$k]]) const;\ GMOCK_INTERNAL_DEFN_##value_params\ private:\ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template operator ::testing::Action() const {\ return ::testing::Action(\ new gmock_Impl(GMOCK_INTERNAL_LIST_##value_params));\ }\ GMOCK_INTERNAL_DEFN_##value_params\ private:\ GTEST_DISALLOW_ASSIGN_(GMOCK_ACTION_CLASS_(name, value_params));\ };\ template \ inline GMOCK_ACTION_CLASS_(name, value_params)<\ GMOCK_INTERNAL_LIST_##template_params\ GMOCK_INTERNAL_LIST_TYPE_##value_params> name(\ GMOCK_INTERNAL_DECL_##value_params) {\ return GMOCK_ACTION_CLASS_(name, value_params)<\ GMOCK_INTERNAL_LIST_##template_params\ GMOCK_INTERNAL_LIST_TYPE_##value_params>(\ GMOCK_INTERNAL_LIST_##value_params);\ }\ template \ template \ template \ typename ::testing::internal::Function::Result\ GMOCK_ACTION_CLASS_(name, value_params)<\ GMOCK_INTERNAL_LIST_##template_params\ GMOCK_INTERNAL_LIST_TYPE_##value_params>::gmock_Impl::\ gmock_PerformImpl(\ GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const $for i [[ $var template = [[$if i==0 [[]] $else [[ $range j 0..i-1 template <$for j, [[typename p$j##_type]]>\ ]]]] $var class_name = [[name##Action[[$if i==0 [[]] $elif i==1 [[P]] $else [[P$i]]]]]] $range j 0..i-1 $var ctor_param_list = [[$for j, [[p$j##_type gmock_p$j]]]] $var param_types_and_names = [[$for j, [[p$j##_type p$j]]]] $var inits = [[$if i==0 [[]] $else [[ : $for j, [[p$j(gmock_p$j)]]]]]] $var param_field_decls = [[$for j [[ p$j##_type p$j;\ ]]]] $var param_field_decls2 = [[$for j [[ p$j##_type p$j;\ ]]]] $var params = [[$for j, [[p$j]]]] $var param_types = [[$if i==0 [[]] $else [[<$for j, [[p$j##_type]]>]]]] $var typename_arg_types = [[$for k, [[typename arg$k[[]]_type]]]] $var arg_types_and_names = [[$for k, [[arg$k[[]]_type arg$k]]]] $var macro_name = [[$if i==0 [[ACTION]] $elif i==1 [[ACTION_P]] $else [[ACTION_P$i]]]] #define $macro_name(name$for j [[, p$j]])\$template class $class_name {\ public:\ [[$if i==1 [[explicit ]]]]$class_name($ctor_param_list)$inits {}\ template \ class gmock_Impl : public ::testing::ActionInterface {\ public:\ typedef F function_type;\ typedef typename ::testing::internal::Function::Result return_type;\ typedef typename ::testing::internal::Function::ArgumentTuple\ args_type;\ [[$if i==1 [[explicit ]]]]gmock_Impl($ctor_param_list)$inits {}\ virtual return_type Perform(const args_type& args) {\ return ::testing::internal::ActionHelper::\ Perform(this, args);\ }\ template <$typename_arg_types>\ return_type gmock_PerformImpl(const args_type& args, [[]] $arg_types_and_names) const;\$param_field_decls private:\ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template operator ::testing::Action() const {\ return ::testing::Action(new gmock_Impl($params));\ }\$param_field_decls2 private:\ GTEST_DISALLOW_ASSIGN_($class_name);\ };\$template inline $class_name$param_types name($param_types_and_names) {\ return $class_name$param_types($params);\ }\$template template \ template <$typename_arg_types>\ typename ::testing::internal::Function::Result\ $class_name$param_types::gmock_Impl::gmock_PerformImpl(\ GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const ]] $$ } // This meta comment fixes auto-indentation in Emacs. It won't $$ // show up in the generated code. namespace testing { // The ACTION*() macros trigger warning C4100 (unreferenced formal // parameter) in MSVC with -W4. Unfortunately they cannot be fixed in // the macro definition, as the warnings are generated when the macro // is expanded and macro expansion cannot contain #pragma. Therefore // we suppress them here. #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable:4100) #endif // Various overloads for InvokeArgument(). // // The InvokeArgument(a1, a2, ..., a_k) action invokes the N-th // (0-based) argument, which must be a k-ary callable, of the mock // function, with arguments a1, a2, ..., a_k. // // Notes: // // 1. The arguments are passed by value by default. If you need to // pass an argument by reference, wrap it inside ByRef(). For // example, // // InvokeArgument<1>(5, string("Hello"), ByRef(foo)) // // passes 5 and string("Hello") by value, and passes foo by // reference. // // 2. If the callable takes an argument by reference but ByRef() is // not used, it will receive the reference to a copy of the value, // instead of the original value. For example, when the 0-th // argument of the mock function takes a const string&, the action // // InvokeArgument<0>(string("Hello")) // // makes a copy of the temporary string("Hello") object and passes a // reference of the copy, instead of the original temporary object, // to the callable. This makes it easy for a user to define an // InvokeArgument action from temporary values and have it performed // later. namespace internal { namespace invoke_argument { // Appears in InvokeArgumentAdl's argument list to help avoid // accidental calls to user functions of the same name. struct AdlTag {}; // InvokeArgumentAdl - a helper for InvokeArgument. // The basic overloads are provided here for generic functors. // Overloads for other custom-callables are provided in the // internal/custom/callback-actions.h header. $range i 0..n $for i [[ $range j 1..i template R InvokeArgumentAdl(AdlTag, F f[[$for j [[, A$j a$j]]]]) { return f([[$for j, [[a$j]]]]); } ]] } // namespace invoke_argument } // namespace internal $range i 0..n $for i [[ $range j 0..i-1 ACTION_TEMPLATE(InvokeArgument, HAS_1_TEMPLATE_PARAMS(int, k), AND_$i[[]]_VALUE_PARAMS($for j, [[p$j]])) { using internal::invoke_argument::InvokeArgumentAdl; return InvokeArgumentAdl( internal::invoke_argument::AdlTag(), ::testing::get(args)$for j [[, p$j]]); } ]] // Various overloads for ReturnNew(). // // The ReturnNew(a1, a2, ..., a_k) action returns a pointer to a new // instance of type T, constructed on the heap with constructor arguments // a1, a2, ..., and a_k. The caller assumes ownership of the returned value. $range i 0..n $for i [[ $range j 0..i-1 $var ps = [[$for j, [[p$j]]]] ACTION_TEMPLATE(ReturnNew, HAS_1_TEMPLATE_PARAMS(typename, T), AND_$i[[]]_VALUE_PARAMS($ps)) { return new T($ps); } ]] #ifdef _MSC_VER # pragma warning(pop) #endif } // namespace testing // Include any custom callback actions added by the local installation. // We must include this header at the end to make sure it can use the // declarations from this file. #include "gmock/internal/custom/gmock-generated-actions.h" #endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/include/gmock/gmock-generated-function-mockers.h000066400000000000000000001325571455373415500340710ustar00rootroot00000000000000// This file was GENERATED by command: // pump.py gmock-generated-function-mockers.h.pump // DO NOT EDIT BY HAND!!! // Copyright 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // Google Mock - a framework for writing C++ mock classes. // // This file implements function mockers of various arities. #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ #include "gmock/gmock-spec-builders.h" #include "gmock/internal/gmock-internal-utils.h" #if GTEST_HAS_STD_FUNCTION_ # include #endif namespace testing { namespace internal { template class FunctionMockerBase; // Note: class FunctionMocker really belongs to the ::testing // namespace. However if we define it in ::testing, MSVC will // complain when classes in ::testing::internal declare it as a // friend class template. To workaround this compiler bug, we define // FunctionMocker in ::testing::internal and import it into ::testing. template class FunctionMocker; template class FunctionMocker : public internal::FunctionMockerBase { public: typedef R F(); typedef typename internal::Function::ArgumentTuple ArgumentTuple; MockSpec& With() { return this->current_spec(); } R Invoke() { // Even though gcc and MSVC don't enforce it, 'this->' is required // by the C++ standard [14.6.4] here, as the base class type is // dependent on the template argument (and thus shouldn't be // looked into when resolving InvokeWith). return this->InvokeWith(ArgumentTuple()); } }; template class FunctionMocker : public internal::FunctionMockerBase { public: typedef R F(A1); typedef typename internal::Function::ArgumentTuple ArgumentTuple; MockSpec& With(const Matcher& m1) { this->current_spec().SetMatchers(::testing::make_tuple(m1)); return this->current_spec(); } R Invoke(A1 a1) { // Even though gcc and MSVC don't enforce it, 'this->' is required // by the C++ standard [14.6.4] here, as the base class type is // dependent on the template argument (and thus shouldn't be // looked into when resolving InvokeWith). return this->InvokeWith(ArgumentTuple(a1)); } }; template class FunctionMocker : public internal::FunctionMockerBase { public: typedef R F(A1, A2); typedef typename internal::Function::ArgumentTuple ArgumentTuple; MockSpec& With(const Matcher& m1, const Matcher& m2) { this->current_spec().SetMatchers(::testing::make_tuple(m1, m2)); return this->current_spec(); } R Invoke(A1 a1, A2 a2) { // Even though gcc and MSVC don't enforce it, 'this->' is required // by the C++ standard [14.6.4] here, as the base class type is // dependent on the template argument (and thus shouldn't be // looked into when resolving InvokeWith). return this->InvokeWith(ArgumentTuple(a1, a2)); } }; template class FunctionMocker : public internal::FunctionMockerBase { public: typedef R F(A1, A2, A3); typedef typename internal::Function::ArgumentTuple ArgumentTuple; MockSpec& With(const Matcher& m1, const Matcher& m2, const Matcher& m3) { this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3)); return this->current_spec(); } R Invoke(A1 a1, A2 a2, A3 a3) { // Even though gcc and MSVC don't enforce it, 'this->' is required // by the C++ standard [14.6.4] here, as the base class type is // dependent on the template argument (and thus shouldn't be // looked into when resolving InvokeWith). return this->InvokeWith(ArgumentTuple(a1, a2, a3)); } }; template class FunctionMocker : public internal::FunctionMockerBase { public: typedef R F(A1, A2, A3, A4); typedef typename internal::Function::ArgumentTuple ArgumentTuple; MockSpec& With(const Matcher& m1, const Matcher& m2, const Matcher& m3, const Matcher& m4) { this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4)); return this->current_spec(); } R Invoke(A1 a1, A2 a2, A3 a3, A4 a4) { // Even though gcc and MSVC don't enforce it, 'this->' is required // by the C++ standard [14.6.4] here, as the base class type is // dependent on the template argument (and thus shouldn't be // looked into when resolving InvokeWith). return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4)); } }; template class FunctionMocker : public internal::FunctionMockerBase { public: typedef R F(A1, A2, A3, A4, A5); typedef typename internal::Function::ArgumentTuple ArgumentTuple; MockSpec& With(const Matcher& m1, const Matcher& m2, const Matcher& m3, const Matcher& m4, const Matcher& m5) { this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4, m5)); return this->current_spec(); } R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) { // Even though gcc and MSVC don't enforce it, 'this->' is required // by the C++ standard [14.6.4] here, as the base class type is // dependent on the template argument (and thus shouldn't be // looked into when resolving InvokeWith). return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5)); } }; template class FunctionMocker : public internal::FunctionMockerBase { public: typedef R F(A1, A2, A3, A4, A5, A6); typedef typename internal::Function::ArgumentTuple ArgumentTuple; MockSpec& With(const Matcher& m1, const Matcher& m2, const Matcher& m3, const Matcher& m4, const Matcher& m5, const Matcher& m6) { this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4, m5, m6)); return this->current_spec(); } R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) { // Even though gcc and MSVC don't enforce it, 'this->' is required // by the C++ standard [14.6.4] here, as the base class type is // dependent on the template argument (and thus shouldn't be // looked into when resolving InvokeWith). return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6)); } }; template class FunctionMocker : public internal::FunctionMockerBase { public: typedef R F(A1, A2, A3, A4, A5, A6, A7); typedef typename internal::Function::ArgumentTuple ArgumentTuple; MockSpec& With(const Matcher& m1, const Matcher& m2, const Matcher& m3, const Matcher& m4, const Matcher& m5, const Matcher& m6, const Matcher& m7) { this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4, m5, m6, m7)); return this->current_spec(); } R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) { // Even though gcc and MSVC don't enforce it, 'this->' is required // by the C++ standard [14.6.4] here, as the base class type is // dependent on the template argument (and thus shouldn't be // looked into when resolving InvokeWith). return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6, a7)); } }; template class FunctionMocker : public internal::FunctionMockerBase { public: typedef R F(A1, A2, A3, A4, A5, A6, A7, A8); typedef typename internal::Function::ArgumentTuple ArgumentTuple; MockSpec& With(const Matcher& m1, const Matcher& m2, const Matcher& m3, const Matcher& m4, const Matcher& m5, const Matcher& m6, const Matcher& m7, const Matcher& m8) { this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4, m5, m6, m7, m8)); return this->current_spec(); } R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) { // Even though gcc and MSVC don't enforce it, 'this->' is required // by the C++ standard [14.6.4] here, as the base class type is // dependent on the template argument (and thus shouldn't be // looked into when resolving InvokeWith). return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6, a7, a8)); } }; template class FunctionMocker : public internal::FunctionMockerBase { public: typedef R F(A1, A2, A3, A4, A5, A6, A7, A8, A9); typedef typename internal::Function::ArgumentTuple ArgumentTuple; MockSpec& With(const Matcher& m1, const Matcher& m2, const Matcher& m3, const Matcher& m4, const Matcher& m5, const Matcher& m6, const Matcher& m7, const Matcher& m8, const Matcher& m9) { this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4, m5, m6, m7, m8, m9)); return this->current_spec(); } R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) { // Even though gcc and MSVC don't enforce it, 'this->' is required // by the C++ standard [14.6.4] here, as the base class type is // dependent on the template argument (and thus shouldn't be // looked into when resolving InvokeWith). return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6, a7, a8, a9)); } }; template class FunctionMocker : public internal::FunctionMockerBase { public: typedef R F(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10); typedef typename internal::Function::ArgumentTuple ArgumentTuple; MockSpec& With(const Matcher& m1, const Matcher& m2, const Matcher& m3, const Matcher& m4, const Matcher& m5, const Matcher& m6, const Matcher& m7, const Matcher& m8, const Matcher& m9, const Matcher& m10) { this->current_spec().SetMatchers(::testing::make_tuple(m1, m2, m3, m4, m5, m6, m7, m8, m9, m10)); return this->current_spec(); } R Invoke(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) { // Even though gcc and MSVC don't enforce it, 'this->' is required // by the C++ standard [14.6.4] here, as the base class type is // dependent on the template argument (and thus shouldn't be // looked into when resolving InvokeWith). return this->InvokeWith(ArgumentTuple(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)); } }; } // namespace internal // The style guide prohibits "using" statements in a namespace scope // inside a header file. However, the FunctionMocker class template // is meant to be defined in the ::testing namespace. The following // line is just a trick for working around a bug in MSVC 8.0, which // cannot handle it if we define FunctionMocker in ::testing. using internal::FunctionMocker; // GMOCK_RESULT_(tn, F) expands to the result type of function type F. // We define this as a variadic macro in case F contains unprotected // commas (the same reason that we use variadic macros in other places // in this file). // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_RESULT_(tn, ...) \ tn ::testing::internal::Function<__VA_ARGS__>::Result // The type of argument N of the given function type. // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_ARG_(tn, N, ...) \ tn ::testing::internal::Function<__VA_ARGS__>::Argument##N // The matcher type for argument N of the given function type. // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_MATCHER_(tn, N, ...) \ const ::testing::Matcher& // The variable for mocking the given method. // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_MOCKER_(arity, constness, Method) \ GTEST_CONCAT_TOKEN_(gmock##constness##arity##_##Method##_, __LINE__) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_METHOD0_(tn, constness, ct, Method, ...) \ GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ ) constness { \ GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ == 0), \ this_method_does_not_take_0_arguments); \ GMOCK_MOCKER_(0, constness, Method).SetOwnerAndName(this, #Method); \ return GMOCK_MOCKER_(0, constness, Method).Invoke(); \ } \ ::testing::MockSpec<__VA_ARGS__>& \ gmock_##Method() constness { \ GMOCK_MOCKER_(0, constness, Method).RegisterOwner(this); \ return GMOCK_MOCKER_(0, constness, Method).With(); \ } \ mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(0, constness, \ Method) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_METHOD1_(tn, constness, ct, Method, ...) \ GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1) constness { \ GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ == 1), \ this_method_does_not_take_1_argument); \ GMOCK_MOCKER_(1, constness, Method).SetOwnerAndName(this, #Method); \ return GMOCK_MOCKER_(1, constness, Method).Invoke(gmock_a1); \ } \ ::testing::MockSpec<__VA_ARGS__>& \ gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1) constness { \ GMOCK_MOCKER_(1, constness, Method).RegisterOwner(this); \ return GMOCK_MOCKER_(1, constness, Method).With(gmock_a1); \ } \ mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(1, constness, \ Method) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_METHOD2_(tn, constness, ct, Method, ...) \ GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2) constness { \ GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ == 2), \ this_method_does_not_take_2_arguments); \ GMOCK_MOCKER_(2, constness, Method).SetOwnerAndName(this, #Method); \ return GMOCK_MOCKER_(2, constness, Method).Invoke(gmock_a1, gmock_a2); \ } \ ::testing::MockSpec<__VA_ARGS__>& \ gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2) constness { \ GMOCK_MOCKER_(2, constness, Method).RegisterOwner(this); \ return GMOCK_MOCKER_(2, constness, Method).With(gmock_a1, gmock_a2); \ } \ mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(2, constness, \ Method) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_METHOD3_(tn, constness, ct, Method, ...) \ GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3) constness { \ GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ == 3), \ this_method_does_not_take_3_arguments); \ GMOCK_MOCKER_(3, constness, Method).SetOwnerAndName(this, #Method); \ return GMOCK_MOCKER_(3, constness, Method).Invoke(gmock_a1, gmock_a2, \ gmock_a3); \ } \ ::testing::MockSpec<__VA_ARGS__>& \ gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3) constness { \ GMOCK_MOCKER_(3, constness, Method).RegisterOwner(this); \ return GMOCK_MOCKER_(3, constness, Method).With(gmock_a1, gmock_a2, \ gmock_a3); \ } \ mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(3, constness, \ Method) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_METHOD4_(tn, constness, ct, Method, ...) \ GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \ GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4) constness { \ GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ == 4), \ this_method_does_not_take_4_arguments); \ GMOCK_MOCKER_(4, constness, Method).SetOwnerAndName(this, #Method); \ return GMOCK_MOCKER_(4, constness, Method).Invoke(gmock_a1, gmock_a2, \ gmock_a3, gmock_a4); \ } \ ::testing::MockSpec<__VA_ARGS__>& \ gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \ GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4) constness { \ GMOCK_MOCKER_(4, constness, Method).RegisterOwner(this); \ return GMOCK_MOCKER_(4, constness, Method).With(gmock_a1, gmock_a2, \ gmock_a3, gmock_a4); \ } \ mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(4, constness, \ Method) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_METHOD5_(tn, constness, ct, Method, ...) \ GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \ GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \ GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5) constness { \ GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ == 5), \ this_method_does_not_take_5_arguments); \ GMOCK_MOCKER_(5, constness, Method).SetOwnerAndName(this, #Method); \ return GMOCK_MOCKER_(5, constness, Method).Invoke(gmock_a1, gmock_a2, \ gmock_a3, gmock_a4, gmock_a5); \ } \ ::testing::MockSpec<__VA_ARGS__>& \ gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \ GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \ GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5) constness { \ GMOCK_MOCKER_(5, constness, Method).RegisterOwner(this); \ return GMOCK_MOCKER_(5, constness, Method).With(gmock_a1, gmock_a2, \ gmock_a3, gmock_a4, gmock_a5); \ } \ mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(5, constness, \ Method) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_METHOD6_(tn, constness, ct, Method, ...) \ GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \ GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \ GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5, \ GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6) constness { \ GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ == 6), \ this_method_does_not_take_6_arguments); \ GMOCK_MOCKER_(6, constness, Method).SetOwnerAndName(this, #Method); \ return GMOCK_MOCKER_(6, constness, Method).Invoke(gmock_a1, gmock_a2, \ gmock_a3, gmock_a4, gmock_a5, gmock_a6); \ } \ ::testing::MockSpec<__VA_ARGS__>& \ gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \ GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \ GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \ GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6) constness { \ GMOCK_MOCKER_(6, constness, Method).RegisterOwner(this); \ return GMOCK_MOCKER_(6, constness, Method).With(gmock_a1, gmock_a2, \ gmock_a3, gmock_a4, gmock_a5, gmock_a6); \ } \ mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(6, constness, \ Method) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_METHOD7_(tn, constness, ct, Method, ...) \ GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \ GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \ GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5, \ GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \ GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7) constness { \ GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ == 7), \ this_method_does_not_take_7_arguments); \ GMOCK_MOCKER_(7, constness, Method).SetOwnerAndName(this, #Method); \ return GMOCK_MOCKER_(7, constness, Method).Invoke(gmock_a1, gmock_a2, \ gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7); \ } \ ::testing::MockSpec<__VA_ARGS__>& \ gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \ GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \ GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \ GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6, \ GMOCK_MATCHER_(tn, 7, __VA_ARGS__) gmock_a7) constness { \ GMOCK_MOCKER_(7, constness, Method).RegisterOwner(this); \ return GMOCK_MOCKER_(7, constness, Method).With(gmock_a1, gmock_a2, \ gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7); \ } \ mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(7, constness, \ Method) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_METHOD8_(tn, constness, ct, Method, ...) \ GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \ GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \ GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5, \ GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \ GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7, \ GMOCK_ARG_(tn, 8, __VA_ARGS__) gmock_a8) constness { \ GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ == 8), \ this_method_does_not_take_8_arguments); \ GMOCK_MOCKER_(8, constness, Method).SetOwnerAndName(this, #Method); \ return GMOCK_MOCKER_(8, constness, Method).Invoke(gmock_a1, gmock_a2, \ gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8); \ } \ ::testing::MockSpec<__VA_ARGS__>& \ gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \ GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \ GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \ GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6, \ GMOCK_MATCHER_(tn, 7, __VA_ARGS__) gmock_a7, \ GMOCK_MATCHER_(tn, 8, __VA_ARGS__) gmock_a8) constness { \ GMOCK_MOCKER_(8, constness, Method).RegisterOwner(this); \ return GMOCK_MOCKER_(8, constness, Method).With(gmock_a1, gmock_a2, \ gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8); \ } \ mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(8, constness, \ Method) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_METHOD9_(tn, constness, ct, Method, ...) \ GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \ GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \ GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5, \ GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \ GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7, \ GMOCK_ARG_(tn, 8, __VA_ARGS__) gmock_a8, \ GMOCK_ARG_(tn, 9, __VA_ARGS__) gmock_a9) constness { \ GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ == 9), \ this_method_does_not_take_9_arguments); \ GMOCK_MOCKER_(9, constness, Method).SetOwnerAndName(this, #Method); \ return GMOCK_MOCKER_(9, constness, Method).Invoke(gmock_a1, gmock_a2, \ gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, \ gmock_a9); \ } \ ::testing::MockSpec<__VA_ARGS__>& \ gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \ GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \ GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \ GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6, \ GMOCK_MATCHER_(tn, 7, __VA_ARGS__) gmock_a7, \ GMOCK_MATCHER_(tn, 8, __VA_ARGS__) gmock_a8, \ GMOCK_MATCHER_(tn, 9, __VA_ARGS__) gmock_a9) constness { \ GMOCK_MOCKER_(9, constness, Method).RegisterOwner(this); \ return GMOCK_MOCKER_(9, constness, Method).With(gmock_a1, gmock_a2, \ gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, \ gmock_a9); \ } \ mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(9, constness, \ Method) // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_METHOD10_(tn, constness, ct, Method, ...) \ GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \ GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2, \ GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \ GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, \ GMOCK_ARG_(tn, 5, __VA_ARGS__) gmock_a5, \ GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \ GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7, \ GMOCK_ARG_(tn, 8, __VA_ARGS__) gmock_a8, \ GMOCK_ARG_(tn, 9, __VA_ARGS__) gmock_a9, \ GMOCK_ARG_(tn, 10, __VA_ARGS__) gmock_a10) constness { \ GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value \ == 10), \ this_method_does_not_take_10_arguments); \ GMOCK_MOCKER_(10, constness, Method).SetOwnerAndName(this, #Method); \ return GMOCK_MOCKER_(10, constness, Method).Invoke(gmock_a1, gmock_a2, \ gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, gmock_a9, \ gmock_a10); \ } \ ::testing::MockSpec<__VA_ARGS__>& \ gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \ GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \ GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \ GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \ GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \ GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6, \ GMOCK_MATCHER_(tn, 7, __VA_ARGS__) gmock_a7, \ GMOCK_MATCHER_(tn, 8, __VA_ARGS__) gmock_a8, \ GMOCK_MATCHER_(tn, 9, __VA_ARGS__) gmock_a9, \ GMOCK_MATCHER_(tn, 10, \ __VA_ARGS__) gmock_a10) constness { \ GMOCK_MOCKER_(10, constness, Method).RegisterOwner(this); \ return GMOCK_MOCKER_(10, constness, Method).With(gmock_a1, gmock_a2, \ gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, gmock_a9, \ gmock_a10); \ } \ mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(10, constness, \ Method) #define MOCK_METHOD0(m, ...) GMOCK_METHOD0_(, , , m, __VA_ARGS__) #define MOCK_METHOD1(m, ...) GMOCK_METHOD1_(, , , m, __VA_ARGS__) #define MOCK_METHOD2(m, ...) GMOCK_METHOD2_(, , , m, __VA_ARGS__) #define MOCK_METHOD3(m, ...) GMOCK_METHOD3_(, , , m, __VA_ARGS__) #define MOCK_METHOD4(m, ...) GMOCK_METHOD4_(, , , m, __VA_ARGS__) #define MOCK_METHOD5(m, ...) GMOCK_METHOD5_(, , , m, __VA_ARGS__) #define MOCK_METHOD6(m, ...) GMOCK_METHOD6_(, , , m, __VA_ARGS__) #define MOCK_METHOD7(m, ...) GMOCK_METHOD7_(, , , m, __VA_ARGS__) #define MOCK_METHOD8(m, ...) GMOCK_METHOD8_(, , , m, __VA_ARGS__) #define MOCK_METHOD9(m, ...) GMOCK_METHOD9_(, , , m, __VA_ARGS__) #define MOCK_METHOD10(m, ...) GMOCK_METHOD10_(, , , m, __VA_ARGS__) #define MOCK_CONST_METHOD0(m, ...) GMOCK_METHOD0_(, const, , m, __VA_ARGS__) #define MOCK_CONST_METHOD1(m, ...) GMOCK_METHOD1_(, const, , m, __VA_ARGS__) #define MOCK_CONST_METHOD2(m, ...) GMOCK_METHOD2_(, const, , m, __VA_ARGS__) #define MOCK_CONST_METHOD3(m, ...) GMOCK_METHOD3_(, const, , m, __VA_ARGS__) #define MOCK_CONST_METHOD4(m, ...) GMOCK_METHOD4_(, const, , m, __VA_ARGS__) #define MOCK_CONST_METHOD5(m, ...) GMOCK_METHOD5_(, const, , m, __VA_ARGS__) #define MOCK_CONST_METHOD6(m, ...) GMOCK_METHOD6_(, const, , m, __VA_ARGS__) #define MOCK_CONST_METHOD7(m, ...) GMOCK_METHOD7_(, const, , m, __VA_ARGS__) #define MOCK_CONST_METHOD8(m, ...) GMOCK_METHOD8_(, const, , m, __VA_ARGS__) #define MOCK_CONST_METHOD9(m, ...) GMOCK_METHOD9_(, const, , m, __VA_ARGS__) #define MOCK_CONST_METHOD10(m, ...) GMOCK_METHOD10_(, const, , m, __VA_ARGS__) #define MOCK_METHOD0_T(m, ...) GMOCK_METHOD0_(typename, , , m, __VA_ARGS__) #define MOCK_METHOD1_T(m, ...) GMOCK_METHOD1_(typename, , , m, __VA_ARGS__) #define MOCK_METHOD2_T(m, ...) GMOCK_METHOD2_(typename, , , m, __VA_ARGS__) #define MOCK_METHOD3_T(m, ...) GMOCK_METHOD3_(typename, , , m, __VA_ARGS__) #define MOCK_METHOD4_T(m, ...) GMOCK_METHOD4_(typename, , , m, __VA_ARGS__) #define MOCK_METHOD5_T(m, ...) GMOCK_METHOD5_(typename, , , m, __VA_ARGS__) #define MOCK_METHOD6_T(m, ...) GMOCK_METHOD6_(typename, , , m, __VA_ARGS__) #define MOCK_METHOD7_T(m, ...) GMOCK_METHOD7_(typename, , , m, __VA_ARGS__) #define MOCK_METHOD8_T(m, ...) GMOCK_METHOD8_(typename, , , m, __VA_ARGS__) #define MOCK_METHOD9_T(m, ...) GMOCK_METHOD9_(typename, , , m, __VA_ARGS__) #define MOCK_METHOD10_T(m, ...) GMOCK_METHOD10_(typename, , , m, __VA_ARGS__) #define MOCK_CONST_METHOD0_T(m, ...) \ GMOCK_METHOD0_(typename, const, , m, __VA_ARGS__) #define MOCK_CONST_METHOD1_T(m, ...) \ GMOCK_METHOD1_(typename, const, , m, __VA_ARGS__) #define MOCK_CONST_METHOD2_T(m, ...) \ GMOCK_METHOD2_(typename, const, , m, __VA_ARGS__) #define MOCK_CONST_METHOD3_T(m, ...) \ GMOCK_METHOD3_(typename, const, , m, __VA_ARGS__) #define MOCK_CONST_METHOD4_T(m, ...) \ GMOCK_METHOD4_(typename, const, , m, __VA_ARGS__) #define MOCK_CONST_METHOD5_T(m, ...) \ GMOCK_METHOD5_(typename, const, , m, __VA_ARGS__) #define MOCK_CONST_METHOD6_T(m, ...) \ GMOCK_METHOD6_(typename, const, , m, __VA_ARGS__) #define MOCK_CONST_METHOD7_T(m, ...) \ GMOCK_METHOD7_(typename, const, , m, __VA_ARGS__) #define MOCK_CONST_METHOD8_T(m, ...) \ GMOCK_METHOD8_(typename, const, , m, __VA_ARGS__) #define MOCK_CONST_METHOD9_T(m, ...) \ GMOCK_METHOD9_(typename, const, , m, __VA_ARGS__) #define MOCK_CONST_METHOD10_T(m, ...) \ GMOCK_METHOD10_(typename, const, , m, __VA_ARGS__) #define MOCK_METHOD0_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD0_(, , ct, m, __VA_ARGS__) #define MOCK_METHOD1_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD1_(, , ct, m, __VA_ARGS__) #define MOCK_METHOD2_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD2_(, , ct, m, __VA_ARGS__) #define MOCK_METHOD3_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD3_(, , ct, m, __VA_ARGS__) #define MOCK_METHOD4_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD4_(, , ct, m, __VA_ARGS__) #define MOCK_METHOD5_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD5_(, , ct, m, __VA_ARGS__) #define MOCK_METHOD6_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD6_(, , ct, m, __VA_ARGS__) #define MOCK_METHOD7_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD7_(, , ct, m, __VA_ARGS__) #define MOCK_METHOD8_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD8_(, , ct, m, __VA_ARGS__) #define MOCK_METHOD9_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD9_(, , ct, m, __VA_ARGS__) #define MOCK_METHOD10_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD10_(, , ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD0_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD0_(, const, ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD1_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD1_(, const, ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD2_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD2_(, const, ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD3_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD3_(, const, ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD4_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD4_(, const, ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD5_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD5_(, const, ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD6_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD6_(, const, ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD7_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD7_(, const, ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD8_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD8_(, const, ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD9_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD9_(, const, ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD10_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD10_(, const, ct, m, __VA_ARGS__) #define MOCK_METHOD0_T_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD0_(typename, , ct, m, __VA_ARGS__) #define MOCK_METHOD1_T_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD1_(typename, , ct, m, __VA_ARGS__) #define MOCK_METHOD2_T_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD2_(typename, , ct, m, __VA_ARGS__) #define MOCK_METHOD3_T_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD3_(typename, , ct, m, __VA_ARGS__) #define MOCK_METHOD4_T_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD4_(typename, , ct, m, __VA_ARGS__) #define MOCK_METHOD5_T_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD5_(typename, , ct, m, __VA_ARGS__) #define MOCK_METHOD6_T_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD6_(typename, , ct, m, __VA_ARGS__) #define MOCK_METHOD7_T_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD7_(typename, , ct, m, __VA_ARGS__) #define MOCK_METHOD8_T_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD8_(typename, , ct, m, __VA_ARGS__) #define MOCK_METHOD9_T_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD9_(typename, , ct, m, __VA_ARGS__) #define MOCK_METHOD10_T_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD10_(typename, , ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD0_T_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD0_(typename, const, ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD1_T_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD1_(typename, const, ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD2_T_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD2_(typename, const, ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD3_T_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD3_(typename, const, ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD4_T_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD4_(typename, const, ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD5_T_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD5_(typename, const, ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD6_T_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD6_(typename, const, ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD7_T_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD7_(typename, const, ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD8_T_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD8_(typename, const, ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD9_T_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD9_(typename, const, ct, m, __VA_ARGS__) #define MOCK_CONST_METHOD10_T_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD10_(typename, const, ct, m, __VA_ARGS__) // A MockFunction class has one mock method whose type is F. It is // useful when you just want your test code to emit some messages and // have Google Mock verify the right messages are sent (and perhaps at // the right times). For example, if you are exercising code: // // Foo(1); // Foo(2); // Foo(3); // // and want to verify that Foo(1) and Foo(3) both invoke // mock.Bar("a"), but Foo(2) doesn't invoke anything, you can write: // // TEST(FooTest, InvokesBarCorrectly) { // MyMock mock; // MockFunction check; // { // InSequence s; // // EXPECT_CALL(mock, Bar("a")); // EXPECT_CALL(check, Call("1")); // EXPECT_CALL(check, Call("2")); // EXPECT_CALL(mock, Bar("a")); // } // Foo(1); // check.Call("1"); // Foo(2); // check.Call("2"); // Foo(3); // } // // The expectation spec says that the first Bar("a") must happen // before check point "1", the second Bar("a") must happen after check // point "2", and nothing should happen between the two check // points. The explicit check points make it easy to tell which // Bar("a") is called by which call to Foo(). // // MockFunction can also be used to exercise code that accepts // std::function callbacks. To do so, use AsStdFunction() method // to create std::function proxy forwarding to original object's Call. // Example: // // TEST(FooTest, RunsCallbackWithBarArgument) { // MockFunction callback; // EXPECT_CALL(callback, Call("bar")).WillOnce(Return(1)); // Foo(callback.AsStdFunction()); // } template class MockFunction; template class MockFunction { public: MockFunction() {} MOCK_METHOD0_T(Call, R()); #if GTEST_HAS_STD_FUNCTION_ std::function AsStdFunction() { return [this]() -> R { return this->Call(); }; } #endif // GTEST_HAS_STD_FUNCTION_ private: GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); }; template class MockFunction { public: MockFunction() {} MOCK_METHOD1_T(Call, R(A0)); #if GTEST_HAS_STD_FUNCTION_ std::function AsStdFunction() { return [this](A0 a0) -> R { return this->Call(a0); }; } #endif // GTEST_HAS_STD_FUNCTION_ private: GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); }; template class MockFunction { public: MockFunction() {} MOCK_METHOD2_T(Call, R(A0, A1)); #if GTEST_HAS_STD_FUNCTION_ std::function AsStdFunction() { return [this](A0 a0, A1 a1) -> R { return this->Call(a0, a1); }; } #endif // GTEST_HAS_STD_FUNCTION_ private: GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); }; template class MockFunction { public: MockFunction() {} MOCK_METHOD3_T(Call, R(A0, A1, A2)); #if GTEST_HAS_STD_FUNCTION_ std::function AsStdFunction() { return [this](A0 a0, A1 a1, A2 a2) -> R { return this->Call(a0, a1, a2); }; } #endif // GTEST_HAS_STD_FUNCTION_ private: GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); }; template class MockFunction { public: MockFunction() {} MOCK_METHOD4_T(Call, R(A0, A1, A2, A3)); #if GTEST_HAS_STD_FUNCTION_ std::function AsStdFunction() { return [this](A0 a0, A1 a1, A2 a2, A3 a3) -> R { return this->Call(a0, a1, a2, a3); }; } #endif // GTEST_HAS_STD_FUNCTION_ private: GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); }; template class MockFunction { public: MockFunction() {} MOCK_METHOD5_T(Call, R(A0, A1, A2, A3, A4)); #if GTEST_HAS_STD_FUNCTION_ std::function AsStdFunction() { return [this](A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) -> R { return this->Call(a0, a1, a2, a3, a4); }; } #endif // GTEST_HAS_STD_FUNCTION_ private: GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); }; template class MockFunction { public: MockFunction() {} MOCK_METHOD6_T(Call, R(A0, A1, A2, A3, A4, A5)); #if GTEST_HAS_STD_FUNCTION_ std::function AsStdFunction() { return [this](A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) -> R { return this->Call(a0, a1, a2, a3, a4, a5); }; } #endif // GTEST_HAS_STD_FUNCTION_ private: GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); }; template class MockFunction { public: MockFunction() {} MOCK_METHOD7_T(Call, R(A0, A1, A2, A3, A4, A5, A6)); #if GTEST_HAS_STD_FUNCTION_ std::function AsStdFunction() { return [this](A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) -> R { return this->Call(a0, a1, a2, a3, a4, a5, a6); }; } #endif // GTEST_HAS_STD_FUNCTION_ private: GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); }; template class MockFunction { public: MockFunction() {} MOCK_METHOD8_T(Call, R(A0, A1, A2, A3, A4, A5, A6, A7)); #if GTEST_HAS_STD_FUNCTION_ std::function AsStdFunction() { return [this](A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) -> R { return this->Call(a0, a1, a2, a3, a4, a5, a6, a7); }; } #endif // GTEST_HAS_STD_FUNCTION_ private: GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); }; template class MockFunction { public: MockFunction() {} MOCK_METHOD9_T(Call, R(A0, A1, A2, A3, A4, A5, A6, A7, A8)); #if GTEST_HAS_STD_FUNCTION_ std::function AsStdFunction() { return [this](A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) -> R { return this->Call(a0, a1, a2, a3, a4, a5, a6, a7, a8); }; } #endif // GTEST_HAS_STD_FUNCTION_ private: GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); }; template class MockFunction { public: MockFunction() {} MOCK_METHOD10_T(Call, R(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9)); #if GTEST_HAS_STD_FUNCTION_ std::function AsStdFunction() { return [this](A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) -> R { return this->Call(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }; } #endif // GTEST_HAS_STD_FUNCTION_ private: GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); }; } // namespace testing #endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ gmock-generated-function-mockers.h.pump000066400000000000000000000221711455373415500347600ustar00rootroot00000000000000nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/include/gmock$$ -*- mode: c++; -*- $$ This is a Pump source file. Please use Pump to convert it to $$ gmock-generated-function-mockers.h. $$ $var n = 10 $$ The maximum arity we support. // Copyright 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // Google Mock - a framework for writing C++ mock classes. // // This file implements function mockers of various arities. #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ #include "gmock/gmock-spec-builders.h" #include "gmock/internal/gmock-internal-utils.h" #if GTEST_HAS_STD_FUNCTION_ # include #endif namespace testing { namespace internal { template class FunctionMockerBase; // Note: class FunctionMocker really belongs to the ::testing // namespace. However if we define it in ::testing, MSVC will // complain when classes in ::testing::internal declare it as a // friend class template. To workaround this compiler bug, we define // FunctionMocker in ::testing::internal and import it into ::testing. template class FunctionMocker; $range i 0..n $for i [[ $range j 1..i $var typename_As = [[$for j [[, typename A$j]]]] $var As = [[$for j, [[A$j]]]] $var as = [[$for j, [[a$j]]]] $var Aas = [[$for j, [[A$j a$j]]]] $var ms = [[$for j, [[m$j]]]] $var matchers = [[$for j, [[const Matcher& m$j]]]] template class FunctionMocker : public internal::FunctionMockerBase { public: typedef R F($As); typedef typename internal::Function::ArgumentTuple ArgumentTuple; MockSpec& With($matchers) { $if i >= 1 [[ this->current_spec().SetMatchers(::testing::make_tuple($ms)); ]] return this->current_spec(); } R Invoke($Aas) { // Even though gcc and MSVC don't enforce it, 'this->' is required // by the C++ standard [14.6.4] here, as the base class type is // dependent on the template argument (and thus shouldn't be // looked into when resolving InvokeWith). return this->InvokeWith(ArgumentTuple($as)); } }; ]] } // namespace internal // The style guide prohibits "using" statements in a namespace scope // inside a header file. However, the FunctionMocker class template // is meant to be defined in the ::testing namespace. The following // line is just a trick for working around a bug in MSVC 8.0, which // cannot handle it if we define FunctionMocker in ::testing. using internal::FunctionMocker; // GMOCK_RESULT_(tn, F) expands to the result type of function type F. // We define this as a variadic macro in case F contains unprotected // commas (the same reason that we use variadic macros in other places // in this file). // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_RESULT_(tn, ...) \ tn ::testing::internal::Function<__VA_ARGS__>::Result // The type of argument N of the given function type. // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_ARG_(tn, N, ...) \ tn ::testing::internal::Function<__VA_ARGS__>::Argument##N // The matcher type for argument N of the given function type. // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_MATCHER_(tn, N, ...) \ const ::testing::Matcher& // The variable for mocking the given method. // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_MOCKER_(arity, constness, Method) \ GTEST_CONCAT_TOKEN_(gmock##constness##arity##_##Method##_, __LINE__) $for i [[ $range j 1..i $var arg_as = [[$for j, \ [[GMOCK_ARG_(tn, $j, __VA_ARGS__) gmock_a$j]]]] $var as = [[$for j, [[gmock_a$j]]]] $var matcher_as = [[$for j, \ [[GMOCK_MATCHER_(tn, $j, __VA_ARGS__) gmock_a$j]]]] // INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!! #define GMOCK_METHOD$i[[]]_(tn, constness, ct, Method, ...) \ GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \ $arg_as) constness { \ GTEST_COMPILE_ASSERT_((::testing::tuple_size< \ tn ::testing::internal::Function<__VA_ARGS__>::ArgumentTuple>::value == $i), \ this_method_does_not_take_$i[[]]_argument[[$if i != 1 [[s]]]]); \ GMOCK_MOCKER_($i, constness, Method).SetOwnerAndName(this, #Method); \ return GMOCK_MOCKER_($i, constness, Method).Invoke($as); \ } \ ::testing::MockSpec<__VA_ARGS__>& \ gmock_##Method($matcher_as) constness { \ GMOCK_MOCKER_($i, constness, Method).RegisterOwner(this); \ return GMOCK_MOCKER_($i, constness, Method).With($as); \ } \ mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_($i, constness, Method) ]] $for i [[ #define MOCK_METHOD$i(m, ...) GMOCK_METHOD$i[[]]_(, , , m, __VA_ARGS__) ]] $for i [[ #define MOCK_CONST_METHOD$i(m, ...) GMOCK_METHOD$i[[]]_(, const, , m, __VA_ARGS__) ]] $for i [[ #define MOCK_METHOD$i[[]]_T(m, ...) GMOCK_METHOD$i[[]]_(typename, , , m, __VA_ARGS__) ]] $for i [[ #define MOCK_CONST_METHOD$i[[]]_T(m, ...) \ GMOCK_METHOD$i[[]]_(typename, const, , m, __VA_ARGS__) ]] $for i [[ #define MOCK_METHOD$i[[]]_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD$i[[]]_(, , ct, m, __VA_ARGS__) ]] $for i [[ #define MOCK_CONST_METHOD$i[[]]_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD$i[[]]_(, const, ct, m, __VA_ARGS__) ]] $for i [[ #define MOCK_METHOD$i[[]]_T_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD$i[[]]_(typename, , ct, m, __VA_ARGS__) ]] $for i [[ #define MOCK_CONST_METHOD$i[[]]_T_WITH_CALLTYPE(ct, m, ...) \ GMOCK_METHOD$i[[]]_(typename, const, ct, m, __VA_ARGS__) ]] // A MockFunction class has one mock method whose type is F. It is // useful when you just want your test code to emit some messages and // have Google Mock verify the right messages are sent (and perhaps at // the right times). For example, if you are exercising code: // // Foo(1); // Foo(2); // Foo(3); // // and want to verify that Foo(1) and Foo(3) both invoke // mock.Bar("a"), but Foo(2) doesn't invoke anything, you can write: // // TEST(FooTest, InvokesBarCorrectly) { // MyMock mock; // MockFunction check; // { // InSequence s; // // EXPECT_CALL(mock, Bar("a")); // EXPECT_CALL(check, Call("1")); // EXPECT_CALL(check, Call("2")); // EXPECT_CALL(mock, Bar("a")); // } // Foo(1); // check.Call("1"); // Foo(2); // check.Call("2"); // Foo(3); // } // // The expectation spec says that the first Bar("a") must happen // before check point "1", the second Bar("a") must happen after check // point "2", and nothing should happen between the two check // points. The explicit check points make it easy to tell which // Bar("a") is called by which call to Foo(). // // MockFunction can also be used to exercise code that accepts // std::function callbacks. To do so, use AsStdFunction() method // to create std::function proxy forwarding to original object's Call. // Example: // // TEST(FooTest, RunsCallbackWithBarArgument) { // MockFunction callback; // EXPECT_CALL(callback, Call("bar")).WillOnce(Return(1)); // Foo(callback.AsStdFunction()); // } template class MockFunction; $for i [[ $range j 0..i-1 $var ArgTypes = [[$for j, [[A$j]]]] $var ArgNames = [[$for j, [[a$j]]]] $var ArgDecls = [[$for j, [[A$j a$j]]]] template class MockFunction { public: MockFunction() {} MOCK_METHOD$i[[]]_T(Call, R($ArgTypes)); #if GTEST_HAS_STD_FUNCTION_ std::function AsStdFunction() { return [this]($ArgDecls) -> R { return this->Call($ArgNames); }; } #endif // GTEST_HAS_STD_FUNCTION_ private: GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFunction); }; ]] } // namespace testing #endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_ nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/include/gmock/gmock-generated-matchers.h000066400000000000000000002504051455373415500324020ustar00rootroot00000000000000// This file was GENERATED by command: // pump.py gmock-generated-matchers.h.pump // DO NOT EDIT BY HAND!!! // Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Google Mock - a framework for writing C++ mock classes. // // This file implements some commonly used variadic matchers. #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ #include #include #include #include #include "gmock/gmock-matchers.h" namespace testing { namespace internal { // The type of the i-th (0-based) field of Tuple. #define GMOCK_FIELD_TYPE_(Tuple, i) \ typename ::testing::tuple_element::type // TupleFields is for selecting fields from a // tuple of type Tuple. It has two members: // // type: a tuple type whose i-th field is the ki-th field of Tuple. // GetSelectedFields(t): returns fields k0, ..., and kn of t as a tuple. // // For example, in class TupleFields, 2, 0>, we have: // // type is tuple, and // GetSelectedFields(make_tuple(true, 'a', 42)) is (42, true). template class TupleFields; // This generic version is used when there are 10 selectors. template class TupleFields { public: typedef ::testing::tuple type; static type GetSelectedFields(const Tuple& t) { return type(get(t), get(t), get(t), get(t), get(t), get(t), get(t), get(t), get(t), get(t)); } }; // The following specialization is used for 0 ~ 9 selectors. template class TupleFields { public: typedef ::testing::tuple<> type; static type GetSelectedFields(const Tuple& /* t */) { return type(); } }; template class TupleFields { public: typedef ::testing::tuple type; static type GetSelectedFields(const Tuple& t) { return type(get(t)); } }; template class TupleFields { public: typedef ::testing::tuple type; static type GetSelectedFields(const Tuple& t) { return type(get(t), get(t)); } }; template class TupleFields { public: typedef ::testing::tuple type; static type GetSelectedFields(const Tuple& t) { return type(get(t), get(t), get(t)); } }; template class TupleFields { public: typedef ::testing::tuple type; static type GetSelectedFields(const Tuple& t) { return type(get(t), get(t), get(t), get(t)); } }; template class TupleFields { public: typedef ::testing::tuple type; static type GetSelectedFields(const Tuple& t) { return type(get(t), get(t), get(t), get(t), get(t)); } }; template class TupleFields { public: typedef ::testing::tuple type; static type GetSelectedFields(const Tuple& t) { return type(get(t), get(t), get(t), get(t), get(t), get(t)); } }; template class TupleFields { public: typedef ::testing::tuple type; static type GetSelectedFields(const Tuple& t) { return type(get(t), get(t), get(t), get(t), get(t), get(t), get(t)); } }; template class TupleFields { public: typedef ::testing::tuple type; static type GetSelectedFields(const Tuple& t) { return type(get(t), get(t), get(t), get(t), get(t), get(t), get(t), get(t)); } }; template class TupleFields { public: typedef ::testing::tuple type; static type GetSelectedFields(const Tuple& t) { return type(get(t), get(t), get(t), get(t), get(t), get(t), get(t), get(t), get(t)); } }; #undef GMOCK_FIELD_TYPE_ // Implements the Args() matcher. template class ArgsMatcherImpl : public MatcherInterface { public: // ArgsTuple may have top-level const or reference modifiers. typedef GTEST_REMOVE_REFERENCE_AND_CONST_(ArgsTuple) RawArgsTuple; typedef typename internal::TupleFields::type SelectedArgs; typedef Matcher MonomorphicInnerMatcher; template explicit ArgsMatcherImpl(const InnerMatcher& inner_matcher) : inner_matcher_(SafeMatcherCast(inner_matcher)) {} virtual bool MatchAndExplain(ArgsTuple args, MatchResultListener* listener) const { const SelectedArgs& selected_args = GetSelectedArgs(args); if (!listener->IsInterested()) return inner_matcher_.Matches(selected_args); PrintIndices(listener->stream()); *listener << "are " << PrintToString(selected_args); StringMatchResultListener inner_listener; const bool match = inner_matcher_.MatchAndExplain(selected_args, &inner_listener); PrintIfNotEmpty(inner_listener.str(), listener->stream()); return match; } virtual void DescribeTo(::std::ostream* os) const { *os << "are a tuple "; PrintIndices(os); inner_matcher_.DescribeTo(os); } virtual void DescribeNegationTo(::std::ostream* os) const { *os << "are a tuple "; PrintIndices(os); inner_matcher_.DescribeNegationTo(os); } private: static SelectedArgs GetSelectedArgs(ArgsTuple args) { return TupleFields::GetSelectedFields(args); } // Prints the indices of the selected fields. static void PrintIndices(::std::ostream* os) { *os << "whose fields ("; const int indices[10] = { k0, k1, k2, k3, k4, k5, k6, k7, k8, k9 }; for (int i = 0; i < 10; i++) { if (indices[i] < 0) break; if (i >= 1) *os << ", "; *os << "#" << indices[i]; } *os << ") "; } const MonomorphicInnerMatcher inner_matcher_; GTEST_DISALLOW_ASSIGN_(ArgsMatcherImpl); }; template class ArgsMatcher { public: explicit ArgsMatcher(const InnerMatcher& inner_matcher) : inner_matcher_(inner_matcher) {} template operator Matcher() const { return MakeMatcher(new ArgsMatcherImpl(inner_matcher_)); } private: const InnerMatcher inner_matcher_; GTEST_DISALLOW_ASSIGN_(ArgsMatcher); }; // A set of metafunctions for computing the result type of AllOf. // AllOf(m1, ..., mN) returns // AllOfResultN::type. // Although AllOf isn't defined for one argument, AllOfResult1 is defined // to simplify the implementation. template struct AllOfResult1 { typedef M1 type; }; template struct AllOfResult2 { typedef BothOfMatcher< typename AllOfResult1::type, typename AllOfResult1::type > type; }; template struct AllOfResult3 { typedef BothOfMatcher< typename AllOfResult1::type, typename AllOfResult2::type > type; }; template struct AllOfResult4 { typedef BothOfMatcher< typename AllOfResult2::type, typename AllOfResult2::type > type; }; template struct AllOfResult5 { typedef BothOfMatcher< typename AllOfResult2::type, typename AllOfResult3::type > type; }; template struct AllOfResult6 { typedef BothOfMatcher< typename AllOfResult3::type, typename AllOfResult3::type > type; }; template struct AllOfResult7 { typedef BothOfMatcher< typename AllOfResult3::type, typename AllOfResult4::type > type; }; template struct AllOfResult8 { typedef BothOfMatcher< typename AllOfResult4::type, typename AllOfResult4::type > type; }; template struct AllOfResult9 { typedef BothOfMatcher< typename AllOfResult4::type, typename AllOfResult5::type > type; }; template struct AllOfResult10 { typedef BothOfMatcher< typename AllOfResult5::type, typename AllOfResult5::type > type; }; // A set of metafunctions for computing the result type of AnyOf. // AnyOf(m1, ..., mN) returns // AnyOfResultN::type. // Although AnyOf isn't defined for one argument, AnyOfResult1 is defined // to simplify the implementation. template struct AnyOfResult1 { typedef M1 type; }; template struct AnyOfResult2 { typedef EitherOfMatcher< typename AnyOfResult1::type, typename AnyOfResult1::type > type; }; template struct AnyOfResult3 { typedef EitherOfMatcher< typename AnyOfResult1::type, typename AnyOfResult2::type > type; }; template struct AnyOfResult4 { typedef EitherOfMatcher< typename AnyOfResult2::type, typename AnyOfResult2::type > type; }; template struct AnyOfResult5 { typedef EitherOfMatcher< typename AnyOfResult2::type, typename AnyOfResult3::type > type; }; template struct AnyOfResult6 { typedef EitherOfMatcher< typename AnyOfResult3::type, typename AnyOfResult3::type > type; }; template struct AnyOfResult7 { typedef EitherOfMatcher< typename AnyOfResult3::type, typename AnyOfResult4::type > type; }; template struct AnyOfResult8 { typedef EitherOfMatcher< typename AnyOfResult4::type, typename AnyOfResult4::type > type; }; template struct AnyOfResult9 { typedef EitherOfMatcher< typename AnyOfResult4::type, typename AnyOfResult5::type > type; }; template struct AnyOfResult10 { typedef EitherOfMatcher< typename AnyOfResult5::type, typename AnyOfResult5::type > type; }; } // namespace internal // Args(a_matcher) matches a tuple if the selected // fields of it matches a_matcher. C++ doesn't support default // arguments for function templates, so we have to overload it. template inline internal::ArgsMatcher Args(const InnerMatcher& matcher) { return internal::ArgsMatcher(matcher); } template inline internal::ArgsMatcher Args(const InnerMatcher& matcher) { return internal::ArgsMatcher(matcher); } template inline internal::ArgsMatcher Args(const InnerMatcher& matcher) { return internal::ArgsMatcher(matcher); } template inline internal::ArgsMatcher Args(const InnerMatcher& matcher) { return internal::ArgsMatcher(matcher); } template inline internal::ArgsMatcher Args(const InnerMatcher& matcher) { return internal::ArgsMatcher(matcher); } template inline internal::ArgsMatcher Args(const InnerMatcher& matcher) { return internal::ArgsMatcher(matcher); } template inline internal::ArgsMatcher Args(const InnerMatcher& matcher) { return internal::ArgsMatcher(matcher); } template inline internal::ArgsMatcher Args(const InnerMatcher& matcher) { return internal::ArgsMatcher(matcher); } template inline internal::ArgsMatcher Args(const InnerMatcher& matcher) { return internal::ArgsMatcher(matcher); } template inline internal::ArgsMatcher Args(const InnerMatcher& matcher) { return internal::ArgsMatcher(matcher); } template inline internal::ArgsMatcher Args(const InnerMatcher& matcher) { return internal::ArgsMatcher(matcher); } // ElementsAre(e_1, e_2, ... e_n) matches an STL-style container with // n elements, where the i-th element in the container must // match the i-th argument in the list. Each argument of // ElementsAre() can be either a value or a matcher. We support up to // 10 arguments. // // The use of DecayArray in the implementation allows ElementsAre() // to accept string literals, whose type is const char[N], but we // want to treat them as const char*. // // NOTE: Since ElementsAre() cares about the order of the elements, it // must not be used with containers whose elements's order is // undefined (e.g. hash_map). inline internal::ElementsAreMatcher< ::testing::tuple<> > ElementsAre() { typedef ::testing::tuple<> Args; return internal::ElementsAreMatcher(Args()); } template inline internal::ElementsAreMatcher< ::testing::tuple< typename internal::DecayArray::type> > ElementsAre(const T1& e1) { typedef ::testing::tuple< typename internal::DecayArray::type> Args; return internal::ElementsAreMatcher(Args(e1)); } template inline internal::ElementsAreMatcher< ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type> > ElementsAre(const T1& e1, const T2& e2) { typedef ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type> Args; return internal::ElementsAreMatcher(Args(e1, e2)); } template inline internal::ElementsAreMatcher< ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> > ElementsAre(const T1& e1, const T2& e2, const T3& e3) { typedef ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> Args; return internal::ElementsAreMatcher(Args(e1, e2, e3)); } template inline internal::ElementsAreMatcher< ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> > ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4) { typedef ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> Args; return internal::ElementsAreMatcher(Args(e1, e2, e3, e4)); } template inline internal::ElementsAreMatcher< ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> > ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, const T5& e5) { typedef ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> Args; return internal::ElementsAreMatcher(Args(e1, e2, e3, e4, e5)); } template inline internal::ElementsAreMatcher< ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> > ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, const T5& e5, const T6& e6) { typedef ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> Args; return internal::ElementsAreMatcher(Args(e1, e2, e3, e4, e5, e6)); } template inline internal::ElementsAreMatcher< ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> > ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, const T5& e5, const T6& e6, const T7& e7) { typedef ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> Args; return internal::ElementsAreMatcher(Args(e1, e2, e3, e4, e5, e6, e7)); } template inline internal::ElementsAreMatcher< ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> > ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, const T5& e5, const T6& e6, const T7& e7, const T8& e8) { typedef ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> Args; return internal::ElementsAreMatcher(Args(e1, e2, e3, e4, e5, e6, e7, e8)); } template inline internal::ElementsAreMatcher< ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> > ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, const T5& e5, const T6& e6, const T7& e7, const T8& e8, const T9& e9) { typedef ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> Args; return internal::ElementsAreMatcher(Args(e1, e2, e3, e4, e5, e6, e7, e8, e9)); } template inline internal::ElementsAreMatcher< ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> > ElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, const T5& e5, const T6& e6, const T7& e7, const T8& e8, const T9& e9, const T10& e10) { typedef ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> Args; return internal::ElementsAreMatcher(Args(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10)); } // UnorderedElementsAre(e_1, e_2, ..., e_n) is an ElementsAre extension // that matches n elements in any order. We support up to n=10 arguments. inline internal::UnorderedElementsAreMatcher< ::testing::tuple<> > UnorderedElementsAre() { typedef ::testing::tuple<> Args; return internal::UnorderedElementsAreMatcher(Args()); } template inline internal::UnorderedElementsAreMatcher< ::testing::tuple< typename internal::DecayArray::type> > UnorderedElementsAre(const T1& e1) { typedef ::testing::tuple< typename internal::DecayArray::type> Args; return internal::UnorderedElementsAreMatcher(Args(e1)); } template inline internal::UnorderedElementsAreMatcher< ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type> > UnorderedElementsAre(const T1& e1, const T2& e2) { typedef ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type> Args; return internal::UnorderedElementsAreMatcher(Args(e1, e2)); } template inline internal::UnorderedElementsAreMatcher< ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> > UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3) { typedef ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> Args; return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3)); } template inline internal::UnorderedElementsAreMatcher< ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> > UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4) { typedef ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> Args; return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4)); } template inline internal::UnorderedElementsAreMatcher< ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> > UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, const T5& e5) { typedef ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> Args; return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4, e5)); } template inline internal::UnorderedElementsAreMatcher< ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> > UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, const T5& e5, const T6& e6) { typedef ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> Args; return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4, e5, e6)); } template inline internal::UnorderedElementsAreMatcher< ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> > UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, const T5& e5, const T6& e6, const T7& e7) { typedef ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> Args; return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4, e5, e6, e7)); } template inline internal::UnorderedElementsAreMatcher< ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> > UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, const T5& e5, const T6& e6, const T7& e7, const T8& e8) { typedef ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> Args; return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4, e5, e6, e7, e8)); } template inline internal::UnorderedElementsAreMatcher< ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> > UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, const T5& e5, const T6& e6, const T7& e7, const T8& e8, const T9& e9) { typedef ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> Args; return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4, e5, e6, e7, e8, e9)); } template inline internal::UnorderedElementsAreMatcher< ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> > UnorderedElementsAre(const T1& e1, const T2& e2, const T3& e3, const T4& e4, const T5& e5, const T6& e6, const T7& e7, const T8& e8, const T9& e9, const T10& e10) { typedef ::testing::tuple< typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type, typename internal::DecayArray::type> Args; return internal::UnorderedElementsAreMatcher(Args(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10)); } // AllOf(m1, m2, ..., mk) matches any value that matches all of the given // sub-matchers. AllOf is called fully qualified to prevent ADL from firing. template inline typename internal::AllOfResult2::type AllOf(M1 m1, M2 m2) { return typename internal::AllOfResult2::type( m1, m2); } template inline typename internal::AllOfResult3::type AllOf(M1 m1, M2 m2, M3 m3) { return typename internal::AllOfResult3::type( m1, ::testing::AllOf(m2, m3)); } template inline typename internal::AllOfResult4::type AllOf(M1 m1, M2 m2, M3 m3, M4 m4) { return typename internal::AllOfResult4::type( ::testing::AllOf(m1, m2), ::testing::AllOf(m3, m4)); } template inline typename internal::AllOfResult5::type AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5) { return typename internal::AllOfResult5::type( ::testing::AllOf(m1, m2), ::testing::AllOf(m3, m4, m5)); } template inline typename internal::AllOfResult6::type AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6) { return typename internal::AllOfResult6::type( ::testing::AllOf(m1, m2, m3), ::testing::AllOf(m4, m5, m6)); } template inline typename internal::AllOfResult7::type AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7) { return typename internal::AllOfResult7::type( ::testing::AllOf(m1, m2, m3), ::testing::AllOf(m4, m5, m6, m7)); } template inline typename internal::AllOfResult8::type AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8) { return typename internal::AllOfResult8::type( ::testing::AllOf(m1, m2, m3, m4), ::testing::AllOf(m5, m6, m7, m8)); } template inline typename internal::AllOfResult9::type AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9) { return typename internal::AllOfResult9::type( ::testing::AllOf(m1, m2, m3, m4), ::testing::AllOf(m5, m6, m7, m8, m9)); } template inline typename internal::AllOfResult10::type AllOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) { return typename internal::AllOfResult10::type( ::testing::AllOf(m1, m2, m3, m4, m5), ::testing::AllOf(m6, m7, m8, m9, m10)); } // AnyOf(m1, m2, ..., mk) matches any value that matches any of the given // sub-matchers. AnyOf is called fully qualified to prevent ADL from firing. template inline typename internal::AnyOfResult2::type AnyOf(M1 m1, M2 m2) { return typename internal::AnyOfResult2::type( m1, m2); } template inline typename internal::AnyOfResult3::type AnyOf(M1 m1, M2 m2, M3 m3) { return typename internal::AnyOfResult3::type( m1, ::testing::AnyOf(m2, m3)); } template inline typename internal::AnyOfResult4::type AnyOf(M1 m1, M2 m2, M3 m3, M4 m4) { return typename internal::AnyOfResult4::type( ::testing::AnyOf(m1, m2), ::testing::AnyOf(m3, m4)); } template inline typename internal::AnyOfResult5::type AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5) { return typename internal::AnyOfResult5::type( ::testing::AnyOf(m1, m2), ::testing::AnyOf(m3, m4, m5)); } template inline typename internal::AnyOfResult6::type AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6) { return typename internal::AnyOfResult6::type( ::testing::AnyOf(m1, m2, m3), ::testing::AnyOf(m4, m5, m6)); } template inline typename internal::AnyOfResult7::type AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7) { return typename internal::AnyOfResult7::type( ::testing::AnyOf(m1, m2, m3), ::testing::AnyOf(m4, m5, m6, m7)); } template inline typename internal::AnyOfResult8::type AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8) { return typename internal::AnyOfResult8::type( ::testing::AnyOf(m1, m2, m3, m4), ::testing::AnyOf(m5, m6, m7, m8)); } template inline typename internal::AnyOfResult9::type AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9) { return typename internal::AnyOfResult9::type( ::testing::AnyOf(m1, m2, m3, m4), ::testing::AnyOf(m5, m6, m7, m8, m9)); } template inline typename internal::AnyOfResult10::type AnyOf(M1 m1, M2 m2, M3 m3, M4 m4, M5 m5, M6 m6, M7 m7, M8 m8, M9 m9, M10 m10) { return typename internal::AnyOfResult10::type( ::testing::AnyOf(m1, m2, m3, m4, m5), ::testing::AnyOf(m6, m7, m8, m9, m10)); } } // namespace testing // The MATCHER* family of macros can be used in a namespace scope to // define custom matchers easily. // // Basic Usage // =========== // // The syntax // // MATCHER(name, description_string) { statements; } // // defines a matcher with the given name that executes the statements, // which must return a bool to indicate if the match succeeds. Inside // the statements, you can refer to the value being matched by 'arg', // and refer to its type by 'arg_type'. // // The description string documents what the matcher does, and is used // to generate the failure message when the match fails. Since a // MATCHER() is usually defined in a header file shared by multiple // C++ source files, we require the description to be a C-string // literal to avoid possible side effects. It can be empty, in which // case we'll use the sequence of words in the matcher name as the // description. // // For example: // // MATCHER(IsEven, "") { return (arg % 2) == 0; } // // allows you to write // // // Expects mock_foo.Bar(n) to be called where n is even. // EXPECT_CALL(mock_foo, Bar(IsEven())); // // or, // // // Verifies that the value of some_expression is even. // EXPECT_THAT(some_expression, IsEven()); // // If the above assertion fails, it will print something like: // // Value of: some_expression // Expected: is even // Actual: 7 // // where the description "is even" is automatically calculated from the // matcher name IsEven. // // Argument Type // ============= // // Note that the type of the value being matched (arg_type) is // determined by the context in which you use the matcher and is // supplied to you by the compiler, so you don't need to worry about // declaring it (nor can you). This allows the matcher to be // polymorphic. For example, IsEven() can be used to match any type // where the value of "(arg % 2) == 0" can be implicitly converted to // a bool. In the "Bar(IsEven())" example above, if method Bar() // takes an int, 'arg_type' will be int; if it takes an unsigned long, // 'arg_type' will be unsigned long; and so on. // // Parameterizing Matchers // ======================= // // Sometimes you'll want to parameterize the matcher. For that you // can use another macro: // // MATCHER_P(name, param_name, description_string) { statements; } // // For example: // // MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; } // // will allow you to write: // // EXPECT_THAT(Blah("a"), HasAbsoluteValue(n)); // // which may lead to this message (assuming n is 10): // // Value of: Blah("a") // Expected: has absolute value 10 // Actual: -9 // // Note that both the matcher description and its parameter are // printed, making the message human-friendly. // // In the matcher definition body, you can write 'foo_type' to // reference the type of a parameter named 'foo'. For example, in the // body of MATCHER_P(HasAbsoluteValue, value) above, you can write // 'value_type' to refer to the type of 'value'. // // We also provide MATCHER_P2, MATCHER_P3, ..., up to MATCHER_P10 to // support multi-parameter matchers. // // Describing Parameterized Matchers // ================================= // // The last argument to MATCHER*() is a string-typed expression. The // expression can reference all of the matcher's parameters and a // special bool-typed variable named 'negation'. When 'negation' is // false, the expression should evaluate to the matcher's description; // otherwise it should evaluate to the description of the negation of // the matcher. For example, // // using testing::PrintToString; // // MATCHER_P2(InClosedRange, low, hi, // string(negation ? "is not" : "is") + " in range [" + // PrintToString(low) + ", " + PrintToString(hi) + "]") { // return low <= arg && arg <= hi; // } // ... // EXPECT_THAT(3, InClosedRange(4, 6)); // EXPECT_THAT(3, Not(InClosedRange(2, 4))); // // would generate two failures that contain the text: // // Expected: is in range [4, 6] // ... // Expected: is not in range [2, 4] // // If you specify "" as the description, the failure message will // contain the sequence of words in the matcher name followed by the // parameter values printed as a tuple. For example, // // MATCHER_P2(InClosedRange, low, hi, "") { ... } // ... // EXPECT_THAT(3, InClosedRange(4, 6)); // EXPECT_THAT(3, Not(InClosedRange(2, 4))); // // would generate two failures that contain the text: // // Expected: in closed range (4, 6) // ... // Expected: not (in closed range (2, 4)) // // Types of Matcher Parameters // =========================== // // For the purpose of typing, you can view // // MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... } // // as shorthand for // // template // FooMatcherPk // Foo(p1_type p1, ..., pk_type pk) { ... } // // When you write Foo(v1, ..., vk), the compiler infers the types of // the parameters v1, ..., and vk for you. If you are not happy with // the result of the type inference, you can specify the types by // explicitly instantiating the template, as in Foo(5, // false). As said earlier, you don't get to (or need to) specify // 'arg_type' as that's determined by the context in which the matcher // is used. You can assign the result of expression Foo(p1, ..., pk) // to a variable of type FooMatcherPk. This // can be useful when composing matchers. // // While you can instantiate a matcher template with reference types, // passing the parameters by pointer usually makes your code more // readable. If, however, you still want to pass a parameter by // reference, be aware that in the failure message generated by the // matcher you will see the value of the referenced object but not its // address. // // Explaining Match Results // ======================== // // Sometimes the matcher description alone isn't enough to explain why // the match has failed or succeeded. For example, when expecting a // long string, it can be very helpful to also print the diff between // the expected string and the actual one. To achieve that, you can // optionally stream additional information to a special variable // named result_listener, whose type is a pointer to class // MatchResultListener: // // MATCHER_P(EqualsLongString, str, "") { // if (arg == str) return true; // // *result_listener << "the difference: " /// << DiffStrings(str, arg); // return false; // } // // Overloading Matchers // ==================== // // You can overload matchers with different numbers of parameters: // // MATCHER_P(Blah, a, description_string1) { ... } // MATCHER_P2(Blah, a, b, description_string2) { ... } // // Caveats // ======= // // When defining a new matcher, you should also consider implementing // MatcherInterface or using MakePolymorphicMatcher(). These // approaches require more work than the MATCHER* macros, but also // give you more control on the types of the value being matched and // the matcher parameters, which may leads to better compiler error // messages when the matcher is used wrong. They also allow // overloading matchers based on parameter types (as opposed to just // based on the number of parameters). // // MATCHER*() can only be used in a namespace scope. The reason is // that C++ doesn't yet allow function-local types to be used to // instantiate templates. The up-coming C++0x standard will fix this. // Once that's done, we'll consider supporting using MATCHER*() inside // a function. // // More Information // ================ // // To learn more about using these macros, please search for 'MATCHER' // on http://code.google.com/p/googlemock/wiki/CookBook. #define MATCHER(name, description)\ class name##Matcher {\ public:\ template \ class gmock_Impl : public ::testing::MatcherInterface {\ public:\ gmock_Impl()\ {}\ virtual bool MatchAndExplain(\ arg_type arg, ::testing::MatchResultListener* result_listener) const;\ virtual void DescribeTo(::std::ostream* gmock_os) const {\ *gmock_os << FormatDescription(false);\ }\ virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ *gmock_os << FormatDescription(true);\ }\ private:\ ::testing::internal::string FormatDescription(bool negation) const {\ const ::testing::internal::string gmock_description = (description);\ if (!gmock_description.empty())\ return gmock_description;\ return ::testing::internal::FormatMatcherDescription(\ negation, #name, \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ ::testing::tuple<>()));\ }\ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template \ operator ::testing::Matcher() const {\ return ::testing::Matcher(\ new gmock_Impl());\ }\ name##Matcher() {\ }\ private:\ GTEST_DISALLOW_ASSIGN_(name##Matcher);\ };\ inline name##Matcher name() {\ return name##Matcher();\ }\ template \ bool name##Matcher::gmock_Impl::MatchAndExplain(\ arg_type arg, \ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ const #define MATCHER_P(name, p0, description)\ template \ class name##MatcherP {\ public:\ template \ class gmock_Impl : public ::testing::MatcherInterface {\ public:\ explicit gmock_Impl(p0##_type gmock_p0)\ : p0(gmock_p0) {}\ virtual bool MatchAndExplain(\ arg_type arg, ::testing::MatchResultListener* result_listener) const;\ virtual void DescribeTo(::std::ostream* gmock_os) const {\ *gmock_os << FormatDescription(false);\ }\ virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ *gmock_os << FormatDescription(true);\ }\ p0##_type p0;\ private:\ ::testing::internal::string FormatDescription(bool negation) const {\ const ::testing::internal::string gmock_description = (description);\ if (!gmock_description.empty())\ return gmock_description;\ return ::testing::internal::FormatMatcherDescription(\ negation, #name, \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ ::testing::tuple(p0)));\ }\ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template \ operator ::testing::Matcher() const {\ return ::testing::Matcher(\ new gmock_Impl(p0));\ }\ explicit name##MatcherP(p0##_type gmock_p0) : p0(gmock_p0) {\ }\ p0##_type p0;\ private:\ GTEST_DISALLOW_ASSIGN_(name##MatcherP);\ };\ template \ inline name##MatcherP name(p0##_type p0) {\ return name##MatcherP(p0);\ }\ template \ template \ bool name##MatcherP::gmock_Impl::MatchAndExplain(\ arg_type arg, \ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ const #define MATCHER_P2(name, p0, p1, description)\ template \ class name##MatcherP2 {\ public:\ template \ class gmock_Impl : public ::testing::MatcherInterface {\ public:\ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1)\ : p0(gmock_p0), p1(gmock_p1) {}\ virtual bool MatchAndExplain(\ arg_type arg, ::testing::MatchResultListener* result_listener) const;\ virtual void DescribeTo(::std::ostream* gmock_os) const {\ *gmock_os << FormatDescription(false);\ }\ virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ *gmock_os << FormatDescription(true);\ }\ p0##_type p0;\ p1##_type p1;\ private:\ ::testing::internal::string FormatDescription(bool negation) const {\ const ::testing::internal::string gmock_description = (description);\ if (!gmock_description.empty())\ return gmock_description;\ return ::testing::internal::FormatMatcherDescription(\ negation, #name, \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ ::testing::tuple(p0, p1)));\ }\ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template \ operator ::testing::Matcher() const {\ return ::testing::Matcher(\ new gmock_Impl(p0, p1));\ }\ name##MatcherP2(p0##_type gmock_p0, p1##_type gmock_p1) : p0(gmock_p0), \ p1(gmock_p1) {\ }\ p0##_type p0;\ p1##_type p1;\ private:\ GTEST_DISALLOW_ASSIGN_(name##MatcherP2);\ };\ template \ inline name##MatcherP2 name(p0##_type p0, \ p1##_type p1) {\ return name##MatcherP2(p0, p1);\ }\ template \ template \ bool name##MatcherP2::gmock_Impl::MatchAndExplain(\ arg_type arg, \ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ const #define MATCHER_P3(name, p0, p1, p2, description)\ template \ class name##MatcherP3 {\ public:\ template \ class gmock_Impl : public ::testing::MatcherInterface {\ public:\ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2)\ : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2) {}\ virtual bool MatchAndExplain(\ arg_type arg, ::testing::MatchResultListener* result_listener) const;\ virtual void DescribeTo(::std::ostream* gmock_os) const {\ *gmock_os << FormatDescription(false);\ }\ virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ *gmock_os << FormatDescription(true);\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ private:\ ::testing::internal::string FormatDescription(bool negation) const {\ const ::testing::internal::string gmock_description = (description);\ if (!gmock_description.empty())\ return gmock_description;\ return ::testing::internal::FormatMatcherDescription(\ negation, #name, \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ ::testing::tuple(p0, p1, \ p2)));\ }\ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template \ operator ::testing::Matcher() const {\ return ::testing::Matcher(\ new gmock_Impl(p0, p1, p2));\ }\ name##MatcherP3(p0##_type gmock_p0, p1##_type gmock_p1, \ p2##_type gmock_p2) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2) {\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ private:\ GTEST_DISALLOW_ASSIGN_(name##MatcherP3);\ };\ template \ inline name##MatcherP3 name(p0##_type p0, \ p1##_type p1, p2##_type p2) {\ return name##MatcherP3(p0, p1, p2);\ }\ template \ template \ bool name##MatcherP3::gmock_Impl::MatchAndExplain(\ arg_type arg, \ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ const #define MATCHER_P4(name, p0, p1, p2, p3, description)\ template \ class name##MatcherP4 {\ public:\ template \ class gmock_Impl : public ::testing::MatcherInterface {\ public:\ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ p3##_type gmock_p3)\ : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3) {}\ virtual bool MatchAndExplain(\ arg_type arg, ::testing::MatchResultListener* result_listener) const;\ virtual void DescribeTo(::std::ostream* gmock_os) const {\ *gmock_os << FormatDescription(false);\ }\ virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ *gmock_os << FormatDescription(true);\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ private:\ ::testing::internal::string FormatDescription(bool negation) const {\ const ::testing::internal::string gmock_description = (description);\ if (!gmock_description.empty())\ return gmock_description;\ return ::testing::internal::FormatMatcherDescription(\ negation, #name, \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ ::testing::tuple(p0, p1, p2, p3)));\ }\ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template \ operator ::testing::Matcher() const {\ return ::testing::Matcher(\ new gmock_Impl(p0, p1, p2, p3));\ }\ name##MatcherP4(p0##_type gmock_p0, p1##_type gmock_p1, \ p2##_type gmock_p2, p3##_type gmock_p3) : p0(gmock_p0), p1(gmock_p1), \ p2(gmock_p2), p3(gmock_p3) {\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ private:\ GTEST_DISALLOW_ASSIGN_(name##MatcherP4);\ };\ template \ inline name##MatcherP4 name(p0##_type p0, p1##_type p1, p2##_type p2, \ p3##_type p3) {\ return name##MatcherP4(p0, \ p1, p2, p3);\ }\ template \ template \ bool name##MatcherP4::gmock_Impl::MatchAndExplain(\ arg_type arg, \ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ const #define MATCHER_P5(name, p0, p1, p2, p3, p4, description)\ template \ class name##MatcherP5 {\ public:\ template \ class gmock_Impl : public ::testing::MatcherInterface {\ public:\ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ p3##_type gmock_p3, p4##_type gmock_p4)\ : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \ p4(gmock_p4) {}\ virtual bool MatchAndExplain(\ arg_type arg, ::testing::MatchResultListener* result_listener) const;\ virtual void DescribeTo(::std::ostream* gmock_os) const {\ *gmock_os << FormatDescription(false);\ }\ virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ *gmock_os << FormatDescription(true);\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ p4##_type p4;\ private:\ ::testing::internal::string FormatDescription(bool negation) const {\ const ::testing::internal::string gmock_description = (description);\ if (!gmock_description.empty())\ return gmock_description;\ return ::testing::internal::FormatMatcherDescription(\ negation, #name, \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ ::testing::tuple(p0, p1, p2, p3, p4)));\ }\ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template \ operator ::testing::Matcher() const {\ return ::testing::Matcher(\ new gmock_Impl(p0, p1, p2, p3, p4));\ }\ name##MatcherP5(p0##_type gmock_p0, p1##_type gmock_p1, \ p2##_type gmock_p2, p3##_type gmock_p3, \ p4##_type gmock_p4) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ p3(gmock_p3), p4(gmock_p4) {\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ p4##_type p4;\ private:\ GTEST_DISALLOW_ASSIGN_(name##MatcherP5);\ };\ template \ inline name##MatcherP5 name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ p4##_type p4) {\ return name##MatcherP5(p0, p1, p2, p3, p4);\ }\ template \ template \ bool name##MatcherP5::gmock_Impl::MatchAndExplain(\ arg_type arg, \ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ const #define MATCHER_P6(name, p0, p1, p2, p3, p4, p5, description)\ template \ class name##MatcherP6 {\ public:\ template \ class gmock_Impl : public ::testing::MatcherInterface {\ public:\ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5)\ : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \ p4(gmock_p4), p5(gmock_p5) {}\ virtual bool MatchAndExplain(\ arg_type arg, ::testing::MatchResultListener* result_listener) const;\ virtual void DescribeTo(::std::ostream* gmock_os) const {\ *gmock_os << FormatDescription(false);\ }\ virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ *gmock_os << FormatDescription(true);\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ p4##_type p4;\ p5##_type p5;\ private:\ ::testing::internal::string FormatDescription(bool negation) const {\ const ::testing::internal::string gmock_description = (description);\ if (!gmock_description.empty())\ return gmock_description;\ return ::testing::internal::FormatMatcherDescription(\ negation, #name, \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ ::testing::tuple(p0, p1, p2, p3, p4, p5)));\ }\ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template \ operator ::testing::Matcher() const {\ return ::testing::Matcher(\ new gmock_Impl(p0, p1, p2, p3, p4, p5));\ }\ name##MatcherP6(p0##_type gmock_p0, p1##_type gmock_p1, \ p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ p5##_type gmock_p5) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ p3(gmock_p3), p4(gmock_p4), p5(gmock_p5) {\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ p4##_type p4;\ p5##_type p5;\ private:\ GTEST_DISALLOW_ASSIGN_(name##MatcherP6);\ };\ template \ inline name##MatcherP6 name(p0##_type p0, p1##_type p1, p2##_type p2, \ p3##_type p3, p4##_type p4, p5##_type p5) {\ return name##MatcherP6(p0, p1, p2, p3, p4, p5);\ }\ template \ template \ bool name##MatcherP6::gmock_Impl::MatchAndExplain(\ arg_type arg, \ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ const #define MATCHER_P7(name, p0, p1, p2, p3, p4, p5, p6, description)\ template \ class name##MatcherP7 {\ public:\ template \ class gmock_Impl : public ::testing::MatcherInterface {\ public:\ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ p6##_type gmock_p6)\ : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \ p4(gmock_p4), p5(gmock_p5), p6(gmock_p6) {}\ virtual bool MatchAndExplain(\ arg_type arg, ::testing::MatchResultListener* result_listener) const;\ virtual void DescribeTo(::std::ostream* gmock_os) const {\ *gmock_os << FormatDescription(false);\ }\ virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ *gmock_os << FormatDescription(true);\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ p4##_type p4;\ p5##_type p5;\ p6##_type p6;\ private:\ ::testing::internal::string FormatDescription(bool negation) const {\ const ::testing::internal::string gmock_description = (description);\ if (!gmock_description.empty())\ return gmock_description;\ return ::testing::internal::FormatMatcherDescription(\ negation, #name, \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ ::testing::tuple(p0, p1, p2, p3, p4, p5, \ p6)));\ }\ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template \ operator ::testing::Matcher() const {\ return ::testing::Matcher(\ new gmock_Impl(p0, p1, p2, p3, p4, p5, p6));\ }\ name##MatcherP7(p0##_type gmock_p0, p1##_type gmock_p1, \ p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ p5##_type gmock_p5, p6##_type gmock_p6) : p0(gmock_p0), p1(gmock_p1), \ p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), \ p6(gmock_p6) {\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ p4##_type p4;\ p5##_type p5;\ p6##_type p6;\ private:\ GTEST_DISALLOW_ASSIGN_(name##MatcherP7);\ };\ template \ inline name##MatcherP7 name(p0##_type p0, p1##_type p1, \ p2##_type p2, p3##_type p3, p4##_type p4, p5##_type p5, \ p6##_type p6) {\ return name##MatcherP7(p0, p1, p2, p3, p4, p5, p6);\ }\ template \ template \ bool name##MatcherP7::gmock_Impl::MatchAndExplain(\ arg_type arg, \ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ const #define MATCHER_P8(name, p0, p1, p2, p3, p4, p5, p6, p7, description)\ template \ class name##MatcherP8 {\ public:\ template \ class gmock_Impl : public ::testing::MatcherInterface {\ public:\ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ p6##_type gmock_p6, p7##_type gmock_p7)\ : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \ p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7) {}\ virtual bool MatchAndExplain(\ arg_type arg, ::testing::MatchResultListener* result_listener) const;\ virtual void DescribeTo(::std::ostream* gmock_os) const {\ *gmock_os << FormatDescription(false);\ }\ virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ *gmock_os << FormatDescription(true);\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ p4##_type p4;\ p5##_type p5;\ p6##_type p6;\ p7##_type p7;\ private:\ ::testing::internal::string FormatDescription(bool negation) const {\ const ::testing::internal::string gmock_description = (description);\ if (!gmock_description.empty())\ return gmock_description;\ return ::testing::internal::FormatMatcherDescription(\ negation, #name, \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ ::testing::tuple(p0, p1, p2, \ p3, p4, p5, p6, p7)));\ }\ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template \ operator ::testing::Matcher() const {\ return ::testing::Matcher(\ new gmock_Impl(p0, p1, p2, p3, p4, p5, p6, p7));\ }\ name##MatcherP8(p0##_type gmock_p0, p1##_type gmock_p1, \ p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ p5##_type gmock_p5, p6##_type gmock_p6, \ p7##_type gmock_p7) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ p7(gmock_p7) {\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ p4##_type p4;\ p5##_type p5;\ p6##_type p6;\ p7##_type p7;\ private:\ GTEST_DISALLOW_ASSIGN_(name##MatcherP8);\ };\ template \ inline name##MatcherP8 name(p0##_type p0, \ p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4, p5##_type p5, \ p6##_type p6, p7##_type p7) {\ return name##MatcherP8(p0, p1, p2, p3, p4, p5, \ p6, p7);\ }\ template \ template \ bool name##MatcherP8::gmock_Impl::MatchAndExplain(\ arg_type arg, \ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ const #define MATCHER_P9(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, description)\ template \ class name##MatcherP9 {\ public:\ template \ class gmock_Impl : public ::testing::MatcherInterface {\ public:\ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ p6##_type gmock_p6, p7##_type gmock_p7, p8##_type gmock_p8)\ : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \ p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \ p8(gmock_p8) {}\ virtual bool MatchAndExplain(\ arg_type arg, ::testing::MatchResultListener* result_listener) const;\ virtual void DescribeTo(::std::ostream* gmock_os) const {\ *gmock_os << FormatDescription(false);\ }\ virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ *gmock_os << FormatDescription(true);\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ p4##_type p4;\ p5##_type p5;\ p6##_type p6;\ p7##_type p7;\ p8##_type p8;\ private:\ ::testing::internal::string FormatDescription(bool negation) const {\ const ::testing::internal::string gmock_description = (description);\ if (!gmock_description.empty())\ return gmock_description;\ return ::testing::internal::FormatMatcherDescription(\ negation, #name, \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ ::testing::tuple(p0, p1, p2, p3, p4, p5, p6, p7, p8)));\ }\ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template \ operator ::testing::Matcher() const {\ return ::testing::Matcher(\ new gmock_Impl(p0, p1, p2, p3, p4, p5, p6, p7, p8));\ }\ name##MatcherP9(p0##_type gmock_p0, p1##_type gmock_p1, \ p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ p5##_type gmock_p5, p6##_type gmock_p6, p7##_type gmock_p7, \ p8##_type gmock_p8) : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), \ p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \ p8(gmock_p8) {\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ p4##_type p4;\ p5##_type p5;\ p6##_type p6;\ p7##_type p7;\ p8##_type p8;\ private:\ GTEST_DISALLOW_ASSIGN_(name##MatcherP9);\ };\ template \ inline name##MatcherP9 name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, \ p8##_type p8) {\ return name##MatcherP9(p0, p1, p2, \ p3, p4, p5, p6, p7, p8);\ }\ template \ template \ bool name##MatcherP9::gmock_Impl::MatchAndExplain(\ arg_type arg, \ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ const #define MATCHER_P10(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, description)\ template \ class name##MatcherP10 {\ public:\ template \ class gmock_Impl : public ::testing::MatcherInterface {\ public:\ gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \ p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \ p6##_type gmock_p6, p7##_type gmock_p7, p8##_type gmock_p8, \ p9##_type gmock_p9)\ : p0(gmock_p0), p1(gmock_p1), p2(gmock_p2), p3(gmock_p3), \ p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), p7(gmock_p7), \ p8(gmock_p8), p9(gmock_p9) {}\ virtual bool MatchAndExplain(\ arg_type arg, ::testing::MatchResultListener* result_listener) const;\ virtual void DescribeTo(::std::ostream* gmock_os) const {\ *gmock_os << FormatDescription(false);\ }\ virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ *gmock_os << FormatDescription(true);\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ p4##_type p4;\ p5##_type p5;\ p6##_type p6;\ p7##_type p7;\ p8##_type p8;\ p9##_type p9;\ private:\ ::testing::internal::string FormatDescription(bool negation) const {\ const ::testing::internal::string gmock_description = (description);\ if (!gmock_description.empty())\ return gmock_description;\ return ::testing::internal::FormatMatcherDescription(\ negation, #name, \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ ::testing::tuple(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)));\ }\ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template \ operator ::testing::Matcher() const {\ return ::testing::Matcher(\ new gmock_Impl(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9));\ }\ name##MatcherP10(p0##_type gmock_p0, p1##_type gmock_p1, \ p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \ p5##_type gmock_p5, p6##_type gmock_p6, p7##_type gmock_p7, \ p8##_type gmock_p8, p9##_type gmock_p9) : p0(gmock_p0), p1(gmock_p1), \ p2(gmock_p2), p3(gmock_p3), p4(gmock_p4), p5(gmock_p5), p6(gmock_p6), \ p7(gmock_p7), p8(gmock_p8), p9(gmock_p9) {\ }\ p0##_type p0;\ p1##_type p1;\ p2##_type p2;\ p3##_type p3;\ p4##_type p4;\ p5##_type p5;\ p6##_type p6;\ p7##_type p7;\ p8##_type p8;\ p9##_type p9;\ private:\ GTEST_DISALLOW_ASSIGN_(name##MatcherP10);\ };\ template \ inline name##MatcherP10 name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \ p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, p8##_type p8, \ p9##_type p9) {\ return name##MatcherP10(p0, \ p1, p2, p3, p4, p5, p6, p7, p8, p9);\ }\ template \ template \ bool name##MatcherP10::gmock_Impl::MatchAndExplain(\ arg_type arg, \ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ const #endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/include/gmock/gmock-generated-matchers.h.pump000066400000000000000000000523511455373415500333620ustar00rootroot00000000000000$$ -*- mode: c++; -*- $$ This is a Pump source file. Please use Pump to convert it to $$ gmock-generated-actions.h. $$ $var n = 10 $$ The maximum arity we support. $$ }} This line fixes auto-indentation of the following code in Emacs. // Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Google Mock - a framework for writing C++ mock classes. // // This file implements some commonly used variadic matchers. #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ #include #include #include #include #include "gmock/gmock-matchers.h" namespace testing { namespace internal { $range i 0..n-1 // The type of the i-th (0-based) field of Tuple. #define GMOCK_FIELD_TYPE_(Tuple, i) \ typename ::testing::tuple_element::type // TupleFields is for selecting fields from a // tuple of type Tuple. It has two members: // // type: a tuple type whose i-th field is the ki-th field of Tuple. // GetSelectedFields(t): returns fields k0, ..., and kn of t as a tuple. // // For example, in class TupleFields, 2, 0>, we have: // // type is tuple, and // GetSelectedFields(make_tuple(true, 'a', 42)) is (42, true). template class TupleFields; // This generic version is used when there are $n selectors. template class TupleFields { public: typedef ::testing::tuple<$for i, [[GMOCK_FIELD_TYPE_(Tuple, k$i)]]> type; static type GetSelectedFields(const Tuple& t) { return type($for i, [[get(t)]]); } }; // The following specialization is used for 0 ~ $(n-1) selectors. $for i [[ $$ }}} $range j 0..i-1 $range k 0..n-1 template class TupleFields { public: typedef ::testing::tuple<$for j, [[GMOCK_FIELD_TYPE_(Tuple, k$j)]]> type; static type GetSelectedFields(const Tuple& $if i==0 [[/* t */]] $else [[t]]) { return type($for j, [[get(t)]]); } }; ]] #undef GMOCK_FIELD_TYPE_ // Implements the Args() matcher. $var ks = [[$for i, [[k$i]]]] template class ArgsMatcherImpl : public MatcherInterface { public: // ArgsTuple may have top-level const or reference modifiers. typedef GTEST_REMOVE_REFERENCE_AND_CONST_(ArgsTuple) RawArgsTuple; typedef typename internal::TupleFields::type SelectedArgs; typedef Matcher MonomorphicInnerMatcher; template explicit ArgsMatcherImpl(const InnerMatcher& inner_matcher) : inner_matcher_(SafeMatcherCast(inner_matcher)) {} virtual bool MatchAndExplain(ArgsTuple args, MatchResultListener* listener) const { const SelectedArgs& selected_args = GetSelectedArgs(args); if (!listener->IsInterested()) return inner_matcher_.Matches(selected_args); PrintIndices(listener->stream()); *listener << "are " << PrintToString(selected_args); StringMatchResultListener inner_listener; const bool match = inner_matcher_.MatchAndExplain(selected_args, &inner_listener); PrintIfNotEmpty(inner_listener.str(), listener->stream()); return match; } virtual void DescribeTo(::std::ostream* os) const { *os << "are a tuple "; PrintIndices(os); inner_matcher_.DescribeTo(os); } virtual void DescribeNegationTo(::std::ostream* os) const { *os << "are a tuple "; PrintIndices(os); inner_matcher_.DescribeNegationTo(os); } private: static SelectedArgs GetSelectedArgs(ArgsTuple args) { return TupleFields::GetSelectedFields(args); } // Prints the indices of the selected fields. static void PrintIndices(::std::ostream* os) { *os << "whose fields ("; const int indices[$n] = { $ks }; for (int i = 0; i < $n; i++) { if (indices[i] < 0) break; if (i >= 1) *os << ", "; *os << "#" << indices[i]; } *os << ") "; } const MonomorphicInnerMatcher inner_matcher_; GTEST_DISALLOW_ASSIGN_(ArgsMatcherImpl); }; template class ArgsMatcher { public: explicit ArgsMatcher(const InnerMatcher& inner_matcher) : inner_matcher_(inner_matcher) {} template operator Matcher() const { return MakeMatcher(new ArgsMatcherImpl(inner_matcher_)); } private: const InnerMatcher inner_matcher_; GTEST_DISALLOW_ASSIGN_(ArgsMatcher); }; // A set of metafunctions for computing the result type of AllOf. // AllOf(m1, ..., mN) returns // AllOfResultN::type. // Although AllOf isn't defined for one argument, AllOfResult1 is defined // to simplify the implementation. template struct AllOfResult1 { typedef M1 type; }; $range i 1..n $range i 2..n $for i [[ $range j 2..i $var m = i/2 $range k 1..m $range t m+1..i template struct AllOfResult$i { typedef BothOfMatcher< typename AllOfResult$m<$for k, [[M$k]]>::type, typename AllOfResult$(i-m)<$for t, [[M$t]]>::type > type; }; ]] // A set of metafunctions for computing the result type of AnyOf. // AnyOf(m1, ..., mN) returns // AnyOfResultN::type. // Although AnyOf isn't defined for one argument, AnyOfResult1 is defined // to simplify the implementation. template struct AnyOfResult1 { typedef M1 type; }; $range i 1..n $range i 2..n $for i [[ $range j 2..i $var m = i/2 $range k 1..m $range t m+1..i template struct AnyOfResult$i { typedef EitherOfMatcher< typename AnyOfResult$m<$for k, [[M$k]]>::type, typename AnyOfResult$(i-m)<$for t, [[M$t]]>::type > type; }; ]] } // namespace internal // Args(a_matcher) matches a tuple if the selected // fields of it matches a_matcher. C++ doesn't support default // arguments for function templates, so we have to overload it. $range i 0..n $for i [[ $range j 1..i template <$for j [[int k$j, ]]typename InnerMatcher> inline internal::ArgsMatcher Args(const InnerMatcher& matcher) { return internal::ArgsMatcher(matcher); } ]] // ElementsAre(e_1, e_2, ... e_n) matches an STL-style container with // n elements, where the i-th element in the container must // match the i-th argument in the list. Each argument of // ElementsAre() can be either a value or a matcher. We support up to // $n arguments. // // The use of DecayArray in the implementation allows ElementsAre() // to accept string literals, whose type is const char[N], but we // want to treat them as const char*. // // NOTE: Since ElementsAre() cares about the order of the elements, it // must not be used with containers whose elements's order is // undefined (e.g. hash_map). $range i 0..n $for i [[ $range j 1..i $if i>0 [[ template <$for j, [[typename T$j]]> ]] inline internal::ElementsAreMatcher< ::testing::tuple< $for j, [[ typename internal::DecayArray::type]]> > ElementsAre($for j, [[const T$j& e$j]]) { typedef ::testing::tuple< $for j, [[ typename internal::DecayArray::type]]> Args; return internal::ElementsAreMatcher(Args($for j, [[e$j]])); } ]] // UnorderedElementsAre(e_1, e_2, ..., e_n) is an ElementsAre extension // that matches n elements in any order. We support up to n=$n arguments. $range i 0..n $for i [[ $range j 1..i $if i>0 [[ template <$for j, [[typename T$j]]> ]] inline internal::UnorderedElementsAreMatcher< ::testing::tuple< $for j, [[ typename internal::DecayArray::type]]> > UnorderedElementsAre($for j, [[const T$j& e$j]]) { typedef ::testing::tuple< $for j, [[ typename internal::DecayArray::type]]> Args; return internal::UnorderedElementsAreMatcher(Args($for j, [[e$j]])); } ]] // AllOf(m1, m2, ..., mk) matches any value that matches all of the given // sub-matchers. AllOf is called fully qualified to prevent ADL from firing. $range i 2..n $for i [[ $range j 1..i $var m = i/2 $range k 1..m $range t m+1..i template <$for j, [[typename M$j]]> inline typename internal::AllOfResult$i<$for j, [[M$j]]>::type AllOf($for j, [[M$j m$j]]) { return typename internal::AllOfResult$i<$for j, [[M$j]]>::type( $if m == 1 [[m1]] $else [[::testing::AllOf($for k, [[m$k]])]], $if m+1 == i [[m$i]] $else [[::testing::AllOf($for t, [[m$t]])]]); } ]] // AnyOf(m1, m2, ..., mk) matches any value that matches any of the given // sub-matchers. AnyOf is called fully qualified to prevent ADL from firing. $range i 2..n $for i [[ $range j 1..i $var m = i/2 $range k 1..m $range t m+1..i template <$for j, [[typename M$j]]> inline typename internal::AnyOfResult$i<$for j, [[M$j]]>::type AnyOf($for j, [[M$j m$j]]) { return typename internal::AnyOfResult$i<$for j, [[M$j]]>::type( $if m == 1 [[m1]] $else [[::testing::AnyOf($for k, [[m$k]])]], $if m+1 == i [[m$i]] $else [[::testing::AnyOf($for t, [[m$t]])]]); } ]] } // namespace testing $$ } // This Pump meta comment fixes auto-indentation in Emacs. It will not $$ // show up in the generated code. // The MATCHER* family of macros can be used in a namespace scope to // define custom matchers easily. // // Basic Usage // =========== // // The syntax // // MATCHER(name, description_string) { statements; } // // defines a matcher with the given name that executes the statements, // which must return a bool to indicate if the match succeeds. Inside // the statements, you can refer to the value being matched by 'arg', // and refer to its type by 'arg_type'. // // The description string documents what the matcher does, and is used // to generate the failure message when the match fails. Since a // MATCHER() is usually defined in a header file shared by multiple // C++ source files, we require the description to be a C-string // literal to avoid possible side effects. It can be empty, in which // case we'll use the sequence of words in the matcher name as the // description. // // For example: // // MATCHER(IsEven, "") { return (arg % 2) == 0; } // // allows you to write // // // Expects mock_foo.Bar(n) to be called where n is even. // EXPECT_CALL(mock_foo, Bar(IsEven())); // // or, // // // Verifies that the value of some_expression is even. // EXPECT_THAT(some_expression, IsEven()); // // If the above assertion fails, it will print something like: // // Value of: some_expression // Expected: is even // Actual: 7 // // where the description "is even" is automatically calculated from the // matcher name IsEven. // // Argument Type // ============= // // Note that the type of the value being matched (arg_type) is // determined by the context in which you use the matcher and is // supplied to you by the compiler, so you don't need to worry about // declaring it (nor can you). This allows the matcher to be // polymorphic. For example, IsEven() can be used to match any type // where the value of "(arg % 2) == 0" can be implicitly converted to // a bool. In the "Bar(IsEven())" example above, if method Bar() // takes an int, 'arg_type' will be int; if it takes an unsigned long, // 'arg_type' will be unsigned long; and so on. // // Parameterizing Matchers // ======================= // // Sometimes you'll want to parameterize the matcher. For that you // can use another macro: // // MATCHER_P(name, param_name, description_string) { statements; } // // For example: // // MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; } // // will allow you to write: // // EXPECT_THAT(Blah("a"), HasAbsoluteValue(n)); // // which may lead to this message (assuming n is 10): // // Value of: Blah("a") // Expected: has absolute value 10 // Actual: -9 // // Note that both the matcher description and its parameter are // printed, making the message human-friendly. // // In the matcher definition body, you can write 'foo_type' to // reference the type of a parameter named 'foo'. For example, in the // body of MATCHER_P(HasAbsoluteValue, value) above, you can write // 'value_type' to refer to the type of 'value'. // // We also provide MATCHER_P2, MATCHER_P3, ..., up to MATCHER_P$n to // support multi-parameter matchers. // // Describing Parameterized Matchers // ================================= // // The last argument to MATCHER*() is a string-typed expression. The // expression can reference all of the matcher's parameters and a // special bool-typed variable named 'negation'. When 'negation' is // false, the expression should evaluate to the matcher's description; // otherwise it should evaluate to the description of the negation of // the matcher. For example, // // using testing::PrintToString; // // MATCHER_P2(InClosedRange, low, hi, // string(negation ? "is not" : "is") + " in range [" + // PrintToString(low) + ", " + PrintToString(hi) + "]") { // return low <= arg && arg <= hi; // } // ... // EXPECT_THAT(3, InClosedRange(4, 6)); // EXPECT_THAT(3, Not(InClosedRange(2, 4))); // // would generate two failures that contain the text: // // Expected: is in range [4, 6] // ... // Expected: is not in range [2, 4] // // If you specify "" as the description, the failure message will // contain the sequence of words in the matcher name followed by the // parameter values printed as a tuple. For example, // // MATCHER_P2(InClosedRange, low, hi, "") { ... } // ... // EXPECT_THAT(3, InClosedRange(4, 6)); // EXPECT_THAT(3, Not(InClosedRange(2, 4))); // // would generate two failures that contain the text: // // Expected: in closed range (4, 6) // ... // Expected: not (in closed range (2, 4)) // // Types of Matcher Parameters // =========================== // // For the purpose of typing, you can view // // MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... } // // as shorthand for // // template // FooMatcherPk // Foo(p1_type p1, ..., pk_type pk) { ... } // // When you write Foo(v1, ..., vk), the compiler infers the types of // the parameters v1, ..., and vk for you. If you are not happy with // the result of the type inference, you can specify the types by // explicitly instantiating the template, as in Foo(5, // false). As said earlier, you don't get to (or need to) specify // 'arg_type' as that's determined by the context in which the matcher // is used. You can assign the result of expression Foo(p1, ..., pk) // to a variable of type FooMatcherPk. This // can be useful when composing matchers. // // While you can instantiate a matcher template with reference types, // passing the parameters by pointer usually makes your code more // readable. If, however, you still want to pass a parameter by // reference, be aware that in the failure message generated by the // matcher you will see the value of the referenced object but not its // address. // // Explaining Match Results // ======================== // // Sometimes the matcher description alone isn't enough to explain why // the match has failed or succeeded. For example, when expecting a // long string, it can be very helpful to also print the diff between // the expected string and the actual one. To achieve that, you can // optionally stream additional information to a special variable // named result_listener, whose type is a pointer to class // MatchResultListener: // // MATCHER_P(EqualsLongString, str, "") { // if (arg == str) return true; // // *result_listener << "the difference: " /// << DiffStrings(str, arg); // return false; // } // // Overloading Matchers // ==================== // // You can overload matchers with different numbers of parameters: // // MATCHER_P(Blah, a, description_string1) { ... } // MATCHER_P2(Blah, a, b, description_string2) { ... } // // Caveats // ======= // // When defining a new matcher, you should also consider implementing // MatcherInterface or using MakePolymorphicMatcher(). These // approaches require more work than the MATCHER* macros, but also // give you more control on the types of the value being matched and // the matcher parameters, which may leads to better compiler error // messages when the matcher is used wrong. They also allow // overloading matchers based on parameter types (as opposed to just // based on the number of parameters). // // MATCHER*() can only be used in a namespace scope. The reason is // that C++ doesn't yet allow function-local types to be used to // instantiate templates. The up-coming C++0x standard will fix this. // Once that's done, we'll consider supporting using MATCHER*() inside // a function. // // More Information // ================ // // To learn more about using these macros, please search for 'MATCHER' // on http://code.google.com/p/googlemock/wiki/CookBook. $range i 0..n $for i [[ $var macro_name = [[$if i==0 [[MATCHER]] $elif i==1 [[MATCHER_P]] $else [[MATCHER_P$i]]]] $var class_name = [[name##Matcher[[$if i==0 [[]] $elif i==1 [[P]] $else [[P$i]]]]]] $range j 0..i-1 $var template = [[$if i==0 [[]] $else [[ template <$for j, [[typename p$j##_type]]>\ ]]]] $var ctor_param_list = [[$for j, [[p$j##_type gmock_p$j]]]] $var impl_ctor_param_list = [[$for j, [[p$j##_type gmock_p$j]]]] $var impl_inits = [[$if i==0 [[]] $else [[ : $for j, [[p$j(gmock_p$j)]]]]]] $var inits = [[$if i==0 [[]] $else [[ : $for j, [[p$j(gmock_p$j)]]]]]] $var params = [[$for j, [[p$j]]]] $var param_types = [[$if i==0 [[]] $else [[<$for j, [[p$j##_type]]>]]]] $var param_types_and_names = [[$for j, [[p$j##_type p$j]]]] $var param_field_decls = [[$for j [[ p$j##_type p$j;\ ]]]] $var param_field_decls2 = [[$for j [[ p$j##_type p$j;\ ]]]] #define $macro_name(name$for j [[, p$j]], description)\$template class $class_name {\ public:\ template \ class gmock_Impl : public ::testing::MatcherInterface {\ public:\ [[$if i==1 [[explicit ]]]]gmock_Impl($impl_ctor_param_list)\ $impl_inits {}\ virtual bool MatchAndExplain(\ arg_type arg, ::testing::MatchResultListener* result_listener) const;\ virtual void DescribeTo(::std::ostream* gmock_os) const {\ *gmock_os << FormatDescription(false);\ }\ virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\ *gmock_os << FormatDescription(true);\ }\$param_field_decls private:\ ::testing::internal::string FormatDescription(bool negation) const {\ const ::testing::internal::string gmock_description = (description);\ if (!gmock_description.empty())\ return gmock_description;\ return ::testing::internal::FormatMatcherDescription(\ negation, #name, \ ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\ ::testing::tuple<$for j, [[p$j##_type]]>($for j, [[p$j]])));\ }\ GTEST_DISALLOW_ASSIGN_(gmock_Impl);\ };\ template \ operator ::testing::Matcher() const {\ return ::testing::Matcher(\ new gmock_Impl($params));\ }\ [[$if i==1 [[explicit ]]]]$class_name($ctor_param_list)$inits {\ }\$param_field_decls2 private:\ GTEST_DISALLOW_ASSIGN_($class_name);\ };\$template inline $class_name$param_types name($param_types_and_names) {\ return $class_name$param_types($params);\ }\$template template \ bool $class_name$param_types::gmock_Impl::MatchAndExplain(\ arg_type arg, \ ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\ const ]] #endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_ nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/include/gmock/gmock-generated-nice-strict.h000066400000000000000000000374701455373415500330250ustar00rootroot00000000000000// This file was GENERATED by command: // pump.py gmock-generated-nice-strict.h.pump // DO NOT EDIT BY HAND!!! // Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // Implements class templates NiceMock, NaggyMock, and StrictMock. // // Given a mock class MockFoo that is created using Google Mock, // NiceMock is a subclass of MockFoo that allows // uninteresting calls (i.e. calls to mock methods that have no // EXPECT_CALL specs), NaggyMock is a subclass of MockFoo // that prints a warning when an uninteresting call occurs, and // StrictMock is a subclass of MockFoo that treats all // uninteresting calls as errors. // // Currently a mock is naggy by default, so MockFoo and // NaggyMock behave like the same. However, we will soon // switch the default behavior of mocks to be nice, as that in general // leads to more maintainable tests. When that happens, MockFoo will // stop behaving like NaggyMock and start behaving like // NiceMock. // // NiceMock, NaggyMock, and StrictMock "inherit" the constructors of // their respective base class, with up-to 10 arguments. Therefore // you can write NiceMock(5, "a") to construct a nice mock // where MockFoo has a constructor that accepts (int, const char*), // for example. // // A known limitation is that NiceMock, NaggyMock, // and StrictMock only works for mock methods defined using // the MOCK_METHOD* family of macros DIRECTLY in the MockFoo class. // If a mock method is defined in a base class of MockFoo, the "nice" // or "strict" modifier may not affect it, depending on the compiler. // In particular, nesting NiceMock, NaggyMock, and StrictMock is NOT // supported. // // Another known limitation is that the constructors of the base mock // cannot have arguments passed by non-const reference, which are // banned by the Google C++ style guide anyway. #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_ #include "gmock/gmock-spec-builders.h" #include "gmock/internal/gmock-port.h" namespace testing { template class NiceMock : public MockClass { public: // We don't factor out the constructor body to a common method, as // we have to avoid a possible clash with members of MockClass. NiceMock() { ::testing::Mock::AllowUninterestingCalls( internal::ImplicitCast_(this)); } // C++ doesn't (yet) allow inheritance of constructors, so we have // to define it for each arity. template explicit NiceMock(const A1& a1) : MockClass(a1) { ::testing::Mock::AllowUninterestingCalls( internal::ImplicitCast_(this)); } template NiceMock(const A1& a1, const A2& a2) : MockClass(a1, a2) { ::testing::Mock::AllowUninterestingCalls( internal::ImplicitCast_(this)); } template NiceMock(const A1& a1, const A2& a2, const A3& a3) : MockClass(a1, a2, a3) { ::testing::Mock::AllowUninterestingCalls( internal::ImplicitCast_(this)); } template NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4) : MockClass(a1, a2, a3, a4) { ::testing::Mock::AllowUninterestingCalls( internal::ImplicitCast_(this)); } template NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) : MockClass(a1, a2, a3, a4, a5) { ::testing::Mock::AllowUninterestingCalls( internal::ImplicitCast_(this)); } template NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6) : MockClass(a1, a2, a3, a4, a5, a6) { ::testing::Mock::AllowUninterestingCalls( internal::ImplicitCast_(this)); } template NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7) : MockClass(a1, a2, a3, a4, a5, a6, a7) { ::testing::Mock::AllowUninterestingCalls( internal::ImplicitCast_(this)); } template NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8) { ::testing::Mock::AllowUninterestingCalls( internal::ImplicitCast_(this)); } template NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9) { ::testing::Mock::AllowUninterestingCalls( internal::ImplicitCast_(this)); } template NiceMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, const A10& a10) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) { ::testing::Mock::AllowUninterestingCalls( internal::ImplicitCast_(this)); } virtual ~NiceMock() { ::testing::Mock::UnregisterCallReaction( internal::ImplicitCast_(this)); } private: GTEST_DISALLOW_COPY_AND_ASSIGN_(NiceMock); }; template class NaggyMock : public MockClass { public: // We don't factor out the constructor body to a common method, as // we have to avoid a possible clash with members of MockClass. NaggyMock() { ::testing::Mock::WarnUninterestingCalls( internal::ImplicitCast_(this)); } // C++ doesn't (yet) allow inheritance of constructors, so we have // to define it for each arity. template explicit NaggyMock(const A1& a1) : MockClass(a1) { ::testing::Mock::WarnUninterestingCalls( internal::ImplicitCast_(this)); } template NaggyMock(const A1& a1, const A2& a2) : MockClass(a1, a2) { ::testing::Mock::WarnUninterestingCalls( internal::ImplicitCast_(this)); } template NaggyMock(const A1& a1, const A2& a2, const A3& a3) : MockClass(a1, a2, a3) { ::testing::Mock::WarnUninterestingCalls( internal::ImplicitCast_(this)); } template NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4) : MockClass(a1, a2, a3, a4) { ::testing::Mock::WarnUninterestingCalls( internal::ImplicitCast_(this)); } template NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) : MockClass(a1, a2, a3, a4, a5) { ::testing::Mock::WarnUninterestingCalls( internal::ImplicitCast_(this)); } template NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6) : MockClass(a1, a2, a3, a4, a5, a6) { ::testing::Mock::WarnUninterestingCalls( internal::ImplicitCast_(this)); } template NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7) : MockClass(a1, a2, a3, a4, a5, a6, a7) { ::testing::Mock::WarnUninterestingCalls( internal::ImplicitCast_(this)); } template NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8) { ::testing::Mock::WarnUninterestingCalls( internal::ImplicitCast_(this)); } template NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9) { ::testing::Mock::WarnUninterestingCalls( internal::ImplicitCast_(this)); } template NaggyMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, const A10& a10) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) { ::testing::Mock::WarnUninterestingCalls( internal::ImplicitCast_(this)); } virtual ~NaggyMock() { ::testing::Mock::UnregisterCallReaction( internal::ImplicitCast_(this)); } private: GTEST_DISALLOW_COPY_AND_ASSIGN_(NaggyMock); }; template class StrictMock : public MockClass { public: // We don't factor out the constructor body to a common method, as // we have to avoid a possible clash with members of MockClass. StrictMock() { ::testing::Mock::FailUninterestingCalls( internal::ImplicitCast_(this)); } // C++ doesn't (yet) allow inheritance of constructors, so we have // to define it for each arity. template explicit StrictMock(const A1& a1) : MockClass(a1) { ::testing::Mock::FailUninterestingCalls( internal::ImplicitCast_(this)); } template StrictMock(const A1& a1, const A2& a2) : MockClass(a1, a2) { ::testing::Mock::FailUninterestingCalls( internal::ImplicitCast_(this)); } template StrictMock(const A1& a1, const A2& a2, const A3& a3) : MockClass(a1, a2, a3) { ::testing::Mock::FailUninterestingCalls( internal::ImplicitCast_(this)); } template StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4) : MockClass(a1, a2, a3, a4) { ::testing::Mock::FailUninterestingCalls( internal::ImplicitCast_(this)); } template StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) : MockClass(a1, a2, a3, a4, a5) { ::testing::Mock::FailUninterestingCalls( internal::ImplicitCast_(this)); } template StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6) : MockClass(a1, a2, a3, a4, a5, a6) { ::testing::Mock::FailUninterestingCalls( internal::ImplicitCast_(this)); } template StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7) : MockClass(a1, a2, a3, a4, a5, a6, a7) { ::testing::Mock::FailUninterestingCalls( internal::ImplicitCast_(this)); } template StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8) { ::testing::Mock::FailUninterestingCalls( internal::ImplicitCast_(this)); } template StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9) { ::testing::Mock::FailUninterestingCalls( internal::ImplicitCast_(this)); } template StrictMock(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, const A10& a10) : MockClass(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) { ::testing::Mock::FailUninterestingCalls( internal::ImplicitCast_(this)); } virtual ~StrictMock() { ::testing::Mock::UnregisterCallReaction( internal::ImplicitCast_(this)); } private: GTEST_DISALLOW_COPY_AND_ASSIGN_(StrictMock); }; // The following specializations catch some (relatively more common) // user errors of nesting nice and strict mocks. They do NOT catch // all possible errors. // These specializations are declared but not defined, as NiceMock, // NaggyMock, and StrictMock cannot be nested. template class NiceMock >; template class NiceMock >; template class NiceMock >; template class NaggyMock >; template class NaggyMock >; template class NaggyMock >; template class StrictMock >; template class StrictMock >; template class StrictMock >; } // namespace testing #endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_ nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/include/gmock/gmock-generated-nice-strict.h.pump000066400000000000000000000136221455373415500337760ustar00rootroot00000000000000$$ -*- mode: c++; -*- $$ This is a Pump source file. Please use Pump to convert it to $$ gmock-generated-nice-strict.h. $$ $var n = 10 $$ The maximum arity we support. // Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // Implements class templates NiceMock, NaggyMock, and StrictMock. // // Given a mock class MockFoo that is created using Google Mock, // NiceMock is a subclass of MockFoo that allows // uninteresting calls (i.e. calls to mock methods that have no // EXPECT_CALL specs), NaggyMock is a subclass of MockFoo // that prints a warning when an uninteresting call occurs, and // StrictMock is a subclass of MockFoo that treats all // uninteresting calls as errors. // // Currently a mock is naggy by default, so MockFoo and // NaggyMock behave like the same. However, we will soon // switch the default behavior of mocks to be nice, as that in general // leads to more maintainable tests. When that happens, MockFoo will // stop behaving like NaggyMock and start behaving like // NiceMock. // // NiceMock, NaggyMock, and StrictMock "inherit" the constructors of // their respective base class, with up-to $n arguments. Therefore // you can write NiceMock(5, "a") to construct a nice mock // where MockFoo has a constructor that accepts (int, const char*), // for example. // // A known limitation is that NiceMock, NaggyMock, // and StrictMock only works for mock methods defined using // the MOCK_METHOD* family of macros DIRECTLY in the MockFoo class. // If a mock method is defined in a base class of MockFoo, the "nice" // or "strict" modifier may not affect it, depending on the compiler. // In particular, nesting NiceMock, NaggyMock, and StrictMock is NOT // supported. // // Another known limitation is that the constructors of the base mock // cannot have arguments passed by non-const reference, which are // banned by the Google C++ style guide anyway. #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_ #include "gmock/gmock-spec-builders.h" #include "gmock/internal/gmock-port.h" namespace testing { $range kind 0..2 $for kind [[ $var clazz=[[$if kind==0 [[NiceMock]] $elif kind==1 [[NaggyMock]] $else [[StrictMock]]]] $var method=[[$if kind==0 [[AllowUninterestingCalls]] $elif kind==1 [[WarnUninterestingCalls]] $else [[FailUninterestingCalls]]]] template class $clazz : public MockClass { public: // We don't factor out the constructor body to a common method, as // we have to avoid a possible clash with members of MockClass. $clazz() { ::testing::Mock::$method( internal::ImplicitCast_(this)); } // C++ doesn't (yet) allow inheritance of constructors, so we have // to define it for each arity. template explicit $clazz(const A1& a1) : MockClass(a1) { ::testing::Mock::$method( internal::ImplicitCast_(this)); } $range i 2..n $for i [[ $range j 1..i template <$for j, [[typename A$j]]> $clazz($for j, [[const A$j& a$j]]) : MockClass($for j, [[a$j]]) { ::testing::Mock::$method( internal::ImplicitCast_(this)); } ]] virtual ~$clazz() { ::testing::Mock::UnregisterCallReaction( internal::ImplicitCast_(this)); } private: GTEST_DISALLOW_COPY_AND_ASSIGN_($clazz); }; ]] // The following specializations catch some (relatively more common) // user errors of nesting nice and strict mocks. They do NOT catch // all possible errors. // These specializations are declared but not defined, as NiceMock, // NaggyMock, and StrictMock cannot be nested. template class NiceMock >; template class NiceMock >; template class NiceMock >; template class NaggyMock >; template class NaggyMock >; template class NaggyMock >; template class StrictMock >; template class StrictMock >; template class StrictMock >; } // namespace testing #endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_NICE_STRICT_H_ nextpnr-nextpnr-0.7/3rdparty/googletest/googlemock/include/gmock/gmock-matchers.h000066400000000000000000004672571455373415500304650ustar00rootroot00000000000000// Copyright 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // Google Mock - a framework for writing C++ mock classes. // // This file implements some commonly used argument matchers. More // matchers can be defined by the user implementing the // MatcherInterface interface if necessary. #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_ #include #include #include #include #include // NOLINT #include #include #include #include #include "gmock/internal/gmock-internal-utils.h" #include "gmock/internal/gmock-port.h" #include "gtest/gtest.h" #if GTEST_HAS_STD_INITIALIZER_LIST_ # include // NOLINT -- must be after gtest.h #endif namespace testing { // To implement a matcher Foo for type T, define: // 1. a class FooMatcherImpl that implements the // MatcherInterface interface, and // 2. a factory function that creates a Matcher object from a // FooMatcherImpl*. // // The two-level delegation design makes it possible to allow a user // to write "v" instead of "Eq(v)" where a Matcher is expected, which // is impossible if we pass matchers by pointers. It also eases // ownership management as Matcher objects can now be copied like // plain values. // MatchResultListener is an abstract class. Its << operator can be // used by a matcher to explain why a value matches or doesn't match. // // TODO(wan@google.com): add method // bool InterestedInWhy(bool result) const; // to indicate whether the listener is interested in why the match // result is 'result'. class MatchResultListener { public: // Creates a listener object with the given underlying ostream. The // listener does not own the ostream, and does not dereference it // in the constructor or destructor. explicit MatchResultListener(::std::ostream* os) : stream_(os) {} virtual ~MatchResultListener() = 0; // Makes this class abstract. // Streams x to the underlying ostream; does nothing if the ostream // is NULL. template MatchResultListener& operator<<(const T& x) { if (stream_ != NULL) *stream_ << x; return *this; } // Returns the underlying ostream. ::std::ostream* stream() { return stream_; } // Returns true iff the listener is interested in an explanation of // the match result. A matcher's MatchAndExplain() method can use // this information to avoid generating the explanation when no one // intends to hear it. bool IsInterested() const { return stream_ != NULL; } private: ::std::ostream* const stream_; GTEST_DISALLOW_COPY_AND_ASSIGN_(MatchResultListener); }; inline MatchResultListener::~MatchResultListener() { } // An instance of a subclass of this knows how to describe itself as a // matcher. class MatcherDescriberInterface { public: virtual ~MatcherDescriberInterface() {} // Describes this matcher to an ostream. The function should print // a verb phrase that describes the property a value matching this // matcher should have. The subject of the verb phrase is the value // being matched. For example, the DescribeTo() method of the Gt(7) // matcher prints "is greater than 7". virtual void DescribeTo(::std::ostream* os) const = 0; // Describes the negation of this matcher to an ostream. For // example, if the description of this matcher is "is greater than // 7", the negated description could be "is not greater than 7". // You are not required to override this when implementing // MatcherInterface, but it is highly advised so that your matcher // can produce good error messages. virtual void DescribeNegationTo(::std::ostream* os) const { *os << "not ("; DescribeTo(os); *os << ")"; } }; // The implementation of a matcher. template class MatcherInterface : public MatcherDescriberInterface { public: // Returns true iff the matcher matches x; also explains the match // result to 'listener' if necessary (see the next paragraph), in // the form of a non-restrictive relative clause ("which ...", // "whose ...", etc) that describes x. For example, the // MatchAndExplain() method of the Pointee(...) matcher should // generate an explanation like "which points to ...". // // Implementations of MatchAndExplain() should add an explanation of // the match result *if and only if* they can provide additional // information that's not already present (or not obvious) in the // print-out of x and the matcher's description. Whether the match // succeeds is not a factor in deciding whether an explanation is // needed, as sometimes the caller needs to print a failure message // when the match succeeds (e.g. when the matcher is used inside // Not()). // // For example, a "has at least 10 elements" matcher should explain // what the actual element count is, regardless of the match result, // as it is useful information to the reader; on the other hand, an // "is empty" matcher probably only needs to explain what the actual // size is when the match fails, as it's redundant to say that the // size is 0 when the value is already known to be empty. // // You should override this method when defining a new matcher. // // It's the responsibility of the caller (Google Mock) to guarantee // that 'listener' is not NULL. This helps to simplify a matcher's // implementation when it doesn't care about the performance, as it // can talk to 'listener' without checking its validity first. // However, in order to implement dummy listeners efficiently, // listener->stream() may be NULL. virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0; // Inherits these methods from MatcherDescriberInterface: // virtual void DescribeTo(::std::ostream* os) const = 0; // virtual void DescribeNegationTo(::std::ostream* os) const; }; // A match result listener that stores the explanation in a string. class StringMatchResultListener : public MatchResultListener { public: StringMatchResultListener() : MatchResultListener(&ss_) {} // Returns the explanation accumulated so far. internal::string str() const { return ss_.str(); } // Clears the explanation accumulated so far. void Clear() { ss_.str(""); } private: ::std::stringstream ss_; GTEST_DISALLOW_COPY_AND_ASSIGN_(StringMatchResultListener); }; namespace internal { struct AnyEq { template bool operator()(const A& a, const B& b) const { return a == b; } }; struct AnyNe { template bool operator()(const A& a, const B& b) const { return a != b; } }; struct AnyLt { template bool operator()(const A& a, const B& b) const { return a < b; } }; struct AnyGt { template bool operator()(const A& a, const B& b) const { return a > b; } }; struct AnyLe { template bool operator()(const A& a, const B& b) const { return a <= b; } }; struct AnyGe { template bool operator()(const A& a, const B& b) const { return a >= b; } }; // A match result listener that ignores the explanation. class DummyMatchResultListener : public MatchResultListener { public: DummyMatchResultListener() : MatchResultListener(NULL) {} private: GTEST_DISALLOW_COPY_AND_ASSIGN_(DummyMatchResultListener); }; // A match result listener that forwards the explanation to a given // ostream. The difference between this and MatchResultListener is // that the former is concrete. class StreamMatchResultListener : public MatchResultListener { public: explicit StreamMatchResultListener(::std::ostream* os) : MatchResultListener(os) {} private: GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamMatchResultListener); }; // An internal class for implementing Matcher, which will derive // from it. We put functionalities common to all Matcher // specializations here to avoid code duplication. template class MatcherBase { public: // Returns true iff the matcher matches x; also explains the match // result to 'listener'. bool MatchAndExplain(T x, MatchResultListener* listener) const { return impl_->MatchAndExplain(x, listener); } // Returns true iff this matcher matches x. bool Matches(T x) const { DummyMatchResultListener dummy; return MatchAndExplain(x, &dummy); } // Describes this matcher to an ostream. void DescribeTo(::std::ostream* os) const { impl_->DescribeTo(os); } // Describes the negation of this matcher to an ostream. void DescribeNegationTo(::std::ostream* os) const { impl_->DescribeNegationTo(os); } // Explains why x matches, or doesn't match, the matcher. void ExplainMatchResultTo(T x, ::std::ostream* os) const { StreamMatchResultListener listener(os); MatchAndExplain(x, &listener); } // Returns the describer for this matcher object; retains ownership // of the describer, which is only guaranteed to be alive when // this matcher object is alive. const MatcherDescriberInterface* GetDescriber() const { return impl_.get(); } protected: MatcherBase() {} // Constructs a matcher from its implementation. explicit MatcherBase(const MatcherInterface* impl) : impl_(impl) {} virtual ~MatcherBase() {} private: // shared_ptr (util/gtl/shared_ptr.h) and linked_ptr have similar // interfaces. The former dynamically allocates a chunk of memory // to hold the reference count, while the latter tracks all // references using a circular linked list without allocating // memory. It has been observed that linked_ptr performs better in // typical scenarios. However, shared_ptr can out-perform // linked_ptr when there are many more uses of the copy constructor // than the default constructor. // // If performance becomes a problem, we should see if using // shared_ptr helps. ::testing::internal::linked_ptr > impl_; }; } // namespace internal // A Matcher is a copyable and IMMUTABLE (except by assignment) // object that can check whether a value of type T matches. The // implementation of Matcher is just a linked_ptr to const // MatcherInterface, so copying is fairly cheap. Don't inherit // from Matcher! template class Matcher : public internal::MatcherBase { public: // Constructs a null matcher. Needed for storing Matcher objects in STL // containers. A default-constructed matcher is not yet initialized. You // cannot use it until a valid value has been assigned to it. explicit Matcher() {} // NOLINT // Constructs a matcher from its implementation. explicit Matcher(const MatcherInterface* impl) : internal::MatcherBase(impl) {} // Implicit constructor here allows people to write // EXPECT_CALL(foo, Bar(5)) instead of EXPECT_CALL(foo, Bar(Eq(5))) sometimes Matcher(T value); // NOLINT }; // The following two specializations allow the user to write str // instead of Eq(str) and "foo" instead of Eq("foo") when a string // matcher is expected. template <> class GTEST_API_ Matcher : public internal::MatcherBase { public: Matcher() {} explicit Matcher(const MatcherInterface* impl) : internal::MatcherBase(impl) {} // Allows the user to write str instead of Eq(str) sometimes, where // str is a string object. Matcher(const internal::string& s); // NOLINT // Allows the user to write "foo" instead of Eq("foo") sometimes. Matcher(const char* s); // NOLINT }; template <> class GTEST_API_ Matcher : public internal::MatcherBase { public: Matcher() {} explicit Matcher(const MatcherInterface* impl) : internal::MatcherBase(impl) {} // Allows the user to write str instead of Eq(str) sometimes, where // str is a string object. Matcher(const internal::string& s); // NOLINT // Allows the user to write "foo" instead of Eq("foo") sometimes. Matcher(const char* s); // NOLINT }; #if GTEST_HAS_STRING_PIECE_ // The following two specializations allow the user to write str // instead of Eq(str) and "foo" instead of Eq("foo") when a StringPiece // matcher is expected. template <> class GTEST_API_ Matcher : public internal::MatcherBase { public: Matcher() {} explicit Matcher(const MatcherInterface* impl) : internal::MatcherBase(impl) {} // Allows the user to write str instead of Eq(str) sometimes, where // str is a string object. Matcher(const internal::string& s); // NOLINT // Allows the user to write "foo" instead of Eq("foo") sometimes. Matcher(const char* s); // NOLINT // Allows the user to pass StringPieces directly. Matcher(StringPiece s); // NOLINT }; template <> class GTEST_API_ Matcher : public internal::MatcherBase { public: Matcher() {} explicit Matcher(const MatcherInterface* impl) : internal::MatcherBase(impl) {} // Allows the user to write str instead of Eq(str) sometimes, where // str is a string object. Matcher(const internal::string& s); // NOLINT // Allows the user to write "foo" instead of Eq("foo") sometimes. Matcher(const char* s); // NOLINT // Allows the user to pass StringPieces directly. Matcher(StringPiece s); // NOLINT }; #endif // GTEST_HAS_STRING_PIECE_ // The PolymorphicMatcher class template makes it easy to implement a // polymorphic matcher (i.e. a matcher that can match values of more // than one type, e.g. Eq(n) and NotNull()). // // To define a polymorphic matcher, a user should provide an Impl // class that has a DescribeTo() method and a DescribeNegationTo() // method, and define a member function (or member function template) // // bool MatchAndExplain(const Value& value, // MatchResultListener* listener) const; // // See the definition of NotNull() for a complete example. template class PolymorphicMatcher { public: explicit PolymorphicMatcher(const Impl& an_impl) : impl_(an_impl) {} // Returns a mutable reference to the underlying matcher // implementation object. Impl& mutable_impl() { return impl_; } // Returns an immutable reference to the underlying matcher // implementation object. const Impl& impl() const { return impl_; } template operator Matcher() const { return Matcher(new MonomorphicImpl(impl_)); } private: template class MonomorphicImpl : public MatcherInterface { public: explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {} virtual void DescribeTo(::std::ostream* os) const { impl_.DescribeTo(os); } virtual void DescribeNegationTo(::std::ostream* os) const { impl_.DescribeNegationTo(os); } virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { return impl_.MatchAndExplain(x, listener); } private: const Impl impl_; GTEST_DISALLOW_ASSIGN_(MonomorphicImpl); }; Impl impl_; GTEST_DISALLOW_ASSIGN_(PolymorphicMatcher); }; // Creates a matcher from its implementation. This is easier to use // than the Matcher constructor as it doesn't require you to // explicitly write the template argument, e.g. // // MakeMatcher(foo); // vs // Matcher(foo); template inline Matcher MakeMatcher(const MatcherInterface* impl) { return Matcher(impl); } // Creates a polymorphic matcher from its implementation. This is // easier to use than the PolymorphicMatcher constructor as it // doesn't require you to explicitly write the template argument, e.g. // // MakePolymorphicMatcher(foo); // vs // PolymorphicMatcher(foo); template inline PolymorphicMatcher MakePolymorphicMatcher(const Impl& impl) { return PolymorphicMatcher(impl); } // Anything inside the 'internal' namespace IS INTERNAL IMPLEMENTATION // and MUST NOT BE USED IN USER CODE!!! namespace internal { // The MatcherCastImpl class template is a helper for implementing // MatcherCast(). We need this helper in order to partially // specialize the implementation of MatcherCast() (C++ allows // class/struct templates to be partially specialized, but not // function templates.). // This general version is used when MatcherCast()'s argument is a // polymorphic matcher (i.e. something that can be converted to a // Matcher but is not one yet; for example, Eq(value)) or a value (for // example, "hello"). template class MatcherCastImpl { public: static Matcher Cast(const M& polymorphic_matcher_or_value) { // M can be a polymorhic matcher, in which case we want to use // its conversion operator to create Matcher. Or it can be a value // that should be passed to the Matcher's constructor. // // We can't call Matcher(polymorphic_matcher_or_value) when M is a // polymorphic matcher because it'll be ambiguous if T has an implicit // constructor from M (this usually happens when T has an implicit // constructor from any type). // // It won't work to unconditionally implict_cast // polymorphic_matcher_or_value to Matcher because it won't trigger // a user-defined conversion from M to T if one exists (assuming M is // a value). return CastImpl( polymorphic_matcher_or_value, BooleanConstant< internal::ImplicitlyConvertible >::value>()); } private: static Matcher CastImpl(const M& value, BooleanConstant) { // M can't be implicitly converted to Matcher, so M isn't a polymorphic // matcher. It must be a value then. Use direct initialization to create // a matcher. return Matcher(ImplicitCast_(value)); } static Matcher CastImpl(const M& polymorphic_matcher_or_value, BooleanConstant) { // M is implicitly convertible to Matcher, which means that either // M is a polymorhpic matcher or Matcher has an implicit constructor // from M. In both cases using the implicit conversion will produce a // matcher. // // Even if T has an implicit constructor from M, it won't be called because // creating Matcher would require a chain of two user-defined conversions // (first to create T from M and then to create Matcher from T). return polymorphic_matcher_or_value; } }; // This more specialized version is used when MatcherCast()'s argument // is already a Matcher. This only compiles when type T can be // statically converted to type U. template class MatcherCastImpl > { public: static Matcher Cast(const Matcher& source_matcher) { return Matcher(new Impl(source_matcher)); } private: class Impl : public MatcherInterface { public: explicit Impl(const Matcher& source_matcher) : source_matcher_(source_matcher) {} // We delegate the matching logic to the source matcher. virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { return source_matcher_.MatchAndExplain(static_cast(x), listener); } virtual void DescribeTo(::std::ostream* os) const { source_matcher_.DescribeTo(os); } virtual void DescribeNegationTo(::std::ostream* os) const { source_matcher_.DescribeNegationTo(os); } private: const Matcher source_matcher_; GTEST_DISALLOW_ASSIGN_(Impl); }; }; // This even more specialized version is used for efficiently casting // a matcher to its own type. template class MatcherCastImpl > { public: static Matcher Cast(const Matcher& matcher) { return matcher; } }; } // namespace internal // In order to be safe and clear, casting between different matcher // types is done explicitly via MatcherCast(m), which takes a // matcher m and returns a Matcher. It compiles only when T can be // statically converted to the argument type of m. template inline Matcher MatcherCast(const M& matcher) { return internal::MatcherCastImpl::Cast(matcher); } // Implements SafeMatcherCast(). // // We use an intermediate class to do the actual safe casting as Nokia's // Symbian compiler cannot decide between // template ... (M) and // template ... (const Matcher&) // for function templates but can for member function templates. template class SafeMatcherCastImpl { public: // This overload handles polymorphic matchers and values only since // monomorphic matchers are handled by the next one. template static inline Matcher Cast(const M& polymorphic_matcher_or_value) { return internal::MatcherCastImpl::Cast(polymorphic_matcher_or_value); } // This overload handles monomorphic matchers. // // In general, if type T can be implicitly converted to type U, we can // safely convert a Matcher to a Matcher (i.e. Matcher is // contravariant): just keep a copy of the original Matcher, convert the // argument from type T to U, and then pass it to the underlying Matcher. // The only exception is when U is a reference and T is not, as the // underlying Matcher may be interested in the argument's address, which // is not preserved in the conversion from T to U. template static inline Matcher Cast(const Matcher& matcher) { // Enforce that T can be implicitly converted to U. GTEST_COMPILE_ASSERT_((internal::ImplicitlyConvertible::value), T_must_be_implicitly_convertible_to_U); // Enforce that we are not converting a non-reference type T to a reference // type U. GTEST_COMPILE_ASSERT_( internal::is_reference::value || !internal::is_reference::value, cannot_convert_non_referentce_arg_to_reference); // In case both T and U are arithmetic types, enforce that the // conversion is not lossy. typedef GTEST_REMOVE_REFERENCE_AND_CONST_(T) RawT; typedef GTEST_REMOVE_REFERENCE_AND_CONST_(U) RawU; const bool kTIsOther = GMOCK_KIND_OF_(RawT) == internal::kOther; const bool kUIsOther = GMOCK_KIND_OF_(RawU) == internal::kOther; GTEST_COMPILE_ASSERT_( kTIsOther || kUIsOther || (internal::LosslessArithmeticConvertible::value), conversion_of_arithmetic_types_must_be_lossless); return MatcherCast(matcher); } }; template inline Matcher SafeMatcherCast(const M& polymorphic_matcher) { return SafeMatcherCastImpl::Cast(polymorphic_matcher); } // A() returns a matcher that matches any value of type T. template Matcher A(); // Anything inside the 'internal' namespace IS INTERNAL IMPLEMENTATION // and MUST NOT BE USED IN USER CODE!!! namespace internal { // If the explanation is not empty, prints it to the ostream. inline void PrintIfNotEmpty(const internal::string& explanation, ::std::ostream* os) { if (explanation != "" && os != NULL) { *os << ", " << explanation; } } // Returns true if the given type name is easy to read by a human. // This is used to decide whether printing the type of a value might // be helpful. inline bool IsReadableTypeName(const string& type_name) { // We consider a type name readable if it's short or doesn't contain // a template or function type. return (type_name.length() <= 20 || type_name.find_first_of("<(") == string::npos); } // Matches the value against the given matcher, prints the value and explains // the match result to the listener. Returns the match result. // 'listener' must not be NULL. // Value cannot be passed by const reference, because some matchers take a // non-const argument. template bool MatchPrintAndExplain(Value& value, const Matcher& matcher, MatchResultListener* listener) { if (!listener->IsInterested()) { // If the listener is not interested, we do not need to construct the // inner explanation. return matcher.Matches(value); } StringMatchResultListener inner_listener; const bool match = matcher.MatchAndExplain(value, &inner_listener); UniversalPrint(value, listener->stream()); #if GTEST_HAS_RTTI const string& type_name = GetTypeName(); if (IsReadableTypeName(type_name)) *listener->stream() << " (of type " << type_name << ")"; #endif PrintIfNotEmpty(inner_listener.str(), listener->stream()); return match; } // An internal helper class for doing compile-time loop on a tuple's // fields. template class TuplePrefix { public: // TuplePrefix::Matches(matcher_tuple, value_tuple) returns true // iff the first N fields of matcher_tuple matches the first N // fields of value_tuple, respectively. template static bool Matches(const MatcherTuple& matcher_tuple, const ValueTuple& value_tuple) { return TuplePrefix::Matches(matcher_tuple, value_tuple) && get(matcher_tuple).Matches(get(value_tuple)); } // TuplePrefix::ExplainMatchFailuresTo(matchers, values, os) // describes failures in matching the first N fields of matchers // against the first N fields of values. If there is no failure, // nothing will be streamed to os. template static void ExplainMatchFailuresTo(const MatcherTuple& matchers, const ValueTuple& values, ::std::ostream* os) { // First, describes failures in the first N - 1 fields. TuplePrefix::ExplainMatchFailuresTo(matchers, values, os); // Then describes the failure (if any) in the (N - 1)-th (0-based) // field. typename tuple_element::type matcher = get(matchers); typedef typename tuple_element::type Value; Value value = get(values); StringMatchResultListener listener; if (!matcher.MatchAndExplain(value, &listener)) { // TODO(wan): include in the message the name of the parameter // as used in MOCK_METHOD*() when possible. *os << " Expected arg #" << N - 1 << ": "; get(matchers).DescribeTo(os); *os << "\n Actual: "; // We remove the reference in type Value to prevent the // universal printer from printing the address of value, which // isn't interesting to the user most of the time. The // matcher's MatchAndExplain() method handles the case when // the address is interesting. internal::UniversalPrint(value, os); PrintIfNotEmpty(listener.str(), os); *os << "\n"; } } }; // The base case. template <> class TuplePrefix<0> { public: template static bool Matches(const MatcherTuple& /* matcher_tuple */, const ValueTuple& /* value_tuple */) { return true; } template static void ExplainMatchFailuresTo(const MatcherTuple& /* matchers */, const ValueTuple& /* values */, ::std::ostream* /* os */) {} }; // TupleMatches(matcher_tuple, value_tuple) returns true iff all // matchers in matcher_tuple match the corresponding fields in // value_tuple. It is a compiler error if matcher_tuple and // value_tuple have different number of fields or incompatible field // types. template bool TupleMatches(const MatcherTuple& matcher_tuple, const ValueTuple& value_tuple) { // Makes sure that matcher_tuple and value_tuple have the same // number of fields. GTEST_COMPILE_ASSERT_(tuple_size::value == tuple_size::value, matcher_and_value_have_different_numbers_of_fields); return TuplePrefix::value>:: Matches(matcher_tuple, value_tuple); } // Describes failures in matching matchers against values. If there // is no failure, nothing will be streamed to os. template void ExplainMatchFailureTupleTo(const MatcherTuple& matchers, const ValueTuple& values, ::std::ostream* os) { TuplePrefix::value>::ExplainMatchFailuresTo( matchers, values, os); } // TransformTupleValues and its helper. // // TransformTupleValuesHelper hides the internal machinery that // TransformTupleValues uses to implement a tuple traversal. template class TransformTupleValuesHelper { private: typedef ::testing::tuple_size TupleSize; public: // For each member of tuple 't', taken in order, evaluates '*out++ = f(t)'. // Returns the final value of 'out' in case the caller needs it. static OutIter Run(Func f, const Tuple& t, OutIter out) { return IterateOverTuple()(f, t, out); } private: template struct IterateOverTuple { OutIter operator() (Func f, const Tup& t, OutIter out) const { *out++ = f(::testing::get(t)); return IterateOverTuple()(f, t, out); } }; template struct IterateOverTuple { OutIter operator() (Func /* f */, const Tup& /* t */, OutIter out) const { return out; } }; }; // Successively invokes 'f(element)' on each element of the tuple 't', // appending each result to the 'out' iterator. Returns the final value // of 'out'. template OutIter TransformTupleValues(Func f, const Tuple& t, OutIter out) { return TransformTupleValuesHelper::Run(f, t, out); } // Implements A(). template class AnyMatcherImpl : public MatcherInterface { public: virtual bool MatchAndExplain( T /* x */, MatchResultListener* /* listener */) const { return true; } virtual void DescribeTo(::std::ostream* os) const { *os << "is anything"; } virtual void DescribeNegationTo(::std::ostream* os) const { // This is mostly for completeness' safe, as it's not very useful // to write Not(A()). However we cannot completely rule out // such a possibility, and it doesn't hurt to be prepared. *os << "never matches"; } }; // Implements _, a matcher that matches any value of any // type. This is a polymorphic matcher, so we need a template type // conversion operator to make it appearing as a Matcher for any // type T. class AnythingMatcher { public: template operator Matcher() const { return A(); } }; // Implements a matcher that compares a given value with a // pre-supplied value using one of the ==, <=, <, etc, operators. The // two values being compared don't have to have the same type. // // The matcher defined here is polymorphic (for example, Eq(5) can be // used to match an int, a short, a double, etc). Therefore we use // a template type conversion operator in the implementation. // // The following template definition assumes that the Rhs parameter is // a "bare" type (i.e. neither 'const T' nor 'T&'). template class ComparisonBase { public: explicit ComparisonBase(const Rhs& rhs) : rhs_(rhs) {} template operator Matcher() const { return MakeMatcher(new Impl(rhs_)); } private: template class Impl : public MatcherInterface { public: explicit Impl(const Rhs& rhs) : rhs_(rhs) {} virtual bool MatchAndExplain( Lhs lhs, MatchResultListener* /* listener */) const { return Op()(lhs, rhs_); } virtual void DescribeTo(::std::ostream* os) const { *os << D::Desc() << " "; UniversalPrint(rhs_, os); } virtual void DescribeNegationTo(::std::ostream* os) const { *os << D::NegatedDesc() << " "; UniversalPrint(rhs_, os); } private: Rhs rhs_; GTEST_DISALLOW_ASSIGN_(Impl); }; Rhs rhs_; GTEST_DISALLOW_ASSIGN_(ComparisonBase); }; template class EqMatcher : public ComparisonBase, Rhs, AnyEq> { public: explicit EqMatcher(const Rhs& rhs) : ComparisonBase, Rhs, AnyEq>(rhs) { } static const char* Desc() { return "is equal to"; } static const char* NegatedDesc() { return "isn't equal to"; } }; template class NeMatcher : public ComparisonBase, Rhs, AnyNe> { public: explicit NeMatcher(const Rhs& rhs) : ComparisonBase, Rhs, AnyNe>(rhs) { } static const char* Desc() { return "isn't equal to"; } static const char* NegatedDesc() { return "is equal to"; } }; template class LtMatcher : public ComparisonBase, Rhs, AnyLt> { public: explicit LtMatcher(const Rhs& rhs) : ComparisonBase, Rhs, AnyLt>(rhs) { } static const char* Desc() { return "is <"; } static const char* NegatedDesc() { return "isn't <"; } }; template class GtMatcher : public ComparisonBase, Rhs, AnyGt> { public: explicit GtMatcher(const Rhs& rhs) : ComparisonBase, Rhs, AnyGt>(rhs) { } static const char* Desc() { return "is >"; } static const char* NegatedDesc() { return "isn't >"; } }; template class LeMatcher : public ComparisonBase, Rhs, AnyLe> { public: explicit LeMatcher(const Rhs& rhs) : ComparisonBase, Rhs, AnyLe>(rhs) { } static const char* Desc() { return "is <="; } static const char* NegatedDesc() { return "isn't <="; } }; template class GeMatcher : public ComparisonBase, Rhs, AnyGe> { public: explicit GeMatcher(const Rhs& rhs) : ComparisonBase, Rhs, AnyGe>(rhs) { } static const char* Desc() { return "is >="; } static const char* NegatedDesc() { return "isn't >="; } }; // Implements the polymorphic IsNull() matcher, which matches any raw or smart // pointer that is NULL. class IsNullMatcher { public: template bool MatchAndExplain(const Pointer& p, MatchResultListener* /* listener */) const { #if GTEST_LANG_CXX11 return p == nullptr; #else // GTEST_LANG_CXX11 return GetRawPointer(p) == NULL; #endif // GTEST_LANG_CXX11 } void DescribeTo(::std::ostream* os) const { *os << "is NULL"; } void DescribeNegationTo(::std::ostream* os) const { *os << "isn't NULL"; } }; // Implements the polymorphic NotNull() matcher, which matches any raw or smart // pointer that is not NULL. class NotNullMatcher { public: template bool MatchAndExplain(const Pointer& p, MatchResultListener* /* listener */) const { #if GTEST_LANG_CXX11 return p != nullptr; #else // GTEST_LANG_CXX11 return GetRawPointer(p) != NULL; #endif // GTEST_LANG_CXX11 } void DescribeTo(::std::ostream* os) const { *os << "isn't NULL"; } void DescribeNegationTo(::std::ostream* os) const { *os << "is NULL"; } }; // Ref(variable) matches any argument that is a reference to // 'variable'. This matcher is polymorphic as it can match any // super type of the type of 'variable'. // // The RefMatcher template class implements Ref(variable). It can // only be instantiated with a reference type. This prevents a user // from mistakenly using Ref(x) to match a non-reference function // argument. For example, the following will righteously cause a // compiler error: // // int n; // Matcher m1 = Ref(n); // This won't compile. // Matcher m2 = Ref(n); // This will compile. template class RefMatcher; template class RefMatcher { // Google Mock is a generic framework and thus needs to support // mocking any function types, including those that take non-const // reference arguments. Therefore the template parameter T (and // Super below) can be instantiated to either a const type or a // non-const type. public: // RefMatcher() takes a T& instead of const T&, as we want the // compiler to catch using Ref(const_value) as a matcher for a // non-const reference. explicit RefMatcher(T& x) : object_(x) {} // NOLINT template operator Matcher() const { // By passing object_ (type T&) to Impl(), which expects a Super&, // we make sure that Super is a super type of T. In particular, // this catches using Ref(const_value) as a matcher for a // non-const reference, as you cannot implicitly convert a const // reference to a non-const reference. return MakeMatcher(new Impl(object_)); } private: template class Impl : public MatcherInterface { public: explicit Impl(Super& x) : object_(x) {} // NOLINT // MatchAndExplain() takes a Super& (as opposed to const Super&) // in order to match the interface MatcherInterface. virtual bool MatchAndExplain( Super& x, MatchResultListener* listener) const { *listener << "which is located @" << static_cast(&x); return &x == &object_; } virtual void DescribeTo(::std::ostream* os) const { *os << "references the variable "; UniversalPrinter::Print(object_, os); } virtual void DescribeNegationTo(::std::ostream* os) const { *os << "does not reference the variable "; UniversalPrinter::Print(object_, os); } private: const Super& object_; GTEST_DISALLOW_ASSIGN_(Impl); }; T& object_; GTEST_DISALLOW_ASSIGN_(RefMatcher); }; // Polymorphic helper functions for narrow and wide string matchers. inline bool CaseInsensitiveCStringEquals(const char* lhs, const char* rhs) { return String::CaseInsensitiveCStringEquals(lhs, rhs); } inline bool CaseInsensitiveCStringEquals(const wchar_t* lhs, const wchar_t* rhs) { return String::CaseInsensitiveWideCStringEquals(lhs, rhs); } // String comparison for narrow or wide strings that can have embedded NUL // characters. template bool CaseInsensitiveStringEquals(const StringType& s1, const StringType& s2) { // Are the heads equal? if (!CaseInsensitiveCStringEquals(s1.c_str(), s2.c_str())) { return false; } // Skip the equal heads. const typename StringType::value_type nul = 0; const size_t i1 = s1.find(nul), i2 = s2.find(nul); // Are we at the end of either s1 or s2? if (i1 == StringType::npos || i2 == StringType::npos) { return i1 == i2; } // Are the tails equal? return CaseInsensitiveStringEquals(s1.substr(i1 + 1), s2.substr(i2 + 1)); } // String matchers. // Implements equality-based string matchers like StrEq, StrCaseNe, and etc. template class StrEqualityMatcher { public: StrEqualityMatcher(const StringType& str, bool expect_eq, bool case_sensitive) : string_(str), expect_eq_(expect_eq), case_sensitive_(case_sensitive) {} // Accepts pointer types, particularly: // const char* // char* // const wchar_t* // wchar_t* template bool MatchAndExplain(CharType* s, MatchResultListener* listener) const { if (s == NULL) { return !expect_eq_; } return MatchAndExplain(StringType(s), listener); } // Matches anything that can convert to StringType. // // This is a template, not just a plain function with const StringType&, // because StringPiece has some interfering non-explicit constructors. template bool MatchAndExplain(const MatcheeStringType& s, MatchResultListener* /* listener */) const { const StringType& s2(s); const bool eq = case_sensitive_ ? s2 == string_ : CaseInsensitiveStringEquals(s2, string_); return expect_eq_ == eq; } void DescribeTo(::std::ostream* os) const { DescribeToHelper(expect_eq_, os); } void DescribeNegationTo(::std::ostream* os) const { DescribeToHelper(!expect_eq_, os); } private: void DescribeToHelper(bool expect_eq, ::std::ostream* os) const { *os << (expect_eq ? "is " : "isn't "); *os << "equal to "; if (!case_sensitive_) { *os << "(ignoring case) "; } UniversalPrint(string_, os); } const StringType string_; const bool expect_eq_; const bool case_sensitive_; GTEST_DISALLOW_ASSIGN_(StrEqualityMatcher); }; // Implements the polymorphic HasSubstr(substring) matcher, which // can be used as a Matcher as long as T can be converted to a // string. template class HasSubstrMatcher { public: explicit HasSubstrMatcher(const StringType& substring) : substring_(substring) {} // Accepts pointer types, particularly: // const char* // char* // const wchar_t* // wchar_t* template bool MatchAndExplain(CharType* s, MatchResultListener* listener) const { return s != NULL && MatchAndExplain(StringType(s), listener); } // Matches anything that can convert to StringType. // // This is a template, not just a plain function with const StringType&, // because StringPiece has some interfering non-explicit constructors. template bool MatchAndExplain(const MatcheeStringType& s, MatchResultListener* /* listener */) const { const StringType& s2(s); return s2.find(substring_) != StringType::npos; } // Describes what this matcher matches. void DescribeTo(::std::ostream* os) const { *os << "has substring "; UniversalPrint(substring_, os); } void DescribeNegationTo(::std::ostream* os) const { *os << "has no substring "; UniversalPrint(substring_, os); } private: const StringType substring_; GTEST_DISALLOW_ASSIGN_(HasSubstrMatcher); }; // Implements the polymorphic StartsWith(substring) matcher, which // can be used as a Matcher as long as T can be converted to a // string. template class StartsWithMatcher { public: explicit StartsWithMatcher(const StringType& prefix) : prefix_(prefix) { } // Accepts pointer types, particularly: // const char* // char* // const wchar_t* // wchar_t* template bool MatchAndExplain(CharType* s, MatchResultListener* listener) const { return s != NULL && MatchAndExplain(StringType(s), listener); } // Matches anything that can convert to StringType. // // This is a template, not just a plain function with const StringType&, // because StringPiece has some interfering non-explicit constructors. template bool MatchAndExplain(const MatcheeStringType& s, MatchResultListener* /* listener */) const { const StringType& s2(s); return s2.length() >= prefix_.length() && s2.substr(0, prefix_.length()) == prefix_; } void DescribeTo(::std::ostream* os) const { *os << "starts with "; UniversalPrint(prefix_, os); } void DescribeNegationTo(::std::ostream* os) const { *os << "doesn't start with "; UniversalPrint(prefix_, os); } private: const StringType prefix_; GTEST_DISALLOW_ASSIGN_(StartsWithMatcher); }; // Implements the polymorphic EndsWith(substring) matcher, which // can be used as a Matcher as long as T can be converted to a // string. template class EndsWithMatcher { public: explicit EndsWithMatcher(const StringType& suffix) : suffix_(suffix) {} // Accepts pointer types, particularly: // const char* // char* // const wchar_t* // wchar_t* template bool MatchAndExplain(CharType* s, MatchResultListener* listener) const { return s != NULL && MatchAndExplain(StringType(s), listener); } // Matches anything that can convert to StringType. // // This is a template, not just a plain function with const StringType&, // because StringPiece has some interfering non-explicit constructors. template bool MatchAndExplain(const MatcheeStringType& s, MatchResultListener* /* listener */) const { const StringType& s2(s); return s2.length() >= suffix_.length() && s2.substr(s2.length() - suffix_.length()) == suffix_; } void DescribeTo(::std::ostream* os) const { *os << "ends with "; UniversalPrint(suffix_, os); } void DescribeNegationTo(::std::ostream* os) const { *os << "doesn't end with "; UniversalPrint(suffix_, os); } private: const StringType suffix_; GTEST_DISALLOW_ASSIGN_(EndsWithMatcher); }; // Implements polymorphic matchers MatchesRegex(regex) and // ContainsRegex(regex), which can be used as a Matcher as long as // T can be converted to a string. class MatchesRegexMatcher { public: MatchesRegexMatcher(const RE* regex, bool full_match) : regex_(regex), full_match_(full_match) {} // Accepts pointer types, particularly: // const char* // char* // const wchar_t* // wchar_t* template bool MatchAndExplain(CharType* s, MatchResultListener* listener) const { return s != NULL && MatchAndExplain(internal::string(s), listener); } // Matches anything that can convert to internal::string. // // This is a template, not just a plain function with const internal::string&, // because StringPiece has some interfering non-explicit constructors. template bool MatchAndExplain(const MatcheeStringType& s, MatchResultListener* /* listener */) const { const internal::string& s2(s); return full_match_ ? RE::FullMatch(s2, *regex_) : RE::PartialMatch(s2, *regex_); } void DescribeTo(::std::ostream* os) const { *os << (full_match_ ? "matches" : "contains") << " regular expression "; UniversalPrinter::Print(regex_->pattern(), os); } void DescribeNegationTo(::std::ostream* os) const { *os << "doesn't " << (full_match_ ? "match" : "contain") << " regular expression "; UniversalPrinter::Print(regex_->pattern(), os); } private: const internal::linked_ptr regex_; const bool full_match_; GTEST_DISALLOW_ASSIGN_(MatchesRegexMatcher); }; // Implements a matcher that compares the two fields of a 2-tuple // using one of the ==, <=, <, etc, operators. The two fields being // compared don't have to have the same type. // // The matcher defined here is polymorphic (for example, Eq() can be // used to match a tuple, a tuple, // etc). Therefore we use a template type conversion operator in the // implementation. template class PairMatchBase { public: template operator Matcher< ::testing::tuple >() const { return MakeMatcher(new Impl< ::testing::tuple >); } template operator Matcher&>() const { return MakeMatcher(new Impl&>); } private: static ::std::ostream& GetDesc(::std::ostream& os) { // NOLINT return os << D::Desc(); } template class Impl : public MatcherInterface { public: virtual bool MatchAndExplain( Tuple args, MatchResultListener* /* listener */) const { return Op()(::testing::get<0>(args), ::testing::get<1>(args)); } virtual void DescribeTo(::std::ostream* os) const { *os << "are " << GetDesc; } virtual void DescribeNegationTo(::std::ostream* os) const { *os << "aren't " << GetDesc; } }; }; class Eq2Matcher : public PairMatchBase { public: static const char* Desc() { return "an equal pair"; } }; class Ne2Matcher : public PairMatchBase { public: static const char* Desc() { return "an unequal pair"; } }; class Lt2Matcher : public PairMatchBase { public: static const char* Desc() { return "a pair where the first < the second"; } }; class Gt2Matcher : public PairMatchBase { public: static const char* Desc() { return "a pair where the first > the second"; } }; class Le2Matcher : public PairMatchBase { public: static const char* Desc() { return "a pair where the first <= the second"; } }; class Ge2Matcher : public PairMatchBase { public: static const char* Desc() { return "a pair where the first >= the second"; } }; // Implements the Not(...) matcher for a particular argument type T. // We do not nest it inside the NotMatcher class template, as that // will prevent different instantiations of NotMatcher from sharing // the same NotMatcherImpl class. template class NotMatcherImpl : public MatcherInterface { public: explicit NotMatcherImpl(const Matcher& matcher) : matcher_(matcher) {} virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { return !matcher_.MatchAndExplain(x, listener); } virtual void DescribeTo(::std::ostream* os) const { matcher_.DescribeNegationTo(os); } virtual void DescribeNegationTo(::std::ostream* os) const { matcher_.DescribeTo(os); } private: const Matcher matcher_; GTEST_DISALLOW_ASSIGN_(NotMatcherImpl); }; // Implements the Not(m) matcher, which matches a value that doesn't // match matcher m. template class NotMatcher { public: explicit NotMatcher(InnerMatcher matcher) : matcher_(matcher) {} // This template type conversion operator allows Not(m) to be used // to match any type m can match. template operator Matcher() const { return Matcher(new NotMatcherImpl(SafeMatcherCast(matcher_))); } private: InnerMatcher matcher_; GTEST_DISALLOW_ASSIGN_(NotMatcher); }; // Implements the AllOf(m1, m2) matcher for a particular argument type // T. We do not nest it inside the BothOfMatcher class template, as // that will prevent different instantiations of BothOfMatcher from // sharing the same BothOfMatcherImpl class. template class BothOfMatcherImpl : public MatcherInterface { public: BothOfMatcherImpl(const Matcher& matcher1, const Matcher& matcher2) : matcher1_(matcher1), matcher2_(matcher2) {} virtual void DescribeTo(::std::ostream* os) const { *os << "("; matcher1_.DescribeTo(os); *os << ") and ("; matcher2_.DescribeTo(os); *os << ")"; } virtual void DescribeNegationTo(::std::ostream* os) const { *os << "("; matcher1_.DescribeNegationTo(os); *os << ") or ("; matcher2_.DescribeNegationTo(os); *os << ")"; } virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { // If either matcher1_ or matcher2_ doesn't match x, we only need // to explain why one of them fails. StringMatchResultListener listener1; if (!matcher1_.MatchAndExplain(x, &listener1)) { *listener << listener1.str(); return false; } StringMatchResultListener listener2; if (!matcher2_.MatchAndExplain(x, &listener2)) { *listener << listener2.str(); return false; } // Otherwise we need to explain why *both* of them match. const internal::string s1 = listener1.str(); const internal::string s2 = listener2.str(); if (s1 == "") { *listener << s2; } else { *listener << s1; if (s2 != "") { *listener << ", and " << s2; } } return true; } private: const Matcher matcher1_; const Matcher matcher2_; GTEST_DISALLOW_ASSIGN_(BothOfMatcherImpl); }; #if GTEST_LANG_CXX11 // MatcherList provides mechanisms for storing a variable number of matchers in // a list structure (ListType) and creating a combining matcher from such a // list. // The template is defined recursively using the following template paramters: // * kSize is the length of the MatcherList. // * Head is the type of the first matcher of the list. // * Tail denotes the types of the remaining matchers of the list. template struct MatcherList { typedef MatcherList MatcherListTail; typedef ::std::pair ListType; // BuildList stores variadic type values in a nested pair structure. // Example: // MatcherList<3, int, string, float>::BuildList(5, "foo", 2.0) will return // the corresponding result of type pair>. static ListType BuildList(const Head& matcher, const Tail&... tail) { return ListType(matcher, MatcherListTail::BuildList(tail...)); } // CreateMatcher creates a Matcher from a given list of matchers (built // by BuildList()). CombiningMatcher is used to combine the matchers of the // list. CombiningMatcher must implement MatcherInterface and have a // constructor taking two Matchers as input. template class CombiningMatcher> static Matcher CreateMatcher(const ListType& matchers) { return Matcher(new CombiningMatcher( SafeMatcherCast(matchers.first), MatcherListTail::template CreateMatcher( matchers.second))); } }; // The following defines the base case for the recursive definition of // MatcherList. template struct MatcherList<2, Matcher1, Matcher2> { typedef ::std::pair ListType; static ListType BuildList(const Matcher1& matcher1, const Matcher2& matcher2) { return ::std::pair(matcher1, matcher2); } template class CombiningMatcher> static Matcher CreateMatcher(const ListType& matchers) { return Matcher(new CombiningMatcher( SafeMatcherCast(matchers.first), SafeMatcherCast(matchers.second))); } }; // VariadicMatcher is used for the variadic implementation of // AllOf(m_1, m_2, ...) and AnyOf(m_1, m_2, ...). // CombiningMatcher is used to recursively combine the provided matchers // (of type Args...). template