mirror of
				https://github.com/arsenetar/dupeguru.git
				synced 2025-09-11 17:58:17 +00:00 
			
		
		
		
	[#14 state:port] Changed the results export method to a pure python (and simpler) one.
--HG-- extra : convert_revision : svn%3Ac306627e-7827-47d3-bdf0-9a457c9553a1/trunk%40106
This commit is contained in:
		
							parent
							
								
									7112c57b92
								
							
						
					
					
						commit
						4eebc7bb2c
					
				| @ -20,7 +20,7 @@ http://www.hardcoded.net/licenses/hs_license | ||||
| - (void)saveIgnoreList; | ||||
| - (void)clearIgnoreList; | ||||
| - (void)purgeIgnoreList; | ||||
| - (NSString *)exportToXHTMLwithColumns:(NSArray *)aColIds xslt:(NSString *)xsltPath css:(NSString *)cssPath; | ||||
| - (NSString *)exportToXHTMLwithColumns:(NSArray *)aColIds; | ||||
| 
 | ||||
| - (NSNumber *)doScan; | ||||
| 
 | ||||
|  | ||||
| @ -36,6 +36,8 @@ http://www.hardcoded.net/licenses/hs_license | ||||
| - (NSString *)logoImageName; | ||||
| 
 | ||||
| /* Helpers */ | ||||
| - (NSArray *)getColumnsOrder; | ||||
| - (NSDictionary *)getColumnsWidth; | ||||
| - (NSArray *)getSelected:(BOOL)aDupesOnly; | ||||
| - (NSArray *)getSelectedPaths:(BOOL)aDupesOnly; | ||||
| - (void)updatePySelection; | ||||
| @ -48,6 +50,7 @@ http://www.hardcoded.net/licenses/hs_license | ||||
| - (IBAction)copyMarked:(id)sender; | ||||
| - (IBAction)deleteMarked:(id)sender; | ||||
| - (IBAction)expandAll:(id)sender; | ||||
| - (IBAction)exportToXHTML:(id)sender; | ||||
| - (IBAction)moveMarked:(id)sender; | ||||
| - (IBAction)switchSelected:(id)sender; | ||||
| - (IBAction)togglePowerMarker:(id)sender; | ||||
|  | ||||
| @ -75,6 +75,37 @@ http://www.hardcoded.net/licenses/hs_license | ||||
| } | ||||
| 
 | ||||
| /* Helpers */ | ||||
| //Returns an array of identifiers, in order. | ||||
| - (NSArray *)getColumnsOrder | ||||
| { | ||||
|     NSTableColumn *col; | ||||
|     NSString *colId; | ||||
|     NSMutableArray *result = [NSMutableArray array]; | ||||
|     NSEnumerator *e = [[matches tableColumns] objectEnumerator]; | ||||
|     while (col = [e nextObject]) | ||||
|     { | ||||
|         colId = [col identifier]; | ||||
|         [result addObject:colId]; | ||||
|     } | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| - (NSDictionary *)getColumnsWidth | ||||
| { | ||||
|     NSMutableDictionary *result = [NSMutableDictionary dictionary]; | ||||
|     NSTableColumn *col; | ||||
|     NSString *colId; | ||||
|     NSNumber *width; | ||||
|     NSEnumerator *e = [[matches tableColumns] objectEnumerator]; | ||||
|     while (col = [e nextObject]) | ||||
|     { | ||||
|         colId = [col identifier]; | ||||
|         width = [NSNumber numberWithFloat:[col width]]; | ||||
|         [result setObject:width forKey:colId]; | ||||
|     } | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| - (NSArray *)getSelected:(BOOL)aDupesOnly | ||||
| { | ||||
|     if (_powerMode) | ||||
| @ -185,6 +216,12 @@ http://www.hardcoded.net/licenses/hs_license | ||||
|         [matches expandItem:[matches itemAtRow:i]]; | ||||
| } | ||||
| 
 | ||||
| - (IBAction)exportToXHTML:(id)sender | ||||
| { | ||||
|     NSString *exported = [py exportToXHTMLwithColumns:[self getColumnsOrder]]; | ||||
|     [[NSWorkspace sharedWorkspace] openFile:exported]; | ||||
| } | ||||
| 
 | ||||
| - (IBAction)moveMarked:(id)sender | ||||
| { | ||||
|     int mark_count = [[py getMarkCount] intValue]; | ||||
|  | ||||
| @ -19,7 +19,7 @@ from hsutil.reg import RegistrableApplication, RegistrationRequired | ||||
| from hsutil.misc import flatten, first | ||||
| from hsutil.str import escape | ||||
| 
 | ||||
| from . import directories, results, scanner | ||||
| from . import directories, results, scanner, export | ||||
| 
 | ||||
| JOB_SCAN = 'job_scan' | ||||
| JOB_LOAD = 'job_load' | ||||
| @ -177,6 +177,20 @@ class DupeGuru(RegistrableApplication): | ||||
|         self._demo_check() | ||||
|         self._start_job(JOB_DELETE, self._do_delete) | ||||
|      | ||||
|     def export_to_xhtml(self, column_ids): | ||||
|         column_ids = [colid for colid in column_ids if colid.isdigit()] | ||||
|         column_ids = map(int, column_ids) | ||||
|         column_ids.sort() | ||||
|         colnames = [col['display'] for i, col in enumerate(self.data.COLUMNS) if i in column_ids] | ||||
|         rows = [] | ||||
|         for group in self.results.groups: | ||||
|             for dupe in group: | ||||
|                 data = self.data.GetDisplayInfo(dupe, group) | ||||
|                 row = [data[colid] for colid in column_ids] | ||||
|                 row.insert(0, dupe is not group.ref) | ||||
|                 rows.append(row) | ||||
|         return export.export_to_xhtml(colnames, rows) | ||||
|      | ||||
|     def load(self): | ||||
|         self._start_job(JOB_LOAD, self._do_load) | ||||
|         self.load_ignore_list() | ||||
|  | ||||
| @ -17,7 +17,7 @@ from hsutil.cocoa import install_exception_hook | ||||
| from hsutil.misc import stripnone | ||||
| from hsutil.reg import RegistrationRequired | ||||
| 
 | ||||
| import export, app, data | ||||
| import app, data | ||||
| 
 | ||||
| JOBID2TITLE = { | ||||
|     app.JOB_SCAN: "Scanning for duplicates", | ||||
| @ -116,16 +116,6 @@ class DupeGuru(app.DupeGuru): | ||||
|     copy_or_move_marked = demo_method(app.DupeGuru.copy_or_move_marked) | ||||
|     delete_marked = demo_method(app.DupeGuru.delete_marked) | ||||
| 
 | ||||
|     def ExportToXHTML(self,column_ids,xslt_path,css_path): | ||||
|         columns = [] | ||||
|         for index,column in enumerate(self.data.COLUMNS): | ||||
|             display = column['display'] | ||||
|             enabled = str(index) in column_ids | ||||
|             columns.append((display,enabled)) | ||||
|         xml_path = op.join(self.appdata,'results_export.xml') | ||||
|         self.results.save_to_xml(xml_path,self.data.GetDisplayInfo) | ||||
|         return export.export_to_xhtml(xml_path,xslt_path,css_path,columns) | ||||
|      | ||||
|     def MakeSelectedReference(self): | ||||
|         self.make_reference(self.selected_dupes) | ||||
|      | ||||
|  | ||||
| @ -7,60 +7,132 @@ | ||||
| # which should be included with this package. The terms are also available at  | ||||
| # http://www.hardcoded.net/licenses/hs_license | ||||
| 
 | ||||
| from xml.dom import minidom | ||||
| import tempfile | ||||
| import os.path as op | ||||
| import os | ||||
| from StringIO import StringIO | ||||
| from tempfile import mkdtemp | ||||
| 
 | ||||
| from hsutil.files import FileOrPath | ||||
| # Yes, this is a very low-tech solution, but at least it doesn't have all these annoying dependency | ||||
| # and resource problems. | ||||
| 
 | ||||
| def output_column_xml(outfile, columns): | ||||
|     """Creates a xml file outfile with the supplied columns. | ||||
|      | ||||
|     outfile can be a filename or a file object. | ||||
|     columns is a list of 2 sized tuples (display,enabled) | ||||
|     """ | ||||
|     doc = minidom.Document() | ||||
|     root = doc.appendChild(doc.createElement('columns')) | ||||
|     for display,enabled in columns: | ||||
|         col_node = root.appendChild(doc.createElement('column')) | ||||
|         col_node.setAttribute('display', display) | ||||
|         col_node.setAttribute('enabled', {True:'y',False:'n'}[enabled]) | ||||
|     with FileOrPath(outfile, 'wb') as fp: | ||||
|         doc.writexml(fp, '\t','\t','\n', encoding='utf-8') | ||||
| MAIN_TEMPLATE = u""" | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'> | ||||
| <html xmlns="http://www.w3.org/1999/xhtml"> | ||||
| <head> | ||||
|     <meta content="text/html; charset=utf-8" http-equiv="Content-Type"/> | ||||
| 	<title>dupeGuru Results</title> | ||||
| 	<style type="text/css"> | ||||
| BODY | ||||
| { | ||||
| 	background-color:white; | ||||
| } | ||||
| 
 | ||||
| def merge_css_into_xhtml(xhtml, css): | ||||
|     with FileOrPath(xhtml, 'r+') as xhtml: | ||||
|         with FileOrPath(css) as css: | ||||
|             try: | ||||
|                 doc = minidom.parse(xhtml) | ||||
|             except Exception: | ||||
|                 return False | ||||
|             head = doc.getElementsByTagName('head')[0] | ||||
|             links = head.getElementsByTagName('link') | ||||
|             for link in links: | ||||
|                 if link.getAttribute('rel') == 'stylesheet': | ||||
|                     head.removeChild(link) | ||||
|             style = head.appendChild(doc.createElement('style')) | ||||
|             style.setAttribute('type','text/css') | ||||
|             style.appendChild(doc.createTextNode(css.read())) | ||||
|             xhtml.truncate(0) | ||||
|             doc.writexml(xhtml, '\t','\t','\n', encoding='utf-8') | ||||
|             xhtml.seek(0) | ||||
|     return True | ||||
| BODY,A,P,UL,TABLE,TR,TD | ||||
| { | ||||
| 	font-family:Tahoma,Arial,sans-serif; | ||||
| 	font-size:10pt; | ||||
| 	color: #4477AA; | ||||
| } | ||||
| 
 | ||||
| def export_to_xhtml(xml, xslt, css, columns, cmd='xsltproc --path "%(folder)s" "%(xslt)s" "%(xml)s"'): | ||||
|     folder = op.split(xml)[0] | ||||
|     output_column_xml(op.join(folder,'columns.xml'),columns) | ||||
|     html = StringIO() | ||||
|     cmd = cmd % {'folder': folder, 'xslt': xslt, 'xml': xml} | ||||
|     html.write(os.popen(cmd).read()) | ||||
|     html.seek(0) | ||||
|     merge_css_into_xhtml(html,css) | ||||
|     html.seek(0) | ||||
|     html_path = op.join(folder,'export.htm') | ||||
|     html_file = open(html_path,'w') | ||||
|     html_file.write(html.read().encode('utf-8')) | ||||
|     html_file.close() | ||||
|     return html_path | ||||
| TABLE | ||||
| { | ||||
| 	background-color: #225588; | ||||
| 	margin-left: auto; | ||||
|   	margin-right: auto; | ||||
| 	width: 90%; | ||||
| } | ||||
| 
 | ||||
| TR  | ||||
| { | ||||
|     background-color: white; | ||||
| } | ||||
| 
 | ||||
| TH  | ||||
| {  | ||||
| 	font-weight: bold;  | ||||
| 	color: black; | ||||
| 	background-color: #C8D6E5; | ||||
| } | ||||
| 
 | ||||
| TH TD  | ||||
| { | ||||
|     color:black; | ||||
| } | ||||
| 
 | ||||
| TD  | ||||
| { | ||||
|     padding-left: 2pt; | ||||
| } | ||||
| 
 | ||||
| TD.rightelem | ||||
| { | ||||
| 	text-align:right; | ||||
| 	/*padding-left:0pt;*/ | ||||
| 	padding-right: 2pt; | ||||
| 	width: 17%; | ||||
| } | ||||
| 
 | ||||
| TD.indented | ||||
| { | ||||
|     padding-left: 12pt; | ||||
| } | ||||
| 
 | ||||
| H1 | ||||
| { | ||||
| 	font-family:"Courier New",monospace; | ||||
| 	color:#6699CC; | ||||
|     font-size:18pt;  | ||||
| 	color:#6da500; | ||||
| 	border-color: #70A0CF; | ||||
| 	border-width: 1pt; | ||||
| 	border-style: solid; | ||||
| 	margin-top:   16pt; | ||||
| 	margin-left:  5%; | ||||
| 	margin-right: 5%; | ||||
| 	padding-top:  2pt; | ||||
| 	padding-bottom:2pt; | ||||
| 	text-align:   center; | ||||
| } | ||||
| </style> | ||||
| </head> | ||||
| <body> | ||||
| <h1>dupeGuru Results</h1> | ||||
| <table> | ||||
| <tr>$colheaders</tr> | ||||
| $rows | ||||
| </table> | ||||
| </body> | ||||
| </html> | ||||
| """ | ||||
| 
 | ||||
| COLHEADERS_TEMPLATE = u"<th>{name}</th>" | ||||
| 
 | ||||
| ROW_TEMPLATE = u""" | ||||
| <tr> | ||||
|     <td class="{indented}">{filename}</td>{cells} | ||||
| </tr> | ||||
| """ | ||||
| 
 | ||||
| CELL_TEMPLATE = u"""<td>{value}</td>""" | ||||
| 
 | ||||
| def export_to_xhtml(colnames, rows): | ||||
|     # a row is a list of values with the first value being a flag indicating if the row should be indented | ||||
|     if rows: | ||||
|         assert len(rows[0]) == len(colnames) + 1 # + 1 is for the "indented" flag | ||||
|     colheaders = u''.join(COLHEADERS_TEMPLATE.format(name=name) for name in colnames) | ||||
|     rendered_rows = [] | ||||
|     for row in rows: | ||||
|         # [2:] is to remove the indented flag + filename | ||||
|         indented = u'indented' if row[0] else u'' | ||||
|         filename = row[1] | ||||
|         cells = u''.join(CELL_TEMPLATE.format(value=value) for value in row[2:]) | ||||
|         rendered_rows.append(ROW_TEMPLATE.format(indented=indented, filename=filename, cells=cells)) | ||||
|     rendered_rows = u''.join(rendered_rows) | ||||
|     # The main template can't use format because the css code uses {} | ||||
|     content = MAIN_TEMPLATE.replace('$colheaders', colheaders).replace('$rows', rendered_rows) | ||||
|     folder = mkdtemp() | ||||
|     destpath = op.join(folder, u'export.htm') | ||||
|     fp = open(destpath, 'w') | ||||
|     fp.write(content.encode('utf-8')) | ||||
|     fp.close() | ||||
|     return destpath | ||||
|  | ||||
| @ -252,7 +252,7 @@ class Results(Markable): | ||||
|             group.clean_matches() | ||||
|         self.__dupes = None | ||||
|      | ||||
|     def save_to_xml(self, outfile, with_data=False): | ||||
|     def save_to_xml(self, outfile): | ||||
|         self.apply_filter(None) | ||||
|         outfile, must_close = open_if_filename(outfile, 'wb') | ||||
|         writer = XMLGenerator(outfile, 'utf-8') | ||||
| @ -275,14 +275,6 @@ class Results(Markable): | ||||
|                     'marked': cond(self.is_marked(d), 'y', 'n') | ||||
|                 }) | ||||
|                 writer.startElement('file', attrs) | ||||
|                 if with_data: | ||||
|                     data_list = self.data.GetDisplayInfo(d, g) | ||||
|                     for data in data_list: | ||||
|                         attrs = AttributesImpl({ | ||||
|                             'value': data, | ||||
|                         }) | ||||
|                         writer.startElement('data', attrs) | ||||
|                         writer.endElement('data') | ||||
|                 writer.endElement('file') | ||||
|             for match in g.matches: | ||||
|                 attrs = AttributesImpl({ | ||||
|  | ||||
| @ -1,86 +0,0 @@ | ||||
| # Created By: Virgil Dupras | ||||
| # Created On: 2006/09/16 | ||||
| # $Id$ | ||||
| # Copyright 2009 Hardcoded Software (http://www.hardcoded.net) | ||||
| #  | ||||
| # This software is licensed under the "HS" License as described in the "LICENSE" file,  | ||||
| # which should be included with this package. The terms are also available at  | ||||
| # http://www.hardcoded.net/licenses/hs_license | ||||
| 
 | ||||
| from xml.dom import minidom | ||||
| from StringIO import StringIO | ||||
| 
 | ||||
| from hsutil.testcase import TestCase | ||||
| 
 | ||||
| from .. import export | ||||
| from ..export import * | ||||
| 
 | ||||
| class TCoutput_columns_xml(TestCase): | ||||
|     def test_empty_columns(self): | ||||
|         f = StringIO() | ||||
|         output_column_xml(f,[]) | ||||
|         f.seek(0) | ||||
|         doc = minidom.parse(f) | ||||
|         root = doc.documentElement | ||||
|         self.assertEqual('columns',root.nodeName) | ||||
|         self.assertEqual(0,len(root.childNodes)) | ||||
|      | ||||
|     def test_some_columns(self): | ||||
|         f = StringIO() | ||||
|         output_column_xml(f,[('foo',True),('bar',False),('baz',True)]) | ||||
|         f.seek(0) | ||||
|         doc = minidom.parse(f) | ||||
|         columns = doc.getElementsByTagName('column') | ||||
|         self.assertEqual(3,len(columns)) | ||||
|         c1,c2,c3 = columns | ||||
|         self.assertEqual('foo',c1.getAttribute('display')) | ||||
|         self.assertEqual('bar',c2.getAttribute('display')) | ||||
|         self.assertEqual('baz',c3.getAttribute('display')) | ||||
|         self.assertEqual('y',c1.getAttribute('enabled')) | ||||
|         self.assertEqual('n',c2.getAttribute('enabled')) | ||||
|         self.assertEqual('y',c3.getAttribute('enabled')) | ||||
|      | ||||
| 
 | ||||
| class TCmerge_css_into_xhtml(TestCase): | ||||
|     def test_main(self): | ||||
|         css = StringIO() | ||||
|         css.write('foobar') | ||||
|         css.seek(0) | ||||
|         xhtml = StringIO() | ||||
|         xhtml.write("""<?xml version="1.0" encoding="utf-8"?> | ||||
|             <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | ||||
|             <html xmlns="http://www.w3.org/1999/xhtml"> | ||||
|             <head> | ||||
|                 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | ||||
|                 <title>dupeGuru - Duplicate file scanner</title> | ||||
|                 <link rel="SHORTCUT ICON" href="/favicon.ico" /> | ||||
|                 <link rel="stylesheet" href="../hardcoded.css" type="text/css" /> | ||||
|             </head> | ||||
|             <body> | ||||
|             </body> | ||||
|             </html>""") | ||||
|         xhtml.seek(0) | ||||
|         self.assert_(merge_css_into_xhtml(xhtml,css)) | ||||
|         xhtml.seek(0) | ||||
|         doc = minidom.parse(xhtml) | ||||
|         head = doc.getElementsByTagName('head')[0] | ||||
|         #A style node should have been added in head. | ||||
|         styles = head.getElementsByTagName('style') | ||||
|         self.assertEqual(1,len(styles)) | ||||
|         style = styles[0] | ||||
|         self.assertEqual('text/css',style.getAttribute('type')) | ||||
|         self.assertEqual('foobar',style.firstChild.nodeValue.strip()) | ||||
|         #all <link rel="stylesheet"> should be removed | ||||
|         self.assertEqual(1,len(head.getElementsByTagName('link'))) | ||||
|      | ||||
|     def test_empty(self): | ||||
|         self.assert_(not merge_css_into_xhtml(StringIO(),StringIO())) | ||||
|      | ||||
|     def test_malformed(self): | ||||
|         xhtml = StringIO() | ||||
|         xhtml.write("""<?xml version="1.0" encoding="utf-8"?> | ||||
|             <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | ||||
|             <html xmlns="http://www.w3.org/1999/xhtml">""") | ||||
|         xhtml.seek(0) | ||||
|         self.assert_(not merge_css_into_xhtml(xhtml,StringIO())) | ||||
|      | ||||
| @ -395,30 +395,6 @@ class TCResultsXML(TestCase): | ||||
|         self.assertEqual('ibabtu',d1.getAttributeNode('words').nodeValue) | ||||
|         self.assertEqual('ibabtu',d2.getAttributeNode('words').nodeValue) | ||||
|      | ||||
|     def test_save_to_xml_with_columns(self): | ||||
|         class FakeDataModule: | ||||
|             def GetDisplayInfo(self,dupe,group): | ||||
|                 return [str(dupe.size),dupe.foo.upper()] | ||||
|          | ||||
|         for i,object in enumerate(self.objects): | ||||
|             object.size = i | ||||
|             object.foo = u'bar\u00e9' | ||||
|         f = StringIO.StringIO() | ||||
|         self.results.data = FakeDataModule() | ||||
|         self.results.save_to_xml(f,True) | ||||
|         f.seek(0) | ||||
|         doc = xml.dom.minidom.parse(f) | ||||
|         root = doc.documentElement | ||||
|         g1,g2 = root.getElementsByTagName('group') | ||||
|         d1,d2,d3 = g1.getElementsByTagName('file') | ||||
|         d4,d5 = g2.getElementsByTagName('file') | ||||
|         self.assertEqual('0',d1.getElementsByTagName('data')[0].getAttribute('value')) | ||||
|         self.assertEqual(u'BAR\u00c9',d1.getElementsByTagName('data')[1].getAttribute('value')) #\u00c9 is upper of \u00e9 | ||||
|         self.assertEqual('1',d2.getElementsByTagName('data')[0].getAttribute('value')) | ||||
|         self.assertEqual('2',d3.getElementsByTagName('data')[0].getAttribute('value')) | ||||
|         self.assertEqual('3',d4.getElementsByTagName('data')[0].getAttribute('value')) | ||||
|         self.assertEqual('4',d5.getElementsByTagName('data')[0].getAttribute('value')) | ||||
|      | ||||
|     def test_LoadXML(self): | ||||
|         def get_file(path): | ||||
|             return [f for f in self.objects if str(f.path) == path][0] | ||||
|  | ||||
| @ -25,7 +25,6 @@ http://www.hardcoded.net/licenses/hs_license | ||||
|     NSMutableIndexSet *_deltaColumns; | ||||
| } | ||||
| - (IBAction)clearIgnoreList:(id)sender; | ||||
| - (IBAction)exportToXHTML:(id)sender; | ||||
| - (IBAction)filter:(id)sender; | ||||
| - (IBAction)ignoreSelected:(id)sender; | ||||
| - (IBAction)markAll:(id)sender; | ||||
| @ -47,8 +46,6 @@ http://www.hardcoded.net/licenses/hs_license | ||||
| - (IBAction)toggleDetailsPanel:(id)sender; | ||||
| 
 | ||||
| - (NSTableColumn *)getColumnForIdentifier:(int)aIdentifier title:(NSString *)aTitle width:(int)aWidth refCol:(NSTableColumn *)aColumn; | ||||
| - (NSArray *)getColumnsOrder; | ||||
| - (NSDictionary *)getColumnsWidth; | ||||
| - (void)initResultColumns; | ||||
| - (void)restoreColumnsPosition:(NSArray *)aColumnsOrder widths:(NSDictionary *)aColumnsWidth; | ||||
| @end | ||||
|  | ||||
| @ -58,14 +58,6 @@ http://www.hardcoded.net/licenses/hs_license | ||||
|     [py clearIgnoreList]; | ||||
| } | ||||
| 
 | ||||
| - (IBAction)exportToXHTML:(id)sender | ||||
| { | ||||
|     NSString *xsltPath = [[NSBundle mainBundle] pathForResource:@"dg" ofType:@"xsl"]; | ||||
|     NSString *cssPath = [[NSBundle mainBundle] pathForResource:@"hardcoded" ofType:@"css"]; | ||||
|     NSString *exported = [py exportToXHTMLwithColumns:[self getColumnsOrder] xslt:xsltPath css:cssPath]; | ||||
|     [[NSWorkspace sharedWorkspace] openFile:exported]; | ||||
| } | ||||
| 
 | ||||
| - (IBAction)filter:(id)sender | ||||
| { | ||||
|     NSUserDefaults *ud = [NSUserDefaults standardUserDefaults]; | ||||
| @ -272,37 +264,6 @@ http://www.hardcoded.net/licenses/hs_license | ||||
|     return col; | ||||
| } | ||||
| 
 | ||||
| //Returns an array of identifiers, in order. | ||||
| - (NSArray *)getColumnsOrder | ||||
| { | ||||
|     NSTableColumn *col; | ||||
|     NSString *colId; | ||||
|     NSMutableArray *result = [NSMutableArray array]; | ||||
|     NSEnumerator *e = [[matches tableColumns] objectEnumerator]; | ||||
|     while (col = [e nextObject]) | ||||
|     { | ||||
|         colId = [col identifier]; | ||||
|         [result addObject:colId]; | ||||
|     } | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| - (NSDictionary *)getColumnsWidth | ||||
| { | ||||
|     NSMutableDictionary *result = [NSMutableDictionary dictionary]; | ||||
|     NSTableColumn *col; | ||||
|     NSString *colId; | ||||
|     NSNumber *width; | ||||
|     NSEnumerator *e = [[matches tableColumns] objectEnumerator]; | ||||
|     while (col = [e nextObject]) | ||||
|     { | ||||
|         colId = [col identifier]; | ||||
|         width = [NSNumber numberWithFloat:[col width]]; | ||||
|         [result setObject:width forKey:colId]; | ||||
|     } | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| - (void)initResultColumns | ||||
| { | ||||
|     NSTableColumn *refCol = [matches tableColumnWithIdentifier:@"0"]; | ||||
|  | ||||
| @ -12,8 +12,6 @@ | ||||
| 		8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; }; | ||||
| 		8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; | ||||
| 		CE073F6309CAE1A3005C1D2F /* dupeguru_help in Resources */ = {isa = PBXBuildFile; fileRef = CE073F5409CAE1A3005C1D2F /* dupeguru_help */; }; | ||||
| 		CE0D67640ABC2D3E00E2FFD9 /* dg.xsl in Resources */ = {isa = PBXBuildFile; fileRef = CE0D67620ABC2D3E00E2FFD9 /* dg.xsl */; }; | ||||
| 		CE0D67650ABC2D3E00E2FFD9 /* hardcoded.css in Resources */ = {isa = PBXBuildFile; fileRef = CE0D67630ABC2D3E00E2FFD9 /* hardcoded.css */; }; | ||||
| 		CE381C9609914ACE003581CE /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CE381C9409914ACE003581CE /* AppDelegate.m */; }; | ||||
| 		CE381C9C09914ADF003581CE /* ResultWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CE381C9A09914ADF003581CE /* ResultWindow.m */; }; | ||||
| 		CE381D0509915304003581CE /* dg_cocoa.plugin in Resources */ = {isa = PBXBuildFile; fileRef = CE381CF509915304003581CE /* dg_cocoa.plugin */; }; | ||||
| @ -77,8 +75,6 @@ | ||||
| 		8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; }; | ||||
| 		8D1107320486CEB800E47090 /* dupeGuru.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = dupeGuru.app; sourceTree = BUILT_PRODUCTS_DIR; }; | ||||
| 		CE073F5409CAE1A3005C1D2F /* dupeguru_help */ = {isa = PBXFileReference; lastKnownFileType = folder; name = dupeguru_help; path = help/dupeguru_help; sourceTree = "<group>"; }; | ||||
| 		CE0D67620ABC2D3E00E2FFD9 /* dg.xsl */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text.xml; name = dg.xsl; path = w3/dg.xsl; sourceTree = SOURCE_ROOT; }; | ||||
| 		CE0D67630ABC2D3E00E2FFD9 /* hardcoded.css */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; name = hardcoded.css; path = w3/hardcoded.css; sourceTree = SOURCE_ROOT; }; | ||||
| 		CE381C9409914ACE003581CE /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = SOURCE_ROOT; }; | ||||
| 		CE381C9509914ACE003581CE /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = SOURCE_ROOT; }; | ||||
| 		CE381C9A09914ADF003581CE /* ResultWindow.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = ResultWindow.m; sourceTree = SOURCE_ROOT; }; | ||||
| @ -215,7 +211,6 @@ | ||||
| 				CE073F5409CAE1A3005C1D2F /* dupeguru_help */, | ||||
| 				CE381CF509915304003581CE /* dg_cocoa.plugin */, | ||||
| 				CEFC294309C89E0000D9F998 /* images */, | ||||
| 				CE0D67610ABC2D3E00E2FFD9 /* w3 */, | ||||
| 				CEEB135109C837A2004D2330 /* dupeguru.icns */, | ||||
| 				8D1107310486CEB800E47090 /* Info.plist */, | ||||
| 				089C165CFE840E0CC02AAC07 /* InfoPlist.strings */, | ||||
| @ -235,15 +230,6 @@ | ||||
| 			name = Frameworks; | ||||
| 			sourceTree = "<group>"; | ||||
| 		}; | ||||
| 		CE0D67610ABC2D3E00E2FFD9 /* w3 */ = { | ||||
| 			isa = PBXGroup; | ||||
| 			children = ( | ||||
| 				CE0D67620ABC2D3E00E2FFD9 /* dg.xsl */, | ||||
| 				CE0D67630ABC2D3E00E2FFD9 /* hardcoded.css */, | ||||
| 			); | ||||
| 			path = w3; | ||||
| 			sourceTree = "<group>"; | ||||
| 		}; | ||||
| 		CEDD92D50FDD01640031C7B7 /* brsinglelineformatter */ = { | ||||
| 			isa = PBXGroup; | ||||
| 			children = ( | ||||
| @ -375,8 +361,6 @@ | ||||
| 				CEF7823809C8AA0200EF38FF /* gear.png in Resources */, | ||||
| 				CECA899909DB12CA00A3D774 /* Details.nib in Resources */, | ||||
| 				CE3AA46709DB207900DB3A21 /* Directories.nib in Resources */, | ||||
| 				CE0D67640ABC2D3E00E2FFD9 /* dg.xsl in Resources */, | ||||
| 				CE0D67650ABC2D3E00E2FFD9 /* hardcoded.css in Resources */, | ||||
| 				CEFC7FAD0FC9518A00CD5728 /* ErrorReportWindow.xib in Resources */, | ||||
| 				CEFC7FAE0FC9518A00CD5728 /* progress.nib in Resources */, | ||||
| 				CEFC7FAF0FC9518A00CD5728 /* registration.nib in Resources */, | ||||
| @ -534,12 +518,11 @@ | ||||
| 		C01FCF5008A954540054247B /* Release */ = { | ||||
| 			isa = XCBuildConfiguration; | ||||
| 			buildSettings = { | ||||
| 				ARCHS = ( | ||||
| 					ppc, | ||||
| 					i386, | ||||
| 				); | ||||
| 				ARCHS = "$(ARCHS_STANDARD_32_BIT_PRE_XCODE_3_1)"; | ||||
| 				ARCHS_STANDARD_32_BIT_PRE_XCODE_3_1 = "ppc i386"; | ||||
| 				FRAMEWORK_SEARCH_PATHS = "@executable_path/../Frameworks"; | ||||
| 				GCC_C_LANGUAGE_STANDARD = c99; | ||||
| 				GCC_VERSION = 4.0; | ||||
| 				GCC_WARN_ABOUT_RETURN_TYPE = YES; | ||||
| 				GCC_WARN_UNUSED_VARIABLE = YES; | ||||
| 				MACOSX_DEPLOYMENT_TARGET = 10.4; | ||||
|  | ||||
| @ -41,8 +41,8 @@ class PyDupeGuru(PyApp): | ||||
|     def doScan(self): | ||||
|         return self.app.start_scanning() | ||||
|      | ||||
|     def exportToXHTMLwithColumns_xslt_css_(self,column_ids,xslt_path,css_path): | ||||
|         return self.app.ExportToXHTML(column_ids,xslt_path,css_path) | ||||
|     def exportToXHTMLwithColumns_(self, column_ids): | ||||
|         return self.app.export_to_xhtml(column_ids) | ||||
|      | ||||
|     def loadIgnoreList(self): | ||||
|         self.app.load_ignore_list() | ||||
|  | ||||
| @ -1,75 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <xsl:stylesheet version="1.0" | ||||
|                 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> | ||||
| 
 | ||||
| <xsl:output  | ||||
| 	method="xml" | ||||
| 	encoding="utf-8" | ||||
| 	doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" | ||||
| 	doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" | ||||
| 	indent="yes"/> | ||||
| 
 | ||||
| <xsl:template match="column"> | ||||
| 	<xsl:if test="@enabled = 'y'"> | ||||
| 		<th> | ||||
| 			<xsl:value-of select="@display"/> | ||||
| 		</th> | ||||
| 	</xsl:if> | ||||
| </xsl:template> | ||||
| 
 | ||||
| <xsl:template match="file"> | ||||
| 	<tr> | ||||
| 		<xsl:variable name="td_class"> | ||||
| 			<xsl:if test="position() > 1"> | ||||
| 		        <xsl:text>indented</xsl:text> | ||||
| 			</xsl:if> | ||||
| 		</xsl:variable> | ||||
| 		<xsl:variable name="file_node" select="."/> | ||||
| 		<xsl:for-each select="data"> | ||||
| 			<xsl:variable name="data_pos" select="position()"/> | ||||
| 			<xsl:if test="document('columns.xml')/columns/column[$data_pos]/@enabled = 'y'"> | ||||
| 				<td> | ||||
| 					<xsl:if test="position() = 1"> | ||||
| 						<xsl:attribute name="class"> | ||||
| 			            	<xsl:value-of select="$td_class"/> | ||||
| 			        	</xsl:attribute> | ||||
| 					</xsl:if> | ||||
| 					<xsl:value-of select="@value"/> | ||||
| 				</td> | ||||
| 			</xsl:if> | ||||
| 		</xsl:for-each> | ||||
| 		<!-- <xsl:for-each select="//results/column"> | ||||
| 			<td> | ||||
| 				<xsl:variable name="attr_name"> | ||||
| 					<xsl:text>attr_</xsl:text> | ||||
| 					<xsl:value-of select="@name"/> | ||||
| 				</xsl:variable> | ||||
| 				<xsl:value-of select="$file_node/@*[local-name(.) = $attr_name]"/> | ||||
| 			</td> | ||||
| 		</xsl:for-each> --> | ||||
| 	</tr> | ||||
| </xsl:template> | ||||
| 
 | ||||
| <xsl:template match="group"> | ||||
| 	<xsl:apply-templates select="file"/> | ||||
| </xsl:template> | ||||
| 
 | ||||
| <xsl:template match="results"> | ||||
| 	<html> | ||||
| 		<head> | ||||
| 			<title>dupeGuru Results</title> | ||||
| 			<link rel="stylesheet" href="hardcoded.css" type="text/css"/> | ||||
| 		</head> | ||||
| 		<body> | ||||
|             <h1>dupeGuru Results</h1> | ||||
| 			<table> | ||||
| 				<tr> | ||||
| 					<xsl:apply-templates select="document('columns.xml')/columns/column"/> | ||||
| 				</tr> | ||||
| 				<xsl:apply-templates select="group"/> | ||||
| 			</table> | ||||
| 		</body> | ||||
| 	</html> | ||||
| </xsl:template> | ||||
| 
 | ||||
| </xsl:stylesheet> | ||||
| @ -1,71 +0,0 @@ | ||||
| BODY | ||||
| { | ||||
| 	background-color:white; | ||||
| } | ||||
| 
 | ||||
| BODY,A,P,UL,TABLE,TR,TD | ||||
| { | ||||
| 	font-family:Tahoma,Arial,sans-serif; | ||||
| 	font-size:10pt; | ||||
| 	color: #4477AA; | ||||
| } | ||||
| 
 | ||||
| TABLE | ||||
| { | ||||
| 	background-color: #225588; | ||||
| 	margin-left: auto; | ||||
|   	margin-right: auto; | ||||
| 	width: 90%; | ||||
| } | ||||
| 
 | ||||
| TR  | ||||
| { | ||||
|     background-color: white; | ||||
| } | ||||
| 
 | ||||
| TH  | ||||
| {  | ||||
| 	font-weight: bold;  | ||||
| 	color: black; | ||||
| 	background-color: #C8D6E5; | ||||
| } | ||||
| 
 | ||||
| TH TD  | ||||
| { | ||||
|     color:black; | ||||
| } | ||||
| 
 | ||||
| TD  | ||||
| { | ||||
|     padding-left: 2pt; | ||||
| } | ||||
| 
 | ||||
| TD.rightelem | ||||
| { | ||||
| 	text-align:right; | ||||
| 	/*padding-left:0pt;*/ | ||||
| 	padding-right: 2pt; | ||||
| 	width: 17%; | ||||
| } | ||||
| 
 | ||||
| TD.indented | ||||
| { | ||||
|     padding-left: 12pt; | ||||
| } | ||||
| 
 | ||||
| H1 | ||||
| { | ||||
| 	font-family:"Courier New",monospace; | ||||
| 	color:#6699CC; | ||||
|     font-size:18pt;  | ||||
| 	color:#6da500; | ||||
| 	border-color: #70A0CF; | ||||
| 	border-width: 1pt; | ||||
| 	border-style: solid; | ||||
| 	margin-top:   16pt; | ||||
| 	margin-left:  5%; | ||||
| 	margin-right: 5%; | ||||
| 	padding-top:  2pt; | ||||
| 	padding-bottom:2pt; | ||||
| 	text-align:   center; | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user