I want to change the order of my blocks in a region when a user is not logged in. I tried to change the block weight but nothing happened. That's what I tried:
function mymodule_block_info_alter(&$blocks, $theme, $code_blocks) {
$blocks['views']['-exp-article-page_knowldg']['weight'] = '-16';
}
and
function mymodule_block_list_alter(&$blocks) {
$blocks['131']->weight = -20;
$blocks['185']->weight = -40;
}
I don't want to create a new region and move the block into it, it should work with one region.
Any ideas how to change block order?
Block list alter would do a static change if I'm right.
You can use modules like panels https://www.drupal.org/project/panels or Context https://www.drupal.org/project/context or CSS which can all do the job for you easily.
Related
I've got a Master/Detail DataGrid and I want to filter the details.
Here's my DataGridCollectionViewSource:
<xcdg:DataGridCollectionViewSource x:Key="Features"
Filter="ExampleFilter"
Source="{Binding Path=ItemUnderEdit.Features}"
AutoCreateDetailDescriptions="False"
AutoCreateItemProperties="False">
<xcdg:DataGridCollectionViewSource.DetailDescriptions>
<xcdg:PropertyDetailDescription RelationName="Settings"
AutoCreateDetailDescriptions="False"
AutoCreateItemProperties="False">
</xcdg:PropertyDetailDescription>
</xcdg:DataGridCollectionViewSource.DetailDescriptions>
</xcdg:DataGridCollectionViewSource>
As you can see I'm filtering it with ExampleFilter, but this only filters the master. I put a breakpoint and it never sees any details.
I cant add a filter to the Detail Descriptions in the same way. Is there any way to filter the details? Any help would be much appreciated!
I went up against this problem today - I had a simple filter for both the master and detail sections that gets turned on / off via code. For the master section, it was a simple matter of code like:
((DataGridCollectionView)grid.ItemsSource).FilterCriteriaMode = FilterCriteriaMode.None; // Off
((DataGridCollectionView)grid.ItemsSource).FilterCriteriaMode = FilterCriteriaMode.And; // On
((DataGridCollectionView)grid.ItemsSource).Refresh(); // Re-run filter.
For the details section, it should have been as simple as the following code (it wasn't though):
MyDetailDescription.FilterCriteriaMode = FilterCriteriaMode.None; // Off
MyDetailDescription.FilterCriteriaMode = FilterCriteriaMode.And; // On
Turns out, doing that will enable the new filter for any new detail sections that get generated, but not existing ones. New detail sections are generated when the master row is expanded. To get around this it turned out I needed a simple foreach loop such as:
foreach (DataGridContext context in grid.GetChildContexts()) {
((DataGridCollectionViewBase)(context.Items)).FilterCriteriaMode = PetsDetailDescriptions.FilterCriteriaMode;
}
Here's my complete(ish) code for all that:
public bool ShowDeleted {
set {
if ((grid.ItemsSource != null) && (grid.ItemsSource.GetType() == DataGridCollectionView));
DataGridCollectionView v = ((DataGridCollectionView)(grid.ItemsSource));
if (value) {
v.FilterCriteriaMode = FilterCriteriaMode.None;
MyDetailDescription.FilterCriteriaMode = FilterCriteriaMode.None;
}
else {
v.FilterCriteriaMode = FilterCriteriaMode.And;
MyDetailDescription.FilterCriteriaMode = FilterCriteriaMode.And;
}
foreach (DataGridContext context in grid.GetChildContexts()) {
((DataGridCollectionViewBase)(context.Items)).FilterCriteriaMode = PetsDetailDescriptions.FilterCriteriaMode;
}
v.Refresh();
}
}
}
I'm using that in-conjunction with a simple predefined filter criterion in the XAML. IE:
<g:DataGridItemProperty Name="IsDeleted"
DataType="{x:Type sys:Boolean}">
<g:DataGridItemProperty.FilterCriterion>
<g:EqualToFilterCriterion>
<sys:Boolean>False</sys:Boolean>
</g:EqualToFilterCriterion>
</g:DataGridItemProperty.FilterCriterion>
</g:DataGridItemProperty>
I recommend using the Xaml FilterCriterions, because if you absolutely need the Filter event, it's going to get a bit more messy. For that route, you need to do the following steps:
Tap into the event when a new child DataGridContext is added to the control.
Add a predicate reference to the context.Items.Filter property (in the code state, this is a property expecting predicate, not an event).
Write your filter code in the predicate function.
I'm not 100% sure how to achieve #1 above (as I didn't need to go that route). However, a good place to possible start is the DetailsExpanding and DetailsExpanded events of the DataGridControl. For the expanding, I'm not sure if the child DataGridContext exists yet (as there is an option to cancel the expanding). So you might have to wait until after the expanded event.
I hope this helps point you in the right direction.
I am facing an issue where my graph is tree layout and looks fine initially. However, if I choose to change GraphSource upon user input/ clicks using PopulateGraphSource like in the OrgChart example, I get all the nodes stacked on top of each other with no links and all in corner.
I tried resetting graphSource by creating a new one
this.graphSource = new GraphSource();
I also tried to use the Clear method for GraphSource. Neither did solve the problem, I keep having the same issue.
I am using
ObservableCollection<Node> hierarchicalDataSource;
to fill up my GraphSource object.
All I do is create a new one and then call
PopulateGraphSource();
method.
Similar issues: question in telerik support , telerik support different question
Try calling the Layout method on the diagram control. Here is a little fragment of code
TreeLayoutSettings settings = new TreeLayoutSettings()
{
TreeLayoutType = TreeLayoutType.TreeDown,
VerticalSeparation = 60,
HorizontalSeparation=30
};
if (this.diagram.Shapes.Count > 0)
{
settings.Roots.Add(this.diagram.Shapes[0]);
this.diagram.Layout(LayoutType.Tree, settings);
this.diagram.AutoFit();
//this.diagram.Zoom = 1;
}
I am creating an item selector with two boxes that move things back and forth within an extjs application. On the right box, I am creating buttons that serve to move items up and down. Essentially I am swapping the item with one above or below it. So, my code is straight forward in that regard
MoveUp: function(button, event, eOpts){
var theChosen = Ext.getStore('storeId').getRootNode().findChild('text', 'Chosen folder');
var chosenPanel = Ext.ComponenetQuery.query('#chosenTreePanel')[0];
var selected = chosenPanel.getSelectionModel().getSelection();
for( var i = 1; i < theChosen.childNodes.length; i++){
if(Ext.Array.contains(selected, theChosen.childNodes[i]) && (!Ext.Array.contains(selected, theChosen.childNodes[i-1]){
var temp = theChosen.childNodes[i];
theChosen.childNodes[i] = theChosen.childNodes[i-1];
theChosen.childNodes[i-1] = temp;
}
}
}
All of this code seems to work fine, because after clicking my button, and checking the DOM in firebug, I can see that the selected nodes have moved in the array correctly, however, this effect is never shown within my treepanel. ???How do I make the treepanel update when it's elements change. ???
TreePanel heirarchy looks like this just to clarify
Root Node
'Chosen Folder Node'
Array of items I am moving up and down within the 'folder'
I am USING VERSION 4.0.7
Attempting to use replaceChild() to fire an event to rerender does not behave as I expected
Changing:
var temp = theChosen.childNodes[i];
theChosen.childNodes[i] = theChosen.childNodes[i-1];
theChosen.childNodes[i-1] = temp;
To:
var temp = theChosen.childNodes[i];
theChosen.replaceChild(theChosen.childNodes[i-1], theChosen.childNodes[i]);
theChosen.replaceChild(temp, theChosen.childNodes[i-1]);
Results in odd behavior in which some nodes go missing. Certaintly not what I was looking for. Where am I going wrong here?
Tried the following code using the datachanged and (undocumented)refresh event:
Ext.getStore('storeId').fireEvent('datachanged', Ext.getStore('chosen') );
Ext.getStore('storeId').fireEvent('datachanged', Ext.getStore('chosen') );
This does not reload anything...
SOLUTION:
Use the insertChild method of nodeInterface....
I have noticed something strange in how insertChild works in that I need to change my index more based on moving up or down will explain with code below.
To move Up:
theChosen.insertChild( (i-1), theChosen.childNodes[i]);
To move down:
theChosen.insertChild( (i+2), theChosen.childNodes[i]);
Although the -1 vs +2 they both effectively move the item by one in the appropriate direction.
If you want to update the view of the nodes, I recommend using yourTree.getView().refresh();
But you can avoid that by using parentNode.insertChild(index, childNode); where index is where you want the node to show up and parentNode is the parent to the nodes you are reordering. ChildNode can be a config for a new node or any other nodeinterface that already exists. If the node does already exist and you use the insertChild method to insert it, it will automatically remove that node from whereever else it is.
So as you provided in your question in response to my answer, your code will work with something like (this is probably how I'd do it, but this is untested):
MoveUp: function(button, event, eOpts){
var chosenPanel = Ext.ComponenetQuery.query('#chosenTreePanel')[0];
var selectedNodes = chosenPanel.getSelectionModel().getSelection();
for( var i = 0; i < selectedNodes.length; i++){
var currentNode = selectedNodes[i];
if(!currentNode.isFirst())
{
var parentNode = currentNode.parentNode;
var newIndex = parentNode.indexOf(currentNode) - 1;
parentNode.insertChild(newIndex, currentNode);
}
}
}
Edit:
Back to the the responsible event question...
You need to fire the
'datachanged'
'refresh'
Events on the store with the store as only param. That should cause a UI update. But please note that I just had a glimpse into the sourcecode and I am sure this can all be done much smarter. At least a DD solution for this exists already.
If I find some time I my look into this again, but I guess you should be fine with these events for the first.
You never see anything cause you just do it without the appropriate methods that then fire the responsible events that cause rerender. Take a look at
appendChild()
removeChild()
replaceChild()
There may also be more methods that can help on the Ext.data.NodeInterface. I recommend you to use these instead of doing it under hood without any responsible event fired.
In addition to my second comment (just a wild guess without knowing if that is exactly what you want):
MoveUp: function(button, event, eOpts){
var target = Ext.getStore('storeId').getRootNode().findChild('text', 'Chosen folder');
var selected = chosenPanel.getSelectionModel().getSelection();
target.appendChild(selected);
}
In Qt Designer I'm creating multiple labels (for instance):
my_label1
my_label2
my_label3
...
my_label n
Then if I want to hide them I do this:
ui->my_label1->hide();
ui->my_label2->hide();
ui->my_label3->hide();
...
ui->my_labeln->hide();
However I would like to define the labels like
my_label[n]
So then I would be able to do this:
for(i=0;i<n;i++)
{
ui->my_label[n]->hide();
}
I read that I can define the widget like:
QLabel* my_label[5];
but is there any way to do the same from Qt Designer?
Thanks in advance!
Finally I decided to do direct assignment:
QLabel* my_label_array[5];
my_label_array[0] = ui->my_label1;
my_label_array[1] = ui->my_label2;
my_label_array[2] = ui->my_label3;
my_label_array[3] = ui->my_label4;
my_label_array[4] = ui->my_label5;
Then I can do for instance:
for(idx=0;idx<6;idx++) my_label_array[idx]->show();
for(idx=0;idx<6;idx++) my_label_array[idx]->hide();
for(idx=0;idx<6;idx++) my_label_array[idx]->setEnabled(1);
for(idx=0;idx<6;idx++) my_label_array[idx]->setDisabled(1);
etc...
Then I was able to perform iterations. I believe is not the cleanest way to do it but given my basic knowledge of Qt is ok for me.
Thank you very much for your answers and your support! This is a great site with great people.
Instead of creating an explicit array, you may be able to name your widgets using a particular scheme and then use QObject::findChildren() on the parent widget to get a list of the widgets you are after.
If you only want to hide widgets, you can put all the widgets you want to hide in an invisible QFrame (set frameShape to NoFrame) and hide them all by calling setVisible(false) on the QFrame. This may cause some unwanted side effects with layouts so you may have to tweak some size policy settings.
In case you are wanting to hide controls so that you can simulate a wizard type UI, you may want to check into QStackedWidget.
I have another dirty workaround for this:
in header file
// .hpp
class UiBlabla : public QWidget {
...
QLabel** labels;
};
in source file
// constructor
ui->setupUi(this);
labels = new QLabel*[10]{ui->label_0, ui->label_1, ui->label_2, ui->label_3,
ui->label_4, ui->label_5, ui->label_6,
ui->label_7, ui->label_8, ui->label_9};
I haven't seen anything in QtDesigner to do that, but there are a couple of relatively easy ways to get that behavior.
1) Simply store the my_labelx pointers (from QtDesigner) in an array (or better, a QVector):
QVector<QLabel*> my_labels;
my_labels.push_back(ui->my_label1);
my_labels.push_back(ui->my_label2);
Then you can iterate through the QVector.
for(int i=0; i < my_labels.size(); ++i) {
my_labels[i]-> hide();
}
// or with QFOREACH
foreach(QLabel* label, my_labels)
label->hide();
There is a little setup needed in terms of adding all the labels to the QVector, but on the plus side you only do that once.
2) Depending on the layout of your gui, you could have all your labels be children of a container object and iterate through the children
I'm using a parent to pass a multi-dimensional array to a child. Structure of the array, named projectPositions is as follows (with example data):
projectPositions[0][0] = 1;
projectPositions[0][1] = 5;
projectPositions[0][2] = '1AD';
projectPositions[0][3] = 'User name';
I need to take this inherited array and turn it into an arrayCollection so that I can use it as a dataProvider. Currently, my init function (which runs onCreationComplete) has this code in it to handle this task of array -> arrayCollection:
for (var i:int = 0; i < projectPositions.length; i++)
{
tempObject = new Object;
tempObject.startOffset = projectPositions[i][0];
tempObject.numDays = projectPositions[i][1];
tempObject.role = projectPositions[i][2];
tempObject.student = projectPositions[i][3];
positionsAC.addItemAt(tempObject, positionsAC.length);
}
Then, during a repeater, I use positionsAC as the dataprovider and reference the items in the following way:
<mx:Repeater id="indPositions" dataProvider="{positionsAC}" startingIndex="0" count="{projectPositions.length}">
<components:block id="thisBlock" offSet="{indPositions.currentItem.startOffset}" numDays="{indPositions.currentItem.numDays}" position="{indPositions.currentItem.role}" sName="{indPositions.currentItem.student}" />
</mx:Repeater>
This all works fine and returns the desired effect, but the load time of this application is around 10 seconds. I'm 99% sure that the load time is caused by the array -> arrayCollection for loop. Is there an easier way to achieve the desired effect without having to wait so long for the page to load?
The issue your having loading items could be because you are using a repeater instead of a list class.
With a repeater, there will be a block created in memory, and drawn on the screen. So, if you have 100 items in your array, then 100 blocks will be created. this could slow down both initial creation and the overall app.
A list based class focuses on a technique called renderer recycling; which means only the displayed elements are created and rendered on the screen. So, depending on settings, you'd usually have 7-10 'block' instances on the screen, no matter how many items you have in your array.
change
positionsAC.addItemAt(tempObject, positionsAC.length);
to
positionsAC.addItem(tempObject);
addItemAt is causing a reindex of the collection which can greatly slow down the collection.
[EDIT]
Put this trace statement before and after the loop
take the output and subtract one from the other and that will show how many milliseconds the loop has run.
var date:Date = new Date( );
trace( date.getTime())