Changeset 6319 for trunk/gli/src/org/greenstone/gatherer/file
- Timestamp:
- 2003-12-19T14:47:38+13:00 (20 years ago)
- Location:
- trunk/gli/src/org/greenstone/gatherer/file
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/gli/src/org/greenstone/gatherer/file/FileManager.java
r5593 r6319 54 54 */ 55 55 public class FileManager { 56 57 static public int countFolderDepth(File file) { 58 int count = 0; 59 while(file != null) { 60 count++; 61 file = file.getParentFile(); 62 } 63 return count; 64 } 65 56 66 /** Not only the queue of files to be moved, but also the object that moves them. */ 57 67 private FileQueue queue = null; -
trunk/gli/src/org/greenstone/gatherer/file/FileQueue.java
r6205 r6319 231 231 if((job.type == FileJob.COPY || job.type == FileJob.MOVE) && !job.done) { 232 232 ///ystem.err.println("Copy/Move: " + origin_node); 233 FileNode new_node = null; 234 // Check if file exists, and action as necessary. Be aware the user can choose to cancel the action all together (where upon ready becomes false). 235 if(target_file.exists()) { 236 // We've previously been told 237 if(yes_to_all) { 238 // Remove the old file and tree entry. 239 target_file.delete(); 240 ready = true; 241 } 242 else { 243 ///atherer.println("Opps! This filename already exists. Give the user some options."); 244 Object[] options = { Dictionary.get("General.Yes"), Dictionary.get("FileActions.Yes_To_All"), Dictionary.get("General.No"), Dictionary.get("General.Cancel") }; 245 int result = JOptionPane.showOptionDialog(Gatherer.g_man, Dictionary.get("FileActions.File_Exists", target_file.getName()), Dictionary.get("General.Warning"), JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[0]); 246 switch(result) { 247 case 1: // Yes To All 248 yes_to_all = true; 249 case 0: // Yes 233 234 // The number one thing to check is whether we are in a cyclic loop. The easiest way is just to check how deep we are 235 int max_folder_depth = Gatherer.config.getInt("general.max_folder_depth", Configuration.COLLECTION_SPECIFIC); 236 boolean continue_over_depth = false; 237 if(FileManager.countFolderDepth(source_file) > max_folder_depth) { 238 Object[] options = { Dictionary.get("General.Yes"), Dictionary.get("General.No"), Dictionary.get("FileActions.Increase_Depth") }; 239 String args[] = { String.valueOf(max_folder_depth), source_file.getAbsolutePath() }; 240 int result = JOptionPane.showOptionDialog(Gatherer.g_man, Utility.formatHTMLWidth(Dictionary.get("FileActions.Possible_Cyclic_Path", args), 80), Dictionary.get("General.Warning"), JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[1]); 241 args = null; 242 options = null; 243 switch(result) { 244 case 0: // Yes 245 continue_over_depth = true; 246 break; 247 case 2: // Continue and increase depth 248 continue_over_depth = true; 249 Gatherer.config.setInt("general.max_folder_depth", Configuration.COLLECTION_SPECIFIC, (max_folder_depth + 1)); 250 break; 251 } 252 } 253 else { 254 continue_over_depth = true; 255 } 256 257 if(continue_over_depth) { 258 FileNode new_node = null; 259 // Check if file exists, and action as necessary. Be aware the user can choose to cancel the action all together (where upon ready becomes false). 260 if(target_file.exists()) { 261 // We've previously been told 262 if(yes_to_all) { 250 263 // Remove the old file and tree entry. 251 if(destination_node != null) {252 TreePath destination_path = new TreePath(destination_node.getPath());253 FileNode temp_target_node = new FileNode(target_file, target_model, true);254 TreePath target_path = destination_path.pathByAddingChild(temp_target_node);255 SynchronizedTreeModelTools.removeNodeFromParent(target_model, target_model.getNode(target_path));256 target_path = null;257 temp_target_node = null;258 destination_path = null;259 }260 264 target_file.delete(); 261 265 ready = true; 262 break; 263 case 3: // No To All 264 cancel_action = true; 265 case 2: // No 266 default: 267 ready = false; 268 // Increment progress by size of potentially copied file 269 progress.addValue(origin_node.getFile().length()); 270 } 271 } 272 } 273 // We proceed with the copy/move if the ready flag is still set. If it is that means there is no longer any existing file of the same name. 274 if(ready) { 275 // update status area 276 String args[] = new String[1]; 277 args[0] = "" + (queue.size() + 1) + ""; 278 if(job.type == FileJob.COPY) { 279 args[0] = Utility.formatPath("FileActions.Copying", source_file.getAbsolutePath(), file_status.getSize().width); 280 file_status.setText(Dictionary.get("FileActions.Copying", args)); 281 } 282 else { 283 args[0] = Utility.formatPath("FileActions.Moving", source_file.getAbsolutePath(), file_status.getSize().width); 284 file_status.setText(Dictionary.get("FileActions.Moving", args)); 285 } 286 args = null; 287 288 // If source is a file 289 if(source_file.isFile()) { 290 // copy the file. If anything goes wrong the copy file should throw the appropriate exception. No matter what exception is thrown (bar an IOException) we display some message, perhaps take some action, then cancel the remainder of the pending file jobs. No point in being told your out of hard drive space for each one of six thousand files eh? 291 try { 292 copyFile(source_file, target_file, progress); 293 } 294 // If we can't find the source file, then the most likely reason is that the file system has changed since the last time it was mapped. Warn the user that the requested file can't be found, then force a refresh of the source folder involved. 295 catch(FileNotFoundException fnf_exception) { 296 Gatherer.printStackTrace(fnf_exception); 266 } 267 else { 268 ///atherer.println("Opps! This filename already exists. Give the user some options."); 269 Object[] options = { Dictionary.get("General.Yes"), Dictionary.get("FileActions.Yes_To_All"), Dictionary.get("General.No"), Dictionary.get("General.Cancel") }; 270 int result = JOptionPane.showOptionDialog(Gatherer.g_man, Dictionary.get("FileActions.File_Exists", target_file.getName()), Dictionary.get("General.Warning"), JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[0]); 271 switch(result) { 272 case 1: // Yes To All 273 yes_to_all = true; 274 case 0: // Yes 275 // Remove the old file and tree entry. 276 if(destination_node != null) { 277 TreePath destination_path = new TreePath(destination_node.getPath()); 278 FileNode temp_target_node = new FileNode(target_file, target_model, true); 279 TreePath target_path = destination_path.pathByAddingChild(temp_target_node); 280 SynchronizedTreeModelTools.removeNodeFromParent(target_model, target_model.getNode(target_path)); 281 target_path = null; 282 temp_target_node = null; 283 destination_path = null; 284 } 285 target_file.delete(); 286 ready = true; 287 break; 288 case 3: // No To All 289 cancel_action = true; 290 case 2: // No 291 default: 292 ready = false; 293 // Increment progress by size of potentially copied file 294 progress.addValue(origin_node.getFile().length()); 295 } 296 } 297 } 298 // We proceed with the copy/move if the ready flag is still set. If it is that means there is no longer any existing file of the same name. 299 if(ready) { 300 // update status area 301 String args[] = new String[1]; 302 args[0] = "" + (queue.size() + 1) + ""; 303 if(job.type == FileJob.COPY) { 304 args[0] = Utility.formatPath("FileActions.Copying", source_file.getAbsolutePath(), file_status.getSize().width); 305 file_status.setText(Dictionary.get("FileActions.Copying", args)); 306 } 307 else { 308 args[0] = Utility.formatPath("FileActions.Moving", source_file.getAbsolutePath(), file_status.getSize().width); 309 file_status.setText(Dictionary.get("FileActions.Moving", args)); 310 } 311 args = null; 312 313 // If source is a file 314 if(source_file.isFile()) { 315 // copy the file. If anything goes wrong the copy file should throw the appropriate exception. No matter what exception is thrown (bar an IOException) we display some message, perhaps take some action, then cancel the remainder of the pending file jobs. No point in being told your out of hard drive space for each one of six thousand files eh? 316 try { 317 copyFile(source_file, target_file, progress); 318 } 319 // If we can't find the source file, then the most likely reason is that the file system has changed since the last time it was mapped. Warn the user that the requested file can't be found, then force a refresh of the source folder involved. 320 catch(FileNotFoundException fnf_exception) { 321 Gatherer.printStackTrace(fnf_exception); 322 cancel_action = true; 323 // Show warning. 324 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("FileActions.File_Not_Found_Message", source_file.getName()), Dictionary.get("FileActions.File_Not_Found_Title"), JOptionPane.ERROR_MESSAGE); 325 // Force refresh of source folder. 326 source_model.refresh(new TreePath(((FileNode)origin_node.getParent()).getPath())); 327 } 328 catch(FileAlreadyExistsException fae_exception) { 329 Gatherer.printStackTrace(fae_exception); 330 cancel_action = true; 331 // Show warning. 332 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("FileActions.File_Already_Exists_Message", target_file.getName()), Dictionary.get("FileActions.File_Already_Exists_Title"), JOptionPane.ERROR_MESSAGE); 333 // Nothing else can be done by the Gatherer. 334 } 335 catch(InsufficientSpaceException is_exception) { 336 Gatherer.printStackTrace(is_exception); 337 cancel_action = true; 338 // Show warning. The message body of the expection explains how much more space is required for this file copy. 339 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("FileActions.Insufficient_Space_Message", is_exception.getMessage()), Dictionary.get("FileActions.Insufficient_Space_Title"), JOptionPane.ERROR_MESSAGE); 340 // Nothing else can be done by the Gatherer. In fact if we are really out of space I'm not even sure we can quit safely. 341 } 342 catch(UnknownFileErrorException ufe_exception) { 343 Gatherer.printStackTrace(ufe_exception); 344 cancel_action = true; 345 // Show warning 346 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("FileActions.Unknown_File_Error_Message"), Dictionary.get("FileActions.Unknown_File_Error_Title"), JOptionPane.ERROR_MESSAGE); 347 // Nothing else we can do. 348 } 349 catch(WriteNotPermittedException wnp_exception) { 350 Gatherer.printStackTrace(wnp_exception); 351 cancel_action = true; 352 // Show warning 353 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("FileActions.Write_Not_Permitted_Message", target_file.getAbsolutePath()), Dictionary.get("FileActions.Write_Not_Permitted_Title"), JOptionPane.ERROR_MESSAGE); 354 // Nothing else we can do. 355 } 356 catch(IOException exception) { 357 // Can't really do much about this. 358 Gatherer.printStackTrace(exception); 359 } 360 // If not cancelled 361 if(!cancel_action) { 362 // Step one is to create a dummy FileNode. Its important it has the correct structure so getPath works. 363 FileNode new_record = new FileNode(target_file); 364 SynchronizedTreeModelTools.insertNodeInto(target_model, destination_node, new_record); 365 new_node = new_record; 366 367 // create undo job 368 if(job.undoable) { 369 job.undoable = false; 370 if(job.type == FileJob.COPY) { 371 // A copy is undone with a delete, so it doesn't really matter where the file originally came from (we're not moving it back there, but into the recycle bin). You may also notice we don't make use of the target parent record. This is because no undo action needs this information, and even if it did it could simply ask for records parent! 372 Gatherer.c_man.undo.addUndo(job.ID(), UndoManager.FILE_COPY, null, null, job.target, new_record, job.undo); 373 } 374 else { 375 // Movements however do need a source and source parent so the file can be moved back to the correct place. 376 Gatherer.c_man.undo.addUndo(job.ID(), UndoManager.FILE_MOVE, job.source, (FileNode)origin_node.getParent(), job.target, new_record, job.undo); 377 } 378 } 379 new_record = null; 380 } 381 } 382 // Else 383 else if(source_file.isDirectory()) { 384 // create new record 385 FileNode directory_record = new FileNode(target_file); 386 ///ystem.err.println("Directory record = " + directory_record + " (" + target_file.getAbsolutePath() + ")"); 387 SynchronizedTreeModelTools.insertNodeInto(target_model, destination_node, directory_record); 388 // Why is this not happening eh? 389 directory_record.setParent(destination_node); 390 if(!target_file.exists()) { 391 // make the directory 392 target_file.mkdirs(); 393 new_node = directory_record; 394 // create undo job 395 if(job.undoable) { 396 job.undoable = false; 397 if(job.type == FileJob.COPY) { 398 // A copy is undone with a delete, so it doesn't really matter where the file originally came from (we're not moving it back there, but into the recycle bin). You may also notice we don't make use of the target parent record. This is because no undo action needs this information, and even if it did it could simply ask for records parent! 399 Gatherer.c_man.undo.addUndo(job.ID(), UndoManager.FILE_COPY, null, null, job.target, directory_record, job.undo); 400 } 401 else { 402 // Movements however do need a source and source parent so the file can be moved back to the correct place. 403 Gatherer.c_man.undo.addUndo(job.ID(), UndoManager.FILE_MOVE, job.source, (FileNode)origin_node.getParent(), job.target, directory_record, job.undo); 404 } 405 } 406 } 407 // Else inform the users that a directory already exists and files will be copied into it 408 //else { 409 // JOptionPane.showMessageDialog(null, Dictionary.get("FileActions.Directory_Exists", target_file.toString()), Dictionary.get("General.Warning"), JOptionPane.WARNING_MESSAGE); 410 //} 411 // Queue non-filtered child files for copying. If this directory already existed, the child records will have to generate the undo jobs, as we don't want to entirely delete this directory if it already existed. 412 FileNode child_record = null; 413 // In order to have a sane copy proceedure (rather than always copying last file first as it used to) we always add the child node at the position the parent was removed from. Consider the file job 'a' at the end of the queue which generates three new jobs 'b', 'c' and 'd'. The resulting flow should look like this. 414 // -- Starting queue ...[a] 415 // remove(position) = 'a' ... 416 // add(position, 'b') ...[b] 417 // add(position, 'c') ...[c][b] 418 // add(position, 'd') ...[d][c][b] 419 // Next loop 420 // remove(position) = 'b' ...[d][c] 421 for(int i = 0; i < origin_node.getChildCount(); i++) { 422 child_record = (FileNode) origin_node.getChildAt(i); 423 addJob(job.ID(), job.source, child_record, job.target, directory_record, job.type, job.undo, false, false, position); 424 } 425 child_record = null; 426 directory_record = null; 427 } 428 // The file wasn't found! 429 else { 297 430 cancel_action = true; 298 431 // Show warning. 299 432 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("FileActions.File_Not_Found_Message", source_file.getName()), Dictionary.get("FileActions.File_Not_Found_Title"), JOptionPane.ERROR_MESSAGE); 300 433 // Force refresh of source folder. 301 434 source_model.refresh(new TreePath(((FileNode)origin_node.getParent()).getPath())); 302 435 } 303 catch(FileAlreadyExistsException fae_exception) { 304 Gatherer.printStackTrace(fae_exception); 305 cancel_action = true; 306 // Show warning. 307 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("FileActions.File_Already_Exists_Message", target_file.getName()), Dictionary.get("FileActions.File_Already_Exists_Title"), JOptionPane.ERROR_MESSAGE); 308 // Nothing else can be done by the Gatherer. 309 } 310 catch(InsufficientSpaceException is_exception) { 311 Gatherer.printStackTrace(is_exception); 312 cancel_action = true; 313 // Show warning. The message body of the expection explains how much more space is required for this file copy. 314 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("FileActions.Insufficient_Space_Message", is_exception.getMessage()), Dictionary.get("FileActions.Insufficient_Space_Title"), JOptionPane.ERROR_MESSAGE); 315 // Nothing else can be done by the Gatherer. In fact if we are really out of space I'm not even sure we can quit safely. 316 } 317 catch(UnknownFileErrorException ufe_exception) { 318 Gatherer.printStackTrace(ufe_exception); 319 cancel_action = true; 320 // Show warning 321 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("FileActions.Unknown_File_Error_Message"), Dictionary.get("FileActions.Unknown_File_Error_Title"), JOptionPane.ERROR_MESSAGE); 322 // Nothing else we can do. 323 } 324 catch(WriteNotPermittedException wnp_exception) { 325 Gatherer.printStackTrace(wnp_exception); 326 cancel_action = true; 327 // Show warning 328 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("FileActions.Write_Not_Permitted_Message", target_file.getAbsolutePath()), Dictionary.get("FileActions.Write_Not_Permitted_Title"), JOptionPane.ERROR_MESSAGE); 329 // Nothing else we can do. 330 } 331 catch(IOException exception) { 332 // Can't really do much about this. 333 Gatherer.printStackTrace(exception); 334 } 335 // If not cancelled 336 if(!cancel_action) { 337 // Step one is to create a dummy FileNode. Its important it has the correct structure so getPath works. 338 FileNode new_record = new FileNode(target_file); 339 SynchronizedTreeModelTools.insertNodeInto(target_model, destination_node, new_record); 340 new_node = new_record; 341 342 // create undo job 343 if(job.undoable) { 344 job.undoable = false; 345 if(job.type == FileJob.COPY) { 346 // A copy is undone with a delete, so it doesn't really matter where the file originally came from (we're not moving it back there, but into the recycle bin). You may also notice we don't make use of the target parent record. This is because no undo action needs this information, and even if it did it could simply ask for records parent! 347 Gatherer.c_man.undo.addUndo(job.ID(), UndoManager.FILE_COPY, null, null, job.target, new_record, job.undo); 348 } 349 else { 350 // Movements however do need a source and source parent so the file can be moved back to the correct place. 351 Gatherer.c_man.undo.addUndo(job.ID(), UndoManager.FILE_MOVE, job.source, (FileNode)origin_node.getParent(), job.target, new_record, job.undo); 352 } 353 } 354 new_record = null; 355 } 356 } 357 // Else 358 else if(source_file.isDirectory()) { 359 // create new record 360 FileNode directory_record = new FileNode(target_file); 361 ///ystem.err.println("Directory record = " + directory_record + " (" + target_file.getAbsolutePath() + ")"); 362 SynchronizedTreeModelTools.insertNodeInto(target_model, destination_node, directory_record); 363 // Why is this not happening eh? 364 directory_record.setParent(destination_node); 365 if(!target_file.exists()) { 366 // make the directory 367 target_file.mkdirs(); 368 new_node = directory_record; 369 // create undo job 370 if(job.undoable) { 371 job.undoable = false; 372 if(job.type == FileJob.COPY) { 373 // A copy is undone with a delete, so it doesn't really matter where the file originally came from (we're not moving it back there, but into the recycle bin). You may also notice we don't make use of the target parent record. This is because no undo action needs this information, and even if it did it could simply ask for records parent! 374 Gatherer.c_man.undo.addUndo(job.ID(), UndoManager.FILE_COPY, null, null, job.target, directory_record, job.undo); 375 } 376 else { 377 // Movements however do need a source and source parent so the file can be moved back to the correct place. 378 Gatherer.c_man.undo.addUndo(job.ID(), UndoManager.FILE_MOVE, job.source, (FileNode)origin_node.getParent(), job.target, directory_record, job.undo); 379 } 380 } 381 } 382 // Else inform the users that a directory already exists and files will be copied into it 383 //else { 384 // JOptionPane.showMessageDialog(null, Dictionary.get("FileActions.Directory_Exists", target_file.toString()), Dictionary.get("General.Warning"), JOptionPane.WARNING_MESSAGE); 385 //} 386 // Queue non-filtered child files for copying. If this directory already existed, the child records will have to generate the undo jobs, as we don't want to entirely delete this directory if it already existed. 387 FileNode child_record = null; 388 // In order to have a sane copy proceedure (rather than always copying last file first as it used to) we always add the child node at the position the parent was removed from. Consider the file job 'a' at the end of the queue which generates three new jobs 'b', 'c' and 'd'. The resulting flow should look like this. 389 // -- Starting queue ...[a] 390 // remove(position) = 'a' ... 391 // add(position, 'b') ...[b] 392 // add(position, 'c') ...[c][b] 393 // add(position, 'd') ...[d][c][b] 394 // Next loop 395 // remove(position) = 'b' ...[d][c] 396 for(int i = 0; i < origin_node.getChildCount(); i++) { 397 child_record = (FileNode) origin_node.getChildAt(i); 398 addJob(job.ID(), job.source, child_record, job.target, directory_record, job.type, job.undo, false, false, position); 399 } 400 child_record = null; 401 directory_record = null; 402 } 403 // The file wasn't found! 404 else { 405 cancel_action = true; 406 // Show warning. 407 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("FileActions.File_Not_Found_Message", source_file.getName()), Dictionary.get("FileActions.File_Not_Found_Title"), JOptionPane.ERROR_MESSAGE); 408 // Force refresh of source folder. 409 source_model.refresh(new TreePath(((FileNode)origin_node.getParent()).getPath())); 410 } 411 412 // We can't have been cancelled, and we must have created a new FileNode during the above phase, before we can handle metadata. 413 if(!cancel_action && new_node != null) { 436 437 // We can't have been cancelled, and we must have created a new FileNode during the above phase, before we can handle metadata. 438 if(!cancel_action && new_node != null) { 414 439 /* Time to handle any existing metadata. */ 415 440 // If the directory came from inside our collection... 416 if (job.source.toString().equals("Collection")) {417 418 419 420 421 422 423 424 425 426 427 }441 if (job.source.toString().equals("Collection")) { 442 ///ystem.err.println("Move within collection..."); 443 GDMManager gdm = Gatherer.c_man.getCollection().gdm; 444 // we just retrieve the metadata attached to the origin node... 445 ArrayList existing_metadata = gdm.getMetadataOnly(source_file); 446 ///atherer.println("Existing metadata for " + origin_node + ": " + gdm.toString(existing_metadata)); 447 // then assign this remainder to the new folder. 448 ///ystem.err.println("New metadata: " + gdm.toString(existing_metadata)); 449 gdm.addMetadata(new_node, existing_metadata); 450 existing_metadata = null; 451 gdm = null; 452 } 428 453 // If it came from the recycle bin retrieve the metadata from there, once again remembering to account for inherited metadata 429 else if (job.source.toString().equals("Undo")) {430 431 432 433 434 435 436 437 }454 else if (job.source.toString().equals("Undo")) { 455 GDMManager gdm = Gatherer.c_man.getCollection().gdm; 456 // Retrieve metadata from the recycle bin 457 ArrayList existing_metadata = Gatherer.c_man.undo.getMetadata(source_file); 458 // then assign this remainder to the new folder. 459 gdm.addMetadata(new_node, existing_metadata); 460 existing_metadata = null; 461 gdm = null; 462 } 438 463 // Otherwise if it came from the workspace use the MSMs parsers to search for folder level metadata (such as metadata.xml or marc records). 439 else if (job.source.toString().equals("Workspace")) {440 441 }442 443 444 464 else if (job.source.toString().equals("Workspace")) { 465 cancel_action = !Gatherer.c_man.getCollection().msm.searchForMetadata(new_node, origin_node, job.folder_level); 466 } 467 } 468 new_node = null; 469 } 445 470 } 446 471 }
Note:
See TracChangeset
for help on using the changeset viewer.