static void raise_bus_cell_position (GtkWidget *widget, gpointer data)
  {
  bus_layout_D *dialog = (bus_layout_D *)data ;
  GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->tview)) ;
  GtkTreeModel *tm = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->tview)) ;
  GtkTreePath *tpBus = g_object_get_data (G_OBJECT (dialog->tview), "tpBus") ;
  GtkTreePath *tpSrc = NULL, *tpDst = NULL ;
  int icChildren = -1, Nix ;

  if (NULL == tpBus) return ;
  if (0 == (icChildren = gtk_tree_model_path_n_children (tm, tpBus))) return ;

  gtk_tree_path_down (tpDst = gtk_tree_path_copy (tpBus)) ;
  gtk_tree_path_next (tpSrc = gtk_tree_path_copy (tpDst)) ;

  for (Nix = 1 ; Nix < icChildren ; Nix++)
    {
    if (gtk_tree_selection_path_is_selected (sel, tpSrc))
      {
      // swap the 2 rows
      swap_model_paths_contents (tm, tpSrc, tpDst) ;
      gtk_tree_selection_unselect_path (sel, tpSrc) ;
      gtk_tree_selection_select_path (sel, tpDst) ;
      }
    gtk_tree_path_next (tpSrc) ;
    gtk_tree_path_next (tpDst) ;
    }
  }
// This callback is responsible for enabling/disabling the appropriate buttons depending on
// the contents of the selection
static void tree_view_selection_changed (GtkTreeSelection *sel, gpointer data)
  {
  bus_layout_D *dialog = (bus_layout_D *)data ;
  gboolean bSomethingSelected = FALSE ;
  gboolean bBusSelected = FALSE ;
  gboolean bSelectionIsFromBus = FALSE ;
  gboolean bFirstSelected = FALSE ;
  gboolean bLastSelected = FALSE ;
  gboolean bFirstBusSelected = TRUE ;
  gboolean bLastBusSelected = TRUE ;
  GtkTreePath *tpSelBus = NULL, *tp = NULL ;
  GtkTreeModel *tm = NULL ;
  int icChildren = -1, Nix ;

  tm = gtk_tree_view_get_model (gtk_tree_selection_get_tree_view (sel)) ;

  if ((bSelectionIsFromBus = (NULL != (tpSelBus = get_selection_bus (sel, &bSomethingSelected)))))
    if (!(bFirstSelected = bLastSelected = bBusSelected = whole_bus_selected_p (sel, tm, tpSelBus)))
      if ((icChildren = gtk_tree_model_path_n_children (tm, tpSelBus)) > 0)
        {
        gtk_tree_path_down (tp = gtk_tree_path_copy (tpSelBus)) ;
        bFirstSelected = gtk_tree_selection_path_is_selected (sel, tp) ;
        for (Nix = 1 ; Nix < icChildren ; Nix++) gtk_tree_path_next (tp) ;
        bLastSelected = gtk_tree_selection_path_is_selected (sel, tp) ;
        gtk_tree_path_free (tp) ;
        }

  if (bSelectionIsFromBus)
    determine_first_or_last_bus (tm, tpSelBus, &bFirstBusSelected, &bLastBusSelected) ;

  gtk_widget_set_sensitive (dialog->btnCreateBus, bSomethingSelected && !bBusSelected) ;
  gtk_widget_set_sensitive (dialog->btnDeleteBus, bSelectionIsFromBus) ;
  gtk_widget_set_sensitive (dialog->btnMoveBusUp, bSelectionIsFromBus && !bFirstBusSelected) ;
  gtk_widget_set_sensitive (dialog->btnMoveBusDown, bSelectionIsFromBus && !bLastBusSelected) ;
  gtk_widget_set_sensitive (dialog->btnMoveCellsUp, bSelectionIsFromBus && !bFirstSelected) ;
  gtk_widget_set_sensitive (dialog->btnMoveCellsDown, bSelectionIsFromBus && !bLastSelected) ;
  gtk_widget_set_sensitive (dialog->lblBusName, bSelectionIsFromBus) ;
  gtk_widget_set_sensitive (dialog->txtBusName, bSelectionIsFromBus) ;

  // Fill in the text box with the name of the bus
  if (bSelectionIsFromBus)
    {
    GtkTreeIter itr ;
    char *psz = NULL ;

    gtk_tree_model_get_iter (tm, &itr, tpSelBus) ;

    gtk_tree_model_get (tm, &itr, BUS_LAYOUT_MODEL_COLUMN_NAME, &psz, -1) ;

    g_signal_handlers_block_matched (G_OBJECT (dialog->txtBusName), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer)bus_name_changed, NULL) ;
    gtk_entry_set_text (GTK_ENTRY (dialog->txtBusName), psz) ;
    g_signal_handlers_unblock_matched (G_OBJECT (dialog->txtBusName), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer)bus_name_changed, NULL) ;

    g_free (psz) ;
    }

  if (NULL != (tp = g_object_get_data (G_OBJECT (gtk_tree_selection_get_tree_view (sel)), "tpBus")))
    gtk_tree_path_free (tp) ;
  g_object_set_data (G_OBJECT (gtk_tree_selection_get_tree_view (sel)), "tpBus", tpSelBus) ;
  }
static GList *get_bus_refs (GtkTreeModel *tm, GtkTreePath *tpBus)
  {
  int Nix, icChildren = -1 ;
  GList *llRefs = NULL ;
  GtkTreePath *tp = gtk_tree_path_copy (tpBus) ;

  icChildren = gtk_tree_model_path_n_children (tm, tp) ;
  gtk_tree_path_down (tp) ;

  for (Nix = 0 ; Nix < icChildren ; Nix++, gtk_tree_path_next (tp))
    llRefs = g_list_prepend (llRefs, gtk_tree_row_reference_new (tm, tp)) ;

  gtk_tree_path_free (tp) ;

  return llRefs ;
  }
static void delete_bus_button_clicked (GtkWidget *widget, gpointer data)
  {
  int icChildren = -1 ;
  bus_layout_D *dialog = (bus_layout_D *)data ;
  GtkTreeModel *tm = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->tview)) ;
  GtkTreePath *tpBus = g_object_get_data (G_OBJECT (dialog->tview), "tpBus") ;
  GtkTreeRowReference *trrBus = NULL ;
  GtkTreeIter itr, itrSrc ;
  GList *llBusRefs = NULL, *llItr = NULL ;
  GtkTreePath *tp = NULL ;

  if (NULL == tpBus) return ;

  icChildren = gtk_tree_model_path_n_children (tm, tpBus) ;

  // There should always be some children
  if (0 == icChildren) return ;

  trrBus = gtk_tree_row_reference_new (tm, tpBus) ;

  llBusRefs = get_bus_refs (tm, tpBus) ;

  for (llItr = llBusRefs ; llItr != NULL ; llItr = llItr->next)
    {
    gtk_tree_store_append (GTK_TREE_STORE (tm), &itr, NULL) ;

    gtk_tree_model_get_iter (tm, &itrSrc, tp = gtk_tree_row_reference_get_path (llItr->data)) ;
    gtk_tree_path_free (tp) ;

    swap_model_iters_contents (tm, &itrSrc, &itr) ;

    gtk_tree_row_reference_free (llItr->data) ;
    }

  g_list_free (llBusRefs) ;

  gtk_tree_model_get_iter (tm, &itrSrc, tp = gtk_tree_row_reference_get_path (trrBus)) ;
  gtk_tree_path_free (tp) ;

  gtk_tree_store_remove (GTK_TREE_STORE (tm), &itrSrc) ;

  gtk_tree_row_reference_free (trrBus) ;
  }
static void lower_bus_cell_position (GtkWidget *widget, gpointer data)
  {
  bus_layout_D *dialog = (bus_layout_D *)data ;
  GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->tview)) ;
  GtkTreeModel *tm = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->tview)) ;
  GtkTreePath *tpBus = g_object_get_data (G_OBJECT (dialog->tview), "tpBus") ;
  GtkTreePath *tpSrc = NULL, *tpDst = NULL ;
  int icChildren = -1, Nix ;

  if (NULL == tpBus)
		{
		fprintf (stderr, "lower_bus_cell_position: tpBus == NULL !\n") ;
		return ;
		}
  if (0 == (icChildren = gtk_tree_model_path_n_children (tm, tpBus)))
		{
		fprintf (stderr, "lower_bus_cell_position: tpBus has no children O_o\n") ;
		return ;
		}

  gtk_tree_path_down (tpDst = gtk_tree_path_copy (tpBus)) ;
  for (Nix = 1 ; Nix < icChildren ; Nix++) gtk_tree_path_next (tpDst) ;
    // St00pid short-circuit if statement to suppress a warning.
    if (gtk_tree_path_prev (tpSrc = gtk_tree_path_copy (tpDst))) ;

  for (Nix = 1 ; Nix < icChildren ; Nix++)
    {
    if (gtk_tree_selection_path_is_selected (sel, tpSrc))
      {
      // swap the 2 rows
      swap_model_paths_contents (tm, tpSrc, tpDst) ;
      gtk_tree_selection_unselect_path (sel, tpSrc) ;
      gtk_tree_selection_select_path (sel, tpDst) ;
      }
    if (!gtk_tree_path_prev (tpSrc)) break ;
    if (!gtk_tree_path_prev (tpDst)) break ;
    }
  }
static gboolean whole_bus_selected_p (GtkTreeSelection *sel, GtkTreeModel *tm, GtkTreePath *tpSelBus)
  {
  int Nix ;
  int icChildren = -1 ;
  GtkTreePath *tp = NULL ;

  icChildren = gtk_tree_model_path_n_children (tm, tpSelBus) ;

  if (icChildren > 0)
    {
    gtk_tree_path_down (tp = gtk_tree_path_copy (tpSelBus)) ;

    for (Nix = 0 ; Nix < icChildren ; Nix++, gtk_tree_path_next (tp))
      if (!gtk_tree_selection_path_is_selected (sel, tp))
        break ;

    gtk_tree_path_free (tp) ;

    return (Nix == icChildren) ;
    }
  fprintf (stderr, "What ?! The bus had 0 children ?!\n") ;
  return TRUE ;
  }
// Create a new bus from the current selection
static void create_bus_button_clicked (GtkWidget *widget, gpointer data)
  {
  int row_type = -1 ;
  bus_layout_D *dialog = (bus_layout_D *)data ;
  GList *llTreeRefs = NULL, *llItr = NULL ;
  GtkTreeStore *ts = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->tview))) ;
  GtkTreeIter itrBus, itr, itrSrc, itrSrcParent ;
  GtkTreeRowReference *refBus = NULL, *refSrcParent = NULL ;
  GtkTreePath *tp = NULL, *tpSrcParent = NULL ;

  llTreeRefs = get_selected_refs (gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->tview))) ;

  if (NULL == llTreeRefs) return ;

  if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (ts), &itr,
    tp = gtk_tree_row_reference_get_path (llTreeRefs->data)))
    {
    gtk_tree_path_free (tp) ;
    return ;
    }

  gtk_tree_model_get (GTK_TREE_MODEL (ts), &itr, BUS_LAYOUT_MODEL_COLUMN_TYPE, &row_type, -1) ;

  gtk_tree_path_free (tp) ;

  gtk_tree_store_prepend (ts, &itrBus, NULL) ;
  gtk_tree_store_set (ts, &itrBus,
    BUS_LAYOUT_MODEL_COLUMN_ICON, (row_type & ROW_TYPE_INPUT) ? QCAD_STOCK_BUS_INPUT : QCAD_STOCK_BUS_OUTPUT,
    BUS_LAYOUT_MODEL_COLUMN_NAME, _("Untitled Bus"),
    BUS_LAYOUT_MODEL_COLUMN_TYPE, (row_type & ROW_TYPE_INPUT) ? ROW_TYPE_BUS_INPUT : ROW_TYPE_BUS_OUTPUT,
    BUS_LAYOUT_MODEL_COLUMN_INDEX, -1, -1) ;

  refBus = gtk_tree_row_reference_new (GTK_TREE_MODEL (ts), tp = gtk_tree_model_get_path (GTK_TREE_MODEL (ts), &itrBus)) ;
  gtk_tree_path_free (tp) ;

  for (llItr = g_list_last (llTreeRefs) ; llItr != NULL ; llItr = llItr->prev)
    {
    if (gtk_tree_model_get_iter (GTK_TREE_MODEL (ts), &itrBus, tp = gtk_tree_row_reference_get_path (refBus)))
      {
      gtk_tree_path_free (tp) ;

      gtk_tree_store_append (ts, &itr, &itrBus) ;

      if (gtk_tree_model_get_iter (GTK_TREE_MODEL (ts), &itrSrc, tp = gtk_tree_row_reference_get_path (llItr->data)))
        swap_model_iters_contents (GTK_TREE_MODEL (ts), &itrSrc, &itr) ;
      gtk_tree_path_free (tp) ;

      if (gtk_tree_model_get_iter (GTK_TREE_MODEL (ts), &itrSrc, tp = gtk_tree_row_reference_get_path (llItr->data)))
        {
        if (gtk_tree_path_get_depth (tp) > 1)
          {
          if (gtk_tree_path_up (tpSrcParent = gtk_tree_path_copy (tp)))
            refSrcParent = (1 == gtk_tree_model_path_n_children (GTK_TREE_MODEL (ts), tpSrcParent)) ?
              gtk_tree_row_reference_new (GTK_TREE_MODEL (ts), tpSrcParent) : NULL ;

          gtk_tree_path_free (tpSrcParent) ;
          }
        }
      gtk_tree_path_free (tp) ;

      gtk_tree_row_reference_free (llItr->data) ;

      // Remove cell from old location
      gtk_tree_store_remove (ts, &itrSrc) ;

      // The bus that owned the row we just moved has become empty - delete it
      if (NULL != refSrcParent)
        {
        tpSrcParent = gtk_tree_row_reference_get_path (refSrcParent) ;

        if (gtk_tree_model_get_iter (GTK_TREE_MODEL (ts), &itrSrcParent, tpSrcParent))
          gtk_tree_store_remove (ts, &itrSrcParent) ;

        gtk_tree_path_free (tpSrcParent) ;
        gtk_tree_row_reference_free (refSrcParent) ;
        refSrcParent = NULL ;
        }
      }
    else
      gtk_tree_path_free (tp) ;
    }

  gtk_tree_selection_select_path (gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->tview)), tp = gtk_tree_row_reference_get_path (refBus)) ;

  gtk_tree_path_free (tp) ;
  gtk_tree_row_reference_free (refBus) ;
  g_list_free (llTreeRefs) ;
  }