indicator-transfer-0.2+16.04.20151216.5/0000755000015600001650000000000012634336272017666 5ustar pbuserpbgroup00000000000000indicator-transfer-0.2+16.04.20151216.5/cmake/0000755000015600001650000000000012634336272020746 5ustar pbuserpbgroup00000000000000indicator-transfer-0.2+16.04.20151216.5/cmake/Translations.cmake0000644000015600001650000000304212634336113024422 0ustar pbuserpbgroup00000000000000# Translations.cmake, CMake macros written for Marlin, feel free to re-use them macro(add_translations_directory NLS_PACKAGE) add_custom_target (i18n ALL) find_program (MSGFMT_EXECUTABLE msgfmt) file (GLOB PO_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.po) foreach (PO_INPUT ${PO_FILES}) get_filename_component (PO_INPUT_BASE ${PO_INPUT} NAME_WE) set (MO_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${PO_INPUT_BASE}.mo) add_custom_command (TARGET i18n COMMAND ${MSGFMT_EXECUTABLE} -o ${MO_OUTPUT} ${PO_INPUT}) install (FILES ${MO_OUTPUT} DESTINATION ${CMAKE_INSTALL_LOCALEDIR}/${PO_INPUT_BASE}/LC_MESSAGES RENAME ${NLS_PACKAGE}.mo) endforeach (PO_INPUT ${PO_FILES}) endmacro(add_translations_directory) macro(add_translations_catalog NLS_PACKAGE) add_custom_target (pot COMMENT “Building translation catalog.”) find_program (XGETTEXT_EXECUTABLE xgettext) # init this list, which will hold all the sources across all dirs set(SOURCES "") # add each directory's sources to the overall sources list foreach(FILES_INPUT ${ARGN}) set (DIR ${CMAKE_CURRENT_SOURCE_DIR}/${FILES_INPUT}) file (GLOB_RECURSE DIR_SOURCES ${DIR}/*.c ${DIR}/*.cc ${DIR}/*.cpp ${DIR}/*.cxx ${DIR}/*.vala) set (SOURCES ${SOURCES} ${DIR_SOURCES}) endforeach() add_custom_command (TARGET pot COMMAND ${XGETTEXT_EXECUTABLE} -d ${NLS_PACKAGE} -o ${CMAKE_CURRENT_SOURCE_DIR}/${NLS_PACKAGE}.pot ${SOURCES} --keyword="_" --keyword="N_" --from-code=UTF-8 ) endmacro() indicator-transfer-0.2+16.04.20151216.5/cmake/FindGMock.cmake0000644000015600001650000000076612634336113023554 0ustar pbuserpbgroup00000000000000# Build with system gmock and embedded gtest set (GMOCK_INCLUDE_DIRS "/usr/include/gmock/include" CACHE PATH "gmock source include directory") set (GMOCK_SOURCE_DIR "/usr/src/gmock" CACHE PATH "gmock source directory") set (GTEST_INCLUDE_DIRS "${GMOCK_SOURCE_DIR}/gtest/include" CACHE PATH "gtest source include directory") add_subdirectory(${GMOCK_SOURCE_DIR} "${CMAKE_CURRENT_BINARY_DIR}/gmock") set(GTEST_LIBRARIES gtest) set(GTEST_MAIN_LIBRARIES gtest_main) set(GMOCK_LIBRARIES gmock gmock_main) indicator-transfer-0.2+16.04.20151216.5/cmake/FindValgrind.cmake0000644000015600001650000000164512634336113024317 0ustar pbuserpbgroup00000000000000 option( ENABLE_MEMCHECK_OPTION "If set to ON, enables automatic creation of memcheck targets" OFF ) find_program( VALGRIND_PROGRAM NAMES valgrind ) if(VALGRIND_PROGRAM) set(VALGRIND_PROGRAM_OPTIONS "--suppressions=${CMAKE_SOURCE_DIR}/tests/data/valgrind.suppression" "--error-exitcode=1" "--leak-check=full" "--gen-suppressions=all" "--quiet" ) endif() find_package_handle_standard_args( VALGRIND DEFAULT_MSG VALGRIND_PROGRAM ) function(add_valgrind_test) foreach(_arg ${ARGN}) if ("VALGRIND" STREQUAL ${_arg}) if(ENABLE_MEMCHECK_OPTION AND VALGRIND_PROGRAM) list(APPEND _vgargs ${VALGRIND_PROGRAM} ${VALGRIND_PROGRAM_OPTIONS}) endif() else() list(APPEND _vgargs ${_arg}) endif() endforeach() add_test(${_vgargs}) endfunction() indicator-transfer-0.2+16.04.20151216.5/cmake/GdbusCodegen.cmake0000644000015600001650000000246512634336113024302 0ustar pbuserpbgroup00000000000000cmake_minimum_required(VERSION 2.6) if(POLICY CMP0011) cmake_policy(SET CMP0011 NEW) endif(POLICY CMP0011) find_program(GDBUS_CODEGEN NAMES gdbus-codegen DOC "gdbus-codegen executable") if(NOT GDBUS_CODEGEN) message(FATAL_ERROR "Excutable gdbus-codegen not found") endif() macro(add_gdbus_codegen outfiles name prefix service_xml) add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${name}.h" "${CMAKE_CURRENT_BINARY_DIR}/${name}.c" COMMAND "${GDBUS_CODEGEN}" --interface-prefix "${prefix}" --generate-c-code "${name}" "${service_xml}" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} DEPENDS ${ARGN} "${service_xml}" ) list(APPEND ${outfiles} "${CMAKE_CURRENT_BINARY_DIR}/${name}.c") endmacro(add_gdbus_codegen) macro(add_gdbus_codegen_with_namespace outfiles name prefix namespace service_xml) add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${name}.h" "${CMAKE_CURRENT_BINARY_DIR}/${name}.c" COMMAND "${GDBUS_CODEGEN}" --interface-prefix "${prefix}" --generate-c-code "${name}" --c-namespace "${namespace}" "${service_xml}" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} DEPENDS ${ARGN} "${service_xml}" ) list(APPEND ${outfiles} "${CMAKE_CURRENT_BINARY_DIR}/${name}.c") endmacro(add_gdbus_codegen_with_namespace) indicator-transfer-0.2+16.04.20151216.5/cmake/GCov.cmake0000644000015600001650000000533512634336113022606 0ustar pbuserpbgroup00000000000000if (CMAKE_BUILD_TYPE MATCHES coverage) set(GCOV_FLAGS "${GCOV_FLAGS} --coverage") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GCOV_FLAGS}") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${GCOV_FLAGS}") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${GCOV_FLAGS}") set(GCOV_LIBS ${GCOV_LIBS} gcov) find_program(GCOVR_EXECUTABLE gcovr HINTS ${GCOVR_ROOT} "${GCOVR_ROOT}/bin") if (NOT GCOVR_EXECUTABLE) message(STATUS "Gcovr binary was not found, can not generate XML coverage info.") else () message(STATUS "Gcovr found, can generate XML coverage info.") add_custom_target (coverage-xml WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND "${GCOVR_EXECUTABLE}" --exclude="test.*" -x -r "${CMAKE_SOURCE_DIR}" --object-directory=${CMAKE_BINARY_DIR} -o coverage.xml) endif() find_program(LCOV_EXECUTABLE lcov HINTS ${LCOV_ROOT} "${GCOVR_ROOT}/bin") find_program(GENHTML_EXECUTABLE genhtml HINTS ${GENHTML_ROOT}) if (NOT LCOV_EXECUTABLE) message(STATUS "Lcov binary was not found, can not generate HTML coverage info.") else () if(NOT GENHTML_EXECUTABLE) message(STATUS "Genthml binary not found, can not generate HTML coverage info.") else() message(STATUS "Lcov and genhtml found, can generate HTML coverage info.") add_custom_target (coverage-html WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND "${CMAKE_CTEST_COMMAND}" --force-new-ctest-process --verbose COMMAND "${LCOV_EXECUTABLE}" --directory ${CMAKE_BINARY_DIR} --capture | ${CMAKE_SOURCE_DIR}/trim-lcov.py > dconf-lcov.info COMMAND "${LCOV_EXECUTABLE}" -r dconf-lcov.info /usr/include/\\* -o nosys-lcov.info COMMAND LANG=C "${GENHTML_EXECUTABLE}" --prefix ${CMAKE_BINARY_DIR} --output-directory lcov-html --legend --show-details nosys-lcov.info COMMAND ${CMAKE_COMMAND} -E echo "" COMMAND ${CMAKE_COMMAND} -E echo "file://${CMAKE_BINARY_DIR}/lcov-html/index.html" COMMAND ${CMAKE_COMMAND} -E echo "") #COMMAND "${LCOV_EXECUTABLE}" --directory ${CMAKE_BINARY_DIR} --capture --output-file coverage.info --no-checksum #COMMAND "${GENHTML_EXECUTABLE}" --prefix ${CMAKE_BINARY_DIR} --output-directory coveragereport --title "Code Coverage" --legend --show-details coverage.info #COMMAND ${CMAKE_COMMAND} -E echo "\\#define foo \\\"bar\\\"" #) endif() endif() endif() #$(MAKE) $(AM_MAKEFLAGS) check #lcov --directory $(top_builddir) --capture --test-name dconf | $(top_srcdir)/trim-lcov.py > dconf-lcov.info #LANG=C genhtml --prefix $(top_builddir) --output-directory lcov-html --legend --show-details dconf-lcov.info #@echo #@echo " file://$(abs_top_builddir)/lcov-html/index.html" #@echo indicator-transfer-0.2+16.04.20151216.5/tests/0000755000015600001650000000000012634336272021030 5ustar pbuserpbgroup00000000000000indicator-transfer-0.2+16.04.20151216.5/tests/glib-fixture.h0000644000015600001650000001002712634336113023574 0ustar pbuserpbgroup00000000000000/* * Copyright 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . * * Authors: * Charles Kerr */ #ifndef INDICATOR_DATETIME_TESTS_GLIB_FIXTURE_H #define INDICATOR_DATETIME_TESTS_GLIB_FIXTURE_H #include #include #include #include #include #include // setlocale() class GlibFixture : public ::testing::Test { public: virtual ~GlibFixture() =default; private: GLogFunc realLogHandler; std::map logCounts; void testLogCount(GLogLevelFlags log_level, int expected) { EXPECT_EQ(expected, logCounts[log_level]); logCounts.erase(log_level); } static void default_log_handler(const gchar * log_domain, GLogLevelFlags log_level, const gchar * message, gpointer self) { g_print("%s - %d - %s\n", log_domain, (int)log_level, message); static_cast(self)->logCounts[log_level]++; } protected: virtual void SetUp() override { setlocale(LC_ALL, "C.UTF-8"); loop = g_main_loop_new(nullptr, false); g_log_set_default_handler(default_log_handler, this); // only use local, temporary settings #ifdef SCHEMA_DIR g_assert(g_setenv("GSETTINGS_BACKEND", "memory", true)); g_assert(g_setenv("GSETTINGS_SCHEMA_DIR", SCHEMA_DIR, true)); g_debug("SCHEMA_DIR is %s", SCHEMA_DIR); #endif g_unsetenv("DISPLAY"); } virtual void TearDown() override { // confirm there aren't any unexpected log messages EXPECT_EQ(0, logCounts[G_LOG_LEVEL_ERROR]); EXPECT_EQ(0, logCounts[G_LOG_LEVEL_CRITICAL]); EXPECT_EQ(0, logCounts[G_LOG_LEVEL_WARNING]); EXPECT_EQ(0, logCounts[G_LOG_LEVEL_MESSAGE]); EXPECT_EQ(0, logCounts[G_LOG_LEVEL_INFO]); // revert to glib's log handler g_log_set_default_handler(realLogHandler, this); g_clear_pointer(&loop, g_main_loop_unref); } private: static gboolean wait_for_signal__timeout(gpointer name) { g_error("%s: timed out waiting for signal '%s'", G_STRLOC, (char*)name); return G_SOURCE_REMOVE; } static gboolean wait_msec__timeout(gpointer loop) { g_main_loop_quit(static_cast(loop)); return G_SOURCE_CONTINUE; } protected: /* convenience func to loop while waiting for a GObject's signal */ void wait_for_signal(gpointer o, const gchar * signal, const int timeout_seconds=5) { // wait for the signal or for timeout, whichever comes first const auto handler_id = g_signal_connect_swapped(o, signal, G_CALLBACK(g_main_loop_quit), loop); const auto timeout_id = g_timeout_add_seconds(timeout_seconds, wait_for_signal__timeout, loop); g_main_loop_run(loop); g_source_remove(timeout_id); g_signal_handler_disconnect(o, handler_id); } /* convenience func to loop for N msec */ void wait_msec(int msec=50) { const auto id = g_timeout_add(msec, wait_msec__timeout, loop); g_main_loop_run(loop); g_source_remove(id); } GMainLoop * loop; }; #endif /* INDICATOR_DATETIME_TESTS_GLIB_FIXTURE_H */ indicator-transfer-0.2+16.04.20151216.5/tests/test-controller.cpp0000644000015600001650000002311512634336113024670 0ustar pbuserpbgroup00000000000000/* * Copyright 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . * * Authors: * Charles Kerr */ #include "glib-fixture.h" #include "source-mock.h" #include using namespace unity::indicator::transfer; class ControllerFixture: public GlibFixture { private: typedef GlibFixture super; protected: GTestDBus* bus = nullptr; std::shared_ptr m_source; std::shared_ptr m_controller; void SetUp() { super::SetUp(); m_source.reset(new MockSource); m_controller.reset(new Controller(m_source)); } void TearDown() { m_controller.reset(); m_source.reset(); super::TearDown(); } }; namespace { static constexpr Transfer::State all_states[] = { Transfer::QUEUED, Transfer::RUNNING, Transfer::PAUSED, Transfer::CANCELED, Transfer::HASHING, Transfer::PROCESSING, Transfer::FINISHED, Transfer::ERROR }; } TEST_F(ControllerFixture, HelloSource) { // confirms that the Test DBus SetUp() and TearDown() works } /** * Test which Transfers get cleared when 'clear_all' is called */ TEST_F(ControllerFixture, ClearAll) { struct { Transfer::State state; bool can_clear; Transfer::Id id; } transfers[] = { { Transfer::QUEUED, false, "queued" }, { Transfer::RUNNING, false, "running" }, { Transfer::PAUSED, false, "paused" }, { Transfer::CANCELED, false, "canceled" }, { Transfer::HASHING, false, "hashing" }, { Transfer::PROCESSING, false, "processing" }, { Transfer::FINISHED, true, "finished" }, { Transfer::ERROR, false, "error" } }; for (const auto& transfer : transfers) { auto t = std::make_shared(); t->state = transfer.state; t->id = transfer.id; m_source->m_model->add(t); } // make sure all the transfers made it into the model EXPECT_EQ(G_N_ELEMENTS(transfers), m_controller->size()); for (const auto& transfer : transfers) { EXPECT_EQ(1, m_controller->count(transfer.id)); EXPECT_CALL(*m_source, clear(transfer.id)).Times(transfer.can_clear?1:0); } // call clear-all m_controller->clear_all(); // make sure all the clearable transfers are gone from controler and source auto source_ids = m_source->get_model()->get_ids(); for (const auto& transfer : transfers) { int expect_count = (transfer.can_clear ? 0 : 1); EXPECT_EQ(source_ids.count(transfer.id), expect_count); EXPECT_EQ(m_controller->count(transfer.id), expect_count); } } /** * Test which Transfers get selected when 'pause_all' is called */ TEST_F(ControllerFixture, PauseAll) { struct { Transfer::State state; bool can_pause; Transfer::Id id; } transfers[] = { { Transfer::QUEUED, true, "queued" }, { Transfer::RUNNING, true, "running" }, { Transfer::PAUSED, false, "paused" }, { Transfer::CANCELED, false, "canceled" }, { Transfer::HASHING, true, "hashing" }, { Transfer::PROCESSING, true, "processing" }, { Transfer::FINISHED, false, "finished" }, { Transfer::ERROR, false, "error" } }; for (const auto& transfer : transfers) { auto t = std::make_shared(); t->state = transfer.state; t->id = transfer.id; m_source->m_model->add(t); EXPECT_EQ(transfer.can_pause, t->can_pause()); EXPECT_CALL(*m_source, pause(transfer.id)).Times(transfer.can_pause?1:0); } m_controller->pause_all(); } /** * Test which Transfers get selected when 'resume_all' is called */ TEST_F(ControllerFixture, ResumeAll) { struct { Transfer::State state; bool can_resume; Transfer::Id id; } transfers[] = { { Transfer::QUEUED, false, "queued" }, { Transfer::RUNNING, false, "running" }, { Transfer::PAUSED, true, "paused" }, { Transfer::CANCELED, true, "canceled" }, { Transfer::HASHING, false, "hashing" }, { Transfer::PROCESSING, false, "processing" }, { Transfer::FINISHED, false, "finished" }, { Transfer::ERROR, true, "error" } }; for (const auto& transfer : transfers) { auto t = std::make_shared(); t->state = transfer.state; t->id = transfer.id; m_source->m_model->add(t); EXPECT_EQ(transfer.can_resume, t->can_resume()); EXPECT_CALL(*m_source, resume(transfer.id)).Times(transfer.can_resume?1:0); } m_controller->resume_all(); } /** * Test what happens when you tap a Transfer */ TEST_F(ControllerFixture, Tap) { const Transfer::Id id = "id"; auto t = std::make_shared(); t->state = Transfer::QUEUED; t->id = id; m_source->m_model->add(t); t->state = Transfer::QUEUED; EXPECT_CALL(*m_source, start(id)).Times(1); EXPECT_CALL(*m_source, pause(id)).Times(0); EXPECT_CALL(*m_source, resume(id)).Times(0); EXPECT_CALL(*m_source, cancel(id)).Times(0); EXPECT_CALL(*m_source, open(id)).Times(0); m_controller->tap(id); t->state = Transfer::RUNNING; EXPECT_CALL(*m_source, start(id)).Times(0); EXPECT_CALL(*m_source, pause(id)).Times(1); EXPECT_CALL(*m_source, resume(id)).Times(0); EXPECT_CALL(*m_source, cancel(id)).Times(0); EXPECT_CALL(*m_source, open(id)).Times(0); m_controller->tap(id); t->state = Transfer::PAUSED; EXPECT_CALL(*m_source, start(id)).Times(0); EXPECT_CALL(*m_source, pause(id)).Times(0); EXPECT_CALL(*m_source, resume(id)).Times(1); EXPECT_CALL(*m_source, cancel(id)).Times(0); EXPECT_CALL(*m_source, open(id)).Times(0); m_controller->tap(id); t->state = Transfer::CANCELED; EXPECT_CALL(*m_source, start(id)).Times(0); EXPECT_CALL(*m_source, pause(id)).Times(0); EXPECT_CALL(*m_source, resume(id)).Times(1); EXPECT_CALL(*m_source, cancel(id)).Times(0); EXPECT_CALL(*m_source, open(id)).Times(0); m_controller->tap(id); t->state = Transfer::ERROR; EXPECT_CALL(*m_source, start(id)).Times(0); EXPECT_CALL(*m_source, pause(id)).Times(0); EXPECT_CALL(*m_source, resume(id)).Times(1); EXPECT_CALL(*m_source, cancel(id)).Times(0); EXPECT_CALL(*m_source, open(id)).Times(0); m_controller->tap(id); t->state = Transfer::HASHING; EXPECT_CALL(*m_source, start(id)).Times(0); EXPECT_CALL(*m_source, pause(id)).Times(1); EXPECT_CALL(*m_source, resume(id)).Times(0); EXPECT_CALL(*m_source, cancel(id)).Times(0); EXPECT_CALL(*m_source, open(id)).Times(0); m_controller->tap(id); t->state = Transfer::PROCESSING; EXPECT_CALL(*m_source, start(id)).Times(0); EXPECT_CALL(*m_source, pause(id)).Times(1); EXPECT_CALL(*m_source, resume(id)).Times(0); EXPECT_CALL(*m_source, cancel(id)).Times(0); EXPECT_CALL(*m_source, open(id)).Times(0); m_controller->tap(id); t->state = Transfer::FINISHED; EXPECT_CALL(*m_source, start(id)).Times(0); EXPECT_CALL(*m_source, pause(id)).Times(0); EXPECT_CALL(*m_source, resume(id)).Times(0); EXPECT_CALL(*m_source, cancel(id)).Times(0); EXPECT_CALL(*m_source, open(id)).Times(1); m_controller->tap(id); } TEST_F(ControllerFixture, Start) { const Transfer::Id id = "id"; auto t = std::make_shared(); t->id = id; t->state = Transfer::QUEUED; m_source->m_model->add(t); for (const auto& state : all_states) { t->state = state; EXPECT_CALL(*m_source, start(id)).Times(t->can_start()?1:0); EXPECT_CALL(*m_source, pause(id)).Times(0); EXPECT_CALL(*m_source, resume(id)).Times(0); EXPECT_CALL(*m_source, cancel(id)).Times(0); EXPECT_CALL(*m_source, open(id)).Times(0); m_controller->start(id); } } TEST_F(ControllerFixture, Pause) { const Transfer::Id id = "id"; auto t = std::make_shared(); t->id = id; t->state = Transfer::QUEUED; m_source->m_model->add(t); for (const auto& state : all_states) { t->state = state; EXPECT_CALL(*m_source, start(id)).Times(0); EXPECT_CALL(*m_source, pause(id)).Times(t->can_pause()?1:0); EXPECT_CALL(*m_source, resume(id)).Times(0); EXPECT_CALL(*m_source, cancel(id)).Times(0); EXPECT_CALL(*m_source, open(id)).Times(0); m_controller->pause(id); } } TEST_F(ControllerFixture, Resume) { const Transfer::Id id = "id"; auto t = std::make_shared(); t->id = id; t->state = Transfer::QUEUED; m_source->m_model->add(t); for (const auto& state : all_states) { t->state = state; EXPECT_CALL(*m_source, start(id)).Times(0); EXPECT_CALL(*m_source, pause(id)).Times(0); EXPECT_CALL(*m_source, resume(id)).Times(t->can_resume()?1:0); EXPECT_CALL(*m_source, cancel(id)).Times(0); EXPECT_CALL(*m_source, open(id)).Times(0); m_controller->resume(id); } } TEST_F(ControllerFixture, Cancel) { const Transfer::Id id = "id"; auto t = std::make_shared(); t->id = id; t->state = Transfer::QUEUED; m_source->m_model->add(t); for (const auto& state : all_states) { t->state = state; EXPECT_CALL(*m_source, start(id)).Times(0); EXPECT_CALL(*m_source, pause(id)).Times(0); EXPECT_CALL(*m_source, resume(id)).Times(0); EXPECT_CALL(*m_source, cancel(id)).Times(t->can_cancel()?1:0); EXPECT_CALL(*m_source, open(id)).Times(0); m_controller->cancel(id); } } indicator-transfer-0.2+16.04.20151216.5/tests/test-plugin-source.cpp0000644000015600001650000000272712634336113025307 0ustar pbuserpbgroup00000000000000/* * Copyright 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . * * Authors: * Charles Kerr */ #include "glib-fixture.h" #include #include using namespace unity::indicator::transfer; class PluginFixture: public GlibFixture { private: typedef GlibFixture super; protected: GTestDBus* bus = nullptr; std::shared_ptr m_source; std::shared_ptr m_controller; void SetUp() { super::SetUp(); auto plugin_dir = g_get_current_dir(); m_source.reset(new PluginSource(plugin_dir)); m_controller.reset(new Controller(m_source)); g_clear_pointer(&plugin_dir, g_free); } void TearDown() { m_controller.reset(); m_source.reset(); super::TearDown(); } }; TEST_F(PluginFixture, MockSourcePluginLoads) { // confirms that the fixture loads MockSourcePlugin } indicator-transfer-0.2+16.04.20151216.5/tests/test-multisource.cpp0000644000015600001650000001276112634336113025065 0ustar pbuserpbgroup00000000000000/* * Copyright 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . * * Authors: * Charles Kerr */ #include "source-mock.h" #include #include #include using ::testing::AtLeast; using namespace unity::indicator::transfer; class MultiSourceFixture: public ::testing::Test { protected: struct Event { typedef enum { ADDED, CHANGED, REMOVED } Type; Type type; Transfer::Id id; bool operator==(const Event& that) const { return type==that.type && id==that.id; } }; bool model_consists_of(const std::shared_ptr& model, std::initializer_list> list) const { // test get_all() std::vector> transfers(list); std::sort(transfers.begin(), transfers.end()); g_return_val_if_fail(transfers == model->get_all(), false); // test get() for(auto& transfer : transfers) g_return_val_if_fail(transfer == model->get(transfer->id), false); // test get_ids() std::set ids; for(auto& transfer : transfers) ids.insert(transfer->id); g_return_val_if_fail(ids == model->get_ids(), false); return true; } }; TEST_F(MultiSourceFixture,MultiplexesModels) { // set up the tributary sources, 'a' and 'b' auto a = std::make_shared(); auto b = std::make_shared(); // set up the multisource and connect it to the tributaries MultiSource multisource; auto multimodel = multisource.get_model(); std::vector events; std::vector expected_events; multisource.get_model()->added().connect([&events](const Transfer::Id& id){events.push_back(Event{Event::ADDED,id});}); multisource.get_model()->changed().connect([&events](const Transfer::Id& id){events.push_back(Event{Event::CHANGED,id});}); multisource.get_model()->removed().connect([&events](const Transfer::Id& id){events.push_back(Event{Event::REMOVED,id});}); multisource.add_source(a); multisource.add_source(b); // add a transfer to the 'a' source... const Transfer::Id aid {"aid"}; auto at = std::make_shared(); at->id = aid; a->m_model->add(at); expected_events.push_back(Event{Event::ADDED,aid}); // confirm that the multimodel sees the new transfer EXPECT_EQ(expected_events, events); EXPECT_EQ(at, a->get_model()->get(aid)); EXPECT_TRUE(model_consists_of(multimodel, {at})); // add a transfer to the 'b' source... const Transfer::Id bid {"bid"}; auto bt = std::make_shared(); bt->id = bid; b->m_model->add(bt); expected_events.push_back(Event{Event::ADDED,bid}); // confirm that the multimodel sees the new transfer EXPECT_EQ(expected_events, events); EXPECT_EQ(bt, b->get_model()->get(bid)); EXPECT_TRUE(model_consists_of(multimodel, {at, bt})); // poke transfer 'at'... at->progress = 50.0; a->m_model->emit_changed(aid); expected_events.push_back(Event{Event::CHANGED,aid}); EXPECT_EQ(expected_events, events); EXPECT_TRUE(model_consists_of(multimodel, {at, bt})); // remove transfer 'at'... a->m_model->remove(aid); expected_events.push_back(Event{Event::REMOVED,aid}); EXPECT_EQ(expected_events, events); EXPECT_FALSE(a->get_model()->get(aid)); EXPECT_TRUE(model_consists_of(multimodel, {bt})); // remove transfer 'bt'... b->m_model->remove(bid); expected_events.push_back(Event{Event::REMOVED,bid}); EXPECT_EQ(expected_events, events); EXPECT_FALSE(b->get_model()->get(aid)); EXPECT_TRUE(model_consists_of(multimodel, {})); } TEST(Multisource,MethodDelegation) { // set up the tributary sources, 'a' and 'b' auto a = std::make_shared(); auto b = std::make_shared(); // set up the multisource and connect it to the tributaries MultiSource multisource; multisource.add_source(a); multisource.add_source(b); // add a transfer to the 'a' source... const Transfer::Id aid {"aid"}; auto at = std::make_shared(); at->id = aid; a->m_model->add(at); // add a transfer to the 'b' source... const Transfer::Id bid {"bid"}; auto bt = std::make_shared(); bt->id = bid; b->m_model->add(bt); // confirm that multisource method calls are delegated to 'a' EXPECT_CALL(*a, open(aid)); multisource.open(aid); EXPECT_CALL(*a, start(aid)); multisource.start(aid); EXPECT_CALL(*a, pause(aid)); multisource.pause(aid); EXPECT_CALL(*a, resume(aid)); multisource.resume(aid); EXPECT_CALL(*a, cancel(aid)); multisource.cancel(aid); EXPECT_CALL(*a, open_app(aid)); multisource.open_app(aid); // confirm that multisource method calls are delegated to 'a' EXPECT_CALL(*b, open(bid)); multisource.open(bid); EXPECT_CALL(*b, start(bid)); multisource.start(bid); EXPECT_CALL(*b, pause(bid)); multisource.pause(bid); EXPECT_CALL(*b, resume(bid)); multisource.resume(bid); EXPECT_CALL(*b, cancel(bid)); multisource.cancel(bid); EXPECT_CALL(*b, open_app(bid)); multisource.open_app(bid); } indicator-transfer-0.2+16.04.20151216.5/tests/controller-mock.h0000644000015600001650000000320112634336113024301 0ustar pbuserpbgroup00000000000000/* * Copyright 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . * * Authors: * Charles Kerr */ #ifndef INDICATOR_TRANSFER_CONTROLLER_MOCK_H #define INDICATOR_TRANSFER_CONTROLLER_MOCK_H #include // parent class #include "gmock/gmock.h" namespace unity { namespace indicator { namespace transfer { class MockController: public Controller { public: explicit MockController(const std::shared_ptr& source): Controller(source) {} MOCK_METHOD0(pause_all, void()); MOCK_METHOD0(resume_all, void()); MOCK_METHOD0(clear_all, void()); MOCK_METHOD1(tap, void(const Transfer::Id&)); MOCK_METHOD1(start, void(const Transfer::Id&)); MOCK_METHOD1(pause, void(const Transfer::Id&)); MOCK_METHOD1(cancel, void(const Transfer::Id&)); MOCK_METHOD1(resume, void(const Transfer::Id&)); MOCK_METHOD1(open, void(const Transfer::Id&)); MOCK_METHOD1(open_app, void(const Transfer::Id&)); }; } // namespace transfer } // namespace indicator } // namespace unity #endif // INDICATOR_TRANSFER_CONTROLLER_MOCK_H indicator-transfer-0.2+16.04.20151216.5/tests/data/0000755000015600001650000000000012634336272021741 5ustar pbuserpbgroup00000000000000indicator-transfer-0.2+16.04.20151216.5/tests/data/valgrind.suppression0000644000015600001650000000000212634336113026045 0ustar pbuserpbgroup00000000000000 indicator-transfer-0.2+16.04.20151216.5/tests/mock-source-plugin.cpp0000644000015600001650000000157112634336113025255 0ustar pbuserpbgroup00000000000000/* * Copyright 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . * * Authors: * Charles Kerr */ #include "source-mock.h" #include using namespace unity::indicator::transfer; extern "C" { G_MODULE_EXPORT Source* get_source() { return new MockSource{}; } } indicator-transfer-0.2+16.04.20151216.5/tests/source-mock.h0000644000015600001650000000360012634336113023421 0ustar pbuserpbgroup00000000000000/* * Copyright 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . * * Authors: * Charles Kerr */ #ifndef INDICATOR_TRANSFER_SOURCE_MOCK_H #define INDICATOR_TRANSFER_SOURCE_MOCK_H #include #include "gmock/gmock.h" namespace unity { namespace indicator { namespace transfer { /** * \brief a Source that gets its updates & events from DBus */ class MockSource: public Source { public: MockSource(): m_model(new MutableModel) { // make sure that the transfer get removed from model on clear call ON_CALL(*this, clear(::testing::_)) .WillByDefault(::testing::Invoke(m_model.get(), &MutableModel::remove)); } MOCK_METHOD1(open, void(const Transfer::Id&)); MOCK_METHOD1(start, void(const Transfer::Id&)); MOCK_METHOD1(pause, void(const Transfer::Id&)); MOCK_METHOD1(resume, void(const Transfer::Id&)); MOCK_METHOD1(cancel, void(const Transfer::Id&)); MOCK_METHOD1(clear, void(const Transfer::Id&)); MOCK_METHOD1(update, void(const Transfer::Id&)); MOCK_METHOD1(open_app, void(const Transfer::Id&)); const std::shared_ptr get_model() override {return m_model;} std::shared_ptr m_model; }; } // namespace transfer } // namespace indicator } // namespace unity #endif // INDICATOR_TRANSFER_SOURCE_MOCK_H indicator-transfer-0.2+16.04.20151216.5/tests/simple-download.py0000755000015600001650000000417712634336113024506 0ustar pbuserpbgroup00000000000000#!/usr/bin/python3 # source: https://wiki.ubuntu.com/DownloadService/DownloadManager#Code_Examples from gi.repository import GLib import dbus from dbus.mainloop.glib import DBusGMainLoop DBusGMainLoop(set_as_default=True) MANAGER_PATH = '/' MANAGER_IFACE = 'com.canonical.applications.DownloadManager' DOWNLOAD_IFACE = 'com.canonical.applications.Download' DOWNLOAD_URIS = [ 'http://i.imgur.com/y51njgu.jpg', 'http://upload.wikimedia.org/wikipedia/commons/c/c6/Bayerischer_Wald_-_Aufichtenwald_001.jpg', 'http://upload.wikimedia.org/wikipedia/commons/e/ea/Sydney_Harbour_Bridge_night.jpg' ] def download_created(path): """Deal with the download created signal.""" print('Download created in %s' % path) def finished_callback(path, loop): global n_remaining """Deal with the finish signal.""" print('Download performed in "%s"' % path) n_remaining -= 1 if n_remaining == 0: loop.quit() def progress_callback(total, progress): """Deal with the progress signals.""" print('Progress is %s/%s' % (progress, total)) if __name__ == '__main__': global n_remaining n_remaining = 0 bus = dbus.SessionBus() loop = GLib.MainLoop() manager = bus.get_object('com.canonical.applications.Downloader', MANAGER_PATH) manager_dev_iface = dbus.Interface(manager, dbus_interface=MANAGER_IFACE) # ensure that download created works manager_dev_iface.connect_to_signal('downloadCreated', download_created) for uri in DOWNLOAD_URIS: n_remaining += 1 print('Adding "%s"' % uri) down_path = manager_dev_iface.createDownload((uri, "", "", dbus.Dictionary({}, signature="sv"), dbus.Dictionary({}, signature="ss"))) download = bus.get_object('com.canonical.applications.Downloader', down_path) download_dev_iface = dbus.Interface(download, dbus_interface=DOWNLOAD_IFACE) download_dev_iface.connect_to_signal('progress', progress_callback) download_dev_iface.connect_to_signal('finished', lambda path: finished_callback(path, loop)) download_dev_iface.start() loop.run() indicator-transfer-0.2+16.04.20151216.5/tests/test-view-gmenu.cpp0000644000015600001650000003112312634336113024566 0ustar pbuserpbgroup00000000000000/* * Copyright 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . * * Authors: * Charles Kerr */ #include "glib-fixture.h" #include "controller-mock.h" #include "source-mock.h" #include #include #include using namespace unity::indicator::transfer; class GMenuViewFixture: public GlibFixture { private: typedef GlibFixture super; protected: GTestDBus* bus = nullptr; std::shared_ptr m_source; std::shared_ptr m_controller; std::shared_ptr m_view; void SetUp() { super::SetUp(); // bring up the test bus bus = g_test_dbus_new(G_TEST_DBUS_NONE); g_test_dbus_up(bus); const auto address = g_test_dbus_get_bus_address(bus); g_setenv("DBUS_SYSTEM_BUS_ADDRESS", address, true); g_setenv("DBUS_SESSION_BUS_ADDRESS", address, true); // bring up the source m_source.reset(new MockSource); std::shared_ptr t; t.reset(new Transfer); t->id = "a"; t->state = Transfer::RUNNING; m_source->m_model->add(t); t.reset(new Transfer); t->id = "b"; t->state = Transfer::PAUSED; m_source->m_model->add(t); t.reset(new Transfer); t->id = "c"; t->state = Transfer::FINISHED; m_source->m_model->add(t); m_controller.reset(new MockController(m_source)); m_view.reset(new GMenuView(m_controller)); } void TearDown() { // empty the source m_view.reset(); m_controller.reset(); m_source.reset(); // bring down the bus GError * error = nullptr; GDBusConnection* connection = g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, &error); if(!g_dbus_connection_is_closed(connection)) g_dbus_connection_close_sync(connection, nullptr, &error); g_assert_no_error(error); g_clear_object(&connection); g_test_dbus_down(bus); g_clear_object(&bus); super::TearDown(); } }; /*** **** ***/ /** * These two are more about testing the scaffolding. * If the objects listening to the bus don't all get * torn down correctly, the second time we setup the * fixture we'll see glib errors */ TEST_F(GMenuViewFixture, CanFixtureSetupOnce) { g_timeout_add_seconds(1, [](gpointer g){ g_main_loop_quit(static_cast(g)); return G_SOURCE_REMOVE; }, loop); g_main_loop_run(loop); } TEST_F(GMenuViewFixture, CanFixtureSetupTwice) { g_timeout_add_seconds(1, [](gpointer g){ g_main_loop_quit(static_cast(g)); return G_SOURCE_REMOVE; }, loop); g_main_loop_run(loop); } /*** **** **** GActions **** ***/ /* Make sure all the actions we expect are there */ TEST_F(GMenuViewFixture, ExportedActions) { wait_msec(); // these are the actions we expect to find std::set expected_actions { "activate-transfer", "cancel-transfer", "clear-all", "open-app-transfer", "open-transfer", "pause-transfer", "pause-all", "phone-header", "resume-all", "resume-transfer" }; for (const auto& id : m_source->get_model()->get_ids()) expected_actions.insert("transfer-state." + id); auto connection = g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, nullptr); auto exported = g_dbus_action_group_get(connection, BUS_NAME, BUS_PATH); auto names_strv = g_action_group_list_actions(G_ACTION_GROUP(exported)); // wait for the exported ActionGroup to be populated if (g_strv_length(names_strv) == 0) { g_strfreev(names_strv); wait_for_signal(exported, "action-added"); names_strv = g_action_group_list_actions(G_ACTION_GROUP(exported)); } // convert it to a std::set for easy prodding std::set actions; for(int i=0; names_strv && names_strv[i]; i++) actions.insert(names_strv[i]); EXPECT_EQ(expected_actions, actions); // try closing the connection prematurely // to test Exporter's name-lost signal bool name_lost = false; m_view->name_lost().connect([this,&name_lost](){ name_lost = true; g_main_loop_quit(loop); }); g_dbus_connection_close_sync(connection, nullptr, nullptr); g_main_loop_run(loop); EXPECT_TRUE(name_lost); // cleanup g_strfreev(names_strv); g_clear_object(&exported); g_clear_object(&connection); } TEST_F(GMenuViewFixture, InvokedGActionsCallTheController) { wait_msec(); auto connection = g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, nullptr); auto dbus_action_group = g_dbus_action_group_get(connection, BUS_NAME, BUS_PATH); auto action_group = G_ACTION_GROUP(dbus_action_group); // wait for the exported ActionGroup to be populated auto names_strv = g_action_group_list_actions(action_group); if (g_strv_length(names_strv) == 0) { g_strfreev(names_strv); wait_for_signal(dbus_action_group, "action-added"); names_strv = g_action_group_list_actions(action_group); } g_strfreev(names_strv); // try tapping a transfer that can be resumed const char* id = "b"; EXPECT_TRUE(m_source->get_model()->get(id)->can_resume()); EXPECT_CALL(*m_controller, tap(id)).Times(1); g_action_group_activate_action(action_group, "activate-transfer", g_variant_new_string(id)); wait_msec(); // try tapping a transfer that CAN'T be resumed id = "c"; EXPECT_TRUE(!m_source->get_model()->get(id)->can_resume()); EXPECT_CALL(*m_controller, tap(id)).Times(1); g_action_group_activate_action(action_group, "activate-transfer", g_variant_new_string(id)); wait_msec(); // try cancelling a transfer id = "a"; EXPECT_CALL(*m_controller, cancel(id)).Times(1); g_action_group_activate_action(action_group, "cancel-transfer", g_variant_new_string(id)); wait_msec(); // try opening a transfer id = "b"; EXPECT_CALL(*m_controller, open(id)).Times(1); g_action_group_activate_action(action_group, "open-transfer", g_variant_new_string(id)); wait_msec(); // try opening a transfer's recipient's app id = "c"; EXPECT_CALL(*m_controller, open_app(id)).Times(1); g_action_group_activate_action(action_group, "open-app-transfer", g_variant_new_string(id)); wait_msec(); // try calling clear-all EXPECT_CALL(*m_controller, clear_all()).Times(1); g_action_group_activate_action(action_group, "clear-all", nullptr); wait_msec(); // try pausing a transfer id = "a"; EXPECT_CALL(*m_controller, pause(id)).Times(1); g_action_group_activate_action(action_group, "pause-transfer", g_variant_new_string(id)); wait_msec(); // try calling pause-all EXPECT_CALL(*m_controller, pause_all()).Times(1); g_action_group_activate_action(action_group, "pause-all", nullptr); wait_msec(); // try calling resume-all EXPECT_CALL(*m_controller, resume_all()).Times(1); g_action_group_activate_action(action_group, "resume-all", nullptr); wait_msec(); // try resuming a transfer id = "a"; EXPECT_CALL(*m_controller, resume(id)).Times(1); g_action_group_activate_action(action_group, "resume-transfer", g_variant_new_string(id)); wait_msec(); // cleanup g_clear_object(&dbus_action_group); g_clear_object(&connection); } /*** **** **** Header **** ***/ namespace { bool is_header_visible(GActionGroup* action_group, const std::string& header_action_name) { auto dict = g_action_group_get_action_state(action_group, header_action_name.c_str()); g_assert(dict != nullptr); g_assert(g_variant_is_of_type(dict, G_VARIANT_TYPE_VARDICT)); auto v = g_variant_lookup_value(dict, "visible", G_VARIANT_TYPE_BOOLEAN); g_assert(v != nullptr); const bool is_visible = g_variant_get_boolean(v); g_clear_pointer(&v, g_variant_unref); g_clear_pointer(&dict, g_variant_unref); return is_visible; } } TEST_F(GMenuViewFixture, PhoneHeader) { const std::string profile = "phone"; wait_msec(); auto connection = g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, nullptr); // SETUP: get the action group and wait for it to be populated auto dbus_action_group = g_dbus_action_group_get(connection, BUS_NAME, BUS_PATH); auto action_group = G_ACTION_GROUP(dbus_action_group); auto names_strv = g_action_group_list_actions(action_group); if (g_strv_length(names_strv) == 0) { g_strfreev(names_strv); wait_for_signal(dbus_action_group, "action-added"); names_strv = g_action_group_list_actions(action_group); } g_clear_pointer(&names_strv, g_strfreev); // SETUP: get the menu model and wait for it to be activated auto phone_dbus_menu_model = g_dbus_menu_model_get(connection, BUS_NAME, BUS_PATH"/phone"); auto phone_menu_model = G_MENU_MODEL(phone_dbus_menu_model); int n = g_menu_model_get_n_items(phone_menu_model); if (!n) { // give the model a moment to populate its info wait_msec(100); n = g_menu_model_get_n_items(phone_menu_model); } EXPECT_TRUE(phone_menu_model != nullptr); EXPECT_NE(0, n); // test to confirm that a header menuitem exists gchar* str = nullptr; g_menu_model_get_item_attribute(phone_menu_model, 0, "x-canonical-type", "s", &str); EXPECT_STREQ("com.canonical.indicator.root", str); g_clear_pointer(&str, g_free); g_menu_model_get_item_attribute(phone_menu_model, 0, G_MENU_ATTRIBUTE_ACTION, "s", &str); const auto action_name = profile + "-header"; EXPECT_EQ(std::string("indicator.")+action_name, str); g_clear_pointer(&str, g_free); // cursory first look at the header auto dict = g_action_group_get_action_state(action_group, action_name.c_str()); EXPECT_TRUE(dict != nullptr); EXPECT_TRUE(g_variant_is_of_type(dict, G_VARIANT_TYPE_VARDICT)); auto v = g_variant_lookup_value(dict, "accessible-desc", G_VARIANT_TYPE_STRING); EXPECT_TRUE(v != nullptr); g_variant_unref(v); v = g_variant_lookup_value(dict, "title", G_VARIANT_TYPE_STRING); EXPECT_TRUE(v != nullptr); EXPECT_STREQ(_("Files"), g_variant_get_string(v, nullptr)); g_variant_unref(v); v = g_variant_lookup_value(dict, "visible", G_VARIANT_TYPE_BOOLEAN); EXPECT_TRUE(g_variant_get_boolean(v)); EXPECT_TRUE(v != nullptr); g_clear_pointer(&v, g_variant_unref); g_clear_pointer(&dict, g_variant_unref); // Visibility test #1: // Change the model to all transfers finished. // Confirm that the header is not visible. for (auto& transfer : m_source->get_model()->get_all()) { transfer->state = Transfer::FINISHED; m_source->m_model->emit_changed(transfer->id); } wait_msec(200); EXPECT_FALSE(is_header_visible(action_group, action_name)); // Visibility test #2: // Change the model to all transfers finished except one running. // Confirm that the header is visible. auto transfer = m_source->get_model()->get("a"); transfer->state = Transfer::RUNNING; m_source->m_model->emit_changed(transfer->id); wait_msec(200); EXPECT_TRUE(is_header_visible(action_group, action_name)); // Visibility test #3: // Change the model to all transfers finished except one paused. // Confirm that the header is visible. transfer = m_source->get_model()->get("a"); transfer->state = Transfer::PAUSED; m_source->m_model->emit_changed(transfer->id); wait_msec(200); EXPECT_TRUE(is_header_visible(action_group, action_name)); // Visibility test #4: // Remove all the transfers from the menu. // Confirm that the header is not visible. for (const auto& id : m_source->get_model()->get_ids()) m_source->m_model->remove(id); wait_msec(200); EXPECT_FALSE(is_header_visible(action_group, action_name)); // cleanup g_clear_object(&action_group); g_clear_object(&phone_dbus_menu_model); g_clear_object(&connection); } /*** **** **** GMenu **** ***/ TEST_F(GMenuViewFixture, DoesExportMenu) { wait_msec(); auto connection = g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, nullptr); auto dbus_menu_model = g_dbus_menu_model_get(connection, BUS_NAME, BUS_PATH"/phone"); auto menu_model = G_MENU_MODEL(dbus_menu_model); // query the GDBusMenuModel for information to activate it int n = g_menu_model_get_n_items(menu_model); if (!n) { // give the model a moment to populate its info wait_msec(100); n = g_menu_model_get_n_items(menu_model); } EXPECT_TRUE(menu_model != nullptr); EXPECT_NE(0, n); // cleanup g_clear_object(&dbus_menu_model); g_clear_object(&connection); } indicator-transfer-0.2+16.04.20151216.5/tests/CMakeLists.txt0000644000015600001650000000417112634336113023565 0ustar pbuserpbgroup00000000000000include(FindGMock) include(FindValgrind) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) include_directories(${GMOCK_INCLUDE_DIRS}) include_directories(${GTEST_INCLUDE_DIRS}) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") # turn off the warnings that break Google Test set (CXX_WARNING_ARGS "${CXX_WARNING_ARGS} -Wno-global-constructors -Wno-weak-vtables -Wno-undef -Wno-c++98-compat-pedantic -Wno-missing-noreturn -Wno-used-but-marked-unused -Wno-padded -Wno-deprecated -Wno-sign-compare -Wno-shift-sign-overflow") endif() add_definitions(-fPIC) SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fPIC -g ${CXX_WARNING_ARGS}") # look for headers in our src dir, and also in the directories where we autogenerate files... include_directories (${CMAKE_SOURCE_DIR}/src) include_directories (${CMAKE_CURRENT_BINARY_DIR}) include_directories (${DBUSTEST_INCLUDE_DIRS}) function(add_valgrind_test_by_name name) set (TEST_NAME ${name}) add_executable (${TEST_NAME} ${TEST_NAME}.cpp) add_valgrind_test(${TEST_NAME} VALGRIND ./${TEST_NAME}) target_link_libraries (${TEST_NAME} indicator-transfer ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBRARIES} ${GMOCK_LIBRARIES}) endfunction() add_valgrind_test_by_name(test-controller) add_valgrind_test_by_name(test-multisource) add_valgrind_test_by_name(test-plugin-source) set(PLUGIN_NAME "mock-source-plugin") add_library(${PLUGIN_NAME} STATIC mock-source-plugin.cpp) target_link_libraries(${PLUGIN_NAME} PRIVATE ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBRARIES} ${GMOCK_LIBRARIES}) function(add_test_by_name name) set (TEST_NAME ${name}) add_executable (${TEST_NAME} ${TEST_NAME}.cpp) add_test (${TEST_NAME} ${TEST_NAME}) target_link_libraries (${TEST_NAME} indicator-transfer ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBRARIES} ${GMOCK_LIBRARIES}) endfunction() add_test_by_name(test-view-gmenu) #add_test_by_name(test-mocks) #add_test_by_name(test-gactions) #add_test_by_name(test-actions-live) #add_test_by_name(test-menus) #add_test_by_name(test-exporter) add_test (cppcheck cppcheck --enable=all -q --error-exitcode=2 --inline-suppr -I${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/tests) indicator-transfer-0.2+16.04.20151216.5/tests/manual0000644000015600001650000000437012634336113022226 0ustar pbuserpbgroup00000000000000 Test-case indicator-transfer/visibility
Start downloading an image from the Browser to the Gallery. (In the Browser, tap-and-hold on an image, choose 'Save image' in the popup, and select 'Gallery' at the 'Open with ' prompt.
If the indicator wasn't already visible in the panel, it should appear as the transfer begins.
After the last transfer finished, the indicator should disappear from the panel.
Test-case indicator-transfer/download-an-image
Start downloading an image from the Browser to the Gallery. (In the Browser, tap-and-hold on an image, choose 'Save image' in the popup, and select 'Gallery' at the 'Open with ' prompt.)
If the indicator wasn't already visible in the panel, it should appear as the transfer begins.
In the 'Ongoing Transfers' section, the transfer should appear
In the 'Ongoing Transfers' section, a 'Pause all' button should appear
While transfer is active, the indicator's icon should indicate activity
While transfer is active, the menuitem's progressbar should show its progress
As the transfer finishes, its menuitem should move from the 'Ongoing' to 'Successful' section
As the transfer finishes, the indicator's icon should change to indicate an idle state
As the transfer finishes, the 'Pause all' button should disappear
After the transfer is finished, the indicator should disappear from the panel.
Click on the completed transfer's menuitem
The gallery app should launch
Press the 'Clear all' button.
The transfer should be cleared from the menu.
The 'Clear all' button should disappear
If all actions produce the expected results listed, please submit a 'passed' result. If an action fails, or produces an unexpected result, please submit a 'failed' result and file a bug. Please be sure to include the bug number when you submit your result. indicator-transfer-0.2+16.04.20151216.5/include/0000755000015600001650000000000012634336272021311 5ustar pbuserpbgroup00000000000000indicator-transfer-0.2+16.04.20151216.5/include/transfer/0000755000015600001650000000000012634336272023135 5ustar pbuserpbgroup00000000000000indicator-transfer-0.2+16.04.20151216.5/include/transfer/model.h0000644000015600001650000000402112634336113024375 0ustar pbuserpbgroup00000000000000/* * Copyright 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . * * Authors: * Charles Kerr */ #ifndef INDICATOR_TRANSFER_MODEL_H #define INDICATOR_TRANSFER_MODEL_H #include #include #include #include // std::shared_ptr namespace unity { namespace indicator { namespace transfer { /** * \brief A model of all the Transfers that we know about */ class Model { public: virtual ~Model(); std::set get_ids() const; std::vector> get_all() const; std::shared_ptr get(const Transfer::Id&) const; int size() const; int count(const Transfer::Id&) const; const core::Signal& changed() const; const core::Signal& added() const; const core::Signal& removed() const; protected: std::map> m_transfers; core::Signal m_changed; core::Signal m_added; core::Signal m_removed; }; /** * \brief A Transfer Model that has a public API for changing its contents */ class MutableModel: public Model { public: ~MutableModel(); void add(const std::shared_ptr& add_me); void remove(const Transfer::Id&); void emit_changed(const Transfer::Id&); }; } // namespace transfer } // namespace indicator } // namespace unity #endif // INDICATOR_TRANSFER_MODEL_H indicator-transfer-0.2+16.04.20151216.5/include/transfer/transfer.h0000644000015600001650000000373412634336113025133 0ustar pbuserpbgroup00000000000000/* * Copyright 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . * * Authors: * Charles Kerr */ #ifndef INDICATOR_TRANSFER_TRANSFER_H #define INDICATOR_TRANSFER_TRANSFER_H #include // parent class #include // GIcon #include // time_t #include #include #include namespace unity { namespace indicator { namespace transfer { /** * \brief A simple struct representing a single Transfer */ struct Transfer { typedef enum { QUEUED, RUNNING, PAUSED, CANCELED, HASHING, PROCESSING, FINISHED, ERROR } State; State state = QUEUED; virtual bool can_start() const; virtual bool can_resume() const; virtual bool can_pause() const; virtual bool can_cancel() const; virtual bool can_clear() const; // -1 == unknown int seconds_left = -1; time_t time_started = 0; // [0...1] float progress = 0.0; // bytes per second uint64_t speed_Bps = 0; uint64_t total_size = 0; typedef std::string Id; Id id; std::string title; std::string app_icon; std::string custom_state; // meaningful iff state is ERROR std::string error_string; // meaningful iff state is FINISHED std::string local_path; protected: static std::string next_unique_id(); }; } // namespace transfer } // namespace indicator } // namespace unity #endif // INDICATOR_TRANSFER_TRANSFER_H indicator-transfer-0.2+16.04.20151216.5/include/transfer/view-gmenu.h0000644000015600001650000000245612634336113025372 0ustar pbuserpbgroup00000000000000/* * Copyright 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . * * Authors: * Charles Kerr */ #ifndef INDICATOR_TRANSFER_VIEW_GMENU_H #define INDICATOR_TRANSFER_VIEW_GMENU_H #include namespace unity { namespace indicator { namespace transfer { /** * \brief a View that exports GActions and GMenus onto the DBus */ class GMenuView { public: explicit GMenuView(const std::shared_ptr& controller); ~GMenuView(); const core::Signal<>& name_lost() const; private: class Impl; std::unique_ptr p; void set_model(const std::shared_ptr&); }; } // namespace transfer } // namespace indicator } // namespace unity #endif // INDICATOR_TRANSFER_VIEW_GMENU_H indicator-transfer-0.2+16.04.20151216.5/include/transfer/multisource.h0000644000015600001650000000324712634336113025661 0ustar pbuserpbgroup00000000000000/* * Copyright 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . * * Authors: * Charles Kerr */ #ifndef INDICATOR_TRANSFER_MULTISOURCE_H #define INDICATOR_TRANSFER_MULTISOURCE_H #include namespace unity { namespace indicator { namespace transfer { /** * \brief A multiplexer/demultiplexer for sources */ class MultiSource: public Source { public: MultiSource(); virtual ~MultiSource(); // Source void open(const Transfer::Id& id) override; void start(const Transfer::Id& id) override; void pause(const Transfer::Id& id) override; void resume(const Transfer::Id& id) override; void cancel(const Transfer::Id& id) override; void clear(const Transfer::Id& id) override; void open_app(const Transfer::Id& id) override; const std::shared_ptr get_model() override; void add_source(const std::shared_ptr& source); private: class Impl; std::unique_ptr impl; }; } // namespace transfer } // namespace indicator } // namespace unity #endif // INDICATOR_TRANSFER_MULTISOURCE_H indicator-transfer-0.2+16.04.20151216.5/include/transfer/controller.h0000644000015600001650000000372712634336113025474 0ustar pbuserpbgroup00000000000000/* * Copyright 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . * * Authors: * Charles Kerr */ #ifndef INDICATOR_TRANSFER_CONTROLLER_H #define INDICATOR_TRANSFER_CONTROLLER_H #include #include #include #include // std::shared_ptr namespace unity { namespace indicator { namespace transfer { /** * \brief Process actions triggered by views */ class Controller { public: explicit Controller(const std::shared_ptr& source); virtual ~Controller(); virtual void pause_all(); virtual void resume_all(); virtual void clear_all(); virtual void tap(const Transfer::Id&); virtual void start(const Transfer::Id&); virtual void pause(const Transfer::Id&); virtual void cancel(const Transfer::Id&); virtual void resume(const Transfer::Id&); virtual void clear(const Transfer::Id&); virtual void open(const Transfer::Id&); virtual void open_app(const Transfer::Id&); int size() const; int count(const Transfer::Id&) const; const std::shared_ptr get_model(); private: std::shared_ptr m_source; std::set get_ids() const; std::shared_ptr get(const Transfer::Id& id) const; }; } // namespace transfer } // namespace indicator } // namespace unity #endif // INDICATOR_TRANSFER_CONTROLLER_H indicator-transfer-0.2+16.04.20151216.5/include/transfer/view.h0000644000015600001650000000233712634336113024257 0ustar pbuserpbgroup00000000000000/* * Copyright 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . * * Authors: * Charles Kerr */ #ifndef INDICATOR_TRANSFER_VIEW_H #define INDICATOR_TRANSFER_VIEW_H #include // std::shared_ptr namespace unity { namespace indicator { namespace transfer { class Controller; class Model; /** * \brief Featureless View base class */ class View { public: virtual ~View(); virtual void set_controller(const std::shared_ptr&) =0; virtual void set_model(const std::shared_ptr&) =0; }; } // namespace transfer } // namespace indicator } // namespace unity #endif // INDICATOR_TRANSFER_VIEW_H indicator-transfer-0.2+16.04.20151216.5/include/transfer/source.h0000644000015600001650000000361312634336113024603 0ustar pbuserpbgroup00000000000000/* * Copyright 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . * * Authors: * Charles Kerr */ #ifndef INDICATOR_TRANSFER_SOURCE_H #define INDICATOR_TRANSFER_SOURCE_H #include #include // Id #include // std::shared_ptr namespace unity { namespace indicator { namespace transfer { /** * \brief Facade for everything outside of indicator-transfer * * A Source is where Transfer items come from; e.g. DMSource * watches DownloadManager on the bus and pulls Transfers from * signals emitted by it. * * It also handles indicator-transfer pauses, stops, resumes, * etc. Transfers. For example, DMSource delegates these requests * to DownloadManager over dbus. */ class Source { public: virtual ~Source(); virtual void open(const Transfer::Id& id) =0; virtual void start(const Transfer::Id& id) =0; virtual void pause(const Transfer::Id& id) =0; virtual void resume(const Transfer::Id& id) =0; virtual void cancel(const Transfer::Id& id) =0; virtual void clear(const Transfer::Id& id) =0; virtual void open_app(const Transfer::Id& id) =0; virtual const std::shared_ptr get_model() =0; }; } // namespace transfer } // namespace indicator } // namespace unity #endif // INDICATOR_TRANSFER_SOURCE_H indicator-transfer-0.2+16.04.20151216.5/include/transfer/plugin-source.h0000644000015600001650000000242712634336113026101 0ustar pbuserpbgroup00000000000000/* * Copyright 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . * * Authors: * Charles Kerr */ #ifndef INDICATOR_TRANSFER_SOURCE_PLUGIN_H #define INDICATOR_TRANSFER_SOURCE_PLUGIN_H #include #include // unique_ptr namespace unity { namespace indicator { namespace transfer { /** * \brief a MultiSource that gets its sources from plugins */ class PluginSource: public MultiSource { public: explicit PluginSource(const std::string& plugin_dir); ~PluginSource(); private: class Impl; std::unique_ptr impl; }; } // namespace transfer } // namespace indicator } // namespace unity #endif // INDICATOR_TRANSFER_SOURCE_PLUGINSH indicator-transfer-0.2+16.04.20151216.5/include/transfer/view-console.h0000644000015600001650000000306312634336113025714 0ustar pbuserpbgroup00000000000000/* * Copyright 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . * * Authors: * Charles Kerr */ #ifndef INDICATOR_TRANSFER_VIEW_CONSOLE_H #define INDICATOR_TRANSFER_VIEW_CONSOLE_H #include #include #include // shared_ptr #include namespace unity { namespace indicator { namespace transfer { /** * \brief a debugging view that dumps output to the console */ class ConsoleView: public View { public: ConsoleView(const std::shared_ptr&, const std::shared_ptr&); ~ConsoleView(); void set_controller(const std::shared_ptr&); void set_model(const std::shared_ptr&); private: std::shared_ptr m_model; std::shared_ptr m_controller; std::set m_connections; static gboolean on_timer (gpointer); }; } // namespace transfer } // namespace indicator } // namespace unity #endif // INDICATOR_TRANSFER_VIEW_H indicator-transfer-0.2+16.04.20151216.5/include/transfer/CMakeLists.txt0000644000015600001650000000030412634336113025664 0ustar pbuserpbgroup00000000000000set (SERVICE_LIB_PUBLIC_HEADERS model.h source.h transfer.h) install (FILES ${SERVICE_LIB_PUBLIC_HEADERS} DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR}/${CMAKE_PROJECT_NAME}/transfer) indicator-transfer-0.2+16.04.20151216.5/include/transfer/dm-source.h0000644000015600001650000000320612634336113025177 0ustar pbuserpbgroup00000000000000/* * Copyright 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . * * Authors: * Charles Kerr */ #ifndef INDICATOR_TRANSFER_DM_SOURCE_H #define INDICATOR_TRANSFER_DM_SOURCE_H #include #include #include namespace unity { namespace indicator { namespace transfer { /** * \brief a Source that gets its updates & events from the Download Manager. */ class DMSource: public Source { public: DMSource(); ~DMSource(); void open(const Transfer::Id& id) override; void start(const Transfer::Id& id) override; void pause(const Transfer::Id& id) override; void resume(const Transfer::Id& id) override; void cancel(const Transfer::Id& id) override; void clear(const Transfer::Id& id) override; void open_app(const Transfer::Id& id) override; const std::shared_ptr get_model() override; private: class Impl; std::unique_ptr impl; }; } // namespace transfer } // namespace indicator } // namespace unity #endif // INDICATOR_TRANSFER_DM_SOURCE_H indicator-transfer-0.2+16.04.20151216.5/include/transfer/dbus-shared.h0000644000015600001650000000167012634336113025505 0ustar pbuserpbgroup00000000000000/* * Copyright 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . * * Authors: * Charles Kerr */ #ifndef INDICATOR_TRANFSFER_DBUS_SHARED_H #define INDICATOR_TRANFSFER_DBUS_SHARED_H #define BUS_NAME "com.canonical.indicator.transfer" #define BUS_PATH "/com/canonical/indicator/transfer" #endif /* INDICATOR_TRANFSFER_DBUS_SHARED_H */ indicator-transfer-0.2+16.04.20151216.5/include/CMakeLists.txt0000644000015600001650000000003312634336113024037 0ustar pbuserpbgroup00000000000000add_subdirectory(transfer) indicator-transfer-0.2+16.04.20151216.5/src/0000755000015600001650000000000012634336272020455 5ustar pbuserpbgroup00000000000000indicator-transfer-0.2+16.04.20151216.5/src/dm-plugin/0000755000015600001650000000000012634336272022351 5ustar pbuserpbgroup00000000000000indicator-transfer-0.2+16.04.20151216.5/src/dm-plugin/dm-source.cpp0000644000015600001650000006712412634336130024756 0ustar pbuserpbgroup00000000000000/* * Copyright 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . * * Authors: * Charles Kerr */ #include #include #include #include #include #include #include #include namespace unity { namespace indicator { namespace transfer { namespace { static constexpr char const * DM_BUS_NAME {"com.canonical.applications.Downloader"}; static constexpr char const * DM_MANAGER_IFACE_NAME {"com.canonical.applications.DownloadManager"}; static constexpr char const * DM_DOWNLOAD_IFACE_NAME {"com.canonical.applications.Download"}; /** * A Transfer whose state comes from content-hub and ubuntu-download-manager. * * Each DMTransfer tracks a com.canonical.applications.Download (ccad) object * from ubuntu-download-manager. The ccad is used for pause/resume/cancel, * state change / download progress signals, etc. * */ class DMTransfer: public Transfer { public: DMTransfer(GDBusConnection* connection, const std::string& ccad_path): m_bus(G_DBUS_CONNECTION(g_object_ref(connection))), m_cancellable(g_cancellable_new()), m_ccad_path(ccad_path) { id = next_unique_id(); time_started = time(nullptr); get_ccad_properties(); } ~DMTransfer() { if (m_changed_tag) g_source_remove(m_changed_tag); g_cancellable_cancel(m_cancellable); g_clear_object(&m_cancellable); g_clear_object(&m_bus); } core::Signal<>& changed() { return m_changed; } void start() { g_return_if_fail(can_start()); call_ccad_method_no_args_no_response("start"); } void pause() { g_return_if_fail(can_pause()); call_ccad_method_no_args_no_response("pause"); } void resume() { g_return_if_fail(can_resume()); call_ccad_method_no_args_no_response("resume"); } void cancel() { call_ccad_method_no_args_no_response("cancel"); } void open() { open_app(); } void open_app() { // destination app has priority over app_id std::string app_id = download_app_id(); if (app_id.empty() && !m_package_name.empty()) { app_id = std::string(ubuntu_app_launch_triplet_to_app_id(m_package_name.c_str(), "first-listed-app", "current-user-version")); } if (app_id.empty()) { g_warning("Fail to discovery app-id"); } else { g_debug("calling ubuntu_app_launch_start_application() for %s", app_id.c_str()); ubuntu_app_launch_start_application(app_id.c_str(), nullptr); } } const std::string& ccad_path() const { return m_ccad_path; } void handle_ccad_signal(const gchar* signal_name, GVariant* parameters) { if (!g_strcmp0(signal_name, "started")) { if (get_signal_success_arg(parameters)) set_state(RUNNING); } else if (!g_strcmp0(signal_name, "paused")) { if (get_signal_success_arg(parameters)) set_state(PAUSED); } else if (!g_strcmp0(signal_name, "resumed")) { if (get_signal_success_arg(parameters)) set_state(RUNNING); } else if (!g_strcmp0(signal_name, "canceled")) { if (get_signal_success_arg(parameters)) set_state(CANCELED); } else if (!g_strcmp0(signal_name, "hashing")) { set_state(HASHING); } else if (!g_strcmp0(signal_name, "processing")) { set_state(PROCESSING); } else if (!g_strcmp0(signal_name, "finished")) { char* local_path = nullptr; g_variant_get_child(parameters, 0, "s", &local_path); set_local_path(local_path); g_free(local_path); set_state(FINISHED); } else if (!g_strcmp0(signal_name, "error")) { char* error_string = nullptr; g_variant_get_child(parameters, 0, "s", &error_string); set_error_string(error_string); set_state(ERROR); g_free(error_string); } else if (!g_strcmp0(signal_name, "progress")) { set_state(RUNNING); g_variant_get_child(parameters, 0, "t", &m_received); g_variant_get_child(parameters, 1, "t", &m_total_size); update_progress(); } else if (!g_strcmp0(signal_name, "httpError") || !g_strcmp0(signal_name, "networkError") || !g_strcmp0(signal_name, "processsError")) { int32_t i; char* str = nullptr; g_variant_get_child(parameters, 0, "(is)", &i, &str); g_debug("%s setting error to '%s'", G_STRLOC, str); set_error_string(str); set_state(ERROR); g_free(str); } else { auto args = g_variant_print(parameters, true); g_warning("%s: unrecognized signal '%s': %s", G_STRLOC, signal_name, args); g_free(args); } } bool can_resume() const override { return state==PAUSED; } private: const std::string& download_app_id() const { return m_app_id.empty() ? m_destination_app : m_app_id; } void emit_changed_soon() { if (m_changed_tag == 0) m_changed_tag = g_timeout_add_seconds(1, emit_changed_now, this); } static gboolean emit_changed_now(gpointer gself) { auto self = static_cast(gself); self->m_changed_tag = 0; self->m_changed(); return G_SOURCE_REMOVE; } /* The 'started', 'paused', 'resumed', and 'canceled' signals from com.canonical.applications.Download all have a single parameter, a boolean success flag. */ bool get_signal_success_arg(GVariant* parameters) { gboolean success = false; g_return_val_if_fail(g_variant_is_container(parameters), false); g_return_val_if_fail(g_variant_n_children(parameters) == 1, false); g_variant_get_child(parameters, 0, "b", &success); return success; } uint64_t get_averaged_speed_Bps() { // limit the average to the last X samples static constexpr int max_slots = 50; if (m_history.size() > max_slots) m_history.erase(m_history.begin(), m_history.end()-max_slots); // limit the average to the last Y seconds static constexpr unsigned int max_age_seconds = 30; const auto oldest_allowed_usec = g_get_real_time() - (max_age_seconds * G_USEC_PER_SEC); const auto is_young = [oldest_allowed_usec](const DownloadProgress& p){return p.time_usec >= oldest_allowed_usec;}; m_history.erase(std::begin(m_history), std::find_if(std::begin(m_history), std::end(m_history), is_young)); uint64_t Bps; if (m_history.size() < 2) { Bps = 0; } else { const auto diff = m_history.back() - m_history.front(); Bps = (diff.bytes * G_USEC_PER_SEC) / diff.time_usec; } return Bps; } void update_progress() { uint64_t tmp_total_size = 0; float tmp_progress = 0.0f; int tmp_seconds_left = 0; uint64_t tmp_speed_Bps = 0; if (m_total_size && m_received) { // update our speed tables m_history.push_back(DownloadProgress{g_get_real_time(),m_received}); const auto Bps = get_averaged_speed_Bps(); const int seconds = Bps ? (int)((m_total_size - m_received) / Bps) : -1; tmp_total_size = m_total_size; tmp_speed_Bps = Bps; tmp_progress = m_received / (float)m_total_size; tmp_seconds_left = seconds; } bool changed = false; if ((int)(progress*100) != (int)(tmp_progress*100)) { progress = tmp_progress; changed = true; } if (seconds_left != tmp_seconds_left) { g_debug("changing '%s' seconds_left to '%d'", m_ccad_path.c_str(), (int)tmp_seconds_left); seconds_left = tmp_seconds_left; changed = true; } if (speed_Bps != tmp_speed_Bps) { speed_Bps = tmp_speed_Bps; changed = true; } if (total_size != tmp_total_size) { total_size = tmp_total_size; changed = true; } if (changed) emit_changed_soon(); } void set_state(State state_in) { if (state != state_in) { state = state_in; if (!can_pause()) { speed_Bps = 0; m_history.clear(); } emit_changed_soon(); } } void set_error_string(const char* str) { const std::string tmp = str ? str : ""; if (error_string != tmp) { g_debug("changing '%s' error to '%s'", m_ccad_path.c_str(), tmp.c_str()); error_string = tmp; emit_changed_soon(); } } void set_local_path(const char* str) { const std::string tmp = str ? str : ""; if (local_path != tmp) { g_debug("changing '%s' path to '%s'", m_ccad_path.c_str(), tmp.c_str()); local_path = tmp; emit_changed_soon(); } // If we don't already have a title, // use the file's basename as the title if (title.empty()) { auto bname = g_path_get_basename(str); set_title(bname); g_free(bname); } } void set_title(const char* title_in) { const std::string tmp = title_in ? title_in : ""; if (title != tmp) { g_debug("changing '%s' title to '%s'", m_ccad_path.c_str(), tmp.c_str()); title = tmp; emit_changed_soon(); } } void set_icon(const char* filename) { const std::string tmp = filename ? filename : ""; if (app_icon != tmp) { g_debug("changing '%s' icon to '%s'", m_ccad_path.c_str(), tmp.c_str()); app_icon = tmp; emit_changed_soon(); } } /*** **** DownloadManager ***/ void get_ccad_properties() { const auto bus_name = DM_BUS_NAME; const auto object_path = m_ccad_path.c_str(); const auto interface_name = DM_DOWNLOAD_IFACE_NAME; g_dbus_connection_call(m_bus, bus_name, object_path, interface_name, "totalSize", nullptr, G_VARIANT_TYPE("(t)"), G_DBUS_CALL_FLAGS_NONE, -1, m_cancellable, on_ccad_total_size, this); g_dbus_connection_call(m_bus, bus_name, object_path, interface_name, "progress", nullptr, G_VARIANT_TYPE("(t)"), G_DBUS_CALL_FLAGS_NONE, -1, m_cancellable, on_ccad_progress, this); g_dbus_connection_call(m_bus, bus_name, object_path, interface_name, "metadata", nullptr, G_VARIANT_TYPE("(a{sv})"), G_DBUS_CALL_FLAGS_NONE, -1, m_cancellable, on_ccad_metadata, this); g_dbus_connection_call(m_bus, bus_name, object_path, "org.freedesktop.DBus.Properties", "Get", g_variant_new ("(ss)", interface_name, "DestinationApp"), G_VARIANT_TYPE ("(v)"), G_DBUS_CALL_FLAGS_NONE, -1, m_cancellable, on_ccad_destination_app, this); g_dbus_connection_call(m_bus, bus_name, object_path, "org.freedesktop.DBus.Properties", "Get", g_variant_new ("(ss)", interface_name, "Title"), G_VARIANT_TYPE ("(v)"), G_DBUS_CALL_FLAGS_NONE, -1, m_cancellable, on_ccad_title, this); } static void on_ccad_total_size(GObject * source, GAsyncResult * res, gpointer gself) { auto v = connection_call_finish(source, res, "Error calling totalSize()"); if (v != nullptr) { guint64 n = 0; g_variant_get_child(v, 0, "t", &n); g_variant_unref(v); auto self = static_cast(gself); self->m_total_size = n; self->update_progress(); } } static void on_ccad_progress(GObject * source, GAsyncResult * res, gpointer gself) { auto v = connection_call_finish(source, res, "Error calling progress()"); if (v != nullptr) { guint64 n = 0; g_variant_get_child(v, 0, "t", &n); g_variant_unref(v); auto self = static_cast(gself); self->m_received = n; self->update_progress(); } } static void on_ccad_metadata(GObject * source, GAsyncResult * res, gpointer gself) { auto v = connection_call_finish(source, res, "Error calling metadata()"); if (v != nullptr) { auto self = static_cast(gself); GVariant *dict; GVariantIter iter; GVariant *value; gchar *key; dict = g_variant_get_child_value(v, 0); g_variant_iter_init (&iter, dict); self->m_app_id = ""; self->m_package_name = ""; while (g_variant_iter_next(&iter, "{sv}", &key, &value)) { if (g_strcmp0(key, "app-id") == 0) { self->m_app_id = std::string(g_variant_get_string(value, nullptr)); } // update-manager uses package-name if (g_strcmp0(key, "package-name") == 0) { self->m_package_name = std::string(g_variant_get_string(value, nullptr)); } // must free data for ourselves g_variant_unref(value); g_free (key); } g_variant_unref(dict); g_debug("App id: %s", self->m_app_id.c_str()); g_debug("Package name: %s", self->m_package_name.c_str()); self->update_app_info(); } } static void on_ccad_destination_app(GObject * source, GAsyncResult * res, gpointer gself) { auto v = connection_call_finish(source, res, "Error getting destinationApp property"); if (v != nullptr) { GVariant *value, *item; item = g_variant_get_child_value(v, 0); value = g_variant_get_variant(item); g_variant_unref(item); auto self = static_cast(gself); self->m_destination_app = std::string(g_variant_get_string(value, nullptr)); g_debug("Destination app: %s", self->m_destination_app.c_str()); self->update_app_info(); g_variant_unref(v); } } static void on_ccad_title(GObject * source, GAsyncResult * res, gpointer gself) { auto v = connection_call_finish(source, res, "Error getting Title property"); if (v != nullptr) { GVariant *value, *item; item = g_variant_get_child_value(v, 0); value = g_variant_get_variant(item); g_variant_unref(item); auto self = static_cast(gself); auto title = g_variant_get_string(value, nullptr); g_debug("Download title: %s", title); if (title && strlen(title)) self->set_title(title); g_variant_unref(v); } } void call_ccad_method_no_args_no_response(const char* method_name) { const auto bus_name = DM_BUS_NAME; const auto object_path = m_ccad_path.c_str(); const auto interface_name = DM_DOWNLOAD_IFACE_NAME; g_debug("%s transfer %s calling '%s' with '%s'", G_STRLOC, id.c_str(), method_name, object_path); g_dbus_connection_call(m_bus, bus_name, object_path, interface_name, method_name, nullptr, nullptr, G_DBUS_CALL_FLAGS_NONE, -1, m_cancellable, nullptr, nullptr); } void update_app_info() { // destination app has priority over app_id std::string app_id = download_app_id(); if (!app_id.empty()) update_app_info_from_app_id(app_id); else if (!m_package_name.empty()) update_app_info_from_package_name(m_package_name); else g_warning("Download without app-id or package-name"); } void update_app_info_from_package_name(const std::string &package_name) { std::string app_id = std::string(ubuntu_app_launch_triplet_to_app_id(package_name.c_str(), "first-listed-app", "current-user-version")); if (!app_id.empty()) update_app_info_from_app_id(app_id); else g_warning("fail to retrive app-id from package: %s", package_name.c_str()); } void update_app_info_from_app_id(const std::string &app_id) { gchar *app_dir; gchar *app_desktop_file; if (!ubuntu_app_launch_application_info(app_id.c_str(), &app_dir, &app_desktop_file)) { g_warning("Fail to get app info: %s", app_id.c_str()); return; } g_debug("App data: %s : %s", app_dir, app_desktop_file); gchar *full_app_desktop_file = g_build_filename(app_dir, app_desktop_file, nullptr); GKeyFile *app_info = g_key_file_new(); GError *error = nullptr; g_debug("Open desktop file: %s", full_app_desktop_file); g_key_file_load_from_file(app_info, full_app_desktop_file, G_KEY_FILE_NONE, &error); if (error) { g_warning("Fail to open desktop info: %s:%s", full_app_desktop_file, error->message); g_free(full_app_desktop_file); g_key_file_free(app_info); g_error_free(error); } else { gchar *icon_name = g_key_file_get_string(app_info, "Desktop Entry", "Icon", &error); if (error == nullptr) { gchar *full_icon_name = g_build_filename(app_dir, icon_name, nullptr); g_debug("App icon: %s", icon_name); g_debug("App full icon name: %s", full_icon_name); // check if it is full path icon or a themed one if (g_file_test(full_icon_name, G_FILE_TEST_EXISTS)) set_icon(full_icon_name); else set_icon(icon_name); g_free(full_icon_name); } else { g_warning("Fail to retrive icon:", error->message); g_error_free(error); } g_free(icon_name); } g_key_file_free(app_info); g_free(full_app_desktop_file); g_free(app_dir); g_free(app_desktop_file); } /*** **** ***/ static GVariant* connection_call_finish(GObject * connection, GAsyncResult * res, const char * warning) { GError* error = nullptr; auto v = g_dbus_connection_call_finish(G_DBUS_CONNECTION(connection), res, &error); if (v == nullptr) { if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) g_warning("%s: %s", warning, error->message); g_error_free(error); } return v; } core::Signal<> m_changed; uint32_t m_changed_tag = 0; uint64_t m_received = 0; uint64_t m_total_size = 0; struct DownloadProgress { int64_t time_usec; // microseconds since epoch uint64_t bytes; DownloadProgress operator-(const DownloadProgress& that) { return DownloadProgress{time_usec-that.time_usec, bytes-that.bytes}; } }; std::vector m_history; GDBusConnection* m_bus = nullptr; GCancellable* m_cancellable = nullptr; std::string m_app_id; std::string m_destination_app; std::string m_package_name; const std::string m_ccad_path; }; } // anonymous namespace /*** **** ***/ class DMSource::Impl { public: Impl(): m_cancellable(g_cancellable_new()), m_model(std::make_shared()) { g_bus_get(G_BUS_TYPE_SESSION, m_cancellable, on_bus_ready, this); } ~Impl() { g_cancellable_cancel(m_cancellable); g_clear_object(&m_cancellable); set_bus(nullptr); g_clear_object(&m_bus); } void start(const Transfer::Id& id) { auto transfer = find_transfer_by_id(id); g_return_if_fail(transfer); transfer->start(); } void pause(const Transfer::Id& id) { auto transfer = find_transfer_by_id(id); g_return_if_fail(transfer); transfer->pause(); } void resume(const Transfer::Id& id) { auto transfer = find_transfer_by_id(id); g_return_if_fail(transfer); transfer->resume(); } void cancel(const Transfer::Id& id) { auto transfer = find_transfer_by_id(id); g_return_if_fail(transfer); transfer->cancel(); // remove transfer from the list if canceled m_removed_ccad.insert(transfer->ccad_path()); m_model->remove(id); } void clear(const Transfer::Id& id) { auto transfer = find_transfer_by_id(id); if (transfer) { m_removed_ccad.insert(transfer->ccad_path()); m_model->remove(id); } } void open(const Transfer::Id& id) { auto transfer = find_transfer_by_id(id); g_return_if_fail(transfer); transfer->open(); transfer->open_app(); } void open_app(const Transfer::Id& id) { auto transfer = find_transfer_by_id(id); g_return_if_fail(transfer); transfer->open_app(); } std::shared_ptr get_model() { return m_model; } private: static void on_bus_ready(GObject * /*source_object*/, GAsyncResult * res, gpointer gself) { GError* error = nullptr; auto bus = g_bus_get_finish(res, &error); if (bus == nullptr) { if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) g_warning("Could not get session bus: %s", error->message); g_error_free(error); } else { static_cast(gself)->set_bus(bus); g_object_unref(bus); } } void set_bus(GDBusConnection* bus) { if (m_bus != nullptr) { for (const auto& tag : m_signal_subscriptions) g_dbus_connection_signal_unsubscribe(m_bus, tag); m_signal_subscriptions.clear(); g_clear_object(&m_bus); } if (bus != nullptr) { g_debug("%s: %s", G_STRFUNC, g_dbus_connection_get_unique_name(bus)); m_bus = G_DBUS_CONNECTION(g_object_ref(bus)); guint tag; tag = g_dbus_connection_signal_subscribe(bus, DM_BUS_NAME, DM_DOWNLOAD_IFACE_NAME, nullptr, nullptr, nullptr, G_DBUS_SIGNAL_FLAGS_NONE, on_download_signal, this, nullptr); m_signal_subscriptions.insert(tag); } } static void on_download_signal(GDBusConnection* /*connection*/, const gchar* /*sender_name*/, const gchar* ccad_path, const gchar* /*interface_name*/, const gchar* signal_name, GVariant* parameters, gpointer gself) { gchar* variant_str = g_variant_print(parameters, TRUE); g_debug("download signal: %s %s %s", ccad_path, signal_name, variant_str); g_free(variant_str); // Route this signal to the DMTransfer for processing auto self = static_cast(gself); auto transfer = self->find_transfer_by_ccad_path(ccad_path); if (transfer) transfer->handle_ccad_signal(signal_name, parameters); else self->create_new_transfer(ccad_path); } /*** **** ***/ std::shared_ptr find_transfer_by_ccad_path(const std::string& path) { for (const auto& transfer : m_model->get_all()) { const auto tmp = std::static_pointer_cast(transfer); if (tmp && (path == tmp->ccad_path())) return tmp; } return nullptr; } void create_new_transfer(const std::string& ccad_path) { // don't let transfers reappear after they've been cleared by the user if (m_removed_ccad.count(ccad_path)) return; // check if the download should appear on indicator GError *error = nullptr; auto show = g_dbus_connection_call_sync(m_bus, DM_BUS_NAME, ccad_path.c_str(), "org.freedesktop.DBus.Properties", "Get", g_variant_new ("(ss)", DM_DOWNLOAD_IFACE_NAME, "ShowInIndicator"), G_VARIANT_TYPE ("(v)"), G_DBUS_CALL_FLAGS_NONE, -1, m_cancellable, &error); if (show != nullptr) { GVariant *value, *item; item = g_variant_get_child_value(show, 0); value = g_variant_get_variant(item); bool show_in_idicator = g_variant_get_boolean(value); g_variant_unref(value); g_variant_unref(item); g_variant_unref(show); if (!show_in_idicator) { m_removed_ccad.insert(ccad_path); return; } } else if (error != nullptr) { if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) g_warning("Fail to retrieve 'ShowInIndicator' property: %s", error->message); g_error_free(error); } auto new_transfer = std::make_shared(m_bus, ccad_path); m_model->add(new_transfer); // when one of the DMTransfer's properties changes, // emit a change signal for the model const auto id = new_transfer->id; new_transfer->changed().connect([this,id]{ if (m_model->get(id)) m_model->emit_changed(id); }); } std::shared_ptr find_transfer_by_id(const Transfer::Id& id) { auto transfer = m_model->get(id); g_return_val_if_fail(transfer, std::shared_ptr()); return std::static_pointer_cast(transfer); } GDBusConnection* m_bus = nullptr; GCancellable* m_cancellable = nullptr; std::set m_signal_subscriptions; std::shared_ptr m_model; std::set m_removed_ccad; }; /*** **** ***/ DMSource::DMSource(): impl(new Impl{}) { } DMSource::~DMSource() { } void DMSource::open(const Transfer::Id& id) { impl->open(id); } void DMSource::start(const Transfer::Id& id) { impl->start(id); } void DMSource::pause(const Transfer::Id& id) { impl->pause(id); } void DMSource::resume(const Transfer::Id& id) { impl->resume(id); } void DMSource::cancel(const Transfer::Id& id) { impl->cancel(id); } void DMSource::clear(const Transfer::Id& id) { impl->clear(id); } void DMSource::open_app(const Transfer::Id& id) { impl->open_app(id); } const std::shared_ptr DMSource::get_model() { return impl->get_model(); } /*** **** ***/ } // namespace transfer } // namespace indicator } // namespace unity indicator-transfer-0.2+16.04.20151216.5/src/dm-plugin/dm-plugin.cpp0000644000015600001650000000163212634336113024745 0ustar pbuserpbgroup00000000000000/* * Copyright 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . * * Authors: * Charles Kerr */ #include #include using namespace unity::indicator::transfer; extern "C" { G_MODULE_EXPORT Source* get_source() { return new unity::indicator::transfer::DMSource{}; } } indicator-transfer-0.2+16.04.20151216.5/src/dm-plugin/CMakeLists.txt0000644000015600001650000000104612634336113025104 0ustar pbuserpbgroup00000000000000# the DownloadManager source plugin... set(DM_LIB "dmtransfers") set(DM_SOURCES dm-source.cpp dm-plugin.cpp) include_directories ( ${CAMAKE_SOURCE_DIR}/src) add_library(${DM_LIB} MODULE ${DM_SOURCES}) target_link_libraries (${DM_LIB} indicator-transfer ${SERVICE_DEPS_LIBRARIES} ${GCOV_LIBS}) install(TARGETS ${DM_LIB} LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_PKGLIBEXECDIR}) set_property (SOURCE ${DM_SOURCES} APPEND_STRING PROPERTY COMPILE_FLAGS " -std=c++11 -fPIC -g ${CXX_WARNING_ARGS} ${GCOV_FLAGS}") indicator-transfer-0.2+16.04.20151216.5/src/main.cpp0000644000015600001650000000327312634336113022104 0ustar pbuserpbgroup00000000000000/* * Copyright 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . * * Authors: * Charles Kerr */ #include #include #include #include #include // bindtextdomain() #include #include using namespace unity::indicator::transfer; int main(int /*argc*/, char** /*argv*/) { // Work around a deadlock in glib's type initialization. // It can be removed when https://bugzilla.gnome.org/show_bug.cgi?id=674885 is fixed. g_type_ensure(G_TYPE_DBUS_CONNECTION); // boilerplate i18n setlocale(LC_ALL, ""); bindtextdomain(GETTEXT_PACKAGE, GNOMELOCALEDIR); textdomain(GETTEXT_PACKAGE); auto loop = g_main_loop_new(nullptr, false); // run until we lose the busname auto source = std::make_shared(PLUGINDIR); auto controller = std::make_shared(source); GMenuView menu_view (controller); // FIXME: listen for busname-lost g_main_loop_run(loop); // cleanup g_main_loop_unref(loop); return 0; } indicator-transfer-0.2+16.04.20151216.5/src/source.cpp0000644000015600001650000000164312634336113022457 0ustar pbuserpbgroup00000000000000/* * Copyright 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . * * Authors: * Charles Kerr */ #include namespace unity { namespace indicator { namespace transfer { /*** **** ***/ Source::~Source() { } /*** **** ***/ } // namespace transfer } // namespace indicator } // namespace unity indicator-transfer-0.2+16.04.20151216.5/src/view.cpp0000644000015600001650000000163412634336113022131 0ustar pbuserpbgroup00000000000000/* * Copyright 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . * * Authors: * Charles Kerr */ #include namespace unity { namespace indicator { namespace transfer { /*** **** ***/ View::~View() { } /*** **** ***/ } // namespace transfer } // namespace indicator } // namespace unity indicator-transfer-0.2+16.04.20151216.5/src/controller.cpp0000644000015600001650000000572712634336113023351 0ustar pbuserpbgroup00000000000000/* * Copyright 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . * * Authors: * Charles Kerr */ #include namespace unity { namespace indicator { namespace transfer { /*** **** ***/ Controller::Controller(const std::shared_ptr& source): m_source(source) { } Controller::~Controller() { } void Controller::pause_all() { for(const auto& id : get_ids()) pause(id); } void Controller::resume_all() { for(const auto& id : get_ids()) resume(id); } void Controller::clear_all() { for (const auto& id : get_ids()) clear(id); } void Controller::tap(const Transfer::Id& id) { const auto transfer = get(id); g_return_if_fail (transfer); if (transfer->can_start()) start(id); else if (transfer->can_resume()) resume(id); else if (transfer->can_pause()) pause(id); else if (transfer->state == Transfer::FINISHED) open(id); } void Controller::pause(const Transfer::Id& id) { const auto& transfer = get(id); if (transfer && transfer->can_pause()) m_source->pause(id); } void Controller::cancel(const Transfer::Id& id) { const auto& transfer = get(id); if (transfer && transfer->can_cancel()) m_source->cancel(id); } void Controller::clear(const Transfer::Id& id) { const auto& transfer = get(id); if (transfer && transfer->can_clear()) m_source->clear(id); } void Controller::resume(const Transfer::Id& id) { const auto& transfer = get(id); if (transfer && transfer->can_resume()) m_source->resume(id); } void Controller::start(const Transfer::Id& id) { const auto& transfer = get(id); if (transfer && transfer->can_start()) m_source->start(id); } void Controller::open(const Transfer::Id& id) { m_source->open(id); } void Controller::open_app(const Transfer::Id& id) { m_source->open_app(id); } int Controller::size() const { return m_source->get_model()->size(); } int Controller::count(const Transfer::Id& id) const { return m_source->get_model()->count(id); } const std::shared_ptr Controller::get_model() { return m_source->get_model(); } std::set Controller::get_ids() const { return m_source->get_model()->get_ids(); } std::shared_ptr Controller::get(const Transfer::Id& id) const { return m_source->get_model()->get(id); } /*** **** ***/ } // namespace transfer } // namespace indicator } // namespace unity indicator-transfer-0.2+16.04.20151216.5/src/model.cpp0000644000015600001650000000443612634336113022262 0ustar pbuserpbgroup00000000000000/* * Copyright 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . * * Authors: * Charles Kerr */ #include namespace unity { namespace indicator { namespace transfer { Model::~Model() { } std::set Model::get_ids() const { std::set keys; for(const auto& it : m_transfers) keys.insert(it.first); return keys; } std::vector> Model::get_all() const { std::vector> transfers; for(const auto& it : m_transfers) transfers.push_back(it.second); return transfers; } std::shared_ptr Model::get(const Transfer::Id& id) const { std::shared_ptr ret; auto it = m_transfers.find(id); if (it != m_transfers.end()) ret = it->second; return ret; } int Model::size() const { return m_transfers.size(); } int Model::count(const Transfer::Id& id) const { return m_transfers.count(id); } const core::Signal& Model::changed() const { return m_changed; } const core::Signal& Model::added() const { return m_added; } const core::Signal& Model::removed() const { return m_removed; } /*** **** ***/ MutableModel::~MutableModel() { } void MutableModel::add(const std::shared_ptr& add_me) { const auto& id = add_me->id; m_transfers[id] = add_me; m_added(id); } void MutableModel::remove(const Transfer::Id& id) { auto it = m_transfers.find(id); g_return_if_fail (it != m_transfers.end()); m_removed(id); m_transfers.erase(it); } void MutableModel::emit_changed(const Transfer::Id& id) { m_changed(id); } /*** **** ***/ } // namespace transfer } // namespace indicator } // namespace unity indicator-transfer-0.2+16.04.20151216.5/src/view-gmenu.cpp0000644000015600001650000007027612634336130023251 0ustar pbuserpbgroup00000000000000/* * Copyright 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . * * Authors: * Charles Kerr */ #include #include #include #include #include #include namespace unity { namespace indicator { namespace transfer { /**** ***** ****/ namespace { /** * \brief GActionGroup wrapper that routes action callbacks to the Controller */ class GActions { public: explicit GActions(const std::shared_ptr& controller): m_action_group(g_simple_action_group_new()), m_controller(controller) { set_model(controller->get_model()); const GActionEntry entries[] = { { "activate-transfer", on_tap, "s", nullptr }, { "cancel-transfer", on_cancel, "s", nullptr }, { "pause-transfer", on_pause, "s", nullptr }, { "resume-transfer", on_resume, "s", nullptr }, { "open-transfer", on_open, "s", nullptr }, { "open-app-transfer", on_open_app, "s", nullptr }, { "resume-all", on_resume_all }, { "pause-all", on_pause_all }, { "clear-all", on_clear_all } }; auto gam = G_ACTION_MAP(m_action_group); g_action_map_add_action_entries(gam, entries, G_N_ELEMENTS(entries), this); // add the header actions auto v = create_default_header_state(); auto a = g_simple_action_new_stateful("phone-header", nullptr, v); g_action_map_add_action(gam, G_ACTION(a)); } void set_model(const std::shared_ptr& model) { // out with the old... auto& c = m_connections; c.clear(); if (m_model) for (const auto& id : m_model->get_ids()) remove(id); // ...in with the new if ((m_model = model)) { c.insert(m_model->added().connect([this](const Transfer::Id& id){add(id);})); c.insert(m_model->changed().connect([this](const Transfer::Id& id){update(id);})); c.insert(m_model->removed().connect([this](const Transfer::Id& id){remove(id);})); // add the transfers for (const auto& id : m_model->get_ids()) add(id); } } ~GActions() { g_clear_object(&m_action_group); } GActionGroup* action_group() const { return G_ACTION_GROUP(m_action_group); } private: /*** **** TRANSFER STATES ***/ void add(const Transfer::Id& id) { const auto name = get_transfer_action_name(id); const auto state = create_transfer_state(id); auto a = g_simple_action_new_stateful(name.c_str(), nullptr, state); g_action_map_add_action(action_map(), G_ACTION(a)); } void update(const Transfer::Id& id) { const auto name = get_transfer_action_name(id); const auto state = create_transfer_state(id); g_action_group_change_action_state(action_group(), name.c_str(), state); } void remove(const Transfer::Id& id) { const auto name = get_transfer_action_name(id); g_action_map_remove_action(action_map(), name.c_str()); } std::string get_transfer_action_name (const Transfer::Id& id) { return std::string("transfer-state.") + id; } GVariant* create_transfer_state(const Transfer::Id& id) { return create_transfer_state(m_model->get(id)); } GVariant* create_transfer_state(const std::shared_ptr& transfer) { GVariantBuilder b; g_variant_builder_init(&b, G_VARIANT_TYPE_VARDICT); if (transfer) { g_variant_builder_add(&b, "{sv}", "percent", g_variant_new_double(CLAMP(transfer->progress, 0.0, 1.0))); if ((transfer->seconds_left >= 0) && (int(transfer->progress*100.0) < 100)) { g_variant_builder_add(&b, "{sv}", "seconds-left", g_variant_new_int32(transfer->seconds_left)); } g_variant_builder_add(&b, "{sv}", "state", g_variant_new_int32(transfer->state)); g_variant_builder_add(&b, "{sv}", "state-label", g_variant_new_string(transfer->custom_state.c_str())); } else { g_warn_if_reached(); } return g_variant_builder_end(&b); } /*** **** ACTION CALLBACKS ***/ std::shared_ptr& controller() { return m_controller; } static void on_tap(GSimpleAction*, GVariant* vuid, gpointer gself) { const auto uid = g_variant_get_string(vuid, nullptr); static_cast(gself)->controller()->tap(uid); } static void on_cancel(GSimpleAction*, GVariant* vuid, gpointer gself) { const auto uid = g_variant_get_string(vuid, nullptr); static_cast(gself)->controller()->cancel(uid); } static void on_pause(GSimpleAction*, GVariant* vuid, gpointer gself) { const auto uid = g_variant_get_string(vuid, nullptr); static_cast(gself)->controller()->pause(uid); } static void on_resume(GSimpleAction*, GVariant* vuid, gpointer gself) { const auto uid = g_variant_get_string(vuid, nullptr); static_cast(gself)->controller()->resume(uid); } static void on_open(GSimpleAction*, GVariant* vuid, gpointer gself) { const auto uid = g_variant_get_string(vuid, nullptr); static_cast(gself)->controller()->open(uid); } static void on_open_app(GSimpleAction*, GVariant* vuid, gpointer gself) { const auto uid = g_variant_get_string(vuid, nullptr); static_cast(gself)->controller()->open_app(uid); } static void on_resume_all(GSimpleAction*, GVariant*, gpointer gself) { static_cast(gself)->controller()->resume_all(); } static void on_clear_all(GSimpleAction*, GVariant*, gpointer gself) { static_cast(gself)->controller()->clear_all(); } static void on_pause_all(GSimpleAction*, GVariant*, gpointer gself) { static_cast(gself)->controller()->pause_all(); } GVariant* create_default_header_state() { GVariantBuilder b; g_variant_builder_init(&b, G_VARIANT_TYPE_VARDICT); g_variant_builder_add(&b, "{sv}", "accessible-desc", g_variant_new_string("accessible-desc")); g_variant_builder_add(&b, "{sv}", "label", g_variant_new_string("label")); g_variant_builder_add(&b, "{sv}", "title", g_variant_new_string("title")); g_variant_builder_add(&b, "{sv}", "visible", g_variant_new_boolean(false)); return g_variant_builder_end(&b); } /*** **** ***/ GActionMap* action_map() const { return G_ACTION_MAP(m_action_group); } GSimpleActionGroup* m_action_group = nullptr; std::shared_ptr m_model; std::shared_ptr m_controller; std::set m_connections; // we've got raw pointers in here, so disable copying GActions(const GActions&) =delete; GActions& operator=(const GActions&) =delete; }; /*** **** ***/ /** * \brief A menu for a specific profile; eg, Desktop or Phone. */ class Menu { public: enum Profile { DESKTOP, PHONE, NUM_PROFILES }; enum Section { ONGOING, SUCCESSFUL, NUM_SECTIONS }; const char* name() const { return m_name; } GMenuModel* menu_model() { return G_MENU_MODEL(m_menu); } Menu(const char* name_in, const std::shared_ptr& model, const std::shared_ptr& gactions): m_name{name_in}, m_gactions{gactions} { // initialize the menu create_gmenu(); set_model(model); } virtual ~Menu() { if (m_update_header_tag > 0) { g_source_remove(m_update_header_tag); // commit any pending change on header update_header(); } g_clear_object(&m_menu); } void set_model (const std::shared_ptr& model) { auto& c = m_connections; c.clear(); if ((m_model = model)) { c.insert(m_model->added().connect([this](const Transfer::Id& id){add(id);})); c.insert(m_model->changed().connect([this](const Transfer::Id& id){update(id);})); c.insert(m_model->removed().connect([this](const Transfer::Id& id){remove(id);})); // add the transfers for (const auto& id : m_model->get_ids()) add(id); } update_header(); } private: void create_gmenu() { g_assert(m_submenu == nullptr); // build the submenu m_submenu = g_menu_new(); for(int i=0; i(gself); self->m_update_header_tag = 0; self->update_header(); return G_SOURCE_REMOVE; } void update_header() { auto action_name = g_strdup_printf("%s-header", name()); auto state = create_header_state(); g_action_group_change_action_state(m_gactions->action_group(), action_name, state); g_free(action_name); } GVariant* get_header_icon() const { int n_in_progress = 0; int n_failed = 0; int n_paused = 0; for (auto it=m_visible_transfers.cbegin(); it!=m_visible_transfers.cend(); ++it) { auto transfer = m_model->get((*it).first); switch (transfer->state) { case Transfer::RUNNING: case Transfer::HASHING: case Transfer::PROCESSING: ++n_in_progress; break; case Transfer::PAUSED: ++n_paused; break; case Transfer::ERROR: ++n_failed; break; case Transfer::QUEUED: case Transfer::CANCELED: case Transfer::FINISHED: break; } } const char * name; if (n_in_progress > 0) name = "transfer-progress"; else if (n_paused > 0) name = "transfer-paused"; else if (n_failed > 0) name = "transfer-error"; else name = "transfer-none"; auto icon = g_themed_icon_new_with_default_fallbacks(name); auto ret = g_icon_serialize(icon); g_object_unref(icon); return ret; } /* Show the header if there are any transfers that have begun and are currently incomplete because they're either ongoing or paused. */ bool header_should_be_visible() const { for (auto it=m_visible_transfers.cbegin(); it!=m_visible_transfers.cend(); ++it) { auto transfer = m_model->get((*it).first); if (transfer->state != Transfer::FINISHED) return true; } return false; } GVariant* create_header_state() { auto reffed_icon_v = get_header_icon(); auto title_v = g_variant_new_string(_("Files")); const bool visible = header_should_be_visible(); GVariantBuilder b; g_variant_builder_init(&b, G_VARIANT_TYPE_VARDICT); g_variant_builder_add(&b, "{sv}", "title", title_v); g_variant_builder_add(&b, "{sv}", "icon", reffed_icon_v); g_variant_builder_add(&b, "{sv}", "accessible-desc", title_v); g_variant_builder_add(&b, "{sv}", "visible", g_variant_new_boolean(visible)); auto ret = g_variant_builder_end (&b); g_variant_unref(reffed_icon_v); return ret; } /*** **** Menu Items Utils ***/ // compare an attribute between a menumodel's existing item and a new item static bool menu_item_attribute_is_equal(GMenuModel* model, int pos, GMenuItem* item, const char* attr) { auto a = g_menu_model_get_item_attribute_value(model, pos, attr, nullptr); auto b = g_menu_item_get_attribute_value(item, attr, nullptr); const bool equal = g_variant_equal(a, b); g_clear_pointer(&a, g_variant_unref); g_clear_pointer(&b, g_variant_unref); return equal; } // find the position of the menumodel's item with the specified attribute static int find_matching_menu_item(GMenuModel* mm, const char* attr, GVariant* value) { g_return_val_if_fail(value != nullptr, -1); for (int i=0, n=g_menu_model_get_n_items(mm); i t = m_model->get(uid); g_free(uid); if (!t) continue; if (t->can_pause()) ++n_can_pause; if (t->can_resume()) ++n_can_resume; if (t->can_clear()) ++n_can_clear; } } if ((section == SUCCESSFUL) && (n_can_clear > 0)) { label = _("Successful Transfers"); extra_label = _("Clear all"); detailed_action = "indicator.clear-all"; } else if ((section == ONGOING) && (n_can_resume > 0)) { label = nullptr; extra_label = _("Resume all"); detailed_action = "indicator.resume-all"; } else if ((section == ONGOING) && (n_can_pause > 0)) { label = nullptr; extra_label = _("Pause all"); detailed_action = "indicator.pause-all"; } GMenuItem* item; if (detailed_action != nullptr) item = create_bulk_menu_item(label, extra_label, detailed_action); else item = nullptr; return item; } static bool bulk_menu_item_is_equal(GMenuModel* model, int pos, GMenuItem* item) { return menu_item_attribute_is_equal(model, pos, item, ATTRIBUTE_X_TYPE) && menu_item_attribute_is_equal(model, pos, item, G_MENU_ATTRIBUTE_ACTION); } void update_bulk_menu_item(GMenu* menu, Section section) { GMenuModel* mm = G_MENU_MODEL(menu); // create a new item auto item = get_next_bulk_action (menu, section); // find the current item auto val = g_variant_new_string(BUTTON_SECTION); int pos = find_matching_menu_item(mm, ATTRIBUTE_X_TYPE, val); g_clear_pointer(&val, g_variant_unref); // maybe remove the current item if ((pos >= 0) && ((item == nullptr) || !bulk_menu_item_is_equal(mm, pos, item))) { g_menu_remove(menu, pos); pos = -1; } // maybe add the new item if (item != nullptr) { if (pos < 0) g_menu_insert_item(menu, 0, item); g_clear_object(&item); } } /*** **** Transfer Menu Items ***/ static GMenuItem* create_transfer_menu_item(const std::shared_ptr& t) { const auto& id = t->id.c_str(); GMenuItem* menu_item; if (!t->title.empty()) { menu_item = g_menu_item_new (t->title.c_str(), nullptr); } else { char* size = g_format_size (t->total_size); char* label = g_strdup_printf(_("Unknown Download (%s)"), size); menu_item = g_menu_item_new (label, nullptr); g_free(label); g_free(size); } g_menu_item_set_attribute (menu_item, ATTRIBUTE_X_TYPE, "s", "com.canonical.indicator.transfer"); GVariant * serialized_icon = nullptr; if (!t->app_icon.empty() && g_file_test(t->app_icon.c_str(), G_FILE_TEST_EXISTS)) { auto file = g_file_new_for_path(t->app_icon.c_str()); auto icon = g_file_icon_new(file); serialized_icon = g_icon_serialize(icon); g_clear_object(&icon); g_clear_object(&file); } if (serialized_icon == nullptr) { auto icon = g_themed_icon_new("image-missing"); serialized_icon = g_icon_serialize(icon); g_clear_object(&icon); } g_menu_item_set_attribute_value (menu_item, G_MENU_ATTRIBUTE_ICON, serialized_icon); g_variant_unref(serialized_icon); g_menu_item_set_attribute (menu_item, ATTRIBUTE_X_UID, "s", id); g_menu_item_set_action_and_target_value (menu_item, "indicator.activate-transfer", g_variant_new_string(id)); return G_MENU_ITEM(menu_item); } void find_transfer_menu_item(const Transfer::Id& id, const Section& section, GMenu*& gmenu, int& pos) const { auto mm = g_menu_model_get_item_link(G_MENU_MODEL(m_submenu), section, G_MENU_LINK_SECTION); gmenu = G_MENU(mm); auto val = g_variant_new_string(id.c_str()); pos = find_matching_menu_item(mm, ATTRIBUTE_X_UID, val); g_variant_unref(val); } static bool transfer_menu_item_is_equal(GMenuModel* model, int pos, GMenuItem* item) { return menu_item_attribute_is_equal(model, pos, item, G_MENU_ATTRIBUTE_LABEL) && menu_item_attribute_is_equal(model, pos, item, G_MENU_ATTRIBUTE_ICON); } // get which Section the Transfer should be in static Section get_correct_section_for_transfer(const std::shared_ptr& transfer) { return (transfer->state == Transfer::FINISHED) ? SUCCESSFUL : ONGOING; } // get which Section, if any, the Transfer is currently in bool get_current_section_for_transfer(const Transfer::Id& id, Section& section) const { const auto it = m_visible_transfers.find(id); if (it == m_visible_transfers.end()) return false; section = it->second; return true; } void update(const Transfer::Id& id) { const auto t = m_model->get(id); // For now we do not want to keep canceled or error downloads on the list // the app will handle it internally switch (t->state) { case Transfer::CANCELED: case Transfer::ERROR: remove(id); return; default: break; } g_return_if_fail(t); // if the transfer already has a menu item, find it Section cur_section = NUM_SECTIONS; GMenu* cur_menu = nullptr; int cur_pos = -1; if (get_current_section_for_transfer(id, cur_section)) find_transfer_menu_item(id, cur_section, cur_menu, cur_pos); // see where the transfer's menu item should be const Section new_section = get_correct_section_for_transfer(t); GMenu* new_menu = nullptr; int new_pos = -1; find_transfer_menu_item(id, new_section, new_menu, new_pos); // if the transfer's switching sections, remove the older menu item if ((cur_menu != new_menu) && (cur_menu != nullptr) && (cur_pos >= 0)) { m_visible_transfers.erase(id); g_menu_remove (cur_menu, cur_pos); update_bulk_menu_item(cur_menu, cur_section); } if (new_menu != nullptr) { auto item = create_transfer_menu_item(t); if (new_pos < 0) // not in the menu yet... { // transfers are sorted newest-to-oldest, // so position this one immediately after the bulk menu item constexpr int insert_pos = 1; g_menu_insert_item(new_menu, insert_pos, item); } else if (!transfer_menu_item_is_equal(G_MENU_MODEL(new_menu), new_pos, item)) { g_menu_remove(new_menu, new_pos); g_menu_insert_item(new_menu, new_pos, item); } g_object_unref(item); m_visible_transfers[t->id] = new_section; update_bulk_menu_item(new_menu, new_section); } update_header_soon(); } void add (const Transfer::Id& id) { update(id); } void remove(const Transfer::Id& id) { Section section = NUM_SECTIONS; if (!get_current_section_for_transfer(id, section)) return; GMenu* menu = nullptr; int pos = -1; find_transfer_menu_item(id, section, menu, pos); if (pos < 0) return; g_menu_remove(menu, pos); m_visible_transfers.erase(id); update_bulk_menu_item(menu, section); update_header_soon(); } /*** **** ***/ std::set m_connections; GMenu* m_menu = nullptr; const char* const m_name; std::shared_ptr m_model; std::shared_ptr m_gactions; std::map m_visible_transfers; GMenu* m_submenu = nullptr; guint m_update_header_tag = 0; // we've got raw pointers in here, so disable copying Menu(const Menu&) =delete; Menu& operator=(const Menu&) =delete; static constexpr char const * ATTRIBUTE_X_UID {"x-canonical-uid"}; static constexpr char const * ATTRIBUTE_X_TYPE {"x-canonical-type"}; static constexpr char const * ATTRIBUTE_X_LABEL {"x-canonical-extra-label"}; static constexpr char const * BUTTON_SECTION {"com.canonical.indicator.button-section"}; }; /*** **** ***/ /** * \brief Exports actions and gmenus to the DBus */ class Exporter { public: Exporter(){} ~Exporter() { if (m_bus != nullptr) { for(const auto& id : m_exported_menu_ids) g_dbus_connection_unexport_menu_model(m_bus, id); if (m_exported_actions_id) g_dbus_connection_unexport_action_group(m_bus, m_exported_actions_id); } if (m_own_id) g_bus_unown_name(m_own_id); g_clear_object(&m_bus); } core::Signal<> name_lost; void publish(const std::shared_ptr& gactions, const std::vector>& menus) { m_gactions = gactions; m_menus = menus; m_own_id = g_bus_own_name(G_BUS_TYPE_SESSION, BUS_NAME, G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT, on_bus_acquired, nullptr, on_name_lost, this, nullptr); } private: /*** **** ***/ static void on_bus_acquired(GDBusConnection* connection, const gchar* name, gpointer gself) { g_debug("bus acquired: %s", name); static_cast(gself)->on_bus_acquired(connection, name); } void on_bus_acquired(GDBusConnection* connection, const gchar* /*name*/) { m_bus = G_DBUS_CONNECTION(g_object_ref(G_OBJECT(connection))); // export the actions GError * error = nullptr; auto id = g_dbus_connection_export_action_group(m_bus, BUS_PATH, m_gactions->action_group(), &error); if (id) { m_exported_actions_id = id; } else { g_warning("cannot export action group: %s", error->message); g_clear_error(&error); } // export the menus for(auto& menu : m_menus) { const auto path = std::string(BUS_PATH) + "/" + menu->name(); id = g_dbus_connection_export_menu_model(m_bus, path.c_str(), menu->menu_model(), &error); if (id) { m_exported_menu_ids.insert(id); } else { if (error != nullptr) g_warning("cannot export %s menu: %s", menu->name(), error->message); g_clear_error(&error); } } } /*** **** ***/ static void on_name_lost(GDBusConnection* connection, const gchar* name, gpointer gthis) { g_debug("name lost: %s", name); static_cast(gthis)->on_name_lost(connection, name); } void on_name_lost(GDBusConnection* /*connection*/, const gchar* /*name*/) { name_lost(); } /*** **** ***/ std::set m_exported_menu_ids; guint m_own_id = 0; guint m_exported_actions_id = 0; GDBusConnection * m_bus = nullptr; std::shared_ptr m_gactions; std::vector> m_menus; // we've got raw pointers and gsignal tags in here, so disable copying Exporter(const Exporter&) =delete; Exporter& operator=(const Exporter&) =delete; }; } // anonymous namespace /*** **** ***/ class GMenuView::Impl { public: explicit Impl (const std::shared_ptr& controller): m_controller(controller), m_gactions(new GActions(controller)), m_exporter(new Exporter) { set_model(controller->get_model()); // create the Menus for(int i=0; ipublish(m_gactions, m_menus); } ~Impl() { } void set_model(const std::shared_ptr& model) { m_model = model; for(const auto& menu : m_menus) menu->set_model(model); } const core::Signal<>& name_lost() { return m_exporter->name_lost; } private: std::shared_ptr create_menu_for_profile(Menu::Profile profile) { // only one design, so for now everything uses the phone menu constexpr static const char* profile_names[] = { "desktop", "phone" }; std::shared_ptr m(new Menu(profile_names[profile], m_model, m_gactions)); return m; } std::shared_ptr m_model; std::shared_ptr m_controller; std::shared_ptr m_gactions; std::vector> m_menus; std::shared_ptr m_exporter; }; /*** **** ***/ GMenuView::GMenuView(const std::shared_ptr& controller): p(new Impl(controller)) { } GMenuView::~GMenuView() { } const core::Signal<>& GMenuView::name_lost() const { return p->name_lost(); } /*** **** ***/ } // namespace transfer } // namespace indicator } // namespace unity indicator-transfer-0.2+16.04.20151216.5/src/plugin-source.cpp0000644000015600001650000000515612634336113023756 0ustar pbuserpbgroup00000000000000/* * Copyright 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . * * Authors: * Charles Kerr */ #include #include namespace unity { namespace indicator { namespace transfer { /*** **** ***/ class PluginSource::Impl { public: Impl(PluginSource& owner, const std::string& plugin_dir): m_owner(owner) { GError * error = nullptr; g_debug("plugin_dir '%s'", plugin_dir.c_str()); GDir * dir = g_dir_open(plugin_dir.c_str(), 0, &error); if (dir != nullptr) { const gchar * name; while ((name = g_dir_read_name(dir))) { if (g_str_has_suffix(name, G_MODULE_SUFFIX)) { gchar * filename = g_build_filename(plugin_dir.c_str(), name, nullptr); GModule * mod = g_module_open(filename, G_MODULE_BIND_LOCAL); gpointer symbol {}; if (mod == nullptr) { g_warning("Unable to load module '%s'", filename); } else if (!g_module_symbol(mod, "get_source", &symbol)) { g_warning("Unable to use module '%s'", filename); } else { using get_source_func = Source*(); auto src = reinterpret_cast(symbol)(); if (src) { auto deleter = [mod,src](Source *s){ delete s; g_module_close(mod); }; m_owner.add_source(std::shared_ptr(src, deleter)); g_debug("Loaded plugin '%s'", filename); mod = nullptr; } } g_clear_pointer(&mod, g_module_close); g_clear_pointer(&filename, g_free); } } g_clear_pointer(&dir, g_dir_close); } } private: PluginSource& m_owner; }; /*** **** ***/ PluginSource::PluginSource(const std::string& plugin_dir): impl(new Impl(*this, plugin_dir)) { } PluginSource::~PluginSource() { } /*** **** ***/ } // namespace transfer } // namespace indicator } // namespace unity indicator-transfer-0.2+16.04.20151216.5/src/transfer.cpp0000644000015600001650000000276112634336113023005 0ustar pbuserpbgroup00000000000000/* * Copyright 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . * * Authors: * Charles Kerr */ #include #include // std::snprintf() namespace unity { namespace indicator { namespace transfer { /*** **** ***/ std::string Transfer::next_unique_id() { static unsigned int next = 1000; char buf[32]; std::snprintf(buf, sizeof(buf), "%u", next); ++next; return buf; } bool Transfer::can_start() const { return state==QUEUED; } bool Transfer::can_resume() const { return state==PAUSED || state==CANCELED || state==ERROR; } bool Transfer::can_pause() const { return state==RUNNING || state==HASHING || state==PROCESSING || state==QUEUED; } bool Transfer::can_cancel() const { return state!=FINISHED; } bool Transfer::can_clear() const { return state==FINISHED; } /*** **** ***/ } // namespace transfer } // namespace indicator } // namespace unity indicator-transfer-0.2+16.04.20151216.5/src/multisource.cpp0000644000015600001650000000776612634336113023546 0ustar pbuserpbgroup00000000000000/* * Copyright 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . * * Authors: * Charles Kerr */ #include #include #include #include namespace unity { namespace indicator { namespace transfer { /*** **** ***/ class MultiSource::Impl { public: Impl(): m_model(std::make_shared()) { } std::shared_ptr get_model() { return m_model; } void add_source(const std::shared_ptr& source) { g_return_if_fail(source); const auto idx = m_sources.size(); m_sources.push_back(source); auto model = source->get_model(); m_connections.insert( model->added().connect([this,idx](const Transfer::Id& id){ auto s = m_sources[idx]; m_id2source[id] = s; m_model->add(s->get_model()->get(id)); }) ); m_connections.insert( model->removed().connect([this](const Transfer::Id& id){ m_id2source.erase(id); m_model->remove(id); }) ); m_connections.insert( model->changed().connect([this](const Transfer::Id& id){ m_model->emit_changed(id); }) ); } void start(const Transfer::Id& id) { auto source = lookup_source(id); g_return_if_fail(source); source->start(id); } void pause(const Transfer::Id& id) { auto source = lookup_source(id); g_return_if_fail(source); source->pause(id); } void resume(const Transfer::Id& id) { auto source = lookup_source(id); g_return_if_fail(source); source->resume(id); } void cancel(const Transfer::Id& id) { auto source = lookup_source(id); g_return_if_fail(source); source->cancel(id); } void clear(const Transfer::Id& id) { auto source = lookup_source(id); g_return_if_fail(source); source->clear(id); } void open(const Transfer::Id& id) { auto source = lookup_source(id); g_return_if_fail(source); source->open(id); } void open_app(const Transfer::Id& id) { auto source = lookup_source(id); g_return_if_fail(source); source->open_app(id); } private: std::shared_ptr lookup_source(const Transfer::Id& id) { std::shared_ptr source; auto it = m_id2source.find(id); if (it != m_id2source.end()) source = it->second; return source; } std::shared_ptr m_model; std::vector> m_sources; std::map> m_id2source; std::set m_connections; }; /*** **** ***/ MultiSource::MultiSource(): impl(new Impl{}) { } MultiSource::~MultiSource() { } void MultiSource::open(const Transfer::Id& id) { impl->open(id); } void MultiSource::start(const Transfer::Id& id) { impl->start(id); } void MultiSource::pause(const Transfer::Id& id) { impl->pause(id); } void MultiSource::resume(const Transfer::Id& id) { impl->resume(id); } void MultiSource::cancel(const Transfer::Id& id) { impl->cancel(id); } void MultiSource::clear(const Transfer::Id &id) { impl->clear(id); } void MultiSource::open_app(const Transfer::Id& id) { impl->open_app(id); } const std::shared_ptr MultiSource::get_model() { return impl->get_model(); } void MultiSource::add_source(const std::shared_ptr& source) { impl->add_source(source); } /*** **** ***/ } // namespace transfer } // namespace indicator } // namespace unity indicator-transfer-0.2+16.04.20151216.5/src/CMakeLists.txt0000644000015600001650000000320412634336113023206 0ustar pbuserpbgroup00000000000000set (SERVICE_LIB "indicator-transfer") set (SERVICE_EXEC "indicator-transfer-service") add_definitions (-DG_LOG_DOMAIN="${CMAKE_PROJECT_NAME}") # handwritten source code... set (SERVICE_LIB_HANDWRITTEN_SOURCES controller.cpp model.cpp plugin-source.cpp transfer.cpp view.cpp view-gmenu.cpp source.cpp multisource.cpp) add_library(${SERVICE_LIB} SHARED ${SERVICE_LIB_HANDWRITTEN_SOURCES}) target_link_libraries (${SERVICE_LIB} PRIVATE ${SERVICE_DEPS_LIBRARIES} ${GCOV_LIBS}) set_target_properties(${SERVICE_LIB} PROPERTIES VERSION ${INDICATOR_TRANSFER_VERSION} SOVERSION ${INDICATOR_TRANSFER_VERSION_MAJOR} ) install (TARGETS ${SERVICE_LIB} LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}) # add the bin dir to the include path so that # the compiler can find the generated header files include_directories (${CMAKE_CURRENT_BINARY_DIR}) link_directories (${SERVICE_DEPS_LIBRARY_DIRS}) set (SERVICE_EXEC_HANDWRITTEN_SOURCES main.cpp) add_executable (${SERVICE_EXEC} ${SERVICE_EXEC_HANDWRITTEN_SOURCES}) target_link_libraries (${SERVICE_EXEC} ${SERVICE_LIB} ${SERVICE_DEPS_LIBRARIES} ${GCOV_LIBS}) install (TARGETS ${SERVICE_EXEC} RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_PKGLIBEXECDIR}) # add warnings/coverage info on handwritten files # but not the generated ones... set_property (SOURCE ${SERVICE_LIB_HANDWRITTEN_SOURCES} ${SERVICE_EXEC_HANDWRITTEN_SOURCES} APPEND_STRING PROPERTY COMPILE_FLAGS " -std=c++11 -fPIC -g ${CXX_WARNING_ARGS} ${GCOV_FLAGS}") set_property (SOURCE main.cpp APPEND PROPERTY COMPILE_DEFINITIONS PLUGINDIR="${CMAKE_INSTALL_FULL_PKGLIBEXECDIR}") add_subdirectory (dm-plugin) indicator-transfer-0.2+16.04.20151216.5/src/view-console.cpp0000644000015600001650000000550512634336113023572 0ustar pbuserpbgroup00000000000000/* * Copyright 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . * * Authors: * Charles Kerr */ #include #include #include #include namespace unity { namespace indicator { namespace transfer { /*** **** ***/ ConsoleView::ConsoleView(const std::shared_ptr& model, const std::shared_ptr& controller) { set_model(model); set_controller(controller); } ConsoleView::~ConsoleView() { } void ConsoleView::set_controller(const std::shared_ptr& controller) { m_controller = controller; } static std::string dump_transfer(const std::shared_ptr& transfer) { auto tmp = g_strdup_printf ("state [%d] id [%s] title[%s] app_icon[%s] time_started[%zu] seconds_left[%d] speed[%f KiB/s] progress[%f] error_string[%s] local_path[%s]", (int)transfer->state, transfer->id.c_str(), transfer->title.c_str(), transfer->app_icon.c_str(), (size_t)transfer->time_started, transfer->seconds_left, transfer->speed_Bps/1024.0, transfer->progress, transfer->error_string.c_str(), transfer->local_path.c_str()); std::string ret = tmp; g_free(tmp); return ret; } void ConsoleView::set_model(const std::shared_ptr& model) { m_connections.clear(); if ((m_model = model)) { m_connections.insert(m_model->added().connect([this](const Transfer::Id& id){ std::cerr << "view added: " << dump_transfer(m_model->get(id)) << std::endl; })); m_connections.insert(m_model->changed().connect([this](const Transfer::Id& id){ std::cerr << "view changed: " << dump_transfer(m_model->get(id)) << std::endl; })); m_connections.insert(m_model->removed().connect([this](const Transfer::Id& id){ std::cerr << "view removing: " << dump_transfer(m_model->get(id)) << std::endl; })); } } /*** **** ***/ } // namespace transfer } // namespace indicator } // namespace unity indicator-transfer-0.2+16.04.20151216.5/README0000644000015600001650000000436712634336113020552 0ustar pbuserpbgroup00000000000000ACTIONS ======= * "activate-transfer" Description: default action when tapping a transfer menuitem. For example, tapping a running transfer pauses it. Tapping a paused transfer resumes it. State: None Parameter: s an opaque uid to specify which transer to use. This uid comes from the menuitems' x-canonical-uid property. * "cancel-transfer" * "pause-transfer" * "resume-transfer" * "open-transfer" * "open-app-transfer" Description: actions that operate on a single transfer. State: None Parameter: s an opaque uid to specify which transer to use. This uid comes from the menuitems' x-canonical-uid property. * "pause-all" * "resume-all" * "clear-all" Description: actions that operate on all transfers. State: None Parameter: None * "transfer-state.$UID" (where $UID matches the x-canonical-uid properties) Description: An action whose state provides a transfer's transient properties. This is a dict whose key/value pairs are: * "percent" d percent of the progress complete, [0.0 ... 1.0] * "seconds-left" i percent done. NB: Not set if no ETA is available. * "state" i int value matching the Transfer::State enum from transfer-indicator/include/transfer/transfer.h Parameter: none. invoking this action has no effect. CUSTOM MENUITEMS ================ See https://docs.google.com/a/canonical.com/document/d/1OyHUg_uUfmhDNa-9UrMc1tZ_eH_99PEU_V2l1YFA1UY/edit# for visual mockups of how these should look. * Transfer - x-canonical-type s "com.canonical.indicator.transfer" - x-canonical-uid s the transfer's unique identifier string - icon v the icon for the app receiving the download - label s human-readable string describing the transfer * Bulk Action Menuitem This behaves like a normal text menuitem but is rendered differently; see the the "Pause all" / "Clear all" buttons in the mockup linked above. - x-canonical-type s "com.canonical.indicator.button-section" - label s label (e.g., "Successful Transfers") - x-canonical-extra-label s action label (e.g., "Clear All") indicator-transfer-0.2+16.04.20151216.5/po/0000755000015600001650000000000012634336272020304 5ustar pbuserpbgroup00000000000000indicator-transfer-0.2+16.04.20151216.5/po/CMakeLists.txt0000644000015600001650000000020112634336113023027 0ustar pbuserpbgroup00000000000000include (Translations) add_translations_directory ("${GETTEXT_PACKAGE}") add_translations_catalog ("${GETTEXT_PACKAGE}" ../src/) indicator-transfer-0.2+16.04.20151216.5/po/POTFILES.in0000644000015600001650000000002312634336113022046 0ustar pbuserpbgroup00000000000000src/view-gmenu.cpp indicator-transfer-0.2+16.04.20151216.5/cmake_uninstall.cmake.in0000644000015600001650000000165412634336113024446 0ustar pbuserpbgroup00000000000000IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) STRING(REGEX REPLACE "\n" ";" files "${files}") FOREACH(file ${files}) MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") IF(EXISTS "$ENV{DESTDIR}${file}") EXEC_PROGRAM( "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" OUTPUT_VARIABLE rm_out RETURN_VALUE rm_retval ) IF(NOT "${rm_retval}" STREQUAL 0) MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") ENDIF(NOT "${rm_retval}" STREQUAL 0) ELSE(EXISTS "$ENV{DESTDIR}${file}") MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") ENDIF(EXISTS "$ENV{DESTDIR}${file}") ENDFOREACH(file) indicator-transfer-0.2+16.04.20151216.5/trim-lcov.py0000755000015600001650000000267012634336113022156 0ustar pbuserpbgroup00000000000000#!/usr/bin/python # This script removes branch and/or line coverage data for lines that # contain a particular substring. # # In the interest of "fairness" it removes all branch or coverage data # when a match is found -- not just negative data. It is therefore # likely that running this script will actually reduce the total number # of lines and branches that are marked as covered (in absolute terms). # # This script intentionally avoids checking for errors. Any exceptions # will trigger make to fail. # # Author: Ryan Lortie import sys line_suppress = ['g_assert_not_reached'] branch_suppress = ['g_assert', 'g_return_if_fail', 'g_clear_object', 'g_clear_pointer', 'g_return_val_if_fail', 'G_DEFINE_TYPE'] def check_suppress(suppressions, source, data): line, _, rest = data.partition(',') line = int(line) - 1 assert line < len(source) for suppression in suppressions: if suppression in source[line]: return True return False source = [] for line in sys.stdin: line = line[:-1] keyword, _, rest = line.partition(':') # Source file if keyword == 'SF': source = file(rest).readlines() # Branch coverage data elif keyword == 'BRDA': if check_suppress(branch_suppress, source, rest): continue # Line coverage data elif keyword == 'DA': if check_suppress(line_suppress, source, rest): continue print line indicator-transfer-0.2+16.04.20151216.5/HACKING0000644000015600001650000000175712634336113020661 0ustar pbuserpbgroup00000000000000Building the code ----------------- 1. $ cd indicator-transfer-X.Y.Z 2. $ mkdir build 3. $ cd build 4. $ cmake .. or $ CXX=clang++ CC=clang cmake .. or $ cmake -DCMAKE_INSTALL_PREFIX=/your/install/prefix/here .. or $ cmake -GNinja .. 5. $ make Running the tests ----------------- 1. $ cd indicator-transfer-X.Y.Z 2. $ mkdir build 3. $ cd build 4. $ cmake .. 5. $ make 6. $ make test 7. $ make cppcheck Generating Test Coverage Reports -------------------------------- 1. $ cd indicator-transfer-X.Y.Z 2. $ mkdir build-coverage 3. $ cd build-coverage 4. $ cmake -DCMAKE_BUILD_TYPE=coverage .. 5. $ make 6. $ make coverage-html What Gets Installed ------------------- * $DATADIR/upstart/sessions/indicator-transfer.conf * $DATADIR/upstart/xdg/autostart/indicator-transfer.desktop * $DATADIR/share/unity/indicators/com.canonical.indicator.transfer * $PKGLIBEXECDIR/indicator-transfer/indicator-transfer-service * /etc/xdg/autostart/indicator-transfer.desktop indicator-transfer-0.2+16.04.20151216.5/TODO0000644000015600001650000000047712634336113020360 0ustar pbuserpbgroup00000000000000- coverage reports - tap-to-open is currently no-op - tap-icon-to-open-app is currently a no-op - transfer's icon is unknown - transfer's title is unknown - need ido in order to be visible on desktop - need unity8 work in order to be visible on phone - missing header icons for 1. idle, 2. active, 3. paused, 4. failed indicator-transfer-0.2+16.04.20151216.5/data/0000755000015600001650000000000012634336272020577 5ustar pbuserpbgroup00000000000000indicator-transfer-0.2+16.04.20151216.5/data/com.canonical.indicator.transfer0000644000015600001650000000047312634336113027022 0ustar pbuserpbgroup00000000000000[Indicator Service] Name=indicator-transfer ObjectPath=/com/canonical/indicator/transfer Position=90 [desktop] ObjectPath=/com/canonical/indicator/transfer/phone [phone] ObjectPath=/com/canonical/indicator/transfer/phone Position=71 [phone_greeter] ObjectPath=/com/canonical/indicator/transfer/phone Position=71 indicator-transfer-0.2+16.04.20151216.5/data/indicator-transfer.desktop.in0000644000015600001650000000034212634336113026366 0ustar pbuserpbgroup00000000000000[Desktop Entry] Type=Application Name=Indicator Transfer Exec=@pkglibexecdir@/indicator-transfer-service OnlyShowIn=Unity;GNOME; NoDisplay=true StartupNotify=false Terminal=false AutostartCondition=GNOME3 unless-session gnome indicator-transfer-0.2+16.04.20151216.5/data/indicator-transfer.pc.in0000644000015600001650000000055712634336113025327 0ustar pbuserpbgroup00000000000000libdir=@CMAKE_INSTALL_FULL_LIBDIR@ includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@/@CMAKE_PROJECT_NAME@ plugindir=@CMAKE_INSTALL_FULL_PKGLIBEXECDIR@ Name: @CMAKE_PROJECT_NAME@ Description: Developer files for @CMAKE_PROJECT_NAME@ Version: @INDICATOR_TRANSFER_VERSION@ Libs: -L${libdir} -lindicator-transfer Cflags: -I${includedir} Requires: properties-cpp, gmodule-2.0 indicator-transfer-0.2+16.04.20151216.5/data/CMakeLists.txt0000644000015600001650000000554012634336113023335 0ustar pbuserpbgroup00000000000000## ## Upstart Job File ## # where to install set (UPSTART_JOB_DIR "${CMAKE_INSTALL_FULL_DATADIR}/upstart/sessions") message (STATUS "${UPSTART_JOB_DIR} is the Upstart Job File install dir") set (UPSTART_JOB_NAME "${CMAKE_PROJECT_NAME}.conf") set (UPSTART_JOB_FILE "${CMAKE_CURRENT_BINARY_DIR}/${UPSTART_JOB_NAME}") set (UPSTART_JOB_FILE_IN "${CMAKE_CURRENT_SOURCE_DIR}/${UPSTART_JOB_NAME}.in") # build it set (pkglibexecdir "${CMAKE_INSTALL_FULL_PKGLIBEXECDIR}") configure_file ("${UPSTART_JOB_FILE_IN}" "${UPSTART_JOB_FILE}") # install it install (FILES "${UPSTART_JOB_FILE}" DESTINATION "${UPSTART_JOB_DIR}") ## ## XDG Autostart File ## # where to install set (XDG_AUTOSTART_DIR "/etc/xdg/autostart") message (STATUS "${XDG_AUTOSTART_DIR} is the DBus Service File install dir") set (XDG_AUTOSTART_NAME "${CMAKE_PROJECT_NAME}.desktop") set (XDG_AUTOSTART_FILE "${CMAKE_CURRENT_BINARY_DIR}/${XDG_AUTOSTART_NAME}") set (XDG_AUTOSTART_FILE_IN "${CMAKE_CURRENT_SOURCE_DIR}/${XDG_AUTOSTART_NAME}.in") # build it set (pkglibexecdir "${CMAKE_INSTALL_FULL_PKGLIBEXECDIR}") configure_file ("${XDG_AUTOSTART_FILE_IN}" "${XDG_AUTOSTART_FILE}") # install it install (FILES "${XDG_AUTOSTART_FILE}" DESTINATION "${XDG_AUTOSTART_DIR}") ## ## Upstart XDG Autostart Override ## # where to install set (UPSTART_XDG_AUTOSTART_DIR "${CMAKE_INSTALL_FULL_DATAROOTDIR}/upstart/xdg/autostart") message (STATUS "${UPSTART_XDG_AUTOSTART_DIR} is the Upstart XDG autostart override dir") set (UPSTART_XDG_AUTOSTART_NAME "${CMAKE_PROJECT_NAME}.upstart.desktop") set (UPSTART_XDG_AUTOSTART_FILE "${CMAKE_CURRENT_BINARY_DIR}/${UPSTART_XDG_AUTOSTART_NAME}") set (UPSTART_XDG_AUTOSTART_FILE_IN "${CMAKE_CURRENT_SOURCE_DIR}/${UPSTART_XDG_AUTOSTART_NAME}.in") # build it set (pkglibexecdir "${CMAKE_INSTALL_FULL_PKGLIBEXECDIR}") configure_file ("${UPSTART_XDG_AUTOSTART_FILE_IN}" "${UPSTART_XDG_AUTOSTART_FILE}") # install it install (FILES "${UPSTART_XDG_AUTOSTART_FILE}" DESTINATION "${UPSTART_XDG_AUTOSTART_DIR}" RENAME "${XDG_AUTOSTART_NAME}") ## ## Unity Indicator File ## # where to install set (UNITY_INDICATOR_DIR "${CMAKE_INSTALL_FULL_DATAROOTDIR}/unity/indicators") message (STATUS "${UNITY_INDICATOR_DIR} is the Unity Indicator install dir") set (UNITY_INDICATOR_NAME "com.canonical.indicator.transfer") set (UNITY_INDICATOR_FILE "${CMAKE_CURRENT_SOURCE_DIR}/${UNITY_INDICATOR_NAME}") install (FILES "${UNITY_INDICATOR_FILE}" DESTINATION "${UNITY_INDICATOR_DIR}") ## ## Pkg dev file set (INDICATOR_PKG_NAME "${CMAKE_PROJECT_NAME}.pc") set (INDICATOR_PKG_FILE "${CMAKE_CURRENT_BINARY_DIR}/${INDICATOR_PKG_NAME}") set (INDICATOR_PKG_FILE_IN "${CMAKE_CURRENT_SOURCE_DIR}/${INDICATOR_PKG_NAME}.in") configure_file ("${INDICATOR_PKG_FILE_IN}" "${INDICATOR_PKG_FILE}" @ONLY) install (FILES "${INDICATOR_PKG_FILE}" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") indicator-transfer-0.2+16.04.20151216.5/data/indicator-transfer.upstart.desktop.in0000644000015600001650000000027112634336113030070 0ustar pbuserpbgroup00000000000000[Desktop Entry] Type=Application Name=Indicator Transfer Exec=@pkglibexecdir@/indicator-transfer-service OnlyShowIn=Unity; NoDisplay=true StartupNotify=false Terminal=false Hidden=true indicator-transfer-0.2+16.04.20151216.5/data/indicator-transfer.conf.in0000644000015600001650000000030712634336113025643 0ustar pbuserpbgroup00000000000000description "Indicator Transfer Backend" start on indicator-services-start stop on desktop-end or indicator-services-end respawn respawn limit 2 10 exec @pkglibexecdir@/indicator-transfer-service indicator-transfer-0.2+16.04.20151216.5/MERGE-REVIEW0000644000015600001650000000371712634336113021451 0ustar pbuserpbgroup00000000000000* '''Checklist for component''': indicator-transfer * '''Component Test Plan''': https://wiki.ubuntu.com/Process/Merges/TestPlan/indicator-transfer * '''Trunk URL''': lp:indicator-transfer * '''Ubuntu Package URL (LP)''': http://launchpad.net/ubuntu/+source/indicator-transfer This documents the expections that the project has on what submitters, reviewers, and landers should ensure that they've done for a merge into the project. The source for this document can be gotten from Bazaar: {{{ $ bzr cat lp:indicator-transfer/MERGE-REVIEW }}} == MP Submission Checklist Template == '''Note: Please ensure you include the following form filled out and submitted along side your code to the MP ticket.''' * Are there any related MPs required for this MP to build/function as expected? Please list. * Is your branch in sync with latest trunk? (e.g. bzr pull lp:trunk -> no changes) * Did the code build without warnings? * Did the tests run successfully? * Did you perform an exploratory manual test run of your code change and any related functionality? * Has your component test plan been executed successfully on emulator or a physical device? * Please list which manual tests are germane for the reviewer in this MP. == MP Review Checklist Template == '''Note: Please ensure you include the following form filled out and submitted along side your code to the MP ticket.''' * Have you checked that the submitter has accurately filled out the submitter checklist and has taken no shortcuts? * Did you run the manual tests listed by the submitter? * Did you do exploratory testing related to the component you own with the MP changeset included? * If new features have been added, are the manual tests sufficient to cover them? == MP Landing Checklist Template == '''Note: Please ensure you include the following form filled out and submitted along side your code to the MP ticket.''' * Ensure that the checklists have been properly filled out by submitter and all reviewers indicator-transfer-0.2+16.04.20151216.5/CMakeLists.txt0000644000015600001650000000604312634336121022422 0ustar pbuserpbgroup00000000000000project (indicator-transfer C CXX) cmake_minimum_required (VERSION 2.8.9) list (APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) set (PROJECT_VERSION "14.04.0") set (PACKAGE ${CMAKE_PROJECT_NAME}) set (GETTEXT_PACKAGE "indicator-transfer") add_definitions (-DGETTEXT_PACKAGE="${GETTEXT_PACKAGE}" -DGNOMELOCALEDIR="${CMAKE_INSTALL_FULL_LOCALEDIR}") option (enable_tests "Build the package's automatic tests." ON) option (enable_lcov "Generate lcov code coverage reports." ON) ## ## GNU standard installation directories ## include (GNUInstallDirs) if (EXISTS "/etc/debian_version") # Workaround for libexecdir on debian set (CMAKE_INSTALL_LIBEXECDIR "${CMAKE_INSTALL_LIBDIR}") set (CMAKE_INSTALL_FULL_LIBEXECDIR "${CMAKE_INSTALL_FULL_LIBDIR}") endif () set (CMAKE_INSTALL_PKGLIBEXECDIR "${CMAKE_INSTALL_LIBEXECDIR}/${CMAKE_PROJECT_NAME}") set (CMAKE_INSTALL_FULL_PKGLIBEXECDIR "${CMAKE_INSTALL_FULL_LIBEXECDIR}/${CMAKE_PROJECT_NAME}") ## ## Version ## set(INDICATOR_TRANSFER_VERSION_MAJOR 0) set(INDICATOR_TRANSFER_VERSION_MINOR 0) set(INDICATOR_TRANSFER_VERSION_PATCH 2) set(INDICATOR_TRANSFER_VERSION "${INDICATOR_TRANSFER_VERSION_MAJOR}.${INDICATOR_TRANSFER_VERSION_MINOR}.${INDICATOR_TRANSFER_VERSION_PATCH}") ## ## Check for prerequisites ## find_package (PkgConfig REQUIRED) include (FindPkgConfig) pkg_check_modules(SERVICE_DEPS REQUIRED glib-2.0>=2.36 gmodule-2.0>=2.36 gio-unix-2.0>=2.36 properties-cpp>=0.0.1 click-0.4>=0.4.30 json-glib-1.0 ubuntu-app-launch-2 mirclient) include_directories(SYSTEM ${SERVICE_DEPS_INCLUDE_DIRS}) ## ## custom targets ## add_custom_target (cppcheck COMMAND cppcheck --enable=all -q --error-exitcode=2 -I${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/tests) ## ## Actually building the service ## # those GActionEntry structs tickle -Wmissing-field-initializers if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") set (CXX_WARNING_ARGS "${CXX_WARNING_ARGS} -Weverything -Wno-c++98-compat -Wno-missing-field-initializers") else() set (CXX_WARNING_ARGS "${CXX_WARNING_ARGS} -Wall -Wextra -Wpedantic -Wno-missing-field-initializers") endif() include_directories (${CMAKE_CURRENT_SOURCE_DIR}/include) include_directories (${CMAKE_CURRENT_BINARY_DIR}/include) # testing & coverage if (${enable_tests}) pkg_check_modules (DBUSTEST REQUIRED dbustest-1>=14.04.0) enable_testing () if (${enable_lcov}) include(GCov) endif () endif () # add the subdirs add_subdirectory(data) add_subdirectory(include) add_subdirectory(src) add_subdirectory(po) if (${enable_tests}) add_subdirectory(tests) endif () # uninstall target configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")