@ -7,10 +7,11 @@ Created on Wed May 29 00:02:24 2019 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					"""  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					import  sys ,  fitz ,  io ,  subprocess ,  os  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					from  copy  import  copy  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					from  PyQt5.QtWidgets  import  QApplication ,  QAction ,  QLabel ,  QDialogButtonBox ,  QDialog ,  QFileDialog ,  QMessageBox ,  QPushButton ,  QLineEdit ,  QCheckBox ,  QSpinBox ,  QDoubleSpinBox ,  QTableWidget ,  QTableWidget Item,  QTabWidget ,  QComboBox ,  QWidget ,  QScrollArea  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					from  PyQt5.QtCore  import  QFile ,  QObject ,  Qt  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					from  PyQt5.QtGui  import  QPixmap ,  QImage  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					from  PyQt5.QtWidgets  import  QApplication ,  QAction ,  QLabel ,  QDialogButtonBox ,  QDialog ,  QFileDialog ,  QMessageBox ,  QPushButton ,  QLineEdit ,  QCheckBox ,  QSpinBox ,  QDoubleSpinBox ,  QTableWidgetItem ,  QTabWidget ,  QComboBox ,  QWidget ,  QScrollArea ,  QMainWindow ,  QShortcut  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					from  PyQt5.QtCore  import  QFile ,  QObject ,  Qt ,  pyqtSlot ,  QSettings  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					from  PyQt5.QtGui  import  QPixmap ,  QImage ,  QKeySequence  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					from  PyQt5  import  uic  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					from  chordsheet.tableView  import  ChordTableView ,  BlockTableView  ,  MItemModel ,  MProxyStyle  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					  
				
			 
			
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
				 
				
					@ -23,38 +24,78 @@ from chordsheet.document import Document, Style, Chord, Block 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					from  chordsheet.render  import  savePDF  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					from  chordsheet.parsers  import  parseFingering ,  parseName  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					# set the directory where our files are depending on whether we're running a pyinstaller binary or not  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					if  getattr ( sys ,  ' frozen ' ,  False ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    scriptDir  =  sys . _MEIPASS  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					else :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    scriptDir  =  os . path . abspath ( os . path . dirname ( os . path . abspath ( __file__ ) ) )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					QApplication . setAttribute ( Qt . AA_EnableHighDpiScaling ,  True )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					QApplication . setAttribute ( Qt . AA_EnableHighDpiScaling ,  True )  # enable automatic high DPI scaling on Windows  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					QApplication . setOrganizationName ( " Ivan Holmes " )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					QApplication . setOrganizationDomain ( " ivanholmes.co.uk " )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					QApplication . setApplicationName ( " Chordsheet " )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					settings  =  QSettings ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					pdfmetrics . registerFont ( TTFont ( ' FreeSans ' ,  os . path . join ( scriptDir ,  ' fonts ' ,  ' FreeSans.ttf ' ) ) )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					if  sys . platform  ==  " darwin " :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    pdfmetrics . registerFont ( TTFont ( ' HelveticaNeue ' ,  ' HelveticaNeue.ttc ' ,  subfontIndex = 0 ) )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					# dictionaries for combo boxes  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					pageSizeDict  =  { ' A4 ' : A4 ,  ' A5 ' : A5 ,  ' Letter ' : LETTER ,  ' Legal ' : LEGAL }  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					unitDict  =  { ' mm ' : mm ,  ' cm ' : cm ,  ' inch ' : inch ,  ' point ' : 1 ,  ' pica ' : pica }   # point is 1 because reportlab's native unit is points.  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					class  DocumentWindow ( QWidget ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  __init__ ( self ,  doc ,  style ,  parent = None ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        super ( ) . __init__ ( parent )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					class  DocumentWindow ( QMainWindow ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    Class  for  the  main  window  of  the  application .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  __init__ ( self ,  doc ,  style ,  filename = None ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        Initialisation  function  for  the  main  window  of  the  application .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        Arguments :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        doc  - -  the  Document  object  for  the  window  to  use  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        style  - -  the  Style  object  for  the  window  to  use  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        super ( ) . __init__ ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					         
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . doc  =  doc  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . style  =  style  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					         
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . lastDoc  =  copy ( self . doc )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . currentFilePath  =  filename  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . UIFileLoader ( str ( os . path . join ( scriptDir ,  ' ui ' , ' mainwindow.ui ' ) ) )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . UIInitStyle ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        # self.UIInitDocument()  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . setCentralWidget ( self . window . centralWidget )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . setMenuBar ( self . window . menuBar )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . setWindowTitle ( " Chordsheet " )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        if  filename :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            try :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                self . doc . loadXML ( filename )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            except :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                UnreadableMessageBox ( ) . exec ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  closeEvent ( self ,  event ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        Reimplement  the  built  in  closeEvent  to  allow  asking  the  user  to  save .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . saveWarning ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					         
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  UIFileLoader ( self ,  ui_file ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        Loads  the  . ui  file  for  this  window  and  connects  the  UI  elements  to  their  actions .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        ui_file  =  QFile ( ui_file )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        ui_file . open ( QFile . ReadOnly )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window  =  uic . loadUi ( ui_file )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        ui_file . close ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					         
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        # link all the UI elements  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . actionAbout . triggered . connect ( self . menuFileAboutAction )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . actionNew . triggered . connect ( self . menuFileNewAction )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . actionOpen . triggered . connect ( self . menuFileOpenAction )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . actionSave . triggered . connect ( self . menuFileSaveAction )  
				
			 
			
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
				 
				
					@ -62,7 +103,20 @@ class DocumentWindow(QWidget): 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . actionSave_PDF . triggered . connect ( self . menuFileSavePDFAction )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . actionPrint . triggered . connect ( self . menuFilePrintAction )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . actionClose . triggered . connect ( self . menuFileCloseAction )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					         
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . actionNew . setShortcut ( QKeySequence . New )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . actionOpen . setShortcut ( QKeySequence . Open )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . actionSave . setShortcut ( QKeySequence . Save )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . actionSave_as . setShortcut ( QKeySequence . SaveAs )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . actionSave_PDF . setShortcut ( QKeySequence ( " Ctrl+E " ) )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . actionPrint . setShortcut ( QKeySequence . Print )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . actionClose . setShortcut ( QKeySequence . Close )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . actionUndo . setShortcut ( QKeySequence . Undo )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . actionRedo . setShortcut ( QKeySequence . Redo )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . actionCut . setShortcut ( QKeySequence . Cut )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . actionCopy . setShortcut ( QKeySequence . Copy )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . actionPaste . setShortcut ( QKeySequence . Paste )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . pageSizeComboBox . currentIndexChanged . connect ( self . pageSizeAction )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . documentUnitsComboBox . currentIndexChanged . connect ( self . unitAction )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
				 
				
					@ -83,21 +137,25 @@ class DocumentWindow(QWidget): 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . blockTableView . clicked . connect ( self . blockClickedAction )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					         
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  UIInitDocument ( self ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        Fills  the  window ' s fields with the values from its document.  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . updateTitleBar ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        # set all fields to appropriate values from document  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . titleLineEdit . setText ( self . doc . title )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . composerLineEdit . setText ( self . doc . composer )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . arrangerLineEdit . setText ( self . doc . arranger )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . timeSignatureSpinBox . setValue ( self . doc . timeSignature )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					         
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        # chord and block table lists here  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . chordTableView . populate ( self . doc . chordList )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . blockTableView . populate ( self . doc . blockList )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . updateChordDict ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . tabWidget . setCurrentWidget ( self . window . tabWidget . findChild ( QWidget ,  ' Overview ' ) )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        # self.updatePreview()  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					         
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  UIInitStyle ( self ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        Fills  the  window ' s fields with the values from its style.  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . pageSizeComboBox . addItems ( list ( pageSizeDict . keys ( ) ) )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . pageSizeComboBox . setCurrentText ( list ( pageSizeDict . keys ( ) ) [ 0 ] )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					         
				
			 
			
		
	
	
		
			
				
					
						
							
								 
							 
						
						
							
								 
							 
						
						
					 
				
				 
				
					@ -133,37 +191,61 @@ class DocumentWindow(QWidget): 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . blockLengthLineEdit . setText ( self . window . blockTableView . model . item ( index . row ( ) ,  1 ) . text ( ) )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . blockNotesLineEdit . setText ( self . window . blockTableView . model . item ( index . row ( ) ,  2 ) . text ( ) )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  getPath ( self ,  value ) :   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        Wrapper  for  Qt  settings  to  return  home  directory  if  no  setting  exists .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        return  str ( ( settings . value ( value )  if  settings . value ( value )  else  os . path . expanduser ( " ~ " ) ) )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  setPath ( self ,  value ,  fullpath ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        Wrapper  for  Qt  settings  to  set  path  to  open / save  from  next  time  from  current  file  location.  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        return  settings . setValue ( value ,  os . path . dirname ( fullpath ) )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  menuFileNewAction ( self ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . doc  =  Document ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . lastDoc  =  copy ( self . doc )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . currentFilePath  =  None  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . UIInitDocument ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . updatePreview ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					     
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  menuFileOpenAction ( self ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        filePath  =  QFileDialog . getOpenFileName ( self . window . tabWidget ,  ' Open file ' ,  str ( os . path . expanduser ( " ~ " ) ) ,  " Chordsheet ML files (*.xml *.cml) " )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        filePath  =  QFileDialog . getOpenFileName ( self . window . tabWidget ,  ' Open file ' ,  self . getPath ( " workingPath " ) ,  " Chordsheet ML files (*.xml *.cml) " )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        if  filePath [ 0 ] :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            self . currentFilePath  =  filePath [ 0 ]  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            self . doc . loadXML ( filePath [ 0 ] )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            self . lastDoc  =  copy ( self . doc )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            self . setPath ( " workingPath " ,  self . currentFilePath )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            self . UIInitDocument ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            self . updatePreview ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					     
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  menuFileSaveAction ( self ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . updateDocument ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        if  not  ( hasattr ( self ,  ' currentFilePath ' )  and  self . currentFilePath ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            filePath  =  QFileDialog . getSaveFileName ( self . window . tabWidget ,  ' Save file ' ,  str ( os . path . expanduser ( " ~ " ) ) ,  " Chordsheet ML files (*.xml *.cml) " )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            filePath  =  QFileDialog . getSaveFileName ( self . window . tabWidget ,  ' Save file ' ,  self . getPath ( " workingPath " ) ,  " Chordsheet ML files (*.xml *.cml) " )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            self . currentFilePath  =  filePath [ 0 ]  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . doc . saveXML ( self . currentFilePath )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . lastDoc  =  copy ( self . doc )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . setPath ( " workingPath " ,  self . currentFilePath )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					     
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  menuFileSaveAsAction ( self ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . updateDocument ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        filePath  =  QFileDialog . getSaveFileName ( self . window . tabWidget ,  ' Save file ' ,  str ( os . path . expanduser ( " ~ " ) ) ,  " Chordsheet ML files (*.xml *.cml) " )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        filePath  =  QFileDialog . getSaveFileName ( self . window . tabWidget ,  ' Save file ' ,  self . getPath ( " workingPath " ) ,  " Chordsheet ML files (*.xml *.cml) " )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        if  filePath [ 0 ] :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            self . currentFilePath  =  filePath [ 0 ]  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            self . doc . saveXML ( self . currentFilePath )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            self . lastDoc  =  copy ( self . doc )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            self . setPath ( " workingPath " ,  self . currentFilePath )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            self . updateTitleBar ( )  # as we now have a new filename  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					     
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  menuFileSavePDFAction ( self ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . updateDocument ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . updatePreview ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        filePath  =  QFileDialog . getSaveFileName ( self . window . tabWidget ,  ' Save file ' ,  str ( os . path . expanduser ( " ~ " ) ) ,  " PDF files (*.pdf) " )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        filePath  =  QFileDialog . getSaveFileName ( self . window . tabWidget ,  ' Save file ' ,  self . getPath ( " lastExportPath " ) ,  " PDF files (*.pdf) " )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        if  filePath [ 0 ] :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            savePDF ( d ,  s ,  filePath [ 0 ] )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            self . setPath ( " lastExportPath " ,  filePath [ 0 ] )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					     
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  menuFilePrintAction ( self ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        if  sys . platform  ==  " darwin " :  
				
			 
			
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
				 
				
					@ -171,9 +253,35 @@ class DocumentWindow(QWidget): 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        #    subprocess.call()  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        else :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            pass  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					             
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    @pyqtSlot ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  menuFileCloseAction ( self ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        pass  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . saveWarning ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  menuFileAboutAction ( self ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        aboutDialog  =  QMessageBox . information ( self ,  " About " ,  " Chordsheet © Ivan Holmes, 2019 " ,  buttons  =  QMessageBox . Ok ,  defaultButton  =  QMessageBox . Ok )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  saveWarning ( self ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        Function  to  check  if  the  document  has  unsaved  data  in  it  and  offer  to  save  it .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . updateDocument ( )  # update the document to catch all changes  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        if  ( self . lastDoc  ==  self . doc ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            self . close ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        else :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            wantToSave  =  UnsavedMessageBox ( ) . exec ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            if  wantToSave  ==  QMessageBox . Save :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                if  not  ( hasattr ( self ,  ' currentFilePath ' )  and  self . currentFilePath ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                    filePath  =  QFileDialog . getSaveFileName ( self . window . tabWidget ,  ' Save file ' ,  str ( os . path . expanduser ( " ~ " ) ) ,  " Chordsheet ML files (*.xml *.cml) " )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                    self . currentFilePath  =  filePath [ 0 ]  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                self . doc . saveXML ( self . currentFilePath )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                self . close ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            elif  wantToSave  ==  QMessageBox . Discard :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                self . close ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            # if cancel or anything else do nothing at all  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					     
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  guitarVoicingAction ( self ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        gdialog  =  GuitarDialog ( )  
				
			 
			
		
	
	
		
			
				
					
						
							
								 
							 
						
						
							
								 
							 
						
						
					 
				
				 
				
					@ -208,7 +316,7 @@ class DocumentWindow(QWidget): 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . doc . chordList . append ( Chord ( parseName ( self . window . chordNameLineEdit . text ( ) ) ) )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        if  self . window . guitarVoicingLineEdit . text ( ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            setattr ( self . doc . chordList [ - 1 ] ,  ' guitar ' ,   parseFingering ( self . window . guitarVoicingLineEdit . text ( ) ,  ' guitar ' ) )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            self . doc . chordList [ - 1 ] . voicings [ ' guitar ' ]  =   parseFingering ( self . window . guitarVoicingLineEdit . text ( ) ,  ' guitar ' )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . chordTableView . populate ( self . doc . chordList )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . clearChordLineEdits ( )  
				
			 
			
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
				 
				
					@ -220,7 +328,7 @@ class DocumentWindow(QWidget): 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            row  =  self . window . chordTableView . selectionModel ( ) . currentIndex ( ) . row ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            self . doc . chordList [ row ]  =  Chord ( parseName ( self . window . chordNameLineEdit . text ( ) ) )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            if  self . window . guitarVoicingLineEdit . text ( ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                setattr ( self . doc . chordList [ row ] ,  ' guitar ' ,   parseFingering ( self . window . guitarVoicingLineEdit . text ( ) ,  ' guitar ' ) )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                self . doc . chordList [ - 1 ] . voicings [ ' guitar ' ]  =   parseFingering ( self . window . guitarVoicingLineEdit . text ( ) ,  ' guitar ' )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            self . window . chordTableView . populate ( self . doc . chordList )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            self . clearChordLineEdits ( )  
				
			 
			
		
	
	
		
			
				
					
						
							
								 
							 
						
						
							
								 
							 
						
						
					 
				
				 
				
					@ -277,13 +385,20 @@ class DocumentWindow(QWidget): 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . imageLabel . setPixmap ( QPixmap . fromImage ( qtimg ) )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . window . imageLabel . repaint ( )  # necessary on Mojave with PyInstaller (or previous contents will be shown)  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					     
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  updateTitleBar ( self ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        appName  =  " Chordsheet "  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        if  self . currentFilePath :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            self . setWindowTitle ( appName  +  "  –  "  +  os . path . basename ( self . currentFilePath ) )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        else :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            self . setWindowTitle ( appName )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  updateChords ( self ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        chordTableList  =  [ ]  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        for  i  in  range ( self . window . chordTableView . model . rowCount ( ) ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            chordTableList . append ( Chord ( parseName ( self . window . chordTableView . model . item ( i ,  0 ) . text ( ) ) ) ) ,  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            if  self . window . chordTableView . model . item ( i ,  1 ) . text ( ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                chordTableList [ - 1 ] . guitar  =  parseFingering ( self . window . chordTableView . model . item ( i ,  1 ) . text ( ) ,  ' guitar ' )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					                chordTableList [ - 1 ] . voicings [ '  guitar' ]   =  parseFingering ( self . window . chordTableView . model . item ( i ,  1 ) . text ( ) ,  ' guitar ' )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					             
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . doc . chordList  =  chordTableList  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					     
				
			 
			
		
	
	
		
			
				
					
						
							
								 
							 
						
						
							
								 
							 
						
						
					 
				
				 
				
					@ -326,6 +441,10 @@ class DocumentWindow(QWidget): 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        # something for the font box here  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					         
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					class  GuitarDialog ( QDialog ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    Dialogue  to  allow  the  user  to  enter  a  guitar  chord  voicing .  Not  particularly  advanced  at  present !  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    May  be  extended  in  future .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  __init__ ( self ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        super ( ) . __init__ ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . UIFileLoader ( str ( os . path . join ( scriptDir ,  ' ui ' , ' guitardialog.ui ' ) ) )  
				
			 
			
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
				 
				
					@ -350,13 +469,40 @@ class GuitarDialog(QDialog): 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        else :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					            return  None  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					class  UnsavedMessageBox ( QMessageBox ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    Message  box  to  alert  the  user  of  unsaved  changes  and  allow  them  to  choose  how  to  act .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  __init__ ( self ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        super ( ) . __init__ ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . setWindowTitle ( " Unsaved changes " )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . setText ( " The document has been modified. " )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . setInformativeText ( " Do you want to save your changes? " )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . setStandardButtons ( QMessageBox . Save  |  QMessageBox . Discard  |  QMessageBox . Cancel )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . setDefaultButton ( QMessageBox . Save )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					class  UnreadableMessageBox ( QMessageBox ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    Message  box  to  inform  the  user  that  the  chosen  file  cannot  be  opened .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    def  __init__ ( self ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        super ( ) . __init__ ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . setWindowTitle ( " File cannot be opened " )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . setText ( " The file you have selected cannot be opened. " )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . setInformativeText ( " Please make sure it is in the right format. " )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . setStandardButtons ( QMessageBox . Ok )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					        self . setDefaultButton ( QMessageBox . Ok )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					if  __name__  ==  ' __main__ ' :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    app  =  QApplication ( sys . argv )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					     
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    d  =  Document ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    s  =  Style ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					     
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    w  =  DocumentWindow ( d ,  s )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    w . window . show ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    w  =  DocumentWindow ( d ,  s ,  filename = ( sys . argv [ 1 ]  if  len ( sys . argv )  >  1  else  None ) )  # pass first argument as filename    
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    w . show ( )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				
					    sys . exit ( app . exec_ ( ) )