Why does filechooser.selection add an additional waypoint? - python

When reading from fileChooser.selection I get a nearly correct path to the choosen file, but with one additional folder in the path that does not exist. It seems like fileType is added after 'MY_GUI_KIVY'. What am I missing here?
The code is part of a GUI that should help manage projects. To load the related file I need to get the path to that file. After trying to find the problem on my own, searching the net to find similar problems and eventually adopt their given solutions, I could not find a working solution.
def loadFile(self, fileType):
self.getPath(fileType)
# code shortened for better readability
return
def getPath(self, fileType):
# create popup layout
content = BoxLayout(orientation='vertical', spacing=5)
popup_width = 500
self.popup = popup = Popup(title='Open ' + str(fileType), content=content, size_hint=(None, 0.9), width=popup_width)
# create the filechooser
initDir = 'projects'
if not fileType == 'project':
initDir += '\\' + fileType
initDir = initDir + '\\'
textinput = FileChooserListView(path=initDir, size_hint=(1, 1), dirselect=False, filters=['*.' + fileType])
self.textinput = textinput
# construct the content
content.add_widget(textinput)
# 2 buttons are created for accept or cancel the current value
btnlayout = BoxLayout(size_hint_y=None, height='50dp', spacing='5dp')
btn = Button(text='Ok')
btn.bind(on_release=partial(self.loadSelectedFile, fileType, textinput, popup))
btnlayout.add_widget(btn)
btn = Button(text='Cancel')
btn.bind(on_release=popup.dismiss)
btnlayout.add_widget(btn)
content.add_widget(btnlayout)
# all done, open the popup !
popup.open()
return
def loadSelectedFile(self, fileType, fileChooser, popup, *args): # *args ist unnötig, aber da die partial den Button auch noch zwingend mitliefert...
log.debug(str(fileChooser.selection))
# code shortened for better readability
return True
Sorry, I'm not allowed to post images yet. Link should show the Image. Shows
order structure - I had to blur some folders but they are not linked to the problem
If I set fileType to 'project', the output is something like that:
'C:\GUI\MY_KIVY_GUI\projects\projects\test.project'
The expected path should have been: 'C:\GUI\MY_KIVY_GUI\projects\test.project'
If fileType is set to 'subproject', the output looks like this:
'C:\GUI\MY_KIVY_GUI\projects\subproject\projects\subproject\test.subproject'
The correct path should have been the following:
'C:\GUI\MY_KIVY_GUI\projects\subproject\test.subproject'
So it seems like initDir is added after 'MY_KIVY_GUI' but I don't get why this happens.

I see the same behavior that you described. I think you may have discovered a bug in the FileChooser code. I think your code should work as written. However, a work around is to add the line:
initDir = os.path.abspath(initDir)
just before you create the FileChooserListView. This uses an absolute path instead of a relative path, and seems to work.

Related

Getting icon from external applications

I am trying to prepare an application similar to 'Windows Start Menu Search'.
That's why I need each applications own icon.
From the C:\ProgramData\Start Menu\Programs\ file path, I add existing applications to a list (QListWidget) with their names and path.
And I get the icons like this:
https://forum.qt.io/topic/62866/getting-icon-from-external-applications
provider = QFileIconProvider()
info = QFileInfo("program_path")
icon = QIcon(provider.icon(info))
And naturally the result is this:
But I don't want this "shortcut icon" to appear.
Then, I am thinking and I came to this conclusion:
shell = win32com.client.Dispatch("WScript.Shell")
provider = QFileIconProvider()
shortcut = shell.CreateShortCut(programPath)
info = QFileInfo(shortcut.targetPath)
icon = QIcon(provider.icon(info))
This solution worked. But, It has created issue for some applications.
So I am looking for an alternative solution.
You were almost there.
Browsing the menu directory tree is actually the right path, but you also have to ensure that the icon of the link is actually the same of the target, as it might not.
The shortcut.iconlocation is a string representing a "tuple" (sort of) including the icon path and the index (as icon resources might contain more than one icon).
>>> shortcut = shell.createShortCut(linkPath)
>>> print(shortcut.iconlocation)
# most links will return this:
> ",0"
# some might return this:
> ",4"
# or this:
> "C:\SomePath\SomeProgram\SomeExe.exe,5"
As long as the icon index is 0, you can get the icon using QFileIconProvider with the targetPath or iconLocation (if there's something before the comma).
The problem comes when there's a value different from 0 for the icon index, as Qt doesn't handle that.
I've put together a simple function (based on some research here on StackOverflow).
def getIcon(self, shortcut):
iconPath, iconId = shortcut.iconLocation.split(',')
iconId = int(iconId)
if not iconPath:
iconPath = shortcut.targetPath
iconPath = os.path.expandvars(iconPath)
if not iconId:
return QICon(self.iconProvider.icon(QFileInfo(iconPath)))
iconRes = win32gui.ExtractIconEx(iconPath, iconId)
hdc = win32ui.CreateDCFromHandle(win32gui.GetDC(0))
hbmp = win32ui.CreateBitmap()
# I think there's a way to find available icon sizes, I'll leave it up to you
hbmp.CreateCompatibleBitmap(hdc, 32, 32)
hdc = hdc.CreateCompatibleDC()
hdc.SelectObject(hbmp)
hdc.DrawIcon((0, 0), iconRes[0][0])
hdc.DeleteDC()
# the original QtGui.QPixmap.fromWinHBITMAP is now part of the
# QtWin sub-module
return QtGui.QIcon(QtWin.fromWinHBITMAP(hbmp.GetHandle(), 2))

Python, returning data collected in npyscreen

So I'm creating a basic TUI for a script I created. The goal is to collect several variables that include paths to directories and files. What I'm not sure about is once I've created the visual aspect of it, how to get those pieces of information to interact with other parts of the code.
Below is what I have so far in terms of the visual portion (the other part is about 500 lines), and honestly I'm at a loss on how to even print any of the variables set under the class and any pointers would be greatly appreciated.
#!/usr/bin/env python
# encoding: utf-8
import npyscreen
class PlistCreator(npyscreen.NPSApp):
def main(self):
screen = npyscreen.Form(name="Welcome to Nicks Playlist Creator!")
plistName = screen.add(npyscreen.TitleText, name="Playlist Name:" )
csvPath = screen.add(npyscreen.TitleFilenameCombo, name="CSV Schedule:")
toaPath = screen.add(npyscreen.TitleFilenameCombo, name="Path to ToA Video Folder:", use_two_lines=True)
outputPath = screen.add(npyscreen.TitleFilenameCombo, name = "Output Folder:", use_two_lines=True)
dateOfAir = screen.add(npyscreen.TitleDateCombo, name="Date of Air:")
timeOfStart = screen.add(npyscreen.TitleText, name="Time of Air (TC):")
screen.edit()
if __name__ == "__main__":
App = PlistCreator()
App.run()
You can get the value of any form object using the dit notation.
plistName = screen.add(npyscreen.TitleText, name="Playlist Name:" )
playlist_name = self.screen.plistName.value
etc. Note there are no parentheses after value. Once you have it in a variable, you can build another method in the class to handle the information.

Sublime Text 3 Plugin changing run to on_pre_save

I have been working on a Sublime Text 3 plugin that fixes some coding standards I have at work(That I have a bad habit of missing) I currently have this working with a command run in the console. Most of the code was originally from this thread.
import sublime, sublime_plugin
class ReplaceCommand(sublime_plugin.TextCommand):
def run(self, edit):
#for each selected region
region = sublime.Region(0, self.view.size())
#if there is slected text
if not region.empty():
#get the selected region
s = self.view.substr(region)
#perform the replacements
s = s.replace('){', ') {')
s = s.replace('}else', '} else')
s = s.replace('else{', 'else {')
#send the updated string back to the selection
self.view.replace(edit, region, s)
Then you just need to run:
view.run_command('replace')
And it will apply the coding standards(there are more I plan to implement but for now i'll stick with these) I would like this to run on save.
I tried just changing run(self, edit) to on_pre_save(self, edit) but it does not work. I don't get any syntax errors but It just doesn't work.
Can anyone tell me how to make this run on save instead of having to run the command?
On ST3 the only way to get an Edit object is by running a TextCommand. (It's in the docs, but they're not terribly clear). But, fortunately, you can run the command pretty much the same way you have been doing.
Events handlers, like on_pre_save, can only be defined on an EventListener. The on_pre_save() event is passed a view object so you just need to add something like this, which kicks-off the command you've already written.
class ReplaceEventListener(sublime_plugin.EventListener):
def on_pre_save(self, view):
view.run_command('replace')
The Solutions I came to was to create an on_pre_save() function that runs the command I listed earlier:
import sublime, sublime_plugin
class ReplaceCodeStandardsCommand(sublime_plugin.TextCommand):
def run(self, edit):
#for each selected region
region = sublime.Region(0, self.view.size())
#if there is slected text
if not region.empty():
#get the selected region
s = self.view.substr(region)
#perform the replacements
s = s.replace('){', ') {')
s = s.replace('}else', '} else')
s = s.replace('else{', 'else {')
#send the updated string back to the selection
self.view.replace(edit, region, s)
class ReplaceCodeStandardsOnSave(sublime_plugin.EventListener):
# Run ST's 'unexpand_tabs' command when saving a file
def on_pre_save(self, view):
if view.settings().get('update_code_standard_on_save') == 1:
view.window().run_command('replace_code_standards')
Hopefully this code helps someone!

How to get the file name and show it on Qlistwidget?

I want to make a song list by open the QfileDialog to add the file .
Now I can play the song of list , When I click the item of QlistWidget.
But the item name is its path .
I want to show the file name on QlistWidget .
And when I click the item of QlistWidget , it has to transfer the path to openaudio() method .
Here is part of code :
expand='Image Files(*.mp3 *.wav)'
tips=open the file''
path = QtGui.QFileDialog.getOpenFileName(self, tips,QtGui.QDesktopServices.storageLocation(QtGui.QDesktopServices.MusicLocation), expand)
if path:
mlist.append(path)
index=mlist.index(path)
self.ui.listWidget.insertItem(index,mlist[index])
Here is code of openaudio() :
def openaudio(self,path):
self.connect(self.ui.listWidget,QtCore.SIGNAL('currentTextChanged(QString)'),self.ui.label_4,QtCore.SLOT('setText(QString)'))
index=self.ui.listWidget.currentRow()
path=mlist[index]
self.mediaObject.setCurrentSource(phonon.Phonon.MediaSource(path))
self.mediaObject.play()
By the way ,how can I open multiple files at once ?
One way would be subclassing QListWidgetItem:
class MyItem(QListWidgetItem):
def __init__(self, path, parent=None):
self.path = path
import os
filename = os.path.basename(self.path)
super().__init__(filename)
And then connecting your QListWidget to your openaudio(path) method:
self.ui.listWidget.itemClicked.connect(lambda n: openaudio(n.path))
Apart from that specific question your code seems to have some other issues. Using an additional list (mlist) is not needed in this particular case:
path = QtGui.QFileDialog.getOpenFileName(self, tips, QtGui.QDesktopServices.storageLocation(QtGui.QDesktopServices.MusicLocation), expand)
if path:
self.ui.listWidget.addItem(MyItem(path))
and
def openaudio(self, path):
# Do not do this here! Connections should usually be made in the init() method of the container!
# self.connect(self.ui.listWidget,QtCore.SIGNAL('currentTextChanged(QString)'),self.ui.label_4,QtCore.SLOT('setText(QString)'))
# Also take a look at the 'new' PyQt signals & slots style:
# self.ui.listWidget.currentTextChanged.connect(self.ui.label_4.setText)
self.mediaObject.setCurrentSource(phonon.Phonon.MediaSource(path))
self.mediaObject.play()

Provide tab title with reportlab generated pdf

This question is really simple, but I can't find any data on it.
When I generate a pdf with reportlab, passing the httpresponse as a file, browsers that are configured to show files display the pdf correctly. However, the title of the tab remains "(Anonymous) 127.0.0.1/whatnot", which is kinda ugly for the user.
Since most sites are able to somehow display an appropiate title, I think it's doable... Is there some sort of title parameter that I can pass to the pdf? Or some header for the response? This is my code:
def render_pdf_report(self, context, file_name):
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'filename="{}"'.format(file_name)
document = BaseDocTemplate(response, **self.get_create_document_kwargs())
# pdf generation code
document.build(story)
return response
Seems that Google Chrome doesn't display the PDF titles at all.
I tested the link in your comment (biblioteca.org.ar) and it displays in Firefox as " - 211756.pdf", seems there's an empty title and Firefox then just displays the filename instead of the full URL path.
I reproduced the same behaviour using this piece of code:
from reportlab.pdfgen import canvas
c = canvas.Canvas("hello.pdf")
c.setTitle("hello stackoverflow")
c.drawString(100, 750, "Welcome to Reportlab!")
c.save()
Opening it in Firefox yields the needed result:
I found out about setTitle in ReportLab's User Guide. It has it listed on page 16. :)
I was also looking for this and I found this in the source code.
reportlab/src/reportlab/platypus/doctemplate.py
# line - 467
We can set the document's title by
document.title = 'Sample Title'
I realise this is an old question but dropping in an answer for anyone using SimpleDocTemplate. The title property can be set in constructor of SimpleDocTemplate as a kwarg. e.g.
doc = SimpleDocTemplate(pdf_bytes, title="my_pdf_title")
If you are using trml2pdf, you will need to add the "title" attribute in the template tag, ie., <template title="Invoices" ...
In addition to what others have said, you can use
Canvas.setTitle("yourtitle")
which shows up fine in chrome.

Categories