I want to achieve something like the following:
Where I can select multiple folders across multiple drives and retrieve the folder paths of those selected. Qt only has a crude multi-folder selection feature, but it does not support selected folders from other drives etc.
Can anyone guide me on how to create such a dialog? Better yet, does any one have any sample code I could use (this is an extension to an old project, and I'd much rather save my time and not re-invent the wheel!)
Thanks
You can use QFileSystemModel for represent filesystem on QTreeView. This example explains how to do that.
For checkbox issue, according to this list archives:
The simplest way to do this (I can think of, at least) is to subclass
QDirModel and override flags, data and setData:
flags should add Qt::ItemIsUserCheckable to the returned flags
data should return the Qt::CheckState of the queried index if the role parameter is Qt::CheckStateRole
setData should store the check state of the index
Or, even better, this should work with a QProxyModel pretty much the
same way (after all, "favor object composition over class
inheritance").
Note that QDirModel class is obsolete. You may not use that on newer Qt versions. I recommend to use QFileSystemModel.
####### Retrieve a list of directories with wxPython-Phoenix - tested on python3.5
### installation instruction for wxPython-Phoenix : https://wiki.wxpython.org/How%20to%20install%20wxPython#Installing_wxPython-Phoenix_using_pip
### modified from : https://wxpython.org/Phoenix/docs/html/wx.lib.agw.multidirdialog.html
import os
import wx
import wx.lib.agw.multidirdialog as MDD
# Our normal wxApp-derived class, as usual
app = wx.App(0)
dlg = MDD.MultiDirDialog(None, title="Custom MultiDirDialog", defaultPath=os.getcwd(), # defaultPath="C:/Users/users/Desktop/",
agwStyle=MDD.DD_MULTIPLE|MDD.DD_DIR_MUST_EXIST)
if dlg.ShowModal() != wx.ID_OK:
print("You Cancelled The Dialog!")
dlg.Destroy()
paths = dlg.GetPaths()
#Print directories' path and files
for path in enumerate(paths):
print(path[1])
directory= path[1].replace('OS (C:)','C:')
print(directory)
for file in os.listdir(directory):
print(file)
dlg.Destroy()
app.MainLoop()
Related
I'm working on a script that does find/replace for missing items in your project. Unfortunately I'm running into a situation detecting and then replacing layered image sources (psd, ai, etc.).
1) I see no way of detecting if a AvItem is a layer within a layered image other than parsing the item.name, which is unreliable because a user can always rename items in the project panel.
2) Once I do know that it is a part of a layered image I cannot figure out how to re-link it to the correct image without replacing the layer with the merged image. item.replace(new_path) will replace that item with the whole image, not the layer within the image. For example:
var item = app.project.item(3); //assuming this is the 'layer' we want to replace
item.replace(new_path);
So is there a secret property somewhere which will reliably tell me if an item is a part of a layered image, and if so is there a way to relink it without replacing the layer with the entire merged image?
EDIT
Here's a function to guess if a layer is part of a layered image. It's not bullet-proof but it should work as long as the user does not rename the item:
function isSourceLayered (av_item) {
// check if there is a "/"
if (av_item.name.indexOf("/") != -1) {
// check if it is in a "layers" folder
if (av_item.parentFolder.name.indexOf("Layers") != -1) {
return true;
}
}
return false;
}
I just asked the same question on the Adobe extendscript forum. Unless there's undocumented features (and I spent a bit of time looking with Extendscript Toolkit's data browser) the fileSource object doesn't seem to have any attributes or methods to do this.
There is a kind of a workaround, you can import the file using ImportOptions.importAs(ImportAsType.COMP) This will import a comp, and you can loop through the layers matching the name, get the source of that layer and use that as your new source. But as you say, it doesn't work if the source has been renamed.
I've written this into a function, it's available on github Edit: I forgot that I changed the way that function works. It doesn't re-import layer sources because of this problem, it just uses the Duplicate menu command.
Newly created files in Atom are always "Plain Text". How can I change this so that new files will automatically be in another language, for example "Shell Script (Bash)"? I want to do this because auto indentation does not work with Plain Text files.
Had this problem as well, there is a plugin called default-language that will do this for you.
Search atom for default-language, install and open its settings. Type the name of the language you want Atom to default to, e.g. Shell Script (if in doubt, copy from the language selection menu) in the Default Language field. Next time you open a script with no extension (or shebang) it'll default to the language you set.
The following code, added to your init.coffee, will do what you're asking:
atom.workspace.observeTextEditors (editor) ->
default_scope = 'source.shell'
original = editor.getGrammar()
# If the editor has "null" grammar (aka unset)
if original? and original is atom.grammars.grammarForScopeName('text.plain.null-grammar')
default_grammar = atom.grammars.grammarForScopeName(default_scope)
if default_grammar? # check if desired grammar is already loaded
editor.setGrammar(default_grammar)
else
# grammar was not loaded yet, so add a callback as grammars load
callback = atom.grammars.onDidAddGrammar (grammar) ->
if grammar.id is default_scope
# once we've loaded the grammar, set it and dispose of the callback
editor.setGrammar(grammar)
callback.dispose()
Things to note:
The init.coffee file is where you can customize Atom without having to write a package
The observeTextEditors method sets a callback that is called upon each TextEditor creation for currently open and future editors
The code above:
Checks the grammar that the editor was created with
If and only if it is the default ("null") grammar, it sets the editor's grammar to the Shell grammar once it's loaded
Disposes of the callback to check for grammar loading once it's done with it
This should solve the TypeError: Cannot call method 'getScore' of undefined that happens for the first file opened in a new window.
To default to a different grammar, just change the default_scope = 'source.shell' line to use the scope of whatever grammar you'd like.
Firstly, CTRL+SHIFT+L is your friend. It's unfortunately not a permanent solution, but nice to know about.
Of course, we'd prefer a more permanent solution. A couple of the other answers are now obsolete due to API changes in Atom. Below is a more up-to-date version. Inspiration initially came from this discussion, but the other answers here seem to follow the same concept as well.
Place this in your init.coffee file (File -> Open Your Init Script):
extname = require("path").extname
fileTypes =
".wxs": "text.xml"
".wxi": "text.xml"
".wixobj": "text.xml"
nullGrammar = atom.grammars.selectGrammar("text.plain.null-grammar")
atom.workspace.observeTextEditors (editor) ->
grammar = atom.grammars.selectGrammar(fileTypes[extname(editor.getPath())])
editor.setGrammar grammar if editor.getGrammar() is nullGrammar and grammar isnt nullGrammar
Basically, you define have an array of file types, and the grammars (AKA syntax highlighting) that you want to associate them with. Find each editor, find out if it has a selected grammar already, and if not, attempt to give it one if we find one.
The one issue I've had with this is that the syntax highlighting only works if you open files after you've already launched Atom; if you open a file that results in Atom launching (say by double clicking on it's icon in your favourite OS), syntax highlighting won't for that file until you re-open it.
You need to create a mapping in your config.cson file.
"*":
core:
customFileTypes:
"source.shell": [
"sh"
"shell"
]
For mapping .sh and .shell files to shell script syntax.
Have a look at this bit of code: (you can can then change 'text.html.basic' to whichever syntax you require)
editor = atom.workspace.getActiveTextEditor()
cursor = editor.getLastCursor()
valueAtCursor = atom.config.get(cursor.getScopeDescriptor(), 'my-package.my-setting')
valueForLanguage = atom.config.get(editor.getRootScopeDescriptor('text.html.basic'), 'my-package.my-setting')
For reference please see: Scope Descriptors # https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors
When we publish some page/dynamic component from tridion is it possible to add some external multimedia file/content(ex:jpg image) in to current executing/rendering package at publish time.So that final transportation package has this binary file present along with original published content?
Is this achivable using customization of tridion renderer/resolver?If yes please provide some inputs.
*Note:*The binary content that needs to be pushed in to package at publish time is not present as multimedia component in tridion, it is located at other file location outside tridion CMS.Instead we have some stub multimedia component being used inside published component/page which has some dummy image. we plan to replace the stub image with original image at publish(rendering/resolving) time.
Since we have huge bulk of binary content stored in DAM tool we dont want that data to be recreated as multimedia component in tridion, insted we want to use that data by querying DAM tool and attach it in to tridion package with some logical referencesplanning to maintain one to one mapping between stub multimedia comp tcmid to original content in some mapping DB for reference).
Please let us know if any solution is there to attach external binary content to package at publish time.
The best - and easiest way - is to use the mechanism provided by Tridion out-of-the-box for this. Create a new multimedia component, select "External" in the resource type drop-down, and type the URL to the object. As long as you can address it with a URL, it will work exactly as you want (item will be added to package and sent to delivery server).
If this is not good enough for you, then yes, you can add it to the package yourself. I've done this in the past with code somewhat like this:
FileInfo file = // Weird logic to get a FileInfo object from external system
Item item = package.GetItem("My original Item");
item.SetAsStream(file.OpenRead());
This replaced the content of my original component with the actual file I wanted. This will work for you IF the original component is also a multimedia component. If it's not, just create a new item with your own name, etc. If possible, do use the out-of-the-box process instead.
PS: FileInfo Class.
As Nuno suggested the best way is to use multimedia component with 'External' resource type. You may not need to create these manually, you can automate using core services or API programs.
Another way I used before to create zip file at run time and add same to package with following code. Hope it may help.
using (MemoryStream ms = new MemoryStream())
{
zip.Save(ms);
downloadAllInOneURL = String.Format("ZipAsset{0}.zip", uniqueZipID);
downloadAllInOneURL = m_Engine.PublishingContext.RenderedItem.AddBinary(ms, downloadAllInOneURL, "", "application/zip").Url;
downloadAllInOneSize = getSize(ms.Length);
}
Users open files in our app through a QFileDialog. The order of the filenames is bizarre. What is determining the sorting order, and how can we make it sort by filenames, or otherwise impose our own sorting, perhaps giving it a pointer to our own comparison function?
The documentation and online forums haven't been helpful. Unless it's well hidden, there doesn't seem to be any sorting method, property, etc.
This is a primarily Linux app, but also runs on Macs. (I know nothing about Mac.)
Here is the juicy part of the source code:
QtFileDialog chooser(parent, caption, directory, filter);
/// QtFileDialog is our class derived from QFileDialog
chooser.setModal(true);
chooser.setAcceptMode(acceptMode);
chooser.setFileMode(fileMode);
QStringList hist = chooser.history();
chooser.setHistory(hist);
/* point "x" */
if(chooser.exec()) {
QStringList files = chooser.selectedFiles();
...blah blah blah...
From one of the answers, I tried an evil experiment, adding this ill-informed guesswork code at "point x":
QSortFilterProxyModel *sorter = new QSortFilterProxyModel();
sorter->sort(1); // ???
chooser.setProxyModel(sorter);
But this crashed spectacularly at a point about 33 subroutine calls deep from this level of code. I admit, even after reading the Qt4 documentation and sample code, I have no idea of the proper usage of QSortFilterProxyModel.
Are you using QFileDialog by calling exec()? If you are, you should have a button to switch the view to Detail View. This will give you some column headers that you can click on to sort the files. It should remember that mode the next time the dialog opens but you can force it by calling setViewMode(QFileDialog::Detail) before calling exec().
An alternative is to call the static function QFileDialog::getOpenFileName() which will open a file dialog that is native to the OS on which you are running. Your users may like the familiarity of this option better.
Update 1:
About sort order in screen cap from OP:
This screen capture is actually showing a sorted list. I don't know if the listing behaviour is originating from the Qt dialog or the underlying file system but I know Windows XP and later do it this way.
When sorting filenames with embedded numbers, any runs of consecutive digits are treated as a single number. With the more classic plain string sorting, files would be sorted like this:
A_A_10e0
A_A_9a05
Going character by character, the first 1 sorts before the 9.
.. But with numerical interpretation (as in Windows 7 at least), they are sorted as:
A_A_9a05
A_A_10e0
The 9 sorts before the 10.
So, the sorting you are seeing is alphabetical with numerical interpretation and not just straight character by character. Some deep digging may be required to see if that is Qt behaviour or OS behaviour and whether or not it can be configured.
Update 2:
The QSortFilterProxyModel will sort the strings alphabetically by default so there is not much work to using it to get the behavior you are looking for. Use the following code where you have "point x" in your example.. (you almost had it :)
QSortFilterProxyModel *sorter = new QSortFilterProxyModel();
sorter->setDynamicSortFilter(true); // This ensures the proxy will resort when the model changes
chooser.setProxyModel(sorter);
I think what you need to do is create a QSortFilterProxyModel which you then set in your QFileDialog with QFileDialog::setProxyModel(QAbstractProxyModel * proxyModel)
Here are some relevant links to the Qt 4.6 docs about it.
http://doc.trolltech.com/4.6/qfiledialog.html#setProxyModel
http://doc.trolltech.com/4.6/qsortfilterproxymodel.html#details
I don't think it depends upon the implementation of Qt libraries... But upon the Native OS implementation..
For example in Windows,
if you use QFileDialog, it will display the Files and Directories by Name sorted.. It is the same when used in other applications. In the sense that, if you try to open a file through MS- Word, it indeed displays the Files and directories as Name sorted by default..
And am not sure about other environments since am not used to them...
But in Windows, you can change the sorted order by right-click in the area of Files and Directories display and can select the options you like.. For e.g like Name,size,type, modified... And also which is similar, when you use an MS-Word application...
So, I believe it does depend on the Native OS implementation and not on QFileDialog's...
I am having trouble in storing the files in a string array from a directory in c++, using System::IO::Directory::GetFiles in c++
Also would like to know if we could copy an entire folder to a new destination/ in c++ like given in http://www.codeproject.com/KB/files/xdirectorycopy.aspx for c#
You can store the file names from a directory in a managed array like this:
System::String ^path = "c:\\";
cli::array<System::String ^>^ a = System::IO::Directory::GetFiles(path);
Console::WriteLine(a[0]);
Console::ReadKey();
As for how would you copy an entire folder... Simply recurse from a given root directory creating each directory and copying the files to the new location. If you are asking for code for this, then please say so, but at least try to figure it out for yourself first (i.e. show me what you have so far).
Check out the file listing program in Boost::FileSystem: http://www.boost.org/doc/libs/1_41_0/libs/filesystem/example/simple_ls.cpp. They iterate over all files, printing the paths, but it's trivial to store them instead.
Assuming you're on Win32, you're looking for the FindFirstFile and FindNextFile APIs.
C/C++ does not define a standard way to do this, though Boost::Filesystem provides a method if you need cross platform support.