diff --git a/CMakeLists.txt.user b/CMakeLists.txt.user new file mode 100644 index 00000000..e8537de4 --- /dev/null +++ b/CMakeLists.txt.user @@ -0,0 +1,4300 @@ + + + + + + EnvironmentId + {8a80725c-e2e1-40d0-b8ef-a04ea95df9eb} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + false + false + true + + Cpp + + CppGlobal + + + 1 + ISO-8859-1 + false + 4 + false + 80 + true + true + 1 + true + false + 2 + true + true + 2 + 8 + true + 1 + true + true + true + false + + + + ProjectExplorer.Project.PluginSettings + + + true + + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop + {0144961e-7153-4981-879a-10678cdd27a3} + 0 + 0 + 0 + + + BUILD_FETCHER_TESTS:BOOL=ON + CMAKE_CODEBLOCKS_MAKE_ARGUMENTS:STRING=-j5 + CMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx} + CMAKE_C_COMPILER:STRING=%{Compiler:Executable:C} + CMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX} + ENABLE_WEBCAM:BOOL=ON + QT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable} + + /home/robby/kde/build/tellico + + + + + all + + true + CMake Build + + CMakeProjectManager.MakeStep + + 1 + Build + + ProjectExplorer.BuildSteps.Build + + + + + + clean + + true + CMake Build + + CMakeProjectManager.MakeStep + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Default + Default + CMakeProjectManager.CMakeBuildConfiguration + + + + CMAKE_BUILD_TYPE:STRING=Debug + + /home/robby/kde/src/build-tellico-Desktop-Debug + + + + + all + + true + CMake Build + + CMakeProjectManager.MakeStep + + 1 + Build + + ProjectExplorer.BuildSteps.Build + + + + + + clean + + true + CMake Build + + CMakeProjectManager.MakeStep + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Debug + Debug + CMakeProjectManager.CMakeBuildConfiguration + + + + CMAKE_BUILD_TYPE:STRING=Release + + /home/robby/kde/src/build-tellico-Desktop-Release + + + + + all + + true + CMake Build + + CMakeProjectManager.MakeStep + + 1 + Build + + ProjectExplorer.BuildSteps.Build + + + + + + clean + + true + CMake Build + + CMakeProjectManager.MakeStep + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Release + Release + CMakeProjectManager.CMakeBuildConfiguration + + + + CMAKE_BUILD_TYPE:STRING=RelWithDebInfo + + /home/robby/kde/src/build-tellico-Desktop-Release with Debug Information + + + + + all + + true + CMake Build + + CMakeProjectManager.MakeStep + + 1 + Build + + ProjectExplorer.BuildSteps.Build + + + + + + clean + + true + CMake Build + + CMakeProjectManager.MakeStep + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Release with Debug Information + Release with Debug Information + CMakeProjectManager.CMakeBuildConfiguration + + + + CMAKE_BUILD_TYPE:STRING=MinSizeRel + + /home/robby/kde/src/build-tellico-Desktop-Minimum Size Release + + + + + all + + true + CMake Build + + CMakeProjectManager.MakeStep + + 1 + Build + + ProjectExplorer.BuildSteps.Build + + + + + + clean + + true + CMake Build + + CMakeProjectManager.MakeStep + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Minimum Size Release + Minimum Size Release + CMakeProjectManager.CMakeBuildConfiguration + + 5 + + + 0 + Deploy + + ProjectExplorer.BuildSteps.Deploy + + 1 + Deploy Configuration + + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + tellico + --nofile + + /home/robby/kde/build/tellico/src + 2 + + tellico + + CMakeProjectManager.CMakeRunConfiguration.tellico + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + documenttest + + + /home/robby/kde/build/tellico/src/tests + 2 + + documenttest + + CMakeProjectManager.CMakeRunConfiguration.documenttest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + cuecattest + + + /home/robby/kde/build/tellico/src/tests + 2 + + cuecattest + + CMakeProjectManager.CMakeRunConfiguration.cuecattest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + filtertest + + + /home/robby/kde/build/tellico/src/tests + 2 + + filtertest + + CMakeProjectManager.CMakeRunConfiguration.filtertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + entitytest + + + /home/robby/kde/build/tellico/src/tests + 2 + + entitytest + + CMakeProjectManager.CMakeRunConfiguration.entitytest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + formattest + + + /home/robby/kde/build/tellico/src/tests + 2 + + formattest + + CMakeProjectManager.CMakeRunConfiguration.formattest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + htmlexportertest + + + /home/robby/kde/build/tellico/src/tests + 2 + + htmlexportertest + + CMakeProjectManager.CMakeRunConfiguration.htmlexportertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + gcstartest + + + /home/robby/kde/build/tellico/src/tests + 2 + + gcstartest + + CMakeProjectManager.CMakeRunConfiguration.gcstartest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + isbntest + + + /home/robby/kde/build/tellico/src/tests + 2 + + isbntest + + CMakeProjectManager.CMakeRunConfiguration.isbntest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + lccntest + + + /home/robby/kde/build/tellico/src/tests + 2 + + lccntest + + CMakeProjectManager.CMakeRunConfiguration.lccntest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + imagetest + + + /home/robby/kde/build/tellico/src/tests + 2 + + imagetest + + CMakeProjectManager.CMakeRunConfiguration.imagetest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + lcctest + + + /home/robby/kde/build/tellico/src/tests + 2 + + lcctest + + CMakeProjectManager.CMakeRunConfiguration.lcctest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + collectiontest + + + /home/robby/kde/build/tellico/src/tests + 2 + + collectiontest + + CMakeProjectManager.CMakeRunConfiguration.collectiontest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + vinoxmltest + + + /home/robby/kde/build/tellico/src/tests + 2 + + vinoxmltest + + CMakeProjectManager.CMakeRunConfiguration.vinoxmltest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + tellicomodeltest + + + /home/robby/kde/build/tellico/src/tests + 2 + + tellicomodeltest + + CMakeProjectManager.CMakeRunConfiguration.tellicomodeltest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + adstest + + + /home/robby/kde/build/tellico/src/tests + 2 + + adstest + + CMakeProjectManager.CMakeRunConfiguration.adstest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + bibtextest + + + /home/robby/kde/build/tellico/src/tests + 2 + + bibtextest + + CMakeProjectManager.CMakeRunConfiguration.bibtextest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + filelistingtest + + + /home/robby/kde/build/tellico/src/tests + 2 + + filelistingtest + + CMakeProjectManager.CMakeRunConfiguration.filelistingtest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + alexandriatest + + + /home/robby/kde/build/tellico/src/tests + 2 + + alexandriatest + + CMakeProjectManager.CMakeRunConfiguration.alexandriatest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + amctest + + + /home/robby/kde/build/tellico/src/tests + 2 + + amctest + + CMakeProjectManager.CMakeRunConfiguration.amctest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + bibtexmltest + + + /home/robby/kde/build/tellico/src/tests + 2 + + bibtexmltest + + CMakeProjectManager.CMakeRunConfiguration.bibtexmltest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + citetest + + + /home/robby/kde/build/tellico/src/tests + 2 + + citetest + + CMakeProjectManager.CMakeRunConfiguration.citetest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + csvtest + + + /home/robby/kde/build/tellico/src/tests + 2 + + csvtest + + CMakeProjectManager.CMakeRunConfiguration.csvtest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + comparisontest + + + /home/robby/kde/build/tellico/src/tests + 2 + + comparisontest + + CMakeProjectManager.CMakeRunConfiguration.comparisontest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + delicioustest + + + /home/robby/kde/build/tellico/src/tests + 2 + + delicioustest + + CMakeProjectManager.CMakeRunConfiguration.delicioustest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + griffithtest + + + /home/robby/kde/build/tellico/src/tests + 2 + + griffithtest + + CMakeProjectManager.CMakeRunConfiguration.griffithtest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + modstest + + + /home/robby/kde/build/tellico/src/tests + 2 + + modstest + + CMakeProjectManager.CMakeRunConfiguration.modstest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + referencertest + + + /home/robby/kde/build/tellico/src/tests + 2 + + referencertest + + CMakeProjectManager.CMakeRunConfiguration.referencertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + ristest + + + /home/robby/kde/build/tellico/src/tests + 2 + + ristest + + CMakeProjectManager.CMakeRunConfiguration.ristest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + mrlookupfetchertest + + + /home/robby/kde/build/tellico/src/tests + 2 + + mrlookupfetchertest + + CMakeProjectManager.CMakeRunConfiguration.mrlookupfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + gcstarfetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + gcstarfetchertest + + CMakeProjectManager.CMakeRunConfiguration.gcstarfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + crossreffetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + crossreffetchertest + + CMakeProjectManager.CMakeRunConfiguration.crossreffetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + externalfetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + externalfetchertest + + CMakeProjectManager.CMakeRunConfiguration.externalfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + z3950fetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + z3950fetchertest + + CMakeProjectManager.CMakeRunConfiguration.z3950fetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + tellicoreadtest + + + /home/robby/kde/build/tellico/src/tests + 2 + + tellicoreadtest + + CMakeProjectManager.CMakeRunConfiguration.tellicoreadtest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + videogamegeekfetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + videogamegeekfetchertest + + CMakeProjectManager.CMakeRunConfiguration.videogamegeekfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + doubanfetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + doubanfetchertest + + CMakeProjectManager.CMakeRunConfiguration.doubanfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + mobygamesfetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + mobygamesfetchertest + + CMakeProjectManager.CMakeRunConfiguration.mobygamesfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + filmasterfetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + filmasterfetchertest + + CMakeProjectManager.CMakeRunConfiguration.filmasterfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + omdbfetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + omdbfetchertest + + CMakeProjectManager.CMakeRunConfiguration.omdbfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + springerfetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + springerfetchertest + + CMakeProjectManager.CMakeRunConfiguration.springerfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + kinofetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + kinofetchertest + + CMakeProjectManager.CMakeRunConfiguration.kinofetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + srufetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + srufetchertest + + CMakeProjectManager.CMakeRunConfiguration.srufetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + dbcfetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + dbcfetchertest + + CMakeProjectManager.CMakeRunConfiguration.dbcfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + dblpfetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + dblpfetchertest + + CMakeProjectManager.CMakeRunConfiguration.dblpfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + iso6937test + + + /home/robby/kde/build/tellico/src/tests + 2 + + iso6937test + + CMakeProjectManager.CMakeRunConfiguration.iso6937test + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + musicbrainzfetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + musicbrainzfetchertest + + CMakeProjectManager.CMakeRunConfiguration.musicbrainzfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + dvdfrfetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + dvdfrfetchertest + + CMakeProjectManager.CMakeRunConfiguration.dvdfrfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + ibsfetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + ibsfetchertest + + CMakeProjectManager.CMakeRunConfiguration.ibsfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + moviemeterfetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + moviemeterfetchertest + + CMakeProjectManager.CMakeRunConfiguration.moviemeterfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + entrezfetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + entrezfetchertest + + CMakeProjectManager.CMakeRunConfiguration.entrezfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + giantbombfetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + giantbombfetchertest + + CMakeProjectManager.CMakeRunConfiguration.giantbombfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + googlebookfetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + googlebookfetchertest + + CMakeProjectManager.CMakeRunConfiguration.googlebookfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + isbndbfetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + isbndbfetchertest + + CMakeProjectManager.CMakeRunConfiguration.isbndbfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + kinopoiskfetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + kinopoiskfetchertest + + CMakeProjectManager.CMakeRunConfiguration.kinopoiskfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + thegamesdbfetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + thegamesdbfetchertest + + CMakeProjectManager.CMakeRunConfiguration.thegamesdbfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + imagejobtest + + + /home/robby/kde/build/tellico/src/tests + 2 + + imagejobtest + + CMakeProjectManager.CMakeRunConfiguration.imagejobtest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + amazonfetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + amazonfetchertest + + CMakeProjectManager.CMakeRunConfiguration.amazonfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + boardgamegeekfetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + boardgamegeekfetchertest + + CMakeProjectManager.CMakeRunConfiguration.boardgamegeekfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + openlibraryfetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + openlibraryfetchertest + + CMakeProjectManager.CMakeRunConfiguration.openlibraryfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + imdbfetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + imdbfetchertest + + CMakeProjectManager.CMakeRunConfiguration.imdbfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + darkhorsefetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + darkhorsefetchertest + + CMakeProjectManager.CMakeRunConfiguration.darkhorsefetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + allocinefetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + allocinefetchertest + + CMakeProjectManager.CMakeRunConfiguration.allocinefetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + vndbfetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + vndbfetchertest + + CMakeProjectManager.CMakeRunConfiguration.vndbfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + comicvinefetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + comicvinefetchertest + + CMakeProjectManager.CMakeRunConfiguration.comicvinefetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + hathitrustfetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + hathitrustfetchertest + + CMakeProjectManager.CMakeRunConfiguration.hathitrustfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + igdbfetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + igdbfetchertest + + CMakeProjectManager.CMakeRunConfiguration.igdbfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + pdftest + + + /home/robby/kde/build/tellico/src/tests + 2 + + pdftest + + CMakeProjectManager.CMakeRunConfiguration.pdftest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + themoviedbfetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + themoviedbfetchertest + + CMakeProjectManager.CMakeRunConfiguration.themoviedbfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + entryupdatejobtest + + + /home/robby/kde/build/tellico/src/tests + -1 + + entryupdatejobtest + + CMakeProjectManager.CMakeRunConfiguration.entryupdatejobtest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + animenfofetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + animenfofetchertest + + CMakeProjectManager.CMakeRunConfiguration.animenfofetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + discogsfetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + discogsfetchertest + + CMakeProjectManager.CMakeRunConfiguration.discogsfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + arxivfetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + arxivfetchertest + + CMakeProjectManager.CMakeRunConfiguration.arxivfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + bedethequefetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + bedethequefetchertest + + CMakeProjectManager.CMakeRunConfiguration.bedethequefetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + googlescholarfetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + googlescholarfetchertest + + CMakeProjectManager.CMakeRunConfiguration.googlescholarfetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + bibliosharefetchertest + + + /home/robby/kde/build/tellico/src/tests + -1 + + bibliosharefetchertest + + CMakeProjectManager.CMakeRunConfiguration.bibliosharefetchertest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + fieldtest + + + /home/robby/kde/build/tellico/src/tests + 2 + + fieldtest + + CMakeProjectManager.CMakeRunConfiguration.fieldtest + 3768 + false + true + false + false + true + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + ciwtest + + + /home/robby/kde/build/tellico/src/tests + 2 + + ciwtest + + CMakeProjectManager.CMakeRunConfiguration.ciwtest + 3768 + false + true + false + false + true + + 78 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 18 + + + Version + 18 + + diff --git a/src/fetch/bibliosharefetcher.cpp b/src/fetch/bibliosharefetcher.cpp index d6cffb12..1033c244 100644 --- a/src/fetch/bibliosharefetcher.cpp +++ b/src/fetch/bibliosharefetcher.cpp @@ -1,210 +1,215 @@ /*************************************************************************** Copyright (C) 2011 Robby Stephenson ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 2 of * * the License or (at your option) version 3 or any later version * * accepted by the membership of KDE e.V. (or its successor approved * * by the membership of KDE e.V.), which shall act as a proxy * * defined in Section 14 of version 3 of the license. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * ***************************************************************************/ #include "bibliosharefetcher.h" #include "../utils/isbnvalidator.h" #include "../entry.h" #include "../images/imagefactory.h" #include "../images/imageinfo.h" #include "../tellico_debug.h" #include #include #include #include #include #include namespace { static const char* BIBLIOSHARE_BASE_URL = "http://www.biblioshare.org/BNCServices/BNCServices.asmx/"; static const char* BIBLIOSHARE_TOKEN = "nsnqwebh87kstlty"; } using namespace Tellico; using Tellico::Fetch::BiblioShareFetcher; BiblioShareFetcher::BiblioShareFetcher(QObject* parent_) : XMLFetcher(parent_) , m_token(QLatin1String(BIBLIOSHARE_TOKEN)) { setLimit(1); setXSLTFilename(QStringLiteral("biblioshare2tellico.xsl")); } BiblioShareFetcher::~BiblioShareFetcher() { } QString BiblioShareFetcher::source() const { return m_name.isEmpty() ? defaultName() : m_name; } +// https://www.booknetcanada.ca/get-a-token +QString BiblioShareFetcher::attribution() const { + return i18n("Data provided by BNC BiblioShare."); +} + bool BiblioShareFetcher::canFetch(int type) const { return type == Data::Collection::Book || type == Data::Collection::Bibtex; } void BiblioShareFetcher::readConfigHook(const KConfigGroup& config_) { QString k = config_.readEntry("Token", BIBLIOSHARE_TOKEN); if(!k.isEmpty()) { m_token = k; } } QUrl BiblioShareFetcher::searchUrl() { QUrl u(QString::fromLatin1(BIBLIOSHARE_BASE_URL)); u.setPath(u.path() + QStringLiteral("BiblioSimple")); QUrlQuery q; q.addQueryItem(QStringLiteral("Token"), m_token); switch(request().key) { case ISBN: { // only grab first value QString v = request().value.section(QLatin1Char(';'), 0); v = ISBNValidator::isbn13(v); v.remove(QLatin1Char('-')); q.addQueryItem(QStringLiteral("EAN"), v); } break; default: return QUrl(); } u.setQuery(q); // myDebug() << "url:" << u.url(); return u; } Tellico::Data::EntryPtr BiblioShareFetcher::fetchEntryHookData(Data::EntryPtr entry_) { Q_ASSERT(entry_); if(!entry_) { myWarning() << "no entry"; return entry_; } // if the entry cover is not set, go ahead and try to fetch it if(entry_->field(QStringLiteral("cover")).isEmpty()) { QString isbn = ISBNValidator::cleanValue(entry_->field(QStringLiteral("isbn"))); if(!isbn.isEmpty()) { isbn = ISBNValidator::isbn13(isbn); isbn.remove(QLatin1Char('-')); QUrl imageUrl(QString::fromLatin1(BIBLIOSHARE_BASE_URL)); imageUrl.setPath(imageUrl.path() + QStringLiteral("Images")); QUrlQuery q; q.addQueryItem(QStringLiteral("Token"), m_token); q.addQueryItem(QStringLiteral("EAN"), isbn); // the actual values for SAN Thumbnail don't seem to matter, they just can't be empty q.addQueryItem(QStringLiteral("SAN"), QStringLiteral("string")); q.addQueryItem(QStringLiteral("Thumbnail"), QStringLiteral("cover")); imageUrl.setQuery(q); const QString id = ImageFactory::addImage(imageUrl, true); if(!id.isEmpty()) { // placeholder images are 120x120 or 1x1 Data::ImageInfo info = ImageFactory::imageInfo(id); if((info.width() != 120 || info.height() != 120) && (info.width() != 1 || info.height() != 1)) { entry_->setField(QStringLiteral("cover"), id); } } } } return entry_; } Tellico::Fetch::FetchRequest BiblioShareFetcher::updateRequest(Data::EntryPtr entry_) { const QString isbn = entry_->field(QStringLiteral("isbn")); if(!isbn.isEmpty()) { return FetchRequest(Fetch::ISBN, isbn); } return FetchRequest(); } Tellico::Fetch::ConfigWidget* BiblioShareFetcher::configWidget(QWidget* parent_) const { return new BiblioShareFetcher::ConfigWidget(parent_, this); } QString BiblioShareFetcher::defaultName() { return QStringLiteral("BiblioShare"); } QString BiblioShareFetcher::defaultIcon() { - return favIcon("https://www.biblioshare.org"); + return favIcon("https://www.booknetcanada.ca/biblioshare"); } BiblioShareFetcher::ConfigWidget::ConfigWidget(QWidget* parent_, const BiblioShareFetcher* fetcher_) : Fetch::ConfigWidget(parent_) { QGridLayout* l = new QGridLayout(optionsWidget()); l->setSpacing(4); l->setColumnStretch(1, 10); int row = -1; QLabel* al = new QLabel(i18n("Registration is required for accessing the %1 data source. " "If you agree to the terms and conditions, sign " "up for an account, and enter your information below.", preferredName(), - QStringLiteral("http://www.booknetcanada.ca/biblioshare-web-services/#onixweb")), + QStringLiteral("https://www.booknetcanada.ca/get-a-token")), optionsWidget()); al->setOpenExternalLinks(true); al->setWordWrap(true); ++row; l->addWidget(al, row, 0, 1, 2); // richtext gets weird with size al->setMinimumWidth(al->sizeHint().width()); QLabel* label = new QLabel(i18n("Access key: "), optionsWidget()); l->addWidget(label, ++row, 0); m_tokenEdit = new QLineEdit(optionsWidget()); connect(m_tokenEdit, SIGNAL(textChanged(QString)), SLOT(slotSetModified())); l->addWidget(m_tokenEdit, row, 1); QString w = i18n("The default Tellico key may be used, but searching may fail due to reaching access limits."); label->setWhatsThis(w); m_tokenEdit->setWhatsThis(w); label->setBuddy(m_tokenEdit); l->setRowStretch(++row, 10); if(fetcher_) { // only show the key if it is not the default Tellico one... // that way the user is prompted to apply for their own if(fetcher_->m_token != QLatin1String(BIBLIOSHARE_TOKEN)) { m_tokenEdit->setText(fetcher_->m_token); } } } void BiblioShareFetcher::ConfigWidget::saveConfigHook(KConfigGroup& config_) { QString token = m_tokenEdit->text().trimmed(); if(!token.isEmpty()) { config_.writeEntry("Token", token); } } QString BiblioShareFetcher::ConfigWidget::preferredName() const { return BiblioShareFetcher::defaultName(); } diff --git a/src/fetch/bibliosharefetcher.h b/src/fetch/bibliosharefetcher.h index f548c956..a66ceda6 100644 --- a/src/fetch/bibliosharefetcher.h +++ b/src/fetch/bibliosharefetcher.h @@ -1,80 +1,81 @@ /*************************************************************************** Copyright (C) 2011 Robby Stephenson ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 2 of * * the License or (at your option) version 3 or any later version * * accepted by the membership of KDE e.V. (or its successor approved * * by the membership of KDE e.V.), which shall act as a proxy * * defined in Section 14 of version 3 of the license. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * ***************************************************************************/ #ifndef TELLICO_FETCH_BIBLIOSHAREFETCHER_H #define TELLICO_FETCH_BIBLIOSHAREFETCHER_H #include "xmlfetcher.h" #include "configwidget.h" class QLineEdit; namespace Tellico { namespace Fetch { /** * @author Robby Stephenson */ class BiblioShareFetcher : public XMLFetcher { Q_OBJECT public: BiblioShareFetcher(QObject* parent = nullptr); ~BiblioShareFetcher(); virtual QString source() const Q_DECL_OVERRIDE; + virtual QString attribution() const Q_DECL_OVERRIDE; virtual bool canSearch(FetchKey k) const Q_DECL_OVERRIDE { return k == ISBN; } virtual Type type() const Q_DECL_OVERRIDE { return BiblioShare; } virtual bool canFetch(int type) const Q_DECL_OVERRIDE; virtual void readConfigHook(const KConfigGroup& config) Q_DECL_OVERRIDE; virtual Fetch::ConfigWidget* configWidget(QWidget* parent) const Q_DECL_OVERRIDE; class ConfigWidget : public Fetch::ConfigWidget { public: explicit ConfigWidget(QWidget* parent_, const BiblioShareFetcher* fetcher = nullptr); virtual void saveConfigHook(KConfigGroup&) Q_DECL_OVERRIDE; virtual QString preferredName() const Q_DECL_OVERRIDE; private: QLineEdit* m_tokenEdit; }; friend class ConfigWidget; static QString defaultName(); static QString defaultIcon(); static StringHash allOptionalFields() { return StringHash(); } private: virtual FetchRequest updateRequest(Data::EntryPtr entry) Q_DECL_OVERRIDE; virtual void resetSearch() Q_DECL_OVERRIDE {} virtual QUrl searchUrl() Q_DECL_OVERRIDE; virtual void parseData(QByteArray&) Q_DECL_OVERRIDE {} virtual Data::EntryPtr fetchEntryHookData(Data::EntryPtr entry) Q_DECL_OVERRIDE; QString m_token; }; } } #endif diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 92465add..acce2459 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1,2384 +1,2384 @@ /*************************************************************************** Copyright (C) 2001-2014 Robby Stephenson Copyright (C) 2011 Pedro Miguel Carvalho ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 2 of * * the License or (at your option) version 3 or any later version * * accepted by the membership of KDE e.V. (or its successor approved * * by the membership of KDE e.V.), which shall act as a proxy * * defined in Section 14 of version 3 of the license. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * ***************************************************************************/ #include "mainwindow.h" #include "tellico_kernel.h" #include "document.h" #include "detailedlistview.h" #include "entryeditdialog.h" #include "groupview.h" #include "viewstack.h" #include "collection.h" #include "collectionfactory.h" #include "entry.h" #include "configdialog.h" #include "filter.h" #include "filterdialog.h" #include "collectionfieldsdialog.h" #include "controller.h" #include "importdialog.h" #include "exportdialog.h" #include "core/filehandler.h" // needed so static mainWindow variable can be set #include "translators/htmlexporter.h" // for printing #include "entryview.h" #include "entryiconview.h" #include "images/imagefactory.h" // needed so tmp files can get cleaned #include "collections/collectioninitializer.h" #include "collections/bibtexcollection.h" // needed for bibtex string macro dialog #include "utils/bibtexhandler.h" // needed for bibtex options #include "utils/datafileregistry.h" #include "fetchdialog.h" #include "reportdialog.h" #include "bibtexkeydialog.h" #include "core/tellico_strings.h" #include "filterview.h" #include "loanview.h" #include "fetch/fetchmanager.h" #include "fetch/fetcherinitializer.h" #include "cite/actionmanager.h" #include "config/tellico_config.h" #include "core/netaccess.h" #include "dbusinterface.h" #include "models/models.h" #include "models/entryiconmodel.h" #include "models/entryselectionmodel.h" #include "newstuff/manager.h" #include "gui/drophandler.h" #include "gui/stringmapdialog.h" #include "gui/lineedit.h" #include "gui/statusbar.h" #include "gui/tabwidget.h" #include "gui/dockwidget.h" #include "utils/cursorsaver.h" #include "utils/guiproxy.h" #include "tellico_debug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // needed for copy, cut, paste slots #include #include #include #include #include namespace { static const int MAIN_WINDOW_MIN_WIDTH = 600; static const int MAX_IMAGES_WARN_PERFORMANCE = 200; QIcon mimeIcon(const char* s) { QMimeDatabase db; QMimeType ptr = db.mimeTypeForName(QLatin1String(s)); if(!ptr.isValid()) { myDebug() << "*** no icon for" << s; } return ptr.isValid() ? QIcon::fromTheme(ptr.iconName()) : QIcon(); } QIcon mimeIcon(const char* s1, const char* s2) { QMimeDatabase db; QMimeType ptr = db.mimeTypeForName(QLatin1String(s1)); if(!ptr.isValid()) { ptr = db.mimeTypeForName(QLatin1String(s2)); if(!ptr.isValid()) { myDebug() << "*** no icon for" << s1 << "or" << s2; } } return ptr.isValid() ? QIcon::fromTheme(ptr.iconName()) : QIcon(); } } using namespace Tellico; using Tellico::MainWindow; MainWindow::MainWindow(QWidget* parent_/*=0*/) : KXmlGuiWindow(parent_), m_updateAll(nullptr), m_statusBar(nullptr), m_editDialog(nullptr), m_groupView(nullptr), m_filterView(nullptr), m_loanView(nullptr), m_configDlg(nullptr), m_filterDlg(nullptr), m_collFieldsDlg(nullptr), m_stringMacroDlg(nullptr), m_bibtexKeyDlg(nullptr), m_fetchDlg(nullptr), m_reportDlg(nullptr), m_queuedFilters(0), m_initialized(false), m_newDocument(true), m_dontQueueFilter(false), m_savingImageLocationChange(false) { Controller::init(this); // the only time this is ever called! // has to be after controller init Kernel::init(this); // the only time this is ever called! GUI::Proxy::setMainWidget(this); setWindowIcon(QIcon::fromTheme(QStringLiteral("tellico"), QIcon(QLatin1String(":/icons/tellico")))); // initialize the status bar and progress bar initStatusBar(); // initialize all the collection types // which must be done before the document is created CollectionInitializer initCollections; // register all the fetcher types Fetch::FetcherInitializer initFetchers; // create a document, which also creates an empty book collection // must be done before the different widgets are created initDocument(); // set up all the actions, some connect to the document, so this must be after initDocument() initActions(); // create the different widgets in the view, some widgets connect to actions, so must be after initActions() initView(); // The edit dialog is not created until after the main window is initialized, so it can be a child. // So don't make any connections, don't read options for it until initFileOpen readOptions(); setAcceptDrops(true); DropHandler* drophandler = new DropHandler(this); installEventFilter(drophandler); new ApplicationInterface(this); new CollectionInterface(this); MARK_LINE; QTimer::singleShot(0, this, SLOT(slotInit())); } MainWindow::~MainWindow() { qDeleteAll(m_fetchActions); m_fetchActions.clear(); } void MainWindow::slotInit() { MARK; // if the edit dialog exists, we know we've already called this function if(m_editDialog) { return; } m_editDialog = new EntryEditDialog(this); Controller::self()->addObserver(m_editDialog); m_toggleEntryEditor->setChecked(Config::showEditWidget()); slotToggleEntryEditor(); - slotToggleLayoutLock(Config::lockLayout()); + m_lockLayout->setActive(Config::lockLayout()); initConnections(); connect(ImageFactory::self(), SIGNAL(imageLocationMismatch()), SLOT(slotImageLocationMismatch())); // Init DBUS NewStuff::Manager::self(); } void MainWindow::initStatusBar() { MARK; m_statusBar = new Tellico::StatusBar(this); setStatusBar(m_statusBar); } void MainWindow::initActions() { MARK; /************************************************* * File->New menu *************************************************/ QSignalMapper* collectionMapper = new QSignalMapper(this); connect(collectionMapper, SIGNAL(mapped(int)), this, SLOT(slotFileNew(int))); KActionMenu* fileNewMenu = new KActionMenu(i18n("New"), this); fileNewMenu->setIcon(QIcon::fromTheme(QStringLiteral("document-new"))); fileNewMenu->setToolTip(i18n("Create a new collection")); fileNewMenu->setDelayed(false); actionCollection()->addAction(QStringLiteral("file_new_collection"), fileNewMenu); QAction* action; #define COLL_ACTION(TYPE, NAME, TEXT, TIP, ICON) \ action = actionCollection()->addAction(QStringLiteral(NAME), collectionMapper, SLOT(map())); \ action->setText(TEXT); \ action->setToolTip(TIP); \ action->setIcon(QIcon(QStringLiteral(":/icons/" ICON))); \ fileNewMenu->addAction(action); \ collectionMapper->setMapping(action, Data::Collection::TYPE); COLL_ACTION(Book, "new_book_collection", i18n("New &Book Collection"), i18n("Create a new book collection"), "book"); COLL_ACTION(Bibtex, "new_bibtex_collection", i18n("New B&ibliography"), i18n("Create a new bibtex bibliography"), "bibtex"); COLL_ACTION(ComicBook, "new_comic_book_collection", i18n("New &Comic Book Collection"), i18n("Create a new comic book collection"), "comic"); COLL_ACTION(Video, "new_video_collection", i18n("New &Video Collection"), i18n("Create a new video collection"), "video"); COLL_ACTION(Album, "new_music_collection", i18n("New &Music Collection"), i18n("Create a new music collection"), "album"); COLL_ACTION(Coin, "new_coin_collection", i18n("New C&oin Collection"), i18n("Create a new coin collection"), "coin"); COLL_ACTION(Stamp, "new_stamp_collection", i18n("New &Stamp Collection"), i18n("Create a new stamp collection"), "stamp"); COLL_ACTION(Card, "new_card_collection", i18n("New C&ard Collection"), i18n("Create a new trading card collection"), "card"); COLL_ACTION(Wine, "new_wine_collection", i18n("New &Wine Collection"), i18n("Create a new wine collection"), "wine"); COLL_ACTION(Game, "new_game_collection", i18n("New &Game Collection"), i18n("Create a new game collection"), "game"); COLL_ACTION(BoardGame, "new_boardgame_collection", i18n("New Boa&rd Game Collection"), i18n("Create a new board game collection"), "boardgame"); COLL_ACTION(File, "new_file_catalog", i18n("New &File Catalog"), i18n("Create a new file catalog"), "file"); action = actionCollection()->addAction(QStringLiteral("new_custom_collection"), collectionMapper, SLOT(map())); action->setText(i18n("New C&ustom Collection")); action->setToolTip(i18n("Create a new custom collection")); action->setIcon(QIcon::fromTheme(QStringLiteral("document-new"))); fileNewMenu->addAction(action); collectionMapper->setMapping(action, Data::Collection::Base); #undef COLL_ACTION /************************************************* * File menu *************************************************/ action = KStandardAction::open(this, SLOT(slotFileOpen()), actionCollection()); action->setToolTip(i18n("Open an existing document")); m_fileOpenRecent = KStandardAction::openRecent(this, SLOT(slotFileOpenRecent(const QUrl&)), actionCollection()); m_fileOpenRecent->setToolTip(i18n("Open a recently used file")); m_fileSave = KStandardAction::save(this, SLOT(slotFileSave()), actionCollection()); m_fileSave->setToolTip(i18n("Save the document")); action = KStandardAction::saveAs(this, SLOT(slotFileSaveAs()), actionCollection()); action->setToolTip(i18n("Save the document as a different file...")); action = KStandardAction::print(this, SLOT(slotFilePrint()), actionCollection()); { KHTMLPart w; // KHTMLPart printing was broken in KDE until KHTML 5.16 const QString version = w.componentData().version(); const uint major = version.section(QLatin1Char('.'), 0, 0).toUInt(); const uint minor = version.section(QLatin1Char('.'), 1, 1).toUInt(); if(major == 5 && minor < 16) { myWarning() << "Printing is broken for KDE Frameworks < 5.16. Please upgrade"; action->setEnabled(false); } } action->setToolTip(i18n("Print the contents of the document...")); action = KStandardAction::quit(this, SLOT(slotFileQuit()), actionCollection()); action->setToolTip(i18n("Quit the application")); /**************** Import Menu ***************************/ QSignalMapper* importMapper = new QSignalMapper(this); connect(importMapper, SIGNAL(mapped(int)), this, SLOT(slotFileImport(int))); KActionMenu* importMenu = new KActionMenu(i18n("&Import"), this); importMenu->setIcon(QIcon::fromTheme(QStringLiteral("document-import"))); importMenu->setToolTip(i18n("Import the collection data from other formats")); importMenu->setDelayed(false); actionCollection()->addAction(QStringLiteral("file_import"), importMenu); #define IMPORT_ACTION(TYPE, NAME, TEXT, TIP, ICON) \ action = actionCollection()->addAction(QStringLiteral(NAME), importMapper, SLOT(map())); \ action->setText(TEXT); \ action->setToolTip(TIP); \ action->setIcon(ICON); \ importMenu->addAction(action); \ importMapper->setMapping(action, TYPE); IMPORT_ACTION(Import::TellicoXML, "file_import_tellico", i18n("Import Tellico Data..."), i18n("Import another Tellico data file"), QIcon::fromTheme(QStringLiteral("tellico"), QIcon(QLatin1String(":/icons/tellico")))); IMPORT_ACTION(Import::CSV, "file_import_csv", i18n("Import CSV Data..."), i18n("Import a CSV file"), mimeIcon("text/csv", "text/x-csv")); IMPORT_ACTION(Import::MODS, "file_import_mods", i18n("Import MODS Data..."), i18n("Import a MODS data file"), mimeIcon("text/xml")); IMPORT_ACTION(Import::Alexandria, "file_import_alexandria", i18n("Import Alexandria Data..."), i18n("Import data from the Alexandria book collection manager"), QIcon::fromTheme(QStringLiteral("alexandria"), QIcon(QLatin1String(":/icons/alexandria")))); IMPORT_ACTION(Import::Delicious, "file_import_delicious", i18n("Import Delicious Library Data..."), i18n("Import data from Delicious Library"), QIcon::fromTheme(QStringLiteral("deliciouslibrary"), QIcon(QLatin1String(":/icons/deliciouslibrary")))); IMPORT_ACTION(Import::Referencer, "file_import_referencer", i18n("Import Referencer Data..."), i18n("Import data from Referencer"), QIcon::fromTheme(QStringLiteral("referencer"), QIcon(QLatin1String(":/icons/referencer")))); IMPORT_ACTION(Import::Bibtex, "file_import_bibtex", i18n("Import Bibtex Data..."), i18n("Import a bibtex bibliography file"), mimeIcon("text/x-bibtex")); IMPORT_ACTION(Import::Bibtexml, "file_import_bibtexml", i18n("Import Bibtexml Data..."), i18n("Import a Bibtexml bibliography file"), mimeIcon("text/xml")); IMPORT_ACTION(Import::RIS, "file_import_ris", i18n("Import RIS Data..."), i18n("Import an RIS reference file"), QIcon::fromTheme(QStringLiteral(":/icons/cite"))); IMPORT_ACTION(Import::Goodreads, "file_import_goodreads", i18n("Import Goodreads Collection..."), i18n("Import a collection from Goodreads.com"), QIcon::fromTheme(QStringLiteral(":/icons/goodreads"))); IMPORT_ACTION(Import::PDF, "file_import_pdf", i18n("Import PDF File..."), i18n("Import a PDF file"), mimeIcon("application/pdf")); IMPORT_ACTION(Import::AudioFile, "file_import_audiofile", i18n("Import Audio File Metadata..."), i18n("Import meta-data from audio files"), mimeIcon("audio/mp3", "audio/x-mp3")); #ifndef HAVE_TAGLIB action->setEnabled(false); #endif IMPORT_ACTION(Import::FreeDB, "file_import_freedb", i18n("Import Audio CD Data..."), i18n("Import audio CD information"), mimeIcon("media/audiocd", "application/x-cda")); #if !defined (HAVE_KCDDB) && !defined (HAVE_KF5KCDDB) action->setEnabled(false); #endif IMPORT_ACTION(Import::GCstar, "file_import_gcstar", i18n("Import GCstar Data..."), i18n("Import a GCstar data file"), QIcon::fromTheme(QStringLiteral("gcstar"), QIcon(QLatin1String(":/icons/gcstar")))); IMPORT_ACTION(Import::Griffith, "file_import_griffith", i18n("Import Griffith Data..."), i18n("Import a Griffith database"), QIcon::fromTheme(QStringLiteral("griffith"), QIcon(QLatin1String(":/icons/griffith")))); IMPORT_ACTION(Import::AMC, "file_import_amc", i18n("Import Ant Movie Catalog Data..."), i18n("Import an Ant Movie Catalog data file"), QIcon::fromTheme(QStringLiteral("amc"), QIcon(QLatin1String(":/icons/amc")))); IMPORT_ACTION(Import::BoardGameGeek, "file_import_boardgamegeek", i18n("Import BoardGameGeek Collection..."), i18n("Import a collection from BoardGameGeek.com"), QIcon(QLatin1String(":/icons/boardgamegeek"))); IMPORT_ACTION(Import::VinoXML, "file_import_vinoxml", i18n("Import VinoXML..."), i18n("Import VinoXML data"), QIcon(QLatin1String(":/icons/vinoxml"))); IMPORT_ACTION(Import::FileListing, "file_import_filelisting", i18n("Import File Listing..."), i18n("Import information about files in a folder"), mimeIcon("inode/directory")); IMPORT_ACTION(Import::XSLT, "file_import_xslt", i18n("Import XSL Transform..."), i18n("Import using an XSL Transform"), mimeIcon("application/xslt+xml", "text/x-xslt")); #undef IMPORT_ACTION /**************** Export Menu ***************************/ QSignalMapper* exportMapper = new QSignalMapper(this); connect(exportMapper, SIGNAL(mapped(int)), this, SLOT(slotFileExport(int))); KActionMenu* exportMenu = new KActionMenu(i18n("&Export"), this); exportMenu->setIcon(QIcon::fromTheme(QStringLiteral("document-export"))); exportMenu->setToolTip(i18n("Export the collection data to other formats")); exportMenu->setDelayed(false); actionCollection()->addAction(QStringLiteral("file_export"), exportMenu); #define EXPORT_ACTION(TYPE, NAME, TEXT, TIP, ICON) \ action = actionCollection()->addAction(QStringLiteral(NAME), exportMapper, SLOT(map())); \ action->setText(TEXT); \ action->setToolTip(TIP); \ action->setIcon(ICON); \ exportMenu->addAction(action); \ exportMapper->setMapping(action, TYPE); EXPORT_ACTION(Export::TellicoXML, "file_export_xml", i18n("Export to XML..."), i18n("Export to a Tellico XML file"), QIcon::fromTheme(QStringLiteral("tellico"), QIcon(QStringLiteral(":/icons/tellico")))); EXPORT_ACTION(Export::TellicoZip, "file_export_zip", i18n("Export to Zip..."), i18n("Export to a Tellico Zip file"), QIcon::fromTheme(QStringLiteral("tellico"), QIcon(QStringLiteral(":/icons/tellico")))); EXPORT_ACTION(Export::HTML, "file_export_html", i18n("Export to HTML..."), i18n("Export to an HTML file"), mimeIcon("text/html")); EXPORT_ACTION(Export::CSV, "file_export_csv", i18n("Export to CSV..."), i18n("Export to a comma-separated values file"), mimeIcon("text/csv", "text/x-csv")); EXPORT_ACTION(Export::Alexandria, "file_export_alexandria", i18n("Export to Alexandria..."), i18n("Export to an Alexandria library"), QIcon::fromTheme(QStringLiteral("alexandria"), QIcon(QStringLiteral(":/icons/alexandria")))); EXPORT_ACTION(Export::Bibtex, "file_export_bibtex", i18n("Export to Bibtex..."), i18n("Export to a bibtex file"), mimeIcon("text/x-bibtex")); EXPORT_ACTION(Export::Bibtexml, "file_export_bibtexml", i18n("Export to Bibtexml..."), i18n("Export to a Bibtexml file"), mimeIcon("text/xml")); EXPORT_ACTION(Export::ONIX, "file_export_onix", i18n("Export to ONIX..."), i18n("Export to an ONIX file"), mimeIcon("text/xml")); EXPORT_ACTION(Export::GCstar, "file_export_gcstar", i18n("Export to GCstar..."), i18n("Export to a GCstar data file"), QIcon::fromTheme(QStringLiteral("gcstar"), QIcon(QStringLiteral(":/icons/gcstar")))); EXPORT_ACTION(Export::XSLT, "file_export_xslt", i18n("Export XSL Transform..."), i18n("Export using an XSL Transform"), mimeIcon("application/xslt+xml", "text/x-xslt")); #undef EXPORT_ACTION /************************************************* * Edit menu *************************************************/ KStandardAction::undo(Kernel::self()->commandHistory(), SLOT(undo()), actionCollection()); KStandardAction::redo(Kernel::self()->commandHistory(), SLOT(undo()), actionCollection()); action = KStandardAction::cut(this, SLOT(slotEditCut()), actionCollection()); action->setToolTip(i18n("Cut the selected text and puts it in the clipboard")); action = KStandardAction::copy(this, SLOT(slotEditCopy()), actionCollection()); action->setToolTip(i18n("Copy the selected text to the clipboard")); action = KStandardAction::paste(this, SLOT(slotEditPaste()), actionCollection()); action->setToolTip(i18n("Paste the clipboard contents")); action = KStandardAction::selectAll(this, SLOT(slotEditSelectAll()), actionCollection()); action->setToolTip(i18n("Select all the entries in the collection")); action = KStandardAction::deselect(this, SLOT(slotEditDeselect()), actionCollection()); action->setToolTip(i18n("Deselect all the entries in the collection")); action = actionCollection()->addAction(QStringLiteral("edit_search_internet"), this, SLOT(slotShowFetchDialog())); action->setText(i18n("Internet Search...")); action->setIconText(i18n("Search")); // find a better word for this? action->setIcon(QIcon::fromTheme(QStringLiteral("tools-wizard"))); actionCollection()->setDefaultShortcut(action, Qt::CTRL + Qt::Key_I); action->setToolTip(i18n("Search the internet...")); action = actionCollection()->addAction(QStringLiteral("filter_dialog"), this, SLOT(slotShowFilterDialog())); action->setText(i18n("Advanced &Filter...")); action->setIconText(i18n("Filter")); action->setIcon(QIcon::fromTheme(QStringLiteral("view-filter"))); actionCollection()->setDefaultShortcut(action, Qt::CTRL + Qt::Key_J); action->setToolTip(i18n("Filter the collection")); /************************************************* * Collection menu *************************************************/ m_newEntry = actionCollection()->addAction(QStringLiteral("coll_new_entry"), this, SLOT(slotNewEntry())); m_newEntry->setText(i18n("&New Entry...")); m_newEntry->setIcon(QIcon::fromTheme(QStringLiteral("document-new"))); m_newEntry->setIconText(i18n("New")); actionCollection()->setDefaultShortcut(m_newEntry, Qt::CTRL + Qt::Key_N); m_newEntry->setToolTip(i18n("Create a new entry")); m_editEntry = actionCollection()->addAction(QStringLiteral("coll_edit_entry"), this, SLOT(slotShowEntryEditor())); m_editEntry->setText(i18n("&Edit Entry...")); m_editEntry->setIcon(QIcon::fromTheme(QStringLiteral("document-properties"))); actionCollection()->setDefaultShortcut(m_editEntry, Qt::CTRL + Qt::Key_E); m_editEntry->setToolTip(i18n("Edit the selected entries")); m_copyEntry = actionCollection()->addAction(QStringLiteral("coll_copy_entry"), Controller::self(), SLOT(slotCopySelectedEntries())); m_copyEntry->setText(i18n("D&uplicate Entry")); m_copyEntry->setIcon(QIcon::fromTheme(QStringLiteral("edit-copy"))); actionCollection()->setDefaultShortcut(m_copyEntry, Qt::CTRL + Qt::Key_Y); m_copyEntry->setToolTip(i18n("Copy the selected entries")); m_deleteEntry = actionCollection()->addAction(QStringLiteral("coll_delete_entry"), Controller::self(), SLOT(slotDeleteSelectedEntries())); m_deleteEntry->setText(i18n("&Delete Entry")); m_deleteEntry->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete"))); actionCollection()->setDefaultShortcut(m_deleteEntry, Qt::CTRL + Qt::Key_D); m_deleteEntry->setToolTip(i18n("Delete the selected entries")); m_mergeEntry = actionCollection()->addAction(QStringLiteral("coll_merge_entry"), Controller::self(), SLOT(slotMergeSelectedEntries())); m_mergeEntry->setText(i18n("&Merge Entries")); m_mergeEntry->setIcon(QIcon::fromTheme(QStringLiteral("document-import"))); // CTRL+G is ambiguous, pick another // actionCollection()->setDefaultShortcut(m_mergeEntry, Qt::CTRL + Qt::Key_G); m_mergeEntry->setToolTip(i18n("Merge the selected entries")); m_mergeEntry->setEnabled(false); // gets enabled when more than 1 entry is selected m_checkOutEntry = actionCollection()->addAction(QStringLiteral("coll_checkout"), Controller::self(), SLOT(slotCheckOut())); m_checkOutEntry->setText(i18n("Check-&out...")); m_checkOutEntry->setIcon(QIcon::fromTheme(QStringLiteral("arrow-up-double"))); m_checkOutEntry->setToolTip(i18n("Check-out the selected items")); m_checkInEntry = actionCollection()->addAction(QStringLiteral("coll_checkin"), Controller::self(), SLOT(slotCheckIn())); m_checkInEntry->setText(i18n("Check-&in")); m_checkInEntry->setIcon(QIcon::fromTheme(QStringLiteral("arrow-down-double"))); m_checkInEntry->setToolTip(i18n("Check-in the selected items")); action = actionCollection()->addAction(QStringLiteral("coll_rename_collection"), this, SLOT(slotRenameCollection())); action->setText(i18n("&Rename Collection...")); action->setIcon(QIcon::fromTheme(QStringLiteral("edit-rename"))); actionCollection()->setDefaultShortcut(action, Qt::CTRL + Qt::Key_R); action->setToolTip(i18n("Rename the collection")); action = actionCollection()->addAction(QStringLiteral("coll_fields"), this, SLOT(slotShowCollectionFieldsDialog())); action->setText(i18n("Collection &Fields...")); action->setIconText(i18n("Fields")); action->setIcon(QIcon::fromTheme(QStringLiteral("preferences-other"))); actionCollection()->setDefaultShortcut(action, Qt::CTRL + Qt::Key_U); action->setToolTip(i18n("Modify the collection fields")); action = actionCollection()->addAction(QStringLiteral("coll_reports"), this, SLOT(slotShowReportDialog())); action->setText(i18n("&Generate Reports...")); action->setIconText(i18n("Reports")); action->setIcon(QIcon::fromTheme(QStringLiteral("text-rdf"))); action->setToolTip(i18n("Generate collection reports")); action = actionCollection()->addAction(QStringLiteral("coll_convert_bibliography"), this, SLOT(slotConvertToBibliography())); action->setText(i18n("Convert to &Bibliography")); action->setIcon(QIcon(QLatin1String(":/icons/bibtex"))); action->setToolTip(i18n("Convert a book collection to a bibliography")); action = actionCollection()->addAction(QStringLiteral("coll_string_macros"), this, SLOT(slotShowStringMacroDialog())); action->setText(i18n("String &Macros...")); action->setIcon(QIcon::fromTheme(QStringLiteral("view-list-text"))); action->setToolTip(i18n("Edit the bibtex string macros")); action = actionCollection()->addAction(QStringLiteral("coll_key_manager"), this, SLOT(slotShowBibtexKeyDialog())); action->setText(i18n("Check for Duplicate Keys...")); action->setIcon(mimeIcon("text/x-bibtex")); action->setToolTip(i18n("Check for duplicate citation keys")); QSignalMapper* citeMapper = new QSignalMapper(this); connect(citeMapper, SIGNAL(mapped(int)), this, SLOT(slotCiteEntry(int))); action = actionCollection()->addAction(QStringLiteral("cite_clipboard"), citeMapper, SLOT(map())); action->setText(i18n("Copy Bibtex to Cli&pboard")); action->setToolTip(i18n("Copy bibtex citations to the clipboard")); action->setIcon(QIcon::fromTheme(QStringLiteral("edit-paste"))); citeMapper->setMapping(action, Cite::CiteClipboard); action = actionCollection()->addAction(QStringLiteral("cite_lyxpipe"), citeMapper, SLOT(map())); action->setText(i18n("Cite Entry in &LyX")); action->setToolTip(i18n("Cite the selected entries in LyX")); action->setIcon(QIcon::fromTheme(QStringLiteral("lyx"), QIcon(QLatin1String(":/icons/lyx")))); citeMapper->setMapping(action, Cite::CiteLyxpipe); m_updateMapper = new QSignalMapper(this); connect(m_updateMapper, SIGNAL(mapped(const QString&)), Controller::self(), SLOT(slotUpdateSelectedEntries(const QString&))); m_updateEntryMenu = new KActionMenu(i18n("&Update Entry"), this); m_updateEntryMenu->setIcon(QIcon::fromTheme(QStringLiteral("document-export"))); m_updateEntryMenu->setIconText(i18nc("Update Entry", "Update")); m_updateEntryMenu->setDelayed(false); actionCollection()->addAction(QStringLiteral("coll_update_entry"), m_updateEntryMenu); m_updateAll = actionCollection()->addAction(QStringLiteral("update_entry_all"), m_updateMapper, SLOT(map())); m_updateAll->setText(i18n("All Sources")); m_updateAll->setToolTip(i18n("Update entry data from all available sources")); m_updateMapper->setMapping(m_updateAll, QStringLiteral("_all")); /************************************************* * Settings menu *************************************************/ setStandardToolBarMenuEnabled(true); createStandardStatusBarAction(); - KDualAction* dualAction = new KDualAction(this); - connect(dualAction, SIGNAL(activeChanged(bool)), SLOT(slotToggleLayoutLock(bool))); - dualAction->setActiveText(i18n("Unlock Layout")); - dualAction->setActiveToolTip(i18n("Unlock the window's layout")); - dualAction->setActiveIcon(QIcon::fromTheme(QStringLiteral("object-unlocked"))); - dualAction->setInactiveText(i18n("Lock Layout")); - dualAction->setInactiveToolTip(i18n("Lock the window's layout")); - dualAction->setInactiveIcon(QIcon::fromTheme(QStringLiteral("object-locked"))); - actionCollection()->addAction(QStringLiteral("lock_layout"), dualAction); + m_lockLayout = new KDualAction(this); + connect(m_lockLayout, SIGNAL(activeChanged(bool)), SLOT(slotToggleLayoutLock(bool))); + m_lockLayout->setActiveText(i18n("Unlock Layout")); + m_lockLayout->setActiveToolTip(i18n("Unlock the window's layout")); + m_lockLayout->setActiveIcon(QIcon::fromTheme(QStringLiteral("object-unlocked"))); + m_lockLayout->setInactiveText(i18n("Lock Layout")); + m_lockLayout->setInactiveToolTip(i18n("Lock the window's layout")); + m_lockLayout->setInactiveIcon(QIcon::fromTheme(QStringLiteral("object-locked"))); + actionCollection()->addAction(QStringLiteral("lock_layout"), m_lockLayout); action = actionCollection()->addAction(QStringLiteral("reset_layout"), this, SLOT(slotResetLayout())); action->setText(i18n("Reset Layout")); action->setToolTip(i18n("Reset the window's layout")); action->setIcon(QIcon::fromTheme(QStringLiteral("resetview"))); m_toggleEntryEditor = new KToggleAction(i18n("Entry &Editor"), this); connect(m_toggleEntryEditor, SIGNAL(triggered()), SLOT(slotToggleEntryEditor())); m_toggleEntryEditor->setToolTip(i18n("Enable/disable the editor")); actionCollection()->addAction(QStringLiteral("toggle_edit_widget"), m_toggleEntryEditor); KStandardAction::preferences(this, SLOT(slotShowConfigDialog()), actionCollection()); /************************************************* * Help menu *************************************************/ KStandardAction::tipOfDay(this, SLOT(slotShowTipOfDay()), actionCollection()); /************************************************* * Short cuts *************************************************/ KStandardAction::fullScreen(this, SLOT(slotToggleFullScreen()), this, actionCollection()); KStandardAction::showMenubar(this, SLOT(slotToggleMenuBarVisibility()), actionCollection()); /************************************************* * Collection Toolbar *************************************************/ action = actionCollection()->addAction(QStringLiteral("change_entry_grouping_accel"), this, SLOT(slotGroupLabelActivated())); action->setText(i18n("Change Grouping")); actionCollection()->setDefaultShortcut(action, Qt::CTRL + Qt::Key_G); m_entryGrouping = new KSelectAction(i18n("&Group Selection"), this); m_entryGrouping->setToolTip(i18n("Change the grouping of the collection")); // really bad hack, but I can't figure out how to make the combobox resize when the contents change // see note in slotUpdateCollectionToolBar() - found a hackier solution // m_entryGrouping->addAction(QString(50, QLatin1Char(' '))); connect(m_entryGrouping, SIGNAL(triggered(int)), SLOT(slotChangeGrouping())); actionCollection()->addAction(QStringLiteral("change_entry_grouping"), m_entryGrouping); action = actionCollection()->addAction(QStringLiteral("quick_filter_accel"), this, SLOT(slotFilterLabelActivated())); action->setText(i18n("Filter")); actionCollection()->setDefaultShortcut(action, Qt::CTRL + Qt::Key_F); m_quickFilter = new GUI::LineEdit(this); m_quickFilter->setPlaceholderText(i18n("Filter here...")); // same text as kdepim and amarok m_quickFilter->setClearButtonEnabled(true); // same as Dolphin text edit m_quickFilter->setMinimumWidth(150); m_quickFilter->setMaximumWidth(300); // want to update every time the filter text changes connect(m_quickFilter, SIGNAL(textChanged(const QString&)), this, SLOT(slotQueueFilter())); connect(m_quickFilter, SIGNAL(clearButtonClicked()), this, SLOT(slotClearFilter())); m_quickFilter->installEventFilter(this); // intercept keyEvents QWidgetAction* widgetAction = new QWidgetAction(this); widgetAction->setDefaultWidget(m_quickFilter); widgetAction->setText(i18n("Filter")); widgetAction->setToolTip(i18n("Filter the collection")); widgetAction->setProperty("isShortcutConfigurable", false); actionCollection()->addAction(QStringLiteral("quick_filter"), widgetAction); // final GUI setup is in initView() } #undef mimeIcon void MainWindow::initDocument() { MARK; Data::Document* doc = Data::Document::self(); Kernel::self()->resetHistory(); KConfigGroup config(KSharedConfig::openConfig(), "General Options"); doc->setLoadAllImages(config.readEntry("Load All Images", false)); // allow status messages from the document connect(doc, SIGNAL(signalStatusMsg(const QString&)), SLOT(slotStatusMsg(const QString&))); // do stuff that changes when the doc is modified connect(doc, SIGNAL(signalModified(bool)), SLOT(slotEnableModifiedActions(bool))); connect(doc, SIGNAL(signalCollectionAdded(Tellico::Data::CollPtr)), Controller::self(), SLOT(slotCollectionAdded(Tellico::Data::CollPtr))); connect(doc, SIGNAL(signalCollectionDeleted(Tellico::Data::CollPtr)), Controller::self(), SLOT(slotCollectionDeleted(Tellico::Data::CollPtr))); connect(Kernel::self()->commandHistory(), SIGNAL(cleanChanged(bool)), doc, SLOT(slotSetClean(bool))); } void MainWindow::initView() { MARK; // initialize the image factory before the entry models are created ImageFactory::init(); m_entryView = new EntryView(this); connect(m_entryView, SIGNAL(signalAction(const QUrl&)), SLOT(slotURLAction(const QUrl&))); m_entryView->view()->setWhatsThis(i18n("The Entry View shows a formatted view of the entry's contents.")); // trick to make sure the group views always extend along the entire left or right side // using QMainWindow::setCorner does not seem to work // https://wiki.qt.io/Technical_FAQ#Is_it_possible_for_either_the_left_or_right_dock_areas_to_have_full_height_of_their_side_rather_than_having_the_bottom_take_the_full_width.3F m_dummyWindow = new QMainWindow(this); m_dummyWindow->setCentralWidget(m_entryView->view()); m_dummyWindow->setWindowFlags(Qt::Widget); setCentralWidget(m_dummyWindow); m_collectionViewDock = new GUI::DockWidget(i18n("Collection View"), m_dummyWindow); m_collectionViewDock->setObjectName(QStringLiteral("collection_dock")); m_viewStack = new ViewStack(this); m_detailedView = m_viewStack->listView(); Controller::self()->addObserver(m_detailedView); m_detailedView->setWhatsThis(i18n("The Column View shows the value of multiple fields " "for each entry.")); connect(Data::Document::self(), SIGNAL(signalCollectionImagesLoaded(Tellico::Data::CollPtr)), m_detailedView, SLOT(slotRefreshImages())); m_iconView = m_viewStack->iconView(); EntryIconModel* iconModel = new EntryIconModel(m_iconView); iconModel->setSourceModel(m_detailedView->model()); m_iconView->setModel(iconModel); Controller::self()->addObserver(m_iconView); m_iconView->setWhatsThis(i18n("The Icon View shows each entry in the collection or group using " "an icon, which may be an image in the entry.")); m_collectionViewDock->setWidget(m_viewStack); m_dummyWindow->addDockWidget(Qt::TopDockWidgetArea, m_collectionViewDock); actionCollection()->addAction(QStringLiteral("toggle_column_widget"), m_collectionViewDock->toggleViewAction()); m_groupViewDock = new GUI::DockWidget(i18n("Group View"), this); m_groupViewDock->setObjectName(QStringLiteral("group_dock")); m_groupViewDock->setAllowedAreas(Qt::DockWidgetAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea)); m_viewTabs = new GUI::TabWidget(this); m_viewTabs->setTabBarHidden(true); m_viewTabs->setDocumentMode(true); m_groupView = new GroupView(m_viewTabs); Controller::self()->addObserver(m_groupView); m_viewTabs->addTab(m_groupView, QIcon::fromTheme(QStringLiteral("folder")), i18n("Groups")); m_groupView->setWhatsThis(i18n("The Group View sorts the entries into groupings " "based on a selected field.")); m_groupViewDock->setWidget(m_viewTabs); addDockWidget(Qt::LeftDockWidgetArea, m_groupViewDock); actionCollection()->addAction(QStringLiteral("toggle_group_widget"), m_groupViewDock->toggleViewAction()); EntrySelectionModel* proxySelect = new EntrySelectionModel(m_iconView->model(), m_detailedView->selectionModel(), this); m_iconView->setSelectionModel(proxySelect); setMinimumWidth(MAIN_WINDOW_MIN_WIDTH); // setting up GUI now rather than in initActions setupGUI(Keys | ToolBar); createGUI(); } void MainWindow::initConnections() { // have to toggle the menu item if the dialog gets closed connect(m_editDialog, SIGNAL(finished(int)), this, SLOT(slotEditDialogFinished())); EntrySelectionModel* proxySelect = static_cast(m_iconView->selectionModel()); connect(proxySelect, SIGNAL(entriesSelected(Tellico::Data::EntryList)), Controller::self(), SLOT(slotUpdateSelection(Tellico::Data::EntryList))); connect(proxySelect, SIGNAL(entriesSelected(Tellico::Data::EntryList)), m_editDialog, SLOT(setContents(Tellico::Data::EntryList))); connect(proxySelect, SIGNAL(entriesSelected(Tellico::Data::EntryList)), m_entryView, SLOT(showEntries(Tellico::Data::EntryList))); // let the group view call filters, too connect(m_groupView, SIGNAL(signalUpdateFilter(Tellico::FilterPtr)), this, SLOT(slotUpdateFilter(Tellico::FilterPtr))); // use the EntrySelectionModel as a proxy so when entries get selected in the group view // the edit dialog and entry view are updated proxySelect->addSelectionProxy(m_groupView->selectionModel()); } void MainWindow::initFileOpen(bool nofile_) { MARK; slotInit(); // check to see if most recent file should be opened bool happyStart = false; if(!nofile_ && Config::reopenLastFile()) { // Config::lastOpenFile() is the full URL, protocol included QUrl lastFile(Config::lastOpenFile()); // empty string is actually ok, it gets handled if(!lastFile.isEmpty() && lastFile.isValid()) { slotFileOpen(lastFile); happyStart = true; } } if(!happyStart) { // the document is created with an initial book collection, continue with that Controller::self()->slotCollectionAdded(Data::Document::self()->collection()); m_fileSave->setEnabled(false); slotEnableOpenedActions(); slotEnableModifiedActions(false); slotEntryCount(); // tell the entry views and models that there are no images to load m_detailedView->slotRefreshImages(); } // show welcome text, even when opening an existing collection const int type = Kernel::self()->collectionType(); QString welcomeFile = DataFileRegistry::self()->locate(QStringLiteral("welcome.html")); QString text = FileHandler::readTextFile(QUrl::fromLocalFile(welcomeFile)); text.replace(QLatin1String("$FGCOLOR$"), Config::templateTextColor(type).name()); text.replace(QLatin1String("$BGCOLOR$"), Config::templateBaseColor(type).name()); text.replace(QLatin1String("$COLOR1$"), Config::templateHighlightedTextColor(type).name()); text.replace(QLatin1String("$COLOR2$"), Config::templateHighlightedBaseColor(type).name()); text.replace(QLatin1String("$IMGDIR$"), QUrl::fromLocalFile(ImageFactory::tempDir()).url()); text.replace(QLatin1String("$BANNER$"), i18n("Welcome to the Tellico Collection Manager")); text.replace(QLatin1String("$WELCOMETEXT$"), i18n("

Tellico is a tool for managing collections of books, " "videos, music, and whatever else you want to catalog.

" "

New entries can be added to your collection by " "entering data manually or by " "downloading data from " "various Internet sources.

")); m_entryView->showText(text); m_initialized = true; } // These are general options. // The options that can be changed in the "Configuration..." dialog // are taken care of by the ConfigDialog object. void MainWindow::saveOptions() { KConfigGroup config(KSharedConfig::openConfig(), "Main Window Options"); saveMainWindowSettings(config); config.writeEntry(QStringLiteral("Central Dock State"), m_dummyWindow->saveState()); Config::setShowEditWidget(m_toggleEntryEditor->isChecked()); // check any single dock widget, they all get locked together Config::setLockLayout(m_groupViewDock->isLocked()); KConfigGroup filesConfig(KSharedConfig::openConfig(), "Recent Files"); m_fileOpenRecent->saveEntries(filesConfig); if(!isNewDocument()) { Config::setLastOpenFile(Data::Document::self()->URL().url()); } Config::setViewWidget(m_viewStack->currentWidget()); // historical reasons // sorting by count was faked by sorting by phantom second column const int sortColumn = m_groupView->sortRole() == RowCountRole ? 1 : 0; Config::setGroupViewSortColumn(sortColumn); // ok to use SortColumn key, save semantics Config::setGroupViewSortAscending(m_groupView->sortOrder() == Qt::AscendingOrder); if(m_loanView) { const int sortColumn = m_loanView->sortRole() == RowCountRole ? 1 : 0; Config::setLoanViewSortAscending(sortColumn); // ok to use SortColumn key, save semantics Config::setLoanViewSortAscending(m_loanView->sortOrder() == Qt::AscendingOrder); } if(m_filterView) { const int sortColumn = m_filterView->sortRole() == RowCountRole ? 1 : 0; Config::setFilterViewSortAscending(sortColumn); // ok to use SortColumn key, save semantics Config::setFilterViewSortAscending(m_filterView->sortOrder() == Qt::AscendingOrder); } // this is used in the EntryEditDialog constructor, too KConfigGroup editDialogConfig(KSharedConfig::openConfig(), "Edit Dialog Options"); KWindowConfig::saveWindowSize(m_editDialog->windowHandle(), editDialogConfig); saveCollectionOptions(Data::Document::self()->collection()); Config::self()->save(); } void MainWindow::readCollectionOptions(Tellico::Data::CollPtr coll_) { if(!coll_) { myDebug() << "Bad, no collection in MainWindow::readCollectionOptions()"; return; } const QString configGroup = QStringLiteral("Options - %1").arg(CollectionFactory::typeName(coll_)); KConfigGroup group(KSharedConfig::openConfig(), configGroup); QString defaultGroup = coll_->defaultGroupField(); QString entryGroup; if(coll_->type() != Data::Collection::Base) { entryGroup = group.readEntry("Group By", defaultGroup); } else { QUrl url = Kernel::self()->URL(); for(int i = 0; i < Config::maxCustomURLSettings(); ++i) { QUrl u(group.readEntry(QStringLiteral("URL_%1").arg(i))); if(url == u) { entryGroup = group.readEntry(QStringLiteral("Group By_%1").arg(i), defaultGroup); break; } } // fall back to old setting if(entryGroup.isEmpty()) { entryGroup = group.readEntry("Group By", defaultGroup); } } if(entryGroup.isEmpty() || (!coll_->entryGroups().contains(entryGroup) && entryGroup != Data::Collection::s_peopleGroupName)) { entryGroup = defaultGroup; } m_groupView->setGroupField(entryGroup); QString entryXSLTFile = Config::templateName(coll_->type()); if(entryXSLTFile.isEmpty()) { entryXSLTFile = QStringLiteral("Fancy"); // should never happen, but just in case } m_entryView->setXSLTFile(entryXSLTFile + QLatin1String(".xsl")); // make sure the right combo element is selected slotUpdateCollectionToolBar(coll_); } void MainWindow::saveCollectionOptions(Tellico::Data::CollPtr coll_) { // don't save initial collection options, or empty collections if(!coll_ || coll_->entryCount() == 0 || isNewDocument()) { return; } int configIndex = -1; QString configGroup = QStringLiteral("Options - %1").arg(CollectionFactory::typeName(coll_)); KConfigGroup config(KSharedConfig::openConfig(), configGroup); QString groupName; if(m_entryGrouping->currentItem() > -1 && static_cast(coll_->entryGroups().count()) > m_entryGrouping->currentItem()) { if(m_entryGrouping->currentText() == (QLatin1Char('<') + i18n("People") + QLatin1Char('>'))) { groupName = Data::Collection::s_peopleGroupName; } else { groupName = Kernel::self()->fieldNameByTitle(m_entryGrouping->currentText()); } if(coll_->type() != Data::Collection::Base) { config.writeEntry("Group By", groupName); } } if(coll_->type() == Data::Collection::Base) { // all of this is to have custom settings on a per file basis QUrl url = Kernel::self()->URL(); QList urls = QList() << url; QStringList groupBys = QStringList() << groupName; for(int i = 0; i < Config::maxCustomURLSettings(); ++i) { QUrl u = config.readEntry(QStringLiteral("URL_%1").arg(i), QUrl()); QString g = config.readEntry(QStringLiteral("Group By_%1").arg(i), QString()); if(!u.isEmpty() && url != u) { urls.append(u); groupBys.append(g); } else if(!u.isEmpty()) { configIndex = i; } } int limit = qMin(urls.count(), Config::maxCustomURLSettings()); for(int i = 0; i < limit; ++i) { config.writeEntry(QStringLiteral("URL_%1").arg(i), urls[i].url()); config.writeEntry(QStringLiteral("Group By_%1").arg(i), groupBys[i]); } } m_detailedView->saveConfig(coll_, configIndex); } void MainWindow::readOptions() { KConfigGroup mainWindowConfig(KSharedConfig::openConfig(), "Main Window Options"); applyMainWindowSettings(mainWindowConfig); m_dummyWindow->restoreState(mainWindowConfig.readEntry(QStringLiteral("Central Dock State"), QByteArray())); m_viewStack->setCurrentWidget(Config::viewWidget()); m_iconView->setMaxAllowedIconWidth(Config::maxIconSize()); connect(toolBar(QStringLiteral("collectionToolBar")), SIGNAL(iconSizeChanged(const QSize&)), SLOT(slotUpdateToolbarIcons())); // initialize the recent file list KConfigGroup filesConfig(KSharedConfig::openConfig(), "Recent Files"); m_fileOpenRecent->loadEntries(filesConfig); // sort by count if column = 1 int sortRole = Config::groupViewSortColumn() == 0 ? static_cast(Qt::DisplayRole) : static_cast(RowCountRole); Qt::SortOrder sortOrder = Config::groupViewSortAscending() ? Qt::AscendingOrder : Qt::DescendingOrder; m_groupView->setSorting(sortOrder, sortRole); BibtexHandler::s_quoteStyle = Config::useBraces() ? BibtexHandler::BRACES : BibtexHandler::QUOTES; // Don't read any options for the edit dialog here, since it's not yet initialized. // Put them in init() } bool MainWindow::querySaveModified() { bool completed = true; if(Data::Document::self()->isModified()) { QString str = i18n("The current file has been modified.\n" "Do you want to save it?"); int want_save = KMessageBox::warningYesNoCancel(this, str, i18n("Unsaved Changes"), KStandardGuiItem::save(), KStandardGuiItem::discard()); switch(want_save) { case KMessageBox::Yes: completed = fileSave(); break; case KMessageBox::No: Data::Document::self()->slotSetModified(false); completed = true; break; case KMessageBox::Cancel: default: completed = false; break; } } return completed; } bool MainWindow::queryClose() { // in case we're still loading the images, cancel that Data::Document::self()->cancelImageWriting(); const bool willClose = m_editDialog->queryModified() && querySaveModified(); if (willClose) { ImageFactory::clean(true); saveOptions(); } return willClose; } void MainWindow::slotFileNew(int type_) { slotStatusMsg(i18n("Creating new document...")); // close the fields dialog slotHideCollectionFieldsDialog(); if(m_editDialog->queryModified() && querySaveModified()) { // remove filter and loan tabs, they'll get re-added if needed if(m_filterView) { m_viewTabs->removeTab(m_viewTabs->indexOf(m_filterView)); Controller::self()->removeObserver(m_filterView); delete m_filterView; m_filterView = nullptr; } if(m_loanView) { m_viewTabs->removeTab(m_viewTabs->indexOf(m_loanView)); Controller::self()->removeObserver(m_loanView); delete m_loanView; m_loanView = nullptr; } m_viewTabs->setTabBarHidden(true); Data::Document::self()->newDocument(type_); Kernel::self()->resetHistory(); m_fileOpenRecent->setCurrentItem(-1); slotEnableOpenedActions(); slotEnableModifiedActions(false); m_newDocument = true; ImageFactory::clean(false); } StatusBar::self()->clearStatus(); } void MainWindow::slotFileOpen() { slotStatusMsg(i18n("Opening file...")); if(m_editDialog->queryModified() && querySaveModified()) { QString filter = i18n("Tellico Files") + QLatin1String(" (*.tc *.bc)"); filter += QLatin1String(";;"); filter += i18n("XML Files") + QLatin1String(" (*.xml)"); filter += QLatin1String(";;"); filter += i18n("All Files") + QLatin1String(" (*)"); // keyword 'open' QString fileClass; const QUrl startUrl = KFileWidget::getStartUrl(QUrl(QStringLiteral("kfiledialog:///open")), fileClass); QUrl url = QFileDialog::getOpenFileUrl(this, i18n("Open File"), startUrl, filter); if(!url.isEmpty() && url.isValid()) { slotFileOpen(url); if(url.isLocalFile()) { KRecentDirs::add(fileClass, url.adjusted(QUrl::RemoveFilename|QUrl::StripTrailingSlash).path()); } } } StatusBar::self()->clearStatus(); } void MainWindow::slotFileOpen(const QUrl& url_) { slotStatusMsg(i18n("Opening file...")); // close the fields dialog slotHideCollectionFieldsDialog(); // there seems to be a race condition at start between slotInit() and initFileOpen() // which means the edit dialog might not have been created yet if((!m_editDialog || m_editDialog->queryModified()) && querySaveModified()) { if(openURL(url_)) { m_fileOpenRecent->addUrl(url_); m_fileOpenRecent->setCurrentItem(-1); } } StatusBar::self()->clearStatus(); } void MainWindow::slotFileOpenRecent(const QUrl& url_) { slotStatusMsg(i18n("Opening file...")); // close the fields dialog slotHideCollectionFieldsDialog(); if(m_editDialog->queryModified() && querySaveModified()) { if(!openURL(url_)) { m_fileOpenRecent->removeUrl(url_); m_fileOpenRecent->setCurrentItem(-1); } } else { // the QAction shouldn't be checked now m_fileOpenRecent->setCurrentItem(-1); } StatusBar::self()->clearStatus(); } void MainWindow::openFile(const QString& file_) { QUrl url(file_); if(!url.isEmpty() && url.isValid()) { slotFileOpen(url); } } bool MainWindow::openURL(const QUrl& url_) { MARK; // try to open document GUI::CursorSaver cs(Qt::WaitCursor); bool success = Data::Document::self()->openDocument(url_); if(success) { Kernel::self()->resetHistory(); m_quickFilter->clear(); slotEnableOpenedActions(); m_newDocument = false; slotEnableModifiedActions(Data::Document::self()->isModified()); // doc might add some stuff } else if(!m_initialized) { // special case on startup when openURL() is called with a command line argument // and that URL can't be opened. The window still needs to be initialized // the doc object is created with an initial book collection, continue with that Controller::self()->slotCollectionAdded(Data::Document::self()->collection()); m_fileSave->setEnabled(false); slotEnableOpenedActions(); slotEnableModifiedActions(false); slotEntryCount(); } // slotFileOpen(URL) gets called when opening files on the command line // so go ahead and make sure m_initialized is set. m_initialized = true; // remove filter and loan tabs, they'll get re-added if needed if(m_filterView && m_filterView->isEmpty()) { m_viewTabs->removeTab(m_viewTabs->indexOf(m_filterView)); Controller::self()->removeObserver(m_filterView); delete m_filterView; m_filterView = nullptr; } if(m_loanView && m_loanView->isEmpty()) { m_viewTabs->removeTab(m_viewTabs->indexOf(m_loanView)); Controller::self()->removeObserver(m_loanView); delete m_loanView; m_loanView = nullptr; } Controller::self()->hideTabs(); // does conditional check return success; } void MainWindow::slotFileSave() { fileSave(); } bool MainWindow::fileSave() { if(!m_editDialog->queryModified()) { return false; } slotStatusMsg(i18n("Saving file...")); bool ret = true; if(isNewDocument()) { ret = fileSaveAs(); } else { // special check: if there are more than 200 images AND the "Write Images In File" config key // is set, then warn user that performance may suffer, and write result if(Config::imageLocation() == Config::ImagesInFile && Config::askWriteImagesInFile() && Data::Document::self()->imageCount() > MAX_IMAGES_WARN_PERFORMANCE) { QString msg = i18n("

You are saving a file with many images, which causes Tellico to " "slow down significantly. Do you want to save the images separately in " "Tellico's data directory to improve performance?

Your choice can " "always be changed in the configuration dialog.

"); KGuiItem yes(i18n("Save Images Separately")); KGuiItem no(i18n("Save Images in File")); int res = KMessageBox::warningYesNo(this, msg, QString() /* caption */, yes, no); if(res == KMessageBox::No) { Config::setImageLocation(Config::ImagesInAppDir); } Config::setAskWriteImagesInFile(false); } GUI::CursorSaver cs(Qt::WaitCursor); if(Data::Document::self()->saveDocument(Data::Document::self()->URL())) { Kernel::self()->resetHistory(); m_newDocument = false; updateCaption(false); m_fileSave->setEnabled(false); // TODO: call a method of the model instead of the view here m_detailedView->resetEntryStatus(); } else { ret = false; } } StatusBar::self()->clearStatus(); return ret; } void MainWindow::slotFileSaveAs() { fileSaveAs(); } bool MainWindow::fileSaveAs() { if(!m_editDialog->queryModified()) { return false; } slotStatusMsg(i18n("Saving file with a new filename...")); QString filter = i18n("Tellico Files") + QLatin1String(" (*.tc *.bc)"); filter += QLatin1String(";;"); filter += i18n("All Files") + QLatin1String(" (*)"); // keyword 'open' QString fileClass; const QUrl startUrl = KFileWidget::getStartUrl(QUrl(QStringLiteral("kfiledialog:///open")), fileClass); const QUrl url = QFileDialog::getSaveFileUrl(this, i18n("Save As"), startUrl, filter); if(url.isEmpty()) { StatusBar::self()->clearStatus(); return false; } if(url.isLocalFile()) { KRecentDirs::add(fileClass, url.adjusted(QUrl::RemoveFilename|QUrl::StripTrailingSlash).path()); } bool ret = true; if(url.isValid()) { GUI::CursorSaver cs(Qt::WaitCursor); m_savingImageLocationChange = true; // Overwriting an existing file was already confirmed in QFileDialog::getSaveFileUrl() if(Data::Document::self()->saveDocument(url, true /* force */)) { Kernel::self()->resetHistory(); KRecentDocument::add(url); m_fileOpenRecent->addUrl(url); updateCaption(false); m_newDocument = false; m_fileSave->setEnabled(false); m_detailedView->resetEntryStatus(); } else { ret = false; } m_savingImageLocationChange = false; } StatusBar::self()->clearStatus(); return ret; } void MainWindow::slotFilePrint() { slotStatusMsg(i18n("Printing...")); bool printGrouped = Config::printGrouped(); bool printHeaders = Config::printFieldHeaders(); int imageWidth = Config::maxImageWidth(); int imageHeight = Config::maxImageHeight(); // If the collection is being filtered, warn the user if(m_detailedView->filter()) { QString str = i18n("The collection is currently being filtered to show a limited subset of " "the entries. Only the visible entries will be printed. Continue?"); int ret = KMessageBox::warningContinueCancel(this, str, QString(), KStandardGuiItem::print(), KStandardGuiItem::cancel(), QStringLiteral("WarnPrintVisible")); if(ret == KMessageBox::Cancel) { StatusBar::self()->clearStatus(); return; } } GUI::CursorSaver cs(Qt::WaitCursor); Export::HTMLExporter exporter(Data::Document::self()->collection()); // only print visible entries exporter.setEntries(m_detailedView->visibleEntries()); exporter.setXSLTFile(QStringLiteral("tellico-printing.xsl")); exporter.setPrintHeaders(printHeaders); exporter.setPrintGrouped(printGrouped); exporter.setGroupBy(Controller::self()->expandedGroupBy()); if(!printGrouped) { // the sort titles are only used if the entries are not grouped exporter.setSortTitles(Controller::self()->sortTitles()); } exporter.setColumns(m_detailedView->visibleColumns()); exporter.setMaxImageSize(imageWidth, imageHeight); slotStatusMsg(i18n("Processing document...")); if(Config::printFormatted()) { exporter.setOptions(Export::ExportUTF8 | Export::ExportFormatted); } else { exporter.setOptions(Export::ExportUTF8); } QString html = exporter.text(); if(html.isEmpty()) { XSLTError(); StatusBar::self()->clearStatus(); return; } // don't have busy cursor when showing the print dialog cs.restore(); // myDebug() << html; slotStatusMsg(i18n("Printing...")); doPrint(html); StatusBar::self()->clearStatus(); } void MainWindow::slotFileQuit() { slotStatusMsg(i18n("Exiting...")); close(); // will call queryClose() StatusBar::self()->clearStatus(); } void MainWindow::slotEditCut() { activateEditSlot("cut()"); } void MainWindow::slotEditCopy() { activateEditSlot("copy()"); } void MainWindow::slotEditPaste() { activateEditSlot("paste()"); } void MainWindow::activateEditSlot(const char* slot_) { // the edit widget is the only one that copies, cuts, and pastes QWidget* w; if(m_editDialog->isVisible()) { w = m_editDialog->focusWidget(); } else { w = qApp->focusWidget(); } if(w && w->isVisible()) { const QMetaObject* meta = w->metaObject(); const int idx = meta->indexOfSlot(slot_); if(idx > -1) { //myDebug() << "MainWindow invoking" << meta->method(idx).signature(); meta->method(idx).invoke(w, Qt::DirectConnection); } } } void MainWindow::slotEditSelectAll() { m_detailedView->selectAllVisible(); } void MainWindow::slotEditDeselect() { Controller::self()->slotUpdateSelection(Data::EntryList()); } void MainWindow::slotToggleEntryEditor() { if(m_toggleEntryEditor->isChecked()) { m_editDialog->show(); } else { m_editDialog->hide(); } } void MainWindow::slotShowConfigDialog() { if(!m_configDlg) { m_configDlg = new ConfigDialog(this); connect(m_configDlg, SIGNAL(signalConfigChanged()), SLOT(slotHandleConfigChange())); connect(m_configDlg, SIGNAL(finished(int)), SLOT(slotHideConfigDialog())); } else { KWindowSystem::activateWindow(m_configDlg->winId()); } m_configDlg->show(); } void MainWindow::slotHideConfigDialog() { if(m_configDlg) { m_configDlg->hide(); m_configDlg->deleteLater(); m_configDlg = nullptr; } } void MainWindow::slotShowTipOfDay(bool force_/*=true*/) { KTipDialog::showTip(this, QStringLiteral("tellico/tellico.tips"), force_); } void MainWindow::slotStatusMsg(const QString& text_) { m_statusBar->setStatus(text_); } void MainWindow::slotClearStatus() { StatusBar::self()->clearStatus(); } void MainWindow::slotEntryCount() { Data::CollPtr coll = Data::Document::self()->collection(); if(!coll) { return; } int count = coll->entryCount(); QString text = i18n("Total entries: %1", count); int selectCount = Controller::self()->selectedEntries().count(); int filterCount = m_detailedView->visibleItems(); // if more than one book is selected, add the number of selected books if(filterCount < count && selectCount > 1) { text += QLatin1Char(' '); text += i18n("(%1 filtered; %2 selected)", filterCount, selectCount); } else if(filterCount < count) { text += QLatin1Char(' '); text += i18n("(%1 filtered)", filterCount); } else if(selectCount > 1) { text += QLatin1Char(' '); text += i18n("(%1 selected)", selectCount); } m_statusBar->setCount(text); } void MainWindow::slotEnableOpenedActions() { slotUpdateToolbarIcons(); updateCollectionActions(); // close the filter dialog when a new collection is opened slotHideFilterDialog(); slotStringMacroDialogFinished(); } void MainWindow::slotEnableModifiedActions(bool modified_ /*= true*/) { updateCaption(modified_); updateCollectionActions(); m_fileSave->setEnabled(modified_); } void MainWindow::slotHandleConfigChange() { const int imageLocation = Config::imageLocation(); const bool autoCapitalize = Config::autoCapitalization(); const bool autoFormat = Config::autoFormat(); const QStringList articles = Config::articleList(); const QStringList nocaps = Config::noCapitalizationList(); const QStringList suffixes = Config::nameSuffixList(); const QStringList prefixes = Config::surnamePrefixList(); m_configDlg->saveConfiguration(); // only modified if there are entries and image location is changed if(imageLocation != Config::imageLocation() && !Data::Document::self()->isEmpty()) { slotImageLocationChanged(); } if(autoCapitalize != Config::autoCapitalization() || autoFormat != Config::autoFormat() || articles != Config::articleList() || nocaps != Config::noCapitalizationList() || suffixes != Config::nameSuffixList() || prefixes != Config::surnamePrefixList()) { // invalidate all groups Data::Document::self()->collection()->invalidateGroups(); // refreshing the title causes the group view to refresh Controller::self()->slotRefreshField(Data::Document::self()->collection()->fieldByName(QStringLiteral("title"))); } QString entryXSLTFile = Config::templateName(Kernel::self()->collectionType()); m_entryView->setXSLTFile(entryXSLTFile + QLatin1String(".xsl")); } void MainWindow::slotUpdateCollectionToolBar(Tellico::Data::CollPtr coll_) { if(!coll_) { myWarning() << "no collection pointer!"; return; } QString current = m_groupView->groupBy(); if(current.isEmpty() || !coll_->entryGroups().contains(current)) { current = coll_->defaultGroupField(); } const QStringList groups = coll_->entryGroups(); if(groups.isEmpty()) { m_entryGrouping->clear(); return; } QMap groupMap; // use a map so they get sorted foreach(const QString& groupName, groups) { // special case for people "pseudo-group" if(groupName == Data::Collection::s_peopleGroupName) { groupMap.insert(groupName, QLatin1Char('<') + i18n("People") + QLatin1Char('>')); } else { groupMap.insert(groupName, coll_->fieldTitleByName(groupName)); } } const QStringList titles = groupMap.values(); if(titles == m_entryGrouping->items()) { // no need to update anything return; } const QStringList names = groupMap.keys(); int index = names.indexOf(current); if(index == -1) { current = names[0]; index = 0; } m_entryGrouping->setItems(titles); m_entryGrouping->setCurrentItem(index); // in case the current grouping field get modified to be non-grouping... m_groupView->setGroupField(current); // don't call slotChangeGrouping() since it adds an undo item // TODO::I have no idea how to get the combobox to update its size // this is the hackiest of hacks, taken from KXmlGuiWindow::saveNewToolbarConfig() // the window flickers as toolbar resizes, unavoidable? // crashes if removeCLient//addClient is called here, need to do later in event loop QTimer::singleShot(0, this, &MainWindow::guiFactoryReset); } void MainWindow::slotChangeGrouping() { const QString title = m_entryGrouping->currentText(); QString groupName = Kernel::self()->fieldNameByTitle(title); if(groupName.isEmpty()) { if(title == (QLatin1Char('<') + i18n("People") + QLatin1Char('>'))) { groupName = Data::Collection::s_peopleGroupName; } else { groupName = Data::Document::self()->collection()->defaultGroupField(); } } m_groupView->setGroupField(groupName); m_viewTabs->setCurrentWidget(m_groupView); } void MainWindow::slotShowReportDialog() { if(!m_reportDlg) { m_reportDlg = new ReportDialog(this); connect(m_reportDlg, SIGNAL(finished(int)), SLOT(slotHideReportDialog())); } else { KWindowSystem::activateWindow(m_reportDlg->winId()); } m_reportDlg->show(); } void MainWindow::slotHideReportDialog() { if(m_reportDlg) { m_reportDlg->hide(); m_reportDlg->deleteLater(); m_reportDlg = nullptr; } } void MainWindow::doPrint(const QString& html_) { KHTMLPart w; // KHTMLPart printing was broken in KDE until KHTML 5.16 // see https://git.reviewboard.kde.org/r/125681/ const QString version = w.componentData().version(); const uint major = version.section(QLatin1Char('.'), 0, 0).toUInt(); const uint minor = version.section(QLatin1Char('.'), 1, 1).toUInt(); if(major == 5 && minor < 16) { myWarning() << "Printing is broken for KDE Frameworks < 5.16. Please upgrade"; return; } w.setJScriptEnabled(false); w.setJavaEnabled(false); w.setMetaRefreshEnabled(false); w.setPluginsEnabled(false); w.begin(Data::Document::self()->URL()); w.write(html_); w.end(); // the problem with doing my own layout is that the text gets truncated, both at the // top and at the bottom. Even adding the overlap parameter, there were problems. // KHTMLView takes care of that with a truncatedAt() parameter, but that's hidden in // the khtml::render_root class. So for now, just use the KHTMLView::print() method. w.view()->print(); } void MainWindow::XSLTError() { QString str = i18n("Tellico encountered an error in XSLT processing.") + QLatin1Char('\n'); str += i18n("Please check your installation."); Kernel::self()->sorry(str); } void MainWindow::slotShowFilterDialog() { if(!m_filterDlg) { m_filterDlg = new FilterDialog(FilterDialog::CreateFilter, this); // allow saving m_quickFilter->setEnabled(false); connect(m_filterDlg, SIGNAL(signalCollectionModified()), Data::Document::self(), SLOT(slotSetModified())); connect(m_filterDlg, SIGNAL(signalUpdateFilter(Tellico::FilterPtr)), this, SLOT(slotUpdateFilter(Tellico::FilterPtr))); connect(m_filterDlg, SIGNAL(finished(int)), SLOT(slotHideFilterDialog())); } else { KWindowSystem::activateWindow(m_filterDlg->winId()); } m_filterDlg->setFilter(m_detailedView->filter()); m_filterDlg->show(); } void MainWindow::slotHideFilterDialog() { // m_quickFilter->blockSignals(false); m_quickFilter->setEnabled(true); if(m_filterDlg) { m_filterDlg->hide(); m_filterDlg->deleteLater(); m_filterDlg = nullptr; } } void MainWindow::slotQueueFilter() { if(m_dontQueueFilter) { return; } m_queuedFilters++; QTimer::singleShot(200, this, SLOT(slotUpdateFilter())); } void MainWindow::slotUpdateFilter() { m_queuedFilters--; if(m_queuedFilters > 0) { return; } setFilter(m_quickFilter->text()); } void MainWindow::slotUpdateFilter(FilterPtr filter_) { // Can't just block signals because clear button won't show then m_dontQueueFilter = true; m_quickFilter->setText(QStringLiteral(" ")); // To be able to clear custom filter Controller::self()->slotUpdateFilter(filter_); m_dontQueueFilter = false; } void MainWindow::setFilter(const QString& text_) { QString text = text_.trimmed(); FilterPtr filter; if(!text.isEmpty()) { filter = new Filter(Filter::MatchAll); QString fieldName; // empty field name means match on any field // if the text contains '=' assume it's a field name or title if(text.indexOf(QLatin1Char('=')) > -1) { fieldName = text.section(QLatin1Char('='), 0, 0).trimmed(); text = text.section(QLatin1Char('='), 1).trimmed(); // check that the field name might be a title if(!Data::Document::self()->collection()->hasField(fieldName)) { fieldName = Data::Document::self()->collection()->fieldNameByTitle(fieldName); } } // if the text contains any non-word characters, assume it's a regexp // but \W in qt is letter, number, or '_', I want to be a bit less strict QRegExp rx(QLatin1String("[^\\w\\s-']")); if(rx.indexIn(text) == -1) { // split by whitespace, and add rules for each word const QStringList tokens = text.split(QRegExp(QLatin1String("\\s"))); foreach(const QString& token, tokens) { // an empty field string means check every field filter->append(new FilterRule(fieldName, token, FilterRule::FuncContains)); } } else { // if it isn't valid, hold off on applying the filter QRegExp tx(text); if(!tx.isValid()) { text = QRegExp::escape(text); tx.setPattern(text); } if(!tx.isValid()) { myDebug() << "invalid regexp:" << text; return; } filter->append(new FilterRule(fieldName, text, FilterRule::FuncRegExp)); } // also want to update the line edit in case the filter was set by DBUS if(m_quickFilter->text() != text_) { m_quickFilter->setText(text_); } } // only update filter if one exists or did exist if(filter || m_detailedView->filter()) { Controller::self()->slotUpdateFilter(filter); } } void MainWindow::slotShowCollectionFieldsDialog() { if(!m_collFieldsDlg) { m_collFieldsDlg = new CollectionFieldsDialog(Data::Document::self()->collection(), this); connect(m_collFieldsDlg, SIGNAL(finished(int)), SLOT(slotHideCollectionFieldsDialog())); } else { KWindowSystem::activateWindow(m_collFieldsDlg->winId()); } m_collFieldsDlg->show(); } void MainWindow::slotHideCollectionFieldsDialog() { if(m_collFieldsDlg) { m_collFieldsDlg->hide(); m_collFieldsDlg->deleteLater(); m_collFieldsDlg = nullptr; } } void MainWindow::slotFileImport(int format_) { slotStatusMsg(i18n("Importing data...")); m_quickFilter->clear(); Import::Format format = static_cast(format_); bool checkURL = true; QUrl url; switch(ImportDialog::importTarget(format)) { case Import::File: { QString fileClass; const QUrl startUrl = KFileWidget::getStartUrl(QUrl(QStringLiteral("kfiledialog:///import")), fileClass); url = QFileDialog::getOpenFileUrl(this, i18n("Import File"), startUrl, ImportDialog::fileFilter(format)); KRecentDirs::add(fileClass, url.adjusted(QUrl::RemoveFilename|QUrl::StripTrailingSlash).path()); } break; case Import::Dir: // TODO: allow remote audiofile importing { const QString fileClass(QStringLiteral("ImportDir")); QString dirName = ImportDialog::startDir(format); if(dirName.isEmpty()) { dirName = KRecentDirs::dir(fileClass); } url = QUrl::fromLocalFile(QFileDialog::getExistingDirectory(this, i18n("Import Directory"), dirName)); KRecentDirs::add(fileClass, url.adjusted(QUrl::RemoveFilename|QUrl::StripTrailingSlash).path()); } break; case Import::None: default: checkURL = false; break; } if(checkURL) { bool ok = !url.isEmpty() && url.isValid() && QFile::exists(url.toLocalFile()); if(!ok) { StatusBar::self()->clearStatus(); return; } } importFile(format, QList() << url); StatusBar::self()->clearStatus(); } void MainWindow::slotFileExport(int format_) { slotStatusMsg(i18n("Exporting data...")); Export::Format format = static_cast(format_); ExportDialog dlg(format, Data::Document::self()->collection(), this); if(dlg.exec() == QDialog::Rejected) { StatusBar::self()->clearStatus(); return; } switch(ExportDialog::exportTarget(format)) { case Export::None: dlg.exportURL(); break; case Export::Dir: myDebug() << "ExportDir not implemented!"; break; case Export::File: { QString fileClass; const QUrl startUrl = KFileWidget::getStartUrl(QUrl(QStringLiteral("kfiledialog:///export")), fileClass); QUrl url = QFileDialog::getSaveFileUrl(this, i18n("Export As"), startUrl, dlg.fileFilter()); if(url.isEmpty()) { StatusBar::self()->clearStatus(); return; } if(url.isValid()) { if(url.isLocalFile()) { KRecentDirs::add(fileClass, url.adjusted(QUrl::RemoveFilename|QUrl::StripTrailingSlash).path()); } GUI::CursorSaver cs(Qt::WaitCursor); dlg.exportURL(url); } } break; } StatusBar::self()->clearStatus(); } void MainWindow::slotShowStringMacroDialog() { if(Data::Document::self()->collection()->type() != Data::Collection::Bibtex) { return; } if(!m_stringMacroDlg) { const Data::BibtexCollection* c = static_cast(Data::Document::self()->collection().data()); m_stringMacroDlg = new StringMapDialog(c->macroList(), this, false); m_stringMacroDlg->setWindowTitle(i18n("String Macros")); m_stringMacroDlg->setLabels(i18n("Macro"), i18n("String")); connect(m_stringMacroDlg, SIGNAL(finished(int)), SLOT(slotStringMacroDialogFinished(int))); } else { KWindowSystem::activateWindow(m_stringMacroDlg->winId()); } m_stringMacroDlg->show(); } void MainWindow::slotStringMacroDialogFinished(int result_) { // no point in checking if collection is bibtex, as dialog would never have been created if(!m_stringMacroDlg) { return; } if(result_ == QDialog::Accepted) { static_cast(Data::Document::self()->collection().data())->setMacroList(m_stringMacroDlg->stringMap()); Data::Document::self()->slotSetModified(true); } m_stringMacroDlg->hide(); m_stringMacroDlg->deleteLater(); m_stringMacroDlg = nullptr; } void MainWindow::slotShowBibtexKeyDialog() { if(Data::Document::self()->collection()->type() != Data::Collection::Bibtex) { return; } if(!m_bibtexKeyDlg) { m_bibtexKeyDlg = new BibtexKeyDialog(Data::Document::self()->collection(), this); connect(m_bibtexKeyDlg, SIGNAL(finished(int)), SLOT(slotHideBibtexKeyDialog())); connect(m_bibtexKeyDlg, SIGNAL(signalUpdateFilter(Tellico::FilterPtr)), this, SLOT(slotUpdateFilter(Tellico::FilterPtr))); } else { KWindowSystem::activateWindow(m_bibtexKeyDlg->winId()); } m_bibtexKeyDlg->show(); } void MainWindow::slotHideBibtexKeyDialog() { if(m_bibtexKeyDlg) { m_bibtexKeyDlg->deleteLater(); m_bibtexKeyDlg = nullptr; } } void MainWindow::slotNewEntry() { m_toggleEntryEditor->setChecked(true); slotToggleEntryEditor(); m_editDialog->slotHandleNew(); } void MainWindow::slotEditDialogFinished() { m_toggleEntryEditor->setChecked(false); } void MainWindow::slotShowEntryEditor() { m_toggleEntryEditor->setChecked(true); m_editDialog->show(); KWindowSystem::activateWindow(m_editDialog->winId()); } void MainWindow::slotConvertToBibliography() { // only book collections can be converted to bibtex Data::CollPtr coll = Data::Document::self()->collection(); if(!coll || coll->type() != Data::Collection::Book) { return; } GUI::CursorSaver cs; // need to make sure all images are transferred Data::Document::self()->loadAllImagesNow(); Data::CollPtr newColl = Data::BibtexCollection::convertBookCollection(coll); if(newColl) { m_newDocument = true; Kernel::self()->replaceCollection(newColl); m_fileOpenRecent->setCurrentItem(-1); slotUpdateToolbarIcons(); updateCollectionActions(); } else { myWarning() << "ERROR: no bibliography created!"; } } void MainWindow::slotCiteEntry(int action_) { StatusBar::self()->setStatus(i18n("Creating citations...")); Cite::ActionManager* man = Cite::ActionManager::self(); man->cite(static_cast(action_), Controller::self()->selectedEntries()); if(man->hasError()) { Kernel::self()->sorry(man->errorString()); } StatusBar::self()->clearStatus(); } void MainWindow::slotShowFetchDialog() { if(!m_fetchDlg) { m_fetchDlg = new FetchDialog(this); connect(m_fetchDlg, SIGNAL(finished(int)), SLOT(slotHideFetchDialog())); connect(Controller::self(), SIGNAL(collectionAdded(int)), m_fetchDlg, SLOT(slotResetCollection())); } else { KWindowSystem::activateWindow(m_fetchDlg->winId()); } m_fetchDlg->show(); } void MainWindow::slotHideFetchDialog() { if(m_fetchDlg) { m_fetchDlg->hide(); m_fetchDlg->deleteLater(); m_fetchDlg = nullptr; } } bool MainWindow::importFile(Tellico::Import::Format format_, const QUrl& url_, Tellico::Import::Action action_) { // try to open document GUI::CursorSaver cs(Qt::WaitCursor); bool failed = false; Data::CollPtr coll; if(!url_.isEmpty() && url_.isValid() && NetAccess::exists(url_, true, this)) { coll = ImportDialog::importURL(format_, url_); } else { Kernel::self()->sorry(i18n(errorLoad, url_.fileName())); failed = true; } if(!coll && !m_initialized) { // special case on startup when openURL() is called with a command line argument // and that URL can't be opened. The window still needs to be initialized // the doc object is created with an initial book collection, continue with that Controller::self()->slotCollectionAdded(Data::Document::self()->collection()); m_fileSave->setEnabled(false); slotEnableOpenedActions(); slotEnableModifiedActions(false); slotEntryCount(); m_fileOpenRecent->setCurrentItem(-1); m_initialized = true; failed = true; } else if(coll) { // this is rather dumb, but I'm too lazy to find the bug // if the document isn't initialized, then Tellico crashes // since Document::replaceCollection() ends up calling lots of stuff that isn't initialized if(!m_initialized) { Controller::self()->slotCollectionAdded(Data::Document::self()->collection()); m_initialized = true; } failed = !importCollection(coll, action_); } StatusBar::self()->clearStatus(); return !failed; // return true means success } bool MainWindow::exportCollection(Tellico::Export::Format format_, const QUrl& url_, bool filtered_) { if(!url_.isValid()) { myDebug() << "invalid URL:" << url_; return false; } GUI::CursorSaver cs; const Data::CollPtr coll = Data::Document::self()->collection(); if(!coll) { return false; } // only bibliographies can export to bibtex or bibtexml const bool isBibtex = (coll->type() == Data::Collection::Bibtex); if(!isBibtex && (format_ == Export::Bibtex || format_ == Export::Bibtexml)) { return false; } // only books and bibliographies can export to alexandria const bool isBook = (coll->type() == Data::Collection::Book); if(!isBibtex && !isBook && format_ == Export::Alexandria) { return false; } return ExportDialog::exportCollection(coll, filtered_ ? Controller::self()->visibleEntries() : coll->entries(), format_, url_); } bool MainWindow::showEntry(Data::ID id) { Data::EntryPtr entry = Data::Document::self()->collection()->entryById(id); if(entry) { m_entryView->showEntry(entry); } return entry; } void MainWindow::addFilterView() { if(m_filterView) { return; } m_filterView = new FilterView(m_viewTabs); Controller::self()->addObserver(m_filterView); m_viewTabs->insertTab(1, m_filterView, QIcon::fromTheme(QStringLiteral("view-filter")), i18n("Filters")); m_filterView->setWhatsThis(i18n("The Filter View shows the entries which meet certain " "filter rules.")); connect(m_filterView, SIGNAL(signalUpdateFilter(Tellico::FilterPtr)), this, SLOT(slotUpdateFilter(Tellico::FilterPtr))); // use the EntrySelectionModel as a proxy so when entries get selected in the filter view // the edit dialog and entry view are updated // TODO: consider using KSelectionProxyModel static_cast(m_iconView->selectionModel())->addSelectionProxy(m_filterView->selectionModel()); // sort by count if column = 1 int sortRole = Config::filterViewSortColumn() == 0 ? static_cast(Qt::DisplayRole) : static_cast(RowCountRole); Qt::SortOrder sortOrder = Config::filterViewSortAscending() ? Qt::AscendingOrder : Qt::DescendingOrder; m_filterView->setSorting(sortOrder, sortRole); } void MainWindow::addLoanView() { if(m_loanView) { return; } m_loanView = new LoanView(m_viewTabs); Controller::self()->addObserver(m_loanView); m_viewTabs->insertTab(2, m_loanView, QIcon::fromTheme(QStringLiteral("kaddressbook")), i18n("Loans")); m_loanView->setWhatsThis(i18n("The Loan View shows a list of all the people who " "have borrowed items from your collection.")); // use the EntrySelectionModel as a proxy so when entries get selected in the loan view // the edit dialog and entry view are updated // TODO: consider using KSelectionProxyModel static_cast(m_iconView->selectionModel())->addSelectionProxy(m_loanView->selectionModel()); // sort by count if column = 1 int sortRole = Config::loanViewSortColumn() == 0 ? static_cast(Qt::DisplayRole) : static_cast(RowCountRole); Qt::SortOrder sortOrder = Config::loanViewSortAscending() ? Qt::AscendingOrder : Qt::DescendingOrder; m_loanView->setSorting(sortOrder, sortRole); } void MainWindow::updateCaption(bool modified_) { QString caption; if(Data::Document::self()->collection()) { caption = Data::Document::self()->collection()->title(); } if(!m_newDocument) { if(!caption.isEmpty()) { caption += QLatin1String(" - "); } QUrl u = Data::Document::self()->URL(); if(u.isLocalFile()) { // for new files, the filename is set to Untitled in Data::Document if(u.fileName() == i18n(Tellico::untitledFilename)) { caption += u.fileName(); } else { caption += u.path(); } } else { caption += u.toDisplayString(); } } setCaption(caption, modified_); } void MainWindow::slotUpdateToolbarIcons() { // first change the icon for the menu item if(Kernel::self()->collectionType() == Data::Collection::Base) { m_newEntry->setIcon(QIcon::fromTheme(QStringLiteral("document-new"))); } else { m_newEntry->setIcon(QIcon(QLatin1String(":/icons/") + Kernel::self()->collectionTypeName())); } } void MainWindow::slotGroupLabelActivated() { // need entry grouping combo id foreach(QWidget* widget, m_entryGrouping->associatedWidgets()) { if(::qobject_cast(widget)) { QWidget* container = m_entryGrouping->requestWidget(widget); QComboBox* combo = ::qobject_cast(container); //krazy:exclude=qclasses if(combo) { combo->showPopup(); break; } } } } void MainWindow::slotFilterLabelActivated() { m_quickFilter->setFocus(); m_quickFilter->selectAll(); } void MainWindow::slotClearFilter() { m_quickFilter->clear(); slotQueueFilter(); } void MainWindow::slotRenameCollection() { Kernel::self()->renameCollection(); } void MainWindow::slotImageLocationMismatch() { // TODO: having a single image location mismatch should not be reason to completely save the whole document QTimer::singleShot(0, this, SLOT(slotImageLocationChanged())); } void MainWindow::slotImageLocationChanged() { if(m_savingImageLocationChange) { return; } m_savingImageLocationChange = true; Data::Document::self()->slotSetModified(); KMessageBox::information(this, QLatin1String("") + i18n("Some images are not saved in the configured location. The current file " "must be saved and the images will be transferred to the new location.") + QLatin1String("")); fileSave(); m_savingImageLocationChange = false; } void MainWindow::updateCollectionActions() { if(!Data::Document::self()->collection()) { return; } stateChanged(QStringLiteral("collection_reset")); Data::Collection::Type type = Data::Document::self()->collection()->type(); stateChanged(QLatin1String("is_") + CollectionFactory::typeName(type)); Controller::self()->updateActions(); // special case when there are no available data sources if(m_fetchActions.isEmpty() && m_updateAll) { m_updateAll->setEnabled(false); } } void MainWindow::updateEntrySources() { unplugActionList(QStringLiteral("update_entry_actions")); foreach(QAction* action, m_fetchActions) { foreach(QWidget* widget, action->associatedWidgets()) { widget->removeAction(action); } m_updateMapper->removeMappings(action); } qDeleteAll(m_fetchActions); m_fetchActions.clear(); Fetch::FetcherVec vec = Fetch::Manager::self()->fetchers(Kernel::self()->collectionType()); foreach(Fetch::Fetcher::Ptr fetcher, vec) { QAction* action = new QAction(Fetch::Manager::fetcherIcon(fetcher), fetcher->source(), actionCollection()); action->setToolTip(i18n("Update entry data from %1", fetcher->source())); connect(action, SIGNAL(triggered()), m_updateMapper, SLOT(map())); m_updateMapper->setMapping(action, fetcher->source()); m_fetchActions.append(action); } plugActionList(QStringLiteral("update_entry_actions"), m_fetchActions); } void MainWindow::importFile(Tellico::Import::Format format_, const QList& urls_) { QList urls = urls_; // update as DropHandler and Importer classes are updated if(urls_.count() > 1 && format_ != Import::Bibtex && format_ != Import::RIS && format_ != Import::CIW && format_ != Import::PDF) { QUrl u = urls_.front(); QString url = u.isLocalFile() ? u.path() : u.toDisplayString(); Kernel::self()->sorry(i18n("Tellico can only import one file of this type at a time. " "Only %1 will be imported.", url)); urls.clear(); urls += u; } ImportDialog dlg(format_, urls, this); if(dlg.exec() != QDialog::Accepted) { return; } // if edit dialog is saved ok and if replacing, then the doc is saved ok if(m_editDialog->queryModified() && (dlg.action() != Import::Replace || querySaveModified())) { GUI::CursorSaver cs(Qt::WaitCursor); Data::CollPtr coll = dlg.collection(); if(!coll) { if(!dlg.statusMessage().isEmpty()) { Kernel::self()->sorry(dlg.statusMessage()); } return; } importCollection(coll, dlg.action()); } } void MainWindow::importText(Tellico::Import::Format format_, const QString& text_) { if(text_.isEmpty()) { return; } Data::CollPtr coll = ImportDialog::importText(format_, text_); if(coll) { importCollection(coll, Import::Merge); } } bool MainWindow::importCollection(Tellico::Data::CollPtr coll_, Tellico::Import::Action action_) { bool failed = false; switch(action_) { case Import::Append: { // only append if match, but special case importing books into bibliographies Data::CollPtr c = Data::Document::self()->collection(); if(c->type() == coll_->type() || (c->type() == Data::Collection::Bibtex && coll_->type() == Data::Collection::Book)) { Kernel::self()->appendCollection(coll_); slotEnableModifiedActions(true); } else { Kernel::self()->sorry(i18n(errorAppendType)); failed = true; } } break; case Import::Merge: { // only merge if match, but special case importing books into bibliographies Data::CollPtr c = Data::Document::self()->collection(); if(c->type() == coll_->type() || (c->type() == Data::Collection::Bibtex && coll_->type() == Data::Collection::Book)) { Kernel::self()->mergeCollection(coll_); slotEnableModifiedActions(true); } else { Kernel::self()->sorry(i18n(errorMergeType)); failed = true; } } break; default: // replace Kernel::self()->replaceCollection(coll_); m_fileOpenRecent->setCurrentItem(-1); m_newDocument = true; slotEnableOpenedActions(); slotEnableModifiedActions(false); break; } // tell the entry views and models that there are no further images to load m_detailedView->slotRefreshImages(); return !failed; } void MainWindow::slotURLAction(const QUrl& url_) { Q_ASSERT(url_.scheme() == QLatin1String("tc")); QString actionName = url_.fileName(); QAction* action = this->action(actionName.toLatin1().constData()); if(action) { action->activate(QAction::Trigger); } else { myWarning() << "unknown action: " << actionName; } } bool MainWindow::eventFilter(QObject* obj_, QEvent* ev_) { if(ev_->type() == QEvent::KeyPress && obj_ == m_quickFilter) { switch(static_cast(ev_)->key()) { case Qt::Key_Escape: m_quickFilter->clear(); return true; } } return KXmlGuiWindow::eventFilter(obj_, ev_); } void MainWindow::slotToggleFullScreen() { Qt::WindowStates ws = windowState(); setWindowState((ws & Qt::WindowFullScreen) ? (ws & ~Qt::WindowFullScreen) : (ws | Qt::WindowFullScreen)); } void MainWindow::slotToggleMenuBarVisibility() { QMenuBar* mb = menuBar(); mb->isHidden() ? mb->show() : mb->hide(); } void MainWindow::slotToggleLayoutLock(bool lock_) { m_groupViewDock->setLocked(lock_); m_collectionViewDock->setLocked(lock_); } void MainWindow::slotResetLayout() { removeDockWidget(m_groupViewDock); addDockWidget(Qt::LeftDockWidgetArea, m_groupViewDock); m_groupViewDock->show(); m_dummyWindow->removeDockWidget(m_collectionViewDock); m_dummyWindow->addDockWidget(Qt::TopDockWidgetArea, m_collectionViewDock); m_collectionViewDock->show(); } void MainWindow::guiFactoryReset() { guiFactory()->removeClient(this); guiFactory()->reset(); guiFactory()->addClient(this); } diff --git a/src/mainwindow.h b/src/mainwindow.h index 74380030..87e6e7f4 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -1,527 +1,529 @@ /*************************************************************************** Copyright (C) 2001-2009 Robby Stephenson Copyright (C) 2011 Pedro Miguel Carvalho ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 2 of * * the License or (at your option) version 3 or any later version * * accepted by the membership of KDE e.V. (or its successor approved * * by the membership of KDE e.V.), which shall act as a proxy * * defined in Section 14 of version 3 of the license. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * ***************************************************************************/ #ifndef TELLICO_MAINWINDOW_H #define TELLICO_MAINWINDOW_H #include #include "translators/translators.h" #include "datavectors.h" #include #include #include class KToolBar; class QAction; class KSelectAction; class KToggleAction; +class KDualAction; class KRecentFilesAction; class KActionMenu; class QCloseEvent; class QDockWidget; class QSignalMapper; namespace Tellico { // forward declarations namespace GUI { class LineEdit; class TabWidget; class DockWidget; } class Controller; class ViewStack; class DetailedListView; class EntryIconView; class EntryView; class FilterDialog; class EntryEditDialog; class GroupView; class FilterView; class LoanView; class ConfigDialog; class CollectionFieldsDialog; class StringMapDialog; class BibtexKeyDialog; class EntryItem; class FetchDialog; class ReportDialog; class StatusBar; class DropHandler; /** * The base class for Tellico application windows. It sets up the main * window and reads the config file as well as providing a menubar, toolbar * and statusbar. Tellico reimplements the methods that KMainWindow provides * for main window handling and supports full session management as well as * using QActions. * * @author Robby Stephenson */ class MainWindow : public KXmlGuiWindow { Q_OBJECT friend class Controller; friend class DropHandler; public: /** * The main window constructor, calls all init functions to create the application. */ MainWindow(QWidget* parent=nullptr); ~MainWindow(); /** * Opens the initial file. * * @param nofile If true, even if the config option to reopen last file is set, no file is opened */ void initFileOpen(bool nofile); /** * Saves the document * * @return Returns @p true if successful */ bool fileSave(); /** * Saves a document by a new filename * * @return Returns @p true if successful */ bool fileSaveAs(); /** * @return Returns whether the current collection is still the non-saved default one */ bool isNewDocument() const { return m_newDocument; } /** * Used by main() and DBUS to import file. * * @param format The file format * @param url The url */ virtual bool importFile(Import::Format format, const QUrl& url, Import::Action action); /** * Used by DBUS to export to a file. */ virtual bool exportCollection(Export::Format format, const QUrl& url, bool filtered); /** * Used by DBUS */ virtual void openFile(const QString& file); virtual void setFilter(const QString& text); virtual bool showEntry(Data::ID id); bool eventFilter(QObject* watched, QEvent* event) Q_DECL_OVERRIDE; public Q_SLOTS: /** * Initializes some stuff after the object is created. */ void slotInit(); /** * Cleans up everything and then opens a new document. * * @param type Type of collection to add */ void slotFileNew(int type); /** * Opens a file and loads it into the document */ void slotFileOpen(); /** * Opens a file by URL and loads it into the document * * @param url The url to open */ void slotFileOpen(const QUrl& url); /** * Opens a file from the recent files menu * * @param url The url sent by the RecentFilesAction */ void slotFileOpenRecent(const QUrl& url); /** * Saves the document */ void slotFileSave(); /** * Saves a document by a new filename */ void slotFileSaveAs(); /** * Prints the current document. */ void slotFilePrint(); /** * Quits the application. */ void slotFileQuit(); /** * Puts the marked text/object into the clipboard and removes it from the document. */ void slotEditCut(); /* * Puts the marked text/object into the clipboard. */ void slotEditCopy(); /** * Pastes the clipboard into the document. */ void slotEditPaste(); /** * Selects all the entries in the collection. */ void slotEditSelectAll(); /** * Deselects all the entries in the collection. */ void slotEditDeselect(); /** * Toggles the edit widget. */ void slotToggleEntryEditor(); /** * Shows the configuration dialog for the application. */ void slotShowConfigDialog(); /** * Hides the configuration dialog for the application. */ void slotHideConfigDialog(); /** * Shows the fetch dialog. */ void slotShowFetchDialog(); /** * Hides the fetch dialog. */ void slotHideFetchDialog(); /** * Changes the statusbar contents for the standard label permanently, * used to indicate current actions being made. * * @param text The text that is displayed in the statusbar */ void slotStatusMsg(const QString& text); void slotClearStatus(); /** * Updates the entry count in the status bar. */ void slotEntryCount(); /** * Handles updating everything when the configuration is changed * via the configuration dialog. This slot is called when the OK or Apply * button is clicked in the dialog */ void slotHandleConfigChange(); /** * Changes the grouping of the entries in the @ref GroupView. The current value * of the combobox in the toolbar is used. */ void slotChangeGrouping(); /** * Imports data. * * @param format The import format */ void slotFileImport(int format); /** * Exports the current document. * * @param format The export format */ void slotFileExport(int format); /** * Shows the filter dialog for the application. */ void slotShowFilterDialog(); /** * Hides the filter dialog for the application. */ void slotHideFilterDialog(); /** * Shows the collection properties dialog for the application. */ void slotShowCollectionFieldsDialog(); /** * Hides the collection properties dialog for the application. */ void slotHideCollectionFieldsDialog(); /** * Shows the "Tip of the Day" dialog. * * @param force Whether the configuration setting should be ignored */ void slotShowTipOfDay(bool force=true); /** * Shows the string macro editor dialog for the application. */ void slotShowStringMacroDialog(); /** * Shows the citation key dialog */ void slotShowBibtexKeyDialog(); /** * Hides the citation key dialog */ void slotHideBibtexKeyDialog(); /** * Handle a url that indicates some actino should be taken */ void slotURLAction(const QUrl& url); private: /** * Saves the general options like all toolbar positions and status as well as the * geometry and the recent file list to the configuration file. */ void saveOptions(); /** * Reads the specific options. */ void readOptions(); /** * Initializes the QActions of the application */ void initActions(); /** * Sets up the statusbar for the main window by initializing a status label * and inserting a progress bar and entry counter. */ void initStatusBar(); /** * Initiates the view, setting up all the dock windows and so on. */ void initView(); /** * Initiates the document. */ void initDocument(); /** * Initiates all the signal and slot connections between major objects in the view. */ void initConnections(); bool querySaveModified(); /** * Called before the window is closed, either by the user or indirectly by the * session manager. * * The purpose of this function is to prepare the window in a way that it is safe to close it, * i.e. without the user losing some data. * @see KMainWindow::queryClose */ bool queryClose() Q_DECL_OVERRIDE; /** * Actual method used when opening a URL. Updating for the list views is turned off * as well as sorting, in order to more quickly load the document. * * @param url The url to open */ bool openURL(const QUrl& url); /* * Helper method to handle the printing duties. * * @param html The HTML string representing the doc to print */ void doPrint(const QString& html); void XSLTError(); /** * Helper function to activate a slot in the edit widget. * Primarily used for copy, cut, and paste. * * @param slot The slot name */ void activateEditSlot(const char* slot); void addFilterView(); void addLoanView(); void updateCaption(bool modified); void updateCollectionActions(); void updateEntrySources(); private Q_SLOTS: /** * Updates the actions when a file is opened. */ void slotEnableOpenedActions(); /** * Updates the save action and the caption when the document is modified. */ void slotEnableModifiedActions(bool modified = true); /** * Read the options specific to a collection * * @param coll The collection pointer */ void readCollectionOptions(Tellico::Data::CollPtr coll); /** * Saves the options relevant for a collection. I was having problems with the collection * being destructed before I could save info. * * @param coll A pointer to the collection */ void saveCollectionOptions(Tellico::Data::CollPtr coll); /** * Queue a filter update. The timer adds a 200 millisecond delay before actually * updating the filter. */ void slotQueueFilter(); /** * Update the filter to match any field with text. If a non-word character appears, the * text is interpreted as a regexp. */ void slotUpdateFilter(); void slotUpdateFilter(Tellico::FilterPtr filter); /** * Updates the collection toolbar. */ void slotUpdateCollectionToolBar(Tellico::Data::CollPtr coll); /** * Make sure the edit dialog is visible and start a new entry. */ void slotNewEntry(); /** * Handle the entry editor dialog being closed. */ void slotEditDialogFinished(); /** * Handle the Ok button being clicked in the string macros dialog. */ void slotStringMacroDialogFinished(int result=-1); /** * Since I use an application icon in the toolbar, I need to change its size whenever * the toolbar changes mode */ void slotUpdateToolbarIcons(); /** * Convert current collection to a bibliography. */ void slotConvertToBibliography(); /** * Send a citation for the selected entries */ void slotCiteEntry(int action); /** * Show the entry editor and update menu item. */ void slotShowEntryEditor(); /** * Show the report window. */ void slotShowReportDialog(); /** * Show the report window. */ void slotHideReportDialog(); /** * Focus the filter */ void slotGroupLabelActivated(); void slotFilterLabelActivated(); void slotClearFilter(); void slotRenameCollection(); void slotImageLocationMismatch(); void slotImageLocationChanged(); /** * Toggle full screen mode */ void slotToggleFullScreen(); /** * Toggle menubar visibility */ void slotToggleMenuBarVisibility(); void slotToggleLayoutLock(bool lock); void slotResetLayout(); void guiFactoryReset(); private: void importFile(Import::Format format, const QList& kurls); void importText(Import::Format format, const QString& text); bool importCollection(Data::CollPtr coll, Import::Action action); // the reason that I have to keep pointers to all these // is because they get plugged into menus later in Controller KRecentFilesAction* m_fileOpenRecent; QAction* m_fileSave; QAction* m_newEntry; QAction* m_editEntry; QAction* m_copyEntry; QAction* m_deleteEntry; QAction* m_mergeEntry; KActionMenu* m_updateEntryMenu; QAction* m_updateAll; QAction* m_checkInEntry; QAction* m_checkOutEntry; KToggleAction* m_toggleEntryEditor; + KDualAction* m_lockLayout; KSelectAction* m_entryGrouping; GUI::LineEdit* m_quickFilter; QMainWindow* m_dummyWindow; GUI::DockWidget* m_groupViewDock; GUI::DockWidget* m_collectionViewDock; Tellico::StatusBar* m_statusBar; DetailedListView* m_detailedView; EntryEditDialog* m_editDialog; GUI::TabWidget* m_viewTabs; GroupView* m_groupView; FilterView* m_filterView; LoanView* m_loanView; EntryView* m_entryView; EntryIconView* m_iconView; ViewStack* m_viewStack; QSignalMapper* m_updateMapper; ConfigDialog* m_configDlg; FilterDialog* m_filterDlg; CollectionFieldsDialog* m_collFieldsDlg; StringMapDialog* m_stringMacroDlg; BibtexKeyDialog* m_bibtexKeyDlg; FetchDialog* m_fetchDlg; ReportDialog* m_reportDlg; QList m_fetchActions; // keep track of the number of queued filter updates uint m_queuedFilters; // keep track whether everything gets initialized bool m_initialized; // need to keep track of whether the current collection has never been saved bool m_newDocument; // Don't queue filter if true bool m_dontQueueFilter; bool m_savingImageLocationChange; }; } // end namespace #endif // TELLICO_MAINWINDOW_H diff --git a/src/tests/bibliosharefetchertest.cpp b/src/tests/bibliosharefetchertest.cpp index a7ab0044..a2ef44e7 100644 --- a/src/tests/bibliosharefetchertest.cpp +++ b/src/tests/bibliosharefetchertest.cpp @@ -1,88 +1,88 @@ /*************************************************************************** Copyright (C) 2011 Robby Stephenson ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 2 of * * the License or (at your option) version 3 or any later version * * accepted by the membership of KDE e.V. (or its successor approved * * by the membership of KDE e.V.), which shall act as a proxy * * defined in Section 14 of version 3 of the license. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * ***************************************************************************/ #undef QT_NO_CAST_FROM_ASCII #include "bibliosharefetchertest.h" #include "../fetch/bibliosharefetcher.h" #include "../entry.h" #include "../collections/bookcollection.h" #include "../collectionfactory.h" #include "../images/imagefactory.h" #include "../utils/datafileregistry.h" #include QTEST_GUILESS_MAIN( BiblioShareFetcherTest ) BiblioShareFetcherTest::BiblioShareFetcherTest() : AbstractFetcherTest() { } void BiblioShareFetcherTest::initTestCase() { Tellico::ImageFactory::init(); Tellico::RegisterCollection registerBook(Tellico::Data::Collection::Book, "book"); // since we use the importer Tellico::DataFileRegistry::self()->addDataLocation(QFINDTESTDATA("../../xslt/biblioshare2tellico.xsl")); } void BiblioShareFetcherTest::testIsbn() { Tellico::Fetch::FetchRequest request(Tellico::Data::Collection::Book, Tellico::Fetch::ISBN, QStringLiteral("0670069035")); Tellico::Fetch::Fetcher::Ptr fetcher(new Tellico::Fetch::BiblioShareFetcher(this)); Tellico::Data::EntryList results = DO_FETCH(fetcher, request); QCOMPARE(results.size(), 1); Tellico::Data::EntryPtr entry = results.at(0); QCOMPARE(entry->field(QStringLiteral("title")), QStringLiteral("The Girl Who Kicked the Hornet's Nest")); QCOMPARE(entry->field(QStringLiteral("author")), QStringLiteral("Stieg Larsson")); QCOMPARE(entry->field(QStringLiteral("binding")), QStringLiteral("Hardback")); QCOMPARE(entry->field(QStringLiteral("isbn")), QStringLiteral("0-670-06903-5")); QCOMPARE(entry->field(QStringLiteral("pub_year")), QStringLiteral("2010")); - QCOMPARE(entry->field(QStringLiteral("publisher")), QStringLiteral("Viking")); + QCOMPARE(entry->field(QStringLiteral("publisher")), QStringLiteral("Penguin Canada")); QVERIFY(!entry->field(QStringLiteral("cover")).isEmpty()); QVERIFY(!entry->field(QStringLiteral("cover")).contains(QLatin1Char('/'))); } void BiblioShareFetcherTest::testIsbn13() { Tellico::Fetch::FetchRequest request(Tellico::Data::Collection::Book, Tellico::Fetch::ISBN, QStringLiteral("9780670069033")); Tellico::Fetch::Fetcher::Ptr fetcher(new Tellico::Fetch::BiblioShareFetcher(this)); Tellico::Data::EntryList results = DO_FETCH(fetcher, request); QCOMPARE(results.size(), 1); Tellico::Data::EntryPtr entry = results.at(0); QCOMPARE(entry->field(QStringLiteral("title")), QStringLiteral("The Girl Who Kicked the Hornet's Nest")); QCOMPARE(entry->field(QStringLiteral("author")), QStringLiteral("Stieg Larsson")); QCOMPARE(entry->field(QStringLiteral("binding")), QStringLiteral("Hardback")); QCOMPARE(entry->field(QStringLiteral("isbn")), QStringLiteral("0-670-06903-5")); QCOMPARE(entry->field(QStringLiteral("pub_year")), QStringLiteral("2010")); - QCOMPARE(entry->field(QStringLiteral("publisher")), QStringLiteral("Viking")); + QCOMPARE(entry->field(QStringLiteral("publisher")), QStringLiteral("Penguin Canada")); QVERIFY(!entry->field(QStringLiteral("cover")).isEmpty()); QVERIFY(!entry->field(QStringLiteral("cover")).contains(QLatin1Char('/'))); }