libgeda

s_page.c

Go to the documentation of this file.
00001 /* gEDA - GPL Electronic Design Automation
00002  * libgeda - gEDA's library
00003  * Copyright (C) 1998-2010 Ales Hvezda
00004  * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details)
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00019  */
00020 
00036 #include <config.h>
00037 
00038 #include <stdio.h>
00039 #ifdef HAVE_STDLIB_H
00040 #include <stdlib.h>
00041 #endif
00042 #ifdef HAVE_UNISTD_H
00043 #include <unistd.h>
00044 #endif
00045 #ifdef HAVE_STRING_H
00046 #include <string.h>
00047 #endif
00048 
00049 #include <sys/types.h>
00050 #include <sys/stat.h>
00051 #include <unistd.h>
00052 
00053 #include "libgeda_priv.h"
00054 
00055 #ifdef HAVE_LIBDMALLOC
00056 #include <dmalloc.h>
00057 #endif
00058 
00059 static gint global_pid = 0;
00060 
00061 /* Called just before removing an OBJECT from a PAGE. */
00062 static void
00063 object_added (TOPLEVEL *toplevel, PAGE *page, OBJECT *object)
00064 {
00065   /* Set up object parent pointer */
00066 #ifndef NDEBUG
00067   if (object->page != NULL) {
00068     g_critical ("Object %p already has parent page %p!", object, object->page);
00069   }
00070 #endif
00071   object->page = page;
00072 
00073   /* Add object to tile system. */
00074   s_tile_add_object (toplevel, object);
00075 
00076   /* Update object connection tracking */
00077   s_conn_update_object (toplevel, object);
00078 
00079   o_emit_change_notify (toplevel, object);
00080 }
00081 
00082 /* Called just before removing an OBJECT from a PAGE. */
00083 static void
00084 pre_object_removed (TOPLEVEL *toplevel, PAGE *page, OBJECT *object)
00085 {
00086   o_emit_pre_change_notify (toplevel, object);
00087 
00088   /* Clear object parent pointer */
00089 #ifndef NDEBUG
00090   if (object->page == NULL) {
00091     g_critical ("Object %p has NULL parent page!", object);
00092   }
00093 #endif
00094   object->page = NULL;
00095 
00096   /* Clear page's object_lastplace pointer if set */
00097   if (page->object_lastplace == object) {
00098     page->object_lastplace = NULL;
00099   }
00100 
00101   /* Remove object from connection system */
00102   s_conn_remove_object (toplevel, object);
00103 
00104   /* Remove object from tile system */
00105   s_tile_remove_object (object);
00106 }
00107 
00116 PAGE *s_page_new (TOPLEVEL *toplevel, const gchar *filename)
00117 {
00118   PAGE *page;
00119 
00120   /* Now create a blank page */
00121   page = (PAGE*)g_new0 (PAGE, 1);
00122 
00123   page->pid = global_pid++;
00124 
00125   page->CHANGED = 0;
00126 
00127   /* big assumption here that page_filename isn't null */
00128   if (g_path_is_absolute (filename)) {
00129     page->page_filename = g_strdup (filename);
00130   } else {
00131     gchar *pwd = g_get_current_dir ();
00132     page->page_filename = g_build_filename (pwd, filename, NULL);
00133     g_free (pwd);
00134   }
00135     
00136   g_assert (toplevel->init_bottom != 0);
00137   page->coord_aspectratio = (
00138     ((float) toplevel->init_right) / ((float) toplevel->init_bottom));
00139 
00140   page->up = -2;
00141   page->page_control = 0;
00142 
00143   /* Init tile array */
00144   s_tile_init (toplevel, page);
00145 
00146   /* Init the object list */
00147   page->_object_list = NULL;
00148 
00149   /* new selection mechanism */
00150   page->selection_list = o_selection_new();
00151 
00152   page->place_list = NULL;
00153 
00154   /* init undo struct pointers */
00155   s_undo_init(page);
00156   
00157   page->object_lastplace = NULL;
00158 
00159   page->weak_refs = NULL;
00160   
00161   set_window (toplevel, page,
00162               toplevel->init_left, toplevel->init_right,
00163               toplevel->init_top,  toplevel->init_bottom);
00164 
00165   /* Backup variables */
00166   g_get_current_time (&page->last_load_or_save_time);
00167   page->ops_since_last_backup = 0;
00168   page->saved_since_first_loaded = 0;
00169   page->do_autosave_backup = 0;
00170 
00171   /* now append page to page list of toplevel */
00172   geda_list_add( toplevel->pages, page );
00173 
00174   return page;
00175 }
00176 
00187 void s_page_delete (TOPLEVEL *toplevel, PAGE *page)
00188 {
00189   PAGE *tmp;
00190   gchar *backup_filename;
00191   gchar *real_filename;
00192 
00193   /* We need to temporarily make the page being deleted current because
00194    * various functions called below (some indirectly) assume they are
00195    * deleting objects from the current page.
00196    *
00197    * These functions are known to include:
00198    *   s_delete_object ()
00199    */
00200 
00201   /* save page_current and switch to page */
00202   if (page == toplevel->page_current) {
00203     tmp = NULL;
00204   } else {
00205     tmp = toplevel->page_current;
00206     s_page_goto (toplevel, page);
00207   }
00208 
00209   /* Get the real filename and file permissions */
00210   real_filename = follow_symlinks (page->page_filename, NULL);
00211   
00212   if (real_filename == NULL) {
00213     s_log_message (_("s_page_delete: Can't get the real filename of %s."),
00214                    page->page_filename);
00215   }
00216   else {
00217     backup_filename = f_get_autosave_filename (real_filename);
00218 
00219     /* Delete the backup file */
00220     if ( (g_file_test (backup_filename, G_FILE_TEST_EXISTS)) && 
00221      (!g_file_test(backup_filename, G_FILE_TEST_IS_DIR)) )
00222     {
00223       if (unlink(backup_filename) != 0) {
00224     s_log_message(_("s_page_delete: Unable to delete backup file %s."),
00225                       backup_filename);
00226       }
00227     }
00228     g_free (backup_filename);
00229   }
00230   g_free(real_filename);
00231 
00232   /* Free the selection object */
00233   g_object_unref( page->selection_list );
00234 
00235   /* then delete objects of page */
00236   s_page_delete_objects (toplevel, page);
00237 
00238   /* Free the objects in the place list. */
00239   s_delete_object_glist (toplevel, page->place_list);
00240   page->place_list = NULL;
00241 
00242 #if DEBUG
00243   printf("Freeing page: %s\n", page->page_filename);
00244   s_tile_print(toplevel, page);
00245 #endif
00246   s_tile_free_all (page);
00247 
00248   /* free current page undo structs */
00249   s_undo_free_all (toplevel, page); 
00250 
00251   /* ouch, deal with parents going away and the children still around */
00252   page->up = -2;
00253   g_free (page->page_filename);
00254 
00255   geda_list_remove( toplevel->pages, page );
00256 
00257 #if DEBUG
00258   s_tile_print (toplevel, page);
00259 #endif
00260 
00261   s_weakref_notify (page, page->weak_refs);
00262 
00263   g_free (page);
00264 
00265   /* restore page_current */
00266   if (tmp != NULL) {
00267     s_page_goto (toplevel, tmp);
00268   } else {
00269     /* page was page_current */
00270     toplevel->page_current = NULL;
00271     /* page_current must be updated by calling function */
00272   }
00273 
00274 }
00275 
00276 
00284 void s_page_delete_list(TOPLEVEL *toplevel)
00285 {
00286   GList *list_copy, *iter;
00287   PAGE *page;
00288 
00289   /* s_page_delete removes items from the page list, so make a copy */
00290   list_copy = g_list_copy (geda_list_get_glist (toplevel->pages));
00291 
00292   for (iter = list_copy; iter != NULL; iter = g_list_next (iter)) {
00293     page = (PAGE *)iter->data;
00294 
00295     s_page_delete (toplevel, page);
00296   }
00297 
00298   g_list_free (list_copy);
00299 
00300   /* reset toplevel fields */
00301   toplevel->page_current = NULL;
00302 }
00303 
00316 void
00317 s_page_weak_ref (PAGE *page,
00318                  void (*notify_func)(void *, void *),
00319                  void *user_data)
00320 {
00321   g_return_if_fail (page != NULL);
00322   page->weak_refs = s_weakref_add (page->weak_refs, notify_func, user_data);
00323 }
00324 
00335 void
00336 s_page_weak_unref (PAGE *page,
00337                    void (*notify_func)(void *, void *),
00338                    void *user_data)
00339 {
00340   g_return_if_fail (page != NULL);
00341   page->weak_refs = s_weakref_remove (page->weak_refs,
00342                                       notify_func, user_data);
00343 }
00344 
00356 void
00357 s_page_add_weak_ptr (PAGE *page,
00358                      void *weak_pointer_loc)
00359 {
00360   g_return_if_fail (page != NULL);
00361   page->weak_refs = s_weakref_add_ptr (page->weak_refs, weak_pointer_loc);
00362 }
00363 
00373 void
00374 s_page_remove_weak_ptr (PAGE *page,
00375                         void *weak_pointer_loc)
00376 {
00377   g_return_if_fail (page != NULL);
00378   page->weak_refs = s_weakref_remove_ptr (page->weak_refs,
00379                                           weak_pointer_loc);
00380 }
00381 
00389 void s_page_goto (TOPLEVEL *toplevel, PAGE *p_new) 
00390 {
00391   gchar *dirname;
00392 
00393   toplevel->page_current = p_new;
00394 
00395   dirname = g_dirname (p_new->page_filename);
00396   if (chdir (dirname)) {
00397     /* An error occured with chdir */
00398 #warning FIXME: What do we do?
00399   }
00400   g_free (dirname);
00401 
00402 }
00403 
00414 PAGE *s_page_search (TOPLEVEL *toplevel, const gchar *filename)
00415 {
00416   const GList *iter;
00417   PAGE *page;
00418 
00419   for ( iter = geda_list_get_glist( toplevel->pages );
00420         iter != NULL;
00421         iter = g_list_next( iter ) ) {
00422 
00423     page = (PAGE *)iter->data;
00424     if ( g_strcasecmp( page->page_filename, filename ) == 0 )
00425       return page;
00426   }
00427   return NULL;
00428 }
00429 
00440 PAGE *s_page_search_by_page_id (GedaPageList *list, int pid)
00441 {
00442   const GList *iter;
00443 
00444   for ( iter = geda_list_get_glist (list);
00445         iter != NULL;
00446         iter = g_list_next (iter) ) {
00447     PAGE *page = (PAGE *)iter->data;
00448     if (page->pid == pid) {
00449       return page;
00450     }
00451   }
00452 
00453   return NULL;
00454 }
00455 
00463 void s_page_print_all (TOPLEVEL *toplevel)
00464 {
00465   const GList *iter;
00466   PAGE *page;
00467 
00468   for ( iter = geda_list_get_glist( toplevel->pages );
00469         iter != NULL;
00470         iter = g_list_next( iter ) ) {
00471 
00472     page = (PAGE *)iter->data;
00473     printf ("FILENAME: %s\n", page->page_filename);
00474     print_struct_forw (page->_object_list);
00475   }
00476 }
00477 
00485 gint s_page_save_all (TOPLEVEL *toplevel)
00486 {
00487   const GList *iter;
00488   PAGE *p_current;
00489   gint status = 0;
00490 
00491   for ( iter = geda_list_get_glist( toplevel->pages );
00492         iter != NULL;
00493         iter = g_list_next( iter ) ) {
00494 
00495     p_current = (PAGE *)iter->data;
00496 
00497     if (f_save (toplevel, p_current,
00498                 p_current->page_filename, NULL)) {
00499       s_log_message (_("Saved [%s]\n"),
00500                      p_current->page_filename);
00501       /* reset the CHANGED flag of p_current */
00502       p_current->CHANGED = 0;
00503 
00504     } else {
00505       s_log_message (_("Could NOT save [%s]\n"),
00506                      p_current->page_filename);
00507       /* increase the error counter */
00508       status++;
00509     }
00510 
00511   }
00512 
00513   return status;
00514 }
00515 
00524 gboolean s_page_check_changed (GedaPageList *list)
00525 {
00526   const GList *iter;
00527   PAGE *p_current;
00528 
00529   for ( iter = geda_list_get_glist( list );
00530         iter != NULL;
00531         iter = g_list_next( iter ) ) {
00532 
00533     p_current = (PAGE *)iter->data;
00534     if (p_current->CHANGED) {
00535       return TRUE;
00536     }
00537   }
00538 
00539   return FALSE;
00540 }
00541 
00548 void s_page_clear_changed (GedaPageList *list)
00549 {
00550   const GList *iter;
00551   PAGE *p_current;
00552 
00553   for ( iter = geda_list_get_glist( list );
00554         iter != NULL;
00555         iter = g_list_next( iter ) ) {
00556 
00557     p_current = (PAGE *)iter->data;
00558     p_current->CHANGED = 0;
00559   }
00560 }
00561 
00568 void s_page_autosave_init(TOPLEVEL *toplevel)
00569 {
00570   if (toplevel->auto_save_interval != 0) {
00571 
00572     /* 1000 converts seconds into milliseconds */
00573     toplevel->auto_save_timeout = 
00574       g_timeout_add(toplevel->auto_save_interval*1000,
00575                     (GSourceFunc) s_page_autosave,
00576                     toplevel);
00577   }
00578 }
00579 
00589 gint s_page_autosave (TOPLEVEL *toplevel) 
00590 {
00591   const GList *iter;
00592   PAGE *p_current;
00593 
00594   if (toplevel == NULL) {
00595     return 0;
00596   }
00597 
00598   /* Do nothing if the interval is 0 */
00599   if (toplevel->auto_save_interval == 0) {
00600     return toplevel->auto_save_interval;
00601   }
00602 
00603   /* Should we just disable the autosave timeout returning 0 or
00604      just wait for more pages to be added? */
00605   if ( toplevel->pages == NULL)
00606     return toplevel->auto_save_interval;
00607 
00608   for ( iter = geda_list_get_glist( toplevel->pages );
00609         iter != NULL;
00610         iter = g_list_next( iter ) ) {
00611 
00612     p_current = (PAGE *)iter->data;
00613 
00614     if (p_current->ops_since_last_backup != 0) {
00615       /* Real autosave is done in o_undo_savestate */
00616       p_current->do_autosave_backup = 1;
00617     }
00618   }
00619 
00620   return toplevel->auto_save_interval;
00621 }
00622 
00633 void s_page_append (TOPLEVEL *toplevel, PAGE *page, OBJECT *object)
00634 {
00635   page->_object_list = g_list_append (page->_object_list, object);
00636   object_added (toplevel, page, object);
00637 }
00638 
00649 void s_page_append_list (TOPLEVEL *toplevel, PAGE *page, GList *obj_list)
00650 {
00651   GList *iter;
00652   page->_object_list = g_list_concat (page->_object_list, obj_list);
00653   for (iter = obj_list; iter != NULL; iter = g_list_next (iter)) {
00654     object_added (toplevel, page, iter->data);
00655   }
00656 }
00657 
00668 void s_page_remove (TOPLEVEL *toplevel, PAGE *page, OBJECT *object)
00669 {
00670   pre_object_removed (toplevel, page, object);
00671   page->_object_list = g_list_remove (page->_object_list, object);
00672 }
00673 
00686 void
00687 s_page_replace (TOPLEVEL *toplevel, PAGE *page,
00688                 OBJECT *object1, OBJECT *object2)
00689 {
00690   GList *iter = g_list_find (page->_object_list, object1);
00691 
00692   /* If object1 not found, append object2 */
00693   if (iter == NULL) {
00694     s_page_append (toplevel, page, object2);
00695     return;
00696   }
00697 
00698   pre_object_removed (toplevel, page, object1);
00699   iter->data = object2;
00700   object_added (toplevel, page, object2);
00701 }
00702 
00711 void s_page_delete_objects (TOPLEVEL *toplevel, PAGE *page)
00712 {
00713   GList *objects = page->_object_list;
00714   GList *iter;
00715   for (iter = objects; iter != NULL; iter = g_list_next (iter)) {
00716     pre_object_removed (toplevel, page, iter->data);
00717   }
00718   page->_object_list = NULL;
00719   s_delete_object_glist (toplevel, objects);
00720 }
00721 
00722 
00734 const GList *s_page_objects (PAGE *page)
00735 {
00736   return page->_object_list;
00737 }
00738 
00739 
00754 GList *s_page_objects_in_region (TOPLEVEL *toplevel, PAGE *page,
00755                                  int min_x, int min_y, int max_x, int max_y)
00756 {
00757   BOX rect;
00758 
00759   rect.lower_x = min_x;
00760   rect.lower_y = min_y;
00761   rect.upper_x = max_x;
00762   rect.upper_y = max_y;
00763 
00764   return s_page_objects_in_regions (toplevel, page, &rect, 1);
00765 }
00766 
00779 GList *s_page_objects_in_regions (TOPLEVEL *toplevel, PAGE *page,
00780                                   BOX *rects, int n_rects)
00781 {
00782   GList *iter;
00783   GList *list = NULL;
00784   int i;
00785 
00786   for (iter = page->_object_list; iter != NULL; iter = g_list_next (iter)) {
00787     OBJECT *object = iter->data;
00788     int left, top, right, bottom;
00789     int visible;
00790 
00791     visible = world_get_single_object_bounds (toplevel, object,
00792                                               &left, &top, &right, &bottom);
00793     if (visible) {
00794       for (i = 0; i < n_rects; i++) {
00795         if (right  >= rects[i].lower_x &&
00796             left   <= rects[i].upper_x &&
00797             top    <= rects[i].upper_y &&
00798             bottom >= rects[i].lower_y) {
00799           list = g_list_prepend (list, object);
00800           break;
00801         }
00802       }
00803     }
00804   }
00805 
00806   list = g_list_reverse (list);
00807   return list;
00808 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines