Ticket #1636: sugar-1636.patch
File sugar-1636.patch, 9.6 KB (added by alsroot, 14 years ago) |
---|
-
src/jarabe/journal/listview.py
diff --git a/src/jarabe/journal/listview.py b/src/jarabe/journal/listview.py index 6556b08..9b287c4 100644
a b class BaseListView(gtk.HBox): 123 123 datastore.connect_to_signal('Deleted', 124 124 self.__datastore_deleted_cb) 125 125 126 model.created.connect(self.__model_updated_cb) 127 model.updated.connect(self.__model_updated_cb) 128 model.deleted.connect(self.__model_updated_cb) 129 130 def __model_updated_cb(self, sender, **kwargs): 131 if 'object_id' in kwargs and kwargs['object_id'].startswith('/'): 132 # otherwise rely on ds' Deleted event for ds objects 133 self._set_dirty() 134 126 135 def __destroy_cb(self, widget): 127 136 self._datastore_created_handler.remove() 128 137 self._datastore_updated_handler.remove() -
src/jarabe/journal/model.py
diff --git a/src/jarabe/journal/model.py b/src/jarabe/journal/model.py index 9521456..635781d 100644
a b import os 19 19 from datetime import datetime 20 20 import time 21 21 import shutil 22 import tempfile 22 23 from stat import S_IFMT, S_IFDIR, S_IFREG 23 24 import traceback 24 25 import re … … import gobject 27 28 import dbus 28 29 import gconf 29 30 import gio 31 import json 32 import base64 30 33 31 34 from sugar import dispatch 32 35 from sugar import mime … … class InplaceResultSet(BaseResultSet): 308 311 files = self._file_list[offset:offset + limit] 309 312 310 313 entries = [] 311 for file_path, stat, mtime_ in files: 312 metadata = _get_file_metadata(file_path, stat) 314 for file_path, stat, mtime_, metadata in files: 315 if metadata == False: 316 # fallback - the find should fetch md 317 metadata = _get_file_metadata(file_path, stat) 313 318 metadata['mountpoint'] = self._mount_point 314 319 entries.append(metadata) 315 320 … … class InplaceResultSet(BaseResultSet): 334 339 elif S_IFMT(stat.st_mode) == S_IFREG: 335 340 add_to_list = True 336 341 337 if self._regex is not None and \ 338 not self._regex.match(full_path): 342 md = _get_file_metadata_from_json(dir_path, entry, 343 preview=False) 344 if self._regex is not None: 339 345 add_to_list = False 346 if self._regex.match(full_path): 347 add_to_list = True 348 elif md: 349 # match any of the text md fields 350 for f in ['fulltext', 'title', 'description', 'tags']: 351 if f in md and self._regex.match(md[f]): 352 add_to_list = True 353 break 340 354 341 355 if None not in [self._date_start, self._date_end] and \ 342 356 (stat.st_mtime < self._date_start or … … class InplaceResultSet(BaseResultSet): 349 363 add_to_list = False 350 364 351 365 if add_to_list: 352 file_info = (full_path, stat, int(stat.st_mtime) )366 file_info = (full_path, stat, int(stat.st_mtime), md) 353 367 self._file_list.append(file_info) 354 368 355 369 self.progress.send(self) … … class InplaceResultSet(BaseResultSet): 364 378 self._pending_directories -= 1 365 379 366 380 def _get_file_metadata(path, stat): 381 # will sometimes be called for 382 # files that do have a metatada file 383 fname = os.path.basename(path) 384 dir_path = os.path.dirname(path) 385 md = _get_file_metadata_from_json(dir_path, fname, preview=True) 386 if md: 387 return md 388 389 # make up something for files w/o metadata 367 390 client = gconf.client_get_default() 368 391 return {'uid': path, 369 392 'title': os.path.basename(path), … … def _get_file_metadata(path, stat): 374 397 'icon-color': client.get_string('/desktop/sugar/user/color'), 375 398 'description': path} 376 399 400 def _get_file_metadata_from_json(dir_path, fname, preview=False): 401 md = None 402 mdpath = os.path.join(dir_path, 403 '.'+fname+'.metadata') 404 md = False 405 if os.path.exists(mdpath): 406 try: 407 md = json.load(open(mdpath)) 408 md['uid'] = os.path.join(dir_path, fname) 409 except: 410 pass 411 if preview: 412 prpath = os.path.join(dir_path, 413 '.'+fname+'.preview') 414 try: 415 preview = base64.b64encode(open(prpath).read()) 416 md['preview'] = preview 417 except: 418 pass 419 else: 420 if md and 'preview' in md: 421 del(md['preview']) 422 return md 423 377 424 _datastore = None 378 425 def _get_datastore(): 379 426 global _datastore … … def delete(object_id): 460 507 """ 461 508 if os.path.exists(object_id): 462 509 os.unlink(object_id) 510 dir_path = os.path.dirname(object_id) 511 fname = os.path.basename(object_id) 512 old_files = [ os.path.join(dir_path, 513 '.'+fname+'.metadata'), 514 os.path.join(dir_path, 515 '.'+fname+'.preview') ] 516 for ofile in old_files: 517 if os.path.exists(ofile): 518 try: 519 os.unlink(ofile) 520 except: 521 pass 463 522 deleted.send(None, object_id=object_id) 464 523 else: 465 524 _get_datastore().delete(object_id) … … def write(metadata, file_path='', update_mtime=True): 480 539 """ 481 540 logging.debug('model.write %r %r %r' % (metadata.get('uid', ''), file_path, 482 541 update_mtime)) 542 543 rename = False 544 483 545 if update_mtime: 484 546 metadata['mtime'] = datetime.now().isoformat() 485 547 metadata['timestamp'] = int(time.time()) … … def write(metadata, file_path='', update_mtime=True): 495 557 file_path, 496 558 True) 497 559 else: 498 if not os.path.exists(file_path): 560 if 'uid' in metadata and os.path.exists(metadata['uid']): 561 file_path = metadata['uid'] 562 563 if not file_path or not os.path.exists(file_path): 499 564 raise ValueError('Entries without a file cannot be copied to ' 500 565 'removable devices') 501 566 … … def write(metadata, file_path='', update_mtime=True): 503 568 file_name = _get_unique_file_name(metadata['mountpoint'], file_name) 504 569 505 570 destination_path = os.path.join(metadata['mountpoint'], file_name) 506 shutil.copy(file_path, destination_path) 571 572 if os.path.dirname(destination_path) == os.path.dirname(file_path): 573 ## FIXME: handle renames in a separate codepath 574 ## in a failsafe manner 575 ## (write new md, then rename and rm old) 576 # rename on a removable disk - mv file, but let 577 # the metadata&preview be written - at least md will 578 # be different 579 rename = True 580 old_file_path = file_path 581 582 os.rename(file_path, destination_path) 583 old_fname = os.path.basename(file_path) 584 old_files = [ os.path.join(metadata['mountpoint'], 585 '.'+old_fname+'.metadata'), 586 os.path.join(metadata['mountpoint'], 587 '.'+old_fname+'.preview') ] 588 for ofile in old_files: 589 if os.path.exists(ofile): 590 try: 591 os.unlink(ofile) 592 except: 593 pass 594 595 else: 596 shutil.copy(file_path, destination_path) 597 598 # issue our metadata massage on a copy 599 md = metadata.copy() 600 del md['mountpoint'] 601 602 # if we ever write to places other than the root 603 # keep in mind that the metadata file must be in the 604 # same directory as the data file. 605 md_path = os.path.join(metadata['mountpoint'], 606 '.'+file_name+'.metadata') 607 608 if 'preview' in md: 609 preview = md['preview'] 610 preview_fname = '.'+file_name+'.preview' 611 preview_path = os.path.join(metadata['mountpoint'], preview_fname) 612 md['preview'] = preview_fname 613 614 # Write preview atomically 615 (fh, fn) = tempfile.mkstemp(dir=metadata['mountpoint']) 616 os.write(fh, preview) 617 os.close(fh) 618 os.rename(fn, preview_path) 619 620 # Write metadata atomically (on FSs that support it) 621 (fh, fn) = tempfile.mkstemp(dir=metadata['mountpoint']) 622 os.write(fh, json.dumps(md)) 623 os.close(fh) 624 os.rename(fn, md_path) 625 507 626 object_id = destination_path 627 metadata['uid'] = object_id 508 628 created.send(None, object_id=object_id) 509 629 510 630 return object_id … … def write(metadata, file_path='', update_mtime=True): 512 632 def _get_file_name(title, mime_type): 513 633 file_name = title 514 634 515 extension = '.' + mime.get_primary_extension(mime_type) 516 if not file_name.endswith(extension): 517 file_name += extension 635 mime_extension = mime.get_primary_extension(mime_type) 636 if mime_extension: 637 extension = '.' + mime_extension 638 if not file_name.endswith(extension): 639 file_name += extension 518 640 519 641 # Invalid characters in VFAT filenames. From 520 642 # http://en.wikipedia.org/wiki/File_Allocation_Table