box_data_calendar_related.cc 21.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/* Glom
 *
 * Copyright (C) 2001-2004 Murray Cumming
 *
 * 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; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

21
#include <glom/mode_data/box_data_calendar_related.h>
22
#include <glom/mode_design/layout/dialog_layout_calendar_related.h>
23
#include <glom/utils_ui.h>
24
#include <glom/application.h>
25
#include <libglom/data_structure/glomconversions.h>
26
#include <glom/frame_glom.h> //For show_ok_dialog()
27
#include <glom/glade_utils.h>
28 29 30 31 32
#include <glibmm/i18n.h>

namespace Glom
{

33
Box_Data_Calendar_Related::Box_Data_Calendar_Related()
34 35
: m_pMenuPopup(0),
  m_query_column_date_field(-1)
36 37 38
{
  set_size_request(400, -1); //An arbitrary default.

39 40
  m_Alignment.add(m_calendar);
  m_calendar.show();
41

42 43
  //m_calendar.set_show_details();
  m_calendar.set_detail_width_chars(7);
44 45
  m_calendar.set_detail_height_rows(2);

46 47
  //Tell the calendar how to get the record details to show:
  m_calendar.set_detail_func( sigc::mem_fun(*this, &Box_Data_Calendar_Related::on_calendar_details) );
48

49
  m_calendar.signal_month_changed().connect( sigc::mem_fun(*this, &Box_Data_Calendar_Related::on_calendar_month_changed) );
50

51 52 53
  setup_menu();
  //m_calendar.add_events(Gdk::BUTTON_PRESS_MASK); //Allow us to catch button_press_event and button_release_event
  m_calendar.signal_button_press_event().connect_notify( sigc::mem_fun(*this, &Box_Data_Calendar_Related::on_calendar_button_press_event) );
54

55
  m_layout_name = "list_related_calendar"; //TODO: We need a unique name when 2 portals use the same table.
56 57
}

58 59 60 61 62
Box_Data_Calendar_Related::~Box_Data_Calendar_Related()
{
  clear_cached_database_values();
}

63
void Box_Data_Calendar_Related::enable_buttons()
64
{
65 66
  //const bool view_details_possible = get_has_suitable_record_to_view_details();
  //m_calendar.set_allow_view_details(view_details_possible); //Don't allow the user to go to a record in a hidden table.
67 68
}

69
bool Box_Data_Calendar_Related::init_db_details(const sharedptr<const LayoutItem_Portal>& portal, bool show_title)
70
{
71 72 73
  //This calls the other method overload:
  return Box_Data_Portal::init_db_details(portal, show_title);
}
74

75 76 77
bool Box_Data_Calendar_Related::init_db_details(const Glib::ustring& parent_table, bool show_title)
{
  //std::cout << "DEBUG: Box_Data_Calendar_Related::init_db_details(): " << parent_table << std::endl;
78

79 80 81
  m_parent_table = parent_table;

  if(m_portal)
82
    LayoutWidgetBase::m_table_name = m_portal->get_table_used(Glib::ustring() /* parent table_name, not used. */);
83 84 85 86 87 88
  else
    LayoutWidgetBase::m_table_name = Glib::ustring();

  Base_DB_Table::m_table_name = LayoutWidgetBase::m_table_name;

  //TODO: This is duplicated in box_data_related_list.cc and box_data_portal.cc. Just use code from the base class?
89 90
  if(show_title)
  {
91 92 93 94 95 96 97 98 99
    Glib::ustring relationship_title;
    if(m_portal && m_portal->get_has_relationship_name())
      relationship_title = m_portal->get_title_used(Glib::ustring() /* parent title - not relevant */);
    else
    {
      //Note to translators: This text is shown instead of a table title, when the table has not yet been chosen.
      relationship_title = _("Undefined Table");
    }

Murray Cumming's avatar
Murray Cumming committed
100
    m_Label.set_markup(Utils::bold_message(relationship_title));
101 102 103 104 105 106 107 108 109 110 111 112
    m_Label.show();

    m_Alignment.set_padding(Utils::DEFAULT_SPACING_SMALL /* top */, 0, Utils::DEFAULT_SPACING_LARGE /* left */, 0);
  }
  else
  {
    m_Label.set_markup(Glib::ustring());
    m_Label.hide();

    m_Alignment.set_padding(0, 0, 0, 0); //The box itself has padding of 6.
  }

113 114 115 116
  if(m_portal)
    m_key_field = get_fields_for_table_one_field(LayoutWidgetBase::m_table_name, m_portal->get_to_field_used());
  else
    m_key_field.clear();
117 118 119 120 121

  enable_buttons();

  FoundSet found_set;
  found_set.m_table_name = LayoutWidgetBase::m_table_name;
122
  return Box_Data::init_db_details(found_set, "" /* layout_platform */); //Calls create_layout() and fill_from_database().
123 124
}

125
bool Box_Data_Calendar_Related::fill_from_database()
126
{
127 128
  if(!m_portal)
    return false;
129

130 131 132 133 134 135
  bool result = false;

  if(m_key_field && m_found_set.m_where_clause.empty()) //There's a key field, but no value.
  {
    //No Foreign Key value, so just show the field names:

136
    result = Base_DB_Table_Data::fill_from_database();
137 138 139 140 141

    //create_layout();
  }
  else
  {
142 143
    if(m_query_column_date_field == -1)
      return false; //This is useless without the date in the result.
144

145 146 147 148 149 150
    //Create a date range from the beginning to end of the selected month:
    Glib::Date calendar_date;
    m_calendar.get_date(calendar_date);
    const Glib::Date date_start(1, calendar_date.get_month(), calendar_date.get_year());
    Glib::Date date_end = date_start;
    date_end.add_months(1);
151

152 153
    Gnome::Gda::Value date_start_value(date_start);
    Gnome::Gda::Value date_end_value(date_end);
154

155 156 157
    //Add a WHERE clause for this date range:
    sharedptr<Relationship> relationship = m_portal->get_relationship();
    Glib::ustring where_clause_to_table_name = relationship->get_to_table();
158

159 160
    sharedptr<LayoutItem_CalendarPortal> derived_portal = sharedptr<LayoutItem_CalendarPortal>::cast_dynamic(m_portal);
    const Glib::ustring date_field_name = derived_portal->get_date_field()->get_name();
161

162 163
    sharedptr<const Relationship> relationship_related = m_portal->get_related_relationship();
    if(relationship_related)
164
    {
165 166 167 168
      //Adjust the WHERE clause appropriately for the extra JOIN:
      sharedptr<UsesRelationship> uses_rel_temp = sharedptr<UsesRelationship>::create();
      uses_rel_temp->set_relationship(relationship);
      where_clause_to_table_name = uses_rel_temp->get_sql_join_alias_name();
169 170
    }

171 172
    //Add an AND to the existing where clause, to get only records within these dates, if any:
    sharedptr<const Field> date_field = derived_portal->get_date_field();
173
    //TODO: Use a SQL parameter instead of using sql().
174 175 176 177 178 179 180 181 182 183 184

    Glib::RefPtr<Gnome::Gda::SqlBuilder> builder =
      Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_SELECT);
    const guint cond = builder->add_cond(Gnome::Gda::SQL_OPERATOR_TYPE_BETWEEN,
       builder->add_id(date_field->get_name()),
       builder->add_expr_as_value(date_start_value),
       builder->add_expr_as_value(date_end_value));
    builder->set_where(cond); //Might be unnecessary.
    const Gnome::Gda::SqlExpr extra_where_clause = builder->export_expression(cond);

    Gnome::Gda::SqlExpr where_clause;
185
    if(m_found_set.m_where_clause.empty())
186
    {
187
      where_clause = extra_where_clause;
188
    }
189
    else
190 191 192 193 194 195
    {
      where_clause = Utils::build_combined_where_expression(
        m_found_set.m_where_clause, extra_where_clause,
        Gnome::Gda::SQL_OPERATOR_TYPE_AND);
    }

196 197
    //Do one SQL query for the whole month and store the cached values here:
    clear_cached_database_values();
198 199

    Glib::RefPtr<Gnome::Gda::SqlBuilder> sql_query = Utils::build_sql_select_with_where_clause(m_found_set.m_table_name, m_FieldsShown, where_clause, m_found_set.m_extra_join, m_found_set.m_sort_clause, m_found_set.m_extra_group_by);
200
    //std::cout << "DEBUG: sql_query=" << sql_query << std::endl;
201
    Glib::RefPtr<const Gnome::Gda::DataModel> datamodel = query_execute_select(sql_query);
202 203
    if(!(datamodel))
      return true;
204

205 206 207
    const int rows_count = datamodel->get_n_rows();
    if(!(rows_count > 0))
      return true;
208

209 210 211 212 213 214
    //Get the data:
    for(int row_index = 0; row_index < rows_count; ++row_index)
    {
      const int columns_count = datamodel->get_n_columns();
      if(m_query_column_date_field > columns_count)
       continue;
215

216
      //Get the date value for this row:
217
#ifdef GLIBMM_EXCEPTIONS_ENABLED
218 219
      Gnome::Gda::Value value_date = datamodel->get_value_at(m_query_column_date_field, row_index);
#else
220
      std::auto_ptr<Glib::Error> error;
221
      Gnome::Gda::Value value_date = datamodel->get_value_at(m_query_column_date_field, row_index, error);
222
#endif
223
      const Glib::Date date = value_date.get_date();
224

225 226 227 228
      //Get all the values for this row:
      type_vector_values* pVector = new type_vector_values(m_FieldsShown.size());
      for(int column_index = 0; column_index < columns_count; ++column_index)
      {
229
#ifdef GLIBMM_EXCEPTIONS_ENABLED
230
        (*pVector)[column_index] = datamodel->get_value_at(column_index, row_index);
231
#else
232
        std::auto_ptr<Glib::Error> error;
233 234 235
          (*pVector)[column_index] = datamodel->get_value_at(column_index, row_index, error);
        if (error.get())
          break;
236
#endif
237
      }
238

239 240
      m_map_values[date].push_back(pVector);
    }
241 242
  }

243

244 245 246
  return result;
}

247 248 249 250 251 252 253 254 255 256 257 258
void Box_Data_Calendar_Related::clear_cached_database_values()
{
  for(type_map_values::iterator iter = m_map_values.begin(); iter != m_map_values.end(); ++iter)
  {
    type_list_vectors vec = iter->second;
    for(type_list_vectors::iterator iter = vec.begin(); iter != vec.end(); ++iter)
    {
      type_vector_values* pValues = *iter;
      if(pValues)
        delete pValues;
    }
  }
259 260

  m_map_values.clear();
261
}
262 263

//TODO: Make this generic in Box_Data_Portal:
264
void Box_Data_Calendar_Related::on_record_added(const Gnome::Gda::Value& primary_key_value, const Gtk::TreeModel::iterator& row)
265 266 267 268 269 270 271 272 273 274 275 276 277 278
{
  //primary_key_value is a new autogenerated or human-entered key for the row.
  //It has already been added to the database.

  if(!row)
    return;

  Gnome::Gda::Value key_value;

  if(m_key_field)
  {
    //m_key_field is the field in this table that must match another field in the parent table.
    sharedptr<LayoutItem_Field> layout_item = sharedptr<LayoutItem_Field>::create();
    layout_item->set_full_field_details(m_key_field);
279
    //TODO: key_value = m_calendar.get_value(row, layout_item);
280 281 282 283 284 285 286 287 288 289 290 291
  }

  //Make sure that the new related record is related,
  //by setting the foreign key:
  //If it's not auto-generated.
  if(!Conversions::value_is_empty(key_value)) //If there is already a value.
  {
    //It was auto-generated. Tell the parent about it, so it can make a link.
    signal_record_added.emit(key_value);
  }
  else if(Conversions::value_is_empty(m_key_value))
  {
292
    g_warning("Box_Data_Calendar_Related::on_record_added(): m_key_value is NULL.");
293 294 295
  }
  else
  {
296
    sharedptr<Field> field_primary_key; //TODO: = m_calendar.get_key_field();
297 298

    //Create the link by setting the foreign key
299
    if(m_key_field && m_portal)
300
    {
Murray Cumming's avatar
Murray Cumming committed
301 302 303 304 305 306 307
      Glib::RefPtr<Gnome::Gda::SqlBuilder> builder = Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_UPDATE);
      builder->set_table(m_portal->get_table_used(Glib::ustring() /* not relevant */));
      builder->add_field_value_as_value(m_key_field->get_name(), m_key_value);
      builder->set_where(
        builder->add_cond(Gnome::Gda::SQL_OPERATOR_TYPE_EQ,
          builder->add_id(field_primary_key->get_name()),
          builder->add_expr_as_value(primary_key_value)));
308

Murray Cumming's avatar
Murray Cumming committed
309
      const bool test = query_execute(builder);
310 311 312 313 314 315
      if(test)
      {
        //Show it on the view, if it's visible:
        sharedptr<LayoutItem_Field> layout_item = sharedptr<LayoutItem_Field>::create();
        layout_item->set_full_field_details(field_primary_key);

316
        //TODO: m_calendar.set_value(row, layout_item, m_key_value);
317 318 319 320 321 322 323
      }
    }

    //on_adddel_user_changed(row, iKey); //Update the database.
  }
}

324
Box_Data_Calendar_Related::type_vecLayoutFields Box_Data_Calendar_Related::get_fields_to_show() const
325
{
326
  type_vecLayoutFields layout_fields = Box_Data_Portal::get_fields_to_show();
327

328 329 330
  sharedptr<LayoutItem_CalendarPortal> derived_portal = sharedptr<LayoutItem_CalendarPortal>::cast_dynamic(m_portal);
  if(!derived_portal)
    return layout_fields;
331

332 333 334
  sharedptr<const Field> date_field = derived_portal->get_date_field();
  if(!date_field)
    return layout_fields;
335

336 337 338 339 340 341
  //Add it to the list to ensure that we request the date (though it will not really be shown in the calendar):
  sharedptr<LayoutItem_Field> layout_item_date_field = sharedptr<LayoutItem_Field>::create();
  layout_item_date_field->set_full_field_details(date_field);
  layout_fields.push_back(layout_item_date_field);
  m_query_column_date_field = layout_fields.size() - 1;
  return layout_fields;
342 343 344
}

#ifndef GLOM_ENABLE_CLIENT_ONLY
345
void Box_Data_Calendar_Related::on_dialog_layout_hide()
346
{
347
  Dialog_Layout_Calendar_Related* dialog_related = dynamic_cast<Dialog_Layout_Calendar_Related*>(m_pDialogLayout);
348
  g_assert(dialog_related);
349
  m_portal = dialog_related->get_portal_layout();
350 351 352


  //Update the UI:
353
  sharedptr<LayoutItem_CalendarPortal> derived_portal = sharedptr<LayoutItem_CalendarPortal>::cast_dynamic(m_portal);
354
  init_db_details(derived_portal);
355 356 357

  Box_Data::on_dialog_layout_hide();

358
  sharedptr<LayoutItem_CalendarPortal> pLayoutItem = sharedptr<LayoutItem_CalendarPortal>::cast_dynamic(get_layout_item());
359 360
  if(pLayoutItem)
  {
361 362 363
    sharedptr<LayoutItem_CalendarPortal> derived_portal = sharedptr<LayoutItem_CalendarPortal>::cast_dynamic(m_portal);
    if(derived_portal)
      *pLayoutItem = *derived_portal;
364

365 366 367 368 369
    signal_layout_changed().emit(); //TODO: Check whether it has really changed.
  }
}
#endif // !GLOM_ENABLE_CLIENT_ONLY

370
#ifndef GLOM_ENABLE_CLIENT_ONLY
371
Dialog_Layout* Box_Data_Calendar_Related::create_layout_dialog() const
372
{
373 374 375
  Dialog_Layout_Calendar_Related* dialog = 0;
  Glom::Utils::get_glade_widget_derived_with_warning(dialog);
  return dialog;
376 377 378 379 380
}

void Box_Data_Calendar_Related::prepare_layout_dialog(Dialog_Layout* dialog)
{
  Dialog_Layout_Calendar_Related* related_dialog = dynamic_cast<Dialog_Layout_Calendar_Related*>(dialog);
381
  g_assert(related_dialog);
382

383
  sharedptr<LayoutItem_CalendarPortal> derived_portal = sharedptr<LayoutItem_CalendarPortal>::cast_dynamic(m_portal);
384 385
  if(derived_portal && derived_portal->get_has_relationship_name())
  {
386
    related_dialog->set_document(m_layout_name, m_layout_platform, get_document(), derived_portal);
387 388 389
  }
  else
  {
390
    related_dialog->set_document(m_layout_name, m_layout_platform, get_document(), m_parent_table);
391
  }
392
}
393
#endif // !GLOM_ENABLE_CLIENT_ONLY
394

395 396 397 398 399 400
void Box_Data_Calendar_Related::on_calendar_month_changed()
{
  //Update the cached values for the new month:
  fill_from_database();
}

401 402 403
Glib::ustring Box_Data_Calendar_Related::on_calendar_details(guint year, guint month, guint day)
{
  sharedptr<LayoutItem_CalendarPortal> derived_portal = sharedptr<LayoutItem_CalendarPortal>::cast_dynamic(m_portal);
404
  if(!derived_portal)
405
  {
406
    //std::cout << "DEBUG: Box_Data_Calendar_Related::on_calendar_details(): date_field is NULL" << std::endl;
407 408
    return Glib::ustring();
  }
409

410 411 412
  sharedptr<const Field> date_field = derived_portal->get_date_field();
  if(!date_field)
    return Glib::ustring();
413

414 415 416 417 418 419 420 421
  //TODO: month seems to be 143710360 sometimes, which seems to be a GtkCalendar bug:
  //std::cout << "Box_Data_Calendar_Related::on_calendar_details(): year=" << year << ", month=" << month << " day=" << day << std::endl;

  //Glib::Date is 1-indexed:
  Glib::Date::Month datemonth = (Glib::Date::Month)(month +1);
  if(datemonth > Glib::Date::DECEMBER)
    datemonth = Glib::Date::JANUARY;
  Glib::Date date(day, datemonth, year);
422

423 424 425 426
  //Examine the cached data:
  type_map_values::const_iterator iter_find = m_map_values.find(date);
  if(iter_find == m_map_values.end())
    return Glib::ustring(); //No data was found for this date.
427 428


429
  Glib::ustring result;
430

431 432 433
  //Look at each row for this date:
  const type_list_vectors& rows = iter_find->second;
  for(type_list_vectors::const_iterator iter = rows.begin(); iter != rows.end(); ++iter)
434
  {
435 436 437
    type_vector_values* pRow = *iter;
    if(!pRow)
      continue;
438

439 440 441
    //Get the data for each column in the row:
    Glib::ustring row_text;
    int column_index = 0;
442

443 444 445 446 447
    //We iterate over the original list of items from the portal,
    //instead of the ones used by the query (m_FieldsShown),
    //because we really don't want to show the extra fields (at the end) to the user:
    LayoutGroup::type_list_items items = m_portal->get_items();
    for(LayoutGroup::type_list_items::const_iterator iter = items.begin(); iter != items.end(); ++iter)
448
    {
449 450 451
      sharedptr<const LayoutItem> layout_item = *iter;
      if(!layout_item)
        continue;
452

453
      Glib::ustring text;
454

455 456 457 458 459
      //Text for a text item:
      sharedptr<const LayoutItem_Text> layout_item_text = sharedptr<const LayoutItem_Text>::cast_dynamic(layout_item);
      if(layout_item_text)
        text = layout_item_text->get_text();
      else
460
      {
461 462
        //Text for a field:
        sharedptr<const LayoutItem_Field> layout_item_field = sharedptr<const LayoutItem_Field>::cast_dynamic(layout_item);
463

464
        const Gnome::Gda::Value value = (*pRow)[column_index];
465
        text = Conversions::get_text_for_gda_value(layout_item_field->get_glom_type(), value, layout_item_field->get_formatting_used().m_numeric_format);
466

467 468
        ++column_index;
      }
469

470 471 472 473 474
      //Add the field text to the row:
      if(!text.empty())
      {
        if(!row_text.empty())
          row_text += ", "; //TODO: Internationalization?
475

476 477
        row_text += text;
      }
478
    }
479

480 481
    //Add the row text to the result:
    if(!row_text.empty())
482 483
    {
      if(!result.empty())
484
        result += '\n';
485

486
      result += row_text;
487 488
    }
  }
489

490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511
  return result;
}

void Box_Data_Calendar_Related::setup_menu()
{
  m_refActionGroup = Gtk::ActionGroup::create();

  m_refActionGroup->add(Gtk::Action::create("ContextMenu", "Context Menu") );

  m_refContextEdit =  Gtk::Action::create("ContextEdit", Gtk::Stock::EDIT);

  m_refActionGroup->add(m_refContextEdit,
    sigc::mem_fun(*this, &Box_Data_Calendar_Related::on_MenuPopup_activate_Edit) );

#ifndef GLOM_ENABLE_CLIENT_ONLY
  // Don't add ContextLayout in client only mode because it would never
  // be sensitive anyway
  m_refContextLayout =  Gtk::Action::create("ContextLayout", _("Layout"));
  m_refActionGroup->add(m_refContextLayout,
    sigc::mem_fun(*this, &Box_Data_Calendar_Related::on_MenuPopup_activate_layout) );

  //TODO: This does not work until this widget is in a container in the window:
512
  Application* pApp = get_application();
513 514 515
  if(pApp)
  {
    pApp->add_developer_action(m_refContextLayout); //So that it can be disabled when not in developer mode.
516
    pApp->update_userlevel_ui(); //Update our action's sensitivity.
517 518 519 520 521 522 523 524 525 526 527 528 529
  }
#endif // !GLOM_ENABLE_CLIENT_ONLY

  m_refUIManager = Gtk::UIManager::create();

  m_refUIManager->insert_action_group(m_refActionGroup);

  //TODO: add_accel_group(m_refUIManager->get_accel_group());

#ifdef GLIBMM_EXCEPTIONS_ENABLED
  try
  {
#endif
530
    Glib::ustring ui_info =
531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
        "<ui>"
        "  <popup name='ContextMenu'>"
        "    <menuitem action='ContextEdit'/>"
#ifndef GLOM_ENABLE_CLIENT_ONLY
        "    <menuitem action='ContextLayout'/>"
#endif
        "  </popup>"
        "</ui>";

#ifdef GLIBMM_EXCEPTIONS_ENABLED
    m_refUIManager->add_ui_from_string(ui_info);
  }
  catch(const Glib::Error& ex)
  {
    std::cerr << "building menus failed: " <<  ex.what();
  }
#else
  std::auto_ptr<Glib::Error> error;
  m_refUIManager->add_ui_from_string(ui_info, error);
550
  if(error.get())
551 552 553 554 555 556
  {
    std::cerr << "building menus failed: " << error->what();
  }
#endif //GLIBMM_EXCEPTIONS_ENABLED

  //Get the menu:
557
  m_pMenuPopup = dynamic_cast<Gtk::Menu*>( m_refUIManager->get_widget("/ContextMenu") );
558 559 560
  if(!m_pMenuPopup)
    g_warning("menu not found");

561

562 563 564
#ifndef GLOM_ENABLE_CLIENT_ONLY
  if(pApp)
    m_refContextLayout->set_sensitive(pApp->get_userlevel() == AppState::USERLEVEL_DEVELOPER);
565 566 567
#endif // !GLOM_ENABLE_CLIENT_ONLY
}

568
void Box_Data_Calendar_Related::on_calendar_button_press_event(GdkEventButton *event)
569
{
570 571 572
#ifndef GLOM_ENABLE_CLIENT_ONLY
  //Enable/Disable items.
  //We did this earlier, but get_application is more likely to work now:
573
  Application* pApp = get_application();
574 575 576
  if(pApp)
  {
    pApp->add_developer_action(m_refContextLayout); //So that it can be disabled when not in developer mode.
577
    pApp->update_userlevel_ui(); //Update our action's sensitivity.
578 579 580 581
  }
#endif

  GdkModifierType mods;
582
  gdk_window_get_pointer( gtk_widget_get_window(Gtk::Widget::gobj()), 0, 0, &mods );
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602
  if(mods & GDK_BUTTON3_MASK)
  {
    //Give user choices of actions on this item:
    m_pMenuPopup->popup(event->button, event->time);
    return; //handled.
  }
  else
  {
    if(event->type == GDK_2BUTTON_PRESS)
    {
      //Double-click means edit.
      //Don't do this usually, because users sometimes double-click by accident when they just want to edit a cell.

      //TODO: If the cell is not editable, handle the double-click as an edit/selection.
      //on_MenuPopup_activate_Edit();
      return; //Not handled.
    }
  }

  return; //Not handled. TODO: Call base class?
603 604
}

605 606 607 608 609 610 611 612 613 614 615 616 617 618 619
void
Box_Data_Calendar_Related::on_MenuPopup_activate_Edit()
{
  const Gnome::Gda::Value primary_key_value; //TODO: = m_AddDel.get_value_key(row); //The primary key is in the key.

  signal_user_requested_details().emit(primary_key_value);
}

#ifndef GLOM_ENABLE_CLIENT_ONLY
void Box_Data_Calendar_Related::on_MenuPopup_activate_layout()
{
  show_layout_dialog();
}
#endif // !GLOM_ENABLE_CLIENT_ONLY

620
Gnome::Gda::Value Box_Data_Calendar_Related::get_primary_key_value(const Gtk::TreeModel::iterator& /* row */) const
621 622 623 624 625 626 627 628 629 630 631 632 633
{
  return Gnome::Gda::Value(); //TODO: m_AddDel.get_value_key(row);
}

Gnome::Gda::Value Box_Data_Calendar_Related::get_primary_key_value_selected() const
{
  return Gnome::Gda::Value(); //TODO: m_AddDel.get_value_key_selected();
}

void Box_Data_Calendar_Related::set_primary_key_value(const Gtk::TreeModel::iterator& /* row */, const Gnome::Gda::Value& /* value */)
{
  //TODO
}
634

635
} //namespace Glom