source: projects/synaptic/trunk/gtk/rgdebinstallprogress.cc @ 280

Revision 280, 23.5 KB checked in by yasumichi, 15 years ago (diff)

first import

Line 
1/* rgdebinstallprogress.cc
2 *
3 * Copyright (c) 2004 Canonical
4 *
5 * Author: Michael Vogt <mvo@debian.org>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 * USA
21 */
22
23#include "config.h"
24
25#ifdef WITH_DPKG_STATUSFD
26
27#include <sys/wait.h>
28#include <sys/types.h>
29#include <sys/fcntl.h>
30#include <sys/socket.h>
31#include <sys/un.h>
32
33#include "rgmainwindow.h"
34#include "gsynaptic.h"
35
36#include "rgdebinstallprogress.h"
37#include "rguserdialog.h"
38
39#include <apt-pkg/configuration.h>
40#include <apt-pkg/error.h>
41#include <gtk/gtk.h>
42
43#include <unistd.h>
44#include <stdio.h>
45
46#include <vte/vte.h>
47
48
49#include "i18n.h"
50
51// timeout in sec until the expander is expanded
52static const int RGTERMINAL_TIMEOUT=60;
53
54// removing
55char* RGDebInstallProgress::remove_stages[NR_REMOVE_STAGES] = {
56   "half-configured", 
57   "half-installed", 
58   "config-files"};
59char* RGDebInstallProgress::remove_stages_translations[NR_REMOVE_STAGES] = {
60   N_("Preparing for removal %s"),
61   N_("Removing %s"),
62   N_("Removed %s")};
63
64// purging
65char *RGDebInstallProgress::purge_stages[NR_PURGE_STAGES] = { 
66   "half-configured",
67   "half-installed", 
68   "config-files", 
69   "not-installed"};
70char *RGDebInstallProgress::purge_stages_translations[NR_PURGE_STAGES] = { 
71   N_("Preparing for removal %s"),
72   N_("Removing with config %s"), 
73   N_("Removed %s"), 
74   N_("Removed with config %s")};
75
76// purge only (for packages that are alreay removed)
77char *RGDebInstallProgress::purge_only_stages[NR_PURGE_ONLY_STAGES] = { 
78   "config-files", 
79   "not-installed"};
80char *RGDebInstallProgress::purge_only_stages_translations[NR_PURGE_ONLY_STAGES] = { 
81   N_("Removing with config %s"), 
82   N_("Removed with config %s")};
83
84// install
85char *RGDebInstallProgress::install_stages[NR_INSTALL_STAGES] = { 
86   "half-installed",
87   "unpacked",
88   "half-configured",
89   "installed"};
90char *RGDebInstallProgress::install_stages_translations[NR_INSTALL_STAGES] = { 
91   N_("Preparing %s"),
92   N_("Unpacking %s"),
93   N_("Configuring %s"),
94   N_("Installed %s")};
95
96// update
97char *RGDebInstallProgress::update_stages[NR_UPDATE_STAGES] = { 
98   "unpack",
99   "half-installed", 
100   "unpacked",
101   "half-configured",
102   "installed"};
103char *RGDebInstallProgress::update_stages_translations[NR_UPDATE_STAGES] = { 
104   N_("Preparing %s"),
105   N_("Installing %s"), 
106   N_("Unpacking %s"),
107   N_("Configuring %s"),
108   N_("Installed %s")};
109
110//reinstall
111char *RGDebInstallProgress::reinstall_stages[NR_REINSTALL_STAGES] = { 
112   "half-configured",
113   "unpacked",
114   "half-installed", 
115   "unpacked",
116   "half-configured",
117   "installed" };
118char *RGDebInstallProgress::reinstall_stages_translations[NR_REINSTALL_STAGES] = { 
119   N_("Preparing %s"),
120   N_("Unpacking %s"),
121   N_("Installing %s"), 
122   N_("Unpacking %s"),
123   N_("Configuring %s"),
124   N_("Installed %s") };
125
126
127void RGDebInstallProgress::child_exited(VteReaper *vtereaper,
128                                        gint child_pid, gint ret, 
129                                        gpointer data)
130{
131   RGDebInstallProgress *me = (RGDebInstallProgress*)data;
132
133   if(child_pid == me->_child_id) {
134//        cout << "correct child exited" << endl;
135//        cout << "waitpid returned: " << WEXITSTATUS(ret) << endl;
136      me->res = (pkgPackageManager::OrderResult)WEXITSTATUS(ret);
137      me->child_has_exited=true;
138   }
139}
140
141
142ssize_t
143write_fd(int fd, void *ptr, size_t nbytes, int sendfd)
144{
145        struct msghdr   msg;
146        struct iovec    iov[1];
147
148        union {
149          struct cmsghdr        cm;
150          char   control[CMSG_SPACE(sizeof(int))];
151        } control_un;
152        struct cmsghdr  *cmptr;
153
154        msg.msg_control = control_un.control;
155        msg.msg_controllen = sizeof(control_un.control);
156
157        cmptr = CMSG_FIRSTHDR(&msg);
158        cmptr->cmsg_len = CMSG_LEN(sizeof(int));
159        cmptr->cmsg_level = SOL_SOCKET;
160        cmptr->cmsg_type = SCM_RIGHTS;
161        *((int *) CMSG_DATA(cmptr)) = sendfd;
162        msg.msg_name = NULL;
163        msg.msg_namelen = 0;
164
165        iov[0].iov_base = ptr;
166        iov[0].iov_len = nbytes;
167        msg.msg_iov = iov;
168        msg.msg_iovlen = 1;
169
170        return(sendmsg(fd, &msg, 0));
171}
172
173
174
175ssize_t
176read_fd(int fd, void *ptr, size_t nbytes, int *recvfd)
177{
178        struct msghdr   msg;
179        struct iovec    iov[1];
180        ssize_t  n;
181        int newfd;
182
183        union {
184          struct cmsghdr        cm;
185          char   control[CMSG_SPACE(sizeof(int))];
186        } control_un;
187        struct cmsghdr  *cmptr;
188
189        msg.msg_control = control_un.control;
190        msg.msg_controllen = sizeof(control_un.control);
191
192        msg.msg_name = NULL;
193        msg.msg_namelen = 0;
194
195        iov[0].iov_base = ptr;
196        iov[0].iov_len = nbytes;
197        msg.msg_iov = iov;
198        msg.msg_iovlen = 1;
199
200        if ( (n = recvmsg(fd, &msg, MSG_WAITALL)) <= 0)
201                return(n);
202        if ( (cmptr = CMSG_FIRSTHDR(&msg)) != NULL &&
203            cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
204           if (cmptr->cmsg_level != SOL_SOCKET) {
205              perror("control level != SOL_SOCKET");
206              exit(1);
207           }
208           if (cmptr->cmsg_type != SCM_RIGHTS) {
209              perror("control type != SCM_RIGHTS");
210              exit(1);
211           }
212                *recvfd = *((int *) CMSG_DATA(cmptr));
213        } else
214                *recvfd = -1;           /* descriptor was not passed */
215        return(n);
216}
217/* end read_fd */
218
219#define UNIXSTR_PATH "/var/run/synaptic.socket"
220
221int ipc_send_fd(int fd)
222{
223   // open connection to server
224   struct sockaddr_un servaddr;
225   int serverfd = socket(AF_LOCAL, SOCK_STREAM, 0);
226   bzero(&servaddr, sizeof(servaddr));
227   servaddr.sun_family = AF_LOCAL;
228   strcpy(servaddr.sun_path, UNIXSTR_PATH);
229
230   // wait max 5s (5000 * 1000/1000000) for the server
231   for(int i=0;i<5000;i++) {
232      if(connect(serverfd, (struct sockaddr *)&servaddr, sizeof(servaddr))==0) 
233         break;
234      usleep(1000);
235   }
236   // send fd to server
237   write_fd(serverfd, (void*)"",1,fd);
238   close(serverfd);
239   return 0;
240}
241
242int ipc_recv_fd()
243{
244   int ret;
245
246   // setup socket
247   struct sockaddr_un servaddr,cliaddr;
248   char c;
249   int connfd=-1,fd;
250
251   int listenfd = socket(AF_LOCAL, SOCK_STREAM, 0);
252   fcntl(listenfd, F_SETFL, O_NONBLOCK);
253
254   unlink(UNIXSTR_PATH);
255   bzero(&servaddr, sizeof(servaddr));
256   servaddr.sun_family = AF_LOCAL;
257   strcpy(servaddr.sun_path, UNIXSTR_PATH);
258   bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
259   listen(listenfd, 1);
260
261   // wait for connections
262   socklen_t clilen = sizeof(cliaddr);
263
264   // wait max 5s (5000 * 1000/1000000) for the client
265   for(int i=0;i<5000 || connfd > 0;i++) {
266      connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);
267      if(connfd > 0)
268         break;
269      usleep(1000);
270      RGFlushInterface();
271   }
272   // read_fd
273   read_fd(connfd, &c,1,&fd);
274
275   close(connfd);
276   close(listenfd);
277
278   return fd;
279}
280
281
282
283void RGDebInstallProgress::conffile(gchar *conffile, gchar *status)
284{
285   string primary, secondary;
286   gchar *m,*s,*p;
287   GtkWidget *w;
288   RGGladeUserDialog dia(this, "conffile");
289   GladeXML *xml = dia.getGladeXML();
290
291   p = g_strdup_printf(_("Replace configuration file\n'%s'?"),conffile);
292   s = g_strdup_printf(_("The configuration file %s was modified (by "
293                         "you or by a script). An updated version is shipped "
294                         "in this package. If you want to keep your current "
295                         "version say 'Keep'. Do you want to replace the "
296                         "current file and install the new package "
297                         "maintainers version? "),conffile);
298
299   // setup dialog
300   w = glade_xml_get_widget(xml, "label_message");
301   m = g_strdup_printf("<span weight=\"bold\" size=\"larger\">%s </span> "
302                       "\n\n%s", p, s);
303   gtk_label_set_markup(GTK_LABEL(w), m);
304   g_free(p);
305   g_free(s);
306   g_free(m);
307
308   // diff stuff
309   bool quot=false;
310   int i=0;
311   string orig_file, new_file;
312
313   // FIXME: add some sanity checks here
314
315   // go to first ' and read until the end
316   for(;status[i] != '\'' || status[i] == 0;i++) 
317      /*nothing*/
318      ;
319   i++;
320   for(;status[i] != '\'' || status[i] == 0;i++) 
321      orig_file.append(1,status[i]);
322   i++;
323
324   // same for second ' and read until the end
325   for(;status[i] != '\'' || status[i] == 0;i++) 
326      /*nothing*/
327      ;
328   i++;
329   for(;status[i] != '\'' || status[i] == 0;i++) 
330      new_file.append(1,status[i]);
331   i++;
332   //cout << "got:" << orig_file << new_file << endl;
333
334   // read diff
335   string diff;
336   char buf[512];
337   char *cmd = g_strdup_printf("/usr/bin/diff -u %s %s", orig_file.c_str(), new_file.c_str());
338   FILE *f = popen(cmd,"r");
339   while(fgets(buf,512,f) != NULL) {
340      diff += utf8(buf);
341   }
342   pclose(f);
343   g_free(cmd);
344
345   // set into buffer
346   GtkTextBuffer *text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(glade_xml_get_widget(xml,"textview_diff")));
347   gtk_text_buffer_set_text(text_buffer,diff.c_str(),-1);
348
349   int res = dia.run(NULL,true);
350   if(res ==  GTK_RESPONSE_YES)
351      vte_terminal_feed_child(VTE_TERMINAL(_term), "y\n",2);
352   else
353      vte_terminal_feed_child(VTE_TERMINAL(_term), "n\n",2);
354
355   // update the "action" clock
356   last_term_action = time(NULL);
357}
358
359void RGDebInstallProgress::startUpdate()
360{
361   child_has_exited=false;
362   VteReaper* reaper = vte_reaper_get();
363   g_signal_connect(G_OBJECT(reaper), "child-exited",
364                    G_CALLBACK(child_exited),
365                    this);
366
367   // check if we run embedded
368   int id = _config->FindI("Volatile::PlugProgressInto", -1);
369   //cout << "Plug ID: " << id << endl;
370   if (id > 0) {
371      GtkWidget *vbox = glade_xml_get_widget(_gladeXML, "vbox_rgdebinstall_progress");
372      _sock =  gtk_plug_new(id);
373      gtk_widget_reparent(vbox, _sock);
374      gtk_widget_show(_sock);
375   } else {
376      show();
377   }
378   RGFlushInterface();
379}
380
381void RGDebInstallProgress::cbCancel(GtkWidget *self, void *data)
382{
383   //FIXME: we can't activate this yet, it's way to heavy (sending KILL)
384   //cout << "cbCancel: sending SIGKILL to child" << endl;
385   RGDebInstallProgress *me = (RGDebInstallProgress*)data;
386   //kill(me->_child_id, SIGINT);
387   //kill(me->_child_id, SIGQUIT);
388   kill(me->_child_id, SIGTERM);
389   //kill(me->_child_id, SIGKILL);
390   
391}
392
393void RGDebInstallProgress::cbClose(GtkWidget *self, void *data)
394{
395   //cout << "cbCancel: sending SIGKILL to child" << endl;
396   RGDebInstallProgress *me = (RGDebInstallProgress*)data;
397   me->_updateFinished = true;
398}
399
400
401void RGDebInstallProgress::expander_callback (GObject    *object,
402                                              GParamSpec *param_spec,
403                                              gpointer    user_data) 
404{
405   RGDebInstallProgress *me = (RGDebInstallProgress*)user_data;
406
407   // this crap here is needed because VteTerminal does not like
408   // it when run hidden. this workaround will scroll to the end of
409   // the current buffer
410   gtk_widget_realize(GTK_WIDGET(me->_term));
411   GtkAdjustment *a = GTK_ADJUSTMENT (VTE_TERMINAL(me->_term)->adjustment);
412   gtk_adjustment_set_value(a, a->upper - a->page_size);
413   gtk_adjustment_value_changed(a);
414
415   gtk_widget_grab_focus(me->_term);
416}
417
418bool RGDebInstallProgress::close()
419{
420   if(child_has_exited)
421      cbClose(NULL, this);
422
423   return TRUE;
424}
425
426
427RGDebInstallProgress::RGDebInstallProgress(RGMainWindow *main,
428                                           RPackageLister *lister,
429                                           RGUserDialog *userDialog)
430
431   : RInstallProgress(), RGGladeWindow(main, "rgdebinstall_progress"),
432     _totalActions(0), _progress(0), _sock(0), _userDialog(userDialog)
433
434{
435   prepare(lister);
436   setTitle(_("Applying Changes"));
437
438   // make sure we try to get a graphical debconf
439   putenv("DEBIAN_FRONTEND=gnome");
440   putenv("APT_LISTCHANGES_FRONTEND=gtk");
441
442   _startCounting = false;
443   _label_status = glade_xml_get_widget(_gladeXML, "label_status");
444   _pbarTotal = glade_xml_get_widget(_gladeXML, "progress_total");
445   gtk_progress_bar_set_pulse_step(GTK_PROGRESS_BAR(_pbarTotal), 0.025);
446   _autoClose = glade_xml_get_widget(_gladeXML, "checkbutton_auto_close");
447   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(_autoClose), 
448                                _config->FindB("Synaptic::closeZvt", false));
449   //_image = glade_xml_get_widget(_gladeXML, "image");
450
451
452   _term = vte_terminal_new();
453   vte_terminal_set_size(VTE_TERMINAL(_term),80,23);
454   GtkWidget *scrollbar = 
455      gtk_vscrollbar_new (GTK_ADJUSTMENT (VTE_TERMINAL(_term)->adjustment));
456   GTK_WIDGET_UNSET_FLAGS (scrollbar, GTK_CAN_FOCUS);
457   vte_terminal_set_scrollback_lines(VTE_TERMINAL(_term), 10000);
458   if(_config->FindB("Synaptic::useUserTerminalFont")) {
459      char *s =(char*)_config->Find("Synaptic::TerminalFontName").c_str();
460      vte_terminal_set_font_from_string(VTE_TERMINAL(_term), s);
461   } else {
462      vte_terminal_set_font_from_string(VTE_TERMINAL(_term), "monospace 8");
463   }
464   gtk_box_pack_start(GTK_BOX(glade_xml_get_widget(_gladeXML,"hbox_vte")), _term, TRUE, TRUE, 0);
465   gtk_widget_show(_term);
466   gtk_box_pack_end(GTK_BOX(glade_xml_get_widget(_gladeXML,"hbox_vte")), scrollbar, FALSE, FALSE, 0);
467   gtk_widget_show(scrollbar);
468
469   gtk_window_set_default_size(GTK_WINDOW(_win), 500, -1);
470
471   GtkWidget *w = glade_xml_get_widget(_gladeXML, "expander_terminal");
472   g_signal_connect(w, "notify::expanded",
473                    G_CALLBACK(expander_callback), this);
474
475   g_signal_connect(_term, "contents-changed",
476                    G_CALLBACK(content_changed), this);
477
478   glade_xml_signal_connect_data(_gladeXML, "on_button_cancel_clicked",
479                                 G_CALLBACK(cbCancel), this);
480   glade_xml_signal_connect_data(_gladeXML, "on_button_close_clicked",
481                                 G_CALLBACK(cbClose), this);
482
483   // init the timer
484   last_term_action = time(NULL);
485}
486
487void RGDebInstallProgress::content_changed(GObject *object, 
488                                           gpointer data)
489{
490   //cout << "RGDebInstallProgress::content_changed()" << endl;
491
492   RGDebInstallProgress *me = (RGDebInstallProgress*)data;
493
494   me->last_term_action = time(NULL);
495}
496
497void RGDebInstallProgress::updateInterface()
498{
499   char buf[2];
500   static char line[1024] = "";
501   int i=0;
502
503   while (1) {
504
505      // This algorithm should be improved (it's the same as the rpm one ;)
506      int len = read(_childin, buf, 1);
507
508      // nothing was read
509      if(len < 1) 
510         break;
511
512      // update the time we last saw some action
513      last_term_action = time(NULL);
514
515      if( buf[0] == '\n') {
516//       cout << line << endl;
517         
518         gchar **split = g_strsplit(line, ":",4);
519         
520         gchar *s=NULL;
521         gchar *pkg = g_strstrip(split[1]);
522         gchar *status = g_strstrip(split[2]);
523         // major problem here, we got unexpected input. should _never_ happen
524         if(!(pkg && status))
525            continue;
526
527         // first check for errors and conf-file prompts
528         if(strstr(status, "error") != NULL) { 
529            // error from dpkg
530            s = g_strdup_printf(_("Error in package %s"), split[1]);
531            string err = split[1] + string(": ") + split[3];
532            _error->Error(err.c_str());
533         } else if(strstr(status, "conffile-prompt") != NULL) {
534            // conffile-request
535            //cout << split[2] << " " << split[3] << endl;
536            conffile(pkg, split[3]);
537         } else if(_actionsMap.count(pkg) == 0) {
538            // no known dpkg state (happens e.g if apt reports:
539            // /bin/sh: apt-listchanges: command-not-found
540            g_strfreev(split);
541            line[0] = 0;
542            continue;
543         } else {
544            _startCounting = true;
545
546            // then go on with the package stuff
547            char *next_stage_str = NULL;
548            int next_stage = _stagesMap[pkg];
549            // is a element is not found in the map, NULL is returned
550            // (this happens when dpkg does some work left from a previous
551            //  session (rare but happens))
552           
553            char **states = _actionsMap[pkg]; 
554            char **translations = _translationsMap[pkg]; 
555            if(states && translations) {
556               next_stage_str = states[next_stage];
557//             cout << "waiting for: " << next_stage_str << endl;
558               if(next_stage_str && (strstr(status, next_stage_str) != NULL)) {
559                  s = g_strdup_printf(_(translations[next_stage]), split[1]);
560                  next_stage++;
561                  _stagesMap[pkg] = next_stage;
562                  _progress++;
563               }
564            }
565         }
566
567         // each package goes through various stages
568         float val = ((float)_progress)/((float)_totalActions);
569//       cout << _progress << "/" << _totalActions << " = " << val << endl;
570         gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(_pbarTotal), val);
571         if(s!=NULL)
572            gtk_label_set(GTK_LABEL(_label_status),s);
573         
574         // clean-up
575         g_strfreev(split);
576         g_free(s);
577         line[0] = 0;
578      } else {
579         buf[1] = 0;
580         strcat(line, buf);
581      }     
582   }
583
584   time_t now = time(NULL);
585
586   if(!_startCounting) {
587      usleep(100000);
588      gtk_progress_bar_pulse (GTK_PROGRESS_BAR(_pbarTotal));
589      // wait until we get the first message from apt
590      last_term_action = now;
591   }
592
593
594   if ((now - last_term_action) > RGTERMINAL_TIMEOUT) {
595      cout << "no statusfd changes/content updates in terminal for " 
596           << RGTERMINAL_TIMEOUT << "seconds" << endl;
597      GtkWidget *w;
598      w = glade_xml_get_widget(_gladeXML, "expander_terminal");
599      gtk_expander_set_expanded(GTK_EXPANDER(w), TRUE);
600      last_term_action = time(NULL);
601   } 
602
603
604   if (gtk_events_pending()) {
605      while (gtk_events_pending())
606         gtk_main_iteration();
607   } else {
608      usleep(5000);
609   }
610}
611
612pkgPackageManager::OrderResult RGDebInstallProgress::start(RPackageManager *pm,
613                                                       int numPackages,
614                                                       int numPackagesTotal)
615{
616   void *dummy;
617   pkgPackageManager::OrderResult res;
618   int ret;
619
620   res = pm->DoInstallPreFork();
621   if (res == pkgPackageManager::Failed)
622       return res;
623
624   /*
625    * This will make a pipe from where we can read child's output
626    */
627   _child_id = vte_terminal_forkpty(VTE_TERMINAL(_term),NULL,NULL,
628                                    false,false,false);
629   if (_child_id == 0) {
630      int fd[2];
631      pipe(fd);
632      ipc_send_fd(fd[0]); // send the read part of the pipe to the parent
633
634#ifdef WITH_DPKG_STATUSFD
635      res = pm->DoInstallPostFork(fd[1]);
636#else
637      res = pm->DoInstallPostFork();
638#endif
639
640      // dump errors into cerr (pass it to the parent process) 
641      _error->DumpErrors();
642
643      ::close(fd[0]);
644      ::close(fd[1]);
645
646      _exit(res);
647   }
648   _childin = ipc_recv_fd();
649
650   if(_childin < 0) {
651      // something _bad_ happend. so the terminal window and hope for the best
652      GtkWidget *w = glade_xml_get_widget(_gladeXML, "expander_terminal");
653      gtk_expander_set_expanded(GTK_EXPANDER(w), TRUE);
654      gtk_widget_hide(_pbarTotal);
655   }
656
657   // make it nonblocking
658   fcntl(_childin, F_SETFL, O_NONBLOCK);
659
660   _donePackages = 0;
661   _numPackages = numPackages;
662   _numPackagesTotal = numPackagesTotal;
663
664   startUpdate();
665   while(!child_has_exited)
666      updateInterface();
667
668   finishUpdate();
669
670   ::close(_childin);
671
672   return res;
673}
674
675
676
677void RGDebInstallProgress::finishUpdate()
678{
679   if (_startCounting) {
680      gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(_pbarTotal), 1.0);
681   }
682   RGFlushInterface();
683
684   GtkWidget *_closeB = glade_xml_get_widget(_gladeXML, "button_close");
685   gtk_widget_set_sensitive(_closeB, TRUE);
686
687   bool autoClose= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(_autoClose));
688   if(res == 0) {
689      gtk_widget_grab_focus(_closeB);
690      if(autoClose)
691         _updateFinished = True;
692   }
693
694   string s = _config->Find("Volatile::InstallFinishedStr",
695                            _("Changes applied"));
696   gchar *msg = g_strdup_printf("<big><b>%s</b></big>\n%s", s.c_str(),
697                                _(getResultStr(res)));
698   setTitle(_("Changes applied"));
699   GtkWidget *l = glade_xml_get_widget(_gladeXML, "label_action");
700   gtk_label_set_markup(GTK_LABEL(l), msg);
701   g_free(msg);
702
703   // hide progress and label
704   gtk_widget_hide(_pbarTotal);
705   gtk_widget_hide(_label_status);
706
707   GtkWidget *img = glade_xml_get_widget(_gladeXML,"image_finished");
708   switch(res) {
709   case 0: // success
710      gtk_image_set_from_file(GTK_IMAGE(img),
711                              PACKAGE_DATA_DIR"/pixmaps/synaptic.png");
712      break;
713   case 1: // error
714      gtk_image_set_from_stock(GTK_IMAGE(img), GTK_STOCK_DIALOG_ERROR,
715                               GTK_ICON_SIZE_DIALOG);
716      _userDialog->showErrors();
717      break;
718   case 2: // incomplete
719      gtk_image_set_from_stock(GTK_IMAGE(img), GTK_STOCK_DIALOG_INFO,
720                               GTK_ICON_SIZE_DIALOG);
721      break;
722   }
723   gtk_widget_show(img);
724   
725
726   // wait for the user to click on "close"
727   while(!_updateFinished && !autoClose) {
728      autoClose= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(_autoClose));
729      while (gtk_events_pending())
730         gtk_main_iteration();
731      usleep(5000);
732   }
733
734   // get the value again, it may have changed
735   _config->Set("Synaptic::closeZvt", autoClose ? "true" : "false");
736
737   // hide and finish
738   if(_sock != NULL) {
739      gtk_widget_destroy(_sock);
740   } else {
741      hide();
742   }
743}
744
745void RGDebInstallProgress::prepare(RPackageLister *lister)
746{
747   //cout << "prepeare called" << endl;
748
749   // build a meaningfull dialog
750   int installed, broken, toInstall, toReInstall, toRemove;
751   double sizeChange;
752   gchar *p = "Should never be displayed, please report";
753   string s = _config->Find("Volatile::InstallProgressStr",
754                            _("The marked changes are now being applied. "
755                              "This can take some time. Please wait."));
756   lister->getStats(installed, broken, toInstall, toReInstall, 
757                    toRemove, sizeChange);
758   if(toRemove > 0 && toInstall > 0) 
759      p = _("Installing and removing software");
760   else if(toRemove > 0)
761      p = _("Removing software");
762   else if(toInstall > 0)
763      p =  _("Installing software");
764
765   gchar *msg = g_strdup_printf("<big><b>%s</b></big>\n\n%s", p, s.c_str());
766   GtkWidget *l = glade_xml_get_widget(_gladeXML, "label_action");
767   gtk_label_set_markup(GTK_LABEL(l), msg);
768   g_free(msg);
769
770   for (unsigned int row = 0; row < lister->packagesSize(); row++) {
771      RPackage *pkg = lister->getPackage(row);
772      int flags = pkg->getFlags();
773      string name = pkg->name();
774
775      if((flags & RPackage::FPurge)&&
776         ((flags & RPackage::FInstalled)||(flags&RPackage::FOutdated))){
777         _actionsMap.insert(pair<string,char**>(name, purge_stages));
778         _translationsMap.insert(pair<string,char**>(name, purge_stages_translations));
779         _stagesMap.insert(pair<string,int>(name, 0));
780         _totalActions += NR_PURGE_STAGES;
781      } else if((flags & RPackage::FPurge)&& 
782                (!(flags & RPackage::FInstalled)||(flags&RPackage::FOutdated))){
783         _actionsMap.insert(pair<string,char**>(name, purge_only_stages));
784         _translationsMap.insert(pair<string,char**>(name, purge_only_stages_translations));
785         _stagesMap.insert(pair<string,int>(name, 0));
786         _totalActions += NR_PURGE_ONLY_STAGES;
787      } else if(flags & RPackage::FRemove) {
788         _actionsMap.insert(pair<string,char**>(name, remove_stages));
789         _translationsMap.insert(pair<string,char**>(name, remove_stages_translations));
790         _stagesMap.insert(pair<string,int>(name, 0));
791         _totalActions += NR_REMOVE_STAGES;
792      } else if(flags & RPackage::FNewInstall) {
793         _actionsMap.insert(pair<string,char**>(name, install_stages));
794         _translationsMap.insert(pair<string,char**>(name, install_stages_translations));
795         _stagesMap.insert(pair<string,int>(name, 0));
796         _totalActions += NR_INSTALL_STAGES;
797      } else if(flags & RPackage::FReInstall) {
798         _actionsMap.insert(pair<string,char**>(name, reinstall_stages));
799         _translationsMap.insert(pair<string,char**>(name, reinstall_stages_translations));
800         _stagesMap.insert(pair<string,int>(name, 0));
801         _totalActions += NR_REINSTALL_STAGES;
802      } else if((flags & RPackage::FUpgrade)||(flags & RPackage::FDowngrade)) {
803         _actionsMap.insert(pair<string,char**>(name, update_stages));
804         _translationsMap.insert(pair<string,char**>(name, update_stages_translations));
805         _stagesMap.insert(pair<string,int>(name, 0));
806         _totalActions += NR_UPDATE_STAGES;
807      }
808   }
809}
810
811#endif
812
813
814// vim:ts=3:sw=3:et
Note: See TracBrowser for help on using the repository browser.