[280] | 1 | /* rgfetchprogress.cc |
---|
| 2 | * |
---|
| 3 | * Copyright (c) 2000, 2001 Conectiva S/A |
---|
| 4 | * 2002, 2003 Michael Vogt <mvo@debian.org> |
---|
| 5 | * |
---|
| 6 | * Author: Alfredo K. Kojima <kojima@conectiva.com.br> |
---|
| 7 | * Michael Vogt <mvo@debian.org> |
---|
| 8 | * |
---|
| 9 | * This program is free software; you can redistribute it and/or |
---|
| 10 | * modify it under the terms of the GNU General Public License as |
---|
| 11 | * published by the Free Software Foundation; either version 2 of the |
---|
| 12 | * License, or (at your option) any later version. |
---|
| 13 | * |
---|
| 14 | * This program is distributed in the hope that it will be useful, |
---|
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
| 17 | * GNU General Public License for more details. |
---|
| 18 | * |
---|
| 19 | * You should have received a copy of the GNU General Public License |
---|
| 20 | * along with this program; if not, write to the Free Software |
---|
| 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
---|
| 22 | * USA |
---|
| 23 | */ |
---|
| 24 | |
---|
| 25 | #include "config.h" |
---|
| 26 | |
---|
| 27 | #include <apt-pkg/acquire-item.h> |
---|
| 28 | #include <apt-pkg/acquire-worker.h> |
---|
| 29 | #include <apt-pkg/strutl.h> |
---|
| 30 | #include <apt-pkg/error.h> |
---|
| 31 | |
---|
| 32 | #include "rgfetchprogress.h" |
---|
| 33 | #include "rguserdialog.h" |
---|
| 34 | #include "rgmisc.h" |
---|
| 35 | |
---|
| 36 | #include <stdio.h> |
---|
| 37 | #include <pango/pango.h> |
---|
| 38 | #include <gtk/gtk.h> |
---|
| 39 | #include <cassert> |
---|
| 40 | |
---|
| 41 | #include "i18n.h" |
---|
| 42 | |
---|
| 43 | enum { |
---|
| 44 | DLDone = -1, |
---|
| 45 | DLQueued = -2, |
---|
| 46 | DLFailed = -3, |
---|
| 47 | DLHit = -4 |
---|
| 48 | }; |
---|
| 49 | |
---|
| 50 | enum { |
---|
| 51 | FETCH_PIXMAP_COLUMN, |
---|
| 52 | FETCH_SIZE_COLUMN, |
---|
| 53 | FETCH_DESCR_COLUMN, |
---|
| 54 | FETCH_URL_COLUMN, |
---|
| 55 | N_FETCH_COLUMNS |
---|
| 56 | }; |
---|
| 57 | |
---|
| 58 | static const int COLUMN_PERCENT_WIDTH=100; |
---|
| 59 | static const int COLUMN_PERCENT_HEIGHT=18; |
---|
| 60 | |
---|
| 61 | |
---|
| 62 | bool RGFetchProgress::close() |
---|
| 63 | { |
---|
| 64 | stopDownload(NULL, this); |
---|
| 65 | |
---|
| 66 | return TRUE; |
---|
| 67 | } |
---|
| 68 | |
---|
| 69 | RGFetchProgress::RGFetchProgress(RGWindow *win) |
---|
| 70 | : RGGladeWindow(win, "fetch"), _cursorDirty(false), _sock(NULL) |
---|
| 71 | { |
---|
| 72 | GtkCellRenderer *renderer; |
---|
| 73 | GtkTreeViewColumn *column; |
---|
| 74 | |
---|
| 75 | _mainProgressBar = glade_xml_get_widget(_gladeXML, "progressbar_download"); |
---|
| 76 | assert(_mainProgressBar); |
---|
| 77 | |
---|
| 78 | _table = glade_xml_get_widget(_gladeXML, "treeview_fetch"); |
---|
| 79 | _tableListStore = gtk_list_store_new(N_FETCH_COLUMNS, |
---|
| 80 | GDK_TYPE_PIXBUF, |
---|
| 81 | G_TYPE_STRING, G_TYPE_STRING, |
---|
| 82 | G_TYPE_STRING); |
---|
| 83 | gtk_tree_view_set_model(GTK_TREE_VIEW(_table), |
---|
| 84 | GTK_TREE_MODEL(_tableListStore)); |
---|
| 85 | |
---|
| 86 | /* percent column */ |
---|
| 87 | renderer = gtk_cell_renderer_pixbuf_new(); |
---|
| 88 | column = gtk_tree_view_column_new_with_attributes(_("Status"), renderer, |
---|
| 89 | "pixbuf", |
---|
| 90 | FETCH_PIXMAP_COLUMN, |
---|
| 91 | NULL); |
---|
| 92 | gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED); |
---|
| 93 | gtk_tree_view_column_set_fixed_width(column, COLUMN_PERCENT_WIDTH); |
---|
| 94 | _statusColumn = column; |
---|
| 95 | _statusRenderer = renderer; |
---|
| 96 | gtk_tree_view_append_column(GTK_TREE_VIEW(_table), column); |
---|
| 97 | |
---|
| 98 | /* size */ |
---|
| 99 | renderer = gtk_cell_renderer_text_new(); |
---|
| 100 | column = gtk_tree_view_column_new_with_attributes(_("Size"), renderer, |
---|
| 101 | "text", FETCH_SIZE_COLUMN, |
---|
| 102 | NULL); |
---|
| 103 | gtk_tree_view_append_column(GTK_TREE_VIEW(_table), column); |
---|
| 104 | |
---|
| 105 | /* descr */ |
---|
| 106 | renderer = gtk_cell_renderer_text_new(); |
---|
| 107 | column = gtk_tree_view_column_new_with_attributes(_("Package"), renderer, |
---|
| 108 | "text",FETCH_DESCR_COLUMN, |
---|
| 109 | NULL); |
---|
| 110 | gtk_tree_view_append_column(GTK_TREE_VIEW(_table), column); |
---|
| 111 | |
---|
| 112 | /* url */ |
---|
| 113 | renderer = gtk_cell_renderer_text_new(); |
---|
| 114 | column = gtk_tree_view_column_new_with_attributes(_("URI"), renderer, |
---|
| 115 | "text", FETCH_URL_COLUMN, |
---|
| 116 | NULL); |
---|
| 117 | gtk_tree_view_append_column(GTK_TREE_VIEW(_table), column); |
---|
| 118 | |
---|
| 119 | |
---|
| 120 | glade_xml_signal_connect_data(_gladeXML, |
---|
| 121 | "on_button_cancel_clicked", |
---|
| 122 | G_CALLBACK(stopDownload), this); |
---|
| 123 | |
---|
| 124 | PangoContext *context = gdk_pango_context_get(); |
---|
| 125 | _layout = pango_layout_new(context); |
---|
| 126 | |
---|
| 127 | // check if we should run embedded somewhere |
---|
| 128 | // we need to make the window show before we obtain the _gc |
---|
| 129 | int id = _config->FindI("Volatile::PlugProgressInto", -1); |
---|
| 130 | //cout << "Plug ID: " << id << endl; |
---|
| 131 | if (id > 0) { |
---|
| 132 | gtk_widget_hide(glade_xml_get_widget(_gladeXML, "window_fetch")); |
---|
| 133 | GtkWidget *vbox = glade_xml_get_widget(_gladeXML, "vbox_fetch"); |
---|
| 134 | _sock = gtk_plug_new(id); |
---|
| 135 | gtk_widget_reparent(vbox, _sock); |
---|
| 136 | gtk_widget_show_all(_sock); |
---|
| 137 | _win = _sock; |
---|
| 138 | } |
---|
| 139 | show(); |
---|
| 140 | |
---|
| 141 | GtkStyle *style = gtk_widget_get_style(_win); |
---|
| 142 | _font = style->font_desc; |
---|
| 143 | _gc = style->white_gc; |
---|
| 144 | _barGC = style->bg_gc[0]; |
---|
| 145 | _textGC = style->black_gc; |
---|
| 146 | |
---|
| 147 | // emit a signal if the user changed the cursor |
---|
| 148 | g_signal_connect(G_OBJECT(_table), "cursor-changed", |
---|
| 149 | G_CALLBACK(cursorChanged), this); |
---|
| 150 | |
---|
| 151 | // emit a signal if the user changed the cursor |
---|
| 152 | GtkWidget *expander = glade_xml_get_widget(_gladeXML, "expander"); |
---|
| 153 | assert(expander); |
---|
| 154 | g_signal_connect (expander, "notify::expanded", |
---|
| 155 | G_CALLBACK (expanderActivate), this); |
---|
| 156 | |
---|
| 157 | } |
---|
| 158 | |
---|
| 159 | void RGFetchProgress::expanderActivate(GObject *object, |
---|
| 160 | GParamSpec *param_spec, |
---|
| 161 | gpointer data) |
---|
| 162 | { |
---|
| 163 | GtkExpander *expander = GTK_EXPANDER (object); |
---|
| 164 | RGFetchProgress *me = (RGFetchProgress*)data; |
---|
| 165 | |
---|
| 166 | GtkWidget *win = glade_xml_get_widget(me->_gladeXML, "window_fetch"); |
---|
| 167 | if (gtk_expander_get_expanded (expander)) |
---|
| 168 | gtk_window_set_resizable(GTK_WINDOW(win),TRUE); |
---|
| 169 | else |
---|
| 170 | gtk_window_set_resizable(GTK_WINDOW(win), FALSE); |
---|
| 171 | } |
---|
| 172 | |
---|
| 173 | |
---|
| 174 | void RGFetchProgress::cursorChanged(GtkTreeView *self, void *data) |
---|
| 175 | { |
---|
| 176 | //cout << "cursor-changed" << endl; |
---|
| 177 | RGFetchProgress *me = (RGFetchProgress *)data; |
---|
| 178 | me->_cursorDirty=true; |
---|
| 179 | } |
---|
| 180 | |
---|
| 181 | void RGFetchProgress::setDescription(string mainText, string secondText) |
---|
| 182 | { |
---|
| 183 | gtk_window_set_title(GTK_WINDOW(_win), mainText.c_str()); |
---|
| 184 | gchar *str = g_strdup_printf("<big><b>%s</b></big> \n\n%s", |
---|
| 185 | mainText.c_str(), secondText.c_str()); |
---|
| 186 | gtk_label_set_markup(GTK_LABEL(glade_xml_get_widget(_gladeXML, "label_description")), str); |
---|
| 187 | |
---|
| 188 | |
---|
| 189 | g_free(str); |
---|
| 190 | } |
---|
| 191 | |
---|
| 192 | bool RGFetchProgress::MediaChange(string Media, string Drive) |
---|
| 193 | { |
---|
| 194 | gchar *msg; |
---|
| 195 | |
---|
| 196 | msg = g_strdup_printf(_("Please insert the disk labeled:\n%s\nin drive %s"), |
---|
| 197 | Media.c_str(), Drive.c_str()); |
---|
| 198 | |
---|
| 199 | RGUserDialog userDialog(this); |
---|
| 200 | _cancelled = !userDialog.proceed(msg); |
---|
| 201 | |
---|
| 202 | RGFlushInterface(); |
---|
| 203 | g_free(msg); |
---|
| 204 | return true; |
---|
| 205 | |
---|
| 206 | |
---|
| 207 | |
---|
| 208 | #if 0 // this code can be used when apt fixed ubuntu #2281 (patch pending) |
---|
| 209 | bool res = !userDialog.proceed(msg); |
---|
| 210 | //cout << "Media change " << res << endl; |
---|
| 211 | |
---|
| 212 | RGFlushInterface(); |
---|
| 213 | g_free(msg); |
---|
| 214 | |
---|
| 215 | if(res) { |
---|
| 216 | return false; |
---|
| 217 | } else { |
---|
| 218 | Update = true; |
---|
| 219 | return true; |
---|
| 220 | } |
---|
| 221 | #endif |
---|
| 222 | } |
---|
| 223 | |
---|
| 224 | |
---|
| 225 | void RGFetchProgress::updateStatus(pkgAcquire::ItemDesc & Itm, int status) |
---|
| 226 | { |
---|
| 227 | //cout << "void RGFetchProgress::updateStatus()" << endl; |
---|
| 228 | |
---|
| 229 | if (Itm.Owner->ID == 0) { |
---|
| 230 | Item item; |
---|
| 231 | item.descr = Itm.ShortDesc; |
---|
| 232 | item.uri = Itm.Description; |
---|
| 233 | item.size = string(SizeToStr(Itm.Owner->FileSize)); |
---|
| 234 | item.status = status; |
---|
| 235 | _items.push_back(item); |
---|
| 236 | Itm.Owner->ID = _items.size(); |
---|
| 237 | refreshTable(Itm.Owner->ID - 1, true); |
---|
| 238 | } else if (_items[Itm.Owner->ID - 1].status != status) { |
---|
| 239 | _items[Itm.Owner->ID - 1].status = status; |
---|
| 240 | refreshTable(Itm.Owner->ID - 1, false); |
---|
| 241 | } |
---|
| 242 | } |
---|
| 243 | |
---|
| 244 | |
---|
| 245 | void RGFetchProgress::IMSHit(pkgAcquire::ItemDesc & Itm) |
---|
| 246 | { |
---|
| 247 | //cout << "void RGFetchProgress::IMSHit(pkgAcquire::ItemDesc &Itm)" << endl; |
---|
| 248 | updateStatus(Itm, DLHit); |
---|
| 249 | |
---|
| 250 | RGFlushInterface(); |
---|
| 251 | } |
---|
| 252 | |
---|
| 253 | |
---|
| 254 | void RGFetchProgress::Fetch(pkgAcquire::ItemDesc & Itm) |
---|
| 255 | { |
---|
| 256 | updateStatus(Itm, DLQueued); |
---|
| 257 | |
---|
| 258 | RGFlushInterface(); |
---|
| 259 | } |
---|
| 260 | |
---|
| 261 | |
---|
| 262 | void RGFetchProgress::Done(pkgAcquire::ItemDesc & Itm) |
---|
| 263 | { |
---|
| 264 | updateStatus(Itm, DLDone); |
---|
| 265 | |
---|
| 266 | RGFlushInterface(); |
---|
| 267 | } |
---|
| 268 | |
---|
| 269 | |
---|
| 270 | void RGFetchProgress::Fail(pkgAcquire::ItemDesc & Itm) |
---|
| 271 | { |
---|
| 272 | if (Itm.Owner->Status == pkgAcquire::Item::StatIdle) |
---|
| 273 | return; |
---|
| 274 | |
---|
| 275 | updateStatus(Itm, DLFailed); |
---|
| 276 | |
---|
| 277 | RGFlushInterface(); |
---|
| 278 | } |
---|
| 279 | |
---|
| 280 | |
---|
| 281 | bool RGFetchProgress::Pulse(pkgAcquire * Owner) |
---|
| 282 | { |
---|
| 283 | //cout << "RGFetchProgress::Pulse(pkgAcquire *Owner)" << endl; |
---|
| 284 | |
---|
| 285 | pkgAcquireStatus::Pulse(Owner); |
---|
| 286 | |
---|
| 287 | for (pkgAcquire::Worker * I = Owner->WorkersBegin(); I != 0; |
---|
| 288 | I = Owner->WorkerStep(I)) { |
---|
| 289 | |
---|
| 290 | if (I->CurrentItem == 0) |
---|
| 291 | continue; |
---|
| 292 | |
---|
| 293 | if (I->TotalSize > 0) |
---|
| 294 | updateStatus(*I->CurrentItem, |
---|
| 295 | long (double (I->CurrentSize * 100.0) / |
---|
| 296 | double (I->TotalSize))); |
---|
| 297 | else |
---|
| 298 | updateStatus(*I->CurrentItem, 100); |
---|
| 299 | |
---|
| 300 | } |
---|
| 301 | |
---|
| 302 | float percent = |
---|
| 303 | long (double ((CurrentBytes + CurrentItems) * 100.0) / |
---|
| 304 | double (TotalBytes + TotalItems)); |
---|
| 305 | // work-around a stupid problem with libapt |
---|
| 306 | if(CurrentItems == TotalItems) |
---|
| 307 | percent=100.0; |
---|
| 308 | |
---|
| 309 | gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(_mainProgressBar), |
---|
| 310 | percent / 100.0); |
---|
| 311 | |
---|
| 312 | unsigned long ETA = |
---|
| 313 | (unsigned long)((TotalBytes - CurrentBytes) / CurrentCPS); |
---|
| 314 | long i = CurrentItems < TotalItems ? CurrentItems + 1 : CurrentItems; |
---|
| 315 | gchar *s; |
---|
| 316 | if (CurrentCPS != 0 && ETA != 0) { |
---|
| 317 | s = g_strdup_printf(_("Download rate: %s/s - %s remaining"), |
---|
| 318 | SizeToStr(CurrentCPS).c_str(), |
---|
| 319 | TimeToStr(ETA).c_str()); |
---|
| 320 | gtk_label_set_text(GTK_LABEL(glade_xml_get_widget(_gladeXML, "label_eta")),s); |
---|
| 321 | g_free(s); |
---|
| 322 | } else { |
---|
| 323 | gtk_label_set_text(GTK_LABEL(glade_xml_get_widget(_gladeXML, "label_eta")),_("Download rate: unknown")); |
---|
| 324 | } |
---|
| 325 | s = g_strdup_printf(_("Downloading file %li of %li"), i, TotalItems); |
---|
| 326 | gtk_progress_bar_set_text(GTK_PROGRESS_BAR(_mainProgressBar), s); |
---|
| 327 | g_free(s); |
---|
| 328 | |
---|
| 329 | RGFlushInterface(); |
---|
| 330 | |
---|
| 331 | return !_cancelled; |
---|
| 332 | } |
---|
| 333 | |
---|
| 334 | |
---|
| 335 | void RGFetchProgress::Start() |
---|
| 336 | { |
---|
| 337 | //cout << "RGFetchProgress::Start()" << endl; |
---|
| 338 | pkgAcquireStatus::Start(); |
---|
| 339 | _cancelled = false; |
---|
| 340 | show(); |
---|
| 341 | |
---|
| 342 | RGFlushInterface(); |
---|
| 343 | } |
---|
| 344 | |
---|
| 345 | |
---|
| 346 | void RGFetchProgress::Stop() |
---|
| 347 | { |
---|
| 348 | //cout << "RGFetchProgress::Stop()" << endl; |
---|
| 349 | RGFlushInterface(); |
---|
| 350 | if(_sock != NULL) { |
---|
| 351 | gtk_widget_destroy(_sock); |
---|
| 352 | } else { |
---|
| 353 | hide(); |
---|
| 354 | } |
---|
| 355 | pkgAcquireStatus::Stop(); |
---|
| 356 | |
---|
| 357 | //FIXME: this needs to be handled in a better way (gtk-2 maybe?) |
---|
| 358 | sleep(1); // this sucks, but if ommited, the window will not always |
---|
| 359 | // closed (e.g. when a package is only deleted) |
---|
| 360 | RGFlushInterface(); |
---|
| 361 | } |
---|
| 362 | |
---|
| 363 | |
---|
| 364 | |
---|
| 365 | void RGFetchProgress::stopDownload(GtkWidget *self, void *data) |
---|
| 366 | { |
---|
| 367 | RGFetchProgress *me = (RGFetchProgress *) data; |
---|
| 368 | |
---|
| 369 | me->_cancelled = true; |
---|
| 370 | } |
---|
| 371 | |
---|
| 372 | |
---|
| 373 | GdkPixmap *RGFetchProgress::statusDraw(int width, int height, int status) |
---|
| 374 | { |
---|
| 375 | int x, y; |
---|
| 376 | char *str = ""; |
---|
| 377 | GdkPixmap *pix; |
---|
| 378 | int px, pw; |
---|
| 379 | |
---|
| 380 | pix = gdk_pixmap_new(_win->window, width, height, -1); |
---|
| 381 | |
---|
| 382 | px = 0; |
---|
| 383 | pw = status * width / 100; |
---|
| 384 | |
---|
| 385 | if (status < 0) { |
---|
| 386 | if (status == DLDone || status == DLHit) |
---|
| 387 | gdk_draw_rectangle(pix, _barGC, TRUE, px, 0, pw, height); |
---|
| 388 | else |
---|
| 389 | gdk_draw_rectangle(pix, _gc, TRUE, px, 0, pw, height); |
---|
| 390 | |
---|
| 391 | switch (status) { |
---|
| 392 | case DLQueued: |
---|
| 393 | str = _("Queued"); |
---|
| 394 | break; |
---|
| 395 | case DLDone: |
---|
| 396 | str = _("Done"); |
---|
| 397 | break; |
---|
| 398 | case DLHit: |
---|
| 399 | str = _("Hit"); |
---|
| 400 | break; |
---|
| 401 | case DLFailed: |
---|
| 402 | str = _("Failed"); |
---|
| 403 | break; |
---|
| 404 | } |
---|
| 405 | } else { |
---|
| 406 | static char buf[16]; |
---|
| 407 | |
---|
| 408 | gdk_draw_rectangle(pix, _barGC, TRUE, px, 0, pw, height); |
---|
| 409 | gdk_draw_rectangle(pix, _gc, TRUE, px + pw, 0, width - pw - 2, height); |
---|
| 410 | |
---|
| 411 | snprintf(buf, sizeof(buf), "%d%%", status); |
---|
| 412 | str = buf; |
---|
| 413 | } |
---|
| 414 | |
---|
| 415 | pango_layout_set_font_description(_layout, _font); |
---|
| 416 | pango_layout_set_text(_layout, str, -1); |
---|
| 417 | pango_layout_get_pixel_size(_layout, &x, &y); |
---|
| 418 | x = (width - x) / 2; |
---|
| 419 | gdk_draw_layout(pix, _textGC, x, 0, _layout); |
---|
| 420 | |
---|
| 421 | return pix; |
---|
| 422 | } |
---|
| 423 | |
---|
| 424 | |
---|
| 425 | void RGFetchProgress::refreshTable(int row, bool append) |
---|
| 426 | { |
---|
| 427 | //cout << "RGFetchProgress::refreshTable() " << row << endl; |
---|
| 428 | GtkTreeIter iter; |
---|
| 429 | static GdkPixmap *pix = NULL; |
---|
| 430 | static GdkPixbuf *buf = NULL; |
---|
| 431 | int w, h; |
---|
| 432 | |
---|
| 433 | // unref pix first (they start with a usage count of 1 |
---|
| 434 | // why not unref'ing it after adding in the table? -- niemeyer |
---|
| 435 | if (pix != NULL) |
---|
| 436 | gdk_pixmap_unref(pix); |
---|
| 437 | if (buf != NULL) |
---|
| 438 | gdk_pixbuf_unref(buf); |
---|
| 439 | |
---|
| 440 | w = COLUMN_PERCENT_WIDTH; //gtk_tree_view_column_get_width(_statusColumn); |
---|
| 441 | h = COLUMN_PERCENT_HEIGHT; // FIXME: height -> get it from somewhere |
---|
| 442 | |
---|
| 443 | pix = statusDraw(w, h, _items[row].status); |
---|
| 444 | buf = gdk_pixbuf_get_from_drawable(NULL, pix, NULL, 0, 0, 0, 0, w, h); |
---|
| 445 | GtkTreePath *path; |
---|
| 446 | if (append == true) { |
---|
| 447 | gtk_list_store_insert(_tableListStore, &iter, row); |
---|
| 448 | path = gtk_tree_path_new(); |
---|
| 449 | gtk_tree_path_append_index(path, row); |
---|
| 450 | //gtk_tree_view_set_cursor(GTK_TREE_VIEW(_table), path, NULL, false); |
---|
| 451 | if(!_cursorDirty) |
---|
| 452 | gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(_table), |
---|
| 453 | path, NULL, TRUE, 0.0, 0.0); |
---|
| 454 | gtk_tree_path_free(path); |
---|
| 455 | // can't we use the iterator here? |
---|
| 456 | } else { |
---|
| 457 | gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(_tableListStore), |
---|
| 458 | &iter, NULL, row); |
---|
| 459 | } |
---|
| 460 | gtk_list_store_set(_tableListStore, &iter, |
---|
| 461 | FETCH_PIXMAP_COLUMN, buf, |
---|
| 462 | FETCH_SIZE_COLUMN, _items[row].size.c_str(), |
---|
| 463 | FETCH_DESCR_COLUMN, _items[row].descr.c_str(), |
---|
| 464 | FETCH_URL_COLUMN, _items[row].uri.c_str(), -1); |
---|
| 465 | path = gtk_tree_model_get_path(GTK_TREE_MODEL(_tableListStore), &iter); |
---|
| 466 | if(!_cursorDirty) |
---|
| 467 | gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(_table), |
---|
| 468 | path, NULL, TRUE, 0.0, 0.0); |
---|
| 469 | gtk_tree_path_free(path); |
---|
| 470 | } |
---|
| 471 | |
---|
| 472 | // vim:sts=4:sw=4 |
---|