Pokazywanie postów oznaczonych etykietą english. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą english. Pokaż wszystkie posty

31 grudnia 2010

Custom PagingNavigator with changing items per page in Wicket

As I am migrating my blog to my own domain, a few posts in the future will be published in both places to allow You, reader, to change address and rss smoothly :)

New blog address: http://tomaszdziurko.pl
New RSS link: http://www.tomaszdziurko.pl/feed

This post can be found at
http://tomaszdziurko.pl/2010/12/custom-pagingnavigator-with-changing-items-per-page-in-wicket/



In one of my recent projects I had to create Wicket pagination component with one additional functionality allowing user to dynamically change maximum number of items presented on each page.

Finished component will look like below:



Of course I was not going to implement this from the scratch, because most of work had been already done by Wicket authors and commiters in component PagingNavigator. Source of this component as a reference to changes I made can be found here.

The first steps in creating our component:
- add List itemsPerPageValues holding numbers for 'items per page' which will be shown to the user allowing him to click and change this value.
- provide default List DEFAULT_ITEMS_PER_PAGE_VALUES, which will be used (what a surprise!) as a default :)
- give our component reference to the DataView object on which we will execute change items per page method.

Below we can see changes in class fields and constructors:

public class CustomPagingNavigator extends Panel {

public static final String NAVIGATION_ID = "navigation";
public static final List<Integer> DEFAULT_ITEMS_PER_PAGE_VALUES = Arrays.asList(5, 10, 50);

private PagingNavigation pagingNavigation;
private final DataView<?> dataView;
private final IPagingLabelProvider labelProvider;
private final List<Integer> itemsPerPageValues;
private WebMarkupContainer pagingLinksContainer;

public CustomPagingNavigator(final String id, final DataView<?> dataView) {
this(id, dataView, null, DEFAULT_ITEMS_PER_PAGE_VALUES);
}

public CustomPagingNavigator(final String id, final DataView<?> dataView, List<Integer> itemsPerPageValues) {
this(id, dataView, null, itemsPerPageValues);
}

public CustomPagingNavigator(final String id, final DataView<?> dataView, final IPagingLabelProvider labelProvider) {
this(id, dataView, labelProvider, DEFAULT_ITEMS_PER_PAGE_VALUES);
}

public CustomPagingNavigator(final String id, final DataView<?> dataView, final IPagingLabelProvider labelProvider,
List<Integer> itemsPerPageValues) {
super(id);
this.dataView = dataView;
this.labelProvider = labelProvider;
this.itemsPerPageValues = itemsPerPageValues;

// these methods will be described later in this post
addContainerWithPagingLinks();
addLinksChangingItemsPerPageNumber();
}
(...)
}


First new method is addContainerWithPagingLinks based mainly of onBeforeRender from PagingNavigator. This method adds paging links to the component to allow user to change number of viewed page. One small addition is an overriden isVisible which will hide paging fragment when there is only one page to show.

private void addContainerWithPagingLinks() {

pagingLinksContainer = new WebMarkupContainer("pagingLinksContainer") {
@Override
public boolean isVisible() {
return dataView.getPageCount() > 1;
}
}

pagingNavigation = newNavigation(dataView, labelProvider);
pagingLinksContainer.add(pagingNavigation);

// Add additional page links
pagingLinksContainer.add(newPagingNavigationLink("first", dataView, 0).add(
new TitleAppender("PagingNavigator.first")));
pagingLinksContainer.add(newPagingNavigationIncrementLink("prev", dataView, -1).add(
new TitleAppender("PagingNavigator.previous")));
pagingLinksContainer.add(newPagingNavigationIncrementLink("next", dataView, 1).add(
new TitleAppender("PagingNavigator.next")));
pagingLinksContainer.add(newPagingNavigationLink("last", dataView, -1).add(
new TitleAppender("PagingNavigator.last")));

add(pagingLinksContainer);
}

Next step is to override isVisible method in our component which will hide it completely when DataView has no items to render:

@Override
public boolean isVisible() {
return dataView.getItemCount() > 0;
}

And now it's time to create the core of our component: a place where items per page can be changed. This is done in method:

private void addLinksChangingItemsPerPageNumber() {
ListView<Integer> itemsPerPageList = new ListView<Integer>("itemsPerPage", itemsPerPageValues) {
@Override
protected void populateItem(ListItem<Integer> item) {
Link<Void> itemPerPageLink = new ItemPerPageLink<Void>("itemPerPageLink", dataView,
pagingLinksContainer, item.getModelObject());
itemPerPageLink.add(new Label("itemsValue", item.getModel()));
item.add(itemPerPageLink);
}
};

add(itemsPerPageList);
}

In the above method we create ListView for Integers from itemsPerPageValues and for each number we add link (new class ItemPerPageLink explained below) which will change DataView itemsPerPage property. Except reference to DataView we also give to our link reference to pagingLinksContainer to hide it after user changes itemsPerPage and there will be only one page to show.

Complete class ItemPerPageLink source code:

public class ItemPerPageLink<T> extends Link<T> {

private final int itemsPerPage;
private final DataView<?> dataView;
private final WebMarkupContainer pagingLinksContainer;

public ItemPerPageLink(final String id, final DataView<?> dataView, WebMarkupContainer pagingLinksContainer, int itemsPerPageValue) {
super(id);
this.dataView = dataView;
this.pagingLinksContainer = pagingLinksContainer;
this.itemsPerPage = itemsPerPageValue;
setEnabled(itemsPerPageValue != dataView.getItemsPerPage());

}

@Override
public void onClick() {
dataView.setItemsPerPage(itemsPerPage);
pagingLinksContainer.setVisible(dataView.getPageCount() > 1);
}

@Override
protected void onComponentTag(ComponentTag tag) {
super.onComponentTag(tag);
tag.put("title", itemsPerPage);
}

}

In this class we:
1. Disable link for number which is current dataView.itemsPerPage value.
2. Hide pagingLinksContainer when there is only one page.
3. Change itemsPerPage property in onClick method.
4. Set link title to the value of items per page.

And that's all. For those who want complete solution in one place there is complete source of the class CustomPagingNavigator with its markup:


import java.util.Arrays;
import java.util.List;

import org.apache.wicket.Component;
import org.apache.wicket.behavior.AbstractBehavior;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.link.AbstractLink;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.navigation.paging.IPageable;
import org.apache.wicket.markup.html.navigation.paging.IPagingLabelProvider;
import org.apache.wicket.markup.html.navigation.paging.PagingNavigation;
import org.apache.wicket.markup.html.navigation.paging.PagingNavigationIncrementLink;
import org.apache.wicket.markup.html.navigation.paging.PagingNavigationLink;
import org.apache.wicket.markup.html.navigation.paging.PagingNavigator;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.markup.repeater.data.DataView;

public class CustomPagingNavigator extends Panel {

public static final String NAVIGATION_ID = "navigation";
public static final List<Integer> DEFAULT_ITEMS_PER_PAGE_VALUES = Arrays.asList(5, 25, 50);

private PagingNavigation pagingNavigation;
private final DataView<?> dataView;
private final IPagingLabelProvider labelProvider;
private final List<Integer> itemsPerPageValues;
private WebMarkupContainer pagingLinksContainer;

public CustomPagingNavigator(final String id, final DataView<?> dataView) {
this(id, dataView, null, DEFAULT_ITEMS_PER_PAGE_VALUES);
}

public CustomPagingNavigator(final String id, final DataView<?> dataView, List<Integer> itemsPerPageValues) {
this(id, dataView, null, itemsPerPageValues);
}

public CustomPagingNavigator(final String id, final DataView<?> dataView, final IPagingLabelProvider labelProvider) {
this(id, dataView, labelProvider, DEFAULT_ITEMS_PER_PAGE_VALUES);
}

public CustomPagingNavigator(final String id, final DataView<?> dataView, final IPagingLabelProvider labelProvider,
List<Integer> itemsPerPageValues) {
super(id);
this.dataView = dataView;
this.labelProvider = labelProvider;
this.itemsPerPageValues = itemsPerPageValues;

addContainerWithPagingLinks();
addLinksChangingItemsPerPageNumber();
}

@Override
public boolean isVisible() {
return dataView.getItemCount() > 0;
}

private void addContainerWithPagingLinks() {

pagingLinksContainer = new WebMarkupContainer("pagingLinksContainer") {
@Override
public boolean isVisible() {
return dataView.getPageCount() > 1;
}
};

pagingNavigation = newNavigation(dataView, labelProvider);
pagingLinksContainer.add(pagingNavigation);

// Add additional page links
pagingLinksContainer.add(newPagingNavigationLink("first", dataView, 0).add(
new TitleAppender("PagingNavigator.first")));
pagingLinksContainer.add(newPagingNavigationIncrementLink("prev", dataView, -1).add(
new TitleAppender("PagingNavigator.previous")));
pagingLinksContainer.add(newPagingNavigationIncrementLink("next", dataView, 1).add(
new TitleAppender("PagingNavigator.next")));
pagingLinksContainer.add(newPagingNavigationLink("last", dataView, -1).add(
new TitleAppender("PagingNavigator.last")));

add(pagingLinksContainer);
}

protected PagingNavigation newNavigation(final IPageable pageable, final IPagingLabelProvider labelProvider) {
return new PagingNavigation(NAVIGATION_ID, pageable, labelProvider);
}

protected AbstractLink newPagingNavigationIncrementLink(String id, IPageable pageable, int increment) {
return new PagingNavigationIncrementLink<Void>(id, pageable, increment);
}

protected AbstractLink newPagingNavigationLink(String id, IPageable pageable, int pageNumber) {
return new PagingNavigationLink<Void>(id, pageable, pageNumber);
}

private void addLinksChangingItemsPerPageNumber() {
ListView<Integer> itemsPerPageList = new ListView<Integer>("itemsPerPage", itemsPerPageValues) {
@Override
protected void populateItem(ListItem<Integer> item) {
Link<Void> itemPerPageLink = new ItemPerPageLink<Void>("itemPerPageLink", dataView,
pagingLinksContainer, item.getModelObject());
itemPerPageLink.add(new Label("itemsValue", item.getModel()));
item.add(itemPerPageLink);
}
};

add(itemsPerPageList);
}

public final PagingNavigation getPagingNavigation() {
return pagingNavigation;
}

private final class TitleAppender extends AbstractBehavior {
private static final long serialVersionUID = 1L;

private final String resourceKey;

public TitleAppender(String resourceKey) {
this.resourceKey = resourceKey;
}

@Override
public void onComponentTag(Component component, ComponentTag tag) {
tag.put("title", CustomPagingNavigator.this.getString(resourceKey));
}
}
}


And its markup:

<?xml version="1.0" encoding="UTF-8" ?>
<html xmlns:wicket>
<body>
<wicket:panel>

<div>
<div>
Items per page:
<span wicket:id="itemsPerPage">
<a wicket:id="itemPerPageLink"><span wicket:id="itemsValue"></span></a>
</span>
</div>
<div wicket:id="pagingLinksContainer">
<table>

<tbody>
<tr valign="top">
<td>
<a wicket:id="first" href="">
<span>First</span>
</a>
</td>
<td>
<a wicket:id="prev" href="">
<span>Previous</span>
</a>
</td>
<td wicket:id="navigation">
<a wicket:id="pageLink"><span
wicket:id="pageNumber">5</span></a>
</td>

<td>
<a wicket:id="next" href="#">
<span>Next</span></a>
</td>
<td>
<a wicket:id="last" href="#">
<span>Last</span></a>
</td>
</tr>
</tbody>
</table>

</div>
</div>

</wicket:panel>
</body>
</html>


Usage of the component

Our newly created component can be used in a very similar way to the standard Wicket PagingNavigator:


public class DataViewPanel extends Panel {

public DataViewPanel(String id) {
super(id);
DataView dataView = new DataView("dataView", new CustomDataProvider());
dataView.setItemsPerPage(5);
add(dataView);

CustomPagingNavigator customPagingNavigator = new CustomPagingNavigator("paginator", dataView);
add(customPagingNavigator);
}
}

19 grudnia 2010

What would you do if your boss give you one week for self-education?

Let’s suppose following scenario:

You are somewhat experienced Java Developer working on a very sophisticated project in the science sector. You create very, very complicated module using very, very time-consuming algorithm which can not be multithreaded. And when you are ready, tests with small data portions went fine, your boss comes to your desk and clicks big, red button on your monitor to proudly start the whole process. Of course nothing bad happens, you just can observe growing CPU and memory usage. Your team expect that those calculation will take about one week to finish and give you results which are indispensable for you next tasks. It’s JIRA blocker status and until it finishes, you had nothing to do. Your boss asks you to visit him in his room and sais:

- Tom, you did a great job with this module. Everything seems to run smoothly and I can not wait to see the results! We must wait one week and it’s a spare time which I would like you to use for you self-education and self-development. What you are going to do and learn?

Of course we don’t know whether this boss is going to pay Tom for this time or not :) But it’s not the case. Tom now has a problem: 40 hours of free time which he can spend on any technology/methodology/language/etc he wants to learn and this opportunity comes to him so unexpectedly that he can not make up his mind.

Please help him! What would YOU do with these 40 hours? :)

PS: As I am migrating my blog to my own domain, a few posts in the future will be published in both places to allow You, reader, to change address and rss smoothly :)

New blog address: http://tomaszdziurko.pl
New RSS link: http://www.tomaszdziurko.pl/feed

19 października 2010

Slides from JDD 2010 available

This post has been moved to my new blog and can be found at here.

22 sierpnia 2010

Submitting SSL and no-SSL html forms using JMeter

This post has been moved to my new blog and can be found at here.

28 czerwca 2010

Solving com.mysql.jdbc.exceptions.jdbc4.CommunicationsException in Spring JDBC based application

This post has been moved to my new blog and can be found at here.

9 lutego 2010

Wicket Ajax Modal 'Are you sure?' window

This post has been moved to my new blog and can be found at here.

15 lipca 2009

Protect your balls, man!

In spite of title, this post is about really, really serious thing.

We all (ok, probably almost all) have laptops and use them in many places, of course to spend time as effectively as possible. Everyday I see people using their laptops in train, bus, on a bench in the park and, most often, in bed. In all those cases laptop lies on their laps.

This is so common that we don't realize this is WRONG AND DANGEROUS!

Medicine researches state that drivers, especially truck and bus drivers more frequently have problems to become fathers. Their sperm isn't in best condition because of their work.
"What the heck I have in common with truck drivers?!" you could ask. The answer is simpler than you think. We all work for serveral hours in sitting position and this is not good for our sperm.

Male balls (testiculars) are placed outside body for one reason: better cooling. High temperature causes damage to sperm cells making them incapable of doing their job properly. If you are using laptop on your laps everyday for some time, your sperm don't have possibility to recover. Sometimes this state could become irreversible and as a result your wife or girlfriend will never be happy mummy.

How can you prevent this horrible scenario?
If you really can't live without working with computer on your laps there are some ways to make you and your balls much safer.

1. Put a large book between laps and laptop.
Pros:
- the cheapest solution
- it's not heavy if book is large but thin
- small, easy to carry

Cons:
- instability, when you move your laptop also moves.
- no place for mouse

2. board made of isolating material
Pros:
- lighter than book
- small, easy to carry

Cons:
- not so cheap
- instability
- no place for mouse

3. notebook/laptop coolers (example 1, example 2)
Pros:
- they cool laptop and help to exchange air between your laps and laptop.

Cons:
- price
- not all are lightweight and easy to carry
- some are cheap but some are really expensive (Zalman for example)
- instability
- no place for mouse

4. small table for laptop (example 1, example 2, example 3)
Pros:
- perfect to use in bed or sofa
- stable, laptop lies on the table not on your laps
- some of them have place for mouse

Cons:
- price
- large size
- rather impossible to use them in train


Summary
As you can see there are many ways to protect our balls from heat and ensure safety of our future parenthood. Some of these solutions won't cost you anything except a little effort so I think they are worth trying.

13 lipca 2009

SCJP - preparations for exam and impressions after

Readers from Poland: this is English version of my old post written in Polish which has additional information interesting only for Polish readers.

It's been some time since I passed my Sun Certified Java Programmer 1.5 (SCJP) exam, but I hope this post will help somebody to choose their way of preparations to the exam and consequently achieve better final result.


Teaching aids
- SCJP Sun Certified Programmer for Java 5 Study Guide (Exam 310-055), definitely "must have" book for everyone planning to pass SCJP. This book covers everything you could encounter on exam. I read it whole once but some chapters twice (mainly Generics and Threads which I didn't catch on at first).
- simulator EnthuWare JQ+, it costs only 28$ or 18$ (for students) but wihout it my score would have been lower.

- Java Language Specification and javadocs for further reading about small details
- your favourite IDE to test your own ideas and experiment with questions from example tests. Question 'What would be if I change ..." is one you should ask often while learning :)
- forum SCJP at JavaRanch.com, where you can meet many people who already passed SCJP and also authors of SCJP book.


General tips
1. I think trying to pass the exam without doing some example tests isn't good idea. Questions are rather specific and after few hundreds of example questions your speed and accuracy will increase significantly. Additionally you will be able to see some problems and errors right after you look at the code, almost without deeper analyze.
2. Money spent on SCJP simulator are never wasted money.
3. Play with code. If you are unsure about how something works, check it with your IDE. Try changing some code and see how it works then. My experiments with NetBeans give me a lot of additional knowledge.
4. Don't learn too long. I know it's hard to say with great confidence "I am ready for the exam", but you should pick a date (even in 3-4 months) and do not change it unless you are really, really justified. With such deadline in your head, you will be more motivated to learn regularly with better final effect. A friend of mine is learning for SCJP for 6 months without any plan and his preparations seem to be endless :)

More user stories about how people prepare for SCJP could be found at:
JavaRanch SCJP Wall of Fame.

PS: My result was 80% :)

getBlog().addLanguage(Locale.ENGLISH), was: getBlog().setLanguage(Locale.ENGLISH);

After a while when I was blogging in Polish, my native language, I decided to make an attempt to switch completely to English, "esperanto of IT world". Main factors which lead me to this decision were:
- feeling that my English language skills are becoming more and more rusty, especially in areas not closely connected with IT and technical language. I know that writing new posts will take more time, but I think it's worth the effort.
- need to be more involved in filling Internet with useful programming stuff and solutions. No one could deny that posts in English are really more helpful than those in other languages. This is even more true if we take into consideration only IT world, when English is language of all information we need and consume everyday: tutorials, documentation, most actual books, etc.
- some voices from Web: post by Paul Szulc in Polish and another convincing post by Jeff Atwood. They both pointed out some good reasons why we all should blog about IT in one, unified language.

In spare time I will translate some old posts from Polish and update page content to conform to "English only" rule :)

So from now on only English posts here. I am eager to read your opinions about this change so feel free to post them in comments :) Also impressions about new blog template from http://www.zenplate.blogspot.com/ are welcome.

UPDATE (two weeks later): I was thinking about formula of this blog and some doubts appeared in my head. Do I really have content which is unique in whole Internet? Recently I thought so, but when I was preparing post in English about book "Effective Java", I found that many, many other people already wrote about similar things and enthusiasm about my post almost disappeared. So what now? I think that most of my post will be in Polish, because I don't want them to duplicate other content from the Web. Moreover writing in Polish will allow me to share some more personal opinions and experiences from programming and my live in general than if I was writing in English. Of course some posts that in my opinion are more unique or interesting will be translated to English.
I apologize for the confusion and my earlier rash decision. I hope it won't happen again :)