libyui-gtk-pkg  2.43.2
 All Classes
ygtkpkgundolist.cc
1 /********************************************************************
2  * YaST2-GTK - http://en.opensuse.org/YaST2-GTK *
3  ********************************************************************/
4 /* YGtkPkgUndoList, list of changes */
5 // check the header file for information about this utility
6 
7 /*
8  Textdomain "gtk"
9  */
10 
11 #include "YGi18n.h"
12 #include "config.h"
13 #include "YGDialog.h"
14 #include "YGUtils.h"
15 #include "ygtkpkgundolist.h"
16 #include <gtk/gtk.h>
17 
19 {
20  YGtkPkgUndoList *parent;
21  Ypp::List changes;
22  std::list <YGtkPkgUndoList::Listener *> listeners;
23 
24  Impl (YGtkPkgUndoList *parent) : parent (parent), changes (0)
25  { Ypp::addSelListener (this); }
26 
27  ~Impl()
28  { Ypp::removeSelListener (this); }
29 
30  virtual void selectableModified()
31  {
32  // remove any previously changed selectable now undone
33  Ypp::List _changes (changes.size());
34  for (int i = 0; i < changes.size(); i++) {
35  Ypp::Selectable &sel = changes.get(i);
36  if (sel.toModify())
37  _changes.append (sel);
38  }
39  changes = _changes;
40 
41  // check for any new changed selectable
42  // first, check for user-modified, then for auto ones, to keep them ordered
43  for (int step = 0; step < 2; step++) {
44  Ypp::PoolQuery query (Ypp::Selectable::ALL);
45  query.addCriteria (new Ypp::StatusMatch (Ypp::StatusMatch::TO_MODIFY));
46  while (query.hasNext()) {
47  Ypp::Selectable sel = query.next();
48  if ((step == 0 && sel.toModifyAuto()) || (step == 1 && !sel.toModifyAuto()))
49  continue;
50  if (changes.find (sel) == -1)
51  changes.append (sel);
52  }
53  }
54 
55  for (std::list <YGtkPkgUndoList::Listener *>::iterator it = listeners.begin();
56  it != listeners.end(); it++)
57  (*it)->undoChanged (parent);
58  }
59 };
60 
61 YGtkPkgUndoList::YGtkPkgUndoList()
62 : impl (new Impl (this)) {}
63 
64 YGtkPkgUndoList::~YGtkPkgUndoList()
65 { delete impl; }
66 
67 Ypp::Selectable *YGtkPkgUndoList::front (int *autoCount)
68 {
69  Ypp::Selectable *sel = 0;
70  if (autoCount)
71  *autoCount = 0;
72  for (int i = impl->changes.size()-1; i >= 0; i--) {
73  sel = &impl->changes.get (i);
74  if (sel->toModifyAuto()) {
75  if (autoCount) (*autoCount)++;
76  }
77  else
78  break;
79  }
80  return sel;
81 }
82 
83 Ypp::List YGtkPkgUndoList::getList()
84 { return impl->changes; }
85 
86 void YGtkPkgUndoList::addListener (Listener *listener)
87 { impl->listeners.push_back (listener); }
88 
89 void YGtkPkgUndoList::removeListener (Listener *listener)
90 { impl->listeners.remove (listener); }
91 
92 #include "YGPackageSelector.h"
93 #include "ygtkpkglistview.h"
94 
96  GtkWidget *vbox, *disk_label, *download_label, *warn_label;
97 
98  GtkWidget *getWidget()
99  { return vbox; }
100 
102  {
103  GtkWidget *hbox = gtk_hbox_new (FALSE, 6);
104  GtkWidget *line;
105  line = createSizeWidget (_("Disk space required:"), &disk_label);
106  gtk_box_pack_start (GTK_BOX (hbox), line, FALSE, TRUE, 0);
107  gtk_box_pack_start (GTK_BOX (hbox), gtk_label_new ("/"), FALSE, TRUE, 0);
108  line = createSizeWidget (_("Download size:"), &download_label);
109  gtk_box_pack_start (GTK_BOX (hbox), line, FALSE, TRUE, 0);
110  gtk_widget_show_all (hbox);
111 
112  warn_label = gtk_label_new ("");
113  gtk_misc_set_alignment (GTK_MISC (warn_label), 0, .5);
114  gtk_label_set_selectable (GTK_LABEL (warn_label), TRUE);
115 
116  vbox = gtk_vbox_new (FALSE, 6);
117  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
118  gtk_box_pack_start (GTK_BOX (vbox), warn_label, FALSE, TRUE, 0);
119  gtk_widget_show (vbox);
120 
121  undoChanged (YGPackageSelector::get()->undoList());
122  YGPackageSelector::get()->undoList()->addListener (this);
123  }
124 
125  ~ChangeSizeInfo()
126  { YGPackageSelector::get()->undoList()->removeListener (this); }
127 
128  virtual void undoChanged (YGtkPkgUndoList *undo)
129  {
130  Size_t disk, download;
131  Ypp::List list = undo->getList();
132  for (int i = 0; i < list.size(); i++) {
133  Ypp::Selectable sel = list.get (i);
134  if (sel.toInstall()) {
135  Ypp::Version candidate = sel.candidate();
136  download += candidate.downloadSize();
137  if (sel.isInstalled())
138  disk += candidate.size() - sel.installed().size();
139  else
140  disk += candidate.size();
141  }
142  else if (sel.toRemove())
143  disk -= sel.installed().size();
144  }
145 
146  gtk_label_set_text (GTK_LABEL (disk_label), disk.asString().c_str());
147  gtk_label_set_text (GTK_LABEL (download_label), download.asString().c_str());
148 
149  gtk_widget_hide (warn_label);
150  ZyppDuSet diskUsage = zypp::getZYpp()->diskUsage();
151  for (ZyppDuSet::iterator it = diskUsage.begin(); it != diskUsage.end(); it++) {
152  const ZyppDu &point = *it;
153  if (!point.readonly && point.freeAfterCommit() < 0) {
154  // Translators: please keep the %s order intact. They refer to mount_point, needed_space
155  char *over = g_strdup_printf (_("Partition %s is %s over-capacity"),
156  point.dir.c_str(), point.freeAfterCommit().asString().c_str());
157  // Translators: please keep the %s order intact. They refer to used_space, total_space
158  char *fill = g_strdup_printf (_("%s filled out of %s"),
159  point.usedAfterCommit().asString().c_str(),
160  point.totalSize().asString().c_str());
161  char *markup = g_strdup_printf (
162  "<b><span color=\"red\">%s (%s)</span></b>", over, fill);
163  gtk_label_set_markup (GTK_LABEL (warn_label), markup);
164  g_free (over); g_free (fill); g_free (markup);
165  gtk_widget_show (warn_label);
166  break;
167  }
168  }
169  }
170 
171  static GtkWidget *createSizeWidget (const char *label, GtkWidget **widget)
172  {
173  *widget = gtk_label_new ("");
174  YGUtils::setWidgetFont (*widget, PANGO_STYLE_ITALIC,
175  PANGO_WEIGHT_NORMAL, PANGO_SCALE_MEDIUM);
176  gtk_misc_set_alignment (GTK_MISC (*widget), 1, .5);
177  gtk_label_set_selectable (GTK_LABEL (*widget), TRUE);
178 
179  GtkWidget *title = gtk_label_new (label);
180  gtk_misc_set_alignment (GTK_MISC (title), 0, .5);
181 
182  GtkWidget *hbox = gtk_hbox_new (FALSE, 6);
183  gtk_box_pack_start (GTK_BOX (hbox), title, FALSE, TRUE, 0);
184  gtk_box_pack_start (GTK_BOX (hbox), *widget, TRUE, TRUE, 0);
185  return hbox;
186  }
187 };
188 
189 #define YAST_SYSCONFIG "/etc/sysconfig/yast2"
190 #include <zypp/base/Sysconfig.h>
191 
192 enum { CLOSE_MODE, RESTART_MODE, SUMMARY_MODE };
193 
194 static int read_PKGMGR_ACTION_AT_EXIT()
195 { // from yast2-ncurses, NCPackageSelector.cc
196  std::map <std::string, std::string> sysconfig =
197  zypp::base::sysconfig::read (YAST_SYSCONFIG);
198  std::map <std::string, std::string>::const_iterator it =
199  sysconfig.find("PKGMGR_ACTION_AT_EXIT");
200  if (it != sysconfig.end()) {
201  yuiMilestone() << "Read sysconfig's action at pkg mgr exit value: " << it->second << std::endl;
202  std::string mode (it->second);
203  if (mode == "restart")
204  return RESTART_MODE;
205  else if (mode == "summary")
206  return SUMMARY_MODE;
207  else //if (mode == "close")
208  return CLOSE_MODE;
209  }
210  yuiMilestone() << "Could not read PKGMGR_ACTION_AT_EXIT variable from sysconfig" << std::endl;
211  return false;
212 }
213 
214 static void write_PKGMGR_ACTION_AT_EXIT (int mode)
215 { // from yast2-ncurses, NCPackageSelector.cc
216  // this is really, really stupid. But we have no other iface for writing sysconfig so far
217  std::string _mode;
218  switch (mode) {
219  case CLOSE_MODE: _mode = "close"; break;
220  case RESTART_MODE: _mode = "restart"; break;
221  case SUMMARY_MODE: _mode = "summary"; break;
222  }
223  int ret = -1;
224  std::string cmd = "sed -i 's/^[ \t]*PKGMGR_ACTION_AT_EXIT.*$/PKGMGR_ACTION_AT_EXIT=\"" +
225  _mode + "\"/' " + YAST_SYSCONFIG;
226  ret = system(cmd.c_str());
227  yuiMilestone() << "Executing system cmd " << cmd << " returned " << ret << std::endl;
228 }
229 
230 static void close_when_done_toggled_cb (GtkToggleButton *button)
231 {
232  gtk_toggle_button_set_inconsistent (button, FALSE);
233  int mode = gtk_toggle_button_get_active (button) ? CLOSE_MODE : RESTART_MODE;
234  write_PKGMGR_ACTION_AT_EXIT (mode);
235 }
236 
237 static GtkWidget *create_close_when_done_check()
238 {
239  GtkWidget *check_box = gtk_check_button_new_with_label (_("Close software manager when done"));
240  int mode = read_PKGMGR_ACTION_AT_EXIT();
241  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_box), mode == CLOSE_MODE);
242  gtk_toggle_button_set_inconsistent (GTK_TOGGLE_BUTTON (check_box), mode == SUMMARY_MODE);
243  if (access (YAST_SYSCONFIG, W_OK) != 0) {
244  gtk_widget_set_sensitive (check_box, FALSE);
245  gtk_widget_set_tooltip_text (check_box, "Cannot write to " YAST_SYSCONFIG);
246  }
247  g_signal_connect_after (G_OBJECT (check_box), "toggled",
248  G_CALLBACK (close_when_done_toggled_cb), NULL);
249  gtk_widget_show (check_box);
250  return check_box;
251 }
252 
254 {
256  : YGtkPkgListView (true, -1, true, false, true)
257  {
258  addImageColumn (NULL, STATUS_ICON_PROP, true);
259  addTextColumn (_("Name"), ACTION_NAME_PROP, true, -1);
260  addTextColumn (_("Version"), SINGLE_VERSION_PROP, true, 125);
261  addButtonColumn (_("Revert?"), UNDO_BUTTON_PROP);
262 
263  undoChanged (YGPackageSelector::get()->undoList());
264  YGPackageSelector::get()->undoList()->addListener (this);
265  }
266 
267  ~YGtkPkgUndoView()
268  { YGPackageSelector::get()->undoList()->removeListener (this); }
269 
270  virtual void undoChanged (YGtkPkgUndoList *undo)
271  { setList (undo->getList()); }
272 };
273 
274 #include "ygtkpkghistorydialog.h"
275 
276 bool YGtkPkgUndoList::popupDialog (bool onApply)
277 {
278  GtkMessageType type = onApply ? GTK_MESSAGE_QUESTION : GTK_MESSAGE_OTHER;
279  GtkWidget *dialog = gtk_message_dialog_new (YGDialog::currentWindow(),
280  GtkDialogFlags (0), type, GTK_BUTTONS_NONE, _("Summary of changes"));
281  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
282  _("Review the changes to perform."));
283  if (onApply)
284  gtk_dialog_add_buttons (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_NO,
285  GTK_STOCK_APPLY, GTK_RESPONSE_YES, NULL);
286  else {
287  GtkWidget *image = gtk_image_new_from_stock (GTK_STOCK_UNDO, GTK_ICON_SIZE_DIALOG);
288  gtk_widget_show (image);
289  gtk_message_dialog_set_image (GTK_MESSAGE_DIALOG (dialog), image);
290  gtk_dialog_add_buttons (GTK_DIALOG (dialog), _("See History"), 1,
291  GTK_STOCK_CLOSE, GTK_RESPONSE_YES, NULL);
292 
293  // work-around for GTK bug: when you set a custom icon, it is packed as expanded
294  GtkWidget *hbox = gtk_widget_get_parent (image);
295  gtk_box_set_child_packing (GTK_BOX (hbox), image, FALSE, TRUE, 0, GTK_PACK_START);
296  }
297  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_YES);
298  gtk_window_set_resizable (GTK_WINDOW (dialog), TRUE);
299  gtk_window_set_default_size (GTK_WINDOW (dialog), 600, 500);
300 
301  YGtkPkgUndoView view;
302  ChangeSizeInfo change_size;
303 
304  GtkWidget *vbox = gtk_vbox_new (FALSE, 6);
305  gtk_box_pack_start (GTK_BOX (vbox), view.getWidget(), TRUE, TRUE, 0);
306  gtk_box_pack_start (GTK_BOX (vbox), change_size.getWidget(), FALSE, TRUE, 0);
307  if (onApply)
308  gtk_box_pack_start (GTK_BOX (vbox), create_close_when_done_check(), FALSE, TRUE, 0);
309  gtk_widget_show (vbox);
310  gtk_widget_set_vexpand (vbox, TRUE);
311  GtkContainer *content = GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (dialog)));
312  gtk_container_add (content, vbox);
313 
314  int ret = gtk_dialog_run (GTK_DIALOG (dialog));
315  if (ret == 1)
316  YGPackageSelector::get()->showHistoryDialog();
317  gtk_widget_destroy (dialog);
318  return ret == GTK_RESPONSE_YES;
319 }
320