notepad_doc.cpp

Go to the documentation of this file.
00001 /*
00002  * File Name: notepad_doc.cpp
00003  */
00004 
00005 /*
00006  * This file is part of notepad.
00007  *
00008  * notepad is free software: you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation, either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * notepad is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00020  */
00021 
00022 /**
00023  * Copyright (C) 2010 IREX Technologies B.V.
00024  * All rights reserved.
00025  */
00026 
00027 #include <math.h>
00028 #include <cstring>
00029 
00030 #include "notepad_doc.h"
00031 #include "notepad_filestore.h"
00032 #include "notepad_ipc.h"
00033 #include "log.h"
00034 #include "notepad_point.h"
00035 
00036 
00037 namespace notepad 
00038 {
00039     CNotepadDoc::CNotepadDoc()
00040         : doc(0)
00041         , page(0)
00042         , stroke(0)
00043         , dirty(FALSE)
00044         , file_store( new CFileStore() )
00045     {
00046         erscribble_init();
00047         erscribble_doc_disable_autodelete(TRUE);
00048     }
00049 
00050     CNotepadDoc::~CNotepadDoc()
00051     {
00052         erscribble_uninit();
00053         delete file_store;
00054     }
00055 
00056     np_result CNotepadDoc::open(const gchar* filename)
00057     {
00058         LOGPRINTF("entry");
00059 
00060         g_assert(doc == 0);
00061 
00062         np_result result = file_store->openFile(filename);
00063         if (result == NP_OK)
00064         {
00065             doc = erscribble_doc_open_with_database(".", file_store->getFile());
00066 
00067             if (!doc)
00068             {
00069                 result = NP_NO_DOCUMENT;
00070             }
00071         }
00072 
00073         LOGPRINTF("exit");
00074         return result;
00075     }
00076 
00077     np_result CNotepadDoc::create(const gchar* filename)
00078     {
00079         LOGPRINTF("entry filename='%s'", filename);
00080 
00081         g_assert(doc == 0);
00082 
00083         np_result result = file_store->createFile(filename);
00084         if (result == NP_OK)
00085         {
00086             doc = erscribble_doc_new_with_database(".", file_store->getFile());
00087 
00088             if (!doc) 
00089             { 
00090                 result = NP_NO_DOCUMENT;
00091             }
00092         }
00093         LOGPRINTF("exit");
00094         return result;
00095     }
00096 
00097     gboolean CNotepadDoc::get_page_dirty()
00098     {
00099         return dirty;
00100     }
00101 
00102     np_result CNotepadDoc::save_page(const int pageno, bool update_last_read)
00103     {
00104         LOGPRINTF("entry");
00105         g_return_val_if_fail(doc != 0, NP_NO_DOCUMENT);
00106 
00107         if (dirty == FALSE)
00108         {
00109             LOGPRINTF("exit No changes to save");
00110             return NP_OK;
00111         }
00112 
00113         ScbPageId pid;
00114         generate_page_id(pid, pageno);
00115         ScbPagePtr thispage = erscribble_doc_get_page(doc, &pid);
00116         if (NULL == thispage)
00117         {
00118             LOGPRINTF("exit No page");
00119             return NP_OK; // no pages yet
00120         }
00121         if (ER_OK != erscribble_doc_save_page(doc, thispage)) 
00122         {
00123             LOGPRINTF("exit Saving page failed");
00124             return NP_SAVE_FAILED;
00125         }
00126 
00127         if ( update_last_read )
00128         {
00129             (void) set_last_read(pageno);
00130         }
00131 
00132         //TODO size and date are not updated in global.db here
00133 
00134         dirty = FALSE; // changes are saved
00135 
00136         LOGPRINTF("exit");
00137         return NP_OK;
00138     }
00139 
00140     void CNotepadDoc::close()
00141     {
00142         LOGPRINTF("entry");
00143 
00144         if (doc)
00145         {
00146             erscribble_doc_free(doc);
00147             file_store->closeFile();
00148             doc = 0;
00149             memset(&path, 0, sizeof(path));
00150             page = 0;
00151             stroke = 0;
00152         }
00153 
00154         LOGPRINTF("exit");
00155     }
00156 
00157     np_result CNotepadDoc::rename(const gchar* new_shortfilename)
00158     {
00159         LOGPRINTF("entry");
00160         g_return_val_if_fail( (new_shortfilename != 0) && (new_shortfilename[0] != '\0'), NP_NO_FILENAME);
00161 
00162         np_result result = file_store->renameFile(new_shortfilename);
00163         gchar* my_filename = file_store->getFileNameFilePartNoExt();
00164         ipc_change_filename(file_store->getFilename(), my_filename);
00165         g_free(my_filename);
00166 
00167         LOGPRINTF("exit");
00168         return result; 
00169     }
00170 
00171     gint     CNotepadDoc::get_num_pages()
00172     {
00173         gint num_pages = 0;
00174         if (doc)
00175         {
00176             num_pages = g_list_length((erscribble_doc_get_pages(doc))->pages); 
00177         }
00178         return num_pages;
00179     }
00180 
00181     gint    CNotepadDoc::get_last_read()
00182     {
00183         if (doc)
00184         {
00185             return file_store->get_last_read_location();
00186         }
00187         return -1;
00188     }
00189 
00190     gboolean CNotepadDoc::set_last_read(gint value)
00191     {
00192         if (doc)
00193         {
00194             return file_store->set_last_read_location(value);
00195         }
00196         return FALSE;
00197     }
00198 
00199     gchar*  CNotepadDoc::get_full_filename()
00200     {
00201         return file_store->getFilename();
00202     }
00203 
00204     gchar*  CNotepadDoc::get_filename_without_dir_and_ext()
00205     {
00206         return file_store->getFileNameFilePartNoExt();  // caller takes ownership
00207     }
00208 
00209     CFileStore* CNotepadDoc::getFileStore()
00210     {
00211         return file_store;
00212     }
00213 
00214     void CNotepadDoc::generate_page_id(ScbPageId& pid, const int pos)
00215     {
00216         gchar anchor[80];
00217         sprintf(anchor, "%d", pos);
00218         erscribble_page_set_id(&pid, pos, anchor, -1);
00219         LOGPRINTF("id %s, pos %d, anno %lld ", pid.id, pid.position, pid.annotation_id);
00220     }
00221 
00222     void CNotepadDoc::add_page(const int pageno)
00223     {
00224         LOGPRINTF("Append Empty Page!!");
00225 
00226         page = 0; 
00227         page = erscribble_page_new();
00228         ScbPageId pid;
00229         generate_page_id(pid, pageno);
00230         erscribble_page_copy_id(&page->id, &pid);
00231         page->attributes.style.orientation = 0;
00232         erscribble_doc_add_page(doc, page);
00233         page = 0;
00234         stroke = 0;
00235         dirty = TRUE; // changes must be saved
00236     }
00237 
00238     void CNotepadDoc::insert_page(const int pageno)
00239     {
00240         LOGPRINTF("Insert Empty Page!!");
00241 
00242         page = 0; 
00243         page = erscribble_page_new();
00244         ScbPageId pid;
00245         generate_page_id(pid, pageno);
00246         erscribble_page_copy_id(&page->id, &pid);
00247         page->attributes.style.orientation = 0;
00248         erscribble_doc_insert_page(doc, page);
00249         page = 0;
00250         stroke = 0;
00251         dirty = TRUE; // changes must be saved
00252     }
00253 
00254     void CNotepadDoc::delete_page(const int pageno) 
00255     {
00256         LOGPRINTF("Deleting page: %d", pageno);
00257 
00258         ScbPageId pid;
00259         generate_page_id(pid, pageno);
00260         erscribble_doc_delete_page(doc, &pid);
00261         page = 0; 
00262         stroke = 0;
00263     }
00264 
00265     void CNotepadDoc::clear_page(const int pageno) 
00266     {
00267         ScbPageId pid;
00268         generate_page_id(pid, pageno);
00269         ScbPagePtr thispage = erscribble_doc_get_page(doc, &pid);
00270         if (thispage == 0)
00271         {
00272             LOGPRINTF("no page to erase");
00273             return;
00274         }
00275         erscribble_page_clear_strokes(thispage);
00276         dirty = TRUE; // changes must be saved
00277     }
00278 
00279 
00280     // drawing functions
00281 
00282     void CNotepadDoc::draw_stroke(GCtx& gctx, GdkImage* image, ScbStrokePtr stroke)
00283     {
00284         g_assert(image != 0);
00285         g_assert(stroke != 0);
00286 
00287         int count = erscribble_stroke_get_point_count(stroke);
00288         ScbPointPtr pts = erscribble_stroke_get_point_data(stroke);
00289         // select color. 
00290         gctx.set_color(stroke->attributes.color);
00291         // select line width and line style.
00292         gctx.set_line_attributes(stroke->attributes.size_id);
00293 
00294         CNPoint  sp1(pts[0]); // init with storageview
00295 
00296         for (int i=1; i < count; i++)
00297         {
00298             CNPoint  sp2(pts[i]);
00299             gctx.draw_line(image, sp1.windowView(), sp2.windowView()); 
00300             sp1 = sp2;
00301         }
00302     }
00303 
00304     void CNotepadDoc::draw_erased_strokes(GCtx& gctx, GdkImage* image, ScbStrokesPtr strokes) 
00305     {
00306         LOGPRINTF("entry");
00307 
00308         g_assert(image != 0);
00309 
00310         // drawing can take a while, dont let device go idle
00311         ipc_sys_bg_busy(TRUE);
00312 
00313         if (strokes)
00314         {
00315             ScbStrokePtr stroke = NULL;
00316             GList *ptr = g_list_first(strokes->strokes);
00317 
00318             while (ptr)
00319             {
00320                 stroke = (ScbStrokePtr)ptr->data;
00321                 if (stroke)
00322                 {
00323                     // adjust color and size to overdraw erased strokes
00324                     int count = erscribble_stroke_get_point_count(stroke);
00325                     stroke->attributes.color = ERSCRIBBLE_DEV_COLOR_WHITE;
00326                     gctx.set_color(stroke->attributes.color); //white
00327                     ScbPointPtr pts = erscribble_stroke_get_point_data(stroke);
00328 
00329                     int erase_offset_x = 0;
00330                     int erase_offset_y = 0;
00331                     // It is necessary to compensate for asymmetry of current kernel brush shape
00332                     // This depends on brush size and orientation
00333                     // Therefore an erase_offset is made here, which corresponds with 
00334                     // the rotated middle of the brush shapes defined in notepad_utils.cpp and deltadriver.
00335                     if (gctx.rotation != NP_PORTRAIT)
00336                     {
00337                         if (gctx.rotation == NP_ANTICLOCKWISE)
00338                         {
00339                             switch (stroke->attributes.size_id)
00340                             {
00341                                 case 1:
00342                                 case 3:
00343                                 case 5:
00344                                     erase_offset_x = -1;
00345                                     break;
00346                                 case 2:
00347                                 case 4:
00348                                     erase_offset_x = -1;
00349                                     erase_offset_y = -1;
00350                                     break;
00351                                 default:
00352                                     break;
00353                             }
00354                         }
00355                         else // NP_CLOCKWISE
00356                         {
00357                             switch (stroke->attributes.size_id)
00358                             {
00359                                 case 1:
00360                                 case 3:
00361                                 case 5:
00362                                     erase_offset_y = -1;
00363                                     break;
00364                                 case 2:
00365                                 case 4:
00366                                     erase_offset_x =  1;
00367                                     erase_offset_y = -1;
00368                                     break;
00369                                 default:
00370                                     break;
00371                             }
00372                         }
00373                     }
00374 
00375                     // move with offset
00376                     for (int i = 0; i < count; i++)
00377                     {
00378                         CNPoint p(pts[i]);
00379                         pts[i].x = p.deviceView().x + erase_offset_x;
00380                         pts[i].y = p.deviceView().y + erase_offset_y;
00381                     }
00382 
00383                     // draw on displaydriver
00384                     erscribble_stroke_driver_draw(stroke);
00385 
00386                     // move back with offset 
00387                     for (int i = 0; i < count; i++)
00388                     {
00389                         pts[i].x -= erase_offset_x;
00390                         pts[i].y -= erase_offset_y;
00391                     }
00392 
00393                     // also update gtk drawing to let lines stay after local display update
00394                     // because then only the damaged area is redrawn.
00395                     // point data
00396                     draw_stroke(gctx, image, stroke);
00397                 }
00398                 ptr = g_list_next(ptr);
00399             }
00400         }
00401 
00402         ipc_sys_bg_busy(FALSE);
00403         LOGPRINTF("exit");
00404     }
00405 
00406 
00407     void CNotepadDoc::on_scribble_begin(
00408             const int   pageno,
00409             GCtx&       gctx,
00410             GdkImage*   image,
00411             CNPoint&    apoint)
00412     {
00413         LOGPRINTF("entry");
00414         g_assert(image);
00415 
00416         if ((pageno > 0) && (page == 0) && (stroke == 0))
00417         {
00418             ScbPageId pid;
00419             generate_page_id(pid, pageno);
00420 
00421             // check page
00422             page = erscribble_doc_get_page(doc, &pid);
00423             if (page == 0)
00424             {
00425                 // does not exist, needs to create a new one
00426                 page = erscribble_page_new();
00427                 erscribble_page_copy_id(&page->id, &pid);
00428                 page->attributes.style.orientation = 0; // portrait, no orientation stored by Notepad app.
00429                 LOGPRINTF("created new page %s", pid.id);
00430             }
00431 
00432             // check stroke
00433             if (stroke == 0)
00434             {
00435                 stroke = erscribble_stroke_new_with_attributes(erscribble_doc_get_current_stroke_attributes(doc));
00436                 stroke->attributes.zoom = 100.0; //notused
00437                 stroke->attributes.size_id = ipc_get_pensize(); // pen_size from gconf
00438                 stroke->attributes.color = ERSCRIBBLE_DEV_COLOR_BLACK;
00439                 erscribble_page_add_stroke(page, stroke);
00440                 LOGPRINTF("Created new stroke");
00441             }
00442 
00443             // Add to drawing
00444             ScbDevPoint point;
00445             point.point = apoint.storageView();
00446             point.pressure = 0;
00447             erscribble_stroke_add_point(stroke, &point);
00448 
00449             // draw in display
00450             point.point = apoint.deviceView();
00451             erscribble_stroke_driver_draw_point(stroke, &point, FALSE);
00452         }
00453     }
00454 
00455     void CNotepadDoc::on_scribble_move(
00456             const int   pageno,
00457             GCtx&       gctx,
00458             GdkImage*   image,
00459             CNPoint&    apoint)
00460     {
00461         g_assert(image);
00462 
00463         if (stroke)
00464         {
00465             // Add to drawing
00466             ScbDevPoint point;
00467             point.point = apoint.storageView();
00468             erscribble_stroke_add_point(stroke, &point);
00469 
00470             point.point = apoint.deviceView();
00471             erscribble_stroke_driver_draw_point(stroke, &point, FALSE);
00472         }
00473     }
00474 
00475     void CNotepadDoc::on_scribble_end(
00476             const int   pageno,
00477             GCtx&       gctx,
00478             GdkImage*   image,
00479             CNPoint&    apoint)
00480     {
00481         LOGPRINTF("End stroke!");
00482 
00483         g_assert(image);
00484 
00485         if ( (pageno > 0) && stroke && doc && page)
00486         {
00487             // add to drawing
00488             ScbDevPoint point;
00489             point.point = apoint.storageView();
00490             erscribble_stroke_add_point(stroke, &point);
00491 
00492             // draw on display
00493             point.point = apoint.deviceView();
00494             erscribble_stroke_driver_draw_point(stroke, &point, TRUE);
00495 
00496             // also update gtk drawing to let lines stay after local display update
00497             // because then only the damaged area is redrawn.
00498             // point data
00499             draw_stroke(gctx, image, stroke);
00500 
00501             // add & reset
00502             erscribble_doc_add_page(doc, page);
00503             page = 0; 
00504             stroke = 0;
00505         }
00506         dirty = TRUE; // changes must be saved
00507     }
00508 
00509     void CNotepadDoc::on_erase_begin(
00510             const int   pageno,
00511             GCtx&       gctx,
00512             GdkImage*   image,
00513             CNPoint&    apoint)
00514     {
00515         LOGPRINTF("entry");
00516 
00517         g_assert(image);
00518 
00519         if (pageno > 0)
00520         {
00521 
00522             ScbPageId pid;
00523             generate_page_id(pid, pageno);
00524 
00525             page = erscribble_doc_get_page(doc, &pid);
00526             if (page == 0)
00527             {
00528                 return;
00529             }
00530 
00531             // prepare for erasing.
00532             erscribble_page_erase_init(&erase_context);
00533 
00534             ScbDevPoint point;
00535             point.point = apoint.storageView();
00536             erase_context.zoom = 100.0; //notused
00537             ScbStrokesPtr strokes = erscribble_page_erase_hit_test(page, &point, &erase_context);
00538             if (strokes)
00539             {
00540                 LOGPRINTF("Erase strokes!");
00541 
00542                 // draw 
00543                 draw_erased_strokes(gctx, image, strokes);
00544 
00545                 // free
00546                 erscribble_strokes_free(strokes);
00547 
00548                 dirty = TRUE; // changes must be saved
00549             }
00550         }
00551     }
00552 
00553     void CNotepadDoc::on_erase_move(
00554             const int   pageno,
00555             GCtx&       gctx,
00556             GdkImage*   image,
00557             CNPoint&    apoint )
00558     {
00559         g_assert(image);
00560 
00561         ScbDevPoint point;
00562         point.point = apoint.storageView(); 
00563 
00564         //Note: Compares current point with existing lines, so crossings can be missed, 
00565         //      although comparing linesize is big (5)
00566         ScbStrokesPtr strokes = erscribble_page_erase_hit_test(page, &point, &erase_context);
00567         if (strokes)
00568         {
00569             LOGPRINTF("Erase strokes!");
00570             // draw
00571             draw_erased_strokes(gctx, image, strokes);
00572 
00573             // free 
00574             erscribble_strokes_free(strokes);
00575 
00576             dirty = TRUE; // changes must be saved
00577         }
00578     }
00579 
00580     void CNotepadDoc::on_erase_end(
00581             const int   pageno,
00582             GCtx&       gctx,
00583             GdkImage*   image,
00584             CNPoint&    apoint)
00585     {
00586         g_assert(image);
00587 
00588         ScbDevPoint point;
00589         point.point = apoint.storageView();
00590         ScbStrokesPtr strokes = erscribble_page_erase_hit_test(page, &point, &erase_context);
00591 
00592         // reset
00593         page = 0;
00594         if (strokes) 
00595         {
00596             LOGPRINTF("Erase strokes!");
00597             //draw
00598             draw_erased_strokes(gctx, image, strokes);
00599 
00600             // free
00601             erscribble_strokes_free(strokes);
00602 
00603             dirty = TRUE; // changes must be saved
00604         }
00605     }
00606 
00607     void CNotepadDoc::draw_scribble_page(const int pageno, GCtx& gctx, GdkImage* image)
00608     {
00609         LOGPRINTF("entry");
00610 
00611         g_assert(image);
00612 
00613         // page from page id
00614         ScbPageId pid;
00615         generate_page_id(pid, pageno);
00616 
00617         ScbPagePtr thispage = erscribble_doc_get_page(doc, &pid);
00618         if (thispage == 0)
00619         {
00620             LOGPRINTF("page %s not found!", pid.id);
00621             return;
00622         }
00623 
00624         // drawing can take a while, dont let device go idle
00625         ipc_sys_bg_busy(TRUE);
00626 
00627         ScbStrokesPtr strokes = erscribble_page_get_strokes(thispage);
00628 
00629         if (strokes)
00630         {
00631             ScbStrokePtr stroke = NULL;
00632             GList *pstroke = g_list_first(strokes->strokes);
00633             while (pstroke)
00634             {
00635                 stroke = (ScbStrokePtr)pstroke->data;
00636                 if (stroke)
00637                 {
00638                     draw_stroke(gctx, image, stroke);
00639 
00640                     // NOTE zoom not used in notepad, but if do transform with:
00641                     // float ratio = z / stroke->attributes.zoom;
00642                     // int x1 = (int)(ratio * pts[i].x); 
00643                     // and scale linesize with gctx.set_line_attributes(calc_line_size(stroke->attributes.size_id, gctx.realzoom, stroke->attributes.zoom));
00644                     // where linesize = (int)(penSize * strokeZoom / dispZoom);
00645                 }
00646                 pstroke = g_list_next(pstroke);
00647             }
00648         }
00649 
00650         ipc_sys_bg_busy(FALSE);
00651 
00652         LOGPRINTF("exit");
00653     }
00654 
00655 } //namespace
00656 
Generated by  doxygen 1.6.2-20100208