// ui_download_manager.h -*-c++-*- // // Copyright (C) 2005, 2007-2009 Daniel Burrows // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. // #ifndef UI_DOWNLOAD_MANAGER_H #define UI_DOWNLOAD_MANAGER_H #include "download_thread.h" #include #include #include #include #include #include #include #include /** \brief Glue code to go between the UI and the download manager/thread stuff * * \file ui_download_manager.h */ class download_signal_log; class download_thread; namespace cwidget { namespace widgets { class widget; } } /** A base class for objects that provide the OpProgress interface and * that can be refcounted. * * Note that this class is not abstract: you can instantiate it to * get a NOP progress object. */ class refcounted_progress : public OpProgress, virtual public aptitude::util::refcounted_base_threadsafe { protected: refcounted_progress() { } public: static cwidget::util::ref_ptr create() { return new refcounted_progress; } static std::pair, sigc::slot0 > make() { return std::make_pair(create(), sigc::slot0()); } }; typedef cwidget::util::ref_ptr refcounted_progress_ref; /** \brief A progress bar paired with a slot that tells * us how to destroy it. */ typedef std::pair > progress_with_destructor; /** \brief A slot that creates a progress bar and * tells us how to hide it. * * The first returned value is a new progress reporting * object; the second value is a slot to be invoked when * any widget associated with the progress object * should be cleaned up. */ typedef sigc::slot0 make_refcounted_progress_slot; /** Represents the UI end of a download process. This object * completely handles its own memory management -- you don't have to * delete it and you shouldn't try. */ class ui_download_manager : public sigc::trackable { /** Used to indicate that a download was cancelled. */ class aborter : public sigc::trackable { bool aborted; public: aborter() : aborted(false) { } void abort() { aborted = true; } bool get_aborted() { return aborted; } }; boost::shared_ptr manager; aborter abort_state; download_signal_log *log; background_status *st; // Used to hide the details of how we make a progress bar. Invoked // every time the ui_download_manager needs a progress bar to do // something. make_refcounted_progress_slot make_progress_bar; // How to post a thunk to the main thread. post_thunk_func post_thunk; // Wrapper so we can use generic refcounted stuff. // // All we want is a pointer that will drop a reference on the target // when we destroy it. // // This seems a little icky; it seems like there should be a better // way of handling these lifetime issues. template class generic_refcounted : public aptitude::util::refcounted_base_threadsafe { cwidget::util::ref_ptr ptr; public: generic_refcounted(const cwidget::util::ref_ptr &_ptr) : ptr(_ptr) { } }; /** Used to keep the download status widget alive until the download * completes. */ cwidget::util::ref_ptr download_status; /** \brief A progress object, used to display progrss in done(). * * This is stored here to handle lifetime issues sensibly: we * create it in done() and free it in finish_done(), and storing * refcounted values in slot bindings is dangerous. * * \todo Would it be reasonable to somehow just use two progress * bars instead of passing one around? The current scheme is the * result of blindly refactoring the old done() and seems likely to * become unmaintainable. */ refcounted_progress_ref done_progress; /** A thunk that makes done_progress invisible and prepares * to free its memory. */ sigc::slot0 done_progress_destructor; void done(download_thread *t, pkgAcquire::RunResult res); /** \brief Finishes the work of done() after the post-download * actions of the download manager have run. * * \param run_res The result of download_manager::finish(). */ void finish_done(download_manager::result run_res); public: /** \brief Create a ui_download_manager. * * \param _manager The download_manager object to wrap. * * \param _log How to report the download status (the * signals will be invoked in a foreground * thread). * * \param _download_status An arbitrary object that * should be kept around until * the download completes (its * references will be adjusted * in the foreground thread). * * \param _make_progress_bar A callback that will be invoked * whenever the download process * needs a fresh progress bar. * * param _post_thunk A callback that schedules a * thunk for execution in the * foreground thread. */ template ui_download_manager(const boost::shared_ptr &_manager, download_signal_log *_log, const cwidget::util::ref_ptr &_download_status, const make_refcounted_progress_slot &_make_progress_bar, post_thunk_func _post_thunk) : manager(_manager), abort_state(), log(_log), st(new background_status(_log, _post_thunk)), make_progress_bar(_make_progress_bar), post_thunk(_post_thunk), download_status(new generic_refcounted(_download_status)) { } ~ui_download_manager(); /** \brief Invoke this method if the download is cancelled. * * This doesn't cancel the download itself, but it changes * the flow-of-control appropriately: for instance, dpkg * won't be invoked for an aborted install run. */ void aborted() { abort_state.abort(); } void start(); /** \brief A signal emitted when the download is about to start. */ sigc::signal download_starts; /** \brief A signal emitted when the download finishes, * after Complete() is invoked on the log object. */ sigc::signal download_stops; /** \brief A signal emitted when the download and any post-download * actions are finished. * * The parameter is \b true if the download was sucessful and \b * false otherwise. The signal is always emitted in the foreground * thread. */ sigc::signal download_complete; }; #endif